| ... | ... | @@ -2046,41 +2046,38 @@ pub const Dir = struct { |
| 2046 | 2046 | /// this function recursively removes its entries and then tries again. |
| 2047 | 2047 | /// This operation is not atomic on most file systems. |
| 2048 | 2048 | pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { |
| 2049 | | start_over: while (true) { |
| 2050 | | var got_access_denied = false; |
| 2051 | | |
| 2052 | | // First, try deleting the item as a file. This way we don't follow sym links. |
| 2053 | | if (self.deleteFile(sub_path)) { |
| 2054 | | return; |
| 2055 | | } else |err| switch (err) { |
| 2056 | | error.FileNotFound => return, |
| 2057 | | error.IsDir => {}, |
| 2058 | | error.AccessDenied => got_access_denied = true, |
| 2049 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 2050 | if (self.deleteFile(sub_path)) { |
| 2051 | return; |
| 2052 | } else |err| switch (err) { |
| 2053 | error.FileNotFound => return, |
| 2054 | error.IsDir => {}, |
| 2055 | error.AccessDenied, |
| 2056 | error.InvalidUtf8, |
| 2057 | error.SymLinkLoop, |
| 2058 | error.NameTooLong, |
| 2059 | error.SystemResources, |
| 2060 | error.ReadOnlyFileSystem, |
| 2061 | error.NotDir, |
| 2062 | error.FileSystem, |
| 2063 | error.FileBusy, |
| 2064 | error.BadPathName, |
| 2065 | error.Unexpected, |
| 2066 | => |e| return e, |
| 2067 | } |
| 2059 | 2068 | |
| 2060 | | error.InvalidUtf8, |
| 2061 | | error.SymLinkLoop, |
| 2062 | | error.NameTooLong, |
| 2063 | | error.SystemResources, |
| 2064 | | error.ReadOnlyFileSystem, |
| 2065 | | error.NotDir, |
| 2066 | | error.FileSystem, |
| 2067 | | error.FileBusy, |
| 2068 | | error.BadPathName, |
| 2069 | | error.Unexpected, |
| 2070 | | => |e| return e, |
| 2071 | | } |
| 2069 | start_over: while (true) { |
| 2072 | 2070 | var iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { |
| 2073 | 2071 | error.NotDir => { |
| 2074 | | if (got_access_denied) { |
| 2075 | | return error.AccessDenied; |
| 2076 | | } |
| 2077 | | continue :start_over; |
| 2072 | // Somehow the sub_path got changed into a file while we were trying to delete the tree. |
| 2073 | // This implies that the dir at the sub_path was deleted at some point so we consider this |
| 2074 | // as a successful delete and return. |
| 2075 | return; |
| 2078 | 2076 | }, |
| 2079 | 2077 | error.FileNotFound => { |
| 2080 | 2078 | // That's fine, we were trying to remove this directory anyway. |
| 2081 | | continue :start_over; |
| 2079 | return; |
| 2082 | 2080 | }, |
| 2083 | | |
| 2084 | 2081 | error.InvalidHandle, |
| 2085 | 2082 | error.AccessDenied, |
| 2086 | 2083 | error.SymLinkLoop, |
| ... | ... | @@ -2112,63 +2109,69 @@ pub const Dir = struct { |
| 2112 | 2109 | // open it, and close the original directory. Repeat. Then start the entire operation over. |
| 2113 | 2110 | |
| 2114 | 2111 | scan_dir: while (true) { |
| 2115 | | var dir_it = iterable_dir.iterate(); |
| 2116 | | while (try dir_it.next()) |entry| { |
| 2117 | | if (iterable_dir.dir.deleteFile(entry.name)) { |
| 2118 | | continue; |
| 2119 | | } else |err| switch (err) { |
| 2120 | | error.FileNotFound => continue, |
| 2121 | | |
| 2122 | | // Impossible because we do not pass any path separators. |
| 2123 | | error.NotDir => unreachable, |
| 2124 | | |
| 2125 | | error.IsDir => {}, |
| 2126 | | error.AccessDenied => got_access_denied = true, |
| 2127 | | |
| 2128 | | error.InvalidUtf8, |
| 2129 | | error.SymLinkLoop, |
| 2130 | | error.NameTooLong, |
| 2131 | | error.SystemResources, |
| 2132 | | error.ReadOnlyFileSystem, |
| 2133 | | error.FileSystem, |
| 2134 | | error.FileBusy, |
| 2135 | | error.BadPathName, |
| 2136 | | error.Unexpected, |
| 2137 | | => |e| return e, |
| 2138 | | } |
| 2139 | | |
| 2140 | | const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { |
| 2141 | | error.NotDir => { |
| 2142 | | if (got_access_denied) { |
| 2143 | | return error.AccessDenied; |
| 2144 | | } |
| 2112 | var dir_it = iterable_dir.iterateAssumeFirstIteration(); |
| 2113 | dir_it: while (try dir_it.next()) |entry| { |
| 2114 | var treat_as_dir = entry.kind == .Directory; |
| 2115 | handle_entry: while (true) { |
| 2116 | if (treat_as_dir) { |
| 2117 | const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { |
| 2118 | error.NotDir => { |
| 2119 | treat_as_dir = false; |
| 2120 | continue :handle_entry; |
| 2121 | }, |
| 2122 | error.FileNotFound => { |
| 2123 | // That's fine, we were trying to remove this directory anyway. |
| 2124 | continue :dir_it; |
| 2125 | }, |
| 2126 | |
| 2127 | error.InvalidHandle, |
| 2128 | error.AccessDenied, |
| 2129 | error.SymLinkLoop, |
| 2130 | error.ProcessFdQuotaExceeded, |
| 2131 | error.NameTooLong, |
| 2132 | error.SystemFdQuotaExceeded, |
| 2133 | error.NoDevice, |
| 2134 | error.SystemResources, |
| 2135 | error.Unexpected, |
| 2136 | error.InvalidUtf8, |
| 2137 | error.BadPathName, |
| 2138 | error.DeviceBusy, |
| 2139 | => |e| return e, |
| 2140 | }; |
| 2141 | if (cleanup_dir_parent) |*d| d.close(); |
| 2142 | cleanup_dir_parent = iterable_dir; |
| 2143 | iterable_dir = new_dir; |
| 2144 | mem.copy(u8, &dir_name_buf, entry.name); |
| 2145 | dir_name = dir_name_buf[0..entry.name.len]; |
| 2145 | 2146 | continue :scan_dir; |
| 2146 | | }, |
| 2147 | | error.FileNotFound => { |
| 2148 | | // That's fine, we were trying to remove this directory anyway. |
| 2149 | | continue :scan_dir; |
| 2150 | | }, |
| 2151 | | |
| 2152 | | error.InvalidHandle, |
| 2153 | | error.AccessDenied, |
| 2154 | | error.SymLinkLoop, |
| 2155 | | error.ProcessFdQuotaExceeded, |
| 2156 | | error.NameTooLong, |
| 2157 | | error.SystemFdQuotaExceeded, |
| 2158 | | error.NoDevice, |
| 2159 | | error.SystemResources, |
| 2160 | | error.Unexpected, |
| 2161 | | error.InvalidUtf8, |
| 2162 | | error.BadPathName, |
| 2163 | | error.DeviceBusy, |
| 2164 | | => |e| return e, |
| 2165 | | }; |
| 2166 | | if (cleanup_dir_parent) |*d| d.close(); |
| 2167 | | cleanup_dir_parent = iterable_dir; |
| 2168 | | iterable_dir = new_dir; |
| 2169 | | mem.copy(u8, &dir_name_buf, entry.name); |
| 2170 | | dir_name = dir_name_buf[0..entry.name.len]; |
| 2171 | | continue :scan_dir; |
| 2147 | } else { |
| 2148 | if (iterable_dir.dir.deleteFile(entry.name)) { |
| 2149 | continue :dir_it; |
| 2150 | } else |err| switch (err) { |
| 2151 | error.FileNotFound => continue :dir_it, |
| 2152 | |
| 2153 | // Impossible because we do not pass any path separators. |
| 2154 | error.NotDir => unreachable, |
| 2155 | |
| 2156 | error.IsDir => { |
| 2157 | treat_as_dir = true; |
| 2158 | continue :handle_entry; |
| 2159 | }, |
| 2160 | |
| 2161 | error.AccessDenied, |
| 2162 | error.InvalidUtf8, |
| 2163 | error.SymLinkLoop, |
| 2164 | error.NameTooLong, |
| 2165 | error.SystemResources, |
| 2166 | error.ReadOnlyFileSystem, |
| 2167 | error.FileSystem, |
| 2168 | error.FileBusy, |
| 2169 | error.BadPathName, |
| 2170 | error.Unexpected, |
| 2171 | => |e| return e, |
| 2172 | } |
| 2173 | } |
| 2174 | } |
| 2172 | 2175 | } |
| 2173 | 2176 | // Reached the end of the directory entries, which means we successfully deleted all of them. |
| 2174 | 2177 | // Now to remove the directory itself. |