-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove absolute path support in Dir.open functions #7540
Comments
This goes against my understanding of the design of the For example, if As mentioned before, this is all rather counter-intuitive (if I'm even right about the reasoning, which I may not be), and it would be great to get some documentation added that clearly lays out why |
@squeek502 I don't understand why code would have to be different? Can you provide an example? If your application works on WASM, then that implies it uses relative path (since WASM doesn't support absolute paths), which would mean you would be using the pub fn example(out_name: []const u8) !void {
const dir = try openDir("out");
defer dir.close();
const f = dir.openFile(out_name);
// code that uses f
}
example("/tmp/foo"); In this example. the intention of the In the case where it is the intention to support absolute and relative paths, then there is no need for a pub fn example(out_filename: []const u8) !void {
const f = try openFile(out_filename);
// code that uses a and b
}
example("/tmp/foo"); With the proposed API change, the first example that is written incorrectly would result in a runtime error which indicates that the path given must be an relative path. This means we are failing earlier, by failing as soon as the function is called rather than failing because an assumption that the file will be created underneath the directory is violated. |
technically, it is how POSIX openat(3) function behave when an absolute path is passed. for quoting POSIX description:
So for someone coming from POSIX, the current behaviour of Dir-based fs is coherent. |
@marler8997 My understanding is that both of your examples would not be able to work when targeting WASI, since a I could very well be wrong about this, though, so please correct me if I am. |
@semarie that's a fair point, it looks like that is the case for the @sqeek502 Sorry I'm not understanding what you're trying to say. This issue is proposing that we remove absolute path support in the Dir methods, so if WASI never supported absolute paths in the first place then this proposal would have no affect on that platform. |
@marler8997 I think what I'm trying to get across is that (as far as I'm aware):
is not possible if the goal is to be able to target all platforms (including WASI) with the same code. So, the options as I see them are:
|
These "free functions" would still work on WASI. The "free functions" I described accept either absolute or relative paths, it handles both. That just means on WASI if an absolute path is passed in, it sounds like the WASI syscall would fail, just like it would today. This behavior doesn't change with this proposal. |
A relative path on its own is not good enough for WASI, though. It's more similar to URL resolution: you can't resolve a relative link like As always, I may be wrong. My understanding only comes from writing some fs tests for Zig and making sure they pass when targeting WASI, so my familiarity with how WASI actually works is pretty minimal. Do you have something in mind for how to implement a |
@sqeek502 I think we're getting off into the weeds here, like I said this proposal should have no affect on WASI. If WASI requires a Dir reference to work, then it will still requires a Dir reference to work regardless of whether or not the Dir methods support absolute paths. If I'm missing something, maybe you can clear it up by providing a code example? Can you provide an example that works on WASI today, but then wouldn't work with this proposal? |
Sure, here's an example. With the current API design, if you were to write a function that takes a path to a file that should be parsed, then the current API is designed to encourage you to write it something like this (although it is not as obvious that this is the case as it should be): const std = @import("std");
const builtin = @import("builtin");
const fs = std.fs;
fn parseFile(dir: fs.Dir, path: []const u8) !ParsedStruct {
const file = try dir.openFile(path, .{});
defer file.close();
var parsed = ParsedStruct{};
// parse
var buffer: [1]u8 = undefined;
const bytes_read = try file.readAll(&buffer);
parsed.empty = bytes_read == 0;
return parsed;
}
const ParsedStruct = struct {
empty: bool = false,
};
test "empty" {
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var file = try tmp.dir.createFile("test", .{});
file.close();
const parsed = try parseFile(tmp.dir, "test");
std.testing.expect(parsed.empty);
}
test "not empty" {
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
try tmp.dir.writeFile("test", "something");
const parsed = try parseFile(tmp.dir, "test");
std.testing.expect(!parsed.empty);
}
test "absolute path" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
try tmp.dir.writeFile("test", "something");
var absolute_path = try tmp.dir.realpathAlloc(std.testing.allocator, "test");
defer std.testing.allocator.free(absolute_path);
const parsed = try parseFile(tmp.dir, absolute_path);
std.testing.expect(!parsed.empty);
} This will allow it to work on any target (with both relative and absolute paths where absolute paths are supported): $ zig test 7540.zig
All 3 tests passed.
$ zig test -target wasm32-wasi --test-cmd wasmtime --test-cmd --dir=. --test-cmd-bin 7540.zig
2 passed; 1 skipped. If, instead, fn parseFile(path: []const u8) !ParsedStruct {
const file = try fs.openAnyFile(path, .{});
defer file.close();
// ...
} But this then makes that function no longer able to target WASI (see my previous comments). So, my concern with the proposal is that the existence of the proposed free functions would change what type of code people are encouraged to write, and that the use of the free functions would (unintentionally) exclude targeting certain platforms (WASI in this case). This would in turn reduce the re-usability of libraries across all the target platforms (you'd have to intentionally 'support' WASI whereas now you basically get WASI support for free). |
Hmm that's interesting. So if I understand you correctly, in order for any code that works with the filesystem to work with WASI, it has to pair every filename with a Dir reference as well? How does the WASI application retrieve a Dir reference in the first place? |
Preopens, see std/fs/wasi.zig. Note: preopens are not guaranteed to exist--running my previous example without the
|
@squeek502 I don't know much about WASI, but I would think that the free functions could use some sort of default Dir reference (i.e. like |
As I understand it, yes, this was/is the intention, although I may be wrong about maximizing-cross-platform-ness being the original goal. From #3813 when
|
For the sake of convenience, I agree that there should be a separate function like Passing in the My suggestion is adding another function to |
Dir functions like
openFile
andopenDir
accept relative paths, but they also accept absolute paths. The implementation could be made simpler if they only worked with relative paths, and the interface would arguably be simpler/easier to understand. I'm not sure what benefit we get by making them also work with absolute paths. By removing absolute path support in these functions, the only thing we would lose isopen
functions that can work with relative and absolute paths, but these methods could be implemented as "free functions" without aDir
reference (if we wanted to support this mechanism). I propose removing support for absolute paths in theDir
functions.The text was updated successfully, but these errors were encountered: