win, fs: uv_fs_fchmod support for -A files
Adds uv_fs_chmod support for files with the Archive attribute cleared Ref: https://github.com/libuv/libuv/pull/1777 Ref: https://github.com/nodejs/node/issues/12803 PR-URL: https://github.com/libuv/libuv/pull/1819 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
60bac5a98f
commit
b59fc58326
49
src/win/fs.c
49
src/win/fs.c
@ -1490,6 +1490,7 @@ static void fs__chmod(uv_fs_t* req) {
|
||||
|
||||
static void fs__fchmod(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int clear_archive_flag;
|
||||
HANDLE handle;
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
@ -1497,7 +1498,11 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
handle = uv__get_osfhandle(fd);
|
||||
handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
nt_status = pNtQueryInformationFile(handle,
|
||||
&io_status,
|
||||
@ -1507,7 +1512,27 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
return;
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
|
||||
/* Test if the Archive attribute is cleared */
|
||||
if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
|
||||
/* Set Archive flag, otherwise setting or clearing the read-olny
|
||||
flag will not work */
|
||||
file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
nt_status = pNtSetInformationFile(handle,
|
||||
&io_status,
|
||||
&file_info,
|
||||
sizeof file_info,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
/* Remeber to clear the flag later on */
|
||||
clear_archive_flag = 1;
|
||||
} else {
|
||||
clear_archive_flag = 0;
|
||||
}
|
||||
|
||||
if (req->fs.info.mode & _S_IWRITE) {
|
||||
@ -1524,10 +1549,28 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
return;
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
|
||||
if (clear_archive_flag) {
|
||||
file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
|
||||
if (file_info.FileAttributes == 0) {
|
||||
file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
nt_status = pNtSetInformationFile(handle,
|
||||
&io_status,
|
||||
&file_info,
|
||||
sizeof file_info,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
SET_REQ_SUCCESS(req);
|
||||
fchmod_cleanup:
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
133
test/test-fs.c
133
test/test-fs.c
@ -3230,3 +3230,136 @@ TEST_IMPL(fs_exclusive_sharing_mode) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
int call_icacls(const char* command, ...) {
|
||||
char icacls_command[1024];
|
||||
va_list args;
|
||||
|
||||
va_start(args, command);
|
||||
vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args);
|
||||
va_end(args);
|
||||
return system(icacls_command);
|
||||
}
|
||||
|
||||
TEST_IMPL(fs_open_readonly_acl) {
|
||||
uv_passwd_t pwd;
|
||||
uv_fs_t req;
|
||||
int r;
|
||||
|
||||
/*
|
||||
Based on Node.js test from
|
||||
https://github.com/nodejs/node/commit/3ba81e34e86a5c32658e218cb6e65b13e8326bc5
|
||||
|
||||
If anything goes wrong, you can delte the test_fle_icacls with:
|
||||
|
||||
icacls test_file_icacls /remove "%USERNAME%" /inheritance:e
|
||||
attrib -r test_file_icacls
|
||||
del test_file_icacls
|
||||
*/
|
||||
|
||||
/* Setup - clear the ACL and remove the file */
|
||||
loop = uv_default_loop();
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
ASSERT(r == 0);
|
||||
call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
|
||||
pwd.username);
|
||||
uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL);
|
||||
unlink("test_file_icacls");
|
||||
|
||||
/* Create the file */
|
||||
r = uv_fs_open(loop,
|
||||
&open_req1,
|
||||
"test_file_icacls",
|
||||
O_RDONLY | O_CREAT,
|
||||
S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(open_req1.result >= 0);
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(close_req.result == 0);
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
/* Set up ACL */
|
||||
r = call_icacls("icacls test_file_icacls /inheritance:r /remove \"%s\"",
|
||||
pwd.username);
|
||||
if (r != 0) {
|
||||
goto acl_cleanup;
|
||||
}
|
||||
r = call_icacls("icacls test_file_icacls /grant \"%s\":RX", pwd.username);
|
||||
if (r != 0) {
|
||||
goto acl_cleanup;
|
||||
}
|
||||
|
||||
/* Try opening the file */
|
||||
r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL);
|
||||
if (r < 0) {
|
||||
goto acl_cleanup;
|
||||
}
|
||||
uv_fs_req_cleanup(&open_req1);
|
||||
r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
|
||||
if (r != 0) {
|
||||
goto acl_cleanup;
|
||||
}
|
||||
uv_fs_req_cleanup(&close_req);
|
||||
|
||||
acl_cleanup:
|
||||
/* Cleanup */
|
||||
call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
|
||||
pwd.username);
|
||||
unlink("test_file_icacls");
|
||||
uv_os_free_passwd(&pwd);
|
||||
ASSERT(r == 0);
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_IMPL(fs_fchmod_archive_readolny) {
|
||||
uv_fs_t req;
|
||||
uv_file file;
|
||||
int r;
|
||||
/* Test clearing read-only flag from files with Archive flag cleared */
|
||||
|
||||
/* Setup*/
|
||||
unlink("test_file");
|
||||
r = uv_fs_open(NULL,
|
||||
&req,
|
||||
"test_file",
|
||||
O_WRONLY | O_CREAT,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(req.result >= 0);
|
||||
file = req.result;
|
||||
uv_fs_req_cleanup(&req);
|
||||
r = uv_fs_close(NULL, &req, file, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
/* Make the file read-only and clear archive flag */
|
||||
r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
|
||||
ASSERT(r != 0);
|
||||
check_permission("test_file", 0400);
|
||||
/* Try fchmod */
|
||||
r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL);
|
||||
ASSERT(r >= 0);
|
||||
ASSERT(req.result >= 0);
|
||||
file = req.result;
|
||||
uv_fs_req_cleanup(&req);
|
||||
r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL);
|
||||
ASSERT(r == 0);
|
||||
ASSERT(req.result == 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
r = uv_fs_close(NULL, &req, file, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
check_permission("test_file", S_IWUSR);
|
||||
|
||||
/* Restore Archive flag for rest of the tests */
|
||||
r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE);
|
||||
ASSERT(r != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -337,6 +337,8 @@ TEST_DECLARE (fs_file_pos_after_op_with_offset)
|
||||
TEST_DECLARE (fs_null_req)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (fs_exclusive_sharing_mode)
|
||||
TEST_DECLARE (fs_open_readonly_acl)
|
||||
TEST_DECLARE (fs_fchmod_archive_readolny)
|
||||
#endif
|
||||
TEST_DECLARE (threadpool_queue_work_simple)
|
||||
TEST_DECLARE (threadpool_queue_work_einval)
|
||||
@ -869,6 +871,8 @@ TASK_LIST_START
|
||||
TEST_ENTRY (fs_null_req)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (fs_exclusive_sharing_mode)
|
||||
TEST_ENTRY (fs_open_readonly_acl)
|
||||
TEST_ENTRY (fs_fchmod_archive_readolny)
|
||||
#endif
|
||||
TEST_ENTRY (get_osfhandle_valid_handle)
|
||||
TEST_ENTRY (threadpool_queue_work_simple)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user