Skip to content

Commit

Permalink
Merge pull request #19 from ktock/filebuf
Browse files Browse the repository at this point in the history
Fix workspace mapping issues
  • Loading branch information
ktock authored Mar 12, 2024
2 parents 1919e5f + 02355b5 commit 6fc127f
Showing 1 changed file with 89 additions and 32 deletions.
121 changes: 89 additions & 32 deletions src/vendor/wasm-wasi-core/src/common/vscodeFileSystemDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { LRUCache } from './linkedMap';
import { u64, size } from './baseTypes';
import {
fdstat, filestat, Rights, fd, rights, fdflags, Filetype, WasiError, Errno, filetype, Whence,
lookupflags, timestamp, fstflags, oflags, Oflags, filesize, Fdflags, inode, Lookupflags
lookupflags, timestamp, fstflags, Fstflags, oflags, Oflags, filesize, Fdflags, inode, Lookupflags
} from './wasi';
import { BigInts, code2Wasi } from './converter';
import { BaseFileDescriptor, FdProvider, FileDescriptor } from './fileDescriptor';
Expand Down Expand Up @@ -128,6 +128,10 @@ type FileNode = {
* generation
*/
name: string | undefined;

/* Cached timestamp */
mtime: number | undefined;
ctime: number | undefined;
};

namespace FileNode {
Expand All @@ -137,7 +141,9 @@ namespace FileNode {
inode: id,
refs: 0,
parent,
name: undefined
name: undefined,
mtime: undefined,
ctime: undefined,
};
}
}
Expand Down Expand Up @@ -171,6 +177,10 @@ type DirectoryNode = {
* generation
*/
name: string | undefined;

/* Cached timestamp */
mtime: number | undefined;
ctime: number | undefined;
};

