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.c153
1 files changed, 105 insertions, 48 deletions
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 9d4d7ff843..8c35cabee2 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -82,8 +82,8 @@
#define FILETIME_TO_TIMESPEC(ts, filetime) \
do { \
- (ts).tv_sec = FILETIME_TO_TIME_T(filetime); \
- (ts).tv_nsec = FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
+ (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
+ (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
} while(0)
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
@@ -241,7 +241,7 @@ static int is_path_dir(const WCHAR* path) {
INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
- int64_t* target_len_ptr) {
+ uint64_t* target_len_ptr) {
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
WCHAR *w_target;
@@ -809,56 +809,117 @@ void fs__readdir(uv_fs_t* req) {
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
- BY_HANDLE_FILE_INFORMATION info;
+ FILE_ALL_INFORMATION file_info;
+ FILE_FS_VOLUME_INFORMATION volume_info;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
- if (!GetFileInformationByHandle(handle, &info)) {
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileAllInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
return -1;
}
- /* TODO: set st_dev, st_rdev and st_ino to something meaningful. */
- statbuf->st_ino = 0;
- statbuf->st_dev = 0;
- statbuf->st_rdev = 0;
+ nt_status = pNtQueryVolumeInformationFile(handle,
+ &io_status,
+ &volume_info,
+ sizeof volume_info,
+ FileFsVolumeInformation);
- statbuf->st_gid = 0;
- statbuf->st_uid = 0;
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ }
+ /* Todo: st_mode should probably always be 0666 for everyone. We might also
+ * want to report 0777 if the file is a .exe or a directory.
+ *
+ * Currently it's based on whether the 'readonly' attribute is set, which
+ * makes little sense because the semantics are so different: the 'read-only'
+ * flag is just a way for a user to protect against accidental deleteion, and
+ * serves no security purpose. Windows uses ACLs for that.
+ *
+ * Also people now use uv_fs_chmod() to take away the writable bit for good
+ * reasons. Windows however just makes the file read-only, which makes it
+ * impossible to delete the file afterwards, since read-only files can't be
+ * deleted.
+ *
+ * IOW it's all just a clusterfuck and we should think of something that
+ * makes slighty more sense.
+ *
+ * And uv_fs_chmod should probably just fail on windows or be a total no-op.
+ * There's nothing sensible it can do anyway.
+ */
statbuf->st_mode = 0;
- statbuf->st_blksize = 0;
- statbuf->st_blocks = 0;
-
- statbuf->st_flags = 0;
- statbuf->st_gen = 0;
-
- if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) {
- return -1;
- }
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
statbuf->st_mode |= S_IFLNK;
- } else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
+ return -1;
+
+ } else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
statbuf->st_size = 0;
+
} else {
statbuf->st_mode |= _S_IFREG;
- statbuf->st_size = ((int64_t) info.nFileSizeHigh << 32) +
- (int64_t) info.nFileSizeLow;
+ statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
}
- if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- statbuf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
- } else {
- statbuf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
- ((_S_IREAD|_S_IWRITE) >> 6));
- }
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
+ else
+ statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
+ ((_S_IREAD | _S_IWRITE) >> 6);
+
+ FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+
+ statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
+
+ /* st_blocks contains the on-disk allocation size in 512-byte units. */
+ statbuf->st_blocks =
+ file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
- FILETIME_TO_TIMESPEC(statbuf->st_mtim, info.ftLastWriteTime);
- FILETIME_TO_TIMESPEC(statbuf->st_atim, info.ftLastAccessTime);
- FILETIME_TO_TIMESPEC(statbuf->st_ctim, info.ftCreationTime);
- FILETIME_TO_TIMESPEC(statbuf->st_birthtim, info.ftCreationTime);
+ statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
- statbuf->st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ?
- (short) info.nNumberOfLinks : SHRT_MAX;
+ statbuf->st_dev = volume_info.VolumeSerialNumber;
+
+ /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
+ * and writing to the disk. That is, for any definition of 'optimal' - it's
+ * supposed to at least avoid read-update-write behavior when writing to the
+ * disk.
+ *
+ * However nobody knows this and even fewer people actually use this value,
+ * and in order to fill it out we'd have to make another syscall to query the
+ * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
+ *
+ * Therefore we'll just report a sensible value that's quite commonly okay
+ * on modern hardware.
+ */
+ statbuf->st_blksize = 2048;
+
+ /* Todo: set st_flags to something meaningful. Also provide a wrapper for
+ * chattr(2).
+ */
+ statbuf->st_flags = 0;
+
+ /* Windows has nothing sensible to say about these values, so they'll just
+ * remain empty.
+ */
+ statbuf->st_gid = 0;
+ statbuf->st_uid = 0;
+ statbuf->st_rdev = 0;
+ statbuf->st_gen = 0;
return 0;
}
@@ -1069,7 +1130,6 @@ static void fs__chmod(uv_fs_t* req) {
static void fs__fchmod(uv_fs_t* req) {
int fd = req->fd;
- int result;
HANDLE handle;
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
@@ -1077,7 +1137,7 @@ static void fs__fchmod(uv_fs_t* req) {
VERIFY_FD(fd, req);
- handle = (HANDLE)_get_osfhandle(fd);
+ handle = (HANDLE) _get_osfhandle(fd);
nt_status = pNtQueryInformationFile(handle,
&io_status,
@@ -1085,9 +1145,9 @@ static void fs__fchmod(uv_fs_t* req) {
sizeof file_info,
FileBasicInformation);
- if (nt_status != STATUS_SUCCESS) {
- result = -1;
- goto done;
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
}
if (req->mode & _S_IWRITE) {
@@ -1102,15 +1162,12 @@ static void fs__fchmod(uv_fs_t* req) {
sizeof file_info,
FileBasicInformation);
- if (nt_status != STATUS_SUCCESS) {
- result = -1;
- goto done;
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
}
- result = 0;
-
-done:
- SET_REQ_RESULT(req, result);
+ SET_REQ_SUCCESS(req);
}