Created
February 2, 2012 15:31
-
-
Save piscisaureus/1724004 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 3af75514d92c4fb0e9608ff66584f3ddd52adf8d Mon Sep 17 00:00:00 2001 | |
From: Bert Belder <[email protected]> | |
Date: Thu, 2 Feb 2012 16:23:57 +0100 | |
Subject: [PATCH 1/1] Windows: better stat implementation | |
--- | |
src/win/fs.c | 184 ++++++++----------------------------------------------- | |
test/test-fs.c | 13 ++++ | |
2 files changed, 40 insertions(+), 157 deletions(-) | |
diff --git a/src/win/fs.c b/src/win/fs.c | |
index 5248ac2..12ad514 100644 | |
--- a/src/win/fs.c | |
+++ b/src/win/fs.c | |
@@ -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); | |
} | |
diff --git a/test/test-fs.c b/test/test-fs.c | |
index b88636b..52b34ea 100644 | |
--- a/test/test-fs.c | |
+++ b/test/test-fs.c | |
@@ -1296,6 +1296,19 @@ TEST_IMPL(fs_stat_root) { | |
r = uv_fs_stat(loop, &stat_req, "\\", NULL); | |
ASSERT(r == 0); | |
+ r = uv_fs_stat(loop, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL); | |
+ ASSERT(r == 0); | |
+ | |
+ r = uv_fs_stat(loop, &stat_req, "..", NULL); | |
+ ASSERT(r == 0); | |
+ | |
+ r = uv_fs_stat(loop, &stat_req, "..\\", NULL); | |
+ ASSERT(r == 0); | |
+ | |
+ /* stats the current directory on c: */ | |
+ r = uv_fs_stat(loop, &stat_req, "c:", NULL); | |
+ ASSERT(r == 0); | |
+ | |
r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); | |
ASSERT(r == 0); | |
-- | |
1.7.7.1.msysgit.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment