win: refactor to support large statfs blocks (#5016)
Accomplish this by replacing `GetDiskFreeSpaceW()` with `NtQueryVolumeInformationFile()` which allows us to represent blocks larger than 2^32 - 1 via `FILE_FS_FULL_SIZE_INFORMATION.TotalAllocationUnits`. Expanded `fs_statfs` test to check that `uv_fs_statfs()` also works with files, meaning https://github.com/libuv/libuv/issues/2683 remains fixed without the need of https://github.com/libuv/libuv/pull/2695.
This commit is contained in:
parent
91dc2389cc
commit
c68ca444e7
93
src/win/fs.c
93
src/win/fs.c
@ -3109,67 +3109,35 @@ static void fs__lchown(uv_fs_t* req) {
|
|||||||
|
|
||||||
|
|
||||||
static void fs__statfs(uv_fs_t* req) {
|
static void fs__statfs(uv_fs_t* req) {
|
||||||
|
FILE_FS_FULL_SIZE_INFORMATION info;
|
||||||
|
IO_STATUS_BLOCK io_status;
|
||||||
uv_statfs_t* stat_fs;
|
uv_statfs_t* stat_fs;
|
||||||
DWORD sectors_per_cluster;
|
NTSTATUS nt_status;
|
||||||
DWORD bytes_per_sector;
|
HANDLE handle;
|
||||||
DWORD free_clusters;
|
|
||||||
DWORD total_clusters;
|
|
||||||
WCHAR* pathw;
|
|
||||||
|
|
||||||
pathw = req->file.pathw;
|
handle = CreateFileW(req->file.pathw,
|
||||||
retry_get_disk_free_space:
|
FILE_READ_ATTRIBUTES,
|
||||||
if (0 == GetDiskFreeSpaceW(pathw,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
§ors_per_cluster,
|
NULL,
|
||||||
&bytes_per_sector,
|
OPEN_EXISTING,
|
||||||
&free_clusters,
|
FILE_FLAG_BACKUP_SEMANTICS,
|
||||||
&total_clusters)) {
|
NULL);
|
||||||
DWORD err;
|
|
||||||
WCHAR* fpart;
|
|
||||||
size_t len;
|
|
||||||
DWORD ret;
|
|
||||||
BOOL is_second;
|
|
||||||
|
|
||||||
err = GetLastError();
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
is_second = pathw != req->file.pathw;
|
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||||
if (err != ERROR_DIRECTORY || is_second) {
|
return;
|
||||||
if (is_second)
|
|
||||||
uv__free(pathw);
|
|
||||||
|
|
||||||
SET_REQ_WIN32_ERROR(req, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = MAX_PATH + 1;
|
|
||||||
pathw = uv__malloc(len * sizeof(*pathw));
|
|
||||||
if (pathw == NULL) {
|
|
||||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
retry_get_full_path_name:
|
|
||||||
ret = GetFullPathNameW(req->file.pathw,
|
|
||||||
len,
|
|
||||||
pathw,
|
|
||||||
&fpart);
|
|
||||||
if (ret == 0) {
|
|
||||||
uv__free(pathw);
|
|
||||||
SET_REQ_WIN32_ERROR(req, err);
|
|
||||||
return;
|
|
||||||
} else if (ret > len) {
|
|
||||||
len = ret;
|
|
||||||
pathw = uv__reallocf(pathw, len * sizeof(*pathw));
|
|
||||||
if (pathw == NULL) {
|
|
||||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
goto retry_get_full_path_name;
|
|
||||||
}
|
|
||||||
if (fpart != 0)
|
|
||||||
*fpart = L'\0';
|
|
||||||
|
|
||||||
goto retry_get_disk_free_space;
|
|
||||||
}
|
}
|
||||||
if (pathw != req->file.pathw) {
|
|
||||||
uv__free(pathw);
|
nt_status = pNtQueryVolumeInformationFile(handle,
|
||||||
|
&io_status,
|
||||||
|
&info,
|
||||||
|
sizeof info,
|
||||||
|
FileFsFullSizeInformation);
|
||||||
|
CloseHandle(handle);
|
||||||
|
|
||||||
|
if (NT_ERROR(nt_status)) {
|
||||||
|
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||||
@ -3179,11 +3147,12 @@ retry_get_full_path_name:
|
|||||||
}
|
}
|
||||||
|
|
||||||
stat_fs->f_type = 0;
|
stat_fs->f_type = 0;
|
||||||
stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster;
|
stat_fs->f_bsize = (uint64_t)info.SectorsPerAllocationUnit *
|
||||||
stat_fs->f_frsize = bytes_per_sector * sectors_per_cluster;
|
info.BytesPerSector;
|
||||||
stat_fs->f_blocks = total_clusters;
|
stat_fs->f_frsize = stat_fs->f_bsize;
|
||||||
stat_fs->f_bfree = free_clusters;
|
stat_fs->f_blocks = info.TotalAllocationUnits.QuadPart;
|
||||||
stat_fs->f_bavail = free_clusters;
|
stat_fs->f_bfree = info.ActualAvailableAllocationUnits.QuadPart;
|
||||||
|
stat_fs->f_bavail = info.CallerAvailableAllocationUnits.QuadPart;
|
||||||
stat_fs->f_files = 0;
|
stat_fs->f_files = 0;
|
||||||
stat_fs->f_ffree = 0;
|
stat_fs->f_ffree = 0;
|
||||||
req->ptr = stat_fs;
|
req->ptr = stat_fs;
|
||||||
|
|||||||
@ -4915,21 +4915,41 @@ TEST_FS_IMPL(fs_invalid_mkdir_name) {
|
|||||||
|
|
||||||
TEST_FS_IMPL(fs_statfs) {
|
TEST_FS_IMPL(fs_statfs) {
|
||||||
uv_fs_t req;
|
uv_fs_t req;
|
||||||
|
uv_fs_t req1;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/* Setup. */
|
||||||
|
unlink("test_file");
|
||||||
|
|
||||||
|
r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
|
||||||
|
S_IRUSR | S_IWUSR, NULL);
|
||||||
|
ASSERT_GT(r, 0);
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
|
r = uv_fs_close(NULL, &req, req.result, NULL);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
|
||||||
loop = uv_default_loop();
|
loop = uv_default_loop();
|
||||||
|
|
||||||
/* Test the synchronous version. */
|
/* Test the synchronous version for both a directory and a file. */
|
||||||
r = uv_fs_statfs(NULL, &req, ".", NULL);
|
r = uv_fs_statfs(NULL, &req, ".", NULL);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
statfs_cb(&req);
|
statfs_cb(&req);
|
||||||
ASSERT_EQ(1, statfs_cb_count);
|
r = uv_fs_statfs(NULL, &req, "test_file", NULL);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
statfs_cb(&req);
|
||||||
|
ASSERT_EQ(2, statfs_cb_count);
|
||||||
|
|
||||||
/* Test the asynchronous version. */
|
/* Test the asynchronous version too. */
|
||||||
r = uv_fs_statfs(loop, &req, ".", statfs_cb);
|
r = uv_fs_statfs(loop, &req, ".", statfs_cb);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
|
r = uv_fs_statfs(loop, &req1, "test_file", statfs_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
uv_run(loop, UV_RUN_DEFAULT);
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
ASSERT_EQ(2, statfs_cb_count);
|
ASSERT_EQ(4, statfs_cb_count);
|
||||||
|
|
||||||
MAKE_VALGRIND_HAPPY(loop);
|
MAKE_VALGRIND_HAPPY(loop);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user