Skip to content

Commit

Permalink
Merge pull request #35 from ansemjo/readonly-files
Browse files Browse the repository at this point in the history
Add readonly flag to Files
  • Loading branch information
bjorn3 authored Jul 2, 2023
2 parents 8056e62 + 1c1a2fd commit db998fe
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
29 changes: 23 additions & 6 deletions src/fs_core.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { OpenDirectory, OpenFile, OpenSyncOPFSFile } from "./fs_fd.js";
import * as wasi from "./wasi_defs.js";

// options that can be passed to Files and SyncOPFSFiles
type FileOptions = Partial<{
readonly: boolean;
}>;

export class File {
data: Uint8Array;
readonly: boolean;

constructor(data: ArrayBuffer | Uint8Array | Array<number>) {
//console.log(data);
constructor(data: ArrayBuffer | SharedArrayBuffer | Uint8Array | Array<number>, options?: FileOptions) {
this.data = new Uint8Array(data);
this.readonly = !!options?.readonly;
}

open(fd_flags: number) {
Expand All @@ -23,8 +29,10 @@ export class File {
return new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, this.size);
}

truncate() {
truncate(): number {
if (this.readonly) return wasi.ERRNO_PERM;
this.data = new Uint8Array([]);
return wasi.ERRNO_SUCCESS;
}
}

Expand All @@ -42,8 +50,14 @@ export interface FileSystemSyncAccessHandle {
// Synchronous access to an individual file in the origin private file system.
// Only allowed inside a WebWorker.
export class SyncOPFSFile {
handle: FileSystemSyncAccessHandle;
readonly: boolean;

// FIXME needs a close() method to be called after start() to release the underlying handle
constructor(public handle: FileSystemSyncAccessHandle) { }
constructor(handle: FileSystemSyncAccessHandle, options?: FileOptions) {
this.handle = handle;
this.readonly = !!options?.readonly;
}

open(fd_flags: number) {
let file = new OpenSyncOPFSFile(this);
Expand All @@ -59,14 +73,17 @@ export class SyncOPFSFile {
return new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, this.size);
}

truncate() {
return this.handle.truncate(0);
truncate(): number {
if (this.readonly) return wasi.ERRNO_PERM;
this.handle.truncate(0);
return wasi.ERRNO_SUCCESS;
}

}

export class Directory {
contents: { [key: string]: File | Directory | SyncOPFSFile };
readonly = false; // FIXME implement, like marking all files within readonly?

constructor(contents: { [key: string]: File | Directory | SyncOPFSFile }) {
this.contents = contents;
Expand Down
33 changes: 22 additions & 11 deletions src/fs_fd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class OpenFile extends Fd {
iovs: Array<wasi.Ciovec>
): { ret: number; nwritten: number } {
let nwritten = 0;
if (this.file.readonly) return { ret: wasi.ERRNO_BADF, nwritten };
for (let iovec of iovs) {
let buffer = view8.slice(iovec.buf, iovec.buf + iovec.buf_len);
if (this.file_pos + BigInt(buffer.byteLength) > this.file.size) {
Expand All @@ -103,28 +104,28 @@ export class OpenFile extends Fd {
}

export class OpenSyncOPFSFile extends Fd {
handle: FileSystemSyncAccessHandle;
file: SyncOPFSFile;
position: bigint = 0n;

constructor(file: SyncOPFSFile) {
super();
this.handle = file.handle;
this.file = file;
};

fd_fdstat_get(): { ret: number; fdstat: wasi.Fdstat | null } {
return { ret: 0, fdstat: new wasi.Fdstat(wasi.FILETYPE_REGULAR_FILE, 0) };
}

fd_filestat_get(): { ret: number; filestat: wasi.Filestat } {
return { ret: 0, filestat: new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, BigInt(this.handle.getSize())) };
return { ret: 0, filestat: new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, BigInt(this.file.handle.getSize())) };
}

fd_read(view8: Uint8Array, iovs: Array<wasi.Iovec>): { ret: number, nread: number } {
let nread = 0;
for (let iovec of iovs) {
if (this.position < this.handle.getSize()) {
if (this.position < this.file.handle.getSize()) {
let buf = new Uint8Array(view8.buffer, iovec.buf, iovec.buf_len);
let n = this.handle.read(buf, { at: Number(this.position) });
let n = this.file.handle.read(buf, { at: Number(this.position) });
this.position += BigInt(n);
nread += n;
} else {
Expand All @@ -144,7 +145,7 @@ export class OpenSyncOPFSFile extends Fd {
calculated_offset = this.position + BigInt(offset);
break;
case wasi.WHENCE_END:
calculated_offset = BigInt(this.handle.getSize()) + BigInt(offset);
calculated_offset = BigInt(this.file.handle.getSize()) + BigInt(offset);
break;
default:
return { ret: wasi.ERRNO_INVAL, offset: 0n };
Expand All @@ -158,18 +159,19 @@ export class OpenSyncOPFSFile extends Fd {

fd_write(view8: Uint8Array, iovs: Array<wasi.Iovec>): { ret: number, nwritten: number } {
let nwritten = 0;
if (this.file.readonly) return { ret: wasi.ERRNO_BADF, nwritten };
for (let iovec of iovs) {
let buf = new Uint8Array(view8.buffer, iovec.buf, iovec.buf_len);
// don't need to extend file manually, just write
let n = this.handle.write(buf, { at: Number(this.position) });
let n = this.file.handle.write(buf, { at: Number(this.position) });
this.position += BigInt(n);
nwritten += n;
}
return { ret: wasi.ERRNO_SUCCESS, nwritten };
}

fd_datasync(): number {
this.handle.flush();
this.file.handle.flush();
return wasi.ERRNO_SUCCESS;
}

Expand Down Expand Up @@ -251,9 +253,18 @@ export class OpenDirectory extends Fd {
) {
return { ret: -1, fd_obj: null };
}
if ((oflags & wasi.OFLAGS_TRUNC) == wasi.OFLAGS_TRUNC) {
// @ts-ignore
entry.truncate();
if (entry.readonly &&
(fs_rights_base & BigInt(wasi.RIGHTS_FD_WRITE)) == BigInt(wasi.RIGHTS_FD_WRITE)
) {
return { ret: wasi.ERRNO_PERM, fd_obj: null };
}
if (
(!(entry instanceof Directory)) &&
(oflags & wasi.OFLAGS_TRUNC) == wasi.OFLAGS_TRUNC
) {
let ret = entry.truncate();
if (ret != wasi.ERRNO_SUCCESS)
return { ret, fd_obj: null };
}
return { ret: 0, fd_obj: entry.open(fd_flags) };
}
Expand Down

0 comments on commit db998fe

Please sign in to comment.