From e1af07e83149024f915febfc7436fb682d8a0633 Mon Sep 17 00:00:00 2001 From: Peter Bright Date: Sun, 4 Sep 2011 20:47:16 +0100 Subject: [PATCH] Open files with sharing enabled. Fixes node's issue #1449. https://github.com/joyent/node/issues/1449 --- src/win/fs.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 770b4df1fb..c0ce3f17df 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -115,13 +115,120 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req, req->errorno = 0; } +/* this is where the CRT stores the current umask */ +extern int _umaskval; void fs__open(uv_fs_t* req, const char* path, int flags, int mode) { - int result = _open(path, flags, mode); + DWORD access; + DWORD share; + SECURITY_ATTRIBUTES sa; + DWORD disposition; + DWORD attributes; + HANDLE file; + int result; + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + access = GENERIC_READ; + break; + case _O_WRONLY: + access = GENERIC_WRITE; + break; + case _O_RDWR: + access = GENERIC_READ | GENERIC_WRITE; + break; + default: + result = -1; + goto end; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open, fixing issue #1449. + */ + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + if (flags & _O_NOINHERIT) { + sa.bInheritHandle = FALSE; + } else { + sa.bInheritHandle = TRUE; + } + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + disposition = OPEN_EXISTING; + break; + case _O_CREAT: + disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + result = -1; + goto end; + } + + attributes = FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((mode & ~_umaskval) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + result = -1; + goto end; + } + + file = CreateFileA(path, + access, + share, + &sa, + disposition, + attributes, + NULL); + if (file == INVALID_HANDLE_VALUE) { + result = -1; + goto end; + } + result = _open_osfhandle((intptr_t)file, flags); +end: SET_REQ_RESULT(req, result); } - void fs__close(uv_fs_t* req, uv_file file) { int result = _close(file); SET_REQ_RESULT(req, result);