├── .github └── workflows │ ├── main.yml │ ├── publish.yml │ └── update.yml ├── LICENSE.md ├── README.md ├── imports.md ├── path-resolution.md ├── test └── README.md ├── wit-0.3.0-draft ├── deps.lock ├── deps.toml ├── deps │ └── clocks │ │ ├── monotonic-clock.wit │ │ ├── timezone.wit │ │ ├── wall-clock.wit │ │ └── world.wit ├── preopens.wit ├── types.wit └── world.wit └── wit ├── deps.lock ├── deps.toml ├── deps ├── clocks │ ├── monotonic-clock.wit │ ├── timezone.wit │ ├── wall-clock.wit │ └── world.wit └── io │ ├── error.wit │ ├── poll.wit │ ├── streams.wit │ └── world.wit ├── preopens.wit ├── types.wit └── world.wit /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | jobs: 9 | abi-up-to-date: 10 | name: Check ABI files are up-to-date 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: ensure `./wit/deps` are in sync 15 | run: | 16 | curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.5.0/wit-deps-x86_64-unknown-linux-musl 17 | chmod +x wit-deps 18 | ./wit-deps lock 19 | ./wit-deps -m wit-0.3.0-draft/deps.toml -l wit-0.3.0-draft/deps.lock -d wit-0.3.0-draft/deps lock 20 | git add -N wit/deps 21 | git add -N wit-0.3.0-draft/deps 22 | git diff --exit-code 23 | - uses: WebAssembly/wit-abi-up-to-date@v23 24 | with: 25 | wit-bindgen: '0.37.0' 26 | all-features: 'true' -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish a Wasm Component package to GitHub Artifacts 2 | 3 | # Run this action whenever a new release is tagged 4 | on: 5 | push: 6 | tags: 7 | - v* 8 | workflow_dispatch: 9 | 10 | env: 11 | IMAGE_NAME: ${{ github.repository }} 12 | 13 | jobs: 14 | publish: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | id-token: write 18 | packages: write 19 | contents: write 20 | 21 | steps: 22 | # Checkout the repo and install dependencies 23 | - name: Checkout repository 24 | uses: actions/checkout@v2 25 | - name: Install cargo-binstall 26 | uses: cargo-bins/cargo-binstall@v1.10.15 27 | - name: Install wkg 28 | shell: bash 29 | run: cargo binstall wkg 30 | - name: Install cosign 31 | uses: sigstore/cosign-installer@v3.7.0 32 | 33 | # To version our image we want to obtain the version from the tag 34 | - name: Get version 35 | id: meta 36 | uses: docker/metadata-action@v5 37 | with: 38 | images: ghcr.io/webassembly/wasi/filesystem 39 | tags: | 40 | type=semver,pattern={{version}} 41 | 42 | # To upload our image to the GitHub registry, we first have to login 43 | - name: Login to the GitHub registry 44 | uses: docker/login-action@v3 45 | with: 46 | registry: ghcr.io 47 | username: ${{ github.actor }} 48 | password: ${{ secrets.ORG_PAT }} 49 | 50 | # Build our `.wit` files into a Wasm binary 51 | - name: Build 52 | shell: bash 53 | run: wkg wit build -o wasi-filesystem.wasm 54 | 55 | # Upload the Wasm binary to the GitHub registry 56 | - name: Publish to GitHub Container Registry 57 | id: publish 58 | uses: bytecodealliance/wkg-github-action@v5 59 | with: 60 | oci-reference-without-tag: 'ghcr.io/webassembly/wasi/filesystem' 61 | file: 'wasi-filesystem.wasm' 62 | description: 'A WASI API primarily for accessing host filesystems.' 63 | source: 'https://github.com/webassembly/wasi' 64 | homepage: 'https://wasi.dev' 65 | version: ${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} 66 | licenses: 'Apache-2.0 WITH LLVM-exception' 67 | 68 | # Sign the output component 69 | - name: Sign the wasm component 70 | run: cosign sign --yes ghcr.io/webassembly/wasi/filesystem@${{ steps.publish.outputs.digest }} 71 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Create a PR to upgrade WIT to a new version 2 | 3 | # Manually dispatch this action from the Actions page 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | prev_version: 8 | description: 'Upgrading from version (without the v)' 9 | required: true 10 | type: string 11 | next_version: 12 | description: 'Upgrading to version (without the v)' 13 | required: true 14 | type: string 15 | 16 | permissions: 17 | pull-requests: write 18 | contents: write 19 | 20 | jobs: 21 | update-versions: 22 | runs-on: ubuntu-latest 23 | steps: 24 | # Checkout the repo and install dependencies 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | - name: Install cargo-binstall 28 | uses: cargo-bins/cargo-binstall@v1.10.15 29 | - name: Install wit-bindgen 30 | shell: bash 31 | run: cargo binstall wit-bindgen-cli 32 | - name: Install wit-deps 33 | shell: bash 34 | run: cargo binstall wit-deps-cli 35 | 36 | # echo input 37 | - name: Print the versions 38 | run: echo Upgrading from ${{ inputs.prev_version }} to ${{ inputs.next_version }} 39 | 40 | # upgrade 41 | - name: Upgrade tag 42 | run: find . -type f -name "*.wit" -exec sed -i "s/${{ inputs.prev_version }}/${{ inputs.next_version }}/g" {} + 43 | - name: Upgrade wit deps 44 | run: wit-deps update 45 | - name: Generate markdown 46 | run: wit-bindgen markdown wit --html-in-md --all-features 47 | 48 | # file PR 49 | - name: Create feature branch 50 | env: 51 | FEATURE_BRANCH: release-v${{ inputs.next_version }} 52 | run: | 53 | git config user.name "github-actions[bot]" 54 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 55 | git add . 56 | git checkout -b $FEATURE_BRANCH 57 | git push -u origin $FEATURE_BRANCH 58 | git commit -m "Update to v${{ inputs.next_version }}" 59 | git push 60 | 61 | - name: Create pull request 62 | run: gh pr create -B main -H release-v${{ inputs.next_version }} --title 'Release v${{ inputs.next_version }}' --body 'Updates the package version to v${{ inputs.next_version }}. Thanks!' 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2019-2024 the Contributors to the WASI Specification, published 2 | by the [WebAssembly Community Group][cg] under the 3 | [W3C Community Contributor License Agreement (CLA)][cla]. A human-readable 4 | [summary][summary] is available. 5 | 6 | [cg]: https://www.w3.org/community/webassembly/ 7 | [cla]: https://www.w3.org/community/about/agreements/cla/ 8 | [summary]: https://www.w3.org/community/about/agreements/cla-deed/ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WASI filesystem 2 | 3 | A proposed [WebAssembly System Interface](https://github.com/WebAssembly/WASI) API. 4 | 5 | ### Current Phase 6 | 7 | WASI-filesystem is currently in [Phase 3]. 8 | 9 | [Phase 3]: https://github.com/WebAssembly/WASI/blob/main/Proposals.md#phase-3---implementation-phase-cg--wg 10 | 11 | ### Champions 12 | 13 | - Dan Gohman 14 | 15 | ### Portability Criteria 16 | 17 | WASI filesystem must have host implementations which can pass the testsuite 18 | on at least Windows, macOS, and Linux. 19 | 20 | WASI filesystem must have at least two complete independent implementations. 21 | 22 | ## Table of Contents 23 | 24 | - [Introduction](#introduction) 25 | - [Goals](#goals) 26 | - [Non-goals](#non-goals) 27 | - [API walk-through](#api-walk-through) 28 | - [Use case 1](#use-case-1) 29 | - [Use case 2](#use-case-2) 30 | - [Detailed design discussion](#detailed-design-discussion) 31 | - [[Tricky design choice 1]](#tricky-design-choice-1) 32 | - [[Tricky design choice 2]](#tricky-design-choice-2) 33 | - [Considered alternatives](#considered-alternatives) 34 | - [[Alternative 1]](#alternative-1) 35 | - [[Alternative 2]](#alternative-2) 36 | - [Stakeholder Interest & Feedback](#stakeholder-interest--feedback) 37 | - [References & acknowledgements](#references--acknowledgements) 38 | 39 | ### Introduction 40 | 41 | WASI filesystem is a WASI API primarily for accessing host filesystems. It 42 | has functions for opening, reading, and writing files, and for working with 43 | directories. 44 | 45 | Unlike many filesystem APIs, WASI filesystem is capability-oriented. Instead 46 | of having functions that implicitly reference a filesystem namespace, 47 | WASI filesystems' APIs are passed a directory handle along with a path, and 48 | the path is looked up relative to the given handle, and sandboxed to be 49 | resolved within that directory. For more information about sandbox, see 50 | [WASI filesystem path resolution](path-resolution.md). 51 | 52 | WASI filesystem hides some of the surface differences between Windows and 53 | Unix-style filesystems, however much of its behavior, including the 54 | semantics of path lookup, and the semantics of files, directories, and 55 | symlinks, and the constraints on filesystem paths, is host-dependent. 56 | 57 | WASI filesystem is not intended to be used as a virtual API for accessing 58 | arbitrary resources. Unix's "everything is a file" philosophy is in conflict 59 | with the goals of supporting modularity and the principle of least authority. 60 | 61 | Many of the ideas related to doing capability-based filesystem sandboxing with 62 | `openat` come from [CloudABI](https://github.com/NuxiNL/cloudabi) and 63 | [Capsicum](https://wiki.freebsd.org/Capsicum). 64 | 65 | ### Goals 66 | 67 | The primary goal of WASI filesystem is to allow users to use WASI programs to 68 | access their existing filesystems in a straightforward and efficient manner. 69 | 70 | ### Non-goals 71 | 72 | WASI filesystem is not aiming for deterministic semantics. That would either 73 | require restricting it to fully controlled private filesystems, which would 74 | conflict with the goal of giving users access to their existing filesystems, 75 | or requiring implementations to do a lot of extra work to emulate specific 76 | defined behaviors, which would conflict with the goal of being efficient. 77 | 78 | ### API walk-through 79 | 80 | #### Opening a file 81 | 82 | ```rust 83 | /// Write "Hello, World" into a file called "greeting.txt" in `dir`. 84 | fn write_hello_world_to_a_file(dir: Descriptor) -> Result<(), Errno> { 85 | let at_flags = AtFlags::FollowSymlinks; 86 | let o_flags = OFlags::Create | OFlags::Trunc; 87 | let descriptor_flags = DescriptorFlags::Write; 88 | let mode = Mode::Readable; 89 | let file = 90 | dir.openat(at_flags, "greeting.txt", o_flags, descriptor_flags, mode)?; 91 | let message = b"Hello, World\n"; 92 | let mut view = &message[..]; 93 | let mut offset = 0; 94 | while !view.is_empty() { 95 | let num_written = file.pwrite(view.to_owned(), 0)?; 96 | offset += num_written; 97 | view = &view[num_written..]; 98 | } 99 | // The file descriptor is closed when it's dropped! 100 | } 101 | ``` 102 | 103 | Perhaps the biggest change from the preview1 version of openat, called 104 | `path_open`, is the removal of the *rights* flags. Preview1 associates 105 | a set of flags with every file descriptor enumerating which operations 106 | may be performed on it, such as reading, writing, appending, truncating, 107 | and many other operations. In practice, this created a lot of ambiguity 108 | about how it mapped to POSIX semantics, as it doesn't directly correspond 109 | to any feature in POSIX, or in Windows either. 110 | 111 | The other major change from preview1 is the introduction of the mode 112 | argument, which controls the permissions of the generated file. There 113 | was no way to control permissions in preview1, so this is new 114 | functionality. 115 | 116 | #### Streaming read from a file 117 | 118 | TODO 119 | 120 | #### Reading from a directory 121 | 122 | fn read_entries(dir: Descriptor) -> Result<(), Errno> { 123 | // TODO: Implement this example. 124 | } 125 | 126 | [etc. 127 | 128 | ### Detailed design discussion 129 | 130 | #### Should WASI filesystem be case-sensitive, case-insensitive, or platform-dependent? 131 | 132 | Even just among popular platforms, there are case-sensitive and 133 | case-insensitive filesystems in wide use. 134 | 135 | It would be nice to have an API which presented consistent behavior across 136 | platforms, so that applications don't have to worry about subtle differences, 137 | and subtle bugs due to those differences. 138 | 139 | However, implementing case sensitivity on a case-insensitive filesystem, or 140 | case-insensitivity on a case-sensitive filesystem, are both tricky to do. 141 | 142 | One issue is that case insensitivity depends on a Unicode version, so the 143 | details can differ between different case-insensitive platforms. Another 144 | issue is the WASI filesystem in general can't assume it has exclusive access 145 | to the filesystem, so approaches that involve checking for files with names 146 | that differ only by case can race with other processes creating new files. 147 | 148 | ### Considered alternatives 149 | 150 | #### Fully deterministic filesystem 151 | 152 | The main tradeoff with full determinism is that it makes it difficult to access existing filesystems that the Wasm runtime doesn't have full control over. This proposal is aiming to address use cases where users have existing filesystems they want to access. 153 | 154 | ### Stakeholder Interest & Feedback 155 | 156 | TODO before entering Phase 3. 157 | 158 | Preview1 has a similar filesystem API, and it's widely exposed in toolchains. 159 | 160 | ### References & acknowledgements 161 | 162 | Many thanks for valuable feedback and advice from: 163 | 164 | - [Person 1] 165 | - [Person 2] 166 | - [etc.] 167 | -------------------------------------------------------------------------------- /imports.md: -------------------------------------------------------------------------------- 1 |

World imports

2 | 14 |

Import interface wasi:io/error@0.2.5

15 |
16 |

Types

17 |

resource error

18 |

A resource which represents some error information.

19 |

The only method provided by this resource is to-debug-string, 20 | which provides some human-readable information about the error.

21 |

In the wasi:io package, this resource is returned through the 22 | wasi:io/streams/stream-error type.

23 |

To provide more specific error information, other interfaces may 24 | offer functions to "downcast" this error into more specific types. For example, 25 | errors returned from streams derived from filesystem types can be described using 26 | the filesystem's own error-code type. This is done using the function 27 | wasi:filesystem/types/filesystem-error-code, which takes a borrow<error> 28 | parameter and returns an option<wasi:filesystem/types/error-code>.

29 |

The set of functions which can "downcast" an error into a more 30 | concrete type is open.

31 |

Functions

32 |

[method]error.to-debug-string: func

33 |

Returns a string that is suitable to assist humans in debugging 34 | this error.

35 |

WARNING: The returned string should not be consumed mechanically! 36 | It may change across platforms, hosts, or other implementation 37 | details. Parsing this string is a major platform-compatibility 38 | hazard.

39 |
Params
40 | 43 |
Return values
44 | 47 |

Import interface wasi:io/poll@0.2.5

48 |

A poll API intended to let users wait for I/O events on multiple handles 49 | at once.

50 |
51 |

Types

52 |

resource pollable

53 |

pollable represents a single I/O event which may be ready, or not.

54 |

Functions

55 |

[method]pollable.ready: func

56 |

Return the readiness of a pollable. This function never blocks.

57 |

Returns true when the pollable is ready, and false otherwise.

58 |
Params
59 | 62 |
Return values
63 | 66 |

[method]pollable.block: func

67 |

block returns immediately if the pollable is ready, and otherwise 68 | blocks until ready.

69 |

This function is equivalent to calling poll.poll on a list 70 | containing only this pollable.

71 |
Params
72 | 75 |

poll: func

76 |

Poll for completion on a set of pollables.

77 |

This function takes a list of pollables, which identify I/O sources of 78 | interest, and waits until one or more of the events is ready for I/O.

79 |

The result list<u32> contains one or more indices of handles in the 80 | argument list that is ready for I/O.

