Skip to content

Commit

Permalink
adding a little support for fsync/flush (?)
Browse files Browse the repository at this point in the history
  • Loading branch information
williamstein committed Aug 20, 2023
1 parent d283dd2 commit be14a98
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 25 deletions.
22 changes: 21 additions & 1 deletion lib/fuse/sftp-fuse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ afterAll(async () => {
await fuse?.unmount();
});

describe("Check many functions...", () => {
describe("Simple tests of each of the FUSE operations...", () => {
it("readdir starts empty", async () => {
expect(await fs.readdir(source)).toEqual([]);
expect(await fs.readdir(target)).toEqual([]);
Expand Down Expand Up @@ -194,3 +194,23 @@ describe("Check many functions...", () => {
await fs.rm(path.join(target, "a dir"), { recursive: true });
});
});

describe("more stressful tests", () => {
let repo, logLength;
it("clones the websocketfs git repo", async () => {
repo = path.join(source, "websocketfs"); // easy for now!
await callback(execFile, "git", ["clone", ".", repo]);
const v = await callback(execFile, "git", ["log", "."], { cwd: repo });
logLength = v.split("\n").length;
expect(logLength).toBeGreaterThan(2500);

repo = path.join(target, "websocketfs"); // make test below hard
});

// it("get the git log several times to make sure it is working and handles aren't leaking", async () => {
// for (let i = 0; i < 2; i++) {
// const v = await callback(execFile, "git", ["log", "."], { cwd: repo });
// expect(v.split("\n").length).toBe(logLength);
// }
// });
});
52 changes: 29 additions & 23 deletions lib/fuse/sftp-fuse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,38 +71,39 @@ export default class SftpFuse {
this.getattr(path, fuseError(cb));
}

// flush(path: string, _fd: number, cb) {
// log("flush", path);
// // TODO: this will impact caching...?
// cb(0);
// }
flush(path: string, fd: number, cb) {
log("flush", { path, fd });
cb(0);
}

// fsync(path: string, _fd: number, _datasync, cb) {
// log("fsync", path);
// cb(0);
// }
fsync(path: string, dataSync: boolean, fd: number, cb: Callback) {
log("fsync", { path, dataSync, fd });
cb(0);
}

// fsyncdir(path: string, _fd: number, _datasync, cb) {
// log("fsyncdir", path);
// cb(0);
// }
fsyncdir(path: string, dataSync: boolean, fd: number, cb: Callback) {
log("fsyncdir", { path, dataSync, fd });
cb(0);
}

async readdir(path: string, cb) {
log("readdir", path);
try {
const handle = await callback(this.sftp.opendir, path);
log("readdir - opendir got a handle", handle._handle);
const items = await callback(this.sftp.readdir, handle);
let handle, items;
try {
handle = await callback(this.sftp.opendir, path);
log("readdir - opendir got a handle", handle._handle);
items = await callback(this.sftp.readdir, handle);
} finally {
await callback(this.sftp.close, handle);
}
//log("readdir - items", items);
// todo: cache attrs from items (?)
if (typeof items == "boolean") {
throw Error("readdir fail");
}
cb(
0,
items.map(({ filename }) => filename),
);
return items;
const filenames = items.map(({ filename }) => filename);
cb(0, filenames);
} catch (err) {
log("readdir - error", err);
fuseError(cb)(err);
Expand Down Expand Up @@ -205,7 +206,8 @@ export default class SftpFuse {
position: number,
cb: Callback,
) {
log("write", { path, fd, buffer: buffer.toString(), length, position });
//log("write", { path, fd, buffer: buffer.toString(), length, position });
log("write", { path, fd, length, position });
const handle = this.sftp.fileDescriptorToHandle(fd);
this.sftp.write(handle, buffer, 0, length, position, (err) => {
if (err) {
Expand All @@ -223,7 +225,11 @@ export default class SftpFuse {
this.sftp.close(handle, fuseError(cb));
}

// releasedir(path, fd, cb)
releasedir(path, fd, cb: Callback) {
log("releasedir", { path, fd });
const handle = this.sftp.fileDescriptorToHandle(fd);
this.sftp.close(handle, fuseError(cb));
}

create(path: string, mode: number, cb: Callback) {
log("create", { path, mode });
Expand Down
1 change: 1 addition & 0 deletions lib/sftp/fs-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,5 @@ export interface IFilesystem {
blockSize: number,
callback: (err: Error | null, hashes?: Buffer, alg?: string) => any,
): void;
fsync?(handle: number, callback: (err: Error | null) => any): void;
}
4 changes: 4 additions & 0 deletions lib/sftp/fs-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export class LocalFilesystem implements IFilesystem {
//LATER: pay attemtion to attrs other than mode (low priority - many SFTP servers ignore these as well)
}

fsync(handle: number, callback: (err: Error | null) => any): void {
fs.fsync(handle, callback);
}

close(handle: any, callback: (err: Error | null) => any): void {
this.checkCallback(callback);

Expand Down
16 changes: 15 additions & 1 deletion lib/sftp/fs-safe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class SafeFilesystem implements IFilesystem {

private _handles: HandleToHandleInfoMap;
private _nextHandle: number;
private static MAX_HANDLE_COUNT = 1024; // standard linux default
private static MAX_HANDLE_COUNT = 1024; // 1024 = standard linux default...

constructor(
fs: IFilesystem,
Expand Down Expand Up @@ -588,6 +588,20 @@ export class SafeFilesystem implements IFilesystem {
}
}

fsync(handle: number, callback: (err: Error | null) => void): void {
this._execute(
handle,
(handle, callback) => {
if (this.fs.fsync != null) {
this.fs.fsync(handle, callback);
} else {
FileUtil.fail("ENOSYS", callback);
}
},
callback,
);
}

fcopy(
fromHandle: number,
fromPosition: number,
Expand Down
9 changes: 9 additions & 0 deletions lib/sftp/sftp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,15 @@ export class SftpServerSession {
fs.write(handle, request.buffer, offset, count, position, (err) =>
this.sendSuccess(response, err),
);

// I was playing around with syncing on write:
// fs.write(handle, request.buffer, offset, count, position, (err) => {
// if (err || handle == null || fs.fsync == null) {
// this.sendSuccess(response, err);
// } else {
// fs.fsync(handle, (err) => this.sendSuccess(response, err));
// }
// });
return;

case SftpPacketType.LSTAT:
Expand Down

0 comments on commit be14a98

Please sign in to comment.