diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c index a0ae7c1..88fbe9a 100644 --- a/libvncserver/tightvnc-filetransfer/filetransfermsg.c +++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c @@ -27,8 +27,34 @@ #include #include #include + +#ifdef WIN32 +#include +#include +#include +#ifdef _MSC_VER +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR) +#define S_IWUSR S_IWRITE +#define S_IRUSR S_IREAD +#define S_IWOTH 0x0000002 +#define S_IROTH 0x0000004 +#define S_IWGRP 0x0000010 +#define S_IRGRP 0x0000020 +#define mkdir(path, perms) _mkdir(path) /* Match POSIX signature */ +/* Prevent POSIX deprecation warnings on MSVC */ +#define creat _creat +#define open _open +#define read _read +#define write _write +#define close _close +#define unlink _unlink +#endif /* _MSC_VER */ +#else #include #include +#endif + #include #include #include @@ -104,6 +130,125 @@ GetFileListResponseMsg(char* path, char flags) #define __FUNCTION__ "unknown" #endif +#ifdef WIN32 + +/* Most of the Windows version here is based on https://github.com/danielgindi/FileDir */ + +#define FILETIME_TO_TIME_T(FILETIME) (((((__int64)FILETIME.dwLowDateTime) | (((__int64)FILETIME.dwHighDateTime) << 32)) - 116444736000000000L) / 10000000L) + +#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM +#define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM)) +#else +#define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) 0 +#endif + +#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA +#define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA)) +#else +#define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) 0 +#endif + +#define IS_REGULAR_FILE(dwFileAttributes) \ + ( \ + !!(dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || \ + ( \ + !(dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && \ + !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && \ + !(dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && \ + !IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) && \ + !IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) && \ + !(dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && \ + !(dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) \ + ) \ + ) + +#define IS_FOLDER(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + +int +CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag) +{ + int pathLen, basePathLength; + char *basePath, *pChar; + WIN32_FIND_DATAA winFindData; + HANDLE findHandle; + + if(path == NULL) { + return FAILURE; + } + + if(strlen(path) == 0) { + /* In this case we will send the list of entries in ftp root*/ + sprintf(path, "%s%s", GetFtpRoot(), "/"); + } + + /* Create a search string, like C:\folder\* */ + + pathLen = strlen(path); + basePath = malloc(pathLen + 3); + memcpy(basePath, path, pathLen); + basePathLength = pathLen; + basePath[basePathLength] = '\\'; + basePath[basePathLength + 1] = '*'; + basePath[basePathLength + 2] = '\0'; + + /* Start a search */ + memset(&winFindData, 0, sizeof(winFindData)); + findHandle = FindFirstFileA(path, &winFindData); + + basePath[basePathLength] = '\0'; /* Restore to a basePath + \ */ + /* Convert \ to / */ + for(pChar = basePath; *pChar; pChar++) { + if (*pChar == '\\') { + *pChar = '/'; + } + } + + /* While we can find a next file do... + But ignore \. and '.. entries, which are current folder and parent folder respectively */ + while(findHandle != INVALID_HANDLE_VALUE && winFindData.cFileName[0] == '.' && + (winFindData.cFileName[1] == '\0' || + (winFindData.cFileName[1] == '.' && winFindData.cFileName[2] == '\0'))) { + char fullpath[PATH_MAX]; + fullpath[0] = 0; + + strncpy_s(fullpath, PATH_MAX, basePath, basePathLength); + strncpy_s(fullpath + basePathLength, PATH_MAX - basePathLength, winFindData.cFileName, (int)strlen(winFindData.cFileName)); + + if(IS_FOLDER(winFindData.dwFileAttributes)) { + if (AddFileListItemInfo(pFileListInfo, winFindData.cFileName, -1, 0) == 0) { + rfbLog("File [%s]: Method [%s]: Add directory %s in the" + " list failed\n", __FILE__, __FUNCTION__, fullpath); + continue; + } + } + else if(IS_REGULAR_FILE(winFindData.dwFileAttributes)) { + if(flag) { + unsigned int fileSize = (winFindData.nFileSizeHigh * (MAXDWORD+1)) + winFindData.nFileSizeLow; + if(AddFileListItemInfo(pFileListInfo, winFindData.cFileName, fileSize, FILETIME_TO_TIME_T(winFindData.ftLastWriteTime)) == 0) { + rfbLog("File [%s]: Method [%s]: Add file %s in the " + "list failed\n", __FILE__, __FUNCTION__, fullpath); + continue; + } + } + } + + if(FindNextFileA(findHandle, &winFindData) == 0) { + FindClose(findHandle); + findHandle = INVALID_HANDLE_VALUE; + } + } + + if(findHandle != INVALID_HANDLE_VALUE) { + FindClose(findHandle); + } + + free(basePath); + + return SUCCESS; +} + +#else /* WIN32 */ + int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag) { @@ -174,6 +319,8 @@ CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag) return SUCCESS; } +#endif + FileTransferMsg CreateFileListErrMsg(char flags)