authorgravatar for egoist@egoistic.devxEgoist <egoist@egoistic.dev> 2023-04-16 00:38:25-05:00
committergravatar for egoist@egoistic.devxEgoist <egoist@egoistic.dev> 2023-04-16 15:18:15-05:00
log911f74e93b15024c7a2a15ca6845bd0ddbdf9b3c
tree6496bc16c1f1ce236465e438f1f978acd4976c3d
parent7fad555e5e16e6cb71554981394387a0622093b0

windows: use NtSetInformationFile in DeleteFile.

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`.

1 files changed, 24 insertions(+), 3 deletions(-)

lib/std/os/windows.zig+24-3
......@@ -870,6 +870,7 @@ pub const DeleteFileError = error{
870870 Unexpected,
871871 NotDir,
872872 IsDir,
873 DirNotEmpty,
873874};
874875
875876pub const DeleteFileOptions = struct {
......@@ -879,9 +880,9 @@ pub const DeleteFileOptions = struct {
879880
880881pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFileError!void {
881882 const create_options_flags: ULONG = if (options.remove_dir)
882 FILE_DELETE_ON_CLOSE | FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
883 FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
883884 else
884 FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT; // would we ever want to delete the target instead?
885 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT; // would we ever want to delete the target instead?
885886
886887 const path_len_bytes = @intCast(u16, sub_path_w.len * 2);
887888 var nt_name = UNICODE_STRING{
......@@ -924,7 +925,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
924925 0,
925926 );
926927 switch (rc) {
927 .SUCCESS => return CloseHandle(tmp_handle),
928 .SUCCESS => {},
928929 .OBJECT_NAME_INVALID => unreachable,
929930 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
930931 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
......@@ -935,6 +936,22 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
935936 .CANNOT_DELETE => return error.AccessDenied,
936937 else => return unexpectedStatus(rc),
937938 }
939 var file_dispo = FILE_DISPOSITION_INFORMATION{
940 .DeleteFile = TRUE,
941 };
942 rc = ntdll.NtSetInformationFile(
943 tmp_handle,
944 &io,
945 &file_dispo,
946 @sizeOf(FILE_DISPOSITION_INFORMATION),
947 .FileDispositionInformation,
948 );
949 CloseHandle(tmp_handle);
950 switch (rc) {
951 .SUCCESS => return,
952 .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
953 else => return unexpectedStatus(rc),
954 }
938955}
939956
940957pub const MoveFileError = error{ FileNotFound, AccessDenied, Unexpected };
......@@ -2470,6 +2487,10 @@ pub const FILE_INFORMATION_CLASS = enum(c_int) {
24702487 FileMaximumInformation,
24712488};
24722489
2490pub const FILE_DISPOSITION_INFORMATION = extern struct {
2491 DeleteFile: BOOLEAN,
2492};
2493
24732494pub const FILE_FS_DEVICE_INFORMATION = extern struct {
24742495 DeviceType: DEVICE_TYPE,
24752496 Characteristics: ULONG,