81 |

This function traps if either:

82 | 86 |

A timeout can be implemented by adding a pollable from the 87 | wasi-clocks API to the list.

88 |

This function does not return a result; polling in itself does not 89 | do any I/O so it doesn't fail. If any of the I/O sources identified by 90 | the pollables has an error, it is indicated by marking the source as 91 | being ready for I/O.

92 |
Params
93 | 96 |
Return values
97 | 100 |

Import interface wasi:io/streams@0.2.5

101 |

WASI I/O is an I/O abstraction API which is currently focused on providing 102 | stream types.

103 |

In the future, the component model is expected to add built-in stream types; 104 | when it does, they are expected to subsume this API.

105 |
106 |

Types

107 |

type error

108 |

error

109 |

110 | #### `type pollable` 111 | [`pollable`](#pollable) 112 |

113 | #### `variant stream-error` 114 |

An error for input-stream and output-stream operations.

115 |
Variant Cases
116 | 131 |

resource input-stream

132 |

An input bytestream.

133 |

input-streams are non-blocking to the extent practical on underlying 134 | platforms. I/O operations always return promptly; if fewer bytes are 135 | promptly available than requested, they return the number of bytes promptly 136 | available, which could even be zero. To wait for data to be available, 137 | use the subscribe function to obtain a pollable which can be polled 138 | for using wasi:io/poll.

139 |

resource output-stream

140 |

An output bytestream.

141 |

output-streams are non-blocking to the extent practical on 142 | underlying platforms. Except where specified otherwise, I/O operations also 143 | always return promptly, after the number of bytes that can be written 144 | promptly, which could even be zero. To wait for the stream to be ready to 145 | accept data, the subscribe function to obtain a pollable which can be 146 | polled for using wasi:io/poll.

147 |

Dropping an output-stream while there's still an active write in 148 | progress may result in the data being lost. Before dropping the stream, 149 | be sure to fully flush your writes.

150 |

Functions

151 |

[method]input-stream.read: func

152 |

Perform a non-blocking read from the stream.

153 |

When the source of a read is binary data, the bytes from the source 154 | are returned verbatim. When the source of a read is known to the 155 | implementation to be text, bytes containing the UTF-8 encoding of the 156 | text are returned.

157 |

This function returns a list of bytes containing the read data, 158 | when successful. The returned list will contain up to len bytes; 159 | it may return fewer than requested, but not more. The list is 160 | empty when no bytes are available for reading at this time. The 161 | pollable given by subscribe will be ready when more bytes are 162 | available.

163 |

This function fails with a stream-error when the operation 164 | encounters an error, giving last-operation-failed, or when the 165 | stream is closed, giving closed.

166 |

When the caller gives a len of 0, it represents a request to 167 | read 0 bytes. If the stream is still open, this call should 168 | succeed and return an empty list, or otherwise fail with closed.

169 |

The len parameter is a u64, which could represent a list of u8 which 170 | is not possible to allocate in wasm32, or not desirable to allocate as 171 | as a return value by the callee. The callee may return a list of bytes 172 | less than len in size while more bytes are available for reading.

173 |
Params
174 | 178 |
Return values
179 | 182 |

[method]input-stream.blocking-read: func

183 |

Read bytes from a stream, after blocking until at least one byte can 184 | be read. Except for blocking, behavior is identical to read.

185 |
Params
186 | 190 |
Return values
191 | 194 |

[method]input-stream.skip: func

195 |

Skip bytes from a stream. Returns number of bytes skipped.

196 |

Behaves identical to read, except instead of returning a list 197 | of bytes, returns the number of bytes consumed from the stream.

198 |
Params
199 | 203 |
Return values
204 | 207 |

[method]input-stream.blocking-skip: func

208 |

Skip bytes from a stream, after blocking until at least one byte 209 | can be skipped. Except for blocking behavior, identical to skip.

210 |
Params
211 | 215 |
Return values
216 | 219 |

[method]input-stream.subscribe: func

220 |

Create a pollable which will resolve once either the specified stream 221 | has bytes available to read or the other end of the stream has been 222 | closed. 223 | The created pollable is a child resource of the input-stream. 224 | Implementations may trap if the input-stream is dropped before 225 | all derived pollables created with this function are dropped.

226 |
Params
227 | 230 |
Return values
231 | 234 |

[method]output-stream.check-write: func

235 |

Check readiness for writing. This function never blocks.

236 |

Returns the number of bytes permitted for the next call to write, 237 | or an error. Calling write with more bytes than this function has 238 | permitted will trap.

239 |

When this function returns 0 bytes, the subscribe pollable will 240 | become ready when this function will report at least 1 byte, or an 241 | error.

242 |
Params
243 | 246 |
Return values
247 | 250 |

[method]output-stream.write: func

251 |

Perform a write. This function never blocks.

252 |

When the destination of a write is binary data, the bytes from 253 | contents are written verbatim. When the destination of a write is 254 | known to the implementation to be text, the bytes of contents are 255 | transcoded from UTF-8 into the encoding of the destination and then 256 | written.

257 |

Precondition: check-write gave permit of Ok(n) and contents has a 258 | length of less than or equal to n. Otherwise, this function will trap.

259 |

returns Err(closed) without writing if the stream has closed since 260 | the last call to check-write provided a permit.

261 |
Params
262 | 266 |
Return values
267 | 270 |

[method]output-stream.blocking-write-and-flush: func

271 |

Perform a write of up to 4096 bytes, and then flush the stream. Block 272 | until all of these operations are complete, or an error occurs.

273 |

This is a convenience wrapper around the use of check-write, 274 | subscribe, write, and flush, and is implemented with the 275 | following pseudo-code:

276 |
let pollable = this.subscribe();
 277 | while !contents.is_empty() {
 278 |   // Wait for the stream to become writable
 279 |   pollable.block();
 280 |   let Ok(n) = this.check-write(); // eliding error handling
 281 |   let len = min(n, contents.len());
 282 |   let (chunk, rest) = contents.split_at(len);
 283 |   this.write(chunk  );            // eliding error handling
 284 |   contents = rest;
 285 | }
 286 | this.flush();
 287 | // Wait for completion of `flush`
 288 | pollable.block();
 289 | // Check for any errors that arose during `flush`
 290 | let _ = this.check-write();         // eliding error handling
 291 | 
292 |
Params
293 | 297 |
Return values
298 | 301 |

[method]output-stream.flush: func

302 |

Request to flush buffered output. This function never blocks.

303 |

This tells the output-stream that the caller intends any buffered 304 | output to be flushed. the output which is expected to be flushed 305 | is all that has been passed to write prior to this call.

306 |

Upon calling this function, the output-stream will not accept any 307 | writes (check-write will return ok(0)) until the flush has 308 | completed. The subscribe pollable will become ready when the 309 | flush has completed and the stream can accept more writes.

310 |
Params
311 | 314 |
Return values
315 | 318 |

[method]output-stream.blocking-flush: func

319 |

Request to flush buffered output, and block until flush completes 320 | and stream is ready for writing again.

321 |
Params
322 | 325 |
Return values
326 | 329 |

[method]output-stream.subscribe: func

330 |

Create a pollable which will resolve once the output-stream 331 | is ready for more writing, or an error has occurred. When this 332 | pollable is ready, check-write will return ok(n) with n>0, or an 333 | error.

334 |

If the stream is closed, this pollable is always ready immediately.

335 |

The created pollable is a child resource of the output-stream. 336 | Implementations may trap if the output-stream is dropped before 337 | all derived pollables created with this function are dropped.

338 |
Params
339 | 342 |
Return values
343 | 346 |

[method]output-stream.write-zeroes: func

347 |

Write zeroes to a stream.

348 |

This should be used precisely like write with the exact same 349 | preconditions (must use check-write first), but instead of 350 | passing a list of bytes, you simply pass the number of zero-bytes 351 | that should be written.

352 |
Params
353 | 357 |
Return values
358 | 361 |

[method]output-stream.blocking-write-zeroes-and-flush: func

362 |

Perform a write of up to 4096 zeroes, and then flush the stream. 363 | Block until all of these operations are complete, or an error 364 | occurs.

365 |

This is a convenience wrapper around the use of check-write, 366 | subscribe, write-zeroes, and flush, and is implemented with 367 | the following pseudo-code:

368 |
let pollable = this.subscribe();
 369 | while num_zeroes != 0 {
 370 |   // Wait for the stream to become writable
 371 |   pollable.block();
 372 |   let Ok(n) = this.check-write(); // eliding error handling
 373 |   let len = min(n, num_zeroes);
 374 |   this.write-zeroes(len);         // eliding error handling
 375 |   num_zeroes -= len;
 376 | }
 377 | this.flush();
 378 | // Wait for completion of `flush`
 379 | pollable.block();
 380 | // Check for any errors that arose during `flush`
 381 | let _ = this.check-write();         // eliding error handling
 382 | 
383 |
Params
384 | 388 |
Return values
389 | 392 |

[method]output-stream.splice: func

393 |

Read from one stream and write to another.

394 |

The behavior of splice is equivalent to:

395 |
    396 |
  1. calling check-write on the output-stream
  2. 397 |
  3. calling read on the input-stream with the smaller of the 398 | check-write permitted length and the len provided to splice
  4. 399 |
  5. calling write on the output-stream with that read data.
  6. 400 |
401 |

Any error reported by the call to check-write, read, or 402 | write ends the splice and reports that error.

403 |

This function returns the number of bytes transferred; it may be less 404 | than len.

405 |
Params
406 | 411 |
Return values
412 | 415 |

[method]output-stream.blocking-splice: func

416 |

Read from one stream and write to another, with blocking.

417 |

This is similar to splice, except that it blocks until the 418 | output-stream is ready for writing, and the input-stream 419 | is ready for reading, before performing the splice.

420 |
Params
421 | 426 |
Return values
427 | 430 |

Import interface wasi:clocks/wall-clock@0.2.5

431 |

WASI Wall Clock is a clock API intended to let users query the current 432 | time. The name "wall" makes an analogy to a "clock on the wall", which 433 | is not necessarily monotonic as it may be reset.

434 |

It is intended to be portable at least between Unix-family platforms and 435 | Windows.

436 |

A wall clock is a clock which measures the date and time according to 437 | some external reference.

438 |

External references may be reset, so this clock is not necessarily 439 | monotonic, making it unsuitable for measuring elapsed time.

440 |

It is intended for reporting the current date and time for humans.

441 |
442 |

Types

443 |

record datetime

444 |

A time and date in seconds plus nanoseconds.

445 |
Record Fields
446 | 450 |
451 |

Functions

452 |

now: func

453 |

Read the current value of the clock.

454 |

This clock is not monotonic, therefore calling this function repeatedly 455 | will not necessarily produce a sequence of non-decreasing values.

456 |

The returned timestamps represent the number of seconds since 457 | 1970-01-01T00:00:00Z, also known as POSIX's Seconds Since the Epoch, 458 | also known as Unix Time.

459 |

The nanoseconds field of the output is always less than 1000000000.

460 |
Return values
461 | 464 |

resolution: func

465 |

Query the resolution of the clock.

466 |

The nanoseconds field of the output is always less than 1000000000.

467 |
Return values
468 | 471 |

Import interface wasi:filesystem/types@0.2.5

472 |

WASI filesystem is a filesystem API primarily intended to let users run WASI 473 | programs that access their files on their existing filesystems, without 474 | significant overhead.

475 |

It is intended to be roughly portable between Unix-family platforms and 476 | Windows, though it does not hide many of the major differences.

477 |

Paths are passed as interface-type strings, meaning they must consist of 478 | a sequence of Unicode Scalar Values (USVs). Some filesystems may contain 479 | paths which are not accessible by this API.

480 |

The directory separator in WASI is always the forward-slash (/).

481 |

All paths in WASI are relative paths, and are interpreted relative to a 482 | descriptor referring to a base directory. If a path argument to any WASI 483 | function starts with /, or if any step of resolving a path, including 484 | .. and symbolic link steps, reaches a directory outside of the base 485 | directory, or reaches a symlink to an absolute or rooted path in the 486 | underlying filesystem, the function fails with error-code::not-permitted.

487 |

For more information about WASI path resolution and sandboxing, see 488 | WASI filesystem path resolution.

489 |
490 |

Types

491 |

type input-stream

492 |

input-stream

493 |

494 | #### `type output-stream` 495 | [`output-stream`](#output_stream) 496 |

497 | #### `type error` 498 | [`error`](#error) 499 |

500 | #### `type datetime` 501 | [`datetime`](#datetime) 502 |

503 | #### `type filesize` 504 | `u64` 505 |

File size or length of a region within a file. 506 |

enum descriptor-type

507 |

The type of a filesystem object referenced by a descriptor.

508 |

Note: This was called filetype in earlier versions of WASI.

509 |
Enum Cases
510 | 545 |

flags descriptor-flags

546 |

Descriptor flags.

547 |

Note: This was called fdflags in earlier versions of WASI.

548 |
Flags members
549 | 595 |

flags path-flags

596 |

Flags determining the method of how paths are resolved.

597 |
Flags members
598 | 603 |

flags open-flags

604 |

Open flags used by open-at.

605 |
Flags members
606 | 624 |

type link-count

625 |

u64

626 |

Number of hard links to an inode. 627 |

record descriptor-stat

628 |

File attributes.

629 |

Note: This was called filestat in earlier versions of WASI.

630 |
Record Fields
631 | 664 |

variant new-timestamp

665 |

When setting a timestamp, this gives the value to set it to.

666 |
Variant Cases
667 | 682 |

record directory-entry

683 |

A directory entry.

684 |
Record Fields
685 | 695 |

enum error-code

696 |

Error codes returned by functions, similar to errno in POSIX. 697 | Not all of these error codes are returned by the functions provided by this 698 | API; some are used in higher-level library layers, and others are provided 699 | merely for alignment with POSIX.

700 |
Enum Cases
701 | 851 |

enum advice

852 |

File or memory access pattern advisory information.

853 |
Enum Cases
854 | 886 |

record metadata-hash-value

887 |

A 128-bit hash value, split into parts because wasm doesn't have a 888 | 128-bit integer type.

889 |
Record Fields
890 | 900 |

resource descriptor

901 |

A descriptor is a reference to a filesystem object, which may be a file, 902 | directory, named pipe, special file, or other object on which filesystem 903 | calls may be made.

904 |

resource directory-entry-stream

905 |

A stream of directory entries.

906 |

Functions

907 |

[method]descriptor.read-via-stream: func

908 |

Return a stream for reading from a file, if available.

909 |

May fail with an error-code describing why the file cannot be read.

910 |

Multiple read, write, and append streams may be active on the same open 911 | file and they do not interfere with each other.

912 |

Note: This allows using read-stream, which is similar to read in POSIX.

913 |
Params
914 | 918 |
Return values
919 | 922 |

[method]descriptor.write-via-stream: func

923 |

Return a stream for writing to a file, if available.

924 |

May fail with an error-code describing why the file cannot be written.

925 |

Note: This allows using write-stream, which is similar to write in 926 | POSIX.

927 |
Params
928 | 932 |
Return values
933 | 936 |

[method]descriptor.append-via-stream: func

937 |

Return a stream for appending to a file, if available.

938 |

May fail with an error-code describing why the file cannot be appended.

939 |

Note: This allows using write-stream, which is similar to write with 940 | O_APPEND in POSIX.

941 |
Params
942 | 945 |
Return values
946 | 949 |

[method]descriptor.advise: func

950 |

Provide file advisory information on a descriptor.

951 |

This is similar to posix_fadvise in POSIX.

952 |
Params
953 | 959 |
Return values
960 | 963 |

[method]descriptor.sync-data: func

964 |

Synchronize the data of a file to disk.

965 |

