Skip to content

Instantly share code, notes, and snippets.

@igorzi
Created November 23, 2011 20:30
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 igorzi/1389807 to your computer and use it in GitHub Desktop.
Save igorzi/1389807 to your computer and use it in GitHub Desktop.
From d092eebc5372e4df44be25cf40b777df8b7cdda0 Mon Sep 17 00:00:00 2001
From: Igor Zinkovsky <igorzi@microsoft.com>
Date: Tue, 22 Nov 2011 00:38:29 -0800
Subject: [PATCH] windows: enables uv_fs_open and uv_fs_stat to work with long paths
---
src/win/fs.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 109 insertions(+), 31 deletions(-)
diff --git a/src/win/fs.c b/src/win/fs.c
index c6d86b0..3bdb8ab 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -492,13 +492,20 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) {
void fs__stat(uv_fs_t* req, const wchar_t* path) {
int result;
- result = _wstati64(path, &req->stat);
+ fs__open(req, path, _O_RDONLY, 0);
+ if (req->result == -1) {
+ return;
+ }
+
+ result = _fstati64(req->result, &req->stat);
if (result == -1) {
req->ptr = NULL;
} else {
req->ptr = &req->stat;
}
+ _close(req->result);
+
SET_REQ_RESULT(req, result);
}
@@ -902,13 +909,71 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
}
+static int fs__make_ext_path(uv_loop_t* loop, const char* path,
+ wchar_t** long_path) {
+ const wchar_t lfs_ext_len_prefix[] = L"\\\\?\\";
+ const wchar_t unc_ext_len_prefix[] = L"\\\\?\\UNC\\";
+ int convert_lfs_to_ext_len = 0, convert_unc_to_ext_len = 0;
+ int size, offset = 0;
+
+ size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(wchar_t);
+
+ if (size >= 3) {
+ if (isalpha(path[0]) && path[1] == ':' && path[2] == '\\') {
+ /*
+ * path is local filesystem path, which needs to be converted
+ * to long UNC path.
+ */
+ convert_lfs_to_ext_len = 1;
+ offset = COUNTOF(lfs_ext_len_prefix) - 1;
+ } else if (memcmp(path, "\\\\", 2) == 0 &&
+ (size < 4 || memcmp(path + 2, "?\\", 2) != 0)) {
+ /*
+ * path is network UNC path, which needs to be converted
+ * to long UNC path.
+ */
+ convert_unc_to_ext_len = 1;
+ offset = COUNTOF(unc_ext_len_prefix) - 1;
+ }
+ }
+
+ *long_path = (wchar_t*)malloc(size + (offset * sizeof(wchar_t)));
+ if (!*long_path) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
+
+ if (!uv_utf8_to_utf16(path, *long_path + offset, size / sizeof(wchar_t))) {
+ return -1;
+ }
+
+ if (convert_lfs_to_ext_len) {
+ memcpy(*long_path, lfs_ext_len_prefix, sizeof(lfs_ext_len_prefix) -
+ (1 * sizeof(*lfs_ext_len_prefix)));
+ } else if (convert_unc_to_ext_len) {
+ memcpy(*long_path, unc_ext_len_prefix, sizeof(unc_ext_len_prefix) -
+ (1 * sizeof(*unc_ext_len_prefix)));
+ }
+
+ return 0;
+}
+
+
int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
int mode, uv_fs_cb cb) {
- wchar_t* pathw;
- int size;
+ wchar_t* pathw = NULL;
- /* Convert to UTF16. */
- UTF8_TO_UTF16(path, pathw);
+ if (fs__make_ext_path(loop, path, &pathw) == -1) {
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_OPEN, NULL, NULL, cb);
+ req->result = -1;
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return 0;
+ } else {
+ uv__set_sys_error(loop, GetLastError());
+ return -1;
+ }
+ }
if (cb) {
uv_fs_req_init_async(loop, req, UV_FS_OPEN, path, pathw, cb);
@@ -1193,7 +1258,6 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int len = strlen(path);
char* path2 = NULL;
wchar_t* pathw;
- int size;
if (len > 1 && path[len - 2] != ':' &&
(path[len - 1] == '\\' || path[len - 1] == '/')) {
@@ -1203,26 +1267,33 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
}
path2[len - 1] = '\0';
+ } else if (cb) {
+ path2 = strdup(path);
}
- if (cb) {
- uv_fs_req_init_async(loop, req, UV_FS_STAT, NULL, NULL, cb);
- if (path2) {
- req->path = path2;
- UTF8_TO_UTF16(path2, req->pathw);
+ if (fs__make_ext_path(loop, path2 ? path2 : path, &pathw) == -1) {
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_STAT, NULL, NULL, cb);
+ req->result = -1;
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return 0;
} else {
- req->path = strdup(path);
- UTF8_TO_UTF16(path, req->pathw);
- }
+ uv__set_sys_error(loop, GetLastError());
+ return -1;
+ }
+ }
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_STAT, NULL, NULL, cb);
+ assert(path2);
+ req->path = path2;
+ req->pathw = pathw;
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);
- if (path2) {
- free(path2);
- }
+ free(path2);
free(pathw);
SET_UV_LAST_ERROR_FROM_REQ(req);
return req->result;
@@ -1237,7 +1308,6 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int len = strlen(path);
char* path2 = NULL;
wchar_t* pathw;
- int size;
if (len > 1 && path[len - 2] != ':' &&
(path[len - 1] == '\\' || path[len - 1] == '/')) {
@@ -1247,26 +1317,33 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
}
path2[len - 1] = '\0';
+ } else if (cb) {
+ path2 = strdup(path);
}
- if (cb) {
- uv_fs_req_init_async(loop, req, UV_FS_LSTAT, NULL, NULL, cb);
- if (path2) {
- req->path = path2;
- UTF8_TO_UTF16(path2, req->pathw);
+ if (fs__make_ext_path(loop, path2 ? path2 : path, &pathw) == -1) {
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_LSTAT, NULL, NULL, cb);
+ req->result = -1;
+ SET_REQ_RESULT_WIN32_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return 0;
} else {
- req->path = strdup(path);
- UTF8_TO_UTF16(path, req->pathw);
- }
+ uv__set_sys_error(loop, GetLastError());
+ return -1;
+ }
+ }
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_LSTAT, NULL, NULL, cb);
+ assert(path2);
+ req->path = path2;
+ req->pathw = pathw;
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);
- if (path2) {
- free(path2);
- }
+ free(path2);
free(pathw);
SET_UV_LAST_ERROR_FROM_REQ(req);
return req->result;
@@ -1517,3 +1594,4 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
req->flags |= UV_FS_CLEANEDUP;
}
+
--
1.7.4.msysgit.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment