|
|
@ -489,191 +489,61 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#define IS_SLASH(c) \ |
|
|
|
((wchar_t) c == L'/' || (wchar_t) c == L'\\') |
|
|
|
#define IS_COLON(c) \ |
|
|
|
((wchar_t) c == L':') |
|
|
|
#define IS_LETTER(c) \ |
|
|
|
((((wchar_t) c >= L'a') && ((wchar_t) c <= L'z')) || \ |
|
|
|
(((wchar_t) c >= L'A') && ((wchar_t) c <= L'Z'))) |
|
|
|
#define IS_QUESTION(c) \ |
|
|
|
((wchar_t) c == L'?') |
|
|
|
|
|
|
|
|
|
|
|
static int uv__count_slash_separated_words(const wchar_t* pos, |
|
|
|
const wchar_t* end, |
|
|
|
int limit) { |
|
|
|
char last_was_slash = 1, count = 0; |
|
|
|
|
|
|
|
for (; pos < end; pos++) { |
|
|
|
if (IS_SLASH(*pos)) { |
|
|
|
/* Don't accept double slashes */ |
|
|
|
if (last_was_slash) { |
|
|
|
return 0; |
|
|
|
} else { |
|
|
|
last_was_slash = 1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (last_was_slash) { |
|
|
|
/* Found a new word */ |
|
|
|
count++; |
|
|
|
if (count > limit) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
last_was_slash = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return count; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns true if the given path is a root directory. The following patterns |
|
|
|
* are recognized: |
|
|
|
* \ |
|
|
|
* c:\ (must have trailing slash) |
|
|
|
* \\server\share (trailing slash optional) |
|
|
|
* \\?\c: (trailing slash optional) |
|
|
|
* \\?\UNC\server\share (trailing slash optional) |
|
|
|
*/ |
|
|
|
static int uv__is_root(const wchar_t* path) { |
|
|
|
size_t len = wcslen(path); |
|
|
|
|
|
|
|
/* Test for \ */ |
|
|
|
if (len == 1 && IS_SLASH(path[0])) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (len < 3) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Test for c:\ */ |
|
|
|
if (IS_LETTER(path[0]) && IS_COLON(path[1]) && IS_SLASH(path[2])) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (!IS_SLASH(path[0]) || !IS_SLASH(path[1])) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Test for \\server\share */ |
|
|
|
if (!IS_QUESTION(path[2])) { |
|
|
|
return uv__count_slash_separated_words(path + 2, path + len, 2) == 2; |
|
|
|
} |
|
|
|
|
|
|
|
if (!IS_SLASH(path[3])) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
if ((len == 6 || len == 7) && |
|
|
|
IS_LETTER(path[4]) && IS_COLON(path[5]) && |
|
|
|
(len == 6 || IS_SLASH(path[6]))) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* Test for \\?\UNC\server\share */ |
|
|
|
if (len >= 8 && |
|
|
|
(path[4] == L'u' || path[4] == L'U') && |
|
|
|
(path[5] == L'n' || path[5] == L'N') && |
|
|
|
(path[6] == L'c' || path[6] == L'C') && |
|
|
|
IS_SLASH(path[7])) { |
|
|
|
return uv__count_slash_separated_words(path + 8, path + len, 2) == 2; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void fs__stat(uv_fs_t* req, const wchar_t* path) { |
|
|
|
HANDLE file; |
|
|
|
WIN32_FIND_DATAW ent; |
|
|
|
static void fs__stat(uv_fs_t* req, const wchar_t* path) { |
|
|
|
HANDLE handle; |
|
|
|
int result; |
|
|
|
BY_HANDLE_FILE_INFORMATION info; |
|
|
|
|
|
|
|
req->ptr = NULL; |
|
|
|
|
|
|
|
if (uv__is_root(path)) { |
|
|
|
/* We can't stat root directories like c:\. _wstati64 can't either, but */ |
|
|
|
/* it will make up something reasonable. */ |
|
|
|
DWORD drive_type = GetDriveTypeW(path); |
|
|
|
if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { |
|
|
|
req->last_error = ERROR_PATH_NOT_FOUND; |
|
|
|
req->errorno = UV_ENOENT; |
|
|
|
req->result = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
memset(&req->stat, 0, sizeof req->stat); |
|
|
|
|
|
|
|
req->stat.st_nlink = 1; |
|
|
|
req->stat.st_mode = ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + |
|
|
|
((_S_IREAD|_S_IWRITE) >> 6)) | S_IFDIR; |
|
|
|
|
|
|
|
req->last_error = ERROR_SUCCESS; |
|
|
|
req->errorno = UV_OK; |
|
|
|
req->result = 0; |
|
|
|
req->ptr = &req->stat; |
|
|
|
handle = CreateFileW(path, |
|
|
|
FILE_READ_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_RESULT_WIN32_ERROR(req, GetLastError()); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
file = FindFirstFileExW(path, FindExInfoStandard, &ent, |
|
|
|
FindExSearchNameMatch, NULL, 0); |
|
|
|
|
|
|
|
if (file == INVALID_HANDLE_VALUE) { |
|
|
|
if (!GetFileInformationByHandle(handle, &info)) { |
|
|
|
SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); |
|
|
|
CloseHandle(handle); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
FindClose(file); |
|
|
|
|
|
|
|
if (ent.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && |
|
|
|
ent.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { |
|
|
|
fs__open(req, path, _O_RDONLY, 0); |
|
|
|
if (req->result != -1) { |
|
|
|
result = _fstati64(req->result, &req->stat); |
|
|
|
_close(req->result); |
|
|
|
|
|
|
|
if (result != -1) { |
|
|
|
req->ptr = &req->stat; |
|
|
|
} |
|
|
|
|
|
|
|
SET_REQ_RESULT(req, result); |
|
|
|
} |
|
|
|
memset(&req->stat, 0, sizeof req->stat); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
/* TODO: set st_dev and st_ino? */ |
|
|
|
|
|
|
|
req->stat.st_ino = 0; |
|
|
|
req->stat.st_uid = 0; |
|
|
|
req->stat.st_gid = 0; |
|
|
|
req->stat.st_mode = 0; |
|
|
|
req->stat.st_rdev = 0; |
|
|
|
req->stat.st_dev = 0; |
|
|
|
req->stat.st_nlink = 1; |
|
|
|
|
|
|
|
if (ent.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) { |
|
|
|
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 (ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
|
|
|
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
|
|
|
req->stat.st_mode |= _S_IFDIR; |
|
|
|
} else { |
|
|
|
req->stat.st_mode |= _S_IFREG; |
|
|
|
} |
|
|
|
|
|
|
|
uv_filetime_to_time_t(&ent.ftLastWriteTime, &(req->stat.st_mtime)); |
|
|
|
uv_filetime_to_time_t(&ent.ftLastAccessTime, &(req->stat.st_atime)); |
|
|
|
uv_filetime_to_time_t(&ent.ftCreationTime, &(req->stat.st_ctime)); |
|
|
|
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_size = ((int64_t)ent.nFileSizeHigh << 32) + |
|
|
|
(int64_t)ent.nFileSizeLow; |
|
|
|
req->stat.st_nlink = info.nNumberOfLinks; |
|
|
|
|
|
|
|
req->ptr = &req->stat; |
|
|
|
req->result = 0; |
|
|
|
|
|
|
|
CloseHandle(handle); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|