This function succeeds with no effect if the file descriptor is not 966 | opened for writing.

967 |

Note: This is similar to fdatasync in POSIX.

968 |
Params
969 | 972 |
Return values
973 | 976 |

[method]descriptor.get-flags: func

977 |

Get flags associated with a descriptor.

978 |

Note: This returns similar flags to fcntl(fd, F_GETFL) in POSIX.

979 |

Note: This returns the value that was the fs_flags value returned 980 | from fdstat_get in earlier versions of WASI.

981 |
Params
982 | 985 |
Return values
986 | 989 |

[method]descriptor.get-type: func

990 |

Get the dynamic type of a descriptor.

991 |

Note: This returns the same value as the type field of the fd-stat 992 | returned by stat, stat-at and similar.

993 |

Note: This returns similar flags to the st_mode & S_IFMT value provided 994 | by fstat in POSIX.

995 |

Note: This returns the value that was the fs_filetype value returned 996 | from fdstat_get in earlier versions of WASI.

997 |
Params
998 | 1001 |
Return values
1002 | 1005 |

[method]descriptor.set-size: func

1006 |

Adjust the size of an open file. If this increases the file's size, the 1007 | extra bytes are filled with zeros.

1008 |

Note: This was called fd_filestat_set_size in earlier versions of WASI.

1009 |
Params
1010 | 1014 |
Return values
1015 | 1018 |

[method]descriptor.set-times: func

1019 |

Adjust the timestamps of an open file or directory.

1020 |

Note: This is similar to futimens in POSIX.

1021 |

Note: This was called fd_filestat_set_times in earlier versions of WASI.

1022 |
Params
1023 | 1028 |
Return values
1029 | 1032 |

[method]descriptor.read: func

1033 |

Read from a descriptor, without using and updating the descriptor's offset.

1034 |

This function returns a list of bytes containing the data that was 1035 | read, along with a bool which, when true, indicates that the end of the 1036 | file was reached. The returned list will contain up to length bytes; it 1037 | may return fewer than requested, if the end of the file is reached or 1038 | if the I/O operation is interrupted.

1039 |

In the future, this may change to return a stream<u8, error-code>.

1040 |

Note: This is similar to pread in POSIX.

1041 |
Params
1042 | 1047 |
Return values
1048 | 1051 |

[method]descriptor.write: func

1052 |

Write to a descriptor, without using and updating the descriptor's offset.

1053 |

It is valid to write past the end of a file; the file is extended to the 1054 | extent of the write, with bytes between the previous end and the start of 1055 | the write set to zero.

1056 |

In the future, this may change to take a stream<u8, error-code>.

1057 |

Note: This is similar to pwrite in POSIX.

1058 |
Params
1059 | 1064 |
Return values
1065 | 1068 |

[method]descriptor.read-directory: func

1069 |

Read directory entries from a directory.

1070 |

On filesystems where directories contain entries referring to themselves 1071 | and their parents, often named . and .. respectively, these entries 1072 | are omitted.

1073 |

This always returns a new stream which starts at the beginning of the 1074 | directory. Multiple streams may be active on the same directory, and they 1075 | do not interfere with each other.

1076 |
Params
1077 | 1080 |
Return values
1081 | 1084 |

[method]descriptor.sync: func

1085 |

Synchronize the data and metadata of a file to disk.

1086 |

This function succeeds with no effect if the file descriptor is not 1087 | opened for writing.

1088 |

Note: This is similar to fsync in POSIX.

1089 |
Params
1090 | 1093 |
Return values
1094 | 1097 |

[method]descriptor.create-directory-at: func

1098 |

Create a directory.

1099 |

Note: This is similar to mkdirat in POSIX.

1100 |
Params
1101 | 1105 |
Return values
1106 | 1109 |

[method]descriptor.stat: func

1110 |

Return the attributes of an open file or directory.

1111 |

Note: This is similar to fstat in POSIX, except that it does not return 1112 | device and inode information. For testing whether two descriptors refer to 1113 | the same underlying filesystem object, use is-same-object. To obtain 1114 | additional data that can be used do determine whether a file has been 1115 | modified, use metadata-hash.

1116 |

Note: This was called fd_filestat_get in earlier versions of WASI.

1117 |
Params
1118 | 1121 |
Return values
1122 | 1125 |

[method]descriptor.stat-at: func

1126 |

Return the attributes of a file or directory.

1127 |

Note: This is similar to fstatat in POSIX, except that it does not 1128 | return device and inode information. See the stat description for a 1129 | discussion of alternatives.

1130 |

Note: This was called path_filestat_get in earlier versions of WASI.

1131 |
Params
1132 | 1137 |
Return values
1138 | 1141 |

[method]descriptor.set-times-at: func

1142 |

Adjust the timestamps of a file or directory.

1143 |

Note: This is similar to utimensat in POSIX.

1144 |

Note: This was called path_filestat_set_times in earlier versions of 1145 | WASI.

1146 |
Params
1147 | 1154 |
Return values
1155 | 1158 |

[method]descriptor.link-at: func

1159 |

Create a hard link.

1160 |

Fails with error-code::no-entry if the old path does not exist, 1161 | with error-code::exist if the new path already exists, and 1162 | error-code::not-permitted if the old path is not a file.

1163 |

Note: This is similar to linkat in POSIX.

1164 |
Params
1165 | 1172 |
Return values
1173 | 1176 |

[method]descriptor.open-at: func

1177 |

Open a file or directory.

1178 |

If flags contains descriptor-flags::mutate-directory, and the base 1179 | descriptor doesn't have descriptor-flags::mutate-directory set, 1180 | open-at fails with error-code::read-only.

1181 |

If flags contains write or mutate-directory, or open-flags 1182 | contains truncate or create, and the base descriptor doesn't have 1183 | descriptor-flags::mutate-directory set, open-at fails with 1184 | error-code::read-only.

1185 |

Note: This is similar to openat in POSIX.

1186 |
Params
1187 | 1194 |
Return values
1195 | 1198 |

[method]descriptor.readlink-at: func

1199 |

Read the contents of a symbolic link.

1200 |

If the contents contain an absolute or rooted path in the underlying 1201 | filesystem, this function fails with error-code::not-permitted.

1202 |

Note: This is similar to readlinkat in POSIX.

1203 |
Params
1204 | 1208 |
Return values
1209 | 1212 |

[method]descriptor.remove-directory-at: func

1213 |

Remove a directory.

1214 |

Return error-code::not-empty if the directory is not empty.

1215 |

Note: This is similar to unlinkat(fd, path, AT_REMOVEDIR) in POSIX.

1216 |
Params
1217 | 1221 |
Return values
1222 | 1225 |

[method]descriptor.rename-at: func

1226 |

Rename a filesystem object.

1227 |

Note: This is similar to renameat in POSIX.

1228 |
Params
1229 | 1235 |
Return values
1236 | 1239 |

[method]descriptor.symlink-at: func

1240 |

Create a symbolic link (also known as a "symlink").

1241 |

If old-path starts with /, the function fails with 1242 | error-code::not-permitted.

1243 |

Note: This is similar to symlinkat in POSIX.

1244 |
Params
1245 | 1250 |
Return values
1251 | 1254 |

[method]descriptor.unlink-file-at: func

1255 |

Unlink a filesystem object that is not a directory.

1256 |

Return error-code::is-directory if the path refers to a directory. 1257 | Note: This is similar to unlinkat(fd, path, 0) in POSIX.

1258 |
Params
1259 | 1263 |
Return values
1264 | 1267 |

[method]descriptor.is-same-object: func

1268 |

Test whether two descriptors refer to the same filesystem object.

1269 |

In POSIX, this corresponds to testing whether the two descriptors have the 1270 | same device (st_dev) and inode (st_ino or d_ino) numbers. 1271 | wasi-filesystem does not expose device and inode numbers, so this function 1272 | may be used instead.

1273 |
Params
1274 | 1278 |
Return values
1279 | 1282 |

[method]descriptor.metadata-hash: func

1283 |

Return a hash of the metadata associated with a filesystem object referred 1284 | to by a descriptor.

1285 |

This returns a hash of the last-modification timestamp and file size, and 1286 | may also include the inode number, device number, birth timestamp, and 1287 | other metadata fields that may change when the file is modified or 1288 | replaced. It may also include a secret value chosen by the 1289 | implementation and not otherwise exposed.

1290 |

Implementations are encouraged to provide the following properties:

1291 | 1299 |

However, none of these is required.

1300 |
Params
1301 | 1304 |
Return values
1305 | 1308 |

[method]descriptor.metadata-hash-at: func

1309 |

Return a hash of the metadata associated with a filesystem object referred 1310 | to by a directory descriptor and a relative path.

1311 |

This performs the same hash computation as metadata-hash.

1312 |
Params
1313 | 1318 |
Return values
1319 | 1322 |

[method]directory-entry-stream.read-directory-entry: func

1323 |

Read a single directory entry from a directory-entry-stream.

1324 |
Params
1325 | 1328 |
Return values
1329 | 1332 |

filesystem-error-code: func

1333 |

Attempts to extract a filesystem-related error-code from the stream 1334 | error provided.

1335 |

Stream operations which return stream-error::last-operation-failed 1336 | have a payload with more information about the operation that failed. 1337 | This payload can be passed through to this function to see if there's 1338 | filesystem-related information about the error to return.

1339 |

Note that this function is fallible because not all stream-related 1340 | errors are filesystem-related errors.

1341 |
Params
1342 | 1345 |
Return values
1346 | 1349 |

Import interface wasi:filesystem/preopens@0.2.5

1350 |
1351 |

Types

1352 |

type descriptor

1353 |

descriptor

1354 |

1355 | ---- 1356 |

Functions

1357 |

get-directories: func

1358 |

Return the set of preopened directories, and their paths.

