Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save piscisaureus/1724004 to your computer and use it in GitHub Desktop.
Save piscisaureus/1724004 to your computer and use it in GitHub Desktop.
From 3af75514d92c4fb0e9608ff66584f3ddd52adf8d Mon Sep 17 00:00:00 2001
From: Bert Belder <bertbelder@gmail.com>
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