ext/asyncengine/libuv/src/win/fs.c in asyncengine-0.0.1.testing1 vs ext/asyncengine/libuv/src/win/fs.c in asyncengine-0.0.2.alpha1

- old
+ new

@@ -30,14 +30,16 @@ #include <sys/utime.h> #include <stdio.h> #include "uv.h" #include "internal.h" +#include "req-inl.h" + #define UV_FS_ASYNC_QUEUED 0x0001 -#define UV_FS_FREE_ARG0 0x0002 -#define UV_FS_FREE_ARG1 0x0004 +#define UV_FS_FREE_PATH 0x0002 +#define UV_FS_FREE_NEW_PATH 0x0004 #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 #define UTF8_TO_UTF16(s, t) \ @@ -49,44 +51,19 @@ if (!uv_utf8_to_utf16(s, t, size / sizeof(wchar_t))) { \ uv__set_sys_error(loop, GetLastError()); \ return -1; \ } -#define STRDUP_ARG(req, i) \ - req->arg##i = (void*)strdup((const char*)req->arg##i); \ - if (!req->arg##i) { \ - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); \ - } \ - req->flags |= UV_FS_FREE_ARG##i; - -#define SET_ALLOCED_ARG(req, i) \ - req->flags |= UV_FS_FREE_ARG##i; - -#define WRAP_REQ_ARGS1(req, a0) \ - req->arg0 = (void*)a0; - -#define WRAP_REQ_ARGS2(req, a0, a1) \ - WRAP_REQ_ARGS1(req, a0) \ - req->arg1 = (void*)a1; - -#define WRAP_REQ_ARGS3(req, a0, a1, a2) \ - WRAP_REQ_ARGS2(req, a0, a1) \ - req->arg2 = (void*)a2; - -#define WRAP_REQ_ARGS4(req, a0, a1, a2, a3) \ - WRAP_REQ_ARGS3(req, a0, a1, a2) \ - req->arg3 = (void*)a3; - #define QUEUE_FS_TP_JOB(loop, req) \ if (!QueueUserWorkItem(&uv_fs_thread_proc, \ req, \ - WT_EXECUTELONGFUNCTION)) { \ + WT_EXECUTEDEFAULT)) { \ uv__set_sys_error((loop), GetLastError()); \ return -1; \ } \ req->flags |= UV_FS_ASYNC_QUEUED; \ - uv_ref((loop)); + uv__req_register(loop, req); #define SET_UV_LAST_ERROR_FROM_REQ(req) \ uv__set_error(req->loop, req->errorno, req->sys_errno_); #define SET_REQ_RESULT(req, result_value) \ @@ -108,15 +85,35 @@ #define VERIFY_UV_FILE(file, req) \ if (file == -1) { \ req->result = -1; \ req->errorno = UV_EBADF; \ - req->sys_errno_ = ERROR_SUCCESS; \ + req->sys_errno_ = ERROR_INVALID_HANDLE; \ return; \ } +#define FILETIME_TO_TIME_T(filetime) \ + ((*((uint64_t*) &(filetime)) - 116444736000000000ULL) / 10000000ULL); +#define TIME_T_TO_FILETIME(time, filetime_ptr) \ + do { \ + *(uint64_t*) (filetime_ptr) = ((int64_t) (time) * 10000000LL) + \ + 116444736000000000ULL; \ + } while(0) + + +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const wchar_t JUNCTION_PREFIX[] = L"\\??\\"; +const wchar_t JUNCTION_PREFIX_LEN = 4; + +const wchar_t LONG_PATH_PREFIX[] = L"\\\\?\\"; +const wchar_t LONG_PATH_PREFIX_LEN = 4; + + void uv_fs_init() { _fmode = _O_BINARY; } @@ -151,10 +148,65 @@ req->pathw = NULL; req->errorno = 0; } +static int is_path_dir(const wchar_t* path) { + DWORD attr = GetFileAttributesW(path); + + if (attr != INVALID_FILE_ATTRIBUTES) { + return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0; + } else { + return 0; + } +} + + +static int get_reparse_point(HANDLE handle, int* target_length) { + void* buffer = NULL; + REPARSE_DATA_BUFFER* reparse_data; + DWORD bytes_returned; + int rv = 0; + + buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, + NULL)) { + free(buffer); + return 0; + } + + reparse_data = (REPARSE_DATA_BUFFER*)buffer; + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + rv = 1; + if (target_length) { + *target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + rv = 1; + if (target_length) { + *target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } + + free(buffer); + return rv; +} + + void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) { DWORD access; DWORD share; DWORD disposition; DWORD attributes; @@ -247,14 +299,12 @@ default: result = -1; goto end; } - /* Figure out whether path is a file or a directory. */ - if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) { - attributes |= FILE_FLAG_BACKUP_SEMANTICS; - } + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; file = CreateFileW(path, access, share, NULL, @@ -287,11 +337,11 @@ SET_REQ_RESULT(req, result); } void fs__read(uv_fs_t* req, uv_file file, void *buf, size_t length, - off_t offset) { + int64_t offset) { HANDLE handle; OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; DWORD error; @@ -333,11 +383,11 @@ } } void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length, - off_t offset) { + int64_t offset) { HANDLE handle; OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; @@ -372,24 +422,57 @@ SET_REQ_WIN32_ERROR(req, GetLastError()); } } -void fs__unlink(uv_fs_t* req, const wchar_t* path) { - int result = _wunlink(path); +void fs__rmdir(uv_fs_t* req, const wchar_t* path) { + int result = _wrmdir(path); SET_REQ_RESULT(req, result); } -void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { - int result = _wmkdir(path); - SET_REQ_RESULT(req, result); +void fs__unlink(uv_fs_t* req, const wchar_t* path) { + int result; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + int is_dir_symlink; + + handle = CreateFileW(path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && + get_reparse_point(handle, NULL); + + CloseHandle(handle); + + if (is_dir_symlink) { + fs__rmdir(req, path); + } else { + result = _wunlink(path); + SET_REQ_RESULT(req, result); + } } -void fs__rmdir(uv_fs_t* req, const wchar_t* path) { - int result = _wrmdir(path); +void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { + int result = _wmkdir(path); SET_REQ_RESULT(req, result); } void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { @@ -497,81 +580,119 @@ SET_REQ_RESULT(req, result); } -static void fs__stat(uv_fs_t* req, const wchar_t* path) { - HANDLE handle; +INLINE static int fs__stat_handle(HANDLE handle, uv_statbuf_t* statbuf) { + int target_length; BY_HANDLE_FILE_INFORMATION info; + if (!GetFileInformationByHandle(handle, &info)) { + return -1; + } + + /* TODO: set st_dev, st_rdev and st_ino to something meaningful. */ + statbuf->st_ino = 0; + statbuf->st_dev = 0; + statbuf->st_rdev = 0; + + statbuf->st_gid = 0; + statbuf->st_uid = 0; + + statbuf->st_mode = 0; + + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + get_reparse_point(handle, &target_length)) { + statbuf->st_mode = S_IFLNK; + /* Adjust for long path */ + statbuf->st_size = target_length - JUNCTION_PREFIX_LEN; + } else { + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + } else { + statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)); + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + } else { + statbuf->st_mode |= _S_IFREG; + } + + statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) + + (int64_t) info.nFileSizeLow; + + } + + statbuf->st_mtime = FILETIME_TO_TIME_T(info.ftLastWriteTime); + statbuf->st_atime = FILETIME_TO_TIME_T(info.ftLastAccessTime); + statbuf->st_ctime = FILETIME_TO_TIME_T(info.ftCreationTime); + + statbuf->st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ? + (short) info.nNumberOfLinks : SHRT_MAX; + + return 0; +} + + +INLINE static void fs__stat(uv_fs_t* req, const wchar_t* path, int do_lstat) { + HANDLE handle; + DWORD flags; + req->ptr = NULL; + flags = FILE_FLAG_BACKUP_SEMANTICS; + if (do_lstat) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } + handle = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, + flags, NULL); if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } - if (!GetFileInformationByHandle(handle, &info)) { + if (fs__stat_handle(handle, &req->stat) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); CloseHandle(handle); return; } - memset(&req->stat, 0, sizeof req->stat); - - /* TODO: set st_dev and st_ino? */ - - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); - } else { - req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)); - } - - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - req->stat.st_mode |= _S_IFDIR; - } else { - req->stat.st_mode |= _S_IFREG; - } - - uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime)); - uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime)); - uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime)); - - req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + - (int64_t) info.nFileSizeLow; - - req->stat.st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ? - (short) info.nNumberOfLinks : SHRT_MAX; - req->ptr = &req->stat; req->result = 0; - CloseHandle(handle); } void fs__fstat(uv_fs_t* req, uv_file file) { - int result; + HANDLE handle; + req->ptr = NULL; + VERIFY_UV_FILE(file, req); - result = _fstati64(file, &req->stat); - if (result == -1) { - req->ptr = NULL; - } else { - req->ptr = &req->stat; + handle = (HANDLE) _get_osfhandle(file); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; } - SET_REQ_RESULT(req, result); + if (fs__stat_handle(handle, &req->stat) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->ptr = &req->stat; + req->result = 0; } void fs__rename(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { if (!MoveFileExW(path, new_path, MOVEFILE_REPLACE_EXISTING)) { @@ -595,35 +716,54 @@ SET_REQ_RESULT(req, result); } } -void fs__ftruncate(uv_fs_t* req, uv_file file, off_t offset) { - int result; +void fs__ftruncate(uv_fs_t* req, uv_file file, int64_t offset) { + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; VERIFY_UV_FILE(file, req); - result = _chsize(file, offset); - SET_REQ_RESULT(req, result); + handle = (HANDLE)_get_osfhandle(file); + + eof_info.EndOfFile.QuadPart = offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } } void fs__sendfile(uv_fs_t* req, uv_file out_file, uv_file in_file, - off_t in_offset, size_t length) { + int64_t in_offset, size_t length) { const size_t max_buf_size = 65536; size_t buf_size = length < max_buf_size ? length : max_buf_size; int n, result = 0; + int64_t result_offset = 0; char* buf = (char*)malloc(buf_size); if (!buf) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (in_offset != -1) { - result = _lseek(in_file, in_offset, SEEK_SET); + result_offset = _lseeki64(in_file, in_offset, SEEK_SET); } - if (result != -1) { + if (result_offset == -1) { + result = -1; + } else { while (length > 0) { n = _read(in_file, buf, length < buf_size ? length : buf_size); if (n == 0) { break; } else if (n == -1) { @@ -697,26 +837,66 @@ done: SET_REQ_RESULT(req, result); } +INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { + FILETIME filetime_a, filetime_m; + + TIME_T_TO_FILETIME((time_t) atime, &filetime_a); + TIME_T_TO_FILETIME((time_t) mtime, &filetime_m); + + if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + return -1; + } + + return 0; +} + + void fs__utime(uv_fs_t* req, const wchar_t* path, double atime, double mtime) { - int result; - struct _utimbuf b = {(time_t)atime, (time_t)mtime}; - result = _wutime(path, &b); - SET_REQ_RESULT(req, result); + HANDLE handle; + + handle = CreateFileW(path, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__utime_handle(handle, atime, mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->result = 0; } void fs__futime(uv_fs_t* req, uv_file file, double atime, double mtime) { - int result; - struct _utimbuf b = {(time_t)atime, (time_t)mtime}; - + HANDLE handle; VERIFY_UV_FILE(file, req); - result = _futime(file, &b); - SET_REQ_RESULT(req, result); + handle = (HANDLE) _get_osfhandle(file); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__utime_handle(handle, atime, mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->result = 0; } void fs__link(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { int result = CreateHardLinkW(new_path, path, NULL) ? 0 : -1; @@ -726,27 +906,197 @@ SET_REQ_RESULT(req, result); } } +void fs__create_junction(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + wchar_t* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + // Do a pessimistic calculation of the required buffer size + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(wchar_t) + + 2 * (target_len + 2) * sizeof(wchar_t); + + // Allocate the buffer + buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + // Grab a pointer to the part of the buffer where filenames go + path_buf = (wchar_t*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + // Copy the substitute (internal) target path + start = path_buf_len; + + wcsncpy((wchar_t*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + // Set the info about the substitute name + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(wchar_t); + + // Insert null terminator + path_buf[path_buf_len++] = L'\0'; + + // Copy the print name of the target path + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + // Set the info about the print name + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(wchar_t); + + // Insert another null terminator + path_buf[path_buf_len++] = L'\0'; + + // Calculate how much buffer space was actually used + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(wchar_t); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + // Put general info in the data buffer + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + // Create a new directory + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + // Open the directory + handle = CreateFileW(new_path, + GENERIC_ALL, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Create the actual reparse point + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Clean up + CloseHandle(handle); + free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path, int flags) { int result; - if (pCreateSymbolicLinkW) { + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, path, new_path); + } else if (pCreateSymbolicLinkW) { result = pCreateSymbolicLinkW(new_path, path, flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; if (result == -1) { SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + } else { + SET_REQ_RESULT(req, result); } } else { SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; } - - SET_REQ_RESULT(req, result); } void fs__readlink(uv_fs_t* req, const wchar_t* path) { int result = -1; @@ -792,26 +1142,35 @@ SET_REQ_WIN32_ERROR(req, GetLastError()); goto done; } reparse_data = (REPARSE_DATA_BUFFER*)buffer; - if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) { + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else { result = -1; /* something is seriously wrong */ SET_REQ_WIN32_ERROR(req, GetLastError()); goto done; } - substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + - (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)); - substitute_name_length = - reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); - /* Strip off the leading \??\ from the substitute name buffer.*/ - if (memcmp(substitute_name, L"\\??\\", 8) == 0) { - substitute_name += 4; - substitute_name_length -= 4; + if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) { + substitute_name += JUNCTION_PREFIX_LEN; + substitute_name_length -= JUNCTION_PREFIX_LEN; } utf8size = uv_utf16_to_utf8(substitute_name, substitute_name_length, NULL, @@ -866,82 +1225,72 @@ assert(req != NULL); assert(req->type == UV_FS); switch (req->fs_type) { case UV_FS_OPEN: - fs__open(req, req->pathw, (int)req->arg0, (int)req->arg1); + fs__open(req, req->pathw, req->file_flags, (int)req->mode); break; case UV_FS_CLOSE: - fs__close(req, (uv_file)req->arg0); + fs__close(req, req->file); break; case UV_FS_READ: - fs__read(req, - (uv_file) req->arg0, - req->arg1, - (size_t) req->arg2, - (off_t) req->arg3); + fs__read(req, req->file, req->buf, req->length, req->offset); break; case UV_FS_WRITE: - fs__write(req, - (uv_file)req->arg0, - req->arg1, - (size_t) req->arg2, - (off_t) req->arg3); + fs__write(req, req->file, req->buf, req->length, req->offset); break; case UV_FS_UNLINK: fs__unlink(req, req->pathw); break; case UV_FS_MKDIR: - fs__mkdir(req, req->pathw, (int)req->arg0); + fs__mkdir(req, req->pathw, req->mode); break; case UV_FS_RMDIR: fs__rmdir(req, req->pathw); break; case UV_FS_READDIR: - fs__readdir(req, req->pathw, (int)req->arg0); + fs__readdir(req, req->pathw, req->file_flags); break; case UV_FS_STAT: + fs__stat(req, req->pathw, 0); + break; case UV_FS_LSTAT: - fs__stat(req, req->pathw); + fs__stat(req, req->pathw, 1); break; case UV_FS_FSTAT: - fs__fstat(req, (uv_file)req->arg0); + fs__fstat(req, req->file); break; case UV_FS_RENAME: - fs__rename(req, req->pathw, (const wchar_t*)req->arg0); + fs__rename(req, req->pathw, req->new_pathw); break; case UV_FS_FSYNC: case UV_FS_FDATASYNC: - fs__fsync(req, (uv_file)req->arg0); + fs__fsync(req, req->file); break; case UV_FS_FTRUNCATE: - fs__ftruncate(req, (uv_file)req->arg0, (off_t)req->arg1); + fs__ftruncate(req, req->file, req->offset); break; case UV_FS_SENDFILE: - fs__sendfile(req, - (uv_file) req->arg0, - (uv_file) req->arg1, - (off_t) req->arg2, - (size_t) req->arg3); + fs__sendfile(req, req->file_out, req->file, req->offset, req->length); break; case UV_FS_CHMOD: - fs__chmod(req, req->pathw, (int)req->arg0); + fs__chmod(req, req->pathw, req->mode); break; case UV_FS_FCHMOD: - fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1); + fs__fchmod(req, req->file, req->mode); break; case UV_FS_UTIME: - fs__utime(req, req->pathw, req->arg4, req->arg5); + fs__utime(req, req->pathw, req->atime, req->mtime); break; case UV_FS_FUTIME: - fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5); + fs__futime(req, req->file, req->atime, req->mtime); break; case UV_FS_LINK: - fs__link(req, req->pathw, (const wchar_t*)req->arg0); + fs__link(req, req->pathw, req->new_pathw); break; case UV_FS_SYMLINK: - fs__symlink(req, req->pathw, (const wchar_t*)req->arg0, (int)req->arg1); + fs__symlink(req, req->pathw, req->new_pathw, req->file_flags); break; case UV_FS_READLINK: fs__readlink(req, req->pathw); break; case UV_FS_CHOWN: @@ -966,11 +1315,12 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_OPEN, path, pathw, cb); - WRAP_REQ_ARGS2(req, flags, mode); + req->file_flags = flags; + req->mode = mode; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_OPEN); fs__open(req, pathw, flags, mode); free(pathw); @@ -983,11 +1333,11 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_CLOSE, NULL, NULL, cb); - WRAP_REQ_ARGS1(req, file); + req->file = file; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_CLOSE); fs__close(req, file); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -997,14 +1347,17 @@ return 0; } int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, - size_t length, off_t offset, uv_fs_cb cb) { + size_t length, int64_t offset, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_READ, NULL, NULL, cb); - WRAP_REQ_ARGS4(req, file, buf, length, offset); + req->file = file; + req->buf = buf; + req->length = length; + req->offset = offset; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_READ); fs__read(req, file, buf, length, offset); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1014,14 +1367,17 @@ return 0; } int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, - size_t length, off_t offset, uv_fs_cb cb) { + size_t length, int64_t offset, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_WRITE, NULL, NULL, cb); - WRAP_REQ_ARGS4(req, file, buf, length, offset); + req->file = file; + req->buf = buf; + req->length = length; + req->offset = offset; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_WRITE); fs__write(req, file, buf, length, offset); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1063,11 +1419,11 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_MKDIR, path, pathw, cb); - WRAP_REQ_ARGS1(req, mode); + req->mode = mode; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_MKDIR); fs__mkdir(req, pathw, mode); free(pathw); @@ -1109,11 +1465,11 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_READDIR, path, pathw, cb); - WRAP_REQ_ARGS1(req, flags); + req->file_flags = flags; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_READDIR); fs__readdir(req, pathw, flags); free(pathw); @@ -1135,12 +1491,12 @@ UTF8_TO_UTF16(path, pathw); UTF8_TO_UTF16(new_path, new_pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_LINK, path, pathw, cb); - WRAP_REQ_ARGS1(req, new_pathw); - SET_ALLOCED_ARG(req, 0); + req->new_pathw = new_pathw; + req->flags |= UV_FS_FREE_NEW_PATH; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_LINK); fs__link(req, pathw, new_pathw); free(pathw); @@ -1163,12 +1519,13 @@ UTF8_TO_UTF16(path, pathw); UTF8_TO_UTF16(new_path, new_pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_SYMLINK, path, pathw, cb); - WRAP_REQ_ARGS2(req, new_pathw, flags); - SET_ALLOCED_ARG(req, 0); + req->new_pathw = new_pathw; + req->file_flags = flags; + req->flags |= UV_FS_FREE_NEW_PATH; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_SYMLINK); fs__symlink(req, pathw, new_pathw, flags); free(pathw); @@ -1212,11 +1569,10 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_CHOWN, path, pathw, cb); - WRAP_REQ_ARGS2(req, uid, gid); QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_CHOWN); fs__nop(req); free(pathw); @@ -1230,11 +1586,10 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid, int gid, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FCHOWN, NULL, NULL, cb); - WRAP_REQ_ARGS3(req, file, uid, gid); QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN); fs__nop(req); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1273,11 +1628,11 @@ QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_STAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 0); if (path2) { free(path2); } free(pathw); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1317,11 +1672,11 @@ QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_LSTAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 1); if (path2) { free(path2); } free(pathw); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1333,11 +1688,11 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FSTAT, NULL, NULL, cb); - WRAP_REQ_ARGS1(req, file); + req->file = file; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FSTAT); fs__fstat(req, file); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1358,12 +1713,12 @@ UTF8_TO_UTF16(path, pathw); UTF8_TO_UTF16(new_path, new_pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_RENAME, path, pathw, cb); - WRAP_REQ_ARGS1(req, new_pathw); - SET_ALLOCED_ARG(req, 0); + req->new_pathw = new_pathw; + req->flags |= UV_FS_FREE_NEW_PATH; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_RENAME); fs__rename(req, pathw, new_pathw); free(pathw); @@ -1377,11 +1732,11 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FDATASYNC, NULL, NULL, cb); - WRAP_REQ_ARGS1(req, file); + req->file = file; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FDATASYNC); fs__fsync(req, file); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1393,11 +1748,11 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FSYNC, NULL, NULL, cb); - WRAP_REQ_ARGS1(req, file); + req->file = file; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FSYNC); fs__fsync(req, file); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1407,14 +1762,15 @@ return 0; } int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, - off_t offset, uv_fs_cb cb) { + int64_t offset, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FTRUNCATE, NULL, NULL, cb); - WRAP_REQ_ARGS2(req, file, offset); + req->file = file; + req->offset = offset; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FTRUNCATE); fs__ftruncate(req, file, offset); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1424,14 +1780,17 @@ return 0; } int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, - uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb) { + uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_SENDFILE, NULL, NULL, cb); - WRAP_REQ_ARGS4(req, out_fd, in_fd, in_offset, length); + req->file_out = out_fd; + req->file = in_fd; + req->offset = in_offset; + req->length = length; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_SENDFILE); fs__sendfile(req, out_fd, in_fd, in_offset, length); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1450,11 +1809,11 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_CHMOD, path, pathw, cb); - WRAP_REQ_ARGS1(req, mode); + req->mode = mode; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_CHMOD); fs__chmod(req, pathw, mode); free(pathw); @@ -1468,11 +1827,12 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FCHMOD, NULL, NULL, cb); - WRAP_REQ_ARGS2(req, file, mode); + req->file = file; + req->mode = mode; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD); fs__fchmod(req, file, mode); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1491,12 +1851,12 @@ /* Convert to UTF16. */ UTF8_TO_UTF16(path, pathw); if (cb) { uv_fs_req_init_async(loop, req, UV_FS_UTIME, path, pathw, cb); - req->arg4 = (ssize_t)atime; - req->arg5 = (ssize_t)mtime; + req->atime = atime; + req->mtime = mtime; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_UTIME); fs__utime(req, pathw, atime, mtime); free(pathw); @@ -1510,13 +1870,13 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) { if (cb) { uv_fs_req_init_async(loop, req, UV_FS_FUTIME, NULL, NULL, cb); - WRAP_REQ_ARGS1(req, file); - req->arg4 = (ssize_t)atime; - req->arg5 = (ssize_t)mtime; + req->file = file; + req->atime = atime; + req->mtime = mtime; QUEUE_FS_TP_JOB(loop, req); } else { uv_fs_req_init_sync(loop, req, UV_FS_FUTIME); fs__futime(req, file, atime, mtime); SET_UV_LAST_ERROR_FROM_REQ(req); @@ -1527,10 +1887,11 @@ } void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { assert(req->cb); + uv__req_unregister(loop, req); SET_UV_LAST_ERROR_FROM_REQ(req); req->cb(req); } @@ -1539,18 +1900,18 @@ if (req->flags & UV_FS_CLEANEDUP) { return; } - if (req->flags & UV_FS_FREE_ARG0 && req->arg0) { - free(req->arg0); - req->arg0 = NULL; + if (req->flags & UV_FS_FREE_PATH && req->pathw) { + free(req->pathw); + req->pathw = NULL; } - if (req->flags & UV_FS_FREE_ARG1 && req->arg1) { - free(req->arg1); - req->arg1 = NULL; + if (req->flags & UV_FS_FREE_NEW_PATH && req->new_pathw) { + free(req->new_pathw); + req->new_pathw = NULL; } if (req->flags & UV_FS_FREE_PTR && req->ptr) { free(req->ptr); } @@ -1558,18 +1919,9 @@ req->ptr = NULL; if (req->path) { free(req->path); req->path = NULL; - } - - if (req->pathw) { - free(req->pathw); - req->pathw = NULL; - } - - if (req->flags & UV_FS_ASYNC_QUEUED) { - uv_unref(loop); } req->flags |= UV_FS_CLEANEDUP; }