Created
November 23, 2011 20:30
-
-
Save igorzi/1389807 to your computer and use it in GitHub Desktop.
This file contains 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 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