summaryrefslogtreecommitdiff
path: root/src/fs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig20
1 files changed, 20 insertions, 0 deletions
diff --git a/src/fs.zig b/src/fs.zig
index 965eb47c..e5980fe9 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -685,6 +685,26 @@ pub fn makeDirs(dir: []const u8) void {
_ = libc.mkdir(z[0..dir.len :0], 0o755);
}
+/// Whether `dir` is not there to make because one above it refuses: its
+/// nearest ancestor that is there may not be searched or written (EACCES:
+/// `noperm/a/b`, `/proc/1/root/x`).
+pub fn deniedAbove(dir: []const u8) bool {
+ if (comptime !platform_has_fs) return false;
+ var at: ?[]const u8 = dir;
+ while (at) |d| : (at = std.fs.path.dirname(d)) {
+ var z: [4096]u8 = undefined;
+ const dz = std.fmt.bufPrintSentinel(&z, "{s}", .{d}, 0) catch return false;
+ if (libc.access(dz.ptr, 0) != 0) continue; // F_OK
+ return libc.access(dz.ptr, 2 | 1) != 0; // W_OK | X_OK
+ }
+ return false;
+}
+
+test "a directory under one that may not be searched or written is denied, one merely missing is not" {
+ try std.testing.expect(deniedAbove("/proc/1/root/x/y"));
+ try std.testing.expect(!deniedAbove("/tmp/pardes-surely-missing-dir/a/b"));
+}
+
pub fn localPath(path: []const u8) ?[]const u8 {
if (std.mem.eql(u8, path, "/n/os")) return "/";
if (std.mem.startsWith(u8, path, "/n/os/")) return path[5..];