Rewrite drive channel using WinPR functions
authorDavid PHAM-VAN <d.phamvan@inuvika.com>
Wed, 30 Nov 2016 21:48:33 +0000 (13:48 -0800)
committerDavid PHAM-VAN <d.phamvan@inuvika.com>
Mon, 13 Mar 2017 21:18:46 +0000 (14:18 -0700)
channels/drive/client/CMakeLists.txt
channels/drive/client/dirent.h [deleted file]
channels/drive/client/drive_file.c
channels/drive/client/drive_file.h
channels/drive/client/drive_main.c
channels/drive/client/statvfs.c [deleted file]
channels/drive/client/statvfs.h [deleted file]
ci/cmake-preloads/config-linux-all.txt
cmake/ConfigOptions.cmake
config.h.in

index ba2d0f4..2c2be39 100644 (file)
@@ -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 (file)
index 7c61d6a..0000000
+++ /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 <windows.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-/* 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*/
index bf1114e..054b3d2 100644 (file)
 #include <winpr/path.h>
 #include <winpr/file.h>
 #include <winpr/stream.h>
+#include <winpr/shell.h>
 
 #include <freerdp/channels/rdpdr.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#define __USE_GNU /* for O_PATH */
-#include <fcntl.h>
-#undef __USE_GNU
-#endif
-
-#ifdef _WIN32
-#pragma comment(lib, "Shlwapi.lib")
-#include <Shlwapi.h>
-#else
-#include <winpr/path.h>
-#endif
-
 #include "drive_file.h"
 
 #ifdef _WIN32
 #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)
+       if (dir == INVALID_HANDLE_VALUE)
+       {
+               free(path_slash);
                return FALSE;
+       }
 
-       pdirent = readdir(dir);
-
-       while (pdirent)
+       do
        {
-               if (strcmp(pdirent->d_name, ".") == 0 || strcmp(pdirent->d_name, "..") == 0)
-               {
-                       pdirent = readdir(dir);
-                       continue;
-               }
-
-               p = (char*) malloc(strlen(path) + strlen(pdirent->d_name) + 2);
+               len = _wcslen(findFileData.cFileName);
 
-               if (!p)
+               if ((len == 1 && findFileData.cFileName[0] == '.') || (len == 2 &&
+                       findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
                {
-                       WLog_ERR(TAG, "malloc failed!");
-                       return FALSE;
+                       continue;
                }
 
-               sprintf(p, "%s/%s", path, pdirent->d_name);
+               fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2);
+               DEBUG_WSTR("Delete %s", fullpath);
 
-               if (STAT(p, &st) != 0)
-               {
-                       ret = FALSE;
-               }
-               else if (S_ISDIR(st.st_mode))
+               if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
-                       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;
-                       return TRUE;
-               }
-
-#ifndef WIN32
+                       if (file->CreateDisposition == FILE_CREATE)
+                       {
+                               SetLastError(ERROR_ALREADY_EXISTS);
+                               return FALSE;
+                       }
 
-               if (st.st_size > (unsigned long) 0x07FFFFFFF)
-                       largeFile = TRUE;
+                       if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
+                       {
+                               SetLastError(ERROR_ACCESS_DENIED);
+                               return FALSE;
+                       }
 
-#endif
-               exists = TRUE;
+                       return 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;
-
-       if (!drive_file_init(file, DesiredAccess, CreateDisposition, CreateOptions))
+       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))
        {
                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;
-
-       r = read(file->fd, buffer, *Length);
+       DEBUG_WSTR("Read file %s", file->fullpath);
 
-       if (r < 0)
-               return FALSE;
+       if (ReadFile(file->file_handle, buffer, *Length, &read, NULL))
+       {
+               *Length = read;
+               return TRUE;
+       }
 
-       *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(file->file_handle, liSize.LowPart, &liSize.HighPart,
+                                          FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+                       {
+                               WLog_ERR(TAG, "Unable to truncate %s to %d (%d)", file->fullpath, size, GetLastError());
+                               return FALSE;
+                       }
+
+                       DEBUG_WSTR("Truncate %s", file->fullpath);
 
-                       if (SetFilePointer(hFd, liSize.LowPart, &liSize.HighPart, FILE_BEGIN) == 0)
+                       if (SetEndOfFile(file->file_handle) == 0)
                        {
-                               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;
                        }
 
-                       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->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 (file->find_handle == INVALID_HANDLE_VALUE)
+                       goto out_fail;
        }
+       else if (!FindNextFileW(file->find_handle, &file->find_data))
+               goto out_fail;
 
-       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;
index 092e7d3..1cdfb33 100644 (file)
 #include <sys/stat.h>
 #include <freerdp/channels/log.h>
 
-#ifdef _WIN32
-#include <direct.h>
-#include <io.h>
-#include "dirent.h"
-#include "statvfs.h"
-#else
-#include <dirent.h>
-#ifdef ANDROID
-#include <sys/vfs.h>
-#else
-#include <sys/statvfs.h>
-#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;
 
index 24c483f..9ec196d 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  * Copyright 2015 Thincast Technologies GmbH
  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
  *
  * 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 <winpr/crt.h>
 #include <winpr/path.h>
+#include <winpr/file.h>
 #include <winpr/string.h>
 #include <winpr/synch.h>
 #include <winpr/thread.h>
@@ -46,6 +48,7 @@
 #include <winpr/environment.h>
 #include <winpr/interlocked.h>
 #include <winpr/collections.h>
+#include <winpr/shell.h>
 
 #include <freerdp/channels/rdpdr.h>
 
@@ -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 (file)
index e92a975..0000000
+++ /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 <d.phamvan@inuvika.com>
- *
- * 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 <string.h>
-#include <malloc.h>
-
-#include <winpr/crt.h>
-#include <winpr/windows.h>
-
-#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 (file)
index 6912c29..0000000
+++ /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 */
index ebad391..dd3221b 100644 (file)
@@ -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")
index 905863e..67b298e 100644 (file)
@@ -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})
index 4441710..0c8ab21 100644 (file)
@@ -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