-
Notifications
You must be signed in to change notification settings - Fork 260
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
WASI: fs.FS
as Preopen parameter with implementation of fd_prestat_get
#362
Conversation
b7e2e0e
to
ad2dc8a
Compare
fs.FS
as Preopen parameter with implementation of fd_prestat_get
internal/wasi/fs.go
Outdated
for name, entry := range dir.Entries { | ||
entries = append(entries, &memFileInfo{name: path.Base(name), fsEntry: entry}) | ||
} | ||
sort.Slice(entries, func(i, j int) bool { return entries[i].Name() < entries[j].Name() }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q: is sorting dirs necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it's necessary. fs.ReadDir requires the result is sorted, and the `fstest.TestFS" becomes flakey if we don't sort.
return wasi.ErrnoBadf | ||
} | ||
writer, ok := f.file.(io.Writer) | ||
if !ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q: in what case !ok
in real world?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Realworld examples are when the fily system of f.file
is an embed.FS
. f.file
is fs.File
, which doesn't require io.Writer
, so it doesn't always implement io.Writer
. Maybe it's better to comment that. let me do it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting this started. I think there will be a fair amount of work to finish this up, and we don't want to hold the supporting changes hostage through that. Can you extract the wasi api changes and tests into a separate PR from the fs.FS stuff?
internal/wasi/fs_test.go
Outdated
"simple file": {Contents: []byte("simple cont")}, | ||
"directory": { | ||
Entries: map[string]*memFSEntry{ | ||
"file1 inside directory": {Contents: []byte("simple cont file1 inside directory")}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe use more realistic paths here? it would make it easier to read and know the intent.
ex would it be "directory/file1" because this includes the name of the key?
also the contents if dummy can be shorter like single character or single word
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed the names to more realistic paths, but let me know if those are not what you intended. THanks!
I'm going to take over this PR for some several minutes, rebase it after extracting the WASI functions to another PR then force push a more isolated variant to proceed with. bear with me a bit |
64ba467
to
169b342
Compare
once #388 is merged I'll rebase this and hand it back over to @nullpo-head. hopefully next time we can keep fixing WASI APIs separate from new API work that uses them. |
…ssary PathOpen features. Signed-off-by: Takaya Saeki <[email protected]>
169b342
to
ca9e8d4
Compare
okie dokie over to you! |
Signed-off-by: Takaya Saeki <[email protected]>
Signed-off-by: Takaya Saeki <[email protected]>
Signed-off-by: Takaya Saeki <[email protected]>
Signed-off-by: Takaya Saeki <[email protected]>
Signed-off-by: Takaya Saeki <[email protected]>
ptal @codefromthecrypt @mathetake thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memFS looks suspiciously like fstest.MapFS
Please delete it and use fstest.MapFS
if you need a dummy filesystem besides embedFS. The main point of this change is to stop bespoke APIs and use fs.FS instead.
I would be very very surprised if there isn't an existing fs.FS library out there that supports writes.
If we couple OpenFile(path string, flag int, perm os.FileMode) (fs.File, error)
with fs.FS
we almost guarantee people can't bring their own impls as an existing impl wouldn't be using our interfaces. Instead, until we find an alternative to OpenFile
(this is a TODO to find one!), make a separate Config option for a write path that accepts this interface.
ex. config.WithOpenFile(path, OpenFile)
and put a TODO to look more into options for writes that don't imply completely custom implementations of fs.FS
// Configure what resources you share with the WASI program. | ||
wasiConfig := wazero.NewWASIConfig() | ||
// Share fs.FS as pre-opened directories | ||
wasiConfig = wasiConfig.WithPreopens( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like WithXXXMount will be easier for people to understand that "preopens" WDYT? Also, we can make it chained instead of a map. the map can be an internal detail
Ex.
// documented as read-only
wasiConfig.WithMount("/input", embeddedFS)
}, | ||
) | ||
// the wasm module will concatenate the contents of the two input.txt and write to output.txt | ||
wasiConfig = wasiConfig.WithArgs("./input.txt", "/input/input.txt", "./output.txt") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just overwrite a file instead? that's a lot simpler and less code.
// OpenFile opens the named file with specified flag in the same way as os.OpenFile. | ||
// For example, if the path does not exist and flag includes os.O_CREATE, it will create a new file with perm. | ||
// | ||
// Unlike os.OpenFile, OpenFile must reject paths that do not satisfy `fs.ValidPath(path)`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a hard time believing there are any strict requirements that need to be made here based on the WASI spec. It doesn't have spec tests and at best very vaguely documented. Any constraints that make something behave different than something else in Go should be not just mentioned but also answered why. (Ex in RATIONALE is a good place as there's not likely any spec or spectest to say why)
Can you please document where these are coming from?
I'm going to fork this and try to salvage what I can from it, but generally this is far from ideal and time is better spent on another path. Hence closing it. |
func (c *Config) Stdin(reader io.Reader) { | ||
c.stdin = reader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not currently planning to do anything to try to make stdin/stdout/stderr act like normal files as they aren't and it is more distracting forcing them though a struct that only has one side useful than the special casing in the first place.
There's nothing to salvage from this PR except experience. Once things are stable we can do another impl, but research and citation here are a prerequisite so that we don't fall into the same hole again #390 Thanks for giving this a try |
// fs.FS requires a FS to reject a path that doesn't satisfy fs.ValidPath. | ||
if !fs.ValidPath(name) || | ||
// '\' works as alternative path separater and ':' allows to express a root drive directory. | ||
// fs.FS implementation must reject those path on Windows. See Note in the doc of fs.ValidPath. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a good example of a leaky abstraction. WASI isn't and OS and if it were it wouldn't be windows, and there's nothing about fs.FS that should ever allow windows paths to leak into it. Ex. if someone exposes their "c:" drive, that's not on us to enforce. The only sensible file mappings would be chrooted if even an actual filesystem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other words windows-based file handing in a barely specified posix system layer is a non-goal. We can use this to simplify discussions in future work. By adding code to address things like OS-specific things inside WASI, we are actually making the problem more confused, especially to people new who may not know Wasm is effectively a virtual machine, and if shares anything in common with OS, it would be unix, not windows, that we'd optimize for.
This PR changes the input type of preopen from
wasi.FS
tofs.FS
, which is more natural for users.This PR also includes implementation of
FdPrestatGet
andPathOpen
flags, which are necessary for multiple pre-open directories to work correctly.