FreeRDP/winpr/libwinpr/file/generic.c

1351 lines
33 KiB
C
Raw Normal View History

/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
2016-12-01 00:47:06 +03:00
* 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.
*/
2022-02-16 12:08:00 +03:00
#include <winpr/config.h>
#include <winpr/crt.h>
2022-06-03 11:25:30 +03:00
#include <winpr/string.h>
2013-07-30 18:57:54 +04:00
#include <winpr/path.h>
#include <winpr/file.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef WINPR_HAVE_FCNTL_H
#include <fcntl.h>
#endif
2014-08-18 19:22:22 +04:00
#include "../log.h"
#define TAG WINPR_TAG("file")
#ifdef _WIN32
#include <io.h>
#include <sys/stat.h>
#else
2021-06-09 15:03:34 +03:00
#include <winpr/assert.h>
#include <pthread.h>
#include <dirent.h>
2016-12-01 00:47:06 +03:00
#include <libgen.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#ifdef WINPR_HAVE_AIO_H
#undef WINPR_HAVE_AIO_H /* disable for now, incomplete */
#endif
#ifdef WINPR_HAVE_AIO_H
#include <aio.h>
#endif
#ifdef ANDROID
#include <sys/vfs.h>
#else
#include <sys/statvfs.h>
#endif
#include "../handle/handle.h"
#include "../pipe/pipe.h"
2014-08-18 19:22:22 +04:00
#include "file.h"
/**
* api-ms-win-core-file-l1-2-0.dll:
*
* CreateFileA
* CreateFileW
* CreateFile2
* DeleteFileA
* DeleteFileW
* CreateDirectoryA
* CreateDirectoryW
* RemoveDirectoryA
* RemoveDirectoryW
* CompareFileTime
* DefineDosDeviceW
* DeleteVolumeMountPointW
* FileTimeToLocalFileTime
* LocalFileTimeToFileTime
* FindClose
* FindCloseChangeNotification
* FindFirstChangeNotificationA
* FindFirstChangeNotificationW
* FindFirstFileA
* FindFirstFileExA
* FindFirstFileExW
* FindFirstFileW
* FindFirstVolumeW
* FindNextChangeNotification
* FindNextFileA
* FindNextFileW
* FindNextVolumeW
* FindVolumeClose
* GetDiskFreeSpaceA
* GetDiskFreeSpaceExA
* GetDiskFreeSpaceExW
* GetDiskFreeSpaceW
* GetDriveTypeA
* GetDriveTypeW
* GetFileAttributesA
* GetFileAttributesExA
* GetFileAttributesExW
* GetFileAttributesW
* GetFileInformationByHandle
* GetFileSize
* GetFileSizeEx
* GetFileTime
* GetFileType
* GetFinalPathNameByHandleA
* GetFinalPathNameByHandleW
* GetFullPathNameA
* GetFullPathNameW
* GetLogicalDrives
* GetLogicalDriveStringsW
* GetLongPathNameA
* GetLongPathNameW
* GetShortPathNameW
* GetTempFileNameW
* GetTempPathW
* GetVolumeInformationByHandleW
* GetVolumeInformationW
* GetVolumeNameForVolumeMountPointW
* GetVolumePathNamesForVolumeNameW
* GetVolumePathNameW
* QueryDosDeviceW
* SetFileAttributesA
* SetFileAttributesW
* SetFileTime
* SetFileValidData
2012-09-26 20:37:35 +04:00
* SetFileInformationByHandle
* ReadFile
* ReadFileEx
* ReadFileScatter
* WriteFile
* WriteFileEx
* WriteFileGather
2012-09-26 20:37:35 +04:00
* FlushFileBuffers
* SetEndOfFile
* SetFilePointer
* SetFilePointerEx
* LockFile
* LockFileEx
* UnlockFile
* UnlockFileEx
*/
2012-10-18 23:37:00 +04:00
/**
* File System Behavior in the Microsoft Windows Environment:
* http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf
*/
/**
* Asynchronous I/O - The GNU C Library:
* http://www.gnu.org/software/libc/manual/html_node/Asynchronous-I_002fO.html
*/
/**
* aio.h - asynchronous input and output:
* http://pubs.opengroup.org/onlinepubs/009695399/basedefs/aio.h.html
*/
/**
* Asynchronous I/O User Guide:
* http://code.google.com/p/kernel/wiki/AIOUserGuide
*/
2017-04-27 09:31:53 +03:00
static wArrayList* _HandleCreators;
static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
2015-03-11 17:10:52 +03:00
2019-11-20 13:30:14 +03:00
extern HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void);
#if defined __linux__ && !defined ANDROID
#include "../comm/comm.h"
#endif /* __linux__ && !defined ANDROID */
2015-03-11 19:57:01 +03:00
static void _HandleCreatorsInit(void)
{
2021-06-09 15:03:34 +03:00
WINPR_ASSERT(_HandleCreators == NULL);
_HandleCreators = ArrayList_New(TRUE);
2017-04-27 09:31:53 +03:00
if (!_HandleCreators)
return;
/*
* Register all file handle creators.
*/
ArrayList_Append(_HandleCreators, GetNamedPipeClientHandleCreator());
#if defined __linux__ && !defined ANDROID
ArrayList_Append(_HandleCreators, GetCommHandleCreator());
#endif /* __linux__ && !defined ANDROID */
ArrayList_Append(_HandleCreators, GetFileHandleCreator());
}
#ifdef WINPR_HAVE_AIO_H
static BOOL g_AioSignalHandlerInstalled = FALSE;
2014-08-18 21:34:47 +04:00
void AioSignalHandler(int signum, siginfo_t* siginfo, void* arg)
{
2014-08-18 19:22:22 +04:00
WLog_INFO("%d", signum);
}
int InstallAioSignalHandler()
{
if (!g_AioSignalHandlerInstalled)
{
struct sigaction action;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGIO);
action.sa_flags = SA_SIGINFO;
2019-11-06 17:24:51 +03:00
action.sa_sigaction = (void*)&AioSignalHandler;
sigaction(SIGIO, &action, NULL);
g_AioSignalHandlerInstalled = TRUE;
}
return 0;
}
#endif /* WINPR_HAVE_AIO_H */
2017-04-27 09:31:53 +03:00
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
2019-11-06 17:24:51 +03:00
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
2020-11-10 10:14:56 +03:00
size_t i;
if (!lpFileName)
return INVALID_HANDLE_VALUE;
if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return INVALID_HANDLE_VALUE;
}
if (_HandleCreators == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return INVALID_HANDLE_VALUE;
}
ArrayList_Lock(_HandleCreators);
2017-04-27 09:31:53 +03:00
for (i = 0; i <= ArrayList_Count(_HandleCreators); i++)
{
HANDLE_CREATOR* creator = ArrayList_GetItem(_HandleCreators, i);
if (creator && creator->IsHandled(lpFileName))
{
2019-11-06 17:24:51 +03:00
HANDLE newHandle =
creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
ArrayList_Unlock(_HandleCreators);
return newHandle;
}
}
ArrayList_Unlock(_HandleCreators);
return INVALID_HANDLE_VALUE;
}
2017-04-27 09:31:53 +03:00
HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
2019-11-06 17:24:51 +03:00
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
HANDLE hdl = NULL;
if (!lpFileName)
return NULL;
char* lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName, NULL);
if (!lpFileNameA)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
2017-04-27 09:31:53 +03:00
hdl = CreateFileA(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
fail:
2017-04-27 09:31:53 +03:00
free(lpFileNameA);
return hdl;
}
BOOL DeleteFileA(LPCSTR lpFileName)
{
int status;
status = unlink(lpFileName);
return (status != -1) ? TRUE : FALSE;
}
BOOL DeleteFileW(LPCWSTR lpFileName)
{
if (!lpFileName)
return FALSE;
LPSTR lpFileNameA = ConvertWCharToUtf8Alloc(lpFileName, NULL);
BOOL rc = FALSE;
if (!lpFileNameA)
goto fail;
2017-04-27 09:31:53 +03:00
rc = DeleteFileA(lpFileNameA);
fail:
2017-04-27 09:31:53 +03:00
free(lpFileNameA);
return rc;
}
2012-09-26 20:37:35 +04:00
BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
2017-04-27 09:31:53 +03:00
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
/*
* from http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
* lpNumberOfBytesRead can be NULL only when the lpOverlapped parameter is not NULL.
*/
if (!lpNumberOfBytesRead && !lpOverlapped)
return FALSE;
2015-07-03 10:36:58 +03:00
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->ReadFile)
2019-11-06 17:24:51 +03:00
return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
lpOverlapped);
WLog_ERR(TAG, "ReadFile operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
2017-04-27 09:31:53 +03:00
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->ReadFileEx)
2019-11-06 17:24:51 +03:00
return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, lpOverlapped,
lpCompletionRoutine);
WLog_ERR(TAG, "ReadFileEx operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
2019-11-06 17:24:51 +03:00
BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytesToRead,
LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->ReadFileScatter)
2019-11-06 17:24:51 +03:00
return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, lpReserved,
lpOverlapped);
WLog_ERR(TAG, "ReadFileScatter operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
2017-04-27 09:31:53 +03:00
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
2015-07-03 10:36:58 +03:00
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->WriteFile)
return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite,
2017-04-27 09:31:53 +03:00
lpNumberOfBytesWritten, lpOverlapped);
WLog_ERR(TAG, "WriteFile operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
2017-04-27 09:31:53 +03:00
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->WriteFileEx)
2019-11-06 17:24:51 +03:00
return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, lpOverlapped,
lpCompletionRoutine);
WLog_ERR(TAG, "WriteFileEx operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[],
2017-04-27 09:31:53 +03:00
DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->WriteFileGather)
return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite,
2017-04-27 09:31:53 +03:00
lpReserved, lpOverlapped);
WLog_ERR(TAG, "WriteFileGather operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL FlushFileBuffers(HANDLE hFile)
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->FlushFileBuffers)
return handle->ops->FlushFileBuffers(handle);
WLog_ERR(TAG, "FlushFileBuffers operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
2016-12-01 00:47:06 +03:00
BOOL WINAPI GetFileAttributesExA(LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
2017-04-06 01:35:03 +03:00
LPVOID lpFileInformation)
2016-12-01 00:47:06 +03:00
{
LPWIN32_FILE_ATTRIBUTE_DATA fd = lpFileInformation;
WIN32_FIND_DATAA findFileData;
HANDLE hFind;
2018-07-30 11:46:20 +03:00
if (!fd)
return FALSE;
if ((hFind = FindFirstFileA(lpFileName, &findFileData)) == INVALID_HANDLE_VALUE)
return FALSE;
FindClose(hFind);
2016-12-01 00:47:06 +03:00
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,
2017-04-06 01:35:03 +03:00
LPVOID lpFileInformation)
2016-12-01 00:47:06 +03:00
{
BOOL ret;
if (!lpFileName)
return FALSE;
LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, NULL);
if (!lpCFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
2016-12-01 00:47:06 +03:00
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;
if (!lpFileName)
return FALSE;
LPSTR lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, NULL);
if (!lpCFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
2016-12-01 00:47:06 +03:00
ret = GetFileAttributesA(lpCFileName);
free(lpCFileName);
return ret;
}
2022-03-22 11:25:40 +03:00
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)
{
2022-06-03 11:25:30 +03:00
winpr_str_append(append, buffer, size, "|");
return buffer;
}
static const char* flagsToStr(char* buffer, size_t size, DWORD flags)
{
char strflags[32] = { 0 };
if (flags & FILE_ATTRIBUTE_READONLY)
append(buffer, size, "FILE_ATTRIBUTE_READONLY");
if (flags & FILE_ATTRIBUTE_HIDDEN)
append(buffer, size, "FILE_ATTRIBUTE_HIDDEN");
if (flags & FILE_ATTRIBUTE_SYSTEM)
append(buffer, size, "FILE_ATTRIBUTE_SYSTEM");
if (flags & FILE_ATTRIBUTE_DIRECTORY)
append(buffer, size, "FILE_ATTRIBUTE_DIRECTORY");
if (flags & FILE_ATTRIBUTE_ARCHIVE)
append(buffer, size, "FILE_ATTRIBUTE_ARCHIVE");
if (flags & FILE_ATTRIBUTE_DEVICE)
append(buffer, size, "FILE_ATTRIBUTE_DEVICE");
if (flags & FILE_ATTRIBUTE_NORMAL)
append(buffer, size, "FILE_ATTRIBUTE_NORMAL");
if (flags & FILE_ATTRIBUTE_TEMPORARY)
append(buffer, size, "FILE_ATTRIBUTE_TEMPORARY");
if (flags & FILE_ATTRIBUTE_SPARSE_FILE)
append(buffer, size, "FILE_ATTRIBUTE_SPARSE_FILE");
if (flags & FILE_ATTRIBUTE_REPARSE_POINT)
append(buffer, size, "FILE_ATTRIBUTE_REPARSE_POINT");
if (flags & FILE_ATTRIBUTE_COMPRESSED)
append(buffer, size, "FILE_ATTRIBUTE_COMPRESSED");
if (flags & FILE_ATTRIBUTE_OFFLINE)
append(buffer, size, "FILE_ATTRIBUTE_OFFLINE");
if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
append(buffer, size, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED");
if (flags & FILE_ATTRIBUTE_ENCRYPTED)
append(buffer, size, "FILE_ATTRIBUTE_ENCRYPTED");
if (flags & FILE_ATTRIBUTE_VIRTUAL)
append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL");
_snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags);
2022-06-03 11:25:30 +03:00
winpr_str_append(strflags, buffer, size, NULL);
return buffer;
}
2016-12-01 00:47:06 +03:00
BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
{
struct stat st;
int fd;
BOOL rc = FALSE;
2016-12-01 00:47:06 +03:00
if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
2016-12-01 00:47:06 +03:00
{
char buffer[8192] = { 0 };
const char* flags =
flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
WLog_WARN(TAG, "Unsupported flags %s, ignoring!", flags);
2016-12-01 00:47:06 +03:00
}
fd = open(lpFileName, O_RDONLY);
if (fd < 0)
return FALSE;
if (fstat(fd, &st) != 0)
goto fail;
2016-12-01 00:47:06 +03:00
if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{
st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
else
{
st.st_mode |= S_IWUSR;
}
if (fchmod(fd, st.st_mode) != 0)
goto fail;
2016-12-01 00:47:06 +03:00
rc = TRUE;
fail:
close(fd);
return rc;
2016-12-01 00:47:06 +03:00
}
BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
{
BOOL ret;
LPSTR lpCFileName;
if (!lpFileName)
return FALSE;
if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
{
char buffer[8192] = { 0 };
const char* flags =
flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
WLog_WARN(TAG, "Unsupported flags %s, ignoring!", flags);
}
lpCFileName = ConvertWCharToUtf8Alloc(lpFileName, NULL);
if (!lpCFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
2017-04-27 09:31:53 +03:00
ret = SetFileAttributesA(lpCFileName, dwFileAttributes);
2016-12-01 00:47:06 +03:00
free(lpCFileName);
return ret;
}
2012-09-26 20:37:35 +04:00
BOOL SetEndOfFile(HANDLE hFile)
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->SetEndOfFile)
return handle->ops->SetEndOfFile(handle);
WLog_ERR(TAG, "SetEndOfFile operation not implemented");
return FALSE;
}
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->GetFileSize)
return handle->ops->GetFileSize(handle, lpFileSizeHigh);
WLog_ERR(TAG, "GetFileSize operation not implemented");
return 0;
2012-09-26 20:37:35 +04:00
}
2019-11-06 17:24:51 +03:00
DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->SetFilePointer)
2019-11-06 17:24:51 +03:00
return handle->ops->SetFilePointer(handle, lDistanceToMove, lpDistanceToMoveHigh,
dwMoveMethod);
WLog_ERR(TAG, "SetFilePointer operation not implemented");
return 0;
2012-09-26 20:37:35 +04:00
}
2019-11-06 17:24:51 +03:00
BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->SetFilePointerEx)
2019-11-06 17:24:51 +03:00
return handle->ops->SetFilePointerEx(handle, liDistanceToMove, lpNewFilePointer,
dwMoveMethod);
WLog_ERR(TAG, "SetFilePointerEx operation not implemented");
return 0;
2012-09-26 20:37:35 +04:00
}
BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2017-04-27 09:31:53 +03:00
DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->LockFile)
return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
2017-04-27 09:31:53 +03:00
nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
WLog_ERR(TAG, "LockFile operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
2019-11-06 17:24:51 +03:00
BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->LockFileEx)
2019-11-06 17:24:51 +03:00
return handle->ops->LockFileEx(handle, dwFlags, dwReserved, nNumberOfBytesToLockLow,
nNumberOfBytesToLockHigh, lpOverlapped);
WLog_ERR(TAG, "LockFileEx operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
2017-04-27 09:31:53 +03:00
DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->UnlockFile)
return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh,
2017-04-27 09:31:53 +03:00
nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
WLog_ERR(TAG, "UnLockFile operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
2012-09-26 20:37:35 +04:00
BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
2017-04-27 09:31:53 +03:00
DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped)
2012-09-26 20:37:35 +04:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
if (handle->ops->UnlockFileEx)
2019-11-06 17:24:51 +03:00
return handle->ops->UnlockFileEx(handle, dwReserved, nNumberOfBytesToUnlockLow,
nNumberOfBytesToUnlockHigh, lpOverlapped);
WLog_ERR(TAG, "UnLockFileEx operation not implemented");
return FALSE;
2012-09-26 20:37:35 +04:00
}
2017-04-27 09:31:53 +03:00
BOOL WINAPI SetFileTime(HANDLE hFile, const FILETIME* lpCreationTime,
const FILETIME* lpLastAccessTime, const FILETIME* lpLastWriteTime)
2016-02-26 12:48:53 +03:00
{
ULONG Type;
2017-04-27 09:31:53 +03:00
WINPR_HANDLE* handle;
2016-02-26 12:48:53 +03:00
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
if (!winpr_Handle_GetInfo(hFile, &Type, &handle))
return FALSE;
2017-04-27 09:31:53 +03:00
handle = (WINPR_HANDLE*)hFile;
2016-02-26 12:48:53 +03:00
if (handle->ops->SetFileTime)
2019-11-06 17:24:51 +03:00
return handle->ops->SetFileTime(handle, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
2016-02-26 12:48:53 +03:00
WLog_ERR(TAG, "operation not implemented");
2016-02-26 12:48:53 +03:00
return FALSE;
}
typedef struct
{
char magic[16];
LPSTR lpPath;
LPSTR lpPattern;
DIR* pDir;
} WIN32_FILE_SEARCH;
static const char file_search_magic[] = "file_srch_magic";
static WIN32_FILE_SEARCH* file_search_new(const char* name, size_t namelen, const char* pattern,
size_t patternlen)
{
WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)calloc(1, sizeof(WIN32_FILE_SEARCH));
if (!pFileSearch)
return NULL;
strncpy(pFileSearch->magic, file_search_magic, sizeof(pFileSearch->magic));
pFileSearch->lpPath = strndup(name, namelen);
pFileSearch->lpPattern = strndup(pattern, patternlen);
if (!pFileSearch->lpPath || !pFileSearch->lpPattern)
goto fail;
pFileSearch->pDir = opendir(pFileSearch->lpPath);
if (!pFileSearch->pDir)
goto fail;
return pFileSearch;
fail:
FindClose(pFileSearch);
return NULL;
}
static BOOL is_valid_file_search_handle(HANDLE handle)
{
WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)handle;
if (!pFileSearch)
return FALSE;
if (pFileSearch == INVALID_HANDLE_VALUE)
return FALSE;
if (strcmp(file_search_magic, pFileSearch->magic) != 0)
return FALSE;
return TRUE;
}
2018-07-11 11:53:26 +03:00
static BOOL FindDataFromStat(const char* path, const struct stat* fileStat,
LPWIN32_FIND_DATAA lpFindFileData)
{
UINT64 ft;
char* lastSep;
lpFindFileData->dwFileAttributes = 0;
if (S_ISDIR(fileStat->st_mode))
lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
if (lpFindFileData->dwFileAttributes == 0)
lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
lastSep = strrchr(path, '/');
if (lastSep)
{
const char* name = lastSep + 1;
const size_t namelen = strlen(name);
2018-07-11 17:27:14 +03:00
if ((namelen > 1) && (name[0] == '.') && (name[1] != '.'))
2018-07-11 11:53:26 +03:00
lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
}
if (!(fileStat->st_mode & S_IWUSR))
lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
#ifdef _DARWIN_FEATURE_64_BIT_INODE
ft = STAT_TIME_TO_FILETIME(fileStat->st_birthtime);
#else
ft = STAT_TIME_TO_FILETIME(fileStat->st_ctime);
#endif
lpFindFileData->ftCreationTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
lpFindFileData->ftCreationTime.dwLowDateTime = ft & 0xFFFFFFFF;
ft = STAT_TIME_TO_FILETIME(fileStat->st_mtime);
lpFindFileData->ftLastWriteTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
lpFindFileData->ftLastWriteTime.dwLowDateTime = ft & 0xFFFFFFFF;
ft = STAT_TIME_TO_FILETIME(fileStat->st_atime);
lpFindFileData->ftLastAccessTime.dwHighDateTime = ((UINT64)ft) >> 32ULL;
lpFindFileData->ftLastAccessTime.dwLowDateTime = ft & 0xFFFFFFFF;
lpFindFileData->nFileSizeHigh = ((UINT64)fileStat->st_size) >> 32ULL;
lpFindFileData->nFileSizeLow = fileStat->st_size & 0xFFFFFFFF;
return TRUE;
}
2012-10-18 23:37:00 +04:00
HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
{
2018-07-30 11:46:20 +03:00
if (!lpFindFileData || !lpFileName)
{
SetLastError(ERROR_BAD_ARGUMENTS);
return INVALID_HANDLE_VALUE;
}
const WIN32_FIND_DATAA empty = { 0 };
*lpFindFileData = empty;
WIN32_FILE_SEARCH* pFileSearch = NULL;
size_t patternlen = 0;
const size_t flen = strlen(lpFileName);
const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE);
const char* ptr = strrchr(lpFileName, sep);
if (!ptr)
goto fail;
patternlen = strlen(ptr + 1);
if (patternlen == 0)
goto fail;
pFileSearch = file_search_new(lpFileName, flen - patternlen, ptr + 1, patternlen);
2017-04-27 09:31:53 +03:00
if (!pFileSearch)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
2017-04-27 09:31:53 +03:00
2019-11-06 17:24:51 +03:00
if (FindNextFileA((HANDLE)pFileSearch, lpFindFileData))
return (HANDLE)pFileSearch;
fail:
FindClose(pFileSearch);
return INVALID_HANDLE_VALUE;
2012-10-18 23:37:00 +04:00
}
2017-04-27 09:31:53 +03:00
static BOOL ConvertFindDataAToW(LPWIN32_FIND_DATAA lpFindFileDataA,
LPWIN32_FIND_DATAW lpFindFileDataW)
{
if (!lpFindFileDataA || !lpFindFileDataW)
return FALSE;
lpFindFileDataW->dwFileAttributes = lpFindFileDataA->dwFileAttributes;
lpFindFileDataW->ftCreationTime = lpFindFileDataA->ftCreationTime;
lpFindFileDataW->ftLastAccessTime = lpFindFileDataA->ftLastAccessTime;
lpFindFileDataW->ftLastWriteTime = lpFindFileDataA->ftLastWriteTime;
lpFindFileDataW->nFileSizeHigh = lpFindFileDataA->nFileSizeHigh;
lpFindFileDataW->nFileSizeLow = lpFindFileDataA->nFileSizeLow;
lpFindFileDataW->dwReserved0 = lpFindFileDataA->dwReserved0;
lpFindFileDataW->dwReserved1 = lpFindFileDataA->dwReserved1;
if (ConvertUtf8NToWChar(lpFindFileDataA->cFileName, ARRAYSIZE(lpFindFileDataA->cFileName),
lpFindFileDataW->cFileName, ARRAYSIZE(lpFindFileDataW->cFileName)) < 0)
2017-04-27 09:31:53 +03:00
return FALSE;
return ConvertUtf8NToWChar(lpFindFileDataA->cAlternateFileName,
ARRAYSIZE(lpFindFileDataA->cAlternateFileName),
lpFindFileDataW->cAlternateFileName,
ARRAYSIZE(lpFindFileDataW->cAlternateFileName)) >= 0;
2017-04-27 09:31:53 +03:00
}
2012-10-18 23:37:00 +04:00
HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)
{
LPSTR utfFileName = NULL;
2017-03-27 21:11:54 +03:00
HANDLE h;
if (!lpFileName)
return FALSE;
2017-04-27 09:31:53 +03:00
LPWIN32_FIND_DATAA fd = (LPWIN32_FIND_DATAA)calloc(1, sizeof(WIN32_FIND_DATAA));
2017-03-27 21:11:54 +03:00
if (!fd)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
utfFileName = ConvertWCharToUtf8Alloc(lpFileName, NULL);
if (!utfFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2017-04-06 18:46:07 +03:00
free(fd);
return INVALID_HANDLE_VALUE;
}
2017-03-27 21:11:54 +03:00
h = FindFirstFileA(utfFileName, fd);
free(utfFileName);
if (h != INVALID_HANDLE_VALUE)
{
2017-04-27 09:31:53 +03:00
if (!ConvertFindDataAToW(fd, lpFindFileData))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
FindClose(h);
h = INVALID_HANDLE_VALUE;
goto out;
}
}
out:
free(fd);
return h;
2012-10-18 23:37:00 +04:00
}
HANDLE FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
2017-04-27 09:31:53 +03:00
FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
2012-10-18 23:37:00 +04:00
{
return INVALID_HANDLE_VALUE;
2012-10-18 23:37:00 +04:00
}
HANDLE FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
2017-04-27 09:31:53 +03:00
FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
2012-10-18 23:37:00 +04:00
{
return INVALID_HANDLE_VALUE;
2012-10-18 23:37:00 +04:00
}
BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
{
if (!lpFindFileData)
return FALSE;
const WIN32_FIND_DATAA empty = { 0 };
*lpFindFileData = empty;
if (!is_valid_file_search_handle(hFindFile))
return FALSE;
WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
struct dirent* pDirent = NULL;
while ((pDirent = readdir(pFileSearch->pDir)) != NULL)
{
if (FilePatternMatchA(pDirent->d_name, pFileSearch->lpPattern))
{
BOOL success = FALSE;
strncpy(lpFindFileData->cFileName, pDirent->d_name, MAX_PATH);
const size_t namelen = strnlen(lpFindFileData->cFileName, MAX_PATH);
size_t pathlen = strlen(pFileSearch->lpPath);
char* fullpath = (char*)malloc(pathlen + namelen + 2);
2017-04-27 09:31:53 +03:00
2017-03-27 21:11:54 +03:00
if (fullpath == NULL)
{
2017-04-01 01:33:28 +03:00
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
2017-04-27 09:31:53 +03:00
memcpy(fullpath, pFileSearch->lpPath, pathlen);
/* Ensure path is terminated with a separator, but prevent
* duplicate separators */
2019-11-06 17:24:51 +03:00
if (fullpath[pathlen - 1] != '/')
fullpath[pathlen++] = '/';
memcpy(fullpath + pathlen, pDirent->d_name, namelen);
fullpath[pathlen + namelen] = 0;
struct stat fileStat = { 0 };
2017-04-19 09:28:00 +03:00
if (stat(fullpath, &fileStat) != 0)
2017-03-27 21:11:54 +03:00
{
free(fullpath);
2017-04-01 01:33:28 +03:00
SetLastError(map_posix_err(errno));
2018-07-11 17:27:14 +03:00
errno = 0;
continue;
2017-03-27 21:11:54 +03:00
}
2017-08-04 10:01:13 +03:00
/* Skip FIFO entries. */
if (S_ISFIFO(fileStat.st_mode))
2018-07-11 11:53:26 +03:00
{
free(fullpath);
2017-08-04 10:01:13 +03:00
continue;
2018-07-11 11:53:26 +03:00
}
2018-07-11 11:53:26 +03:00
success = FindDataFromStat(fullpath, &fileStat, lpFindFileData);
free(fullpath);
return success;
}
}
SetLastError(ERROR_NO_MORE_FILES);
2012-10-18 23:37:00 +04:00
return FALSE;
}
BOOL FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
{
2017-04-27 09:31:53 +03:00
LPWIN32_FIND_DATAA fd = (LPWIN32_FIND_DATAA)calloc(1, sizeof(WIN32_FIND_DATAA));
2017-03-27 21:11:54 +03:00
if (!fd)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2017-04-01 01:33:28 +03:00
return FALSE;
}
if (FindNextFileA(hFindFile, fd))
{
2017-04-27 09:31:53 +03:00
if (!ConvertFindDataAToW(fd, lpFindFileData))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2017-03-27 21:11:54 +03:00
free(fd);
return FALSE;
}
2017-04-27 09:31:53 +03:00
free(fd);
return TRUE;
}
free(fd);
2012-10-18 23:37:00 +04:00
return FALSE;
}
BOOL FindClose(HANDLE hFindFile)
{
2019-11-06 17:24:51 +03:00
WIN32_FILE_SEARCH* pFileSearch = (WIN32_FILE_SEARCH*)hFindFile;
/* Since INVALID_HANDLE_VALUE != NULL the analyzer guesses that there
* is a initialized HANDLE that is not freed properly.
* Disable this return to stop confusing the analyzer. */
#ifndef __clang_analyzer__
if (!is_valid_file_search_handle(hFindFile))
2017-04-06 18:46:07 +03:00
return FALSE;
#endif
2017-04-06 18:46:07 +03:00
free(pFileSearch->lpPath);
free(pFileSearch->lpPattern);
2017-04-06 18:46:07 +03:00
if (pFileSearch->pDir)
closedir(pFileSearch->pDir);
2017-04-06 18:46:07 +03:00
free(pFileSearch);
return TRUE;
2012-10-18 23:37:00 +04:00
}
2013-03-22 23:52:43 +04:00
BOOL CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
if (!mkdir(lpPathName, S_IRUSR | S_IWUSR | S_IXUSR))
return TRUE;
return FALSE;
}
BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
if (!lpPathName)
return FALSE;
char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName, NULL);
BOOL ret = FALSE;
2016-12-01 00:47:06 +03:00
if (!utfPathName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
2016-12-01 00:47:06 +03:00
ret = CreateDirectoryA(utfPathName, lpSecurityAttributes);
fail:
2016-12-01 00:47:06 +03:00
free(utfPathName);
return ret;
}
BOOL RemoveDirectoryA(LPCSTR lpPathName)
{
2016-12-01 00:47:06 +03:00
int ret = rmdir(lpPathName);
2017-04-27 09:31:53 +03:00
2016-12-01 00:47:06 +03:00
if (ret != 0)
SetLastError(map_posix_err(errno));
else
SetLastError(STATUS_SUCCESS);
2017-04-27 09:31:53 +03:00
2016-12-01 00:47:06 +03:00
return ret == 0;
}
BOOL RemoveDirectoryW(LPCWSTR lpPathName)
{
if (!lpPathName)
return FALSE;
char* utfPathName = ConvertWCharToUtf8Alloc(lpPathName, NULL);
BOOL ret = FALSE;
2016-12-01 00:47:06 +03:00
if (!utfPathName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
2016-12-01 00:47:06 +03:00
ret = RemoveDirectoryA(utfPathName);
fail:
2016-12-01 00:47:06 +03:00
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)
{
if (!lpExistingFileName || !lpNewFileName)
return FALSE;
LPSTR lpCExistingFileName = ConvertWCharToUtf8Alloc(lpExistingFileName, NULL);
LPSTR lpCNewFileName = ConvertWCharToUtf8Alloc(lpNewFileName, NULL);
BOOL ret = FALSE;
if (!lpCExistingFileName || !lpCNewFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
2016-12-01 00:47:06 +03:00
ret = MoveFileExA(lpCExistingFileName, lpCNewFileName, dwFlags);
fail:
2016-12-01 00:47:06 +03:00
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);
2013-03-22 23:52:43 +04:00
}
#endif
2013-07-30 18:57:54 +04:00
/* Extended API */
2014-08-18 21:34:47 +04:00
int UnixChangeFileMode(const char* filename, int flags)
2013-07-30 18:57:54 +04:00
{
if (!filename)
return -1;
#ifndef _WIN32
2013-07-30 18:57:54 +04:00
mode_t fl = 0;
fl |= (flags & 0x4000) ? S_ISUID : 0;
fl |= (flags & 0x2000) ? S_ISGID : 0;
fl |= (flags & 0x1000) ? S_ISVTX : 0;
fl |= (flags & 0x0400) ? S_IRUSR : 0;
fl |= (flags & 0x0200) ? S_IWUSR : 0;
fl |= (flags & 0x0100) ? S_IXUSR : 0;
fl |= (flags & 0x0040) ? S_IRGRP : 0;
fl |= (flags & 0x0020) ? S_IWGRP : 0;
fl |= (flags & 0x0010) ? S_IXGRP : 0;
fl |= (flags & 0x0004) ? S_IROTH : 0;
fl |= (flags & 0x0002) ? S_IWOTH : 0;
fl |= (flags & 0x0001) ? S_IXOTH : 0;
return chmod(filename, fl);
#else
int rc;
WCHAR* wfl = ConvertUtf8ToWCharAlloc(filename, NULL);
if (!wfl)
return -1;
/* Check for unsupported flags. */
if (flags & ~(_S_IREAD | _S_IWRITE))
WLog_WARN(TAG, "Unsupported file mode %d for _wchmod", flags);
rc = _wchmod(wfl, flags);
2017-04-27 09:31:53 +03:00
free(wfl);
return rc;
#endif
2013-07-30 18:57:54 +04:00
}