type Node = FileNode | DirectoryNode;
Expand All @@ -183,7 +193,9 @@ namespace DirectoryNode {
refs: 0,
parent,
name: undefined,
entries: new Map()
entries: new Map(),
mtime: undefined,
ctime: undefined,
};
}
}
Expand All @@ -196,8 +208,6 @@ class FileSystem {
private readonly root: DirectoryNode;

private readonly inodes: Map<inode, Node>;
// Cache contents of files
private readonly contents: Map<inode, Uint8Array>;
// Cached stats for deleted files and directories if there is still
// an open file descriptor
private readonly stats: Map<inode, FileStat>;
Expand All @@ -212,12 +222,13 @@ class FileSystem {
parent: undefined,
refs: 1,
name: '/',
entries: new Map()
entries: new Map(),
mtime: undefined,
ctime: undefined,
};

this.inodes = new Map();
this.inodes.set(this.root.inode, this.root);
this.contents = new Map();
this.stats = new Map();
this.deletedNodes = new Map();
this.pathCache = new LRUCache(256);
Expand Down Expand Up @@ -247,6 +258,12 @@ class FileSystem {
return node;
}

public touchMCtime(inode: FileNode | DirectoryNode) {
const now: number = new Date().getTime();
inode.mtime = now;
inode.ctime = now;
}

public getOrCreateNode(parent: DirectoryNode, path: string, kind: NodeKind, ref: boolean): FileNode | DirectoryNode {
const parts = this.getPathSegments(path);
if (parts.length === 1) {
Expand Down Expand Up @@ -281,6 +298,7 @@ class FileSystem {
current.entries.set(parts[i], entry);
// Cache the name for faster lookup.
entry.name = parts[i];
this.touchMCtime(current);
this.inodes.set(entry.inode, entry);
} else {
if (i === parts.length - 1 && ref) {
Expand Down Expand Up @@ -329,16 +347,8 @@ class FileSystem {
return this.getNodeByPath(parent, path) !== undefined;
}

public setContent(inode: FileNode, content: Uint8Array): void {
this.contents.set(inode.inode, content);
}

public async getContent(inode: FileNode, contentProvider: { readFile(uri: Uri): Thenable<Uint8Array> }): Promise<Uint8Array> {
let content = this.contents.get(inode.inode);
if (content === undefined) {
content = await contentProvider.readFile(this.getUri(inode));
this.contents.set(inode.inode, content);
}
let content = await contentProvider.readFile(this.getUri(inode));
return Promise.resolve(content);
}

Expand All @@ -362,9 +372,6 @@ class FileSystem {
}
const name = this.getName(node);
node.parent.entries.delete(name);
if (content !== undefined) {
this.contents.set(node.inode, content);
}
if (stat !== undefined) {
this.stats.set(node.inode, stat);
}
Expand All @@ -388,7 +395,6 @@ class FileSystem {
node.refs--;
if (node.refs === 0) {
if (node.kind === NodeKind.File) {
this.contents.delete(node.inode);
this.stats.delete(node.inode);
}
this.deletedNodes.delete(node.inode);
Expand Down Expand Up @@ -566,9 +572,6 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
async function writeContent(node: FileNode, content?: Uint8Array): Promise<void> {
const toWrite = content ?? await fs.getContent(node, vscode_fs);
await vscode_fs.writeFile(fs.getUri(node), toWrite);
if (content !== undefined) {
fs.setContent(node, content);
}
}

const $this: FileSystemDeviceDriver = {
Expand Down Expand Up @@ -645,6 +648,8 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
}
const inode = fs.getNode(fileDescriptor.inode);
const vStat: FileStat = await vscode_fs.stat(fs.getUri(inode));
vStat.ctime = inode.ctime || vStat.ctime;
vStat.mtime = inode.mtime || vStat.mtime;
assignStat(result, inode.inode, vStat);
},
async fd_filestat_set_size(fileDescriptor: FileDescriptor, _size: bigint): Promise<void> {
Expand All @@ -659,17 +664,36 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
const newContent = new Uint8Array(size);
newContent.set(content);
await writeContent(node, newContent);
fs.touchMCtime(node);
} else if (content.byteLength > size) {
const newContent = new Uint8Array(size);
newContent.set(content.subarray(0, size));
await writeContent(node, newContent);
fs.touchMCtime(node);
}
},
fd_filestat_set_times(_fileDescriptor: FileDescriptor, _atim: bigint, _mtim: bigint, _fst_flags: fstflags): Promise<void> {
// For new we do nothing. We could cache the timestamp in memory
// But we would loose them during reload. We could also store them
async fd_filestat_set_times(fileDescriptor: FileDescriptor, atim: bigint, mtim: bigint, fst_flags: fstflags): Promise<void> {
// We would loose timestamp during reload. We could also store them
// in local storage
throw new WasiError(Errno.nosys);
const node = fs.getNode(fileDescriptor.inode);
var tim: number = 0;
var doset: boolean = false;
const now: number = new Date().getTime();
// TODO: atime
if (Fstflags.mtimOn(fst_flags)) {
tim = BigInts.asNumber(mtim / 1000000n)
doset = true;
}
if (Fstflags.mtim_nowOn(fst_flags)) {
tim = now;
doset = true;
}
if (!doset) {
return Promise.resolve();
}
node.mtime = now;
node.ctime = now;
return Promise.resolve();
},
async fd_pread(fileDescriptor: FileDescriptor, _offset: filesize, buffers: Uint8Array[]): Promise<size> {
const offset = BigInts.asNumber(_offset);
Expand All @@ -681,6 +705,7 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
const inode = fs.getNode(fileDescriptor.inode, NodeKind.File);
const [newContent, bytesWritten] = write(await fs.getContent(inode, vscode_fs), offset, buffers);
await writeContent(inode, newContent);
fs.touchMCtime(inode);
return bytesWritten;
},
async fd_read(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise<number> {
Expand Down Expand Up @@ -755,25 +780,51 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
fileDescriptor.cursor = content.byteLength;
}
const [newContent, bytesWritten] = write(content, fileDescriptor.cursor, buffers);
fs.touchMCtime(inode);
await writeContent(inode,newContent);
fileDescriptor.cursor = fileDescriptor.cursor + bytesWritten;
return bytesWritten;
},
async path_create_directory(fileDescriptor: FileDescriptor, path: string): Promise<void> {
const inode = fs.getNode(fileDescriptor.inode, NodeKind.Directory);
await vscode_fs.createDirectory(fs.getUri(inode, path));
fs.touchMCtime(inode);
},
async path_filestat_get(fileDescriptor: FileDescriptor, _flags: lookupflags, path: string, result: filestat): Promise<void> {
assertDirectoryDescriptor(fileDescriptor);
const inode = fs.getNode(fileDescriptor.inode, NodeKind.Directory);
const vStat: FileStat = await vscode_fs.stat(fs.getUri(inode, path));
const cinode = fs.getNodeByPath(inode, path);
if (cinode != undefined) {
vStat.ctime = cinode.ctime || vStat.ctime;
vStat.mtime = cinode.mtime || vStat.mtime;
}
assignStat(result, fs.getOrCreateNode(inode, path, vStat.type === FileType.Directory ? NodeKind.Directory : NodeKind.File, false).inode, vStat);
},
path_filestat_set_times(_fileDescriptor: FileDescriptor, _flags: lookupflags, _path: string, _atim: timestamp, _mtim: timestamp, _fst_flags: fstflags): Promise<void> {
// For now we do nothing. We could cache the timestamp in memory
// But we would loose them during reload. We could also store them
async path_filestat_set_times(fileDescriptor: FileDescriptor, _flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags): Promise<void> {
// We would loose timestamp during reload. We could also store them
// in local storage
throw new WasiError(Errno.nosys);
const inodep = fs.getNode(fileDescriptor.inode, NodeKind.Directory);
const vStat: FileStat = await vscode_fs.stat(fs.getUri(inodep, path));
const node = fs.getOrCreateNode(inodep, path, vStat.type === FileType.Directory ? NodeKind.Directory : NodeKind.File, false)
// TODO: atime
var tim: number = 0;
var doset: boolean = false;
const now: number = new Date().getTime();
if (Fstflags.mtimOn(fst_flags)) {
tim = BigInts.asNumber(mtim / 1000000n)
doset = true;
}
if (Fstflags.mtim_nowOn(fst_flags)) {
tim = now;
doset = true;
}
if (!doset) {
return Promise.resolve();
}
node.mtime = now;
node.ctime = now;
return Promise.resolve();
},
path_link(_oldFileDescriptor: FileDescriptor, _old_flags: lookupflags, _old_path: string, _newFileDescriptor: FileDescriptor, _new_path: string): Promise<void> {
// For now we do nothing. If we need to implement this we need
Expand Down Expand Up @@ -855,6 +906,8 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
if (targetNode !== undefined && targetNode.refs > 0) {
try {
filestat = await vscode_fs.stat(fs.getUri(targetNode));
filestat.ctime = targetNode.ctime || filestat.ctime;
filestat.mtime = targetNode.mtime || filestat.mtime;
} catch {
filestat = { type: FileType.Directory, ctime: Date.now(), mtime: Date.now(), size: 0 };
}
Expand Down Expand Up @@ -884,6 +937,8 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
try {
const uri = fs.getUri(oldNode);
filestat = await vscode_fs.stat(uri);
filestat.ctime = oldNode.ctime || filestat.ctime;
filestat.mtime = oldNode.mtime || filestat.mtime;
if (oldNode.kind === NodeKind.File) {
content = await vscode_fs.readFile(uri);
}
Expand Down Expand Up @@ -915,6 +970,8 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
try {
const uri = fs.getUri(targetNode);
filestat = await vscode_fs.stat(uri);
filestat.ctime = targetNode.ctime || filestat.ctime;
filestat.mtime = targetNode.mtime || filestat.mtime;
content = await vscode_fs.readFile(uri);
} catch {
filestat = { type: FileType.File, ctime: Date.now(), mtime: Date.now(), size: 0 };
Expand All @@ -941,4 +998,4 @@ export function create(deviceId: DeviceId, baseUri: Uri, readOnly: boolean = fal
};

return Object.assign({}, NoSysDeviceDriver, $this, readOnly ? WritePermDeniedDeviceDriver : {});
}
}

0 comments on commit 6fc127f

Please sign in to comment.