Skip to content

Instantly share code, notes, and snippets.

@igorzi
Created September 3, 2011 18:07
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/1191551 to your computer and use it in GitHub Desktop.
Save igorzi/1191551 to your computer and use it in GitHub Desktop.
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