summaryrefslogtreecommitdiff
path: root/deps/uv/src/win/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/uv/src/win/fs.c')
-rw-r--r--deps/uv/src/win/fs.c458
1 files changed, 450 insertions, 8 deletions
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 7d78d466c8..5dccca7799 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -34,6 +34,7 @@
#include "internal.h"
#include "req-inl.h"
#include "handle-inl.h"
+#include "fs-fd-hash-inl.h"
#include <wincrypt.h>
@@ -126,6 +127,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 +140,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 +425,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 +476,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 +616,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 +675,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 +702,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 +832,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 +897,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 +1034,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 +1046,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,8 +1188,13 @@ 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_);
+ }
}
@@ -1536,6 +1879,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;
@@ -1544,6 +1888,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,
@@ -1556,6 +1911,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);
}
}
@@ -1563,7 +1955,6 @@ static void fs__ftruncate(uv_fs_t* req) {
static void fs__copyfile(uv_fs_t* req) {
int flags;
int overwrite;
- DWORD error;
uv_stat_t statbuf;
uv_stat_t new_statbuf;
@@ -2165,6 +2556,41 @@ 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;
+ SET_REQ_RESULT(req, 0);
+}
+
+
static void uv__fs_work(struct uv__work* w) {
uv_fs_t* req;
@@ -2204,8 +2630,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");
}
@@ -2717,3 +3144,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;
+}