Created
September 3, 2011 18:07
-
-
Save igorzi/1191551 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 f1bf11eb59921bed44e1e01ae33e117907a9afc8 Mon Sep 17 00:00:00 2001 | |
From: Igor Zinkovsky <igorzi@microsoft.com> | |
Date: Sat, 3 Sep 2011 11:06:08 -0700 | |
Subject: [PATCH] windows: implement missing fs functions | |
--- | |
src/win/fs.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++------- | |
src/win/winapi.c | 8 +++ | |
src/win/winapi.h | 15 ++++++ | |
test/test-fs.c | 112 ++++++++++++++++++++++++++++++++++++++-- | |
test/test-list.h | 2 + | |
5 files changed, 262 insertions(+), 24 deletions(-) | |
diff --git a/src/win/fs.c b/src/win/fs.c | |
index cd64718..63d569b 100644 | |
--- a/src/win/fs.c | |
+++ b/src/win/fs.c | |
@@ -323,6 +323,50 @@ void fs__chmod(uv_fs_t* req, const char* path, int mode) { | |
} | |
+void fs__fchmod(uv_fs_t* req, uv_file file, int mode) { | |
+ int result; | |
+ HANDLE handle; | |
+ NTSTATUS nt_status; | |
+ IO_STATUS_BLOCK io_status; | |
+ FILE_BASIC_INFORMATION file_info; | |
+ | |
+ handle = (HANDLE)_get_osfhandle(file); | |
+ | |
+ nt_status = pNtQueryInformationFile(handle, | |
+ &io_status, | |
+ &file_info, | |
+ sizeof file_info, | |
+ FileBasicInformation); | |
+ | |
+ if (nt_status != STATUS_SUCCESS) { | |
+ result = -1; | |
+ goto done; | |
+ } | |
+ | |
+ if (mode & _S_IWRITE) { | |
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; | |
+ } else { | |
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; | |
+ } | |
+ | |
+ nt_status = pNtSetInformationFile(handle, | |
+ &io_status, | |
+ &file_info, | |
+ sizeof file_info, | |
+ FileBasicInformation); | |
+ | |
+ if (nt_status != STATUS_SUCCESS) { | |
+ result = -1; | |
+ goto done; | |
+ } | |
+ | |
+ result = 0; | |
+ | |
+done: | |
+ SET_REQ_RESULT(req, result); | |
+} | |
+ | |
+ | |
void fs__utime(uv_fs_t* req, const char* path, double atime, double mtime) { | |
int result; | |
struct _utimbuf b = {(time_t)atime, (time_t)mtime}; | |
@@ -339,6 +383,11 @@ void fs__futime(uv_fs_t* req, uv_file file, double atime, double mtime) { | |
} | |
+void fs__nop(uv_fs_t* req) { | |
+ req->result = 0; | |
+} | |
+ | |
+ | |
static DWORD WINAPI uv_fs_thread_proc(void* parameter) { | |
uv_fs_t* req = (uv_fs_t*) parameter; | |
uv_loop_t* loop = req->loop; | |
@@ -380,6 +429,7 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { | |
fs__readdir(req, (const char*)req->arg0, (int)req->arg1); | |
break; | |
case UV_FS_STAT: | |
+ case UV_FS_LSTAT: | |
fs__stat(req, (const char*)req->arg0); | |
break; | |
case UV_FS_FSTAT: | |
@@ -405,12 +455,19 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { | |
case UV_FS_CHMOD: | |
fs__chmod(req, (const char*)req->arg0, (int)req->arg1); | |
break; | |
+ case UV_FS_FCHMOD: | |
+ fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1); | |
+ break; | |
case UV_FS_UTIME: | |
fs__utime(req, (const char*)req->arg0, req->arg4, req->arg5); | |
break; | |
case UV_FS_FUTIME: | |
fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5); | |
break; | |
+ case UV_FS_CHOWN: | |
+ case UV_FS_FCHOWN: | |
+ fs__nop(req); | |
+ break; | |
default: | |
assert(!"bad uv_fs_type"); | |
} | |
@@ -544,13 +601,6 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, | |
} | |
-int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { | |
- assert(0 && "implement me"); | |
- return -1; | |
-} | |
- | |
- | |
-// uv_fs_readlink, uv_fs_fchmod, uv_fs_chown, uv_fs_fchown | |
int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, | |
const char* new_path, uv_fs_cb cb) { | |
assert(0 && "implement me"); | |
@@ -572,24 +622,34 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, | |
} | |
-int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, | |
- uv_fs_cb cb) { | |
- assert(0 && "implement me"); | |
- return -1; | |
-} | |
- | |
- | |
int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid, | |
int gid, uv_fs_cb cb) { | |
- assert(0 && "implement me"); | |
- return -1; | |
+ if (cb) { | |
+ uv_fs_req_init_async(loop, req, UV_FS_CHOWN, cb); | |
+ WRAP_REQ_ARGS3(req, path, uid, gid); | |
+ STRDUP_ARG(req, 0); | |
+ QUEUE_FS_TP_JOB(loop, req); | |
+ } else { | |
+ uv_fs_req_init_sync(loop, req, UV_FS_CHOWN); | |
+ fs__nop(req); | |
+ } | |
+ | |
+ return 0; | |
} | |
int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid, | |
int gid, uv_fs_cb cb) { | |
- assert(0 && "implement me"); | |
- return -1; | |
+ if (cb) { | |
+ uv_fs_req_init_async(loop, req, UV_FS_FCHOWN, cb); | |
+ WRAP_REQ_ARGS3(req, file, uid, gid); | |
+ QUEUE_FS_TP_JOB(loop, req); | |
+ } else { | |
+ uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN); | |
+ fs__nop(req); | |
+ } | |
+ | |
+ return 0; | |
} | |
@@ -630,6 +690,44 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { | |
} | |
+/* TODO: add support for links. */ | |
+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; | |
+ int has_backslash = (path[len - 1] == '\\' || path[len - 1] == '/'); | |
+ | |
+ if (path[len - 1] == '\\' || path[len - 1] == '/') { | |
+ path2 = strdup(path); | |
+ if (!path2) { | |
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); | |
+ } | |
+ | |
+ path2[len - 1] = '\0'; | |
+ } | |
+ | |
+ if (cb) { | |
+ uv_fs_req_init_async(loop, req, UV_FS_LSTAT, cb); | |
+ if (path2) { | |
+ WRAP_REQ_ARGS1(req, path2); | |
+ req->flags |= UV_FS_FREE_ARG0; | |
+ } else { | |
+ WRAP_REQ_ARGS1(req, path); | |
+ STRDUP_ARG(req, 0); | |
+ } | |
+ | |
+ QUEUE_FS_TP_JOB(loop, req); | |
+ } else { | |
+ uv_fs_req_init_sync(loop, req, UV_FS_LSTAT); | |
+ fs__stat(req, path2 ? path2 : path); | |
+ if (path2) { | |
+ free(path2); | |
+ } | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+ | |
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { | |
if (cb) { | |
uv_fs_req_init_async(loop, req, UV_FS_FSTAT, cb); | |
@@ -735,6 +833,21 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, | |
} | |
+int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, | |
+ uv_fs_cb cb) { | |
+ if (cb) { | |
+ uv_fs_req_init_async(loop, req, UV_FS_FCHMOD, cb); | |
+ WRAP_REQ_ARGS2(req, file, mode); | |
+ QUEUE_FS_TP_JOB(loop, req); | |
+ } else { | |
+ uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD); | |
+ fs__fchmod(req, file, mode); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+ | |
int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, | |
double mtime, uv_fs_cb cb) { | |
if (cb) { | |
diff --git a/src/win/winapi.c b/src/win/winapi.c | |
index 739cb9c..bf4d5e3 100644 | |
--- a/src/win/winapi.c | |
+++ b/src/win/winapi.c | |
@@ -28,6 +28,7 @@ | |
sRtlNtStatusToDosError pRtlNtStatusToDosError; | |
sNtQueryInformationFile pNtQueryInformationFile; | |
+sNtSetInformationFile pNtSetInformationFile; | |
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; | |
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; | |
@@ -55,6 +56,13 @@ void uv_winapi_init() { | |
uv_fatal_error(GetLastError(), "GetProcAddress"); | |
} | |
+ pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress( | |
+ ntdll_module, | |
+ "NtSetInformationFile"); | |
+ if (pNtSetInformationFile == NULL) { | |
+ uv_fatal_error(GetLastError(), "GetProcAddress"); | |
+ } | |
+ | |
kernel32_module = GetModuleHandleA("kernel32.dll"); | |
if (kernel32_module == NULL) { | |
uv_fatal_error(GetLastError(), "GetModuleHandleA"); | |
diff --git a/src/win/winapi.h b/src/win/winapi.h | |
index 00eda7c..9feee8b 100644 | |
--- a/src/win/winapi.h | |
+++ b/src/win/winapi.h | |
@@ -4096,6 +4096,14 @@ typedef struct _FILE_PIPE_LOCAL_INFORMATION { | |
ULONG NamedPipeEnd; | |
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; | |
+typedef struct _FILE_BASIC_INFORMATION { | |
+ LARGE_INTEGER CreationTime; | |
+ LARGE_INTEGER LastAccessTime; | |
+ LARGE_INTEGER LastWriteTime; | |
+ LARGE_INTEGER ChangeTime; | |
+ DWORD FileAttributes; | |
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; | |
+ | |
typedef enum _FILE_INFORMATION_CLASS { | |
FileDirectoryInformation = 1, | |
FileFullDirectoryInformation, | |
@@ -4165,6 +4173,12 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationFile) | |
ULONG Length, | |
FILE_INFORMATION_CLASS FileInformationClass); | |
+typedef NTSTATUS (NTAPI *sNtSetInformationFile) | |
+ (HANDLE FileHandle, | |
+ PIO_STATUS_BLOCK IoStatusBlock, | |
+ PVOID FileInformation, | |
+ ULONG Length, | |
+ FILE_INFORMATION_CLASS FileInformationClass); | |
/* | |
* Kernel32 headers | |
@@ -4197,6 +4211,7 @@ typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) | |
/* Ntapi function pointers */ | |
extern sRtlNtStatusToDosError pRtlNtStatusToDosError; | |
extern sNtQueryInformationFile pNtQueryInformationFile; | |
+extern sNtSetInformationFile pNtSetInformationFile; | |
/* Kernel32 function pointers */ | |
diff --git a/test/test-fs.c b/test/test-fs.c | |
index 1d172e5..9a649a4 100644 | |
--- a/test/test-fs.c | |
+++ b/test/test-fs.c | |
@@ -60,6 +60,8 @@ static int sendfile_cb_count; | |
static int fstat_cb_count; | |
static int chmod_cb_count; | |
static int fchmod_cb_count; | |
+static int chown_cb_count; | |
+static int fchown_cb_count; | |
static uv_loop_t* loop; | |
@@ -93,7 +95,7 @@ void check_permission(const char* filename, int mode) { | |
ASSERT(req.result == 0); | |
s = req.ptr; | |
- ASSERT((s->st_mode & 0777) == mode); | |
+ ASSERT((s->st_mode & 0777) & mode); | |
uv_fs_req_cleanup(&req); | |
} | |
@@ -104,7 +106,7 @@ static void fchmod_cb(uv_fs_t* req) { | |
ASSERT(req->result == 0); | |
fchmod_cb_count++; | |
uv_fs_req_cleanup(req); | |
- check_permission("test_file", 0600); | |
+ check_permission("test_file", (int)req->data); | |
} | |
@@ -113,7 +115,23 @@ static void chmod_cb(uv_fs_t* req) { | |
ASSERT(req->result == 0); | |
chmod_cb_count++; | |
uv_fs_req_cleanup(req); | |
- check_permission("test_file", 0200); | |
+ check_permission("test_file", (int)req->data); | |
+} | |
+ | |
+ | |
+static void fchown_cb(uv_fs_t* req) { | |
+ ASSERT(req->fs_type == UV_FS_FCHOWN); | |
+ ASSERT(req->result == 0); | |
+ fchown_cb_count++; | |
+ uv_fs_req_cleanup(req); | |
+} | |
+ | |
+ | |
+static void chown_cb(uv_fs_t* req) { | |
+ ASSERT(req->fs_type == UV_FS_CHOWN); | |
+ ASSERT(req->result == 0); | |
+ chown_cb_count++; | |
+ uv_fs_req_cleanup(req); | |
} | |
@@ -598,6 +616,7 @@ TEST_IMPL(fs_fstat) { | |
int r; | |
uv_fs_t req; | |
uv_file file; | |
+ struct stat* s; | |
/* Setup. */ | |
unlink("test_file"); | |
@@ -606,7 +625,8 @@ TEST_IMPL(fs_fstat) { | |
loop = uv_default_loop(); | |
- r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, 0, NULL); | |
+ r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, | |
+ S_IWRITE | S_IREAD, NULL); | |
ASSERT(r == 0); | |
ASSERT(req.result != -1); | |
file = req.result; | |
@@ -620,7 +640,7 @@ TEST_IMPL(fs_fstat) { | |
r = uv_fs_fstat(loop, &req, file, NULL); | |
ASSERT(r == 0); | |
ASSERT(req.result == 0); | |
- struct stat* s = req.ptr; | |
+ s = req.ptr; | |
ASSERT(s->st_size == sizeof(test_buf)); | |
uv_fs_req_cleanup(&req); | |
@@ -661,7 +681,8 @@ TEST_IMPL(fs_chmod) { | |
loop = uv_default_loop(); | |
- r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, 0, NULL); | |
+ r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, | |
+ S_IWRITE | S_IREAD, NULL); | |
ASSERT(r == 0); | |
ASSERT(req.result != -1); | |
file = req.result; | |
@@ -672,6 +693,7 @@ TEST_IMPL(fs_chmod) { | |
ASSERT(req.result == sizeof(test_buf)); | |
uv_fs_req_cleanup(&req); | |
+#ifndef _WIN32 | |
/* Make the file write-only */ | |
r = uv_fs_chmod(loop, &req, "test_file", 0200, NULL); | |
ASSERT(r == 0); | |
@@ -679,6 +701,15 @@ TEST_IMPL(fs_chmod) { | |
uv_fs_req_cleanup(&req); | |
check_permission("test_file", 0200); | |
+#endif | |
+ | |
+ /* Make the file read-only */ | |
+ r = uv_fs_chmod(loop, &req, "test_file", 0400, NULL); | |
+ ASSERT(r == 0); | |
+ ASSERT(req.result == 0); | |
+ uv_fs_req_cleanup(&req); | |
+ | |
+ check_permission("test_file", 0400); | |
/* Make the file read+write with sync uv_fs_fchmod */ | |
r = uv_fs_fchmod(loop, &req, file, 0600, NULL); | |
@@ -688,13 +719,24 @@ TEST_IMPL(fs_chmod) { | |
check_permission("test_file", 0600); | |
+#ifndef _WIN32 | |
/* async chmod */ | |
+ req.data = (void*)0200; | |
r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb); | |
ASSERT(r == 0); | |
uv_run(loop); | |
ASSERT(chmod_cb_count == 1); | |
+#endif | |
+ | |
+ /* async chmod */ | |
+ req.data = (void*)0400; | |
+ r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb); | |
+ ASSERT(r == 0); | |
+ uv_run(loop); | |
+ ASSERT(chmod_cb_count == 1); | |
/* async fchmod */ | |
+ req.data = (void*)0600; | |
r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb); | |
ASSERT(r == 0); | |
uv_run(loop); | |
@@ -713,3 +755,61 @@ TEST_IMPL(fs_chmod) { | |
return 0; | |
} | |
+ | |
+ | |
+TEST_IMPL(fs_chown) { | |
+ int r; | |
+ uv_fs_t req; | |
+ uv_file file; | |
+ | |
+ /* Setup. */ | |
+ unlink("test_file"); | |
+ | |
+ uv_init(); | |
+ | |
+ loop = uv_default_loop(); | |
+ | |
+ r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, | |
+ S_IWRITE | S_IREAD, NULL); | |
+ ASSERT(r == 0); | |
+ ASSERT(req.result != -1); | |
+ file = req.result; | |
+ uv_fs_req_cleanup(&req); | |
+ | |
+ /* sync chown */ | |
+ r = uv_fs_chown(loop, &req, "test_file", -1, -1, NULL); | |
+ ASSERT(r == 0); | |
+ ASSERT(req.result == 0); | |
+ uv_fs_req_cleanup(&req); | |
+ | |
+ /* sync fchown */ | |
+ r = uv_fs_fchown(loop, &req, file, -1, -1, NULL); | |
+ ASSERT(r == 0); | |
+ ASSERT(req.result == 0); | |
+ uv_fs_req_cleanup(&req); | |
+ | |
+ /* async chown */ | |
+ r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb); | |
+ ASSERT(r == 0); | |
+ uv_run(loop); | |
+ ASSERT(chown_cb_count == 1); | |
+ | |
+ /* async fchown */ | |
+ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); | |
+ ASSERT(r == 0); | |
+ uv_run(loop); | |
+ ASSERT(fchown_cb_count == 1); | |
+ | |
+ close(file); | |
+ | |
+ /* | |
+ * Run the loop just to check we don't have make any extranious uv_ref() | |
+ * calls. This should drop out immediately. | |
+ */ | |
+ uv_run(loop); | |
+ | |
+ /* Cleanup. */ | |
+ unlink("test_file"); | |
+ | |
+ return 0; | |
+} | |
\ No newline at end of file | |
diff --git a/test/test-list.h b/test/test-list.h | |
index 032060d..94cf03c 100644 | |
--- a/test/test-list.h | |
+++ b/test/test-list.h | |
@@ -78,6 +78,7 @@ TEST_DECLARE (fs_async_dir) | |
TEST_DECLARE (fs_async_sendfile) | |
TEST_DECLARE (fs_fstat) | |
TEST_DECLARE (fs_chmod) | |
+TEST_DECLARE (fs_chown) | |
TEST_DECLARE (threadpool_queue_work_simple) | |
#ifdef _WIN32 | |
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) | |
@@ -183,6 +184,7 @@ TASK_LIST_START | |
TEST_ENTRY (fs_async_sendfile) | |
TEST_ENTRY (fs_fstat) | |
TEST_ENTRY (fs_chmod) | |
+ TEST_ENTRY (fs_chown) | |
TEST_ENTRY (threadpool_queue_work_simple) | |
-- | |
1.7.4.msysgit.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment