From e62aaff3196349bf431538d8decb5ca461728607 Mon Sep 17 00:00:00 2001 From: Zhengyi Fu Date: Tue, 22 Mar 2022 16:25:40 +0800 Subject: [PATCH] winpr: add GetFileInformationByHandle --- winpr/include/winpr/file.h | 17 +++ winpr/libwinpr/file/file.c | 147 +++++++++++++++++++------- winpr/libwinpr/file/file.h | 3 + winpr/libwinpr/file/generic.c | 24 ++++- winpr/libwinpr/file/namedPipeClient.c | 3 +- winpr/libwinpr/handle/handle.h | 3 + 6 files changed, 154 insertions(+), 43 deletions(-) diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index b9a0614cb..7cbc7cdb7 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -216,6 +216,20 @@ typedef struct WCHAR cAlternateFileName[14]; } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW; +typedef struct +{ + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; +} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION; + typedef enum { FindExInfoStandard, @@ -312,6 +326,9 @@ extern "C" WINPR_API DWORD GetFileAttributesW(LPCWSTR lpFileName); + WINPR_API BOOL GetFileInformationByHandle(HANDLE hFile, + LPBY_HANDLE_FILE_INFORMATION lpFileInformation); + WINPR_API BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes); WINPR_API BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes); diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 8663c25ce..c1737d8c0 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -325,6 +325,69 @@ static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh) return (UINT32)(size & 0xFFFFFFFF); } +static BOOL FileGetFileInformationByHandle(HANDLE hFile, + LPBY_HANDLE_FILE_INFORMATION lpFileInformation) +{ + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + struct stat st; + UINT64 ft; + const char* lastSep; + + if (!pFile) + return FALSE; + if (!lpFileInformation) + return FALSE; + + if (fstat(fileno(pFile->fp), &st) == -1) + { + WLog_ERR(TAG, "fstat failed with %s [%#08X]", errno, strerror(errno)); + return FALSE; + } + + lpFileInformation->dwFileAttributes = 0; + + if (S_ISDIR(st.st_mode)) + lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + + if (lpFileInformation->dwFileAttributes == 0) + lpFileInformation->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; + + lastSep = strrchr(pFile->lpFileName, '/'); + + if (lastSep) + { + const char* name = lastSep + 1; + const size_t namelen = strlen(name); + + if ((namelen > 1) && (name[0] == '.') && (name[1] != '.')) + lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if (!(st.st_mode & S_IWUSR)) + lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; + +#ifdef _DARWIN_FEATURE_64_BIT_INODE + ft = STAT_TIME_TO_FILETIME(st.st_birthtime); +#else + ft = STAT_TIME_TO_FILETIME(st.st_ctime); +#endif + lpFileInformation->ftCreationTime.dwHighDateTime = ((UINT64)ft) >> 32ULL; + lpFileInformation->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF; + ft = STAT_TIME_TO_FILETIME(st.st_mtime); + lpFileInformation->ftLastWriteTime.dwHighDateTime = ((UINT64)ft) >> 32ULL; + lpFileInformation->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF; + ft = STAT_TIME_TO_FILETIME(st.st_atime); + lpFileInformation->ftLastAccessTime.dwHighDateTime = ((UINT64)ft) >> 32ULL; + lpFileInformation->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF; + lpFileInformation->nFileSizeHigh = ((UINT64)st.st_size) >> 32ULL; + lpFileInformation->nFileSizeLow = st.st_size & 0xFFFFFFFF; + lpFileInformation->dwVolumeSerialNumber = st.st_dev; + lpFileInformation->nNumberOfLinks = st.st_nlink; + lpFileInformation->nFileIndexHigh = (st.st_ino >> 4) & 0xFFFFFFFF; + lpFileInformation->nFileIndexLow = st.st_ino & 0xFFFFFFFF; + return TRUE; +} + static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) @@ -484,10 +547,10 @@ static BOOL FileUnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfByte static UINT64 FileTimeToUS(const FILETIME* ft) { - const UINT64 EPOCH_DIFF = 11644473600ULL * 1000000ULL; + const UINT64 EPOCH_DIFF_US = EPOCH_DIFF * 1000000ULL; UINT64 tmp = ((UINT64)ft->dwHighDateTime) << 32 | ft->dwLowDateTime; tmp /= 10; /* 100ns steps to 1us step */ - tmp -= EPOCH_DIFF; + tmp -= EPOCH_DIFF_US; return tmp; } @@ -586,44 +649,52 @@ static BOOL FileSetFileTime(HANDLE hFile, const FILETIME* lpCreationTime, return TRUE; } -static HANDLE_OPS fileOps = { FileIsHandled, - FileCloseHandle, - FileGetFd, - NULL, /* CleanupHandle */ - FileRead, - NULL, /* FileReadEx */ - NULL, /* FileReadScatter */ - FileWrite, - NULL, /* FileWriteEx */ - NULL, /* FileWriteGather */ - FileGetFileSize, - NULL, /* FlushFileBuffers */ - FileSetEndOfFile, - FileSetFilePointer, - FileSetFilePointerEx, - NULL, /* FileLockFile */ - FileLockFileEx, - FileUnlockFile, - FileUnlockFileEx, - FileSetFileTime }; +static HANDLE_OPS fileOps = { + FileIsHandled, + FileCloseHandle, + FileGetFd, + NULL, /* CleanupHandle */ + FileRead, + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + FileWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + FileGetFileSize, + NULL, /* FlushFileBuffers */ + FileSetEndOfFile, + FileSetFilePointer, + FileSetFilePointerEx, + NULL, /* FileLockFile */ + FileLockFileEx, + FileUnlockFile, + FileUnlockFileEx, + FileSetFileTime, + FileGetFileInformationByHandle, +}; static HANDLE_OPS shmOps = { - FileIsHandled, FileCloseHandle, - FileGetFd, NULL, /* CleanupHandle */ - FileRead, NULL, /* FileReadEx */ - NULL, /* FileReadScatter */ - FileWrite, NULL, /* FileWriteEx */ - NULL, /* FileWriteGather */ - NULL, /* FileGetFileSize */ - NULL, /* FlushFileBuffers */ - NULL, /* FileSetEndOfFile */ - NULL, /* FileSetFilePointer */ - NULL, /* SetFilePointerEx */ - NULL, /* FileLockFile */ - NULL, /* FileLockFileEx */ - NULL, /* FileUnlockFile */ - NULL, /* FileUnlockFileEx */ - NULL /* FileSetFileTime */ + FileIsHandled, + FileCloseHandle, + FileGetFd, + NULL, /* CleanupHandle */ + FileRead, + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + FileWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + NULL, /* FileGetFileSize */ + NULL, /* FlushFileBuffers */ + NULL, /* FileSetEndOfFile */ + NULL, /* FileSetFilePointer */ + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + NULL, /* FileLockFileEx */ + NULL, /* FileUnlockFile */ + NULL, /* FileUnlockFileEx */ + NULL, /* FileSetFileTime */ + FileGetFileInformationByHandle, }; static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create) diff --git a/winpr/libwinpr/file/file.h b/winpr/libwinpr/file/file.h index f6cf9097a..749ec5851 100644 --- a/winpr/libwinpr/file/file.h +++ b/winpr/libwinpr/file/file.h @@ -34,6 +34,9 @@ #include #include "../handle/handle.h" +#define EPOCH_DIFF 11644473600LL +#define STAT_TIME_TO_FILETIME(_t) (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL) + struct winpr_file { WINPR_HANDLE_DEF(); diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 732f78b11..b96c2f5f5 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -173,10 +173,6 @@ * Asynchronous I/O User Guide: * 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; @@ -537,6 +533,26 @@ DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName) return ret; } +BOOL GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation) +{ + ULONG Type; + WINPR_HANDLE* handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE*)hFile; + + if (handle->ops->GetFileInformationByHandle) + return handle->ops->GetFileInformationByHandle(handle, lpFileInformation); + + WLog_ERR(TAG, "GetFileInformationByHandle operation not implemented"); + return 0; +} + static char* append(char* buffer, size_t size, const char* append) { const size_t len = strnlen(buffer, size); diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c index 8b91d9f39..cf4bc481b 100644 --- a/winpr/libwinpr/file/namedPipeClient.c +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -121,7 +121,8 @@ static HANDLE_OPS ops = { NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ NULL, /* FileUnlockFileEx */ - NULL /* SetFileTime */ + NULL, /* SetFileTime */ + NULL, /* FileGetFileInformationByHandle */ }; static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 3c2c32faf..f6bf6ae7c 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -66,6 +66,8 @@ typedef BOOL (*pcWriteFileGather)(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArr DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped); typedef DWORD (*pcGetFileSize)(HANDLE handle, LPDWORD lpFileSizeHigh); +typedef BOOL (*pcGetFileInformationByHandle)(HANDLE handle, + LPBY_HANDLE_FILE_INFORMATION lpFileInformation); typedef BOOL (*pcFlushFileBuffers)(HANDLE hFile); typedef BOOL (*pcSetEndOfFile)(HANDLE handle); typedef DWORD (*pcSetFilePointer)(HANDLE handle, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, @@ -106,6 +108,7 @@ typedef struct pcUnlockFile UnlockFile; pcUnlockFileEx UnlockFileEx; pcSetFileTime SetFileTime; + pcGetFileInformationByHandle GetFileInformationByHandle; } HANDLE_OPS; struct winpr_handle