From b89bfaaae4d3e49bb4df9a7cce84e62ae4fc3ea7 Mon Sep 17 00:00:00 2001 From: David PHAM-VAN Date: Wed, 30 Nov 2016 13:47:06 -0800 Subject: [PATCH] Add missing functions to WinPR --- winpr/include/winpr/file.h | 62 ++++++++++++ winpr/include/winpr/shell.h | 7 ++ winpr/libwinpr/file/file.c | 86 +++++++++++++++++ winpr/libwinpr/file/file.h | 3 + winpr/libwinpr/file/generic.c | 172 +++++++++++++++++++++++++++++++++- winpr/libwinpr/path/shell.c | 49 +++++++++- 6 files changed, 375 insertions(+), 4 deletions(-) diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 7b050ab34..f2610e787 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -3,6 +3,7 @@ * File Functions * * Copyright 2012 Marc-Andre Moreau + * 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. @@ -172,6 +173,13 @@ #define LOCKFILE_FAIL_IMMEDIATELY 1 #define LOCKFILE_EXCLUSIVE_LOCK 2 +#define MOVEFILE_REPLACE_EXISTING 0x1 +#define MOVEFILE_COPY_ALLOWED 0x2 +#define MOVEFILE_DELAY_UNTIL_REBOOT 0x4 +#define MOVEFILE_WRITE_THROUGH 0x8 +#define MOVEFILE_CREATE_HARDLINK 0x10 +#define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x20 + typedef union _FILE_SEGMENT_ELEMENT { PVOID64 Buffer; @@ -266,6 +274,34 @@ WINPR_API BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[ WINPR_API BOOL FlushFileBuffers(HANDLE hFile); +typedef struct _WIN32_FILE_ATTRIBUTE_DATA +{ + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; +} WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA; + +typedef enum _GET_FILEEX_INFO_LEVELS +{ + GetFileExInfoStandard, + GetFileExMaxInfoLevel +} GET_FILEEX_INFO_LEVELS; + +WINPR_API BOOL GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation); + +WINPR_API DWORD GetFileAttributesA(LPCSTR lpFileName); + +WINPR_API BOOL GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation); + +WINPR_API DWORD GetFileAttributesW(LPCWSTR lpFileName); + +WINPR_API BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes); + +WINPR_API BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes); + WINPR_API BOOL SetEndOfFile(HANDLE hFile); WINPR_API DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); @@ -314,6 +350,20 @@ WINPR_API HANDLE GetStdHandle(DWORD nStdHandle); WINPR_API BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle); +WINPR_API BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters); + +WINPR_API BOOL GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters); + +WINPR_API BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags); + +WINPR_API BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags); + +WINPR_API BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName); + +WINPR_API BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); + #ifdef __cplusplus } #endif @@ -326,6 +376,12 @@ WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOl #define FindNextFile FindNextFileW #define CreateDirectory CreateDirectoryW #define RemoveDirectory RemoveDirectoryW +#define GetFileAttributesEx GetFileAttributesExW +#define GetFileAttributes GetFileAttributesW +#define SetFileAttributes SetFileAttributesW +#define GetDiskFreeSpace GetDiskFreeSpaceW +#define MoveFileEx MoveFileExW +#define MoveFile MoveFileW #else #define CreateFile CreateFileA #define DeleteFile DeleteFileA @@ -334,6 +390,12 @@ WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOl #define FindNextFile FindNextFileA #define CreateDirectory CreateDirectoryA #define RemoveDirectory RemoveDirectoryA +#define GetFileAttributesEx GetFileAttributesExA +#define GetFileAttributes GetFileAttributesA +#define SetFileAttributes SetFileAttributesA +#define GetDiskFreeSpace GetDiskFreeSpaceA +#define MoveFileEx MoveFileExA +#define MoveFile MoveFileA #endif /* Extra Functions */ diff --git a/winpr/include/winpr/shell.h b/winpr/include/winpr/shell.h index 5093925f8..ceb22e827 100644 --- a/winpr/include/winpr/shell.h +++ b/winpr/include/winpr/shell.h @@ -3,6 +3,7 @@ * Shell Functions * * Copyright 2015 Dell Software + * 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. @@ -36,14 +37,20 @@ WINPR_API BOOL GetUserProfileDirectoryA(HANDLE hToken, LPSTR lpProfileDir, LPDWO WINPR_API BOOL GetUserProfileDirectoryW(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize); +WINPR_API BOOL PathIsDirectoryEmptyA(LPCSTR pszPath); + +WINPR_API BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath); + #ifdef __cplusplus } #endif #ifdef UNICODE #define GetUserProfileDirectory GetUserProfileDirectoryW +#define PathIsDirectoryEmpty PathIsDirectoryEmptyW #else #define GetUserProfileDirectory GetUserProfileDirectoryA +#define PathIsDirectoryEmpty PathIsDirectoryEmptyA #endif #endif diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index d42e3e658..1846c8ea4 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -4,6 +4,7 @@ * * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 Bernhard Miklautz + * 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. @@ -44,6 +45,13 @@ #include #include +#ifdef ANDROID +#include +#else +#include +#endif + + static BOOL FileIsHandled(HANDLE handle) { WINPR_FILE* pFile = (WINPR_FILE*) handle; @@ -532,6 +540,51 @@ static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDispositio } } +UINT32 map_posix_err(int fs_errno) +{ + UINT32 rc; + + /* try to return NTSTATUS version of error code */ + + switch (fs_errno) + { + case 0: + rc = STATUS_SUCCESS; + break; + + case EPERM: + case EACCES: + rc = ERROR_ACCESS_DENIED; + break; + + case ENOENT: + rc = ERROR_FILE_NOT_FOUND; + break; + + case EBUSY: + rc = ERROR_BUSY_DRIVE; + break; + + case EEXIST: + rc = ERROR_FILE_EXISTS; + break; + + case EISDIR: + rc = STATUS_FILE_IS_A_DIRECTORY; + break; + + case ENOTEMPTY: + rc = STATUS_DIRECTORY_NOT_EMPTY; + break; + + default: + rc = STATUS_UNSUCCESSFUL; + break; + } + + return rc; +} + static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { @@ -695,6 +748,39 @@ BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle) return FALSE; } +BOOL GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters) +{ +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#define STATVFS statvfs +#elif defined(ANDROID) +#define STATVFS statfs +#else +#define STATVFS statvfs +#endif + + struct STATVFS svfst; + STATVFS(lpRootPathName, &svfst); + *lpSectorsPerCluster = svfst.f_frsize; + *lpBytesPerSector = 1; + *lpNumberOfFreeClusters = svfst.f_bavail; + *lpTotalNumberOfClusters = svfst.f_blocks; + return TRUE; +} + +BOOL GetDiskFreeSpaceW(LPCWSTR lpwRootPathName, LPDWORD lpSectorsPerCluster, + LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters) +{ + LPSTR lpRootPathName; + BOOL ret; + + ConvertFromUnicode(CP_UTF8, 0, lpwRootPathName, -1, &lpRootPathName, 0, NULL, NULL); + ret = GetDiskFreeSpaceA(lpRootPathName, lpSectorsPerCluster, lpBytesPerSector, + lpNumberOfFreeClusters, lpTotalNumberOfClusters); + free(lpRootPathName); + return ret; +} + #endif /* _WIN32 */ #ifdef _UWP diff --git a/winpr/libwinpr/file/file.h b/winpr/libwinpr/file/file.h index af0916753..d7dfe1dc8 100644 --- a/winpr/libwinpr/file/file.h +++ b/winpr/libwinpr/file/file.h @@ -4,6 +4,7 @@ * * Copyright 2015 Armin Novak * Copyright 2015 Thincast Technologies GmbH + * 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. @@ -55,6 +56,8 @@ typedef struct winpr_file WINPR_FILE; HANDLE_CREATOR *GetFileHandleCreator(void); +UINT32 map_posix_err(int fs_errno); + #endif /* _WIN32 */ #endif /* WINPR_FILE_PRIV_H */ diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 1f2dc0508..77a9a81da 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -4,6 +4,7 @@ * * Copyright 2012 Marc-Andre Moreau * Copyright 2014 Hewlett-Packard Development Company, L.P. + * 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. @@ -44,6 +45,8 @@ #include #include #include +#include +#include #include #include @@ -173,6 +176,10 @@ * http://code.google.com/p/kernel/wiki/AIOUserGuide */ +#define EPOCH_DIFF 11644473600LL +#define STAT_TIME_TO_FILETIME(_t) (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL) + + static wArrayList *_HandleCreators; static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT; @@ -461,6 +468,94 @@ BOOL FlushFileBuffers(HANDLE hFile) return FALSE; } +BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation) +{ + LPWIN32_FILE_ATTRIBUTE_DATA fd = lpFileInformation; + WIN32_FIND_DATAA findFileData; + HANDLE hFind; + + if (!(hFind = FindFirstFileA(lpFileName, &findFileData) == INVALID_HANDLE_VALUE)) + FindClose(hFind); + + fd->dwFileAttributes = findFileData.dwFileAttributes; + fd->ftCreationTime = findFileData.ftCreationTime; + fd->ftLastAccessTime = findFileData.ftLastAccessTime; + fd->ftLastWriteTime = findFileData.ftLastWriteTime; + fd->nFileSizeHigh = findFileData.nFileSizeHigh; + fd->nFileSizeLow = findFileData.nFileSizeLow; + return TRUE; +} + +BOOL WINAPI GetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, + LPVOID lpFileInformation) +{ + BOOL ret; + LPSTR lpCFileName; + ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL); + ret = GetFileAttributesExA(lpCFileName, fInfoLevelId, lpFileInformation); + free(lpCFileName); + return ret; +} + +DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName) +{ + WIN32_FIND_DATAA findFileData; + HANDLE hFind; + + if ((hFind = FindFirstFileA(lpFileName, &findFileData)) == INVALID_HANDLE_VALUE) + return INVALID_FILE_ATTRIBUTES; + + FindClose(hFind); + return findFileData.dwFileAttributes; +} + +DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName) +{ + DWORD ret; + LPSTR lpCFileName; + ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL); + ret = GetFileAttributesA(lpCFileName); + free(lpCFileName); + return ret; +} + +BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) +{ + struct stat st; + + if (stat(lpFileName, &st) != 0) + { + return FALSE; + } + + if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) + { + st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + } + else + { + st.st_mode |= S_IWUSR; + } + + if (chmod(lpFileName, st.st_mode) != 0) + { + return FALSE; + } + + return TRUE; +} + +BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) +{ + BOOL ret; + LPSTR lpCFileName; + ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL); + ret = SetFileAttributesA(lpCFileName,dwFileAttributes); + free(lpCFileName); + return ret; +} + BOOL SetEndOfFile(HANDLE hFile) { ULONG Type; @@ -816,17 +911,88 @@ BOOL CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttribu BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { - return FALSE; + char* utfPathName = NULL; + BOOL ret; + + ConvertFromUnicode(CP_UTF8, 0, lpPathName, -1, &utfPathName, 0, NULL, NULL); + ret = CreateDirectoryA(utfPathName, lpSecurityAttributes); + free(utfPathName); + return ret; } BOOL RemoveDirectoryA(LPCSTR lpPathName) { - return (rmdir(lpPathName) == 0); + int ret = rmdir(lpPathName); + if (ret != 0) + SetLastError(map_posix_err(errno)); + else + SetLastError(STATUS_SUCCESS); + return ret == 0; } BOOL RemoveDirectoryW(LPCWSTR lpPathName) { - return FALSE; + char* utfPathName = NULL; + BOOL ret; + + ConvertFromUnicode(CP_UTF8, 0, lpPathName, -1, &utfPathName, 0, NULL, NULL); + ret = RemoveDirectoryA(utfPathName); + free(utfPathName); + return ret; +} + +BOOL MoveFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags) +{ + struct stat st; + int ret; + ret = stat(lpNewFileName, &st); + + if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0) + { + if (ret == 0) + { + SetLastError(ERROR_ALREADY_EXISTS); + return FALSE; + } + } + else + { + if (ret == 0 && (st.st_mode & S_IWUSR) == 0) + { + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + } + + ret = rename(lpExistingFileName, lpNewFileName); + + if (ret != 0) + SetLastError(map_posix_err(errno)); + + return ret == 0; +} + +BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, DWORD dwFlags) +{ + LPSTR lpCExistingFileName; + LPSTR lpCNewFileName; + BOOL ret; + ConvertFromUnicode(CP_UTF8, 0, lpExistingFileName, -1, &lpCExistingFileName, 0, NULL, NULL); + ConvertFromUnicode(CP_UTF8, 0, lpNewFileName, -1, &lpCNewFileName, 0, NULL, NULL); + ret = MoveFileExA(lpCExistingFileName, lpCNewFileName, dwFlags); + free(lpCNewFileName); + free(lpCExistingFileName); + return ret; +} + +BOOL MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName) +{ + return MoveFileExA(lpExistingFileName, lpNewFileName, 0); +} + +BOOL MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) +{ + return MoveFileExW(lpExistingFileName, lpNewFileName, 0); } #endif diff --git a/winpr/libwinpr/path/shell.c b/winpr/libwinpr/path/shell.c index 386cac37d..785197fc9 100644 --- a/winpr/libwinpr/path/shell.c +++ b/winpr/libwinpr/path/shell.c @@ -3,6 +3,7 @@ * Path Functions * * Copyright 2012 Marc-Andre Moreau + * 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. @@ -43,6 +44,7 @@ #include #else #include +#include #endif static char* GetPath_XDG_CONFIG_HOME(void); @@ -505,9 +507,54 @@ BOOL PathFileExistsA(LPCSTR pszPath) BOOL PathFileExistsW(LPCWSTR pszPath) { - return FALSE; + LPSTR lpFileNameA = NULL; + BOOL ret; + + if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1) + return FALSE; + + ret = PathFileExistsA(lpFileNameA); + free (lpFileNameA); + + return ret; } +BOOL PathIsDirectoryEmptyA(LPCSTR pszPath) +{ + struct dirent *dp; + int empty = 1; + + DIR *dir = opendir(pszPath); + 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; +} + + +BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath) +{ + LPSTR lpFileNameA = NULL; + BOOL ret; + + if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1) + return FALSE; + + ret = PathIsDirectoryEmptyA(lpFileNameA); + free (lpFileNameA); + + return ret; +} + + #else #ifdef _WIN32