30 #include <sys/utime.h>
40 #define UV_FS_FREE_PATHS 0x0002
41 #define UV_FS_FREE_PTR 0x0008
42 #define UV_FS_CLEANEDUP 0x0010
45 #define INIT(subtype) \
49 uv_fs_req_init(loop, req, subtype, cb); \
56 uv__req_register(loop, req); \
57 uv__work_submit(loop, \
64 uv__fs_work(&req->work_req); \
70 #define SET_REQ_RESULT(req, result_value) \
72 req->result = (result_value); \
73 if (req->result == -1) { \
74 req->sys_errno_ = _doserrno; \
75 req->result = uv_translate_sys_error(req->sys_errno_); \
79 #define SET_REQ_WIN32_ERROR(req, sys_errno) \
81 req->sys_errno_ = (sys_errno); \
82 req->result = uv_translate_sys_error(req->sys_errno_); \
85 #define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
87 req->result = (uv_errno); \
88 req->sys_errno_ = (sys_errno); \
91 #define VERIFY_FD(fd, req) \
93 req->result = UV_EBADF; \
94 req->sys_errno_ = ERROR_INVALID_HANDLE; \
98 #define MILLIONu (1000U * 1000U)
99 #define BILLIONu (1000U * 1000U * 1000U)
101 #define FILETIME_TO_UINT(filetime) \
102 (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
104 #define FILETIME_TO_TIME_T(filetime) \
105 (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
107 #define FILETIME_TO_TIME_NS(filetime, secs) \
108 ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
110 #define FILETIME_TO_TIMESPEC(ts, filetime) \
112 (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
113 (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
116 #define TIME_T_TO_FILETIME(time, filetime_ptr) \
118 uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
119 (uint64_t) 116444736 * BILLIONu; \
120 (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
121 (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
124 #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
125 #define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
126 ((c) >= L'A' && (c) <= L'Z'))
128 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
145 SYSTEM_INFO system_info;
147 GetSystemInfo(&system_info);
155 const char* new_path,
const int copy_path) {
158 ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
161 assert(new_path == NULL ||
path != NULL);
164 pathw_len = MultiByteToWideChar(CP_UTF8,
170 if (pathw_len == 0) {
171 return GetLastError();
174 buf_sz += pathw_len *
sizeof(WCHAR);
177 if (
path != NULL && copy_path) {
178 path_len = 1 + strlen(
path);
182 if (new_path != NULL) {
183 new_pathw_len = MultiByteToWideChar(CP_UTF8,
189 if (new_pathw_len == 0) {
190 return GetLastError();
193 buf_sz += new_pathw_len *
sizeof(WCHAR);
198 req->file.pathw = NULL;
199 req->fs.info.new_pathw = NULL;
206 return ERROR_OUTOFMEMORY;
212 DWORD
r = MultiByteToWideChar(CP_UTF8,
218 assert(
r == (DWORD) pathw_len);
219 req->file.pathw = (WCHAR*)
pos;
220 pos +=
r *
sizeof(WCHAR);
222 req->file.pathw = NULL;
225 if (new_path != NULL) {
226 DWORD
r = MultiByteToWideChar(CP_UTF8,
232 assert(
r == (DWORD) new_pathw_len);
233 req->fs.info.new_pathw = (WCHAR*)
pos;
234 pos +=
r *
sizeof(WCHAR);
236 req->fs.info.new_pathw = NULL;
240 if (
path != NULL && copy_path) {
242 assert(path_len == buf_sz - (
pos -
buf));
259 req->fs_type = fs_type;
275 target_len = WideCharToMultiByte(CP_UTF8,
284 if (target_len == 0) {
288 if (target_len_ptr != NULL) {
289 *target_len_ptr = target_len;
292 if (target_ptr == NULL) {
298 SetLastError(ERROR_OUTOFMEMORY);
302 r = WideCharToMultiByte(CP_UTF8,
310 assert(
r == target_len);
311 target[target_len] =
'\0';
319 char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
320 REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*)
buffer;
325 if (!DeviceIoControl(
handle,
338 w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
339 (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
342 reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
350 if (w_target_len >= 4 &&
351 w_target[0] ==
L'\\' &&
352 w_target[1] ==
L'?' &&
353 w_target[2] ==
L'?' &&
354 w_target[3] ==
L'\\') {
356 if (w_target_len >= 6 &&
357 ((w_target[4] >=
L'A' && w_target[4] <=
L'Z') ||
358 (w_target[4] >=
L'a' && w_target[4] <=
L'z')) &&
359 w_target[5] ==
L':' &&
360 (w_target_len == 6 || w_target[6] ==
L'\\')) {
365 }
else if (w_target_len >= 8 &&
366 (w_target[4] ==
L'U' || w_target[4] ==
L'u') &&
367 (w_target[5] ==
L'N' || w_target[5] ==
L'n') &&
368 (w_target[6] ==
L'C' || w_target[6] ==
L'c') &&
369 w_target[7] ==
L'\\') {
378 }
else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
380 w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
381 (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
383 w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
391 if (!(w_target_len >= 6 &&
392 w_target[0] ==
L'\\' &&
393 w_target[1] ==
L'?' &&
394 w_target[2] ==
L'?' &&
395 w_target[3] ==
L'\\' &&
396 ((w_target[4] >=
L'A' && w_target[4] <=
L'Z') ||
397 (w_target[4] >=
L'a' && w_target[4] <=
L'z')) &&
398 w_target[5] ==
L':' &&
399 (w_target_len == 6 || w_target[6] ==
L'\\'))) {
414 return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
422 DWORD attributes = 0;
424 int fd, current_umask;
425 int flags =
req->fs.info.file_flags;
450 current_umask = umask(0);
451 umask(current_umask);
456 access = FILE_GENERIC_READ;
459 access = FILE_GENERIC_WRITE;
462 access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
469 access &= ~FILE_WRITE_DATA;
470 access |= FILE_APPEND_DATA;
486 share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
492 disposition = OPEN_EXISTING;
495 disposition = OPEN_ALWAYS;
499 disposition = CREATE_NEW;
503 disposition = TRUNCATE_EXISTING;
506 disposition = CREATE_ALWAYS;
512 attributes |= FILE_ATTRIBUTE_NORMAL;
514 if (!((
req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
515 attributes |= FILE_ATTRIBUTE_READONLY;
520 attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
525 attributes |= FILE_ATTRIBUTE_TEMPORARY;
532 attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
535 attributes |= FILE_FLAG_RANDOM_ACCESS;
562 if (
access & FILE_APPEND_DATA) {
563 if (
access & FILE_WRITE_DATA) {
564 access &= ~FILE_APPEND_DATA;
569 attributes |= FILE_FLAG_NO_BUFFERING;
577 attributes |= FILE_FLAG_WRITE_THROUGH;
584 attributes |= FILE_FLAG_BACKUP_SEMANTICS;
586 file = CreateFileW(
req->file.pathw,
594 DWORD
error = GetLastError();
614 else if (GetLastError() != ERROR_SUCCESS)
623 FILE_STANDARD_INFO file_info;
624 if (!GetFileInformationByHandleEx(
file,
635 fd_info.
size.QuadPart = 0;
644 if (fd_info.
size.QuadPart == 0) {
652 fd_info.
size.HighPart,
653 fd_info.
size.LowPart,
674 int fd =
req->file.fd;
695 assert(errno == EBADF);
705 if (excode != EXCEPTION_IN_PAGE_ERROR) {
706 return EXCEPTION_CONTINUE_SEARCH;
709 assert(perror != NULL);
710 if (pep != NULL && pep->ExceptionRecord != NULL &&
711 pep->ExceptionRecord->NumberParameters >= 3) {
714 if (*perror != ERROR_SUCCESS) {
715 return EXCEPTION_EXECUTE_HANDLER;
718 *perror = UV_UNKNOWN;
719 return EXCEPTION_EXECUTE_HANDLER;
724 int fd =
req->file.fd;
725 int rw_flags = fd_info->
flags &
729 LARGE_INTEGER
pos, end_pos;
731 LARGE_INTEGER view_base;
743 if (
req->fs.info.offset == -1) {
746 pos.QuadPart =
req->fs.info.offset;
750 if (
pos.QuadPart >= fd_info->
size.QuadPart) {
760 fd_info->
size.QuadPart -
pos.QuadPart);
769 view_base.QuadPart =
pos.QuadPart - view_offset;
770 view = MapViewOfFile(fd_info->
mapping,
785 size_t this_read_size =
MIN(
req->fs.info.bufs[
index].len,
791 (
char*)view + view_offset + done_read,
796 GetExceptionInformation(), &
err)) {
798 UnmapViewOfFile(view);
802 done_read += this_read_size;
806 if (!UnmapViewOfFile(view)) {
811 if (
req->fs.info.offset == -1) {
821 int fd =
req->file.fd;
824 OVERLAPPED overlapped, *overlapped_ptr;
825 LARGE_INTEGER offset_;
830 LARGE_INTEGER original_position;
831 LARGE_INTEGER zero_offset;
832 int restore_position;
842 zero_offset.QuadPart = 0;
843 restore_position = 0;
852 memset(&overlapped, 0,
sizeof overlapped);
853 overlapped_ptr = &overlapped;
854 if (SetFilePointerEx(
handle, zero_offset, &original_position,
856 restore_position = 1;
859 overlapped_ptr = NULL;
865 DWORD incremental_bytes;
869 overlapped.Offset = offset_.LowPart;
870 overlapped.OffsetHigh = offset_.HighPart;
878 bytes += incremental_bytes;
880 }
while (
result && index < req->fs.info.nbufs);
882 if (restore_position)
883 SetFilePointerEx(
handle, original_position, NULL, FILE_BEGIN);
888 error = GetLastError();
889 if (
error == ERROR_HANDLE_EOF) {
900 int fd =
req->file.fd;
902 int rw_flags = fd_info->
flags &
906 LARGE_INTEGER zero,
pos, end_pos;
908 LARGE_INTEGER view_base;
923 write_size +=
req->fs.info.bufs[
index].len;
926 if (write_size == 0) {
934 }
else if (
req->fs.info.offset == -1) {
937 pos.QuadPart =
req->fs.info.offset;
940 end_pos.QuadPart =
pos.QuadPart + write_size;
943 if (end_pos.QuadPart > fd_info->
size.QuadPart) {
954 if (fd_info->
mapping == NULL) {
958 fd_info->
size.QuadPart = 0;
964 fd_info->
size = end_pos;
969 view_base.QuadPart =
pos.QuadPart - view_offset;
970 view = MapViewOfFile(fd_info->
mapping,
974 view_offset + write_size);
992 GetExceptionInformation(), &
err)) {
994 UnmapViewOfFile(view);
1002 if (!FlushViewOfFile(view, 0)) {
1004 UnmapViewOfFile(view);
1007 if (!UnmapViewOfFile(view)) {
1012 if (
req->fs.info.offset == -1) {
1017 GetSystemTimeAsFileTime(&ft);
1018 SetFileTime(
file, NULL, NULL, &ft);
1024 int fd =
req->file.fd;
1027 OVERLAPPED overlapped, *overlapped_ptr;
1028 LARGE_INTEGER offset_;
1032 LARGE_INTEGER original_position;
1033 LARGE_INTEGER zero_offset;
1034 int restore_position;
1039 zero_offset.QuadPart = 0;
1040 restore_position = 0;
1053 memset(&overlapped, 0,
sizeof overlapped);
1054 overlapped_ptr = &overlapped;
1055 if (SetFilePointerEx(
handle, zero_offset, &original_position,
1057 restore_position = 1;
1060 overlapped_ptr = NULL;
1066 DWORD incremental_bytes;
1070 overlapped.Offset = offset_.LowPart;
1071 overlapped.OffsetHigh = offset_.HighPart;
1079 bytes += incremental_bytes;
1081 }
while (
result && index < req->fs.info.nbufs);
1083 if (restore_position)
1084 SetFilePointerEx(
handle, original_position, NULL, FILE_BEGIN);
1101 const WCHAR* pathw =
req->file.pathw;
1103 BY_HANDLE_FILE_INFORMATION info;
1108 handle = CreateFileW(pathw,
1109 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
1110 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1113 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
1121 if (!GetFileInformationByHandle(
handle, &info)) {
1127 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1133 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
1142 DWORD
error = GetLastError();
1144 error = ERROR_ACCESS_DENIED;
1151 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
1155 basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
1156 FILE_ATTRIBUTE_ARCHIVE;
1189 req->result = _wmkdir(
req->file.pathw);
1190 if (
req->result == -1) {
1191 req->sys_errno_ = _doserrno;
1192 req->result =
req->sys_errno_ == ERROR_INVALID_NAME
1202 static const WCHAR *tempchars =
1203 L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1204 static const size_t num_chars = 62;
1205 static const size_t num_x = 6;
1207 unsigned int tries,
i;
1211 len = wcslen(
req->file.pathw);
1212 ep =
req->file.pathw +
len;
1213 if (
len < num_x || wcsncmp(ep - num_x,
L"XXXXXX", num_x)) {
1226 for (
i = 0;
i < num_x;
i++) {
1227 *cp++ = tempchars[
v % num_chars];
1232 if (
req->result >= 0) {
1234 wcstombs((
char*)
req->path +
len - num_x, ep - num_x, num_x);
1247 if (_wmkdir(
req->file.pathw) == 0) {
1250 }
else if (errno != EEXIST) {
1268 file = CreateFileW(
req->file.pathw,
1269 GENERIC_READ | GENERIC_WRITE,
1270 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1273 FILE_ATTRIBUTE_NORMAL,
1278 error = GetLastError();
1282 if (
error != ERROR_FILE_EXISTS) {
1296 if (errno == EMFILE)
1298 else if (GetLastError() != ERROR_SUCCESS)
1318 static const size_t dirents_initial_size = 32;
1323 size_t dirents_size = 0;
1324 size_t dirents_used = 0;
1346 CreateFileW(
req->file.pathw,
1347 FILE_LIST_DIRECTORY | SYNCHRONIZE,
1348 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1351 FILE_FLAG_BACKUP_SEMANTICS,
1373 goto not_a_directory_error;
1377 size_t next_entry_offset = 0;
1400 while (wchar_len > 0 && info->
FileName[wchar_len - 1] ==
L'\0')
1405 if (wchar_len == 1 && info->
FileName[0] ==
L'.')
1407 if (wchar_len == 2 && info->
FileName[0] ==
L'.' &&
1412 utf8_len = WideCharToMultiByte(
1413 CP_UTF8, 0, &info->
FileName[0], wchar_len, NULL, 0, NULL, NULL);
1418 if (dirents_used >= dirents_size) {
1419 size_t new_dirents_size =
1420 dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
1424 if (new_dirents == NULL)
1425 goto out_of_memory_error;
1427 dirents_size = new_dirents_size;
1435 dirent =
uv__malloc(
sizeof *dirent + utf8_len);
1437 goto out_of_memory_error;
1439 dirents[dirents_used++] = dirent;
1442 if (WideCharToMultiByte(CP_UTF8,
1453 dirent->d_name[utf8_len] =
'\0';
1464 }
while (next_entry_offset != 0);
1490 CloseHandle(dir_handle);
1500 req->fs.info.nbufs = 0;
1512 not_a_directory_error:
1516 out_of_memory_error:
1522 CloseHandle(dir_handle);
1523 while (dirents_used > 0)
1536 pathw =
req->file.pathw;
1541 if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
1552 len = wcslen(pathw);
1568 dir->dir_handle = FindFirstFileW(
find_path, &dir->find_data);
1572 GetLastError() != ERROR_FILE_NOT_FOUND) {
1577 dir->need_find_call =
FALSE;
1592 unsigned int dirent_idx;
1593 PWIN32_FIND_DATAW find_data;
1601 find_data = &dir->find_data;
1604 while (dirent_idx < dir->nentries) {
1605 if (dir->need_find_call && FindNextFileW(dir->dir_handle, find_data) == 0) {
1606 if (GetLastError() == ERROR_NO_MORE_FILES)
1612 if (find_data->cFileName[0] ==
L'.' &&
1613 (find_data->cFileName[1] ==
L'\0' ||
1614 (find_data->cFileName[1] ==
L'.' &&
1615 find_data->cFileName[2] ==
L'\0'))) {
1616 dir->need_find_call =
TRUE;
1627 if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
1629 else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
1631 else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
1637 dir->need_find_call =
TRUE;
1646 for (
i = 0;
i < dirent_idx; ++
i) {
1656 FindClose(dir->dir_handle);
1749 statbuf->
st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
1751 statbuf->
st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
1752 ((_S_IREAD | _S_IWRITE) >> 6);
1803 size_t len = wcslen(pathw);
1806 if (
len > 1 && pathw[
len - 2] !=
L':' &&
1807 (pathw[
len - 1] ==
L'\\' || pathw[
len - 1] ==
L'/')) {
1808 pathw[
len - 1] =
'\0';
1820 flags = FILE_FLAG_BACKUP_SEMANTICS;
1822 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
1825 FILE_READ_ATTRIBUTES,
1826 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1833 ret = GetLastError();
1835 ret = GetLastError();
1851 error == ERROR_NOT_A_REPARSE_POINT)) {
1862 req->ptr = &
req->statbuf;
1880 int fd =
req->file.fd;
1897 req->ptr = &
req->statbuf;
1903 if (!MoveFileExW(
req->file.pathw,
req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
1913 int fd =
req->file.fd;
1938 int fd =
req->file.fd;
1973 if (fd_info.
flags) {
1976 fd_info.
size.QuadPart = 0;
1983 if (fd_info.
flags) {
1986 if (fd_info.
size.QuadPart == 0) {
1994 fd_info.
size.HighPart,
1995 fd_info.
size.LowPart,
1997 if (fd_info.
mapping == NULL) {
2001 fd_info.
size.QuadPart = 0;
2028 if (CopyFileW(
req->file.pathw,
req->fs.info.new_pathw, overwrite) != 0) {
2034 if (
req->result != UV_EBUSY)
2051 int fd_in =
req->file.fd, fd_out =
req->fs.info.fd_out;
2052 size_t length =
req->fs.info.bufsml[0].len;
2054 const size_t max_buf_size = 65536;
2055 size_t buf_size =
length < max_buf_size ?
length : max_buf_size;
2067 if (result_offset == -1) {
2074 }
else if (
n == -1) {
2081 n = _write(fd_out,
buf,
n);
2098 DWORD
attr = GetFileAttributesW(
req->file.pathw);
2100 if (
attr == INVALID_FILE_ATTRIBUTES) {
2112 if (!(
req->fs.info.mode &
W_OK) ||
2113 !(
attr & FILE_ATTRIBUTE_READONLY) ||
2114 (
attr & FILE_ATTRIBUTE_DIRECTORY)) {
2124 int result = _wchmod(
req->file.pathw,
req->fs.info.mode);
2130 int fd =
req->file.fd;
2131 int clear_archive_flag;
2153 goto fchmod_cleanup;
2168 goto fchmod_cleanup;
2171 clear_archive_flag = 1;
2173 clear_archive_flag = 0;
2176 if (
req->fs.info.mode & _S_IWRITE) {
2190 goto fchmod_cleanup;
2193 if (clear_archive_flag) {
2205 goto fchmod_cleanup;
2216 FILETIME filetime_a, filetime_m;
2221 if (!SetFileTime(
handle, NULL, &filetime_a, &filetime_m)) {
2236 flags = FILE_FLAG_BACKUP_SEMANTICS;
2238 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
2242 FILE_WRITE_ATTRIBUTES,
2243 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2250 ret = GetLastError();
2252 ret = GetLastError();
2272 error == ERROR_NOT_A_REPARSE_POINT)) {
2292 int fd =
req->file.fd;
2317 DWORD
r = CreateHardLinkW(
req->fs.info.new_pathw,
req->file.pathw, NULL);
2327 const WCHAR* new_path) {
2329 REPARSE_DATA_BUFFER *
buffer = NULL;
2332 int is_absolute, is_long_path;
2333 int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
2339 target_len = wcslen(
path);
2357 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
2359 2 * (target_len + 2) *
sizeof(WCHAR);
2368 path_buf = (WCHAR*)&(
buffer->MountPointReparseBuffer.PathBuffer);
2372 start = path_buf_len;
2386 path_buf[path_buf_len++] =
L'\\';
2390 path_buf[path_buf_len++] =
path[
i];
2392 path_buf[path_buf_len++] =
L'\\';
2396 buffer->MountPointReparseBuffer.SubstituteNameOffset =
start *
sizeof(WCHAR);
2397 buffer->MountPointReparseBuffer.SubstituteNameLength =
len *
sizeof(WCHAR);
2400 path_buf[path_buf_len++] =
L'\0';
2403 start = path_buf_len;
2412 path_buf[path_buf_len++] =
L'\\';
2416 path_buf[path_buf_len++] =
path[
i];
2420 path_buf[path_buf_len++] =
L'\\';
2425 buffer->MountPointReparseBuffer.PrintNameOffset =
start *
sizeof(WCHAR);
2426 buffer->MountPointReparseBuffer.PrintNameLength =
len *
sizeof(WCHAR);
2429 path_buf[path_buf_len++] =
L'\0';
2432 used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
2433 path_buf_len *
sizeof(WCHAR);
2434 used_data_size = used_buf_size -
2435 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
2438 buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
2439 buffer->ReparseDataLength = used_data_size;
2443 if (!CreateDirectoryW(new_path, NULL)) {
2450 handle = CreateFileW(new_path,
2455 FILE_FLAG_BACKUP_SEMANTICS |
2456 FILE_FLAG_OPEN_REPARSE_POINT,
2464 if (!DeviceIoControl(
handle,
2491 RemoveDirectoryW(new_path);
2502 pathw =
req->file.pathw;
2503 new_pathw =
req->fs.info.new_pathw;
2515 if (CreateSymbolicLinkW(new_pathw, pathw,
flags)) {
2523 err = GetLastError();
2524 if (
err == ERROR_INVALID_PARAMETER &&
2545 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
2568 DWORD w_realpath_len;
2569 WCHAR* w_realpath_ptr = NULL;
2570 WCHAR* w_realpath_buf;
2572 w_realpath_len = GetFinalPathNameByHandleW(
handle, NULL, 0, VOLUME_NAME_DOS);
2573 if (w_realpath_len == 0) {
2577 w_realpath_buf =
uv__malloc((w_realpath_len + 1) *
sizeof(WCHAR));
2578 if (w_realpath_buf == NULL) {
2579 SetLastError(ERROR_OUTOFMEMORY);
2582 w_realpath_ptr = w_realpath_buf;
2584 if (GetFinalPathNameByHandleW(
2585 handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) {
2587 SetLastError(ERROR_INVALID_HANDLE);
2592 if (wcsncmp(w_realpath_ptr,
2595 w_realpath_ptr += 6;
2596 *w_realpath_ptr =
L'\\';
2597 w_realpath_len -= 6;
2598 }
else if (wcsncmp(w_realpath_ptr,
2601 w_realpath_ptr += 4;
2602 w_realpath_len -= 4;
2605 SetLastError(ERROR_INVALID_HANDLE);
2622 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
2658 DWORD sectors_per_cluster;
2659 DWORD bytes_per_sector;
2660 DWORD free_clusters;
2661 DWORD total_clusters;
2664 pathw =
req->file.pathw;
2665 retry_get_disk_free_space:
2666 if (0 == GetDiskFreeSpaceW(pathw,
2667 §ors_per_cluster,
2677 err = GetLastError();
2678 is_second = pathw !=
req->file.pathw;
2679 if (
err != ERROR_DIRECTORY || is_second) {
2689 if (pathw == NULL) {
2693 retry_get_full_path_name:
2694 ret = GetFullPathNameW(
req->file.pathw,
2705 if (pathw == NULL) {
2709 goto retry_get_full_path_name;
2714 goto retry_get_disk_free_space;
2716 if (pathw !=
req->file.pathw) {
2721 if (stat_fs == NULL) {
2727 stat_fs->
f_bsize = bytes_per_sector * sectors_per_cluster;
2728 stat_fs->
f_blocks = total_clusters;
2729 stat_fs->
f_bfree = free_clusters;
2743 assert(
req->type == UV_FS);
2745 #define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
2746 switch (
req->fs_type) {
2751 XX(COPYFILE, copyfile)
2752 XX(SENDFILE, sendfile)
2756 XX(FTRUNCATE, ftruncate)
2764 XX(FDATASYNC, fdatasync)
2769 XX(MKSTEMP, mkstemp)
2772 XX(READDIR, readdir)
2773 XX(OPENDIR, opendir)
2774 XX(CLOSEDIR, closedir)
2776 XX(SYMLINK, symlink)
2777 XX(READLINK, readlink)
2778 XX(REALPATH, realpath)
2784 assert(!
"bad uv_fs_type");
2795 if (
status == UV_ECANCELED) {
2796 assert(
req->result == 0);
2797 req->result = UV_ECANCELED;
2823 if (
req->fs.info.bufs !=
req->fs.info.bufsml)
2827 req->file.pathw = NULL;
2828 req->fs.info.new_pathw = NULL;
2829 req->fs.info.bufs = NULL;
2868 if (
bufs == NULL || nbufs == 0)
2873 req->fs.info.nbufs = nbufs;
2874 req->fs.info.bufs =
req->fs.info.bufsml;
2878 if (
req->fs.info.bufs == NULL)
2897 if (
bufs == NULL || nbufs == 0)
2902 req->fs.info.nbufs = nbufs;
2903 req->fs.info.bufs =
req->fs.info.bufsml;
2907 if (
req->fs.info.bufs == NULL)
3212 const char* new_path,
3238 req->file.fd = fd_in;
3239 req->fs.info.fd_out = fd_out;
3240 req->fs.info.offset = in_offset;
3297 req->fs.time.atime = atime;
3298 req->fs.time.mtime = mtime;
3307 req->fs.time.atime = atime;
3308 req->fs.time.mtime = mtime;
3322 req->fs.time.atime = atime;
3323 req->fs.time.mtime = mtime;