Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Oct 7, 2024
1 parent e7280ec commit 29d8391
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 133 deletions.
60 changes: 58 additions & 2 deletions src/win/fs-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,62 @@ static void uv__relative_path(const WCHAR* filename,
(*relpath)[relpathlen] = L'\0';
}

static int uv__split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
DWORD dir_len;

if (filename == NULL) {
if (dir != NULL)
*dir = NULL;
*file = NULL;
return 0;
}

len = wcslen(filename);
i = len;
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');

if (i == 0) {
if (dir) {
dir_len = GetCurrentDirectoryW(0, NULL);
if (dir_len == 0) {
return -1;
}
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}

if (!GetCurrentDirectoryW(dir_len, *dir)) {
uv__free(*dir);
*dir = NULL;
return -1;
}
}

*file = _wcsdup(filename);
} else {
if (dir) {
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*dir, filename, i + 1);
(*dir)[i + 1] = L'\0';
}

*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
if (!*file) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*file, filename + i + 1, len - i - 1);
(*file)[len - i - 1] = L'\0';
}

return 0;
}


int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
Expand Down Expand Up @@ -186,12 +242,12 @@ int uv_fs_event_start(uv_fs_event_t* handle,
short_path_done:
short_path = short_path_buffer;

if (uv__fs_split_path(pathw, &dir, &handle->filew) != 0) {
if (uv__split_path(pathw, &dir, &handle->filew) != 0) {
last_error = GetLastError();
goto error;
}

if (uv__fs_split_path(short_path, NULL, &handle->short_filew) != 0) {
if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) {
last_error = GetLastError();
goto error;
}
Expand Down
239 changes: 113 additions & 126 deletions src/win/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@
#define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010
#endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */

NTSTATUS uv__RtlUnicodeStringInit(
PUNICODE_STRING DestinationString,
PWSTR SourceString,
size_t SourceStringLen
) {
if (SourceStringLen > 0x7FFF)
return STATUS_INVALID_PARAMETER;
DestinationString->MaximumLength = DestinationString->Length =
SourceStringLen * sizeof(SourceString[0]);
DestinationString->Buffer = SourceString;
return STATUS_SUCCESS;
}

#define INIT(subtype) \
do { \
if (req == NULL) \
Expand Down Expand Up @@ -1943,21 +1956,46 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) {

INLINE static int fs__stat_directory(WCHAR* path, uv_stat_t* statbuf,
int do_lstat) {

HANDLE handle = INVALID_HANDLE_VALUE;
FILE_STAT_BASIC_INFORMATION stat_info;
FILE_FULL_DIR_INFORMATION* pdir_info;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
WCHAR buf[32 * 1024];
FILE_ID_FULL_DIR_INFORMATION dir_info;
FILE_FS_VOLUME_INFORMATION volume_info;
FILE_FS_DEVICE_INFORMATION device_info;
IO_STATUS_BLOCK io_status;
NTSTATUS nt_status;
WCHAR* path_dirpath = NULL;
WCHAR* path_filename = NULL;
BOOL ret_val = FALSE;
UNICODE_STRING FileMask;
DWORD ret_error = 0;
size_t len;
size_t split;
WCHAR splitchar;

/* aka strtok or wcscspn, in reverse */
len = wcslen(path);
split = len;
while (split > 0 && path[split - 1] != L'\\' && path[split - 1] != L'/')
split--;
if (split == 0) {
path_dirpath = L".";
} else {
path_dirpath = path;
splitchar = path[split - 1];
path[split - 1] = L'\0';
}
path_filename = &path[split];

if (uv__fs_split_path(path, &path_dirpath, &path_filename) != 0) {
ret_error = GetLastError();
goto cleanup;
len = 0;
while (1) {
if (path_filename[len] == L'\0')
break;
if (path_filename[len] == L'*' || path_filename[len] == L'?' ||
path_filename[len] == L'>' || path_filename[len] == L'<' ||
path_filename[len] == L'"') {
ret_error = ERROR_INVALID_NAME;
goto cleanup;
}
len++;
}

/* Get directory handle */
Expand All @@ -1974,78 +2012,85 @@ INLINE static int fs__stat_directory(WCHAR* path, uv_stat_t* statbuf,
goto cleanup;
}

do {
/* Get files in the directory */
status = pNtQueryDirectoryFile(handle,
NULL,
0,
0,
&ioStatusBlock,
buf,
sizeof(buf),
FileFullDirectoryInformation,
FALSE,
NULL,
FALSE);

if (!NT_SUCCESS(status)) {
if (status == STATUS_NO_MORE_FILES) {
break;
}
SetLastError(pRtlNtStatusToDosError(status));
ret_error = GetLastError();
goto cleanup;
}

pdir_info = buf;
/* Get files in the directory */
nt_status = uv__RtlUnicodeStringInit(&FileMask, path_filename, len);
if (!NT_SUCCESS(nt_status)) {
ret_error = pRtlNtStatusToDosError(nt_status);
goto cleanup;
}
nt_status = pNtQueryDirectoryFile(handle,
NULL,
NULL,
NULL,
&io_status,
&dir_info,
sizeof(dir_info),
FileIdFullDirectoryInformation,
TRUE,
&FileMask,
TRUE);

/* Check files one by one */
for (;;)
{
if (wcscmp(&pdir_info->FileName[0], path_filename) == 0) {
ret_val = TRUE;
break;
}
/* Buffer overflow (a warning status code) is expected here since there isn't
* enough space to store the FileName, and actually indicates success. */
if (!NT_SUCCESS(nt_status) && nt_status != STATUS_BUFFER_OVERFLOW) {
if (nt_status == STATUS_NO_MORE_FILES)
ret_error = ERROR_PATH_NOT_FOUND;
else
ret_error = pRtlNtStatusToDosError(nt_status);
goto cleanup;
}

if (pdir_info->NextEntryOffset == 0) {
break;
}
/* Assign values to stat_info */
memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION));
stat_info.FileAttributes = dir_info.FileAttributes;
stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart;
stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart;
stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart;
stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart;
stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart;
stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart;
stat_info.FileId.QuadPart = dir_info.FileId.QuadPart;

/* Finish up by getting device info from the directory handle,
* since files presumably must live on their device. */
nt_status = pNtQueryVolumeInformationFile(handle,
&io_status,
&volume_info,
sizeof volume_info,
FileFsVolumeInformation);

pdir_info = (FILE_FULL_DIR_INFORMATION*)((unsigned char*)pdir_info +
pdir_info->NextEntryOffset);
}
/* Buffer overflow (a warning status code) is expected here. */
if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
stat_info.VolumeSerialNumber.QuadPart = 0;
} else if (NT_ERROR(nt_status)) {
ret_error = pRtlNtStatusToDosError(nt_status);
goto cleanup;
} else {
stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber;
}

} while (TRUE && !ret_val);
nt_status = pNtQueryVolumeInformationFile(handle,
&io_status,
&device_info,
sizeof device_info,
FileFsDeviceInformation);

if (!ret_val) {
ret_error = ERROR_PATH_NOT_FOUND;
/* Buffer overflow (a warning status code) is expected here. */
if (NT_ERROR(nt_status)) {
ret_error = pRtlNtStatusToDosError(nt_status);
goto cleanup;
}

/* Assign values to stat_info */
memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION));
stat_info.FileAttributes = pdir_info->FileAttributes;
stat_info.CreationTime.QuadPart = pdir_info->CreationTime.QuadPart;
stat_info.LastAccessTime.QuadPart = pdir_info->LastAccessTime.QuadPart;
stat_info.LastWriteTime.QuadPart = pdir_info->LastWriteTime.QuadPart;
stat_info.EndOfFile.QuadPart = pdir_info->EndOfFile.QuadPart;
stat_info.ChangeTime.QuadPart = pdir_info->ChangeTime.QuadPart;
stat_info.AllocationSize.QuadPart = pdir_info->AllocationSize.QuadPart;
stat_info.DeviceType = device_info.DeviceType;
stat_info.NumberOfLinks = 1; /* No way to recover this info. */

fs__stat_assign_statbuf(statbuf, stat_info, do_lstat);

cleanup:
if (path_filename) {
uv__free(path_filename);
path_filename = NULL;
}
if (path_dirpath) {
uv__free(path_dirpath);
path_dirpath = NULL;
}
if (handle != INVALID_HANDLE_VALUE) {
if (split != 0)
path[split - 1] = splitchar;
if (handle != INVALID_HANDLE_VALUE)
CloseHandle(handle);
}
return ret_error;
}

Expand Down Expand Up @@ -3679,64 +3724,6 @@ int uv_fs_statfs(uv_loop_t* loop,
POST;
}


int uv__fs_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
DWORD dir_len;

if (filename == NULL) {
if (dir != NULL)
*dir = NULL;
*file = NULL;
return 0;
}

len = wcslen(filename);
i = len;
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');

if (i == 0) {
if (dir) {
dir_len = GetCurrentDirectoryW(0, NULL);
if (dir_len == 0) {
return -1;
}
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}

if (!GetCurrentDirectoryW(dir_len, *dir)) {
uv__free(*dir);
*dir = NULL;
return -1;
}
}

*file = _wcsdup(filename);
} else {
if (dir) {
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*dir, filename, i + 1);
(*dir)[i + 1] = L'\0';
}

*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
if (!*file) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*file, filename + i + 1, len - i - 1);
(*file)[len - i - 1] = L'\0';
}

return 0;
}


int uv_fs_get_system_error(const uv_fs_t* req) {
return req->sys_errno_;
}
1 change: 0 additions & 1 deletion src/win/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle);
* FS
*/
void uv__fs_init(void);
int uv__fs_split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file);


/*
Expand Down
5 changes: 3 additions & 2 deletions src/win/winapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -4285,7 +4285,7 @@ typedef struct _FILE_BOTH_DIR_INFORMATION {
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

typedef struct _FILE_FULL_DIR_INFORMATION {
typedef struct _FILE_ID_FULL_DIR_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
Expand All @@ -4297,8 +4297,9 @@ typedef struct _FILE_FULL_DIR_INFORMATION {
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
LARGE_INTEGER FileId;
WCHAR FileName[1];
} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;

typedef struct _FILE_BASIC_INFORMATION {
LARGE_INTEGER CreationTime;
Expand Down
Loading

0 comments on commit 29d8391

Please sign in to comment.