From 68000aaaa89a03353d12d88f3863a308c2248d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Fri, 27 Dec 2024 11:49:51 +0300 Subject: [PATCH 1/5] win,fs: get fstat of AppExecLink reparse points --- src/win/fs.c | 102 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index a4742aa2..4e4a1fd1 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1960,6 +1960,7 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, FILE_ID_FULL_DIR_INFORMATION dir_info; FILE_FS_VOLUME_INFORMATION volume_info; FILE_FS_DEVICE_INFORMATION device_info; + FILE_ALL_INFORMATION file_info; IO_STATUS_BLOCK io_status; NTSTATUS nt_status; WCHAR* path_dirpath = NULL; @@ -1968,6 +1969,7 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, size_t len; size_t split; WCHAR splitchar; + char *target = NULL; int includes_name; /* AKA strtok or wcscspn, in reverse. */ @@ -2065,24 +2067,91 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart; stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart; stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart; - if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - /* A file handle is needed to get st_size for the link (from - * FSCTL_GET_REPARSE_POINT), which is required by posix, but we are here - * because getting the file handle failed. We could get just the - * ReparsePointTag by querying FILE_ID_EXTD_DIR_INFORMATION instead to make - * sure this really is a link before giving up here on the uv_fs_stat call, - * but that doesn't seem essential. */ - if (!do_lstat) - goto cleanup; - stat_info.EndOfFile.QuadPart = 0; - stat_info.AllocationSize.QuadPart = 0; - } else { - stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart; - stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart; - } + stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart; + stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart; stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart; stat_info.FileId.QuadPart = dir_info.FileId.QuadPart; + if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (!do_lstat) { + /* Adjust the path */ + if (split != 0) + path[split - 1] = splitchar; + + /* Close the directory handle */ + CloseHandle(handle); + + /* Get file handle */ + handle = CreateFileW(path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + /* Read the target file name */ + if (fs__readlink_handle(handle, (char**)&target, NULL) != 0) { + printf("fs__readlink_handle error: %d\n", GetLastError()); + goto cleanup; + } + + CloseHandle(handle); + + /* Get file handle for the target */ + handle = CreateFile(target, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + uv__free(target); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileAllInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + stat_info.FileAttributes = file_info.BasicInformation.FileAttributes; + stat_info.NumberOfLinks = file_info.StandardInformation.NumberOfLinks; + stat_info.FileId.QuadPart = + file_info.InternalInformation.IndexNumber.QuadPart; + stat_info.ChangeTime.QuadPart = + file_info.BasicInformation.ChangeTime.QuadPart; + stat_info.CreationTime.QuadPart = + file_info.BasicInformation.CreationTime.QuadPart; + stat_info.LastAccessTime.QuadPart = + file_info.BasicInformation.LastAccessTime.QuadPart; + stat_info.LastWriteTime.QuadPart = + file_info.BasicInformation.LastWriteTime.QuadPart; + stat_info.AllocationSize.QuadPart = + file_info.StandardInformation.AllocationSize.QuadPart; + stat_info.EndOfFile.QuadPart = + file_info.StandardInformation.EndOfFile.QuadPart; + } else { + stat_info.EndOfFile.QuadPart = 0; + stat_info.AllocationSize.QuadPart = 0; + } + } + /* Finish up by getting device info from the directory handle, * since files presumably must live on their device. */ nt_status = pNtQueryVolumeInformationFile(handle, @@ -2159,7 +2228,8 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, if (handle == INVALID_HANDLE_VALUE) { ret = GetLastError(); - if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION) + if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION && + ret != ERROR_CANT_ACCESS_FILE) return ret; return fs__stat_directory(path, statbuf, do_lstat, ret); } From be967742c50010addea392c319e268a64c2a86ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Fri, 3 Jan 2025 16:24:45 +0300 Subject: [PATCH 2/5] fixup! win,fs: get fstat of AppExecLink reparse points --- src/win/fs.c | 126 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 36 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 4e4a1fd1..acb18460 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1953,6 +1953,93 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { } } +INLINE static DWORD fs__stat_get_handle(HANDLE handle, WCHAR* path, int do_lstat) { + WCHAR* tmp_path = NULL; + char *target = NULL; + size_t len = 0; + int ret_error = 0; + size_t tmp_len = 0; + int i; + + if (!do_lstat) { + /* Create a tmp path variable */ + len = wcslen(path); + tmp_path = uv__malloc(sizeof(WCHAR) * (len + 1)); + memcpy(tmp_path, path, sizeof(WCHAR) * (len + 1)); + + for (i = 0; i < 255; i++) { + /* Get file handle */ + handle = CreateFileW(tmp_path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + break; + } + + handle = CreateFileW(tmp_path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + if (target) { + uv__free(target); + target = NULL; + } + + /* Read the target file name */ + if (fs__readlink_handle(handle, (char**)&target, NULL) != 0) { + ret_error = GetLastError(); + CloseHandle(handle); + goto cleanup; + } + + CloseHandle(handle); + + /* Convert from char* to WCHAR* */ + uv__free(tmp_path); + tmp_len = uv_wtf8_length_as_utf16(target); + tmp_path = uv__malloc(tmp_len * sizeof(WCHAR)); + uv_wtf8_to_utf16(target, tmp_path, tmp_len); + } + +cleanup: + if (target) { + uv__free(target); + target = NULL; + } + if (tmp_path) { + uv__free(tmp_path); + tmp_path = NULL; + } + } else { + handle = CreateFileW(path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + } + } + return ret_error; +} + INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, int do_lstat, DWORD ret_error) { HANDLE handle = INVALID_HANDLE_VALUE; @@ -1969,7 +2056,6 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, size_t len; size_t split; WCHAR splitchar; - char *target = NULL; int includes_name; /* AKA strtok or wcscspn, in reverse. */ @@ -2081,40 +2167,9 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, /* Close the directory handle */ CloseHandle(handle); - /* Get file handle */ - handle = CreateFileW(path, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); + ret_error = fs__stat_get_handle(handle, path, do_lstat); - if (handle == INVALID_HANDLE_VALUE) { - ret_error = GetLastError(); - goto cleanup; - } - - /* Read the target file name */ - if (fs__readlink_handle(handle, (char**)&target, NULL) != 0) { - printf("fs__readlink_handle error: %d\n", GetLastError()); - goto cleanup; - } - - CloseHandle(handle); - - /* Get file handle for the target */ - handle = CreateFile(target, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); - uv__free(target); - - if (handle == INVALID_HANDLE_VALUE) { - ret_error = GetLastError(); + if (ret_error != 0) { goto cleanup; } @@ -2126,8 +2181,7 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, /* Buffer overflow (a warning status code) is expected here. */ if (NT_ERROR(nt_status)) { - SetLastError(pRtlNtStatusToDosError(nt_status)); - return -1; + return pRtlNtStatusToDosError(nt_status); } stat_info.FileAttributes = file_info.BasicInformation.FileAttributes; From 85b488e1b8fc3a91bfe65b463f398b904795efe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= <110401522+huseyinacacak-janea@users.noreply.github.com> Date: Mon, 6 Jan 2025 09:16:28 +0300 Subject: [PATCH 3/5] Update src/win/fs.c Co-authored-by: Jameson Nash --- src/win/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index acb18460..e8551c04 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1953,7 +1953,7 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { } } -INLINE static DWORD fs__stat_get_handle(HANDLE handle, WCHAR* path, int do_lstat) { +INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lstat) { WCHAR* tmp_path = NULL; char *target = NULL; size_t len = 0; From 8dc553ac190b1b090ddfc9369b59cfaf88422d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Tue, 7 Jan 2025 16:22:45 +0300 Subject: [PATCH 4/5] fixup! win,fs: get fstat of AppExecLink reparse points --- src/win/fs.c | 55 +++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index e8551c04..0f634a87 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1969,7 +1969,7 @@ INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lsta for (i = 0; i < 255; i++) { /* Get file handle */ - handle = CreateFileW(tmp_path, + *handle = CreateFileW(tmp_path, 0, 0, NULL, @@ -1977,11 +1977,11 @@ INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lsta FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (handle != INVALID_HANDLE_VALUE) { + if (*handle != INVALID_HANDLE_VALUE) { break; } - handle = CreateFileW(tmp_path, + *handle = CreateFileW(tmp_path, 0, 0, NULL, @@ -1989,7 +1989,7 @@ INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lsta FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); - if (handle == INVALID_HANDLE_VALUE) { + if (*handle == INVALID_HANDLE_VALUE) { ret_error = GetLastError(); goto cleanup; } @@ -2000,13 +2000,13 @@ INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lsta } /* Read the target file name */ - if (fs__readlink_handle(handle, (char**)&target, NULL) != 0) { + if (fs__readlink_handle(*handle, (char**)&target, NULL) != 0) { ret_error = GetLastError(); - CloseHandle(handle); + CloseHandle(*handle); goto cleanup; } - CloseHandle(handle); + CloseHandle(*handle); /* Convert from char* to WCHAR* */ uv__free(tmp_path); @@ -2025,7 +2025,7 @@ cleanup: tmp_path = NULL; } } else { - handle = CreateFileW(path, + *handle = CreateFileW(path, 0, 0, NULL, @@ -2033,7 +2033,7 @@ cleanup: FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); - if (handle == INVALID_HANDLE_VALUE) { + if (*handle == INVALID_HANDLE_VALUE) { ret_error = GetLastError(); } } @@ -2043,6 +2043,7 @@ cleanup: INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, int do_lstat, DWORD ret_error) { HANDLE handle = INVALID_HANDLE_VALUE; + HANDLE tmp_handle = INVALID_HANDLE_VALUE; FILE_STAT_BASIC_INFORMATION stat_info; FILE_ID_FULL_DIR_INFORMATION dir_info; FILE_FS_VOLUME_INFORMATION volume_info; @@ -2080,6 +2081,7 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, /* If there is no filename, consider it as a relative folder path */ if (!includes_name) { split = len; + splitchar = path[split - 1]; /* Else, split it */ } else { splitchar = path[split - 1]; @@ -2089,6 +2091,7 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, } else { path_dirpath = path; split = len; + splitchar = path[split - 1]; } path_filename = &path[split]; @@ -2158,20 +2161,23 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart; stat_info.FileId.QuadPart = dir_info.FileId.QuadPart; - if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - if (!do_lstat) { - /* Adjust the path */ - if (split != 0) - path[split - 1] = splitchar; + if (!do_lstat) { + /* Adjust the path */ + if (split != 0) + path[split - 1] = splitchar; - /* Close the directory handle */ - CloseHandle(handle); + tmp_handle = handle; + handle = INVALID_HANDLE_VALUE; - ret_error = fs__stat_get_handle(handle, path, do_lstat); + ret_error = fs__stat_get_handle(&handle, path, do_lstat); - if (ret_error != 0) { - goto cleanup; - } + /* If there occurs an error while getting file handle, continue + * with the directory handle */ + if (ret_error != 0) { + handle = tmp_handle; + } else { + /* Close directory handle and continue with file handle */ + CloseHandle(tmp_handle); nt_status = pNtQueryInformationFile(handle, &io_status, @@ -2181,7 +2187,8 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, /* Buffer overflow (a warning status code) is expected here. */ if (NT_ERROR(nt_status)) { - return pRtlNtStatusToDosError(nt_status); + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; } stat_info.FileAttributes = file_info.BasicInformation.FileAttributes; @@ -2200,10 +2207,10 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, file_info.StandardInformation.AllocationSize.QuadPart; stat_info.EndOfFile.QuadPart = file_info.StandardInformation.EndOfFile.QuadPart; - } else { - stat_info.EndOfFile.QuadPart = 0; - stat_info.AllocationSize.QuadPart = 0; } + } else { + stat_info.EndOfFile.QuadPart = 0; + stat_info.AllocationSize.QuadPart = 0; } /* Finish up by getting device info from the directory handle, From 4ee3bd5d0aef2527a1f953cc99b378d7e40c7e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Wed, 8 Jan 2025 14:26:44 +0300 Subject: [PATCH 5/5] fixup! win,fs: get fstat of AppExecLink reparse points --- src/win/fs.c | 78 +++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 0f634a87..f14fa164 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -183,7 +183,7 @@ void uv__fs_init(void) { INLINE static int fs__readlink_handle(HANDLE handle, - char** target_ptr, + WCHAR** target_ptr, size_t* target_len_ptr) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; @@ -315,7 +315,15 @@ INLINE static int fs__readlink_handle(HANDLE handle, } assert(target_ptr == NULL || *target_ptr == NULL); - return uv_utf16_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); + if (target_ptr) { + *target_ptr = uv__malloc((w_target_len + 1) * sizeof(WCHAR)); + memcpy(*target_ptr, w_target, w_target_len * sizeof(WCHAR)); + (*target_ptr)[w_target_len] = L'\0'; + } + if (target_len_ptr) { + *target_len_ptr = w_target_len; + } + return 0; } @@ -1955,10 +1963,8 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lstat) { WCHAR* tmp_path = NULL; - char *target = NULL; size_t len = 0; int ret_error = 0; - size_t tmp_len = 0; int i; if (!do_lstat) { @@ -1970,68 +1976,56 @@ INLINE static DWORD fs__stat_get_handle(HANDLE* handle, WCHAR* path, int do_lsta for (i = 0; i < 255; i++) { /* Get file handle */ *handle = CreateFileW(tmp_path, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); if (*handle != INVALID_HANDLE_VALUE) { break; } *handle = CreateFileW(tmp_path, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); if (*handle == INVALID_HANDLE_VALUE) { ret_error = GetLastError(); goto cleanup; } - if (target) { - uv__free(target); - target = NULL; - } + uv__free(tmp_path); + tmp_path = NULL; /* Read the target file name */ - if (fs__readlink_handle(*handle, (char**)&target, NULL) != 0) { + if (fs__readlink_handle(*handle, (WCHAR**)&tmp_path, NULL) != 0) { ret_error = GetLastError(); CloseHandle(*handle); goto cleanup; } CloseHandle(*handle); - - /* Convert from char* to WCHAR* */ - uv__free(tmp_path); - tmp_len = uv_wtf8_length_as_utf16(target); - tmp_path = uv__malloc(tmp_len * sizeof(WCHAR)); - uv_wtf8_to_utf16(target, tmp_path, tmp_len); } cleanup: - if (target) { - uv__free(target); - target = NULL; - } if (tmp_path) { uv__free(tmp_path); tmp_path = NULL; } } else { *handle = CreateFileW(path, - 0, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); if (*handle == INVALID_HANDLE_VALUE) { ret_error = GetLastError(); @@ -2041,7 +2035,8 @@ cleanup: } INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, - int do_lstat, DWORD ret_error) { + int do_lstat) { + DWORD ret_error; HANDLE handle = INVALID_HANDLE_VALUE; HANDLE tmp_handle = INVALID_HANDLE_VALUE; FILE_STAT_BASIC_INFORMATION stat_info; @@ -2292,7 +2287,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION && ret != ERROR_CANT_ACCESS_FILE) return ret; - return fs__stat_directory(path, statbuf, do_lstat, ret); + return fs__stat_directory(path, statbuf, do_lstat); } if (fs__stat_handle(handle, statbuf, do_lstat) != 0) @@ -3049,7 +3044,8 @@ static void fs__readlink(uv_fs_t* req) { } assert(req->ptr == NULL); - if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { + WCHAR* target_ptr = NULL; + if (fs__readlink_handle(handle, (WCHAR**) &target_ptr, NULL) != 0) { DWORD error = GetLastError(); SET_REQ_WIN32_ERROR(req, error); if (error == ERROR_NOT_A_REPARSE_POINT) @@ -3058,6 +3054,8 @@ static void fs__readlink(uv_fs_t* req) { return; } + uv_utf16_to_wtf8(target_ptr, wcslen(target_ptr), (char**)&req->ptr, NULL); + uv__free(target_ptr); req->flags |= UV_FS_FREE_PTR; SET_REQ_RESULT(req, 0);