Commit 2f6dbaa0ea

Ryan Liptak <squeek502@hotmail.com>
2021-08-14 02:03:27
fs.Dir.walk: Do not close the initial dir during/after walking it
Closing the initial directory was unexpected to me, and does not mesh very well with how the rest of the Dir API works. Fixes #9556
1 parent 6a50948
Changed files (3)
lib/std/fs/test.zig
@@ -909,11 +909,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
 test "walker" {
     if (builtin.os.tag == .wasi) return error.SkipZigTest;
 
-    var arena = ArenaAllocator.init(testing.allocator);
-    defer arena.deinit();
-    var allocator = &arena.allocator;
-
-    var tmp = tmpDir(.{});
+    var tmp = tmpDir(.{ .iterate = true });
     defer tmp.cleanup();
 
     // iteration order of walker is undefined, so need lookup maps to check against
@@ -942,10 +938,7 @@ test "walker" {
         try tmp.dir.makePath(kv.key);
     }
 
-    const tmp_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
-    const tmp_dir = try fs.cwd().openDir(tmp_path, .{ .iterate = true });
-
-    var walker = try tmp_dir.walk(testing.allocator);
+    var walker = try tmp.dir.walk(testing.allocator);
     defer walker.deinit();
 
     var num_walked: usize = 0;
lib/std/build.zig
@@ -3026,7 +3026,8 @@ pub const InstallDirStep = struct {
         const self = @fieldParentPtr(InstallDirStep, "step", step);
         const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
         const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
-        const src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
+        var src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
+        defer src_dir.close();
         var it = try src_dir.walk(self.builder.allocator);
         next_entry: while (try it.next()) |entry| {
             for (self.options.exclude_extensions) |ext| {
lib/std/fs.zig
@@ -795,22 +795,31 @@ pub const Dir = struct {
                         .kind = base.kind,
                     };
                 } else {
-                    self.stack.pop().iter.dir.close();
+                    var item = self.stack.pop();
+                    if (self.stack.items.len != 0) {
+                        item.iter.dir.close();
+                    }
                 }
             }
             return null;
         }
 
         pub fn deinit(self: *Walker) void {
-            while (self.stack.popOrNull()) |*item| item.iter.dir.close();
+            while (self.stack.popOrNull()) |*item| {
+                if (self.stack.items.len != 0) {
+                    item.iter.dir.close();
+                }
+            }
             self.stack.deinit();
             self.name_buffer.deinit();
         }
     };
 
     /// Recursively iterates over a directory.
+    /// `self` must have been opened with `OpenDirOptions{.iterate = true}`.
     /// Must call `Walker.deinit` when done.
     /// The order of returned file system entries is undefined.
+    /// `self` will not be closed after walking it.
     pub fn walk(self: Dir, allocator: *Allocator) !Walker {
         var name_buffer = std.ArrayList(u8).init(allocator);
         errdefer name_buffer.deinit();