mirror of
https://github.com/curl/curl.git
synced 2026-08-25 09:23:31 +03:00
parent
ebc0fbc0e8
commit
c7c42afab9
5 changed files with 150 additions and 17 deletions
|
|
@ -291,6 +291,37 @@ HANDLE curlx_CreateFile(const char *filename,
|
|||
|
||||
return handle;
|
||||
}
|
||||
|
||||
HANDLE curlx_FindFirstFile(const char *filename,
|
||||
WIN32_FIND_DATA *find_data)
|
||||
{
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
#ifdef UNICODE
|
||||
TCHAR *filename_t = curlx_convert_UTF8_to_wchar(filename);
|
||||
#else
|
||||
const TCHAR *filename_t = filename;
|
||||
#endif
|
||||
|
||||
if(filename_t) {
|
||||
TCHAR *fixed = NULL;
|
||||
const TCHAR *target;
|
||||
|
||||
if(fix_excessive_path(filename_t, &fixed))
|
||||
target = fixed;
|
||||
else
|
||||
target = filename_t;
|
||||
|
||||
handle = FindFirstFile(target, find_data);
|
||||
CURLX_FREE(fixed);
|
||||
|
||||
#ifdef UNICODE
|
||||
curlx_free(filename_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
#endif /* !CURL_WINDOWS_UWP */
|
||||
|
||||
int curlx_win32_open(const char *filename, int oflag, ...)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ HANDLE curlx_CreateFile(const char *filename,
|
|||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes,
|
||||
HANDLE hTemplateFile);
|
||||
HANDLE curlx_FindFirstFile(const char *filename,
|
||||
WIN32_FIND_DATA *find_data);
|
||||
#endif /* !CURL_WINDOWS_UWP */
|
||||
#define curlx_fstat _fstati64
|
||||
#define curlx_struct_stat struct _stati64
|
||||
|
|
|
|||
113
lib/file.c
113
lib/file.c
|
|
@ -76,12 +76,14 @@ struct FILEPROTO {
|
|||
char *freepath; /* pointer to the allocated block we must free, this might
|
||||
differ from the 'path' pointer */
|
||||
int fd; /* open file descriptor to read from! */
|
||||
bool is_dir;
|
||||
};
|
||||
|
||||
static void file_cleanup(struct FILEPROTO *file)
|
||||
{
|
||||
curlx_safefree(file->freepath);
|
||||
file->path = NULL;
|
||||
file->is_dir = FALSE;
|
||||
if(file->fd != -1) {
|
||||
curlx_close(file->fd);
|
||||
file->fd = -1;
|
||||
|
|
@ -126,6 +128,38 @@ static CURLcode file_done(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static int file_stat(const char *path, curlx_struct_stat *statbuf)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int result = curlx_stat(path, statbuf);
|
||||
|
||||
if(result) {
|
||||
size_t pathlen = strlen(path);
|
||||
|
||||
/* MSVCRT's narrow stat() rejects trailing directory separators. */
|
||||
if((pathlen > 3) &&
|
||||
((path[pathlen - 1] == '\\') || (path[pathlen - 1] == '/'))) {
|
||||
char *trimmed = curlx_strdup(path);
|
||||
|
||||
if(trimmed) {
|
||||
do {
|
||||
trimmed[--pathlen] = '\0';
|
||||
} while((pathlen > 3) &&
|
||||
((trimmed[pathlen - 1] == '\\') ||
|
||||
(trimmed[pathlen - 1] == '/')));
|
||||
|
||||
result = curlx_stat(trimmed, statbuf);
|
||||
curlx_free(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
#else
|
||||
return curlx_stat(path, statbuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* file_connect() gets called from Curl_protocol_connect() to allow us to
|
||||
* do protocol-specific actions at connect-time. We emulate a
|
||||
|
|
@ -135,6 +169,9 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
|
|||
{
|
||||
char *real_path;
|
||||
struct FILEPROTO *file = Curl_meta_get(data, CURL_META_FILE_EASY);
|
||||
#ifdef _WIN32
|
||||
curlx_struct_stat statbuf;
|
||||
#endif
|
||||
int fd;
|
||||
#ifdef DOS_FILESYSTEM
|
||||
size_t i;
|
||||
|
|
@ -233,7 +270,13 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
|
|||
file->freepath = real_path; /* free this when done */
|
||||
|
||||
file->fd = fd;
|
||||
if(!data->state.upload && (fd == -1)) {
|
||||
#ifdef _WIN32
|
||||
if(!data->state.upload && (fd == -1) &&
|
||||
!file_stat(file->path, &statbuf) && S_ISDIR(statbuf.st_mode))
|
||||
file->is_dir = TRUE;
|
||||
#endif
|
||||
|
||||
if(!data->state.upload && (fd == -1) && !file->is_dir) {
|
||||
failf(data, "Could not open file %s", data->state.up.path);
|
||||
file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE);
|
||||
return CURLE_FILE_COULDNT_READ_FILE;
|
||||
|
|
@ -370,6 +413,58 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
|
||||
static CURLcode win32_file_list(struct Curl_easy *data, const char *path)
|
||||
{
|
||||
WIN32_FIND_DATA entry;
|
||||
HANDLE handle;
|
||||
char *pattern;
|
||||
size_t pathlen = strlen(path);
|
||||
CURLcode result = CURLE_OK;
|
||||
DWORD error;
|
||||
|
||||
pattern = curl_maprintf("%s%s*", path,
|
||||
pathlen &&
|
||||
(path[pathlen - 1] == '\\' ||
|
||||
path[pathlen - 1] == '/') ? "" : "\\");
|
||||
if(!pattern)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
handle = curlx_FindFirstFile(pattern, &entry);
|
||||
curlx_free(pattern);
|
||||
if(handle == INVALID_HANDLE_VALUE)
|
||||
return CURLE_READ_ERROR;
|
||||
|
||||
do {
|
||||
if(entry.cFileName[0] != TEXT('.')) {
|
||||
char *name = curlx_convert_tchar_to_UTF8(entry.cFileName);
|
||||
|
||||
if(!name) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY,
|
||||
name, strlen(name));
|
||||
curlx_free(name);
|
||||
if(result)
|
||||
break;
|
||||
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
|
||||
if(result)
|
||||
break;
|
||||
}
|
||||
} while(FindNextFile(handle, &entry));
|
||||
|
||||
error = GetLastError();
|
||||
if(!result && error != ERROR_NO_MORE_FILES)
|
||||
result = CURLE_READ_ERROR;
|
||||
|
||||
FindClose(handle);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* file_do() is the protocol-specific function for the do-phase, separated
|
||||
* from the connect-phase above. Other protocols merely setup the transfer in
|
||||
|
|
@ -405,8 +500,10 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
|
|||
fd = file->fd;
|
||||
|
||||
/* VMS: This only works reliable for STREAMLF files */
|
||||
if(curlx_fstat(fd, &statbuf) != -1) {
|
||||
if(!S_ISDIR(statbuf.st_mode))
|
||||
if((file->is_dir ? file_stat(file->path, &statbuf) :
|
||||
curlx_fstat(fd, &statbuf)) != -1) {
|
||||
file->is_dir = (fd == -1) || S_ISDIR(statbuf.st_mode);
|
||||
if(!file->is_dir)
|
||||
expected_size = statbuf.st_size;
|
||||
/* and store the modification time */
|
||||
data->info.filetime = statbuf.st_mtime;
|
||||
|
|
@ -510,7 +607,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
|
|||
Curl_pgrsSetDownloadSize(data, expected_size);
|
||||
|
||||
if(data->state.resume_from) {
|
||||
if(!S_ISDIR(statbuf.st_mode)) {
|
||||
if(!file->is_dir) {
|
||||
if(data->state.resume_from !=
|
||||
curl_lseek(fd, data->state.resume_from, SEEK_SET))
|
||||
return CURLE_BAD_DOWNLOAD_RESUME;
|
||||
|
|
@ -524,7 +621,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
|
|||
if(result)
|
||||
goto out;
|
||||
|
||||
if(!S_ISDIR(statbuf.st_mode)) {
|
||||
if(!file->is_dir) {
|
||||
while(!result) {
|
||||
ssize_t nread;
|
||||
/* Do not fill a whole buffer if we want less than all data */
|
||||
|
|
@ -558,7 +655,11 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
|
|||
}
|
||||
}
|
||||
else {
|
||||
#ifdef HAVE_OPENDIR
|
||||
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
|
||||
result = win32_file_list(data, file->path);
|
||||
if(result)
|
||||
goto out;
|
||||
#elif defined(HAVE_OPENDIR)
|
||||
DIR *dir = opendir(file->path);
|
||||
struct dirent *entry;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue