FreeRDP/winpr/libwinpr/file/file.c

1026 lines
21 KiB
C

/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/synch.h>
#include <winpr/error.h>
#include <winpr/handle.h>
#include <winpr/platform.h>
#include <winpr/collections.h>
#include <winpr/file.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
/**
* 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
* SetFileInformationByHandle
* ReadFile
* ReadFileEx
* ReadFileScatter
* WriteFile
* WriteFileEx
* WriteFileGather
* FlushFileBuffers
* SetEndOfFile
* SetFilePointer
* SetFilePointerEx
* LockFile
* LockFileEx
* UnlockFile
* UnlockFileEx
*/
/**
* 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
*/
#ifndef _WIN32
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <assert.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#ifdef HAVE_AIO_H
#undef HAVE_AIO_H /* disable for now, incomplete */
#endif
#ifdef HAVE_AIO_H
#include <aio.h>
#endif
#ifndef _WIN32
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
#endif
#ifdef ANDROID
#include <sys/vfs.h>
#else
#include <sys/statvfs.h>
#endif
#include "../handle/handle.h"
#include "../pipe/pipe.h"
/* TODO: FIXME: use of a wArrayList and split winpr-utils with
* winpr-collections to avoid a circular dependency
* _HandleCreators = ArrayList_New(TRUE);
*/
/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */
#define HANDLE_CREATOR_MAX 128
static HANDLE_CREATOR **_HandleCreators = NULL;
static CRITICAL_SECTION _HandleCreatorsLock;
static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
static void _HandleCreatorsInit()
{
/* NB: error management to be done outside of this function */
assert(_HandleCreators == NULL);
_HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*));
InitializeCriticalSection(&_HandleCreatorsLock);
assert(_HandleCreators != NULL);
}
/**
* Returns TRUE on success, FALSE otherwise.
*
* ERRORS:
* ERROR_DLL_INIT_FAILED
* ERROR_INSUFFICIENT_BUFFER _HandleCreators full
*/
BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator)
{
int i;
if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
if (_HandleCreators == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
EnterCriticalSection(&_HandleCreatorsLock);
for (i=0; i<HANDLE_CREATOR_MAX; i++)
{
if (_HandleCreators[i] == NULL)
{
_HandleCreators[i] = pHandleCreator;
LeaveCriticalSection(&_HandleCreatorsLock);
return TRUE;
}
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
LeaveCriticalSection(&_HandleCreatorsLock);
return FALSE;
}
#ifdef HAVE_AIO_H
static BOOL g_AioSignalHandlerInstalled = FALSE;
void AioSignalHandler(int signum, siginfo_t* siginfo, void* arg)
{
printf("AioSignalHandler\n");
}
int InstallAioSignalHandler()
{
if (!g_AioSignalHandlerInstalled)
{
struct sigaction action;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGIO);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = (void*) &AioSignalHandler;
sigaction(SIGIO, &action, NULL);
g_AioSignalHandlerInstalled = TRUE;
}
return 0;
}
#endif /* HAVE_AIO_H */
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
int i;
char* name;
int status;
HANDLE hNamedPipe;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
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;
}
EnterCriticalSection(&_HandleCreatorsLock);
for (i=0; _HandleCreators[i] != NULL; i++)
{
HANDLE_CREATOR *creator = (HANDLE_CREATOR*)_HandleCreators[i];
if (creator && creator->IsHandled(lpFileName))
{
HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
LeaveCriticalSection(&_HandleCreatorsLock);
return newHandle;
}
}
LeaveCriticalSection(&_HandleCreatorsLock);
/* TODO: use of a HANDLE_CREATOR for named pipes as well */
if (!IsNamedPipeFileNameA(lpFileName))
return INVALID_HANDLE_VALUE;
name = GetNamedPipeNameWithoutPrefixA(lpFileName);
if (!name)
return INVALID_HANDLE_VALUE;
free(name);
pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE));
hNamedPipe = (HANDLE) pNamedPipe;
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
pNamedPipe->name = _strdup(lpFileName);
pNamedPipe->dwOpenMode = 0;
pNamedPipe->dwPipeMode = 0;
pNamedPipe->nMaxInstances = 0;
pNamedPipe->nOutBufferSize = 0;
pNamedPipe->nInBufferSize = 0;
pNamedPipe->nDefaultTimeOut = 0;
pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
pNamedPipe->serverfd = -1;
pNamedPipe->ServerMode = FALSE;
ZeroMemory(&s, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
strcpy(s.sun_path, pNamedPipe->lpFilePath);
status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
if (status != 0)
{
close(pNamedPipe->clientfd);
free((char*) pNamedPipe->name);
free((char*) pNamedPipe->lpFileName);
free((char*) pNamedPipe->lpFilePath);
free(pNamedPipe);
return INVALID_HANDLE_VALUE;
}
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
#if 0
int flags = fcntl(pNamedPipe->clientfd, F_GETFL);
if (flags != -1)
fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK);
#endif
}
return hNamedPipe;
}
HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
return NULL;
}
BOOL DeleteFileA(LPCSTR lpFileName)
{
int status;
status = unlink(lpFileName);
return (status != -1) ? TRUE : FALSE;
}
BOOL DeleteFileW(LPCWSTR lpFileName)
{
return TRUE;
}
BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
ULONG Type;
PVOID Object;
BOOL status = TRUE;
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;
if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE;
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
int io_status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object;
do
{
io_status = read(pipe->fd, lpBuffer, nNumberOfBytesToRead);
}
while ((io_status < 0) && (errno == EINTR));
if (io_status < 0)
{
status = FALSE;
switch (errno)
{
case EWOULDBLOCK:
SetLastError(ERROR_NO_DATA);
break;
}
}
if (lpNumberOfBytesRead)
*lpNumberOfBytesRead = io_status;
return status;
}
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
int io_status;
WINPR_NAMED_PIPE* pipe;
pipe = (WINPR_NAMED_PIPE*) Object;
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
{
if (pipe->clientfd == -1)
return FALSE;
do
{
io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
}
while ((io_status < 0) && (errno == EINTR));
if (io_status == 0)
{
SetLastError(ERROR_BROKEN_PIPE);
status = FALSE;
}
else if (io_status < 0)
{
status = FALSE;
switch (errno)
{
case EWOULDBLOCK:
SetLastError(ERROR_NO_DATA);
break;
default:
SetLastError(ERROR_BROKEN_PIPE);
break;
}
}
*lpNumberOfBytesRead = io_status;
}
else
{
/* Overlapped I/O */
if (!lpOverlapped)
return FALSE;
if (pipe->clientfd == -1)
return FALSE;
pipe->lpOverlapped = lpOverlapped;
#ifdef HAVE_AIO_H
{
int aio_status;
struct aiocb cb;
ZeroMemory(&cb, sizeof(struct aiocb));
cb.aio_fildes = pipe->clientfd;
cb.aio_buf = lpBuffer;
cb.aio_nbytes = nNumberOfBytesToRead;
cb.aio_offset = lpOverlapped->Offset;
cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb.aio_sigevent.sigev_signo = SIGIO;
cb.aio_sigevent.sigev_value.sival_ptr = (void*) lpOverlapped;
InstallAioSignalHandler();
aio_status = aio_read(&cb);
printf("aio_read status: %d\n", aio_status);
if (aio_status < 0)
status = FALSE;
return status;
}
#else
/* synchronous behavior */
lpOverlapped->Internal = 0;
lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToRead;
lpOverlapped->Pointer = (PVOID) lpBuffer;
SetEvent(lpOverlapped->hEvent);
#endif
}
return status;
}
return FALSE;
}
BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
return TRUE;
}
BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[],
DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
{
return TRUE;
}
BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
ULONG Type;
PVOID Object;
BOOL status = TRUE;
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
if (!winpr_Handle_GetInfo(hFile, &Type, &Object))
return FALSE;
if (Type == HANDLE_TYPE_ANONYMOUS_PIPE)
{
int io_status;
WINPR_PIPE* pipe;
pipe = (WINPR_PIPE*) Object;
do
{
io_status = write(pipe->fd, lpBuffer, nNumberOfBytesToWrite);
}
while ((io_status < 0) && (errno == EINTR));
if ((io_status < 0) && (errno == EWOULDBLOCK))
io_status = 0;
*lpNumberOfBytesWritten = io_status;
return TRUE;
}
else if (Type == HANDLE_TYPE_NAMED_PIPE)
{
int io_status;
WINPR_NAMED_PIPE* pipe;
pipe = (WINPR_NAMED_PIPE*) Object;
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
{
io_status = nNumberOfBytesToWrite;
if (pipe->clientfd == -1)
return FALSE;
do
{
io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
}
while ((io_status < 0) && (errno == EINTR));
if (io_status < 0)
{
*lpNumberOfBytesWritten = 0;
switch(errno)
{
case EWOULDBLOCK:
io_status = 0;
status = TRUE;
break;
default:
status = FALSE;
}
}
*lpNumberOfBytesWritten = io_status;
return status;
}
else
{
/* Overlapped I/O */
if (!lpOverlapped)
return FALSE;
if (pipe->clientfd == -1)
return FALSE;
pipe->lpOverlapped = lpOverlapped;
#ifdef HAVE_AIO_H
{
struct aiocb cb;
ZeroMemory(&cb, sizeof(struct aiocb));
cb.aio_fildes = pipe->clientfd;
cb.aio_buf = (void*) lpBuffer;
cb.aio_nbytes = nNumberOfBytesToWrite;
cb.aio_offset = lpOverlapped->Offset;
cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb.aio_sigevent.sigev_signo = SIGIO;
cb.aio_sigevent.sigev_value.sival_ptr = (void*) lpOverlapped;
InstallAioSignalHandler();
io_status = aio_write(&cb);
printf("aio_write status: %d\n", io_status);
if (io_status < 0)
status = FALSE;
return status;
}
#else
/* synchronous behavior */
lpOverlapped->Internal = 1;
lpOverlapped->InternalHigh = (ULONG_PTR) nNumberOfBytesToWrite;
lpOverlapped->Pointer = (PVOID) lpBuffer;
SetEvent(lpOverlapped->hEvent);
#endif
}
return TRUE;
}
return FALSE;
}
BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
return TRUE;
}
BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[],
DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
{
return TRUE;
}
BOOL FlushFileBuffers(HANDLE hFile)
{
return TRUE;
}
BOOL SetEndOfFile(HANDLE hFile)
{
return TRUE;
}
DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
{
return TRUE;
}
BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
{
return TRUE;
}
BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
{
return TRUE;
}
BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved,
DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped)
{
return TRUE;
}
BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
{
return TRUE;
}
BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow,
DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped)
{
return TRUE;
}
struct _WIN32_FILE_SEARCH
{
DIR* pDir;
LPSTR lpPath;
LPSTR lpPattern;
struct dirent* pDirent;
};
typedef struct _WIN32_FILE_SEARCH WIN32_FILE_SEARCH;
HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
{
char* p;
int index;
int length;
struct stat fileStat;
WIN32_FILE_SEARCH* pFileSearch;
ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
pFileSearch = (WIN32_FILE_SEARCH*) malloc(sizeof(WIN32_FILE_SEARCH));
ZeroMemory(pFileSearch, sizeof(WIN32_FILE_SEARCH));
/* Separate lpFileName into path and pattern components */
p = strrchr(lpFileName, '/');
if (!p)
p = strrchr(lpFileName, '\\');
index = (p - lpFileName);
length = (p - lpFileName);
pFileSearch->lpPath = (LPSTR) malloc(length + 1);
CopyMemory(pFileSearch->lpPath, lpFileName, length);
pFileSearch->lpPath[length] = '\0';
length = strlen(lpFileName) - index;
pFileSearch->lpPattern = (LPSTR) malloc(length + 1);
CopyMemory(pFileSearch->lpPattern, &lpFileName[index + 1], length);
pFileSearch->lpPattern[length] = '\0';
/* Check if the path is a directory */
if (lstat(pFileSearch->lpPath, &fileStat) < 0)
{
FindClose(pFileSearch);
return INVALID_HANDLE_VALUE; /* stat error */
}
if (S_ISDIR(fileStat.st_mode) == 0)
{
FindClose(pFileSearch);
return INVALID_HANDLE_VALUE; /* not a directory */
}
/* Open directory for reading */
pFileSearch->pDir = opendir(pFileSearch->lpPath);
if (!pFileSearch->pDir)
{
FindClose(pFileSearch);
return INVALID_HANDLE_VALUE; /* failed to open directory */
}
while ((pFileSearch->pDirent = readdir(pFileSearch->pDir)) != NULL)
{
if ((strcmp(pFileSearch->pDirent->d_name, ".") == 0) || (strcmp(pFileSearch->pDirent->d_name, "..") == 0))
{
/* skip "." and ".." */
continue;
}
if (FilePatternMatchA(pFileSearch->pDirent->d_name, pFileSearch->lpPattern))
{
strcpy(lpFindFileData->cFileName, pFileSearch->pDirent->d_name);
return (HANDLE) pFileSearch;
}
}
FindClose(pFileSearch);
return INVALID_HANDLE_VALUE;
}
HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData)
{
return NULL;
}
HANDLE FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
{
return NULL;
}
HANDLE FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
{
return NULL;
}
BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
{
WIN32_FILE_SEARCH* pFileSearch;
if (!hFindFile)
return FALSE;
if (hFindFile == INVALID_HANDLE_VALUE)
return FALSE;
pFileSearch = (WIN32_FILE_SEARCH*) hFindFile;
while ((pFileSearch->pDirent = readdir(pFileSearch->pDir)) != NULL)
{
if (FilePatternMatchA(pFileSearch->pDirent->d_name, pFileSearch->lpPattern))
{
strcpy(lpFindFileData->cFileName, pFileSearch->pDirent->d_name);
return TRUE;
}
}
return FALSE;
}
BOOL FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
{
return FALSE;
}
BOOL FindClose(HANDLE hFindFile)
{
WIN32_FILE_SEARCH* pFileSearch;
pFileSearch = (WIN32_FILE_SEARCH*) hFindFile;
if (pFileSearch)
{
if (pFileSearch->lpPath)
free(pFileSearch->lpPath);
if (pFileSearch->lpPattern)
free(pFileSearch->lpPattern);
if (pFileSearch->pDir)
closedir(pFileSearch->pDir);
free(pFileSearch);
return TRUE;
}
return FALSE;
}
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)
{
return TRUE;
}
#endif
/* Extended API */
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
{
if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
return FALSE;
return TRUE;
}
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName;
if (!lpName)
return NULL;
if (!IsNamedPipeFileNameA(lpName))
return NULL;
lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]);
return lpFileName;
}
char* GetNamedPipeUnixDomainSocketBaseFilePathA()
{
char* lpTempPath;
char* lpPipePath;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
free(lpTempPath);
return lpPipePath;
}
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath;
char* lpFileName;
char* lpFilePath;
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
{
#ifndef _WIN32
int fd;
WINPR_NAMED_PIPE* pNamedPipe;
pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe;
if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE)
return -1;
fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
return fd;
#else
return -1;
#endif
}
int UnixChangeFileMode(const char* filename, int flags)
{
#ifndef _WIN32
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
return 0;
#endif
}