From 6d6f6a4ac6f1f2666fa2d4500ef4634fdfe0d947 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 14 Mar 2023 17:21:29 -0700 Subject: [PATCH] std.os.windows.OpenFile: handle DELETE_PENDING This error means that there *was* a file in this location on the file system, but it was deleted. However, the OS is not finished with the deletion operation, and so this CreateFile call has failed. There is not really a sane way to handle this other than retrying the creation after the OS finishes the deletion. --- lib/std/os/windows.zig | 82 ++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index b63fdb9f92..5576200ea5 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -105,41 +105,53 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN // If we're not following symlinks, we need to ensure we don't pass in any synchronization flags such as FILE_SYNCHRONOUS_IO_NONALERT. const flags: ULONG = if (options.follow_symlinks) file_or_dir_flag | blocking_flag else file_or_dir_flag | FILE_OPEN_REPARSE_POINT; - const rc = ntdll.NtCreateFile( - &result, - options.access_mask, - &attr, - &io, - null, - FILE_ATTRIBUTE_NORMAL, - options.share_access, - options.creation, - flags, - null, - 0, - ); - switch (rc) { - .SUCCESS => { - if (std.io.is_async and options.io_mode == .evented) { - _ = CreateIoCompletionPort(result, std.event.Loop.instance.?.os_data.io_port, undefined, undefined) catch undefined; - } - return result; - }, - .OBJECT_NAME_INVALID => unreachable, - .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, - .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, - .NO_MEDIA_IN_DEVICE => return error.NoDevice, - .INVALID_PARAMETER => unreachable, - .SHARING_VIOLATION => return error.AccessDenied, - .ACCESS_DENIED => return error.AccessDenied, - .PIPE_BUSY => return error.PipeBusy, - .OBJECT_PATH_SYNTAX_BAD => unreachable, - .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, - .FILE_IS_A_DIRECTORY => return error.IsDir, - .NOT_A_DIRECTORY => return error.NotDir, - .USER_MAPPED_FILE => return error.AccessDenied, - .INVALID_HANDLE => unreachable, - else => return unexpectedStatus(rc), + while (true) { + const rc = ntdll.NtCreateFile( + &result, + options.access_mask, + &attr, + &io, + null, + FILE_ATTRIBUTE_NORMAL, + options.share_access, + options.creation, + flags, + null, + 0, + ); + switch (rc) { + .SUCCESS => { + if (std.io.is_async and options.io_mode == .evented) { + _ = CreateIoCompletionPort(result, std.event.Loop.instance.?.os_data.io_port, undefined, undefined) catch undefined; + } + return result; + }, + .OBJECT_NAME_INVALID => unreachable, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.NoDevice, + .INVALID_PARAMETER => unreachable, + .SHARING_VIOLATION => return error.AccessDenied, + .ACCESS_DENIED => return error.AccessDenied, + .PIPE_BUSY => return error.PipeBusy, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, + .FILE_IS_A_DIRECTORY => return error.IsDir, + .NOT_A_DIRECTORY => return error.NotDir, + .USER_MAPPED_FILE => return error.AccessDenied, + .INVALID_HANDLE => unreachable, + .DELETE_PENDING => { + // This error means that there *was* a file in this location on + // the file system, but it was deleted. However, the OS is not + // finished with the deletion operation, and so this CreateFile + // call has failed. There is not really a sane way to handle + // this other than retrying the creation after the OS finishes + // the deletion. + std.time.sleep(std.time.ns_per_ms); + continue; + }, + else => return unexpectedStatus(rc), + } } }