From c7924b554d9e62781c5a0eb15394c528925abfef Mon Sep 17 00:00:00 2001 From: David PHAM-VAN Date: Wed, 30 Nov 2016 13:48:33 -0800 Subject: [PATCH] Rewrite drive channel using WinPR functions --- channels/drive/client/CMakeLists.txt | 7 - channels/drive/client/dirent.h | 374 ------------- channels/drive/client/drive_file.c | 720 ++++++++++++------------- channels/drive/client/drive_file.h | 95 +--- channels/drive/client/drive_main.c | 188 ++++--- channels/drive/client/statvfs.c | 60 --- channels/drive/client/statvfs.h | 50 -- ci/cmake-preloads/config-linux-all.txt | 1 + cmake/ConfigOptions.cmake | 1 + config.h.in | 1 + 10 files changed, 442 insertions(+), 1055 deletions(-) delete mode 100644 channels/drive/client/dirent.h delete mode 100644 channels/drive/client/statvfs.c delete mode 100644 channels/drive/client/statvfs.h diff --git a/channels/drive/client/CMakeLists.txt b/channels/drive/client/CMakeLists.txt index ba2d0f4f9..2c2be3930 100644 --- a/channels/drive/client/CMakeLists.txt +++ b/channels/drive/client/CMakeLists.txt @@ -22,13 +22,6 @@ set(${MODULE_PREFIX}_SRCS drive_file.h drive_main.c) -if(WIN32) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - statvfs.c - statvfs.h - dirent.h) -endif() - add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry") diff --git a/channels/drive/client/dirent.h b/channels/drive/client/dirent.h deleted file mode 100644 index 7c61d6a2c..000000000 --- a/channels/drive/client/dirent.h +++ /dev/null @@ -1,374 +0,0 @@ -/***************************************************************************** - * dirent.h - dirent API for Microsoft Visual Studio - * - * Copyright (C) 2006 Toni Ronkko - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * ``Software''), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Mar 15, 2011, Toni Ronkko - * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0. - * - * Aug 11, 2010, Toni Ronkko - * Added d_type and d_namlen fields to dirent structure. The former is - * especially useful for determining whether directory entry represents a - * file or a directory. For more information, see - * http://www.delorie.com/gnu/docs/glibc/libc_270.html - * - * Aug 11, 2010, Toni Ronkko - * Improved conformance to the standards. For example, errno is now set - * properly on failure and assert() is never used. Thanks to Peter Brockam - * for suggestions. - * - * Aug 11, 2010, Toni Ronkko - * Fixed a bug in rewinddir(): when using relative directory names, change - * of working directory no longer causes rewinddir() to fail. - * - * Dec 15, 2009, John Cunningham - * Added rewinddir member function - * - * Jan 18, 2008, Toni Ronkko - * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string - * between multi-byte and unicode representations. This makes the - * code simpler and also allows the code to be compiled under MingW. Thanks - * to Azriel Fasten for the suggestion. - * - * Mar 4, 2007, Toni Ronkko - * Bug fix: due to the strncpy_s() function this file only compiled in - * Visual Studio 2005. Using the new string functions only when the - * compiler version allows. - * - * Nov 2, 2006, Toni Ronkko - * Major update: removed support for Watcom C, MS-DOS and Turbo C to - * simplify the file, updated the code to compile cleanly on Visual - * Studio 2005 with both unicode and multi-byte character strings, - * removed rewinddir() as it had a bug. - * - * Aug 20, 2006, Toni Ronkko - * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified - * comments by removing SGML tags. - * - * May 14 2002, Toni Ronkko - * Embedded the function definitions directly to the header so that no - * source modules need to be included in the Visual Studio project. Removed - * all the dependencies to other projects so that this very header can be - * used independently. - * - * May 28 1998, Toni Ronkko - * First version. - *****************************************************************************/ -#ifndef DIRENT_H -#define DIRENT_H - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include -#include -#include -#include -#include - -/* Entries missing from MSVC 6.0 */ -#if !defined(FILE_ATTRIBUTE_DEVICE) -# define FILE_ATTRIBUTE_DEVICE 0x40 -#endif - -/* File type and permission flags for stat() */ -#if defined(_MSC_VER) && !defined(S_IREAD) -# define S_IFMT _S_IFMT /* file type mask */ -# define S_IFDIR _S_IFDIR /* directory */ -# define S_IFCHR _S_IFCHR /* character device */ -# define S_IFFIFO _S_IFFIFO /* pipe */ -# define S_IFREG _S_IFREG /* regular file */ -# define S_IREAD _S_IREAD /* read permission */ -# define S_IWRITE _S_IWRITE /* write permission */ -# define S_IEXEC _S_IEXEC /* execute permission */ -#endif -#define S_IFBLK 0 /* block device */ -#define S_IFLNK 0 /* link */ -#define S_IFSOCK 0 /* socket */ - -#if defined(_MSC_VER) -# define S_IRUSR S_IREAD /* read, user */ -# define S_IWUSR S_IWRITE /* write, user */ -# define S_IXUSR 0 /* execute, user */ -# define S_IRGRP 0 /* read, group */ -# define S_IWGRP 0 /* write, group */ -# define S_IXGRP 0 /* execute, group */ -# define S_IROTH 0 /* read, others */ -# define S_IWOTH 0 /* write, others */ -# define S_IXOTH 0 /* execute, others */ -#endif - -/* Indicates that d_type field is available in dirent structure */ -#define _DIRENT_HAVE_D_TYPE - -/* File type flags for d_type */ -#define DT_UNKNOWN 0 -#define DT_REG S_IFREG -#define DT_DIR S_IFDIR -#define DT_FIFO S_IFFIFO -#define DT_SOCK S_IFSOCK -#define DT_CHR S_IFCHR -#define DT_BLK S_IFBLK - -/* Macros for converting between st_mode and d_type */ -#define IFTODT(mode) ((mode) & S_IFMT) -#define DTTOIF(type) (type) - -/* - * File type macros. Note that block devices, sockets and links cannot be - * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are - * only defined for compatibility. These macros should always return FALSE - * on Windows. - */ -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) -#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) -#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) -#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef struct dirent -{ - char d_name[MAX_PATH + 1]; /* File name */ - size_t d_namlen; /* Length of name without \0 */ - int d_type; /* File type */ -} dirent; - - -typedef struct DIR -{ - dirent curentry; /* Current directory entry */ - WIN32_FIND_DATAA find_data; /* Private file data */ - int cached; /* True if data is valid */ - HANDLE search_handle; /* Win32 search handle */ - char patt[MAX_PATH + 3]; /* Initial directory name */ -} DIR; - - -/* Forward declarations */ -static DIR *opendir(const char *dirname); -static struct dirent *readdir(DIR *dirp); -static int closedir(DIR *dirp); -static void rewinddir(DIR* dirp); - - -/* Use the new safe string functions introduced in Visual Studio 2005 */ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE) -#else -# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size)) -#endif - -/* Set errno variable */ -#if defined(_MSC_VER) -#define DIRENT_SET_ERRNO(x) _set_errno (x) -#else -#define DIRENT_SET_ERRNO(x) (errno = (x)) -#endif - - -/***************************************************************************** - * Open directory stream DIRNAME for read and return a pointer to the - * internal working area that is used to retrieve individual directory - * entries. - */ -static DIR *opendir(const char *dirname) -{ - DIR *dirp; - - /* ensure that the resulting search pattern will be a valid file name */ - if (dirname == NULL) { - DIRENT_SET_ERRNO (ENOENT); - return NULL; - } - if (strlen (dirname) + 3 >= MAX_PATH) { - DIRENT_SET_ERRNO (ENAMETOOLONG); - return NULL; - } - - /* construct new DIR structure */ - dirp = (DIR*) malloc (sizeof (struct DIR)); - if (dirp != NULL) { - int error; - - /* - * Convert relative directory name to an absolute one. This - * allows rewinddir() to function correctly when the current working - * directory is changed between opendir() and rewinddir(). - */ - if (GetFullPathNameA(dirname, MAX_PATH, dirp->patt, NULL)) { - char *p; - - /* append the search pattern "\\*\0" to the directory name */ - p = strchr (dirp->patt, '\0'); - if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') { - *p++ = '\\'; - } - *p++ = '*'; - *p = '\0'; - - /* open directory stream and retrieve the first entry */ - dirp->search_handle = FindFirstFileA(dirp->patt, &dirp->find_data); - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - /* a directory entry is now waiting in memory */ - dirp->cached = 1; - error = 0; - } else { - /* search pattern is not a directory name? */ - DIRENT_SET_ERRNO (ENOENT); - error = 1; - } - } else { - /* buffer too small */ - DIRENT_SET_ERRNO (ENOMEM); - error = 1; - } - - if (error) { - free (dirp); - dirp = NULL; - } - } - - return dirp; -} - - -/***************************************************************************** - * Read a directory entry, and return a pointer to a dirent structure - * containing the name of the entry in d_name field. Individual directory - * entries returned by this very function include regular files, - * sub-directories, pseudo-directories "." and "..", but also volume labels, - * hidden files and system files may be returned. - */ -static struct dirent *readdir(DIR *dirp) -{ - DWORD attr; - if (dirp == NULL) { - /* directory stream did not open */ - DIRENT_SET_ERRNO (EBADF); - return NULL; - } - - /* get next directory entry */ - if (dirp->cached != 0) { - /* a valid directory entry already in memory */ - dirp->cached = 0; - } else { - /* get the next directory entry from stream */ - if (dirp->search_handle == INVALID_HANDLE_VALUE) { - return NULL; - } - if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) { - /* the very last entry has been processed or an error occurred */ - FindClose (dirp->search_handle); - dirp->search_handle = INVALID_HANDLE_VALUE; - return NULL; - } - } - - /* copy as a multibyte character string */ - DIRENT_STRNCPY ( dirp->curentry.d_name, - dirp->find_data.cFileName, - sizeof(dirp->curentry.d_name) ); - dirp->curentry.d_name[MAX_PATH] = '\0'; - - /* compute the length of name */ - dirp->curentry.d_namlen = strlen (dirp->curentry.d_name); - - /* determine file type */ - attr = dirp->find_data.dwFileAttributes; - if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - dirp->curentry.d_type = DT_CHR; - } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - dirp->curentry.d_type = DT_DIR; - } else { - dirp->curentry.d_type = DT_REG; - } - return &dirp->curentry; -} - - -/***************************************************************************** - * Close directory stream opened by opendir() function. Close of the - * directory stream invalidates the DIR structure as well as any previously - * read directory entry. - */ -static int closedir(DIR *dirp) -{ - if (dirp == NULL) { - /* invalid directory stream */ - DIRENT_SET_ERRNO (EBADF); - return -1; - } - - /* release search handle */ - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - FindClose (dirp->search_handle); - dirp->search_handle = INVALID_HANDLE_VALUE; - } - - /* release directory structure */ - free (dirp); - return 0; -} - - -/***************************************************************************** - * Resets the position of the directory stream to which dirp refers to the - * beginning of the directory. It also causes the directory stream to refer - * to the current state of the corresponding directory, as a call to opendir() - * would have done. If dirp does not refer to a directory stream, the effect - * is undefined. - */ -static void rewinddir(DIR* dirp) -{ - if (dirp != NULL) { - /* release search handle */ - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - FindClose (dirp->search_handle); - } - - /* open new search handle and retrieve the first entry */ - dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data); - if (dirp->search_handle != INVALID_HANDLE_VALUE) { - /* a directory entry is now waiting in memory */ - dirp->cached = 1; - } else { - /* failed to re-open directory: no directory entry in memory */ - dirp->cached = 0; - } - } -} - - -#ifdef __cplusplus -} -#endif -#endif /*DIRENT_H*/ diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index bf1114e5f..054b3d2bb 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -48,26 +48,10 @@ #include #include #include +#include #include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_FCNTL_H -#define __USE_GNU /* for O_PATH */ -#include -#undef __USE_GNU -#endif - -#ifdef _WIN32 -#pragma comment(lib, "Shlwapi.lib") -#include -#else -#include -#endif - #include "drive_file.h" #ifdef _WIN32 @@ -75,10 +59,18 @@ #pragma warning(disable: 4244) #endif -static void drive_file_fix_path(char* path) +#ifdef WITH_DEBUG_RDPDR +#define DEBUG_WSTR(msg, wstr) do { LPSTR lpstr; ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); WLog_DBG(TAG, msg, lpstr); free(lpstr); } while (0) +#else +#define DEBUG_WSTR(msg, wstr) do { } while (0) +#endif + + +static void drive_file_fix_path(WCHAR* path) { - size_t i; - size_t length = strlen(path); + int i; + int length; + length = (int) _wcslen(path); for (i = 0; i < length; i++) { @@ -102,14 +94,17 @@ static void drive_file_fix_path(char* path) path[length - 1] = '\0'; } -static char* drive_file_combine_fullpath(const char* base_path, const char* path) +static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path, + UINT32 PathLength) { - char* fullpath; + WCHAR* fullpath; + UINT32 base_path_length; if (!base_path || !path) return NULL; - fullpath = (char*) malloc(strlen(base_path) + strlen(path) + 1); + base_path_length = _wcslen(base_path) * 2; + fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR)); if (!fullpath) { @@ -117,91 +112,94 @@ static char* drive_file_combine_fullpath(const char* base_path, const char* path return NULL; } - strcpy(fullpath, base_path); - strcat(fullpath, path); + CopyMemory(fullpath, base_path, base_path_length); + CopyMemory((char*)fullpath + base_path_length, path, PathLength); drive_file_fix_path(fullpath); return fullpath; } -static BOOL drive_file_remove_dir(const char* path) +static BOOL drive_file_remove_dir(const WCHAR* path) { - DIR* dir; - char* p; - struct STAT st; - struct dirent* pdirent; + WIN32_FIND_DATAW findFileData; BOOL ret = TRUE; + INT len; + HANDLE dir; + WCHAR* fullpath; + WCHAR* path_slash; + UINT32 base_path_length; + base_path_length = _wcslen(path) * 2; + path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3); + + if (!path_slash) + { + WLog_ERR(TAG, "malloc failed!"); + return FALSE; + } if (!path) return FALSE; - dir = opendir(path); + CopyMemory(path_slash, path, base_path_length); + path_slash[base_path_length / 2] = '/'; + path_slash[base_path_length / 2 + 1] = '*'; + DEBUG_WSTR("Search in %s", path_slash); + dir = FindFirstFileW(path_slash, &findFileData); + path_slash[base_path_length / 2 + 1] = 0; - if (dir == NULL) - return FALSE; - - pdirent = readdir(dir); - - while (pdirent) + if (dir == INVALID_HANDLE_VALUE) { - if (strcmp(pdirent->d_name, ".") == 0 || strcmp(pdirent->d_name, "..") == 0) + free(path_slash); + return FALSE; + } + + do + { + len = _wcslen(findFileData.cFileName); + + if ((len == 1 && findFileData.cFileName[0] == '.') || (len == 2 && + findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.')) { - pdirent = readdir(dir); continue; } - p = (char*) malloc(strlen(path) + strlen(pdirent->d_name) + 2); + fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2); + DEBUG_WSTR("Delete %s", fullpath); - if (!p) + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - WLog_ERR(TAG, "malloc failed!"); - return FALSE; - } - - sprintf(p, "%s/%s", path, pdirent->d_name); - - if (STAT(p, &st) != 0) - { - ret = FALSE; - } - else if (S_ISDIR(st.st_mode)) - { - ret = drive_file_remove_dir(p); - } - else if (unlink(p) < 0) - { - ret = FALSE; + ret = drive_file_remove_dir(fullpath); } else { - ret = TRUE; + ret = DeleteFileW(fullpath); } - free(p); + free(fullpath); if (!ret) break; - - pdirent = readdir(dir); } + while (ret && FindNextFileW(dir, &findFileData) != 0); - closedir(dir); + FindClose(dir); if (ret) { - if (rmdir(path) < 0) + if (!RemoveDirectoryW(path)) { ret = FALSE; } } + free(path_slash); return ret; } -static void drive_file_set_fullpath(DRIVE_FILE* file, char* fullpath) +static void drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath) { free(file->fullpath); file->fullpath = fullpath; - file->filename = strrchr(file->fullpath, '/'); + file->filename = _wcsrchr(file->fullpath, 0x5c); if (file->filename == NULL) file->filename = file->fullpath; @@ -209,139 +207,126 @@ static void drive_file_set_fullpath(DRIVE_FILE* file, char* fullpath) file->filename += 1; } -static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 CreateDisposition, - UINT32 CreateOptions) +BOOL drive_file_init(DRIVE_FILE* file) { - struct STAT st; - BOOL exists; -#ifdef WIN32 - const static int mode = _S_IREAD | _S_IWRITE ; -#else - const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; - BOOL largeFile = FALSE; -#endif - int oflag = 0; + UINT CreateDisposition = 0; + DWORD dwAttr = GetFileAttributesW(file->fullpath); - if (STAT(file->fullpath, &st) == 0) + if (dwAttr != INVALID_FILE_ATTRIBUTES) { - file->is_dir = (S_ISDIR(st.st_mode) ? TRUE : FALSE); + /* The file exists */ + file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0; - if (!file->is_dir && !S_ISREG(st.st_mode)) + if (file->is_dir) { - file->err = EPERM; + if (file->CreateDisposition == FILE_CREATE) + { + SetLastError(ERROR_ALREADY_EXISTS); + return FALSE; + } + + if (file->CreateOptions & FILE_NON_DIRECTORY_FILE) + { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + return TRUE; } - -#ifndef WIN32 - - if (st.st_size > (unsigned long) 0x07FFFFFFF) - largeFile = TRUE; - -#endif - exists = TRUE; + else + { + if (file->CreateOptions & FILE_DIRECTORY_FILE) + { + SetLastError(ERROR_DIRECTORY); + return FALSE; + } + } } else { - file->is_dir = ((CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); + file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); if (file->is_dir) { /* Should only create the directory if the disposition allows for it */ - if ((CreateDisposition == FILE_OPEN_IF) || (CreateDisposition == FILE_CREATE)) + if ((file->CreateDisposition == FILE_OPEN_IF) || (file->CreateDisposition == FILE_CREATE)) { - if (mkdir(file->fullpath, mode) != 0) + if (CreateDirectoryW(file->fullpath, NULL) != 0) { - file->err = errno; return TRUE; } } - } - exists = FALSE; - } - - if (file->is_dir) - { - file->dir = opendir(file->fullpath); - - if (file->dir == NULL) - { - file->err = errno; - return TRUE; + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; } } - else + + if (file->file_handle == INVALID_HANDLE_VALUE) { - switch (CreateDisposition) + switch (file->CreateDisposition) { - case FILE_SUPERSEDE: - oflag = O_TRUNC | O_CREAT; + case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If it does not, create the given file. */ + CreateDisposition = CREATE_ALWAYS; break; - case FILE_OPEN: + case FILE_OPEN: /* If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file. */ + CreateDisposition = OPEN_EXISTING; break; - case FILE_CREATE: - oflag = O_CREAT | O_EXCL; + case FILE_CREATE: /* If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file. */ + CreateDisposition = CREATE_NEW; break; - case FILE_OPEN_IF: - oflag = O_CREAT; + case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the given file. */ + CreateDisposition = OPEN_ALWAYS; break; - case FILE_OVERWRITE: - oflag = O_TRUNC; + case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does not, fail the request. */ + CreateDisposition = TRUNCATE_EXISTING; break; - case FILE_OVERWRITE_IF: - oflag = O_TRUNC | O_CREAT; + case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it does not, create the given file. */ + CreateDisposition = CREATE_ALWAYS; break; default: break; } - if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (DesiredAccess & DELETE)) - { - file->delete_pending = TRUE; - } - - if ((DesiredAccess & GENERIC_ALL) - || (DesiredAccess & GENERIC_WRITE) - || (DesiredAccess & FILE_WRITE_DATA) - || (DesiredAccess & FILE_APPEND_DATA)) - { - oflag |= O_RDWR; - } - else - { - oflag |= O_RDONLY; - } - #ifndef WIN32 - - if (largeFile) - { - oflag |= O_LARGEFILE; - } - -#else - oflag |= O_BINARY; + file->SharedAccess = 0; #endif - file->fd = OPEN(file->fullpath, oflag, mode); + file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, + file->SharedAccess, NULL, CreateDisposition, + file->FileAttributes, NULL); + } - if (file->fd == -1) + if (file->file_handle == INVALID_HANDLE_VALUE) + { + /* Get the error message, if any. */ + DWORD errorMessageID = GetLastError(); + + if (errorMessageID != 0) { - file->err = errno; - return TRUE; +#ifdef WIN32 + LPSTR messageBuffer = NULL; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, file->fullpath); + /* Free the buffer. */ + LocalFree(messageBuffer); +#endif } } - return TRUE; + return file->file_handle != INVALID_HANDLE_VALUE; } -DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions) +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, + UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess) { DRIVE_FILE* file; file = (DRIVE_FILE*) calloc(1, sizeof(DRIVE_FILE)); @@ -352,62 +337,59 @@ DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id, return NULL; } + file->file_handle = INVALID_HANDLE_VALUE; + file->find_handle = INVALID_HANDLE_VALUE; file->id = id; - file->basepath = (char*) base_path; - drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path)); - file->fd = -1; + file->basepath = (WCHAR*) base_path; + file->FileAttributes = FileAttributes; + file->DesiredAccess = DesiredAccess; + file->CreateDisposition = CreateDisposition; + file->CreateOptions = CreateOptions; + file->SharedAccess = SharedAccess; + drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength)); - if (!drive_file_init(file, DesiredAccess, CreateDisposition, CreateOptions)) + if (!drive_file_init(file)) { drive_file_free(file); return NULL; } -#if defined(__linux__) && defined(O_PATH) - - if (file->fd < 0 && file->err == EACCES) - { - /** - * We have no access permissions for the file or directory but if the - * peer is only interested in reading the object's attributes we can try - * to obtain a file descriptor who's only purpose is to perform - * operations that act purely at the file descriptor level. - * See open(2) - **/ - { - if ((file->fd = OPEN(file->fullpath, O_PATH)) >= 0) - { - file->err = 0; - } - } - } - -#endif return file; } -void drive_file_free(DRIVE_FILE* file) +BOOL drive_file_free(DRIVE_FILE* file) { if (!file) return; - if (file->fd != -1) - close(file->fd); + if (file->file_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(file->file_handle); + file->file_handle = INVALID_HANDLE_VALUE; + } - if (file->dir != NULL) - closedir(file->dir); + if (file->find_handle != INVALID_HANDLE_VALUE) + { + FindClose(file->find_handle); + file->find_handle = INVALID_HANDLE_VALUE; + } if (file->delete_pending) { if (file->is_dir) drive_file_remove_dir(file->fullpath); - else - unlink(file->fullpath); + else if (!DeleteFileW(file->fullpath)) + { + free(file->fullpath); + free(file); + return FALSE; + } } - free(file->pattern); + DEBUG_WSTR("Free %s", file->fullpath); free(file->fullpath); free(file); + return TRUE; } BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset) @@ -415,53 +397,46 @@ BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset) if (!file) return FALSE; - if (file->is_dir || file->fd == -1) - return FALSE; - - if (LSEEK(file->fd, Offset, SEEK_SET) == (off_t) - 1) - return FALSE; - - return TRUE; + LONG lDistHigh = Offset >> 32; + DEBUG_WSTR("Seek %s", file->fullpath); + DWORD dwPtrLow = SetFilePointer(file->file_handle, Offset & 0xFFFFFFFF, &lDistHigh, FILE_BEGIN); + return dwPtrLow != INVALID_SET_FILE_POINTER; } BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length) { - ssize_t r; + UINT32 read; if (!file || !buffer || !Length) return FALSE; - if (file->is_dir || file->fd == -1) - return FALSE; + DEBUG_WSTR("Read file %s", file->fullpath); - r = read(file->fd, buffer, *Length); + if (ReadFile(file->file_handle, buffer, *Length, &read, NULL)) + { + *Length = read; + return TRUE; + } - if (r < 0) - return FALSE; - - *Length = (UINT32) r; - return TRUE; + return FALSE; } BOOL drive_file_write(DRIVE_FILE* file, BYTE* buffer, UINT32 Length) { - ssize_t r; + UINT32 written; if (!file || !buffer) return FALSE; - if (file->is_dir || file->fd == -1) - return FALSE; + DEBUG_WSTR("Write file %s", file->fullpath); while (Length > 0) { - r = write(file->fd, buffer, Length); - - if (r == -1) + if (!WriteFile(file->file_handle, buffer, Length, &written, NULL)) return FALSE; - Length -= r; - buffer += r; + Length -= written; + buffer += written; } return TRUE; @@ -469,17 +444,31 @@ BOOL drive_file_write(DRIVE_FILE* file, BYTE* buffer, UINT32 Length) BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output) { - struct STAT st; + WIN32_FIND_DATAW findFileData; + HANDLE hFind; + DEBUG_WSTR("FindFirstFile %s", file->fullpath); if (!file || !output) return FALSE; - if (STAT(file->fullpath, &st) != 0) + if ((hFind = FindFirstFileW(file->fullpath, &findFileData)) == INVALID_HANDLE_VALUE) { - Stream_Write_UINT32(output, 0); /* Length */ - return FALSE; +#ifdef WIN32 + ZeroMemory(&findFileData, sizeof(findFileData)); + findFileData.dwFileAttributes = GetFileAttributesW(file->fullpath); + + if (findFileData.dwFileAttributes == INVALID_FILE_ATTRIBUTES) + { + goto out_fail; + } + +#else + goto out_fail; +#endif } + FindClose(hFind); + switch (FsInformationClass) { case FileBasicInformation: @@ -489,11 +478,15 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 36); /* Length */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ - Stream_Write_UINT32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + Stream_Write_UINT32(output, findFileData.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, findFileData.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, findFileData.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, findFileData.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, findFileData.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, findFileData.dwFileAttributes); /* FileAttributes */ /* Reserved(4), MUST NOT be added! */ break; @@ -504,11 +497,14 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 22); /* Length */ - Stream_Write_UINT64(output, st.st_size); /* AllocationSize */ - Stream_Write_UINT64(output, st.st_size); /* EndOfFile */ - Stream_Write_UINT32(output, st.st_nlink); /* NumberOfLinks */ + Stream_Write_UINT32(output, findFileData.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, findFileData.nFileSizeHigh); /* AllocationSize */ + Stream_Write_UINT32(output, findFileData.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, findFileData.nFileSizeHigh); /* EndOfFile */ + Stream_Write_UINT32(output, 0); /* NumberOfLinks */ Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */ - Stream_Write_UINT8(output, file->is_dir ? 1 : 0); /* Directory */ + Stream_Write_UINT8(output, findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE : + FALSE); /* Directory */ /* Reserved(2), MUST NOT be added! */ break; @@ -519,14 +515,13 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 8); /* Length */ - Stream_Write_UINT32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + Stream_Write_UINT32(output, findFileData.dwFileAttributes); /* FileAttributes */ Stream_Write_UINT32(output, 0); /* ReparseTag */ break; default: /* Unhandled FsInformationClass */ - Stream_Write_UINT32(output, 0); /* Length */ - return FALSE; + goto out_fail; } return TRUE; @@ -535,38 +530,11 @@ out_fail: return FALSE; } -int dir_empty(const char* path) -{ -#ifdef _WIN32 - return PathIsDirectoryEmptyA(path); -#else - struct dirent* dp; - int empty = 1; - DIR* dir = opendir(path); - - if (dir == NULL) //Not a directory or doesn't exist - return 1; - - while ((dp = readdir(dir)) != NULL) - { - if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) - continue; /* Skip . and .. */ - - empty = 0; - break; - } - - closedir(dir); - return empty; -#endif -} BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { - char* s = NULL; INT64 size; - int status; - char* fullpath; + WCHAR* fullpath; ULARGE_INTEGER liCreationTime; ULARGE_INTEGER liLastAccessTime; ULARGE_INTEGER liLastWriteTime; @@ -579,8 +547,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN FILETIME* pftLastWriteTime = NULL; UINT32 FileAttributes; UINT32 FileNameLength; - HANDLE hFd; LARGE_INTEGER liSize; + UINT8 delete_pending; + UINT8 ReplaceIfExists; + DWORD attr; if (!file || !input) return FALSE; @@ -595,13 +565,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN Stream_Read_UINT64(input, liChangeTime.QuadPart); Stream_Read_UINT32(input, FileAttributes); - if (!PathFileExistsA(file->fullpath)) + if (!PathFileExistsW(file->fullpath)) return FALSE; - hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFd == INVALID_HANDLE_VALUE) + if (file->file_handle == INVALID_HANDLE_VALUE) { WLog_ERR(TAG, "Unable to create file %s", file->fullpath); return FALSE; @@ -635,14 +602,15 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN pftLastWriteTime = &ftLastWriteTime; } - if (!SetFileTime(hFd, pftCreationTime, pftLastAccessTime, pftLastWriteTime)) + DEBUG_WSTR("SetFileTime %s", file->fullpath); + + if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime)) { - WLog_ERR(TAG, "Unable to set file time on %s", file->fullpath); - CloseHandle(hFd); + WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath); return FALSE; } - CloseHandle(hFd); + SetFileAttributesW(file->fullpath, FileAttributes); break; case FileEndOfFileInformation: @@ -651,74 +619,83 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ Stream_Read_INT64(input, size); - hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (hFd == INVALID_HANDLE_VALUE) + if (file->file_handle == INVALID_HANDLE_VALUE) { WLog_ERR(TAG, "Unable to truncate %s to %"PRId64"", file->fullpath, size); return FALSE; } - liSize.QuadPart = size; - - if (SetFilePointer(hFd, liSize.LowPart, &liSize.HighPart, FILE_BEGIN) == 0) + if (SetFilePointer(file->file_handle, liSize.LowPart, &liSize.HighPart, + FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - WLog_ERR(TAG, "Unable to truncate %s to %"PRId64"", file->fullpath, size); - CloseHandle(hFd); + WLog_ERR(TAG, "Unable to truncate %s to %d (%d)", file->fullpath, size, GetLastError()); + return FALSE; + } + + DEBUG_WSTR("Truncate %s", file->fullpath); + + if (SetEndOfFile(file->file_handle) == 0) + { + WLog_ERR(TAG, "Unable to truncate %s to %d (%d)", file->fullpath, size, GetLastError()); return FALSE; } - CloseHandle(hFd); break; case FileDispositionInformation: /* http://msdn.microsoft.com/en-us/library/cc232098.aspx */ /* http://msdn.microsoft.com/en-us/library/cc241371.aspx */ - if (file->is_dir && !dir_empty(file->fullpath)) - break; + if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath)) + break; // TODO: SetLastError ??? if (Length) - Stream_Read_UINT8(input, file->delete_pending); + Stream_Read_UINT8(input, delete_pending); else - file->delete_pending = 1; + delete_pending = 1; + if (delete_pending) + { + DEBUG_WSTR("SetDeletePending %s", file->fullpath); + attr = GetFileAttributesW(file->fullpath); + + if (attr & FILE_ATTRIBUTE_READONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + + file->delete_pending = delete_pending; break; case FileRenameInformation: /* http://msdn.microsoft.com/en-us/library/cc232085.aspx */ - Stream_Seek_UINT8(input); /* ReplaceIfExists */ + Stream_Read_UINT8(input, ReplaceIfExists); Stream_Seek_UINT8(input); /* RootDirectory */ Stream_Read_UINT32(input, FileNameLength); - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input), - FileNameLength / 2, &s, 0, NULL, NULL); - - if (status < 1) - if (!(s = (char*) calloc(1, 1))) - { - WLog_ERR(TAG, "calloc failed!"); - return FALSE; - } - - fullpath = drive_file_combine_fullpath(file->basepath, s); + fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input), + FileNameLength); if (!fullpath) { WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); - free(s); return FALSE; } - free(s); #ifdef _WIN32 - - if (file->fd) - close(file->fd); + if (file->file_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(file->file_handle); + file->file_handle = INVALID_HANDLE_VALUE; + } #endif + DEBUG_WSTR("MoveFileExW %s", file->fullpath); - if (rename(file->fullpath, fullpath) == 0) + if (MoveFileExW(file->fullpath, fullpath, + MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0))) { drive_file_set_fullpath(file, fullpath); #ifdef _WIN32 @@ -731,6 +708,9 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; } +#ifdef _WIN32 + drive_file_init(file); +#endif break; default: @@ -741,86 +721,33 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN } BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const char* path, wStream* output) + const WCHAR* path, UINT32 PathLength, wStream* output) { int length; BOOL ret; WCHAR* ent_path; - struct STAT st; - struct dirent* ent; if (!file || !path || !output) return FALSE; - if (!file->dir) - { - Stream_Write_UINT32(output, 0); /* Length */ - Stream_Write_UINT8(output, 0); /* Padding */ - return FALSE; - } - if (InitialQuery != 0) { - rewinddir(file->dir); - free(file->pattern); + /* release search handle */ + if (file->find_handle != INVALID_HANDLE_VALUE) + FindClose(file->find_handle); - if (path[0]) - { - if (!(file->pattern = _strdup(strrchr(path, '\\') + 1))) - { - WLog_ERR(TAG, "_strdup failed!"); - return FALSE; - } - } - else - file->pattern = NULL; + ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength); + /* open new search handle and retrieve the first entry */ + file->find_handle = FindFirstFileW(ent_path, &file->find_data); + free(ent_path); + + if (file->find_handle == INVALID_HANDLE_VALUE) + goto out_fail; } + else if (!FindNextFileW(file->find_handle, &file->find_data)) + goto out_fail; - if (file->pattern) - { - do - { - ent = readdir(file->dir); - - if (ent == NULL) - continue; - - if (FilePatternMatchA(ent->d_name, file->pattern)) - break; - } - while (ent); - } - else - { - ent = readdir(file->dir); - } - - if (!ent) - { - Stream_Write_UINT32(output, 0); /* Length */ - Stream_Write_UINT8(output, 0); /* Padding */ - return FALSE; - } - - memset(&st, 0, sizeof(struct STAT)); - ent_path = (WCHAR*) malloc(strlen(file->fullpath) + strlen(ent->d_name) + 2); - - if (!ent_path) - { - WLog_ERR(TAG, "malloc failed!"); - return FALSE; - } - - sprintf((char*) ent_path, "%s/%s", file->fullpath, ent->d_name); - - if (STAT((char*) ent_path, &st) != 0) - { - } - - free(ent_path); - ent_path = NULL; - length = ConvertToUnicode(sys_code_page, 0, ent->d_name, -1, &ent_path, 0) * 2; - ret = TRUE; + length = _wcslen(file->find_data.cFileName) * 2; switch (FsInformationClass) { @@ -833,15 +760,21 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, 64 + length); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ - Stream_Write_UINT64(output, st.st_size); /* EndOfFile */ - Stream_Write_UINT64(output, st.st_size); /* AllocationSize */ - Stream_Write_UINT32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ Stream_Write_UINT32(output, length); /* FileNameLength */ - Stream_Write(output, ent_path, length); + Stream_Write(output, file->find_data.cFileName, length); break; case FileFullDirectoryInformation: @@ -853,16 +786,22 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, 68 + length); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ - Stream_Write_UINT64(output, st.st_size); /* EndOfFile */ - Stream_Write_UINT64(output, st.st_size); /* AllocationSize */ - Stream_Write_UINT32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ Stream_Write_UINT32(output, length); /* FileNameLength */ Stream_Write_UINT32(output, 0); /* EaSize */ - Stream_Write(output, ent_path, length); + Stream_Write(output, file->find_data.cFileName, length); break; case FileBothDirectoryInformation: @@ -874,19 +813,25 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, 93 + length); /* Length */ Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */ - Stream_Write_UINT64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */ - Stream_Write_UINT64(output, st.st_size); /* EndOfFile */ - Stream_Write_UINT64(output, st.st_size); /* AllocationSize */ - Stream_Write_UINT32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */ + Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */ + Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */ Stream_Write_UINT32(output, length); /* FileNameLength */ Stream_Write_UINT32(output, 0); /* EaSize */ Stream_Write_UINT8(output, 0); /* ShortNameLength */ /* Reserved(1), MUST NOT be added! */ Stream_Zero(output, 24); /* ShortName */ - Stream_Write(output, ent_path, length); + Stream_Write(output, file->find_data.cFileName, length); break; case FileNamesInformation: @@ -899,21 +844,16 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT Stream_Write_UINT32(output, 0); /* NextEntryOffset */ Stream_Write_UINT32(output, 0); /* FileIndex */ Stream_Write_UINT32(output, length); /* FileNameLength */ - Stream_Write(output, ent_path, length); + Stream_Write(output, file->find_data.cFileName, length); break; default: /* Unhandled FsInformationClass */ - Stream_Write_UINT32(output, 0); /* Length */ - Stream_Write_UINT8(output, 0); /* Padding */ - ret = FALSE; - break; + goto out_fail; } - free(ent_path); - return ret; + return TRUE; out_fail: - free(ent_path); Stream_Write_UINT32(output, 0); /* Length */ Stream_Write_UINT8(output, 0); /* Padding */ return FALSE; diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index 092e7d338..1cdfb3353 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -30,69 +30,6 @@ #include #include -#ifdef _WIN32 -#include -#include -#include "dirent.h" -#include "statvfs.h" -#else -#include -#ifdef ANDROID -#include -#else -#include -#endif -#endif - -#ifdef _WIN32 -#define STAT __stat64 -#define OPEN _open -#define close _close -#define read _read -#define write _write -#define LSEEK _lseeki64 -#define FSTAT _fstat64 -#define STATVFS statvfs -#define mkdir(a,b) _mkdir(a) -#define rmdir _rmdir -#define unlink(a) _unlink(a) -#define ftruncate(a,b) _chsize(a,b) - -typedef UINT32 ssize_t; -typedef UINT32 mode_t; - -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) -#define STAT stat -#define OPEN open -#define LSEEK lseek -#define FSTAT fstat -#define STATVFS statvfs -#define O_LARGEFILE 0 -#elif defined(ANDROID) -#define STAT stat -#define OPEN open -#define LSEEK lseek -#define FSTAT fstat -#define STATVFS statfs -#else -#define STAT stat64 -#define OPEN open64 -#define LSEEK lseek64 -#define FSTAT fstat64 -#define STATVFS statvfs64 -#endif - -#define EPOCH_DIFF 11644473600LL - -#define FILE_TIME_SYSTEM_TO_RDP(_t) \ - (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL) - -#define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \ - (S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \ - (_f->filename[0] == '.' ? FILE_ATTRIBUTE_HIDDEN : 0) | \ - (_f->delete_pending ? FILE_ATTRIBUTE_TEMPORARY : 0) | \ - (st.st_mode & S_IWUSR ? 0 : FILE_ATTRIBUTE_READONLY)) - #define TAG CHANNELS_TAG("drive.client") typedef struct _DRIVE_FILE DRIVE_FILE; @@ -101,28 +38,34 @@ struct _DRIVE_FILE { UINT32 id; BOOL is_dir; - int fd; - int err; - DIR* dir; - char* basepath; - char* fullpath; - char* filename; - char* pattern; + HANDLE file_handle; + HANDLE find_handle; + WIN32_FIND_DATAW find_data; + WCHAR* basepath; + WCHAR* fullpath; + WCHAR* filename; BOOL delete_pending; + UINT32 FileAttributes; + UINT32 SharedAccess; + UINT32 DesiredAccess; + UINT32 CreateDisposition; + UINT32 CreateOptions; }; -DRIVE_FILE* drive_file_new(const char* base_path, const char* path, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions); -void drive_file_free(DRIVE_FILE* file); +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, + UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess); +BOOL drive_file_free(DRIVE_FILE* file); +BOOL drive_file_open(DRIVE_FILE* file); BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset); BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length); BOOL drive_file_write(DRIVE_FILE* file, BYTE* buffer, UINT32 Length); BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output); -BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input); +BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, + wStream* input); BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const char* path, wStream* output); -int dir_empty(const char *path); + const WCHAR* path, UINT32 PathLength, wStream* output); extern UINT sys_code_page; diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 24c483f67..9ec196d2a 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -6,6 +6,7 @@ * Copyright 2010-2012 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +40,7 @@ #include #include +#include #include #include #include @@ -46,6 +48,7 @@ #include #include #include +#include #include @@ -57,7 +60,8 @@ struct _DRIVE_DEVICE { DEVICE device; - char* path; + WCHAR* path; + UINT32 PathLength; wListDictionary* files; HANDLE thread; @@ -68,37 +72,59 @@ struct _DRIVE_DEVICE rdpContext* rdpcontext; }; -static UINT32 drive_map_posix_err(int fs_errno) +static DWORD drive_map_windows_err(DWORD fs_errno) { - UINT32 rc; + DWORD rc; /* try to return NTSTATUS version of error code */ switch (fs_errno) { - case EPERM: - case EACCES: + case STATUS_SUCCESS: + rc = STATUS_SUCCESS; + break; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: rc = STATUS_ACCESS_DENIED; break; - case ENOENT: + case ERROR_FILE_NOT_FOUND: rc = STATUS_NO_SUCH_FILE; break; - case EBUSY: + case ERROR_BUSY_DRIVE: rc = STATUS_DEVICE_BUSY; break; - case EEXIST: + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: rc = STATUS_OBJECT_NAME_COLLISION; break; - case EISDIR: - rc = STATUS_FILE_IS_A_DIRECTORY; + case ERROR_INVALID_NAME: + rc = STATUS_NO_SUCH_FILE; + break; + + case ERROR_INVALID_HANDLE: + rc = STATUS_INVALID_HANDLE; + break; + + case ERROR_NO_MORE_FILES: + rc = STATUS_NO_MORE_FILES; + break; + + case ERROR_DIRECTORY: + rc = STATUS_NOT_A_DIRECTORY; + break; + + case ERROR_PATH_NOT_FOUND: + rc = STATUS_OBJECT_PATH_NOT_FOUND; break; default: rc = STATUS_UNSUCCESSFUL; + WLog_ERR(TAG, "Error code not found: %d", fs_errno); break; } @@ -120,54 +146,35 @@ static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id) */ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) { - int status; void* key; UINT32 FileId; DRIVE_FILE* file; BYTE Information; + UINT32 FileAttributes; + UINT32 SharedAccess; UINT32 DesiredAccess; UINT32 CreateDisposition; UINT32 CreateOptions; UINT32 PathLength; - char* path = NULL; + const WCHAR* path; Stream_Read_UINT32(irp->input, DesiredAccess); - Stream_Seek(irp->input, - 16); /* AllocationSize(8), FileAttributes(4), SharedAccess(4) */ + Stream_Seek(irp->input, 8); /* AllocationSize(8) */ + Stream_Read_UINT32(irp->input, FileAttributes); + Stream_Read_UINT32(irp->input, SharedAccess); Stream_Read_UINT32(irp->input, CreateDisposition); Stream_Read_UINT32(irp->input, CreateOptions); Stream_Read_UINT32(irp->input, PathLength); - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), - PathLength / 2, &path, 0, NULL, NULL); - - if (status < 1) - { - path = (char*) calloc(1, 1); - - if (!path) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - } - + path = (WCHAR*) Stream_Pointer(irp->input); FileId = irp->devman->id_sequence++; - file = drive_file_new(drive->path, path, FileId, - DesiredAccess, CreateDisposition, CreateOptions); + file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition, + CreateOptions, FileAttributes, SharedAccess); if (!file) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); FileId = 0; Information = 0; } - else if (file->err) - { - FileId = 0; - Information = 0; - /* map errno to windows result */ - irp->IoStatus = drive_map_posix_err(file->err); - drive_file_free(file); - } else { key = (void*)(size_t) file->id; @@ -175,7 +182,6 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) if (!ListDictionary_Add(drive->files, key, file)) { WLog_ERR(TAG, "ListDictionary_Add failed!"); - free(path); return ERROR_INTERNAL_ERROR; } @@ -204,7 +210,6 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) Stream_Write_UINT32(irp->output, FileId); Stream_Write_UINT8(irp->output, Information); - free(path); return irp->Complete(irp); } @@ -227,7 +232,11 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp) else { ListDictionary_Remove(drive->files, key); - drive_file_free(file); + + if (drive_file_free(file)) + irp->IoStatus = STATUS_SUCCESS; + else + irp->IoStatus = drive_map_windows_err(GetLastError()); } Stream_Zero(irp->output, 5); /* Padding(5) */ @@ -256,7 +265,7 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp) } else if (!drive_file_seek(file, Offset)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); Length = 0; } else @@ -271,7 +280,7 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp) if (!drive_file_read(file, buffer, &Length)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); free(buffer); buffer = NULL; Length = 0; @@ -317,12 +326,12 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp) } else if (!drive_file_seek(file, Offset)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); Length = 0; } else if (!drive_file_write(file, Stream_Pointer(irp->input), Length)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); Length = 0; } @@ -349,7 +358,7 @@ static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp) } else if (!drive_file_query_information(file, FsInformationClass, irp->output)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); } return irp->Complete(irp); @@ -377,16 +386,17 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp) else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input)) { - irp->IoStatus = STATUS_UNSUCCESSFUL; + irp->IoStatus = drive_map_windows_err(GetLastError()); } - if (file && file->is_dir && !dir_empty(file->fullpath)) + if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath)) irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY; Stream_Write_UINT32(irp->output, Length); return irp->Complete(irp); } + /** * Function description * @@ -397,15 +407,18 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, { UINT32 FsInformationClass; wStream* output = irp->output; - struct STATVFS svfst; - struct STAT st; char* volumeLabel = {"FREERDP"}; char* diskType = {"FAT32"}; WCHAR* outStr = NULL; int length; + DWORD lpSectorsPerCluster; + DWORD lpBytesPerSector; + DWORD lpNumberOfFreeClusters; + DWORD lpTotalNumberOfClusters; + WIN32_FILE_ATTRIBUTE_DATA wfad; Stream_Read_UINT32(irp->input, FsInformationClass); - STATVFS(drive->path, &svfst); - STAT(drive->path, &st); + GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters, + &lpTotalNumberOfClusters); switch (FsInformationClass) { @@ -421,13 +434,10 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT64(output, - FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* VolumeCreationTime */ -#ifdef ANDROID - Stream_Write_UINT32(output, svfst.f_fsid.__val[0]); /* VolumeSerialNumber */ -#else - Stream_Write_UINT32(output, svfst.f_fsid); /* VolumeSerialNumber */ -#endif + GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad); + Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */ + Stream_Write_UINT32(output, wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */ + Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */ Stream_Write_UINT32(output, length); /* VolumeLabelLength */ Stream_Write_UINT8(output, 0); /* SupportsObjects */ /* Reserved(1), MUST NOT be added! */ @@ -445,10 +455,10 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT64(output, svfst.f_blocks); /* TotalAllocationUnits */ - Stream_Write_UINT64(output, svfst.f_bavail); /* AvailableAllocationUnits */ - Stream_Write_UINT32(output, 1); /* SectorsPerAllocationUnit */ - Stream_Write_UINT32(output, svfst.f_bsize); /* BytesPerSector */ + Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */ + Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */ + Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ + Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ break; case FileFsAttributeInformation: @@ -466,12 +476,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK); /* FileSystemAttributes */ -#ifdef ANDROID - Stream_Write_UINT32(output, 255); /* MaximumComponentNameLength */ -#else - Stream_Write_UINT32(output, - svfst.f_namemax/*510*/); /* MaximumComponentNameLength */ -#endif + Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */ Stream_Write_UINT32(output, length); /* FileSystemNameLength */ Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */ free(outStr); @@ -487,12 +492,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT64(output, svfst.f_blocks); /* TotalAllocationUnits */ - Stream_Write_UINT64(output, - svfst.f_bavail); /* CallerAvailableAllocationUnits */ - Stream_Write_UINT64(output, svfst.f_bfree); /* AvailableAllocationUnits */ - Stream_Write_UINT32(output, 1); /* SectorsPerAllocationUnit */ - Stream_Write_UINT32(output, svfst.f_bsize); /* BytesPerSector */ + Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */ + Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */ + Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */ + Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ + Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ break; case FileFsDeviceInformation: @@ -541,8 +545,7 @@ static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp) */ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) { - char* path = NULL; - int status; + const WCHAR* path; DRIVE_FILE* file; BYTE InitialQuery; UINT32 PathLength; @@ -551,16 +554,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT8(irp->input, InitialQuery); Stream_Read_UINT32(irp->input, PathLength); Stream_Seek(irp->input, 23); /* Padding */ - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), - PathLength / 2, &path, 0, NULL, NULL); - - if (status < 1) - if (!(path = (char*) calloc(1, 1))) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } + path = (WCHAR*) Stream_Pointer(irp->input); file = drive_get_file_by_id(drive, irp->FileId); if (file == NULL) @@ -568,13 +563,12 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) irp->IoStatus = STATUS_UNSUCCESSFUL; Stream_Write_UINT32(irp->output, 0); /* Length */ } - else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, - path, irp->output)) + else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength, + irp->output)) { - irp->IoStatus = STATUS_NO_MORE_FILES; + irp->IoStatus = drive_map_windows_err(GetLastError()); } - free(path); return irp->Complete(irp); } @@ -714,8 +708,7 @@ static void* drive_thread_func(void* arg) } if (error && drive->rdpcontext) - setChannelError(drive->rdpcontext, error, - "drive_thread_func reported an error"); + setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error"); ExitThread((DWORD)error); return NULL; @@ -820,7 +813,7 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, for (i = 0; i <= length; i++) Stream_Write_UINT8(drive->device.data, name[i] < 0 ? '_' : name[i]); - drive->path = path; + ConvertToUnicode(sys_code_page, 0, path, -1, &drive->path, 0); drive->files = ListDictionary_New(TRUE); if (!drive->files) @@ -830,8 +823,7 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto out_error; } - ListDictionary_ValueObject(drive->files)->fnObjectFree = - (OBJECT_FREE_FN) drive_file_free; + ListDictionary_ValueObject(drive->files)->fnObjectFree = (OBJECT_FREE_FN) drive_file_free; drive->IrpQueue = MessageQueue_New(NULL); if (!drive->IrpQueue) @@ -848,8 +840,8 @@ UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto out_error; } - if (!(drive->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) drive_thread_func, drive, CREATE_SUSPENDED, NULL))) + if (!(drive->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) drive_thread_func, drive, + CREATE_SUSPENDED, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto out_error; diff --git a/channels/drive/client/statvfs.c b/channels/drive/client/statvfs.c deleted file mode 100644 index e92a97557..000000000 --- a/channels/drive/client/statvfs.c +++ /dev/null @@ -1,60 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * statvfs emulation for Windows - * - * Copyright 2012 Gerald Richter - * Copyright 2016 Inuvika Inc. - * Copyright 2016 David PHAM-VAN - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include - -#include "statvfs.h" - -int statvfs(const char *path, struct statvfs *buf) -{ - BOOL res; - int len; - LPWSTR unicodestr = NULL; - DWORD lpSectorsPerCluster; - DWORD lpBytesPerSector; - DWORD lpNumberOfFreeClusters; - DWORD lpTotalNumberOfClusters; - - len = ConvertToUnicode(CP_ACP, 0, path, -1, &unicodestr, 0); - if (len <= 0) - return -1; - - res = GetDiskFreeSpaceW(unicodestr, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters, &lpTotalNumberOfClusters); - free(unicodestr); - - buf->f_bsize = lpBytesPerSector; /* file system block size */ - buf->f_frsize = 0; /* fragment size */ - buf->f_blocks = lpTotalNumberOfClusters; /* size of fs in f_frsize units */ - buf->f_bfree = lpNumberOfFreeClusters; /* # free blocks */ - buf->f_bavail = lpNumberOfFreeClusters; /* # free blocks for unprivileged users */ - buf->f_files = 0; /* # inodes */ - buf->f_ffree = 0; /* # free inodes */ - buf->f_favail = 0; /* # free inodes for unprivileged users */ - buf->f_fsid = lpNumberOfFreeClusters & 0xffff; /* file system ID */ - buf->f_flag = 0; /* mount flags */ - buf->f_namemax = 250; /* maximum filename length */ - - return res; -} diff --git a/channels/drive/client/statvfs.h b/channels/drive/client/statvfs.h deleted file mode 100644 index 6912c29a4..000000000 --- a/channels/drive/client/statvfs.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * statvfs emulation for windows - * - * Copyright 2012 Gerald Richter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RDPDR_DISK_STATVFS_H -#define RDPDR_DISK_STATVFS_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned long long fsblkcnt_t; -typedef unsigned long long fsfilcnt_t; - -struct statvfs { - unsigned long f_bsize; /* file system block size */ - unsigned long f_frsize; /* fragment size */ - fsblkcnt_t f_blocks; /* size of fs in f_frsize units */ - fsblkcnt_t f_bfree; /* # free blocks */ - fsblkcnt_t f_bavail; /* # free blocks for unprivileged users */ - fsfilcnt_t f_files; /* # inodes */ - fsfilcnt_t f_ffree; /* # free inodes */ - fsfilcnt_t f_favail; /* # free inodes for unprivileged users */ - unsigned long f_fsid; /* file system ID */ - unsigned long f_flag; /* mount flags */ - unsigned long f_namemax; /* maximum filename length */ -}; - -int statvfs(const char *path, struct statvfs *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* RDPDR_DISK_STATVFS_H */ diff --git a/ci/cmake-preloads/config-linux-all.txt b/ci/cmake-preloads/config-linux-all.txt index ebad39185..dd3221b5b 100644 --- a/ci/cmake-preloads/config-linux-all.txt +++ b/ci/cmake-preloads/config-linux-all.txt @@ -30,6 +30,7 @@ set (WITH_DEBUG_RAIL OFF CACHE BOOL "enable debug") set (WITH_DEBUG_RDP OFF CACHE BOOL "enable debug") set (WITH_DEBUG_RDPEI OFF CACHE BOOL "enable debug") set (WITH_DEBUG_REDIR OFF CACHE BOOL "enable debug") +set (WITH_DEBUG_RDPDR OFF CACHE BOOL "enable debug") set (WITH_DEBUG_RFX OFF CACHE BOOL "enable debug") set (WITH_DEBUG_SCARD OFF CACHE BOOL "enable debug") set (WITH_DEBUG_SND OFF CACHE BOOL "enable debug") diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 905863eed..67b298e13 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -112,6 +112,7 @@ option(WITH_DEBUG_RAIL "Print RemoteApp debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_RDP "Print RDP debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_RDPEI "Print input virtual channel debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_REDIR "Redirection debug messages" ${DEFAULT_DEBUG_OPTION}) +option(WITH_DEBUG_RDPDR "Rdpdr debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_RFX "Print RemoteFX debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_SCARD "Print smartcard debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_SND "Print rdpsnd debug messages" ${DEFAULT_DEBUG_OPTION}) diff --git a/config.h.in b/config.h.in index 444171097..0c8ab218e 100644 --- a/config.h.in +++ b/config.h.in @@ -71,6 +71,7 @@ #cmakedefine WITH_DEBUG_RAIL #cmakedefine WITH_DEBUG_RDP #cmakedefine WITH_DEBUG_REDIR +#cmakedefine WITH_DEBUG_RDPDR #cmakedefine WITH_DEBUG_RFX #cmakedefine WITH_DEBUG_SCARD #cmakedefine WITH_DEBUG_SND