summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibuv/src/win/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmlibuv/src/win/fs.c')
-rw-r--r--Utilities/cmlibuv/src/win/fs.c641
1 files changed, 593 insertions, 48 deletions
diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c
index 9e2f084..8502b07 100644
--- a/Utilities/cmlibuv/src/win/fs.c
+++ b/Utilities/cmlibuv/src/win/fs.c
@@ -34,8 +34,7 @@
#include "internal.h"
#include "req-inl.h"
#include "handle-inl.h"
-
-#include <wincrypt.h>
+#include "fs-fd-hash-inl.h"
#define UV_FS_FREE_PATHS 0x0002
@@ -126,6 +125,8 @@
#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
((c) >= L'A' && (c) <= L'Z'))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
const WCHAR JUNCTION_PREFIX_LEN = 4;
@@ -137,8 +138,16 @@ const WCHAR UNC_PATH_PREFIX_LEN = 8;
static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
+static DWORD uv__allocation_granularity;
+
+
void uv_fs_init(void) {
- _fmode = _O_BINARY;
+ SYSTEM_INFO system_info;
+
+ GetSystemInfo(&system_info);
+ uv__allocation_granularity = system_info.dwAllocationGranularity;
+
+ uv__fd_hash_init();
}
@@ -414,6 +423,27 @@ void fs__open(uv_fs_t* req) {
HANDLE file;
int fd, current_umask;
int flags = req->fs.info.file_flags;
+ struct uv__fd_info_s fd_info;
+
+ /* Adjust flags to be compatible with the memory file mapping. Save the
+ * original flags to emulate the correct behavior. */
+ if (flags & UV_FS_O_FILEMAP) {
+ fd_info.flags = flags;
+ fd_info.current_pos.QuadPart = 0;
+
+ if ((flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) ==
+ UV_FS_O_WRONLY) {
+ /* CreateFileMapping always needs read access */
+ flags = (flags & ~UV_FS_O_WRONLY) | UV_FS_O_RDWR;
+ }
+
+ if (flags & UV_FS_O_APPEND) {
+ /* Clear the append flag and ensure RDRW mode */
+ flags &= ~UV_FS_O_APPEND;
+ flags &= ~(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
+ flags |= UV_FS_O_RDWR;
+ }
+ }
/* Obtain the active umask. umask() never fails and returns the previous
* umask. */
@@ -444,7 +474,8 @@ void fs__open(uv_fs_t* req) {
* 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.
+ * be deleted even whilst it's open, fixing issue
+ * https://github.com/nodejs/node-v0.x-archive/issues/1449.
* We still support exclusive sharing mode, since it is necessary
* for opening raw block devices, otherwise Windows will prevent
* any attempt to write past the master boot record.
@@ -583,11 +614,55 @@ void fs__open(uv_fs_t* req) {
else if (GetLastError() != ERROR_SUCCESS)
SET_REQ_WIN32_ERROR(req, GetLastError());
else
- SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ SET_REQ_WIN32_ERROR(req, (DWORD) UV_UNKNOWN);
CloseHandle(file);
return;
}
+ if (flags & UV_FS_O_FILEMAP) {
+ FILE_STANDARD_INFO file_info;
+ if (!GetFileInformationByHandleEx(file,
+ FileStandardInfo,
+ &file_info,
+ sizeof file_info)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(file);
+ return;
+ }
+ fd_info.is_directory = file_info.Directory;
+
+ if (fd_info.is_directory) {
+ fd_info.size.QuadPart = 0;
+ fd_info.mapping = INVALID_HANDLE_VALUE;
+ } else {
+ if (!GetFileSizeEx(file, &fd_info.size)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(file);
+ return;
+ }
+
+ if (fd_info.size.QuadPart == 0) {
+ fd_info.mapping = INVALID_HANDLE_VALUE;
+ } else {
+ DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
+ UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
+ fd_info.mapping = CreateFileMapping(file,
+ NULL,
+ flProtect,
+ fd_info.size.HighPart,
+ fd_info.size.LowPart,
+ NULL);
+ if (fd_info.mapping == NULL) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(file);
+ return;
+ }
+ }
+ }
+
+ uv__fd_hash_add(fd, &fd_info);
+ }
+
SET_REQ_RESULT(req, fd);
return;
@@ -598,9 +673,16 @@ void fs__open(uv_fs_t* req) {
void fs__close(uv_fs_t* req) {
int fd = req->file.fd;
int result;
+ struct uv__fd_info_s fd_info;
VERIFY_FD(fd, req);
+ if (uv__fd_hash_remove(fd, &fd_info)) {
+ if (fd_info.mapping != INVALID_HANDLE_VALUE) {
+ CloseHandle(fd_info.mapping);
+ }
+ }
+
if (fd > 2)
result = _close(fd);
else
@@ -618,6 +700,123 @@ void fs__close(uv_fs_t* req) {
}
+LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
+ int* perror) {
+ if (excode != EXCEPTION_IN_PAGE_ERROR) {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ assert(perror != NULL);
+ if (pep != NULL && pep->ExceptionRecord != NULL &&
+ pep->ExceptionRecord->NumberParameters >= 3) {
+ NTSTATUS status = (NTSTATUS)pep->ExceptionRecord->ExceptionInformation[3];
+ *perror = pRtlNtStatusToDosError(status);
+ if (*perror != ERROR_SUCCESS) {
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ }
+ *perror = UV_UNKNOWN;
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+
+void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
+ int fd = req->file.fd; /* VERIFY_FD done in fs__read */
+ int rw_flags = fd_info->flags &
+ (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
+ size_t read_size, done_read;
+ unsigned int index;
+ LARGE_INTEGER pos, end_pos;
+ size_t view_offset;
+ LARGE_INTEGER view_base;
+ void* view;
+
+ if (rw_flags == UV_FS_O_WRONLY) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ return;
+ }
+ if (fd_info->is_directory) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
+ return;
+ }
+
+ if (req->fs.info.offset == -1) {
+ pos = fd_info->current_pos;
+ } else {
+ pos.QuadPart = req->fs.info.offset;
+ }
+
+ /* Make sure we wont read past EOF. */
+ if (pos.QuadPart >= fd_info->size.QuadPart) {
+ SET_REQ_RESULT(req, 0);
+ return;
+ }
+
+ read_size = 0;
+ for (index = 0; index < req->fs.info.nbufs; ++index) {
+ read_size += req->fs.info.bufs[index].len;
+ }
+ read_size = (size_t) MIN((LONGLONG) read_size,
+ fd_info->size.QuadPart - pos.QuadPart);
+ if (read_size == 0) {
+ SET_REQ_RESULT(req, 0);
+ return;
+ }
+
+ end_pos.QuadPart = pos.QuadPart + read_size;
+
+ view_offset = pos.QuadPart % uv__allocation_granularity;
+ view_base.QuadPart = pos.QuadPart - view_offset;
+ view = MapViewOfFile(fd_info->mapping,
+ FILE_MAP_READ,
+ view_base.HighPart,
+ view_base.LowPart,
+ view_offset + read_size);
+ if (view == NULL) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ done_read = 0;
+ for (index = 0;
+ index < req->fs.info.nbufs && done_read < read_size;
+ ++index) {
+ int err = 0;
+ size_t this_read_size = MIN(req->fs.info.bufs[index].len,
+ read_size - done_read);
+#ifdef _MSC_VER
+ __try {
+#endif
+ memcpy(req->fs.info.bufs[index].base,
+ (char*)view + view_offset + done_read,
+ this_read_size);
+#ifdef _MSC_VER
+ }
+ __except (fs__filemap_ex_filter(GetExceptionCode(),
+ GetExceptionInformation(), &err)) {
+ SET_REQ_WIN32_ERROR(req, err);
+ UnmapViewOfFile(view);
+ return;
+ }
+#endif
+ done_read += this_read_size;
+ }
+ assert(done_read == read_size);
+
+ if (!UnmapViewOfFile(view)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (req->fs.info.offset == -1) {
+ fd_info->current_pos = end_pos;
+ uv__fd_hash_add(fd, fd_info);
+ }
+
+ SET_REQ_RESULT(req, read_size);
+ return;
+}
+
void fs__read(uv_fs_t* req) {
int fd = req->file.fd;
int64_t offset = req->fs.info.offset;
@@ -631,9 +830,15 @@ void fs__read(uv_fs_t* req) {
LARGE_INTEGER original_position;
LARGE_INTEGER zero_offset;
int restore_position;
+ struct uv__fd_info_s fd_info;
VERIFY_FD(fd, req);
+ if (uv__fd_hash_get(fd, &fd_info)) {
+ fs__read_filemap(req, &fd_info);
+ return;
+ }
+
zero_offset.QuadPart = 0;
restore_position = 0;
handle = uv__get_osfhandle(fd);
@@ -690,6 +895,131 @@ void fs__read(uv_fs_t* req) {
}
+void fs__write_filemap(uv_fs_t* req, HANDLE file,
+ struct uv__fd_info_s* fd_info) {
+ int fd = req->file.fd; /* VERIFY_FD done in fs__write */
+ int force_append = fd_info->flags & UV_FS_O_APPEND;
+ int rw_flags = fd_info->flags &
+ (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
+ size_t write_size, done_write;
+ unsigned int index;
+ LARGE_INTEGER zero, pos, end_pos;
+ size_t view_offset;
+ LARGE_INTEGER view_base;
+ void* view;
+ FILETIME ft;
+
+ if (rw_flags == UV_FS_O_RDONLY) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ return;
+ }
+ if (fd_info->is_directory) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
+ return;
+ }
+
+ write_size = 0;
+ for (index = 0; index < req->fs.info.nbufs; ++index) {
+ write_size += req->fs.info.bufs[index].len;
+ }
+
+ if (write_size == 0) {
+ SET_REQ_RESULT(req, 0);
+ return;
+ }
+
+ zero.QuadPart = 0;
+ if (force_append) {
+ pos = fd_info->size;
+ } else if (req->fs.info.offset == -1) {
+ pos = fd_info->current_pos;
+ } else {
+ pos.QuadPart = req->fs.info.offset;
+ }
+
+ end_pos.QuadPart = pos.QuadPart + write_size;
+
+ /* Recreate the mapping to enlarge the file if needed */
+ if (end_pos.QuadPart > fd_info->size.QuadPart) {
+ if (fd_info->mapping != INVALID_HANDLE_VALUE) {
+ CloseHandle(fd_info->mapping);
+ }
+
+ fd_info->mapping = CreateFileMapping(file,
+ NULL,
+ PAGE_READWRITE,
+ end_pos.HighPart,
+ end_pos.LowPart,
+ NULL);
+ if (fd_info->mapping == NULL) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(file);
+ fd_info->mapping = INVALID_HANDLE_VALUE;
+ fd_info->size.QuadPart = 0;
+ fd_info->current_pos.QuadPart = 0;
+ uv__fd_hash_add(fd, fd_info);
+ return;
+ }
+
+ fd_info->size = end_pos;
+ uv__fd_hash_add(fd, fd_info);
+ }
+
+ view_offset = pos.QuadPart % uv__allocation_granularity;
+ view_base.QuadPart = pos.QuadPart - view_offset;
+ view = MapViewOfFile(fd_info->mapping,
+ FILE_MAP_WRITE,
+ view_base.HighPart,
+ view_base.LowPart,
+ view_offset + write_size);
+ if (view == NULL) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ done_write = 0;
+ for (index = 0; index < req->fs.info.nbufs; ++index) {
+ int err = 0;
+#ifdef _MSC_VER
+ __try {
+#endif
+ memcpy((char*)view + view_offset + done_write,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len);
+#ifdef _MSC_VER
+ }
+ __except (fs__filemap_ex_filter(GetExceptionCode(),
+ GetExceptionInformation(), &err)) {
+ SET_REQ_WIN32_ERROR(req, err);
+ UnmapViewOfFile(view);
+ return;
+ }
+#endif
+ done_write += req->fs.info.bufs[index].len;
+ }
+ assert(done_write == write_size);
+
+ if (!FlushViewOfFile(view, 0)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ UnmapViewOfFile(view);
+ return;
+ }
+ if (!UnmapViewOfFile(view)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (req->fs.info.offset == -1) {
+ fd_info->current_pos = end_pos;
+ uv__fd_hash_add(fd, fd_info);
+ }
+
+ GetSystemTimeAsFileTime(&ft);
+ SetFileTime(file, NULL, NULL, &ft);
+
+ SET_REQ_RESULT(req, done_write);
+}
+
void fs__write(uv_fs_t* req) {
int fd = req->file.fd;
int64_t offset = req->fs.info.offset;
@@ -702,6 +1032,7 @@ void fs__write(uv_fs_t* req) {
LARGE_INTEGER original_position;
LARGE_INTEGER zero_offset;
int restore_position;
+ struct uv__fd_info_s fd_info;
VERIFY_FD(fd, req);
@@ -713,6 +1044,11 @@ void fs__write(uv_fs_t* req) {
return;
}
+ if (uv__fd_hash_get(fd, &fd_info)) {
+ fs__write_filemap(req, handle, &fd_info);
+ return;
+ }
+
if (offset != -1) {
memset(&overlapped, 0, sizeof overlapped);
overlapped_ptr = &overlapped;
@@ -850,13 +1186,19 @@ void fs__unlink(uv_fs_t* req) {
void fs__mkdir(uv_fs_t* req) {
/* TODO: use req->mode. */
- int result = _wmkdir(req->file.pathw);
- SET_REQ_RESULT(req, result);
+ req->result = _wmkdir(req->file.pathw);
+ if (req->result == -1) {
+ req->sys_errno_ = _doserrno;
+ req->result = req->sys_errno_ == ERROR_INVALID_NAME
+ ? UV_EINVAL
+ : uv_translate_sys_error(req->sys_errno_);
+ }
}
+typedef int (*uv__fs_mktemp_func)(uv_fs_t* req);
/* OpenBSD original: lib/libc/stdio/mktemp.c */
-void fs__mkdtemp(uv_fs_t* req) {
+void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
static const WCHAR *tempchars =
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const size_t num_chars = 62;
@@ -864,9 +1206,7 @@ void fs__mkdtemp(uv_fs_t* req) {
WCHAR *cp, *ep;
unsigned int tries, i;
size_t len;
- HCRYPTPROV h_crypt_prov;
uint64_t v;
- BOOL released;
len = wcslen(req->file.pathw);
ep = req->file.pathw + len;
@@ -875,16 +1215,10 @@ void fs__mkdtemp(uv_fs_t* req) {
return;
}
- if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
tries = TMP_MAX;
do {
- if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
+ if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) {
+ SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE);
break;
}
@@ -894,25 +1228,92 @@ void fs__mkdtemp(uv_fs_t* req) {
v /= num_chars;
}
- if (_wmkdir(req->file.pathw) == 0) {
- len = strlen(req->path);
- wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
- SET_REQ_RESULT(req, 0);
- break;
- } else if (errno != EEXIST) {
- SET_REQ_RESULT(req, -1);
+ if (func(req)) {
+ if (req->result >= 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
+ }
break;
}
} while (--tries);
- released = CryptReleaseContext(h_crypt_prov, 0);
- assert(released);
if (tries == 0) {
SET_REQ_RESULT(req, -1);
}
}
+static int fs__mkdtemp_func(uv_fs_t* req) {
+ if (_wmkdir(req->file.pathw) == 0) {
+ SET_REQ_RESULT(req, 0);
+ return 1;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void fs__mkdtemp(uv_fs_t* req) {
+ fs__mktemp(req, fs__mkdtemp_func);
+}
+
+
+static int fs__mkstemp_func(uv_fs_t* req) {
+ HANDLE file;
+ int fd;
+
+ file = CreateFileW(req->file.pathw,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ DWORD error;
+ error = GetLastError();
+
+ /* If the file exists, the main fs__mktemp() function
+ will retry. If it's another error, we want to stop. */
+ if (error != ERROR_FILE_EXISTS) {
+ SET_REQ_WIN32_ERROR(req, error);
+ return 1;
+ }
+
+ return 0;
+ }
+
+ fd = _open_osfhandle((intptr_t) file, 0);
+ if (fd < 0) {
+ /* The only known failure mode for _open_osfhandle() is EMFILE, in which
+ * case GetLastError() will return zero. However we'll try to handle other
+ * errors as well, should they ever occur.
+ */
+ if (errno == EMFILE)
+ SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
+ else if (GetLastError() != ERROR_SUCCESS)
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ else
+ SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ CloseHandle(file);
+ return 1;
+ }
+
+ SET_REQ_RESULT(req, fd);
+
+ return 1;
+}
+
+
+void fs__mkstemp(uv_fs_t* req) {
+ fs__mktemp(req, fs__mkstemp_func);
+}
+
+
void fs__scandir(uv_fs_t* req) {
static const size_t dirents_initial_size = 32;
@@ -1409,47 +1810,57 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
}
-INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
+ int do_lstat,
+ uv_stat_t* statbuf) {
HANDLE handle;
DWORD flags;
+ DWORD ret;
flags = FILE_FLAG_BACKUP_SEMANTICS;
- if (do_lstat) {
+ if (do_lstat)
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
- }
- handle = CreateFileW(req->file.pathw,
+ handle = CreateFileW(path,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
flags,
NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
- if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) {
- DWORD error = GetLastError();
+ if (handle == INVALID_HANDLE_VALUE)
+ ret = GetLastError();
+ else if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
+ ret = GetLastError();
+ else
+ ret = 0;
+
+ CloseHandle(handle);
+ return ret;
+}
+
+
+INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+ DWORD error;
+
+ error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf);
+ if (error != 0) {
if (do_lstat &&
(error == ERROR_SYMLINK_NOT_SUPPORTED ||
error == ERROR_NOT_A_REPARSE_POINT)) {
/* We opened a reparse point but it was not a symlink. Try again. */
fs__stat_impl(req, 0);
-
} else {
/* Stat failed. */
- SET_REQ_WIN32_ERROR(req, GetLastError());
+ SET_REQ_WIN32_ERROR(req, error);
}
- CloseHandle(handle);
return;
}
req->ptr = &req->statbuf;
req->result = 0;
- CloseHandle(handle);
}
@@ -1526,6 +1937,7 @@ static void fs__fdatasync(uv_fs_t* req) {
static void fs__ftruncate(uv_fs_t* req) {
int fd = req->file.fd;
HANDLE handle;
+ struct uv__fd_info_s fd_info = { 0 };
NTSTATUS status;
IO_STATUS_BLOCK io_status;
FILE_END_OF_FILE_INFORMATION eof_info;
@@ -1534,6 +1946,17 @@ static void fs__ftruncate(uv_fs_t* req) {
handle = uv__get_osfhandle(fd);
+ if (uv__fd_hash_get(fd, &fd_info)) {
+ if (fd_info.is_directory) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ return;
+ }
+
+ if (fd_info.mapping != INVALID_HANDLE_VALUE) {
+ CloseHandle(fd_info.mapping);
+ }
+ }
+
eof_info.EndOfFile.QuadPart = req->fs.info.offset;
status = pNtSetInformationFile(handle,
@@ -1546,6 +1969,43 @@ static void fs__ftruncate(uv_fs_t* req) {
SET_REQ_RESULT(req, 0);
} else {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+
+ if (fd_info.flags) {
+ CloseHandle(handle);
+ fd_info.mapping = INVALID_HANDLE_VALUE;
+ fd_info.size.QuadPart = 0;
+ fd_info.current_pos.QuadPart = 0;
+ uv__fd_hash_add(fd, &fd_info);
+ return;
+ }
+ }
+
+ if (fd_info.flags) {
+ fd_info.size = eof_info.EndOfFile;
+
+ if (fd_info.size.QuadPart == 0) {
+ fd_info.mapping = INVALID_HANDLE_VALUE;
+ } else {
+ DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
+ UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
+ fd_info.mapping = CreateFileMapping(handle,
+ NULL,
+ flProtect,
+ fd_info.size.HighPart,
+ fd_info.size.LowPart,
+ NULL);
+ if (fd_info.mapping == NULL) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ fd_info.mapping = INVALID_HANDLE_VALUE;
+ fd_info.size.QuadPart = 0;
+ fd_info.current_pos.QuadPart = 0;
+ uv__fd_hash_add(fd, &fd_info);
+ return;
+ }
+ }
+
+ uv__fd_hash_add(fd, &fd_info);
}
}
@@ -1553,6 +2013,8 @@ static void fs__ftruncate(uv_fs_t* req) {
static void fs__copyfile(uv_fs_t* req) {
int flags;
int overwrite;
+ uv_stat_t statbuf;
+ uv_stat_t new_statbuf;
flags = req->fs.info.file_flags;
@@ -1563,12 +2025,25 @@ static void fs__copyfile(uv_fs_t* req) {
overwrite = flags & UV_FS_COPYFILE_EXCL;
- if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
+ if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) != 0) {
+ SET_REQ_RESULT(req, 0);
return;
}
- SET_REQ_RESULT(req, 0);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ if (req->result != UV_EBUSY)
+ return;
+
+ /* if error UV_EBUSY check if src and dst file are the same */
+ if (fs__stat_impl_from_path(req->file.pathw, 0, &statbuf) != 0 ||
+ fs__stat_impl_from_path(req->fs.info.new_pathw, 0, &new_statbuf) != 0) {
+ return;
+ }
+
+ if (statbuf.st_dev == new_statbuf.st_dev &&
+ statbuf.st_ino == new_statbuf.st_ino) {
+ SET_REQ_RESULT(req, 0);
+ }
}
@@ -2139,6 +2614,42 @@ static void fs__lchown(uv_fs_t* req) {
req->result = 0;
}
+
+static void fs__statfs(uv_fs_t* req) {
+ uv_statfs_t* stat_fs;
+ DWORD sectors_per_cluster;
+ DWORD bytes_per_sector;
+ DWORD free_clusters;
+ DWORD total_clusters;
+
+ if (0 == GetDiskFreeSpaceW(req->file.pathw,
+ &sectors_per_cluster,
+ &bytes_per_sector,
+ &free_clusters,
+ &total_clusters)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ stat_fs = uv__malloc(sizeof(*stat_fs));
+ if (stat_fs == NULL) {
+ SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
+ return;
+ }
+
+ stat_fs->f_type = 0;
+ stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster;
+ stat_fs->f_blocks = total_clusters;
+ stat_fs->f_bfree = free_clusters;
+ stat_fs->f_bavail = free_clusters;
+ stat_fs->f_files = 0;
+ stat_fs->f_ffree = 0;
+ req->ptr = stat_fs;
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
+
static void uv__fs_work(struct uv__work* w) {
uv_fs_t* req;
@@ -2168,6 +2679,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(RMDIR, rmdir)
XX(MKDIR, mkdir)
XX(MKDTEMP, mkdtemp)
+ XX(MKSTEMP, mkstemp)
XX(RENAME, rename)
XX(SCANDIR, scandir)
XX(READDIR, readdir)
@@ -2178,8 +2690,9 @@ static void uv__fs_work(struct uv__work* w) {
XX(READLINK, readlink)
XX(REALPATH, realpath)
XX(CHOWN, chown)
- XX(FCHOWN, fchown);
- XX(LCHOWN, lchown);
+ XX(FCHOWN, fchown)
+ XX(LCHOWN, lchown)
+ XX(STATFS, statfs)
default:
assert(!"bad uv_fs_type");
}
@@ -2343,8 +2856,10 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
}
-int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
- uv_fs_cb cb) {
+int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb) {
int err;
INIT(UV_FS_MKDTEMP);
@@ -2356,6 +2871,21 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
}
+int uv_fs_mkstemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ INIT(UV_FS_MKSTEMP);
+ err = fs__capture_path(req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ POST;
+}
+
+
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
@@ -2691,3 +3221,18 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
req->fs.time.mtime = mtime;
POST;
}
+
+
+int uv_fs_statfs(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ INIT(UV_FS_STATFS);
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ POST;
+}