1359 |
Return values
1360 | 1363 | -------------------------------------------------------------------------------- /path-resolution.md: -------------------------------------------------------------------------------- 1 | # WASI filesystem path resolution 2 | 3 | wasi-filesystem uses a filesystem path sandboxing scheme modeled after the 4 | system used in [CloudABI], which is also similar to the system used in 5 | [Capsicum]. 6 | 7 | On Linux, it corresponds to the `RESOLVE_BENEATH` behavior in 8 | [Linux's `openat2`]. In FreeBSD, it corresponds to the `O_RESOLVE_BENEATH` 9 | behavior in [FreeBSD's `open`]. However, path resolution can also be 10 | implemented manually using `openat` and `readlinkat` or similar primitives. 11 | 12 | ## Sandboxing overview 13 | 14 | All functions in wasi-filesystem which operate on filesystem paths take 15 | a pair of values: a base directory handle, and a relative path. Absolute 16 | paths are not permitted, and there is no global namespace. All path 17 | accesses are relative to a base directory handle. 18 | 19 | Path resolution is constrained to occur within the sub-filesystem referenced 20 | by the base handle. Information about the filesystem outside of the base 21 | directory handles is not visible. In particular, it's not permitted to use 22 | paths that temporarily step outside the sandbox with something like 23 | "../../../stuff/here", even if the final resolved path is back inside the 24 | sandbox, because that would leak information about the existence of 25 | directories outside the sandbox. 26 | 27 | Importantly, the sandboxing is designed to be implementable even in the presence 28 | of outside processes accessing the same filesystem, including renaming, 29 | unlinking, and creating new files and directories. 30 | 31 | ## Symlinks 32 | 33 | Creating a symlink with an absolute path string fails with a "not permitted" 34 | error. 35 | 36 | Other than that, symlinks may be created with any string, provided the 37 | underlying filesystem implementation supports it. 38 | 39 | Sandboxing for symlink strings is performed at the time of an access, when a 40 | path is being resolved, and not at the time that the symlink is created or 41 | moved. This ensures that the sandbox is respected even if there are symlinks 42 | created or renamed by other entities with access to the filesystem. 43 | 44 | ## Host Implementation 45 | 46 | ### Implementing path resolution manually 47 | 48 | Plain `openat` doesn't perform any sandboxing; it will readily open paths 49 | containing ".." or starting with "/", or symlinks to paths containing ".." 50 | or starting with "/". It has an `O_NOFOLLOW` flag, however this flag only 51 | applies to the last component of the path (eg. the "c" in "a/b/c"). So 52 | the strategy for using `openat` to implement sandboxing is to split paths 53 | into components (eg. "a", "b", "c") and open them one component at a time, 54 | so that each component can be opened with `O_NOFOLLOW`. 55 | 56 | If the `openat` call fails, and the OS error code indicates that it *was* 57 | a symlink (eg. `ELOOP`), then call `readlinkat` to read the link contents, 58 | split the contents into components, and prepend these new components to the 59 | component list. If it starts with an absolute path, that's an attempt to 60 | jump outside the sandbox, so path resolution should fail with an 61 | "access denied" error message. 62 | 63 | If a path component is "..", instead of opening it, pop an item off of the 64 | component list. If the list was empty, that represents an attempt to use 65 | ".." to step outside the sandbox, so path resolution should fail with an 66 | "access denied" error message. 67 | 68 | ### Implementation notes 69 | 70 | On Linux, `openat2` with `RESOLVE_BENEATH` may be used as an optimization to 71 | implement many system calls other than just "open" by utilizing Linux's 72 | `O_PATH` and "/proc/self/fd" features. 73 | 74 | On Windows, the [`NtCreateFile`] function can accept a directory handle and 75 | can behave like an `openat` function, which can be used in the 76 | [manual algorithm](implementing-path-resolution-manually). 77 | 78 | The Rust library [cap-std] implements WASI's filesystem sandboxing semantics, 79 | but is otherwise independent of WASI or Wasm, so it can be reused in other 80 | settings. It uses `openat2` and `NtCreateFile` and other optimizations. 81 | 82 | cloudabi-utils has an [implementation of the manual technique in C], though 83 | that repository is no longer maintained. 84 | 85 | [implementation of the manual technique in C]: https://github.com/NuxiNL/cloudabi-utils/blob/master/src/libemulator/posix.c#L1205 86 | [cap-std]: https://github.com/bytecodealliance/cap-std 87 | [Linux's `openat2`]: https://man7.org/linux/man-pages/man2/openat2.2.html 88 | [CloudABI]: https://github.com/NuxiNL/cloudabi 89 | [Capsicum]: https://wiki.freebsd.org/Capsicum 90 | [FreeBSD's `open`]: https://man.freebsd.org/cgi/man.cgi?sektion=2&query=open 91 | [`NtCreateFile`]: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile 92 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Testing guidelines 2 | 3 | TK fill in testing guidelines 4 | 5 | ## Installing the tools 6 | 7 | TK fill in instructions 8 | 9 | ## Running the tests 10 | 11 | TK fill in instructions 12 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps.lock: -------------------------------------------------------------------------------- 1 | [clocks] 2 | url = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz" 3 | subdir = "wit-0.3.0-draft" 4 | sha256 = "26e315db0d371495f8834edfc0e479042f94152ce677d96d54d3623d0e4ffb1e" 5 | sha512 = "e1c76f499435841316f9287b88d8173558e64f277c321ff390556de8707a0b18dd6c1749bbb17bbbba8d523da246ef6eb05c990ceddb762e03efb2ae30cacc76" 6 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps.toml: -------------------------------------------------------------------------------- 1 | clocks = { url = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz", subdir = "wit-0.3.0-draft" } 2 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/monotonic-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 2 | /// WASI Monotonic Clock is a clock API intended to let users measure elapsed 3 | /// time. 4 | /// 5 | /// It is intended to be portable at least between Unix-family platforms and 6 | /// Windows. 7 | /// 8 | /// A monotonic clock is a clock which has an unspecified initial value, and 9 | /// successive reads of the clock will produce non-decreasing values. 10 | @since(version = 0.3.0) 11 | interface monotonic-clock { 12 | /// An instant in time, in nanoseconds. An instant is relative to an 13 | /// unspecified initial value, and can only be compared to instances from 14 | /// the same monotonic-clock. 15 | @since(version = 0.3.0) 16 | type instant = u64; 17 | 18 | /// A duration of time, in nanoseconds. 19 | @since(version = 0.3.0) 20 | type duration = u64; 21 | 22 | /// Read the current value of the clock. 23 | /// 24 | /// The clock is monotonic, therefore calling this function repeatedly will 25 | /// produce a sequence of non-decreasing values. 26 | @since(version = 0.3.0) 27 | now: func() -> instant; 28 | 29 | /// Query the resolution of the clock. Returns the duration of time 30 | /// corresponding to a clock tick. 31 | @since(version = 0.3.0) 32 | resolution: func() -> duration; 33 | 34 | /// Wait until the specified instant has occurred. 35 | @since(version = 0.3.0) 36 | wait-until: func( 37 | when: instant, 38 | ); 39 | 40 | /// Wait for the specified duration has elapsed. 41 | @since(version = 0.3.0) 42 | wait-for: func( 43 | how-long: duration, 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/timezone.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 2 | 3 | @unstable(feature = clocks-timezone) 4 | interface timezone { 5 | @unstable(feature = clocks-timezone) 6 | use wall-clock.{datetime}; 7 | 8 | /// Return information needed to display the given `datetime`. This includes 9 | /// the UTC offset, the time zone name, and a flag indicating whether 10 | /// daylight saving time is active. 11 | /// 12 | /// If the timezone cannot be determined for the given `datetime`, return a 13 | /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight 14 | /// saving time. 15 | @unstable(feature = clocks-timezone) 16 | display: func(when: datetime) -> timezone-display; 17 | 18 | /// The same as `display`, but only return the UTC offset. 19 | @unstable(feature = clocks-timezone) 20 | utc-offset: func(when: datetime) -> s32; 21 | 22 | /// Information useful for displaying the timezone of a specific `datetime`. 23 | /// 24 | /// This information may vary within a single `timezone` to reflect daylight 25 | /// saving time adjustments. 26 | @unstable(feature = clocks-timezone) 27 | record timezone-display { 28 | /// The number of seconds difference between UTC time and the local 29 | /// time of the timezone. 30 | /// 31 | /// The returned value will always be less than 86400 which is the 32 | /// number of seconds in a day (24*60*60). 33 | /// 34 | /// In implementations that do not expose an actual time zone, this 35 | /// should return 0. 36 | utc-offset: s32, 37 | 38 | /// The abbreviated name of the timezone to display to a user. The name 39 | /// `UTC` indicates Coordinated Universal Time. Otherwise, this should 40 | /// reference local standards for the name of the time zone. 41 | /// 42 | /// In implementations that do not expose an actual time zone, this 43 | /// should be the string `UTC`. 44 | /// 45 | /// In time zones that do not have an applicable name, a formatted 46 | /// representation of the UTC offset may be returned, such as `-04:00`. 47 | name: string, 48 | 49 | /// Whether daylight saving time is active. 50 | /// 51 | /// In implementations that do not expose an actual time zone, this 52 | /// should return false. 53 | in-daylight-saving-time: bool, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/wall-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 2 | /// WASI Wall Clock is a clock API intended to let users query the current 3 | /// time. The name "wall" makes an analogy to a "clock on the wall", which 4 | /// is not necessarily monotonic as it may be reset. 5 | /// 6 | /// It is intended to be portable at least between Unix-family platforms and 7 | /// Windows. 8 | /// 9 | /// A wall clock is a clock which measures the date and time according to 10 | /// some external reference. 11 | /// 12 | /// External references may be reset, so this clock is not necessarily 13 | /// monotonic, making it unsuitable for measuring elapsed time. 14 | /// 15 | /// It is intended for reporting the current date and time for humans. 16 | @since(version = 0.3.0) 17 | interface wall-clock { 18 | /// A time and date in seconds plus nanoseconds. 19 | @since(version = 0.3.0) 20 | record datetime { 21 | seconds: u64, 22 | nanoseconds: u32, 23 | } 24 | 25 | /// Read the current value of the clock. 26 | /// 27 | /// This clock is not monotonic, therefore calling this function repeatedly 28 | /// will not necessarily produce a sequence of non-decreasing values. 29 | /// 30 | /// The returned timestamps represent the number of seconds since 31 | /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], 32 | /// also known as [Unix Time]. 33 | /// 34 | /// The nanoseconds field of the output is always less than 1000000000. 35 | /// 36 | /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 37 | /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time 38 | @since(version = 0.3.0) 39 | now: func() -> datetime; 40 | 41 | /// Query the resolution of the clock. 42 | /// 43 | /// The nanoseconds field of the output is always less than 1000000000. 44 | @since(version = 0.3.0) 45 | resolution: func() -> datetime; 46 | } 47 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/deps/clocks/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import monotonic-clock; 7 | @since(version = 0.3.0) 8 | import wall-clock; 9 | @unstable(feature = clocks-timezone) 10 | import timezone; 11 | } 12 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/preopens.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | interface preopens { 5 | @since(version = 0.3.0) 6 | use types.{descriptor}; 7 | 8 | /// Return the set of preopened directories, and their paths. 9 | @since(version = 0.3.0) 10 | get-directories: func() -> list>; 11 | } 12 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/types.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | /// WASI filesystem is a filesystem API primarily intended to let users run WASI 3 | /// programs that access their files on their existing filesystems, without 4 | /// significant overhead. 5 | /// 6 | /// It is intended to be roughly portable between Unix-family platforms and 7 | /// Windows, though it does not hide many of the major differences. 8 | /// 9 | /// Paths are passed as interface-type `string`s, meaning they must consist of 10 | /// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain 11 | /// paths which are not accessible by this API. 12 | /// 13 | /// The directory separator in WASI is always the forward-slash (`/`). 14 | /// 15 | /// All paths in WASI are relative paths, and are interpreted relative to a 16 | /// `descriptor` referring to a base directory. If a `path` argument to any WASI 17 | /// function starts with `/`, or if any step of resolving a `path`, including 18 | /// `..` and symbolic link steps, reaches a directory outside of the base 19 | /// directory, or reaches a symlink to an absolute or rooted path in the 20 | /// underlying filesystem, the function fails with `error-code::not-permitted`. 21 | /// 22 | /// For more information about WASI path resolution and sandboxing, see 23 | /// [WASI filesystem path resolution]. 24 | /// 25 | /// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md 26 | @since(version = 0.3.0) 27 | interface types { 28 | @since(version = 0.3.0) 29 | use wasi:clocks/wall-clock@0.3.0.{datetime}; 30 | 31 | /// File size or length of a region within a file. 32 | @since(version = 0.3.0) 33 | type filesize = u64; 34 | 35 | /// The type of a filesystem object referenced by a descriptor. 36 | /// 37 | /// Note: This was called `filetype` in earlier versions of WASI. 38 | @since(version = 0.3.0) 39 | enum descriptor-type { 40 | /// The type of the descriptor or file is unknown or is different from 41 | /// any of the other types specified. 42 | unknown, 43 | /// The descriptor refers to a block device inode. 44 | block-device, 45 | /// The descriptor refers to a character device inode. 46 | character-device, 47 | /// The descriptor refers to a directory inode. 48 | directory, 49 | /// The descriptor refers to a named pipe. 50 | fifo, 51 | /// The file refers to a symbolic link inode. 52 | symbolic-link, 53 | /// The descriptor refers to a regular file inode. 54 | regular-file, 55 | /// The descriptor refers to a socket. 56 | socket, 57 | } 58 | 59 | /// Descriptor flags. 60 | /// 61 | /// Note: This was called `fdflags` in earlier versions of WASI. 62 | @since(version = 0.3.0) 63 | flags descriptor-flags { 64 | /// Read mode: Data can be read. 65 | read, 66 | /// Write mode: Data can be written to. 67 | write, 68 | /// Request that writes be performed according to synchronized I/O file 69 | /// integrity completion. The data stored in the file and the file's 70 | /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. 71 | /// 72 | /// The precise semantics of this operation have not yet been defined for 73 | /// WASI. At this time, it should be interpreted as a request, and not a 74 | /// requirement. 75 | file-integrity-sync, 76 | /// Request that writes be performed according to synchronized I/O data 77 | /// integrity completion. Only the data stored in the file is 78 | /// synchronized. This is similar to `O_DSYNC` in POSIX. 79 | /// 80 | /// The precise semantics of this operation have not yet been defined for 81 | /// WASI. At this time, it should be interpreted as a request, and not a 82 | /// requirement. 83 | data-integrity-sync, 84 | /// Requests that reads be performed at the same level of integrity 85 | /// requested for writes. This is similar to `O_RSYNC` in POSIX. 86 | /// 87 | /// The precise semantics of this operation have not yet been defined for 88 | /// WASI. At this time, it should be interpreted as a request, and not a 89 | /// requirement. 90 | requested-write-sync, 91 | /// Mutating directories mode: Directory contents may be mutated. 92 | /// 93 | /// When this flag is unset on a descriptor, operations using the 94 | /// descriptor which would create, rename, delete, modify the data or 95 | /// metadata of filesystem objects, or obtain another handle which 96 | /// would permit any of those, shall fail with `error-code::read-only` if 97 | /// they would otherwise succeed. 98 | /// 99 | /// This may only be set on directories. 100 | mutate-directory, 101 | } 102 | 103 | /// File attributes. 104 | /// 105 | /// Note: This was called `filestat` in earlier versions of WASI. 106 | @since(version = 0.3.0) 107 | record descriptor-stat { 108 | /// File type. 109 | %type: descriptor-type, 110 | /// Number of hard links to the file. 111 | link-count: link-count, 112 | /// For regular files, the file size in bytes. For symbolic links, the 113 | /// length in bytes of the pathname contained in the symbolic link. 114 | size: filesize, 115 | /// Last data access timestamp. 116 | /// 117 | /// If the `option` is none, the platform doesn't maintain an access 118 | /// timestamp for this file. 119 | data-access-timestamp: option, 120 | /// Last data modification timestamp. 121 | /// 122 | /// If the `option` is none, the platform doesn't maintain a 123 | /// modification timestamp for this file. 124 | data-modification-timestamp: option, 125 | /// Last file status-change timestamp. 126 | /// 127 | /// If the `option` is none, the platform doesn't maintain a 128 | /// status-change timestamp for this file. 129 | status-change-timestamp: option, 130 | } 131 | 132 | /// Flags determining the method of how paths are resolved. 133 | @since(version = 0.3.0) 134 | flags path-flags { 135 | /// As long as the resolved path corresponds to a symbolic link, it is 136 | /// expanded. 137 | symlink-follow, 138 | } 139 | 140 | /// Open flags used by `open-at`. 141 | @since(version = 0.3.0) 142 | flags open-flags { 143 | /// Create file if it does not exist, similar to `O_CREAT` in POSIX. 144 | create, 145 | /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. 146 | directory, 147 | /// Fail if file already exists, similar to `O_EXCL` in POSIX. 148 | exclusive, 149 | /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. 150 | truncate, 151 | } 152 | 153 | /// Number of hard links to an inode. 154 | @since(version = 0.3.0) 155 | type link-count = u64; 156 | 157 | /// When setting a timestamp, this gives the value to set it to. 158 | @since(version = 0.3.0) 159 | variant new-timestamp { 160 | /// Leave the timestamp set to its previous value. 161 | no-change, 162 | /// Set the timestamp to the current time of the system clock associated 163 | /// with the filesystem. 164 | now, 165 | /// Set the timestamp to the given value. 166 | timestamp(datetime), 167 | } 168 | 169 | /// A directory entry. 170 | record directory-entry { 171 | /// The type of the file referred to by this directory entry. 172 | %type: descriptor-type, 173 | 174 | /// The name of the object. 175 | name: string, 176 | } 177 | 178 | /// Error codes returned by functions, similar to `errno` in POSIX. 179 | /// Not all of these error codes are returned by the functions provided by this 180 | /// API; some are used in higher-level library layers, and others are provided 181 | /// merely for alignment with POSIX. 182 | enum error-code { 183 | /// Permission denied, similar to `EACCES` in POSIX. 184 | access, 185 | /// Connection already in progress, similar to `EALREADY` in POSIX. 186 | already, 187 | /// Bad descriptor, similar to `EBADF` in POSIX. 188 | bad-descriptor, 189 | /// Device or resource busy, similar to `EBUSY` in POSIX. 190 | busy, 191 | /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. 192 | deadlock, 193 | /// Storage quota exceeded, similar to `EDQUOT` in POSIX. 194 | quota, 195 | /// File exists, similar to `EEXIST` in POSIX. 196 | exist, 197 | /// File too large, similar to `EFBIG` in POSIX. 198 | file-too-large, 199 | /// Illegal byte sequence, similar to `EILSEQ` in POSIX. 200 | illegal-byte-sequence, 201 | /// Operation in progress, similar to `EINPROGRESS` in POSIX. 202 | in-progress, 203 | /// Interrupted function, similar to `EINTR` in POSIX. 204 | interrupted, 205 | /// Invalid argument, similar to `EINVAL` in POSIX. 206 | invalid, 207 | /// I/O error, similar to `EIO` in POSIX. 208 | io, 209 | /// Is a directory, similar to `EISDIR` in POSIX. 210 | is-directory, 211 | /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. 212 | loop, 213 | /// Too many links, similar to `EMLINK` in POSIX. 214 | too-many-links, 215 | /// Message too large, similar to `EMSGSIZE` in POSIX. 216 | message-size, 217 | /// Filename too long, similar to `ENAMETOOLONG` in POSIX. 218 | name-too-long, 219 | /// No such device, similar to `ENODEV` in POSIX. 220 | no-device, 221 | /// No such file or directory, similar to `ENOENT` in POSIX. 222 | no-entry, 223 | /// No locks available, similar to `ENOLCK` in POSIX. 224 | no-lock, 225 | /// Not enough space, similar to `ENOMEM` in POSIX. 226 | insufficient-memory, 227 | /// No space left on device, similar to `ENOSPC` in POSIX. 228 | insufficient-space, 229 | /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. 230 | not-directory, 231 | /// Directory not empty, similar to `ENOTEMPTY` in POSIX. 232 | not-empty, 233 | /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. 234 | not-recoverable, 235 | /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. 236 | unsupported, 237 | /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. 238 | no-tty, 239 | /// No such device or address, similar to `ENXIO` in POSIX. 240 | no-such-device, 241 | /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. 242 | overflow, 243 | /// Operation not permitted, similar to `EPERM` in POSIX. 244 | not-permitted, 245 | /// Broken pipe, similar to `EPIPE` in POSIX. 246 | pipe, 247 | /// Read-only file system, similar to `EROFS` in POSIX. 248 | read-only, 249 | /// Invalid seek, similar to `ESPIPE` in POSIX. 250 | invalid-seek, 251 | /// Text file busy, similar to `ETXTBSY` in POSIX. 252 | text-file-busy, 253 | /// Cross-device link, similar to `EXDEV` in POSIX. 254 | cross-device, 255 | } 256 | 257 | /// File or memory access pattern advisory information. 258 | @since(version = 0.3.0) 259 | enum advice { 260 | /// The application has no advice to give on its behavior with respect 261 | /// to the specified data. 262 | normal, 263 | /// The application expects to access the specified data sequentially 264 | /// from lower offsets to higher offsets. 265 | sequential, 266 | /// The application expects to access the specified data in a random 267 | /// order. 268 | random, 269 | /// The application expects to access the specified data in the near 270 | /// future. 271 | will-need, 272 | /// The application expects that it will not access the specified data 273 | /// in the near future. 274 | dont-need, 275 | /// The application expects to access the specified data once and then 276 | /// not reuse it thereafter. 277 | no-reuse, 278 | } 279 | 280 | /// A 128-bit hash value, split into parts because wasm doesn't have a 281 | /// 128-bit integer type. 282 | @since(version = 0.3.0) 283 | record metadata-hash-value { 284 | /// 64 bits of a 128-bit hash value. 285 | lower: u64, 286 | /// Another 64 bits of a 128-bit hash value. 287 | upper: u64, 288 | } 289 | 290 | /// A descriptor is a reference to a filesystem object, which may be a file, 291 | /// directory, named pipe, special file, or other object on which filesystem 292 | /// calls may be made. 293 | @since(version = 0.3.0) 294 | resource descriptor { 295 | /// Return a stream for reading from a file. 296 | /// 297 | /// Multiple read, write, and append streams may be active on the same open 298 | /// file and they do not interfere with each other. 299 | /// 300 | /// This function returns a future, which will resolve to an error code if 301 | /// reading full contents of the file fails. 302 | /// 303 | /// Note: This is similar to `pread` in POSIX. 304 | @since(version = 0.3.0) 305 | read-via-stream: func( 306 | /// The offset within the file at which to start reading. 307 | offset: filesize, 308 | ) -> tuple, future>>; 309 | 310 | /// Return a stream for writing to a file, if available. 311 | /// 312 | /// May fail with an error-code describing why the file cannot be written. 313 | /// 314 | /// It is valid to write past the end of a file; the file is extended to the 315 | /// extent of the write, with bytes between the previous end and the start of 316 | /// the write set to zero. 317 | /// 318 | /// This function returns once either full contents of the stream are 319 | /// written or an error is encountered. 320 | /// 321 | /// Note: This is similar to `pwrite` in POSIX. 322 | @since(version = 0.3.0) 323 | write-via-stream: func( 324 | /// Data to write 325 | data: stream, 326 | /// The offset within the file at which to start writing. 327 | offset: filesize, 328 | ) -> result<_, error-code>; 329 | 330 | /// Return a stream for appending to a file, if available. 331 | /// 332 | /// May fail with an error-code describing why the file cannot be appended. 333 | /// 334 | /// This function returns once either full contents of the stream are 335 | /// written or an error is encountered. 336 | /// 337 | /// Note: This is similar to `write` with `O_APPEND` in POSIX. 338 | @since(version = 0.3.0) 339 | append-via-stream: func(data: stream) -> result<_, error-code>; 340 | 341 | /// Provide file advisory information on a descriptor. 342 | /// 343 | /// This is similar to `posix_fadvise` in POSIX. 344 | @since(version = 0.3.0) 345 | advise: func( 346 | /// The offset within the file to which the advisory applies. 347 | offset: filesize, 348 | /// The length of the region to which the advisory applies. 349 | length: filesize, 350 | /// The advice. 351 | advice: advice 352 | ) -> result<_, error-code>; 353 | 354 | /// Synchronize the data of a file to disk. 355 | /// 356 | /// This function succeeds with no effect if the file descriptor is not 357 | /// opened for writing. 358 | /// 359 | /// Note: This is similar to `fdatasync` in POSIX. 360 | @since(version = 0.3.0) 361 | sync-data: func() -> result<_, error-code>; 362 | 363 | /// Get flags associated with a descriptor. 364 | /// 365 | /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. 366 | /// 367 | /// Note: This returns the value that was the `fs_flags` value returned 368 | /// from `fdstat_get` in earlier versions of WASI. 369 | @since(version = 0.3.0) 370 | get-flags: func() -> result; 371 | 372 | /// Get the dynamic type of a descriptor. 373 | /// 374 | /// Note: This returns the same value as the `type` field of the `fd-stat` 375 | /// returned by `stat`, `stat-at` and similar. 376 | /// 377 | /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided 378 | /// by `fstat` in POSIX. 379 | /// 380 | /// Note: This returns the value that was the `fs_filetype` value returned 381 | /// from `fdstat_get` in earlier versions of WASI. 382 | @since(version = 0.3.0) 383 | get-type: func() -> result; 384 | 385 | /// Adjust the size of an open file. If this increases the file's size, the 386 | /// extra bytes are filled with zeros. 387 | /// 388 | /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. 389 | @since(version = 0.3.0) 390 | set-size: func(size: filesize) -> result<_, error-code>; 391 | 392 | /// Adjust the timestamps of an open file or directory. 393 | /// 394 | /// Note: This is similar to `futimens` in POSIX. 395 | /// 396 | /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. 397 | @since(version = 0.3.0) 398 | set-times: func( 399 | /// The desired values of the data access timestamp. 400 | data-access-timestamp: new-timestamp, 401 | /// The desired values of the data modification timestamp. 402 | data-modification-timestamp: new-timestamp, 403 | ) -> result<_, error-code>; 404 | 405 | /// Read directory entries from a directory. 406 | /// 407 | /// On filesystems where directories contain entries referring to themselves 408 | /// and their parents, often named `.` and `..` respectively, these entries 409 | /// are omitted. 410 | /// 411 | /// This always returns a new stream which starts at the beginning of the 412 | /// directory. Multiple streams may be active on the same directory, and they 413 | /// do not interfere with each other. 414 | /// 415 | /// This function returns a future, which will resolve to an error code if 416 | /// reading full contents of the directory fails. 417 | @since(version = 0.3.0) 418 | read-directory: func() -> tuple, future>>; 419 | 420 | /// Synchronize the data and metadata of a file to disk. 421 | /// 422 | /// This function succeeds with no effect if the file descriptor is not 423 | /// opened for writing. 424 | /// 425 | /// Note: This is similar to `fsync` in POSIX. 426 | @since(version = 0.3.0) 427 | sync: func() -> result<_, error-code>; 428 | 429 | /// Create a directory. 430 | /// 431 | /// Note: This is similar to `mkdirat` in POSIX. 432 | @since(version = 0.3.0) 433 | create-directory-at: func( 434 | /// The relative path at which to create the directory. 435 | path: string, 436 | ) -> result<_, error-code>; 437 | 438 | /// Return the attributes of an open file or directory. 439 | /// 440 | /// Note: This is similar to `fstat` in POSIX, except that it does not return 441 | /// device and inode information. For testing whether two descriptors refer to 442 | /// the same underlying filesystem object, use `is-same-object`. To obtain 443 | /// additional data that can be used do determine whether a file has been 444 | /// modified, use `metadata-hash`. 445 | /// 446 | /// Note: This was called `fd_filestat_get` in earlier versions of WASI. 447 | @since(version = 0.3.0) 448 | stat: func() -> result; 449 | 450 | /// Return the attributes of a file or directory. 451 | /// 452 | /// Note: This is similar to `fstatat` in POSIX, except that it does not 453 | /// return device and inode information. See the `stat` description for a 454 | /// discussion of alternatives. 455 | /// 456 | /// Note: This was called `path_filestat_get` in earlier versions of WASI. 457 | @since(version = 0.3.0) 458 | stat-at: func( 459 | /// Flags determining the method of how the path is resolved. 460 | path-flags: path-flags, 461 | /// The relative path of the file or directory to inspect. 462 | path: string, 463 | ) -> result; 464 | 465 | /// Adjust the timestamps of a file or directory. 466 | /// 467 | /// Note: This is similar to `utimensat` in POSIX. 468 | /// 469 | /// Note: This was called `path_filestat_set_times` in earlier versions of 470 | /// WASI. 471 | @since(version = 0.3.0) 472 | set-times-at: func( 473 | /// Flags determining the method of how the path is resolved. 474 | path-flags: path-flags, 475 | /// The relative path of the file or directory to operate on. 476 | path: string, 477 | /// The desired values of the data access timestamp. 478 | data-access-timestamp: new-timestamp, 479 | /// The desired values of the data modification timestamp. 480 | data-modification-timestamp: new-timestamp, 481 | ) -> result<_, error-code>; 482 | 483 | /// Create a hard link. 484 | /// 485 | /// Fails with `error-code::no-entry` if the old path does not exist, 486 | /// with `error-code::exist` if the new path already exists, and 487 | /// `error-code::not-permitted` if the old path is not a file. 488 | /// 489 | /// Note: This is similar to `linkat` in POSIX. 490 | @since(version = 0.3.0) 491 | link-at: func( 492 | /// Flags determining the method of how the path is resolved. 493 | old-path-flags: path-flags, 494 | /// The relative source path from which to link. 495 | old-path: string, 496 | /// The base directory for `new-path`. 497 | new-descriptor: borrow, 498 | /// The relative destination path at which to create the hard link. 499 | new-path: string, 500 | ) -> result<_, error-code>; 501 | 502 | /// Open a file or directory. 503 | /// 504 | /// If `flags` contains `descriptor-flags::mutate-directory`, and the base 505 | /// descriptor doesn't have `descriptor-flags::mutate-directory` set, 506 | /// `open-at` fails with `error-code::read-only`. 507 | /// 508 | /// If `flags` contains `write` or `mutate-directory`, or `open-flags` 509 | /// contains `truncate` or `create`, and the base descriptor doesn't have 510 | /// `descriptor-flags::mutate-directory` set, `open-at` fails with 511 | /// `error-code::read-only`. 512 | /// 513 | /// Note: This is similar to `openat` in POSIX. 514 | @since(version = 0.3.0) 515 | open-at: func( 516 | /// Flags determining the method of how the path is resolved. 517 | path-flags: path-flags, 518 | /// The relative path of the object to open. 519 | path: string, 520 | /// The method by which to open the file. 521 | open-flags: open-flags, 522 | /// Flags to use for the resulting descriptor. 523 | %flags: descriptor-flags, 524 | ) -> result; 525 | 526 | /// Read the contents of a symbolic link. 527 | /// 528 | /// If the contents contain an absolute or rooted path in the underlying 529 | /// filesystem, this function fails with `error-code::not-permitted`. 530 | /// 531 | /// Note: This is similar to `readlinkat` in POSIX. 532 | @since(version = 0.3.0) 533 | readlink-at: func( 534 | /// The relative path of the symbolic link from which to read. 535 | path: string, 536 | ) -> result; 537 | 538 | /// Remove a directory. 539 | /// 540 | /// Return `error-code::not-empty` if the directory is not empty. 541 | /// 542 | /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. 543 | @since(version = 0.3.0) 544 | remove-directory-at: func( 545 | /// The relative path to a directory to remove. 546 | path: string, 547 | ) -> result<_, error-code>; 548 | 549 | /// Rename a filesystem object. 550 | /// 551 | /// Note: This is similar to `renameat` in POSIX. 552 | @since(version = 0.3.0) 553 | rename-at: func( 554 | /// The relative source path of the file or directory to rename. 555 | old-path: string, 556 | /// The base directory for `new-path`. 557 | new-descriptor: borrow, 558 | /// The relative destination path to which to rename the file or directory. 559 | new-path: string, 560 | ) -> result<_, error-code>; 561 | 562 | /// Create a symbolic link (also known as a "symlink"). 563 | /// 564 | /// If `old-path` starts with `/`, the function fails with 565 | /// `error-code::not-permitted`. 566 | /// 567 | /// Note: This is similar to `symlinkat` in POSIX. 568 | @since(version = 0.3.0) 569 | symlink-at: func( 570 | /// The contents of the symbolic link. 571 | old-path: string, 572 | /// The relative destination path at which to create the symbolic link. 573 | new-path: string, 574 | ) -> result<_, error-code>; 575 | 576 | /// Unlink a filesystem object that is not a directory. 577 | /// 578 | /// Return `error-code::is-directory` if the path refers to a directory. 579 | /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. 580 | @since(version = 0.3.0) 581 | unlink-file-at: func( 582 | /// The relative path to a file to unlink. 583 | path: string, 584 | ) -> result<_, error-code>; 585 | 586 | /// Test whether two descriptors refer to the same filesystem object. 587 | /// 588 | /// In POSIX, this corresponds to testing whether the two descriptors have the 589 | /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. 590 | /// wasi-filesystem does not expose device and inode numbers, so this function 591 | /// may be used instead. 592 | @since(version = 0.3.0) 593 | is-same-object: func(other: borrow) -> bool; 594 | 595 | /// Return a hash of the metadata associated with a filesystem object referred 596 | /// to by a descriptor. 597 | /// 598 | /// This returns a hash of the last-modification timestamp and file size, and 599 | /// may also include the inode number, device number, birth timestamp, and 600 | /// other metadata fields that may change when the file is modified or 601 | /// replaced. It may also include a secret value chosen by the 602 | /// implementation and not otherwise exposed. 603 | /// 604 | /// Implementations are encouraged to provide the following properties: 605 | /// 606 | /// - If the file is not modified or replaced, the computed hash value should 607 | /// usually not change. 608 | /// - If the object is modified or replaced, the computed hash value should 609 | /// usually change. 610 | /// - The inputs to the hash should not be easily computable from the 611 | /// computed hash. 612 | /// 613 | /// However, none of these is required. 614 | @since(version = 0.3.0) 615 | metadata-hash: func() -> result; 616 | 617 | /// Return a hash of the metadata associated with a filesystem object referred 618 | /// to by a directory descriptor and a relative path. 619 | /// 620 | /// This performs the same hash computation as `metadata-hash`. 621 | @since(version = 0.3.0) 622 | metadata-hash-at: func( 623 | /// Flags determining the method of how the path is resolved. 624 | path-flags: path-flags, 625 | /// The relative path of the file or directory to inspect. 626 | path: string, 627 | ) -> result; 628 | } 629 | } 630 | -------------------------------------------------------------------------------- /wit-0.3.0-draft/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.3.0; 2 | 3 | @since(version = 0.3.0) 4 | world imports { 5 | @since(version = 0.3.0) 6 | import types; 7 | @since(version = 0.3.0) 8 | import preopens; 9 | } 10 | -------------------------------------------------------------------------------- /wit/deps.lock: -------------------------------------------------------------------------------- 1 | [clocks] 2 | url = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz" 3 | sha256 = "f1c53079469e20167e2cd4300651f13f34a6fd508b5c7331bb7c8c95fb8857fb" 4 | sha512 = "2a9281d0edcabad3bfef0dcfa7a9712d6beb6d6bb07b29fbf24235706d149672901ffc32192404a1ac511c512eb775daf9716ad3a0514bdf6a5c93a5fed19450" 5 | 6 | [io] 7 | url = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz" 8 | sha256 = "749de54c05f7118dc118999ad69c5b63890ea1dd86f1be69270062195c7b79c2" 9 | sha512 = "b5096d518a7931c100594b9216bb4a98cd64533166bc7fdbb7465b48effc345863bd3ce2ec84fef59b273bae507edab08ec08975d56240ccef68f2494964e80a" 10 | -------------------------------------------------------------------------------- /wit/deps.toml: -------------------------------------------------------------------------------- 1 | io = "https://github.com/WebAssembly/wasi-io/archive/main.tar.gz" 2 | clocks = "https://github.com/WebAssembly/wasi-clocks/archive/main.tar.gz" 3 | -------------------------------------------------------------------------------- /wit/deps/clocks/monotonic-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.5; 2 | /// WASI Monotonic Clock is a clock API intended to let users measure elapsed 3 | /// time. 4 | /// 5 | /// It is intended to be portable at least between Unix-family platforms and 6 | /// Windows. 7 | /// 8 | /// A monotonic clock is a clock which has an unspecified initial value, and 9 | /// successive reads of the clock will produce non-decreasing values. 10 | @since(version = 0.2.0) 11 | interface monotonic-clock { 12 | @since(version = 0.2.0) 13 | use wasi:io/poll@0.2.5.{pollable}; 14 | 15 | /// An instant in time, in nanoseconds. An instant is relative to an 16 | /// unspecified initial value, and can only be compared to instances from 17 | /// the same monotonic-clock. 18 | @since(version = 0.2.0) 19 | type instant = u64; 20 | 21 | /// A duration of time, in nanoseconds. 22 | @since(version = 0.2.0) 23 | type duration = u64; 24 | 25 | /// Read the current value of the clock. 26 | /// 27 | /// The clock is monotonic, therefore calling this function repeatedly will 28 | /// produce a sequence of non-decreasing values. 29 | @since(version = 0.2.0) 30 | now: func() -> instant; 31 | 32 | /// Query the resolution of the clock. Returns the duration of time 33 | /// corresponding to a clock tick. 34 | @since(version = 0.2.0) 35 | resolution: func() -> duration; 36 | 37 | /// Create a `pollable` which will resolve once the specified instant 38 | /// has occurred. 39 | @since(version = 0.2.0) 40 | subscribe-instant: func( 41 | when: instant, 42 | ) -> pollable; 43 | 44 | /// Create a `pollable` that will resolve after the specified duration has 45 | /// elapsed from the time this function is invoked. 46 | @since(version = 0.2.0) 47 | subscribe-duration: func( 48 | when: duration, 49 | ) -> pollable; 50 | } 51 | -------------------------------------------------------------------------------- /wit/deps/clocks/timezone.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.5; 2 | 3 | @unstable(feature = clocks-timezone) 4 | interface timezone { 5 | @unstable(feature = clocks-timezone) 6 | use wall-clock.{datetime}; 7 | 8 | /// Return information needed to display the given `datetime`. This includes 9 | /// the UTC offset, the time zone name, and a flag indicating whether 10 | /// daylight saving time is active. 11 | /// 12 | /// If the timezone cannot be determined for the given `datetime`, return a 13 | /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight 14 | /// saving time. 15 | @unstable(feature = clocks-timezone) 16 | display: func(when: datetime) -> timezone-display; 17 | 18 | /// The same as `display`, but only return the UTC offset. 19 | @unstable(feature = clocks-timezone) 20 | utc-offset: func(when: datetime) -> s32; 21 | 22 | /// Information useful for displaying the timezone of a specific `datetime`. 23 | /// 24 | /// This information may vary within a single `timezone` to reflect daylight 25 | /// saving time adjustments. 26 | @unstable(feature = clocks-timezone) 27 | record timezone-display { 28 | /// The number of seconds difference between UTC time and the local 29 | /// time of the timezone. 30 | /// 31 | /// The returned value will always be less than 86400 which is the 32 | /// number of seconds in a day (24*60*60). 33 | /// 34 | /// In implementations that do not expose an actual time zone, this 35 | /// should return 0. 36 | utc-offset: s32, 37 | 38 | /// The abbreviated name of the timezone to display to a user. The name 39 | /// `UTC` indicates Coordinated Universal Time. Otherwise, this should 40 | /// reference local standards for the name of the time zone. 41 | /// 42 | /// In implementations that do not expose an actual time zone, this 43 | /// should be the string `UTC`. 44 | /// 45 | /// In time zones that do not have an applicable name, a formatted 46 | /// representation of the UTC offset may be returned, such as `-04:00`. 47 | name: string, 48 | 49 | /// Whether daylight saving time is active. 50 | /// 51 | /// In implementations that do not expose an actual time zone, this 52 | /// should return false. 53 | in-daylight-saving-time: bool, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /wit/deps/clocks/wall-clock.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.5; 2 | /// WASI Wall Clock is a clock API intended to let users query the current 3 | /// time. The name "wall" makes an analogy to a "clock on the wall", which 4 | /// is not necessarily monotonic as it may be reset. 5 | /// 6 | /// It is intended to be portable at least between Unix-family platforms and 7 | /// Windows. 8 | /// 9 | /// A wall clock is a clock which measures the date and time according to 10 | /// some external reference. 11 | /// 12 | /// External references may be reset, so this clock is not necessarily 13 | /// monotonic, making it unsuitable for measuring elapsed time. 14 | /// 15 | /// It is intended for reporting the current date and time for humans. 16 | @since(version = 0.2.0) 17 | interface wall-clock { 18 | /// A time and date in seconds plus nanoseconds. 19 | @since(version = 0.2.0) 20 | record datetime { 21 | seconds: u64, 22 | nanoseconds: u32, 23 | } 24 | 25 | /// Read the current value of the clock. 26 | /// 27 | /// This clock is not monotonic, therefore calling this function repeatedly 28 | /// will not necessarily produce a sequence of non-decreasing values. 29 | /// 30 | /// The returned timestamps represent the number of seconds since 31 | /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], 32 | /// also known as [Unix Time]. 33 | /// 34 | /// The nanoseconds field of the output is always less than 1000000000. 35 | /// 36 | /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 37 | /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time 38 | @since(version = 0.2.0) 39 | now: func() -> datetime; 40 | 41 | /// Query the resolution of the clock. 42 | /// 43 | /// The nanoseconds field of the output is always less than 1000000000. 44 | @since(version = 0.2.0) 45 | resolution: func() -> datetime; 46 | } 47 | -------------------------------------------------------------------------------- /wit/deps/clocks/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:clocks@0.2.5; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import monotonic-clock; 7 | @since(version = 0.2.0) 8 | import wall-clock; 9 | @unstable(feature = clocks-timezone) 10 | import timezone; 11 | } 12 | -------------------------------------------------------------------------------- /wit/deps/io/error.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.5; 2 | 3 | @since(version = 0.2.0) 4 | interface error { 5 | /// A resource which represents some error information. 6 | /// 7 | /// The only method provided by this resource is `to-debug-string`, 8 | /// which provides some human-readable information about the error. 9 | /// 10 | /// In the `wasi:io` package, this resource is returned through the 11 | /// `wasi:io/streams/stream-error` type. 12 | /// 13 | /// To provide more specific error information, other interfaces may 14 | /// offer functions to "downcast" this error into more specific types. For example, 15 | /// errors returned from streams derived from filesystem types can be described using 16 | /// the filesystem's own error-code type. This is done using the function 17 | /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` 18 | /// parameter and returns an `option`. 19 | /// 20 | /// The set of functions which can "downcast" an `error` into a more 21 | /// concrete type is open. 22 | @since(version = 0.2.0) 23 | resource error { 24 | /// Returns a string that is suitable to assist humans in debugging 25 | /// this error. 26 | /// 27 | /// WARNING: The returned string should not be consumed mechanically! 28 | /// It may change across platforms, hosts, or other implementation 29 | /// details. Parsing this string is a major platform-compatibility 30 | /// hazard. 31 | @since(version = 0.2.0) 32 | to-debug-string: func() -> string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wit/deps/io/poll.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.5; 2 | 3 | /// A poll API intended to let users wait for I/O events on multiple handles 4 | /// at once. 5 | @since(version = 0.2.0) 6 | interface poll { 7 | /// `pollable` represents a single I/O event which may be ready, or not. 8 | @since(version = 0.2.0) 9 | resource pollable { 10 | 11 | /// Return the readiness of a pollable. This function never blocks. 12 | /// 13 | /// Returns `true` when the pollable is ready, and `false` otherwise. 14 | @since(version = 0.2.0) 15 | ready: func() -> bool; 16 | 17 | /// `block` returns immediately if the pollable is ready, and otherwise 18 | /// blocks until ready. 19 | /// 20 | /// This function is equivalent to calling `poll.poll` on a list 21 | /// containing only this pollable. 22 | @since(version = 0.2.0) 23 | block: func(); 24 | } 25 | 26 | /// Poll for completion on a set of pollables. 27 | /// 28 | /// This function takes a list of pollables, which identify I/O sources of 29 | /// interest, and waits until one or more of the events is ready for I/O. 30 | /// 31 | /// The result `list` contains one or more indices of handles in the 32 | /// argument list that is ready for I/O. 33 | /// 34 | /// This function traps if either: 35 | /// - the list is empty, or: 36 | /// - the list contains more elements than can be indexed with a `u32` value. 37 | /// 38 | /// A timeout can be implemented by adding a pollable from the 39 | /// wasi-clocks API to the list. 40 | /// 41 | /// This function does not return a `result`; polling in itself does not 42 | /// do any I/O so it doesn't fail. If any of the I/O sources identified by 43 | /// the pollables has an error, it is indicated by marking the source as 44 | /// being ready for I/O. 45 | @since(version = 0.2.0) 46 | poll: func(in: list>) -> list; 47 | } 48 | -------------------------------------------------------------------------------- /wit/deps/io/streams.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.5; 2 | 3 | /// WASI I/O is an I/O abstraction API which is currently focused on providing 4 | /// stream types. 5 | /// 6 | /// In the future, the component model is expected to add built-in stream types; 7 | /// when it does, they are expected to subsume this API. 8 | @since(version = 0.2.0) 9 | interface streams { 10 | @since(version = 0.2.0) 11 | use error.{error}; 12 | @since(version = 0.2.0) 13 | use poll.{pollable}; 14 | 15 | /// An error for input-stream and output-stream operations. 16 | @since(version = 0.2.0) 17 | variant stream-error { 18 | /// The last operation (a write or flush) failed before completion. 19 | /// 20 | /// More information is available in the `error` payload. 21 | /// 22 | /// After this, the stream will be closed. All future operations return 23 | /// `stream-error::closed`. 24 | last-operation-failed(error), 25 | /// The stream is closed: no more input will be accepted by the 26 | /// stream. A closed output-stream will return this error on all 27 | /// future operations. 28 | closed 29 | } 30 | 31 | /// An input bytestream. 32 | /// 33 | /// `input-stream`s are *non-blocking* to the extent practical on underlying 34 | /// platforms. I/O operations always return promptly; if fewer bytes are 35 | /// promptly available than requested, they return the number of bytes promptly 36 | /// available, which could even be zero. To wait for data to be available, 37 | /// use the `subscribe` function to obtain a `pollable` which can be polled 38 | /// for using `wasi:io/poll`. 39 | @since(version = 0.2.0) 40 | resource input-stream { 41 | /// Perform a non-blocking read from the stream. 42 | /// 43 | /// When the source of a `read` is binary data, the bytes from the source 44 | /// are returned verbatim. When the source of a `read` is known to the 45 | /// implementation to be text, bytes containing the UTF-8 encoding of the 46 | /// text are returned. 47 | /// 48 | /// This function returns a list of bytes containing the read data, 49 | /// when successful. The returned list will contain up to `len` bytes; 50 | /// it may return fewer than requested, but not more. The list is 51 | /// empty when no bytes are available for reading at this time. The 52 | /// pollable given by `subscribe` will be ready when more bytes are 53 | /// available. 54 | /// 55 | /// This function fails with a `stream-error` when the operation 56 | /// encounters an error, giving `last-operation-failed`, or when the 57 | /// stream is closed, giving `closed`. 58 | /// 59 | /// When the caller gives a `len` of 0, it represents a request to 60 | /// read 0 bytes. If the stream is still open, this call should 61 | /// succeed and return an empty list, or otherwise fail with `closed`. 62 | /// 63 | /// The `len` parameter is a `u64`, which could represent a list of u8 which 64 | /// is not possible to allocate in wasm32, or not desirable to allocate as 65 | /// as a return value by the callee. The callee may return a list of bytes 66 | /// less than `len` in size while more bytes are available for reading. 67 | @since(version = 0.2.0) 68 | read: func( 69 | /// The maximum number of bytes to read 70 | len: u64 71 | ) -> result, stream-error>; 72 | 73 | /// Read bytes from a stream, after blocking until at least one byte can 74 | /// be read. Except for blocking, behavior is identical to `read`. 75 | @since(version = 0.2.0) 76 | blocking-read: func( 77 | /// The maximum number of bytes to read 78 | len: u64 79 | ) -> result, stream-error>; 80 | 81 | /// Skip bytes from a stream. Returns number of bytes skipped. 82 | /// 83 | /// Behaves identical to `read`, except instead of returning a list 84 | /// of bytes, returns the number of bytes consumed from the stream. 85 | @since(version = 0.2.0) 86 | skip: func( 87 | /// The maximum number of bytes to skip. 88 | len: u64, 89 | ) -> result; 90 | 91 | /// Skip bytes from a stream, after blocking until at least one byte 92 | /// can be skipped. Except for blocking behavior, identical to `skip`. 93 | @since(version = 0.2.0) 94 | blocking-skip: func( 95 | /// The maximum number of bytes to skip. 96 | len: u64, 97 | ) -> result; 98 | 99 | /// Create a `pollable` which will resolve once either the specified stream 100 | /// has bytes available to read or the other end of the stream has been 101 | /// closed. 102 | /// The created `pollable` is a child resource of the `input-stream`. 103 | /// Implementations may trap if the `input-stream` is dropped before 104 | /// all derived `pollable`s created with this function are dropped. 105 | @since(version = 0.2.0) 106 | subscribe: func() -> pollable; 107 | } 108 | 109 | 110 | /// An output bytestream. 111 | /// 112 | /// `output-stream`s are *non-blocking* to the extent practical on 113 | /// underlying platforms. Except where specified otherwise, I/O operations also 114 | /// always return promptly, after the number of bytes that can be written 115 | /// promptly, which could even be zero. To wait for the stream to be ready to 116 | /// accept data, the `subscribe` function to obtain a `pollable` which can be 117 | /// polled for using `wasi:io/poll`. 118 | /// 119 | /// Dropping an `output-stream` while there's still an active write in 120 | /// progress may result in the data being lost. Before dropping the stream, 121 | /// be sure to fully flush your writes. 122 | @since(version = 0.2.0) 123 | resource output-stream { 124 | /// Check readiness for writing. This function never blocks. 125 | /// 126 | /// Returns the number of bytes permitted for the next call to `write`, 127 | /// or an error. Calling `write` with more bytes than this function has 128 | /// permitted will trap. 129 | /// 130 | /// When this function returns 0 bytes, the `subscribe` pollable will 131 | /// become ready when this function will report at least 1 byte, or an 132 | /// error. 133 | @since(version = 0.2.0) 134 | check-write: func() -> result; 135 | 136 | /// Perform a write. This function never blocks. 137 | /// 138 | /// When the destination of a `write` is binary data, the bytes from 139 | /// `contents` are written verbatim. When the destination of a `write` is 140 | /// known to the implementation to be text, the bytes of `contents` are 141 | /// transcoded from UTF-8 into the encoding of the destination and then 142 | /// written. 143 | /// 144 | /// Precondition: check-write gave permit of Ok(n) and contents has a 145 | /// length of less than or equal to n. Otherwise, this function will trap. 146 | /// 147 | /// returns Err(closed) without writing if the stream has closed since 148 | /// the last call to check-write provided a permit. 149 | @since(version = 0.2.0) 150 | write: func( 151 | contents: list 152 | ) -> result<_, stream-error>; 153 | 154 | /// Perform a write of up to 4096 bytes, and then flush the stream. Block 155 | /// until all of these operations are complete, or an error occurs. 156 | /// 157 | /// This is a convenience wrapper around the use of `check-write`, 158 | /// `subscribe`, `write`, and `flush`, and is implemented with the 159 | /// following pseudo-code: 160 | /// 161 | /// ```text 162 | /// let pollable = this.subscribe(); 163 | /// while !contents.is_empty() { 164 | /// // Wait for the stream to become writable 165 | /// pollable.block(); 166 | /// let Ok(n) = this.check-write(); // eliding error handling 167 | /// let len = min(n, contents.len()); 168 | /// let (chunk, rest) = contents.split_at(len); 169 | /// this.write(chunk ); // eliding error handling 170 | /// contents = rest; 171 | /// } 172 | /// this.flush(); 173 | /// // Wait for completion of `flush` 174 | /// pollable.block(); 175 | /// // Check for any errors that arose during `flush` 176 | /// let _ = this.check-write(); // eliding error handling 177 | /// ``` 178 | @since(version = 0.2.0) 179 | blocking-write-and-flush: func( 180 | contents: list 181 | ) -> result<_, stream-error>; 182 | 183 | /// Request to flush buffered output. This function never blocks. 184 | /// 185 | /// This tells the output-stream that the caller intends any buffered 186 | /// output to be flushed. the output which is expected to be flushed 187 | /// is all that has been passed to `write` prior to this call. 188 | /// 189 | /// Upon calling this function, the `output-stream` will not accept any 190 | /// writes (`check-write` will return `ok(0)`) until the flush has 191 | /// completed. The `subscribe` pollable will become ready when the 192 | /// flush has completed and the stream can accept more writes. 193 | @since(version = 0.2.0) 194 | flush: func() -> result<_, stream-error>; 195 | 196 | /// Request to flush buffered output, and block until flush completes 197 | /// and stream is ready for writing again. 198 | @since(version = 0.2.0) 199 | blocking-flush: func() -> result<_, stream-error>; 200 | 201 | /// Create a `pollable` which will resolve once the output-stream 202 | /// is ready for more writing, or an error has occurred. When this 203 | /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an 204 | /// error. 205 | /// 206 | /// If the stream is closed, this pollable is always ready immediately. 207 | /// 208 | /// The created `pollable` is a child resource of the `output-stream`. 209 | /// Implementations may trap if the `output-stream` is dropped before 210 | /// all derived `pollable`s created with this function are dropped. 211 | @since(version = 0.2.0) 212 | subscribe: func() -> pollable; 213 | 214 | /// Write zeroes to a stream. 215 | /// 216 | /// This should be used precisely like `write` with the exact same 217 | /// preconditions (must use check-write first), but instead of 218 | /// passing a list of bytes, you simply pass the number of zero-bytes 219 | /// that should be written. 220 | @since(version = 0.2.0) 221 | write-zeroes: func( 222 | /// The number of zero-bytes to write 223 | len: u64 224 | ) -> result<_, stream-error>; 225 | 226 | /// Perform a write of up to 4096 zeroes, and then flush the stream. 227 | /// Block until all of these operations are complete, or an error 228 | /// occurs. 229 | /// 230 | /// This is a convenience wrapper around the use of `check-write`, 231 | /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with 232 | /// the following pseudo-code: 233 | /// 234 | /// ```text 235 | /// let pollable = this.subscribe(); 236 | /// while num_zeroes != 0 { 237 | /// // Wait for the stream to become writable 238 | /// pollable.block(); 239 | /// let Ok(n) = this.check-write(); // eliding error handling 240 | /// let len = min(n, num_zeroes); 241 | /// this.write-zeroes(len); // eliding error handling 242 | /// num_zeroes -= len; 243 | /// } 244 | /// this.flush(); 245 | /// // Wait for completion of `flush` 246 | /// pollable.block(); 247 | /// // Check for any errors that arose during `flush` 248 | /// let _ = this.check-write(); // eliding error handling 249 | /// ``` 250 | @since(version = 0.2.0) 251 | blocking-write-zeroes-and-flush: func( 252 | /// The number of zero-bytes to write 253 | len: u64 254 | ) -> result<_, stream-error>; 255 | 256 | /// Read from one stream and write to another. 257 | /// 258 | /// The behavior of splice is equivalent to: 259 | /// 1. calling `check-write` on the `output-stream` 260 | /// 2. calling `read` on the `input-stream` with the smaller of the 261 | /// `check-write` permitted length and the `len` provided to `splice` 262 | /// 3. calling `write` on the `output-stream` with that read data. 263 | /// 264 | /// Any error reported by the call to `check-write`, `read`, or 265 | /// `write` ends the splice and reports that error. 266 | /// 267 | /// This function returns the number of bytes transferred; it may be less 268 | /// than `len`. 269 | @since(version = 0.2.0) 270 | splice: func( 271 | /// The stream to read from 272 | src: borrow, 273 | /// The number of bytes to splice 274 | len: u64, 275 | ) -> result; 276 | 277 | /// Read from one stream and write to another, with blocking. 278 | /// 279 | /// This is similar to `splice`, except that it blocks until the 280 | /// `output-stream` is ready for writing, and the `input-stream` 281 | /// is ready for reading, before performing the `splice`. 282 | @since(version = 0.2.0) 283 | blocking-splice: func( 284 | /// The stream to read from 285 | src: borrow, 286 | /// The number of bytes to splice 287 | len: u64, 288 | ) -> result; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /wit/deps/io/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:io@0.2.5; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import streams; 7 | 8 | @since(version = 0.2.0) 9 | import poll; 10 | } 11 | -------------------------------------------------------------------------------- /wit/preopens.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.2.5; 2 | 3 | @since(version = 0.2.0) 4 | interface preopens { 5 | @since(version = 0.2.0) 6 | use types.{descriptor}; 7 | 8 | /// Return the set of preopened directories, and their paths. 9 | @since(version = 0.2.0) 10 | get-directories: func() -> list>; 11 | } 12 | -------------------------------------------------------------------------------- /wit/types.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.2.5; 2 | /// WASI filesystem is a filesystem API primarily intended to let users run WASI 3 | /// programs that access their files on their existing filesystems, without 4 | /// significant overhead. 5 | /// 6 | /// It is intended to be roughly portable between Unix-family platforms and 7 | /// Windows, though it does not hide many of the major differences. 8 | /// 9 | /// Paths are passed as interface-type `string`s, meaning they must consist of 10 | /// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain 11 | /// paths which are not accessible by this API. 12 | /// 13 | /// The directory separator in WASI is always the forward-slash (`/`). 14 | /// 15 | /// All paths in WASI are relative paths, and are interpreted relative to a 16 | /// `descriptor` referring to a base directory. If a `path` argument to any WASI 17 | /// function starts with `/`, or if any step of resolving a `path`, including 18 | /// `..` and symbolic link steps, reaches a directory outside of the base 19 | /// directory, or reaches a symlink to an absolute or rooted path in the 20 | /// underlying filesystem, the function fails with `error-code::not-permitted`. 21 | /// 22 | /// For more information about WASI path resolution and sandboxing, see 23 | /// [WASI filesystem path resolution]. 24 | /// 25 | /// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md 26 | @since(version = 0.2.0) 27 | interface types { 28 | @since(version = 0.2.0) 29 | use wasi:io/streams@0.2.5.{input-stream, output-stream, error}; 30 | @since(version = 0.2.0) 31 | use wasi:clocks/wall-clock@0.2.5.{datetime}; 32 | 33 | /// File size or length of a region within a file. 34 | @since(version = 0.2.0) 35 | type filesize = u64; 36 | 37 | /// The type of a filesystem object referenced by a descriptor. 38 | /// 39 | /// Note: This was called `filetype` in earlier versions of WASI. 40 | @since(version = 0.2.0) 41 | enum descriptor-type { 42 | /// The type of the descriptor or file is unknown or is different from 43 | /// any of the other types specified. 44 | unknown, 45 | /// The descriptor refers to a block device inode. 46 | block-device, 47 | /// The descriptor refers to a character device inode. 48 | character-device, 49 | /// The descriptor refers to a directory inode. 50 | directory, 51 | /// The descriptor refers to a named pipe. 52 | fifo, 53 | /// The file refers to a symbolic link inode. 54 | symbolic-link, 55 | /// The descriptor refers to a regular file inode. 56 | regular-file, 57 | /// The descriptor refers to a socket. 58 | socket, 59 | } 60 | 61 | /// Descriptor flags. 62 | /// 63 | /// Note: This was called `fdflags` in earlier versions of WASI. 64 | @since(version = 0.2.0) 65 | flags descriptor-flags { 66 | /// Read mode: Data can be read. 67 | read, 68 | /// Write mode: Data can be written to. 69 | write, 70 | /// Request that writes be performed according to synchronized I/O file 71 | /// integrity completion. The data stored in the file and the file's 72 | /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. 73 | /// 74 | /// The precise semantics of this operation have not yet been defined for 75 | /// WASI. At this time, it should be interpreted as a request, and not a 76 | /// requirement. 77 | file-integrity-sync, 78 | /// Request that writes be performed according to synchronized I/O data 79 | /// integrity completion. Only the data stored in the file is 80 | /// synchronized. This is similar to `O_DSYNC` in POSIX. 81 | /// 82 | /// The precise semantics of this operation have not yet been defined for 83 | /// WASI. At this time, it should be interpreted as a request, and not a 84 | /// requirement. 85 | data-integrity-sync, 86 | /// Requests that reads be performed at the same level of integrity 87 | /// requested for writes. This is similar to `O_RSYNC` in POSIX. 88 | /// 89 | /// The precise semantics of this operation have not yet been defined for 90 | /// WASI. At this time, it should be interpreted as a request, and not a 91 | /// requirement. 92 | requested-write-sync, 93 | /// Mutating directories mode: Directory contents may be mutated. 94 | /// 95 | /// When this flag is unset on a descriptor, operations using the 96 | /// descriptor which would create, rename, delete, modify the data or 97 | /// metadata of filesystem objects, or obtain another handle which 98 | /// would permit any of those, shall fail with `error-code::read-only` if 99 | /// they would otherwise succeed. 100 | /// 101 | /// This may only be set on directories. 102 | mutate-directory, 103 | } 104 | 105 | /// File attributes. 106 | /// 107 | /// Note: This was called `filestat` in earlier versions of WASI. 108 | @since(version = 0.2.0) 109 | record descriptor-stat { 110 | /// File type. 111 | %type: descriptor-type, 112 | /// Number of hard links to the file. 113 | link-count: link-count, 114 | /// For regular files, the file size in bytes. For symbolic links, the 115 | /// length in bytes of the pathname contained in the symbolic link. 116 | size: filesize, 117 | /// Last data access timestamp. 118 | /// 119 | /// If the `option` is none, the platform doesn't maintain an access 120 | /// timestamp for this file. 121 | data-access-timestamp: option, 122 | /// Last data modification timestamp. 123 | /// 124 | /// If the `option` is none, the platform doesn't maintain a 125 | /// modification timestamp for this file. 126 | data-modification-timestamp: option, 127 | /// Last file status-change timestamp. 128 | /// 129 | /// If the `option` is none, the platform doesn't maintain a 130 | /// status-change timestamp for this file. 131 | status-change-timestamp: option, 132 | } 133 | 134 | /// Flags determining the method of how paths are resolved. 135 | @since(version = 0.2.0) 136 | flags path-flags { 137 | /// As long as the resolved path corresponds to a symbolic link, it is 138 | /// expanded. 139 | symlink-follow, 140 | } 141 | 142 | /// Open flags used by `open-at`. 143 | @since(version = 0.2.0) 144 | flags open-flags { 145 | /// Create file if it does not exist, similar to `O_CREAT` in POSIX. 146 | create, 147 | /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. 148 | directory, 149 | /// Fail if file already exists, similar to `O_EXCL` in POSIX. 150 | exclusive, 151 | /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. 152 | truncate, 153 | } 154 | 155 | /// Number of hard links to an inode. 156 | @since(version = 0.2.0) 157 | type link-count = u64; 158 | 159 | /// When setting a timestamp, this gives the value to set it to. 160 | @since(version = 0.2.0) 161 | variant new-timestamp { 162 | /// Leave the timestamp set to its previous value. 163 | no-change, 164 | /// Set the timestamp to the current time of the system clock associated 165 | /// with the filesystem. 166 | now, 167 | /// Set the timestamp to the given value. 168 | timestamp(datetime), 169 | } 170 | 171 | /// A directory entry. 172 | record directory-entry { 173 | /// The type of the file referred to by this directory entry. 174 | %type: descriptor-type, 175 | 176 | /// The name of the object. 177 | name: string, 178 | } 179 | 180 | /// Error codes returned by functions, similar to `errno` in POSIX. 181 | /// Not all of these error codes are returned by the functions provided by this 182 | /// API; some are used in higher-level library layers, and others are provided 183 | /// merely for alignment with POSIX. 184 | enum error-code { 185 | /// Permission denied, similar to `EACCES` in POSIX. 186 | access, 187 | /// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX. 188 | would-block, 189 | /// Connection already in progress, similar to `EALREADY` in POSIX. 190 | already, 191 | /// Bad descriptor, similar to `EBADF` in POSIX. 192 | bad-descriptor, 193 | /// Device or resource busy, similar to `EBUSY` in POSIX. 194 | busy, 195 | /// Resource deadlock would occur, similar to `EDEADLK` in POSIX. 196 | deadlock, 197 | /// Storage quota exceeded, similar to `EDQUOT` in POSIX. 198 | quota, 199 | /// File exists, similar to `EEXIST` in POSIX. 200 | exist, 201 | /// File too large, similar to `EFBIG` in POSIX. 202 | file-too-large, 203 | /// Illegal byte sequence, similar to `EILSEQ` in POSIX. 204 | illegal-byte-sequence, 205 | /// Operation in progress, similar to `EINPROGRESS` in POSIX. 206 | in-progress, 207 | /// Interrupted function, similar to `EINTR` in POSIX. 208 | interrupted, 209 | /// Invalid argument, similar to `EINVAL` in POSIX. 210 | invalid, 211 | /// I/O error, similar to `EIO` in POSIX. 212 | io, 213 | /// Is a directory, similar to `EISDIR` in POSIX. 214 | is-directory, 215 | /// Too many levels of symbolic links, similar to `ELOOP` in POSIX. 216 | loop, 217 | /// Too many links, similar to `EMLINK` in POSIX. 218 | too-many-links, 219 | /// Message too large, similar to `EMSGSIZE` in POSIX. 220 | message-size, 221 | /// Filename too long, similar to `ENAMETOOLONG` in POSIX. 222 | name-too-long, 223 | /// No such device, similar to `ENODEV` in POSIX. 224 | no-device, 225 | /// No such file or directory, similar to `ENOENT` in POSIX. 226 | no-entry, 227 | /// No locks available, similar to `ENOLCK` in POSIX. 228 | no-lock, 229 | /// Not enough space, similar to `ENOMEM` in POSIX. 230 | insufficient-memory, 231 | /// No space left on device, similar to `ENOSPC` in POSIX. 232 | insufficient-space, 233 | /// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX. 234 | not-directory, 235 | /// Directory not empty, similar to `ENOTEMPTY` in POSIX. 236 | not-empty, 237 | /// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX. 238 | not-recoverable, 239 | /// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX. 240 | unsupported, 241 | /// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX. 242 | no-tty, 243 | /// No such device or address, similar to `ENXIO` in POSIX. 244 | no-such-device, 245 | /// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX. 246 | overflow, 247 | /// Operation not permitted, similar to `EPERM` in POSIX. 248 | not-permitted, 249 | /// Broken pipe, similar to `EPIPE` in POSIX. 250 | pipe, 251 | /// Read-only file system, similar to `EROFS` in POSIX. 252 | read-only, 253 | /// Invalid seek, similar to `ESPIPE` in POSIX. 254 | invalid-seek, 255 | /// Text file busy, similar to `ETXTBSY` in POSIX. 256 | text-file-busy, 257 | /// Cross-device link, similar to `EXDEV` in POSIX. 258 | cross-device, 259 | } 260 | 261 | /// File or memory access pattern advisory information. 262 | @since(version = 0.2.0) 263 | enum advice { 264 | /// The application has no advice to give on its behavior with respect 265 | /// to the specified data. 266 | normal, 267 | /// The application expects to access the specified data sequentially 268 | /// from lower offsets to higher offsets. 269 | sequential, 270 | /// The application expects to access the specified data in a random 271 | /// order. 272 | random, 273 | /// The application expects to access the specified data in the near 274 | /// future. 275 | will-need, 276 | /// The application expects that it will not access the specified data 277 | /// in the near future. 278 | dont-need, 279 | /// The application expects to access the specified data once and then 280 | /// not reuse it thereafter. 281 | no-reuse, 282 | } 283 | 284 | /// A 128-bit hash value, split into parts because wasm doesn't have a 285 | /// 128-bit integer type. 286 | @since(version = 0.2.0) 287 | record metadata-hash-value { 288 | /// 64 bits of a 128-bit hash value. 289 | lower: u64, 290 | /// Another 64 bits of a 128-bit hash value. 291 | upper: u64, 292 | } 293 | 294 | /// A descriptor is a reference to a filesystem object, which may be a file, 295 | /// directory, named pipe, special file, or other object on which filesystem 296 | /// calls may be made. 297 | @since(version = 0.2.0) 298 | resource descriptor { 299 | /// Return a stream for reading from a file, if available. 300 | /// 301 | /// May fail with an error-code describing why the file cannot be read. 302 | /// 303 | /// Multiple read, write, and append streams may be active on the same open 304 | /// file and they do not interfere with each other. 305 | /// 306 | /// Note: This allows using `read-stream`, which is similar to `read` in POSIX. 307 | @since(version = 0.2.0) 308 | read-via-stream: func( 309 | /// The offset within the file at which to start reading. 310 | offset: filesize, 311 | ) -> result; 312 | 313 | /// Return a stream for writing to a file, if available. 314 | /// 315 | /// May fail with an error-code describing why the file cannot be written. 316 | /// 317 | /// Note: This allows using `write-stream`, which is similar to `write` in 318 | /// POSIX. 319 | @since(version = 0.2.0) 320 | write-via-stream: func( 321 | /// The offset within the file at which to start writing. 322 | offset: filesize, 323 | ) -> result; 324 | 325 | /// Return a stream for appending to a file, if available. 326 | /// 327 | /// May fail with an error-code describing why the file cannot be appended. 328 | /// 329 | /// Note: This allows using `write-stream`, which is similar to `write` with 330 | /// `O_APPEND` in POSIX. 331 | @since(version = 0.2.0) 332 | append-via-stream: func() -> result; 333 | 334 | /// Provide file advisory information on a descriptor. 335 | /// 336 | /// This is similar to `posix_fadvise` in POSIX. 337 | @since(version = 0.2.0) 338 | advise: func( 339 | /// The offset within the file to which the advisory applies. 340 | offset: filesize, 341 | /// The length of the region to which the advisory applies. 342 | length: filesize, 343 | /// The advice. 344 | advice: advice 345 | ) -> result<_, error-code>; 346 | 347 | /// Synchronize the data of a file to disk. 348 | /// 349 | /// This function succeeds with no effect if the file descriptor is not 350 | /// opened for writing. 351 | /// 352 | /// Note: This is similar to `fdatasync` in POSIX. 353 | @since(version = 0.2.0) 354 | sync-data: func() -> result<_, error-code>; 355 | 356 | /// Get flags associated with a descriptor. 357 | /// 358 | /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. 359 | /// 360 | /// Note: This returns the value that was the `fs_flags` value returned 361 | /// from `fdstat_get` in earlier versions of WASI. 362 | @since(version = 0.2.0) 363 | get-flags: func() -> result; 364 | 365 | /// Get the dynamic type of a descriptor. 366 | /// 367 | /// Note: This returns the same value as the `type` field of the `fd-stat` 368 | /// returned by `stat`, `stat-at` and similar. 369 | /// 370 | /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided 371 | /// by `fstat` in POSIX. 372 | /// 373 | /// Note: This returns the value that was the `fs_filetype` value returned 374 | /// from `fdstat_get` in earlier versions of WASI. 375 | @since(version = 0.2.0) 376 | get-type: func() -> result; 377 | 378 | /// Adjust the size of an open file. If this increases the file's size, the 379 | /// extra bytes are filled with zeros. 380 | /// 381 | /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. 382 | @since(version = 0.2.0) 383 | set-size: func(size: filesize) -> result<_, error-code>; 384 | 385 | /// Adjust the timestamps of an open file or directory. 386 | /// 387 | /// Note: This is similar to `futimens` in POSIX. 388 | /// 389 | /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. 390 | @since(version = 0.2.0) 391 | set-times: func( 392 | /// The desired values of the data access timestamp. 393 | data-access-timestamp: new-timestamp, 394 | /// The desired values of the data modification timestamp. 395 | data-modification-timestamp: new-timestamp, 396 | ) -> result<_, error-code>; 397 | 398 | /// Read from a descriptor, without using and updating the descriptor's offset. 399 | /// 400 | /// This function returns a list of bytes containing the data that was 401 | /// read, along with a bool which, when true, indicates that the end of the 402 | /// file was reached. The returned list will contain up to `length` bytes; it 403 | /// may return fewer than requested, if the end of the file is reached or 404 | /// if the I/O operation is interrupted. 405 | /// 406 | /// In the future, this may change to return a `stream`. 407 | /// 408 | /// Note: This is similar to `pread` in POSIX. 409 | @since(version = 0.2.0) 410 | read: func( 411 | /// The maximum number of bytes to read. 412 | length: filesize, 413 | /// The offset within the file at which to read. 414 | offset: filesize, 415 | ) -> result, bool>, error-code>; 416 | 417 | /// Write to a descriptor, without using and updating the descriptor's offset. 418 | /// 419 | /// It is valid to write past the end of a file; the file is extended to the 420 | /// extent of the write, with bytes between the previous end and the start of 421 | /// the write set to zero. 422 | /// 423 | /// In the future, this may change to take a `stream`. 424 | /// 425 | /// Note: This is similar to `pwrite` in POSIX. 426 | @since(version = 0.2.0) 427 | write: func( 428 | /// Data to write 429 | buffer: list, 430 | /// The offset within the file at which to write. 431 | offset: filesize, 432 | ) -> result; 433 | 434 | /// Read directory entries from a directory. 435 | /// 436 | /// On filesystems where directories contain entries referring to themselves 437 | /// and their parents, often named `.` and `..` respectively, these entries 438 | /// are omitted. 439 | /// 440 | /// This always returns a new stream which starts at the beginning of the 441 | /// directory. Multiple streams may be active on the same directory, and they 442 | /// do not interfere with each other. 443 | @since(version = 0.2.0) 444 | read-directory: func() -> result; 445 | 446 | /// Synchronize the data and metadata of a file to disk. 447 | /// 448 | /// This function succeeds with no effect if the file descriptor is not 449 | /// opened for writing. 450 | /// 451 | /// Note: This is similar to `fsync` in POSIX. 452 | @since(version = 0.2.0) 453 | sync: func() -> result<_, error-code>; 454 | 455 | /// Create a directory. 456 | /// 457 | /// Note: This is similar to `mkdirat` in POSIX. 458 | @since(version = 0.2.0) 459 | create-directory-at: func( 460 | /// The relative path at which to create the directory. 461 | path: string, 462 | ) -> result<_, error-code>; 463 | 464 | /// Return the attributes of an open file or directory. 465 | /// 466 | /// Note: This is similar to `fstat` in POSIX, except that it does not return 467 | /// device and inode information. For testing whether two descriptors refer to 468 | /// the same underlying filesystem object, use `is-same-object`. To obtain 469 | /// additional data that can be used do determine whether a file has been 470 | /// modified, use `metadata-hash`. 471 | /// 472 | /// Note: This was called `fd_filestat_get` in earlier versions of WASI. 473 | @since(version = 0.2.0) 474 | stat: func() -> result; 475 | 476 | /// Return the attributes of a file or directory. 477 | /// 478 | /// Note: This is similar to `fstatat` in POSIX, except that it does not 479 | /// return device and inode information. See the `stat` description for a 480 | /// discussion of alternatives. 481 | /// 482 | /// Note: This was called `path_filestat_get` in earlier versions of WASI. 483 | @since(version = 0.2.0) 484 | stat-at: func( 485 | /// Flags determining the method of how the path is resolved. 486 | path-flags: path-flags, 487 | /// The relative path of the file or directory to inspect. 488 | path: string, 489 | ) -> result; 490 | 491 | /// Adjust the timestamps of a file or directory. 492 | /// 493 | /// Note: This is similar to `utimensat` in POSIX. 494 | /// 495 | /// Note: This was called `path_filestat_set_times` in earlier versions of 496 | /// WASI. 497 | @since(version = 0.2.0) 498 | set-times-at: func( 499 | /// Flags determining the method of how the path is resolved. 500 | path-flags: path-flags, 501 | /// The relative path of the file or directory to operate on. 502 | path: string, 503 | /// The desired values of the data access timestamp. 504 | data-access-timestamp: new-timestamp, 505 | /// The desired values of the data modification timestamp. 506 | data-modification-timestamp: new-timestamp, 507 | ) -> result<_, error-code>; 508 | 509 | /// Create a hard link. 510 | /// 511 | /// Fails with `error-code::no-entry` if the old path does not exist, 512 | /// with `error-code::exist` if the new path already exists, and 513 | /// `error-code::not-permitted` if the old path is not a file. 514 | /// 515 | /// Note: This is similar to `linkat` in POSIX. 516 | @since(version = 0.2.0) 517 | link-at: func( 518 | /// Flags determining the method of how the path is resolved. 519 | old-path-flags: path-flags, 520 | /// The relative source path from which to link. 521 | old-path: string, 522 | /// The base directory for `new-path`. 523 | new-descriptor: borrow, 524 | /// The relative destination path at which to create the hard link. 525 | new-path: string, 526 | ) -> result<_, error-code>; 527 | 528 | /// Open a file or directory. 529 | /// 530 | /// If `flags` contains `descriptor-flags::mutate-directory`, and the base 531 | /// descriptor doesn't have `descriptor-flags::mutate-directory` set, 532 | /// `open-at` fails with `error-code::read-only`. 533 | /// 534 | /// If `flags` contains `write` or `mutate-directory`, or `open-flags` 535 | /// contains `truncate` or `create`, and the base descriptor doesn't have 536 | /// `descriptor-flags::mutate-directory` set, `open-at` fails with 537 | /// `error-code::read-only`. 538 | /// 539 | /// Note: This is similar to `openat` in POSIX. 540 | @since(version = 0.2.0) 541 | open-at: func( 542 | /// Flags determining the method of how the path is resolved. 543 | path-flags: path-flags, 544 | /// The relative path of the object to open. 545 | path: string, 546 | /// The method by which to open the file. 547 | open-flags: open-flags, 548 | /// Flags to use for the resulting descriptor. 549 | %flags: descriptor-flags, 550 | ) -> result; 551 | 552 | /// Read the contents of a symbolic link. 553 | /// 554 | /// If the contents contain an absolute or rooted path in the underlying 555 | /// filesystem, this function fails with `error-code::not-permitted`. 556 | /// 557 | /// Note: This is similar to `readlinkat` in POSIX. 558 | @since(version = 0.2.0) 559 | readlink-at: func( 560 | /// The relative path of the symbolic link from which to read. 561 | path: string, 562 | ) -> result; 563 | 564 | /// Remove a directory. 565 | /// 566 | /// Return `error-code::not-empty` if the directory is not empty. 567 | /// 568 | /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. 569 | @since(version = 0.2.0) 570 | remove-directory-at: func( 571 | /// The relative path to a directory to remove. 572 | path: string, 573 | ) -> result<_, error-code>; 574 | 575 | /// Rename a filesystem object. 576 | /// 577 | /// Note: This is similar to `renameat` in POSIX. 578 | @since(version = 0.2.0) 579 | rename-at: func( 580 | /// The relative source path of the file or directory to rename. 581 | old-path: string, 582 | /// The base directory for `new-path`. 583 | new-descriptor: borrow, 584 | /// The relative destination path to which to rename the file or directory. 585 | new-path: string, 586 | ) -> result<_, error-code>; 587 | 588 | /// Create a symbolic link (also known as a "symlink"). 589 | /// 590 | /// If `old-path` starts with `/`, the function fails with 591 | /// `error-code::not-permitted`. 592 | /// 593 | /// Note: This is similar to `symlinkat` in POSIX. 594 | @since(version = 0.2.0) 595 | symlink-at: func( 596 | /// The contents of the symbolic link. 597 | old-path: string, 598 | /// The relative destination path at which to create the symbolic link. 599 | new-path: string, 600 | ) -> result<_, error-code>; 601 | 602 | /// Unlink a filesystem object that is not a directory. 603 | /// 604 | /// Return `error-code::is-directory` if the path refers to a directory. 605 | /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. 606 | @since(version = 0.2.0) 607 | unlink-file-at: func( 608 | /// The relative path to a file to unlink. 609 | path: string, 610 | ) -> result<_, error-code>; 611 | 612 | /// Test whether two descriptors refer to the same filesystem object. 613 | /// 614 | /// In POSIX, this corresponds to testing whether the two descriptors have the 615 | /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. 616 | /// wasi-filesystem does not expose device and inode numbers, so this function 617 | /// may be used instead. 618 | @since(version = 0.2.0) 619 | is-same-object: func(other: borrow) -> bool; 620 | 621 | /// Return a hash of the metadata associated with a filesystem object referred 622 | /// to by a descriptor. 623 | /// 624 | /// This returns a hash of the last-modification timestamp and file size, and 625 | /// may also include the inode number, device number, birth timestamp, and 626 | /// other metadata fields that may change when the file is modified or 627 | /// replaced. It may also include a secret value chosen by the 628 | /// implementation and not otherwise exposed. 629 | /// 630 | /// Implementations are encouraged to provide the following properties: 631 | /// 632 | /// - If the file is not modified or replaced, the computed hash value should 633 | /// usually not change. 634 | /// - If the object is modified or replaced, the computed hash value should 635 | /// usually change. 636 | /// - The inputs to the hash should not be easily computable from the 637 | /// computed hash. 638 | /// 639 | /// However, none of these is required. 640 | @since(version = 0.2.0) 641 | metadata-hash: func() -> result; 642 | 643 | /// Return a hash of the metadata associated with a filesystem object referred 644 | /// to by a directory descriptor and a relative path. 645 | /// 646 | /// This performs the same hash computation as `metadata-hash`. 647 | @since(version = 0.2.0) 648 | metadata-hash-at: func( 649 | /// Flags determining the method of how the path is resolved. 650 | path-flags: path-flags, 651 | /// The relative path of the file or directory to inspect. 652 | path: string, 653 | ) -> result; 654 | } 655 | 656 | /// A stream of directory entries. 657 | @since(version = 0.2.0) 658 | resource directory-entry-stream { 659 | /// Read a single directory entry from a `directory-entry-stream`. 660 | @since(version = 0.2.0) 661 | read-directory-entry: func() -> result, error-code>; 662 | } 663 | 664 | /// Attempts to extract a filesystem-related `error-code` from the stream 665 | /// `error` provided. 666 | /// 667 | /// Stream operations which return `stream-error::last-operation-failed` 668 | /// have a payload with more information about the operation that failed. 669 | /// This payload can be passed through to this function to see if there's 670 | /// filesystem-related information about the error to return. 671 | /// 672 | /// Note that this function is fallible because not all stream-related 673 | /// errors are filesystem-related errors. 674 | @since(version = 0.2.0) 675 | filesystem-error-code: func(err: borrow) -> option; 676 | } 677 | -------------------------------------------------------------------------------- /wit/world.wit: -------------------------------------------------------------------------------- 1 | package wasi:filesystem@0.2.5; 2 | 3 | @since(version = 0.2.0) 4 | world imports { 5 | @since(version = 0.2.0) 6 | import types; 7 | @since(version = 0.2.0) 8 | import preopens; 9 | } 10 | --------------------------------------------------------------------------------