-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
windows: use NtSetInformationFile in DeleteFile. #15316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Should also enable this test case: Lines 490 to 494 in 397649f
|
Using `FILE_DELETE_ON_CLOSE` can silently succeed without reporting any error on non-empty directory. This commit adds usage of NtSetInformationFile which will report `DIRECTORY_NOT_EMPTY`.
Will do, thanks for pointing that. |
e05340a
to
73c04d4
Compare
lib/std/os/windows.zig
Outdated
@@ -935,6 +936,22 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil | |||
.CANNOT_DELETE => return error.AccessDenied, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this NtCreateFile
call does not use FILE_DELETE_ON_CLOSE
anymore, it seems likely that this error is no longer possible here but likely is possible from the NtSetInformationFile
call.
More context:
- Add CANNOT_DELETE as a possible error in os.windows.DeleteFile #10495
- Windows: Files marked as read-only fail to get deleted #13084
It'd probably be good to add a test case that intentionally tries to delete a read-only file so that we know this case continues to be handled in the same way. Maybe something like (totally untested):
test "deleting a read-only file on windows" {
if (builtin.os.tag != .windows) return error.SkipZigTest;
var tmp = tmpDir(.{});
defer tmp.cleanup();
// Create a file and make it read-only
{
const file = try tmp.dir.createFile("test_file", .{ .read = true });
defer file.close();
const metadata = try file.metadata();
var permissions = metadata.permissions();
permissions.setReadOnly(true);
try file.setPermissions(permissions);
}
try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file"));
// Now make the file not read-only
{
const file = try tmp.dir.openFile("test_file", .{});
defer file.close();
const metadata = try file.metadata();
var permissions = metadata.permissions();
permissions.setReadOnly(false);
try file.setPermissions(permissions);
}
try tmp.dir.deleteFile("test_file");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. It should be moved to the set function return.
Also, while testing this, I found out that NtCreateFile
can also result in AccessDenied, when the owner is different. So we can replace CANNOT_DELETE
with ACCESS_DENIED
and add CANNOT_DELETE
to the second rc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note on the test example:
I think you may have found another bug with that (if it doesn't already exist) 😄 . The test will fail on Access Denied for a different reason. The file is not open with FILE_WRITE_ATTRIBUTES
as the only OpenMode
are read_only
(GENERIC_READ), write_only
(GENERIC_WRITE), and read_write
(both).
and since GENERIC_READ
only have FILE_READ_ATTRIBUTES
, it cannot change its attributes anymore after the read only is set. Sort of related to the second issue you linked, but specific to setPermissions
rather than deleteFile
I am looking to see if there are more refined flags or functions that allows that, but from a quick search, i couldn't find one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is the relevant issue: #12377 (about Dir
but seems like it might apply to File.OpenFlags
too).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that looks like the same behavior.
I am adding a modified test with no file closing/reopen. If it doesn't seem necessary to test right now due to this, I can remove it.
Can also add "closes #5537" to OP |
Deleting a read-only file should result in `AccessDenied` (`CANNOT_DELETE`). Note: This test was observed to fail when the file is closed then reopened before the change in permission due to the absence of `FILE_WRITE_ATTRIBUTES` when re-opened. (see ziglang#15316).
Deleting a read-only file should result in `AccessDenied` (`CANNOT_DELETE`). Note: This test was observed to fail when the file is closed then reopened before the change in permission due to the absence of `FILE_WRITE_ATTRIBUTES` when re-opened. (see ziglang#15316).
d273e3c
to
55b2456
Compare
DELETE_PENDING can happen when the file is yet to be closed for deletion or if it never get closed. In that case, DeleteFile should assume the file deletion is succeeding (no CloseHandle is required as it's a "failure"). In case of `DELETE_PENDING` failure, the file may still exist. In which case if it's part of `deleteTree`, it will eventually fail on `error.DirNotEmpty`.
Thank you for the implementation @xEgoist and thank you for the review @squeek502. I'm happy to merge this when @squeek502 gives the thumbs up. |
Looks good to me 👍 |
Deleting a read-only file should result in `AccessDenied` (`CANNOT_DELETE`). Note: This test was observed to fail when the file is closed then reopened before the change in permission due to the absence of `FILE_WRITE_ATTRIBUTES` when re-opened. (see ziglang#15316).
closes #15315closes #5537
Using
FILE_DELETE_ON_CLOSE
can silently succeed without reporting any error on non-empty directory. One way to return an error is to addNtSetInformationFile
which will causeDeleteFile
to reportDIRECTORY_NOT_EMPTY
.