1package wasi:[email protected]; 2 3/// WASI filesystem is a filesystem API primarily intended to let users run WASI 4/// programs that access their files on their existing filesystems, without 5/// significant overhead. 6/// 7/// It is intended to be roughly portable between Unix-family platforms and 8/// Windows, though it does not hide many of the major differences. 9/// 10/// Paths are passed as interface-type `string`s, meaning they must consist of 11/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain 12/// paths which are not accessible by this API. 13/// 14/// The directory separator in WASI is always the forward-slash (`/`). 15/// 16/// All paths in WASI are relative paths, and are interpreted relative to a 17/// `descriptor` referring to a base directory. If a `path` argument to any WASI 18/// function starts with `/`, or if any step of resolving a `path`, including 19/// `..` and symbolic link steps, reaches a directory outside of the base 20/// directory, or reaches a symlink to an absolute or rooted path in the 21/// underlying filesystem, the function fails with `error-code::not-permitted`. 22/// 23/// For more information about WASI path resolution and sandboxing, see 24/// [WASI filesystem path resolution]. 25/// 26/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md 27@since(version = 0.2.0) 28interface types { 29 @since(version = 0.2.0) 30 use wasi:io/streams@0.2.6.{input-stream, output-stream, error}; 31 @since(version = 0.2.0) 32 use wasi:clocks/wall-clock@0.2.6.{datetime}; 33 34 /// File size or length of a region within a file. 35 @since(version = 0.2.0) 36 type filesize = u64; 37 38 /// The type of a filesystem object referenced by a descriptor. 39 /// 40 /// Note: This was called `filetype` in earlier versions of WASI. 41 @since(version = 0.2.0) 42 enum descriptor-type { 43 /// The type of the descriptor or file is unknown or is different from 44 /// any of the other types specified. 45 unknown, 46 /// The descriptor refers to a block device inode. 47 block-device, 48 /// The descriptor refers to a character device inode. 49 character-device, 50 /// The descriptor refers to a directory inode. 51 directory, 52 /// The descriptor refers to a named pipe. 53 fifo, 54 /// The file refers to a symbolic link inode. 55 symbolic-link, 56 /// The descriptor refers to a regular file inode. 57 regular-file, 58 /// The descriptor refers to a socket. 59 socket, 60 } 61 62 /// Descriptor flags. 63 /// 64 /// Note: This was called `fdflags` in earlier versions of WASI. 65 @since(version = 0.2.0) 66 flags descriptor-flags { 67 /// Read mode: Data can be read. 68 read, 69 /// Write mode: Data can be written to. 70 write, 71 /// Request that writes be performed according to synchronized I/O file 72 /// integrity completion. The data stored in the file and the file's 73 /// metadata are synchronized. This is similar to `O_SYNC` in POSIX. 74 /// 75 /// The precise semantics of this operation have not yet been defined for 76 /// WASI. At this time, it should be interpreted as a request, and not a 77 /// requirement. 78 file-integrity-sync, 79 /// Request that writes be performed according to synchronized I/O data 80 /// integrity completion. Only the data stored in the file is 81 /// synchronized. This is similar to `O_DSYNC` in POSIX. 82 /// 83 /// The precise semantics of this operation have not yet been defined for 84 /// WASI. At this time, it should be interpreted as a request, and not a 85 /// requirement. 86 data-integrity-sync, 87 /// Requests that reads be performed at the same level of integrity 88 /// requested for writes. This is similar to `O_RSYNC` in POSIX. 89 /// 90 /// The precise semantics of this operation have not yet been defined for 91 /// WASI. At this time, it should be interpreted as a request, and not a 92 /// requirement. 93 requested-write-sync, 94 /// Mutating directories mode: Directory contents may be mutated. 95 /// 96 /// When this flag is unset on a descriptor, operations using the 97 /// descriptor which would create, rename, delete, modify the data or 98 /// metadata of filesystem objects, or obtain another handle which 99 /// would permit any of those, shall fail with `error-code::read-only` if 100 /// they would otherwise succeed. 101 /// 102 /// This may only be set on directories. 103 mutate-directory, 104 } 105 106 /// Flags determining the method of how paths are resolved. 107 @since(version = 0.2.0) 108 flags path-flags { 109 /// As long as the resolved path corresponds to a symbolic link, it is 110 /// expanded. 111 symlink-follow, 112 } 113 114 /// Open flags used by `open-at`. 115 @since(version = 0.2.0) 116 flags open-flags { 117 /// Create file if it does not exist, similar to `O_CREAT` in POSIX. 118 create, 119 /// Fail if not a directory, similar to `O_DIRECTORY` in POSIX. 120 directory, 121 /// Fail if file already exists, similar to `O_EXCL` in POSIX. 122 exclusive, 123 /// Truncate file to size 0, similar to `O_TRUNC` in POSIX. 124 truncate, 125 } 126 127 /// Number of hard links to an inode. 128 @since(version = 0.2.0) 129 type link-count = u64; 130 131 /// File attributes. 132 /// 133 /// Note: This was called `filestat` in earlier versions of WASI. 134 @since(version = 0.2.0) 135 record descriptor-stat { 136 /// File type. 137 %type: descriptor-type, 138 /// Number of hard links to the file. 139 link-count: link-count, 140 /// For regular files, the file size in bytes. For symbolic links, the 141 /// length in bytes of the pathname contained in the symbolic link. 142 size: filesize, 143 /// Last data access timestamp. 144 /// 145 /// If the `option` is none, the platform doesn't maintain an access 146 /// timestamp for this file. 147 data-access-timestamp: option<datetime>, 148 /// Last data modification timestamp. 149 /// 150 /// If the `option` is none, the platform doesn't maintain a 151 /// modification timestamp for this file. 152 data-modification-timestamp: option<datetime>, 153 /// Last file status-change timestamp. 154 /// 155 /// If the `option` is none, the platform doesn't maintain a 156 /// status-change timestamp for this file. 157 status-change-timestamp: option<datetime>, 158 } 159 160 /// When setting a timestamp, this gives the value to set it to. 161 @since(version = 0.2.0) 162 variant new-timestamp { 163 /// Leave the timestamp set to its previous value. 164 no-change, 165 /// Set the timestamp to the current time of the system clock associated 166 /// with the filesystem. 167 now, 168 /// Set the timestamp to the given value. 169 timestamp(datetime), 170 } 171 172 /// A directory entry. 173 record directory-entry { 174 /// The type of the file referred to by this directory entry. 175 %type: descriptor-type, 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(offset: filesize) -> result<input-stream, error-code>; 309 /// Return a stream for writing to a file, if available. 310 /// 311 /// May fail with an error-code describing why the file cannot be written. 312 /// 313 /// Note: This allows using `write-stream`, which is similar to `write` in 314 /// POSIX. 315 @since(version = 0.2.0) 316 write-via-stream: func(offset: filesize) -> result<output-stream, error-code>; 317 /// Return a stream for appending to a file, if available. 318 /// 319 /// May fail with an error-code describing why the file cannot be appended. 320 /// 321 /// Note: This allows using `write-stream`, which is similar to `write` with 322 /// `O_APPEND` in POSIX. 323 @since(version = 0.2.0) 324 append-via-stream: func() -> result<output-stream, error-code>; 325 /// Provide file advisory information on a descriptor. 326 /// 327 /// This is similar to `posix_fadvise` in POSIX. 328 @since(version = 0.2.0) 329 advise: func(offset: filesize, length: filesize, advice: advice) -> result<_, error-code>; 330 /// Synchronize the data of a file to disk. 331 /// 332 /// This function succeeds with no effect if the file descriptor is not 333 /// opened for writing. 334 /// 335 /// Note: This is similar to `fdatasync` in POSIX. 336 @since(version = 0.2.0) 337 sync-data: func() -> result<_, error-code>; 338 /// Get flags associated with a descriptor. 339 /// 340 /// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX. 341 /// 342 /// Note: This returns the value that was the `fs_flags` value returned 343 /// from `fdstat_get` in earlier versions of WASI. 344 @since(version = 0.2.0) 345 get-flags: func() -> result<descriptor-flags, error-code>; 346 /// Get the dynamic type of a descriptor. 347 /// 348 /// Note: This returns the same value as the `type` field of the `fd-stat` 349 /// returned by `stat`, `stat-at` and similar. 350 /// 351 /// Note: This returns similar flags to the `st_mode & S_IFMT` value provided 352 /// by `fstat` in POSIX. 353 /// 354 /// Note: This returns the value that was the `fs_filetype` value returned 355 /// from `fdstat_get` in earlier versions of WASI. 356 @since(version = 0.2.0) 357 get-type: func() -> result<descriptor-type, error-code>; 358 /// Adjust the size of an open file. If this increases the file's size, the 359 /// extra bytes are filled with zeros. 360 /// 361 /// Note: This was called `fd_filestat_set_size` in earlier versions of WASI. 362 @since(version = 0.2.0) 363 set-size: func(size: filesize) -> result<_, error-code>; 364 /// Adjust the timestamps of an open file or directory. 365 /// 366 /// Note: This is similar to `futimens` in POSIX. 367 /// 368 /// Note: This was called `fd_filestat_set_times` in earlier versions of WASI. 369 @since(version = 0.2.0) 370 set-times: func(data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>; 371 /// Read from a descriptor, without using and updating the descriptor's offset. 372 /// 373 /// This function returns a list of bytes containing the data that was 374 /// read, along with a bool which, when true, indicates that the end of the 375 /// file was reached. The returned list will contain up to `length` bytes; it 376 /// may return fewer than requested, if the end of the file is reached or 377 /// if the I/O operation is interrupted. 378 /// 379 /// In the future, this may change to return a `stream<u8, error-code>`. 380 /// 381 /// Note: This is similar to `pread` in POSIX. 382 @since(version = 0.2.0) 383 read: func(length: filesize, offset: filesize) -> result<tuple<list<u8>, bool>, error-code>; 384 /// Write to a descriptor, without using and updating the descriptor's offset. 385 /// 386 /// It is valid to write past the end of a file; the file is extended to the 387 /// extent of the write, with bytes between the previous end and the start of 388 /// the write set to zero. 389 /// 390 /// In the future, this may change to take a `stream<u8, error-code>`. 391 /// 392 /// Note: This is similar to `pwrite` in POSIX. 393 @since(version = 0.2.0) 394 write: func(buffer: list<u8>, offset: filesize) -> result<filesize, error-code>; 395 /// Read directory entries from a directory. 396 /// 397 /// On filesystems where directories contain entries referring to themselves 398 /// and their parents, often named `.` and `..` respectively, these entries 399 /// are omitted. 400 /// 401 /// This always returns a new stream which starts at the beginning of the 402 /// directory. Multiple streams may be active on the same directory, and they 403 /// do not interfere with each other. 404 @since(version = 0.2.0) 405 read-directory: func() -> result<directory-entry-stream, error-code>; 406 /// Synchronize the data and metadata of a file to disk. 407 /// 408 /// This function succeeds with no effect if the file descriptor is not 409 /// opened for writing. 410 /// 411 /// Note: This is similar to `fsync` in POSIX. 412 @since(version = 0.2.0) 413 sync: func() -> result<_, error-code>; 414 /// Create a directory. 415 /// 416 /// Note: This is similar to `mkdirat` in POSIX. 417 @since(version = 0.2.0) 418 create-directory-at: func(path: string) -> result<_, error-code>; 419 /// Return the attributes of an open file or directory. 420 /// 421 /// Note: This is similar to `fstat` in POSIX, except that it does not return 422 /// device and inode information. For testing whether two descriptors refer to 423 /// the same underlying filesystem object, use `is-same-object`. To obtain 424 /// additional data that can be used do determine whether a file has been 425 /// modified, use `metadata-hash`. 426 /// 427 /// Note: This was called `fd_filestat_get` in earlier versions of WASI. 428 @since(version = 0.2.0) 429 stat: func() -> result<descriptor-stat, error-code>; 430 /// Return the attributes of a file or directory. 431 /// 432 /// Note: This is similar to `fstatat` in POSIX, except that it does not 433 /// return device and inode information. See the `stat` description for a 434 /// discussion of alternatives. 435 /// 436 /// Note: This was called `path_filestat_get` in earlier versions of WASI. 437 @since(version = 0.2.0) 438 stat-at: func(path-flags: path-flags, path: string) -> result<descriptor-stat, error-code>; 439 /// Adjust the timestamps of a file or directory. 440 /// 441 /// Note: This is similar to `utimensat` in POSIX. 442 /// 443 /// Note: This was called `path_filestat_set_times` in earlier versions of 444 /// WASI. 445 @since(version = 0.2.0) 446 set-times-at: func(path-flags: path-flags, path: string, data-access-timestamp: new-timestamp, data-modification-timestamp: new-timestamp) -> result<_, error-code>; 447 /// Create a hard link. 448 /// 449 /// Fails with `error-code::no-entry` if the old path does not exist, 450 /// with `error-code::exist` if the new path already exists, and 451 /// `error-code::not-permitted` if the old path is not a file. 452 /// 453 /// Note: This is similar to `linkat` in POSIX. 454 @since(version = 0.2.0) 455 link-at: func(old-path-flags: path-flags, old-path: string, new-descriptor: borrow<descriptor>, new-path: string) -> result<_, error-code>; 456 /// Open a file or directory. 457 /// 458 /// If `flags` contains `descriptor-flags::mutate-directory`, and the base 459 /// descriptor doesn't have `descriptor-flags::mutate-directory` set, 460 /// `open-at` fails with `error-code::read-only`. 461 /// 462 /// If `flags` contains `write` or `mutate-directory`, or `open-flags` 463 /// contains `truncate` or `create`, and the base descriptor doesn't have 464 /// `descriptor-flags::mutate-directory` set, `open-at` fails with 465 /// `error-code::read-only`. 466 /// 467 /// Note: This is similar to `openat` in POSIX. 468 @since(version = 0.2.0) 469 open-at: func(path-flags: path-flags, path: string, open-flags: open-flags, %flags: descriptor-flags) -> result<descriptor, error-code>; 470 /// Read the contents of a symbolic link. 471 /// 472 /// If the contents contain an absolute or rooted path in the underlying 473 /// filesystem, this function fails with `error-code::not-permitted`. 474 /// 475 /// Note: This is similar to `readlinkat` in POSIX. 476 @since(version = 0.2.0) 477 readlink-at: func(path: string) -> result<string, error-code>; 478 /// Remove a directory. 479 /// 480 /// Return `error-code::not-empty` if the directory is not empty. 481 /// 482 /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. 483 @since(version = 0.2.0) 484 remove-directory-at: func(path: string) -> result<_, error-code>; 485 /// Rename a filesystem object. 486 /// 487 /// Note: This is similar to `renameat` in POSIX. 488 @since(version = 0.2.0) 489 rename-at: func(old-path: string, new-descriptor: borrow<descriptor>, new-path: string) -> result<_, error-code>; 490 /// Create a symbolic link (also known as a "symlink"). 491 /// 492 /// If `old-path` starts with `/`, the function fails with 493 /// `error-code::not-permitted`. 494 /// 495 /// Note: This is similar to `symlinkat` in POSIX. 496 @since(version = 0.2.0) 497 symlink-at: func(old-path: string, new-path: string) -> result<_, error-code>; 498 /// Unlink a filesystem object that is not a directory. 499 /// 500 /// Return `error-code::is-directory` if the path refers to a directory. 501 /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. 502 @since(version = 0.2.0) 503 unlink-file-at: func(path: string) -> result<_, error-code>; 504 /// Test whether two descriptors refer to the same filesystem object. 505 /// 506 /// In POSIX, this corresponds to testing whether the two descriptors have the 507 /// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers. 508 /// wasi-filesystem does not expose device and inode numbers, so this function 509 /// may be used instead. 510 @since(version = 0.2.0) 511 is-same-object: func(other: borrow<descriptor>) -> bool; 512 /// Return a hash of the metadata associated with a filesystem object referred 513 /// to by a descriptor. 514 /// 515 /// This returns a hash of the last-modification timestamp and file size, and 516 /// may also include the inode number, device number, birth timestamp, and 517 /// other metadata fields that may change when the file is modified or 518 /// replaced. It may also include a secret value chosen by the 519 /// implementation and not otherwise exposed. 520 /// 521 /// Implementations are encouraged to provide the following properties: 522 /// 523 /// - If the file is not modified or replaced, the computed hash value should 524 /// usually not change. 525 /// - If the object is modified or replaced, the computed hash value should 526 /// usually change. 527 /// - The inputs to the hash should not be easily computable from the 528 /// computed hash. 529 /// 530 /// However, none of these is required. 531 @since(version = 0.2.0) 532 metadata-hash: func() -> result<metadata-hash-value, error-code>; 533 /// Return a hash of the metadata associated with a filesystem object referred 534 /// to by a directory descriptor and a relative path. 535 /// 536 /// This performs the same hash computation as `metadata-hash`. 537 @since(version = 0.2.0) 538 metadata-hash-at: func(path-flags: path-flags, path: string) -> result<metadata-hash-value, error-code>; 539 } 540 541 /// A stream of directory entries. 542 @since(version = 0.2.0) 543 resource directory-entry-stream { 544 /// Read a single directory entry from a `directory-entry-stream`. 545 @since(version = 0.2.0) 546 read-directory-entry: func() -> result<option<directory-entry>, error-code>; 547 } 548 549 /// Attempts to extract a filesystem-related `error-code` from the stream 550 /// `error` provided. 551 /// 552 /// Stream operations which return `stream-error::last-operation-failed` 553 /// have a payload with more information about the operation that failed. 554 /// This payload can be passed through to this function to see if there's 555 /// filesystem-related information about the error to return. 556 /// 557 /// Note that this function is fallible because not all stream-related 558 /// errors are filesystem-related errors. 559 @since(version = 0.2.0) 560 filesystem-error-code: func(err: borrow<error>) -> option<error-code>; 561} 562 563@since(version = 0.2.0) 564interface preopens { 565 @since(version = 0.2.0) 566 use types.{descriptor}; 567 568 /// Return the set of preopened directories, and their paths. 569 @since(version = 0.2.0) 570 get-directories: func() -> list<tuple<descriptor, string>>; 571} 572 573@since(version = 0.2.0) 574world imports { 575 @since(version = 0.2.0) 576 import wasi:io/error@0.2.6; 577 @since(version = 0.2.0) 578 import wasi:io/poll@0.2.6; 579 @since(version = 0.2.0) 580 import wasi:io/streams@0.2.6; 581 @since(version = 0.2.0) 582 import wasi:clocks/wall-clock@0.2.6; 583 @since(version = 0.2.0) 584 import types; 585 @since(version = 0.2.0) 586 import preopens; 587} 588