Skip to content

Commit

Permalink
Merge pull request #7 from divyenduz/fix_symlinks_and_links
Browse files Browse the repository at this point in the history
fix: symlinks and links
  • Loading branch information
divyenduz authored Nov 1, 2023
2 parents 73ca0bd + 07167bb commit 58b5fb8
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 163 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
tsconfig.tsbuildinfo
img.png

*.log

# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
Expand Down
28 changes: 13 additions & 15 deletions packages/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { File } from "@prisma/client";
import { File, Link } from "@prisma/client";

type FileType = "file" | "dir" | "symlink";

type Result<T> =
| {
type Result<T, K extends string = "file"> =
| ({
status: "ok";
file: T;
}
} & { [P in K]: T })
| {
status: "not_found";
};

// TODO: bump this based on the latest state of the actual backend!

export interface Backend {
getFiles: (dir: string) => Promise<File[]>;
// TODO: use resule
getLinks: (dir: string) => Promise<Link[]>;
getLink: (dir: string) => Promise<Result<Link, "link">>;
getFile: (filepath: string) => Promise<Result<File>>;

createFile: (
Expand All @@ -23,16 +24,13 @@ export interface Backend {
mode: number,
uid: number,
gid: number,
targetId: number
) => Promise<Result<File>>;

writeFile: (
filepath: string,
uid: number,
gid: number
targetPath: string
) => Promise<Result<File>>;

deleteFile: (filepath: string) => Promise<Result<File>>;
renameFile: (srcPath: string, destPath: string) => Promise<Result<File>>;
deleteFile: (filepath: string) => Promise<Result<number, "count">>;
renameFile: (
srcPath: string,
destPath: string
) => Promise<Result<Link, "link">>;
updateMode: (filepath: string, mode: number) => Promise<Result<File>>;
}
9 changes: 5 additions & 4 deletions packages/fuse-client/syscalls/getattr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@ export const getattr: (backend: SQLiteBackend) => MountOptions["getattr"] = (
backend
) => {
return async (path, cb) => {
console.log("getattr(%s)", path);
console.info("getattr(%s)", path);
const r = await backend.getFile(path);

await match(r)
.with({ status: "ok" }, async (r) => {
const rSize = await backend.getFileSize(path);
if (rSize.status !== "ok") {
cb(fuse.ENOENT);
return;
}

const rNlinks = await backend.getFileNLinks(path);
const { mtime, atime, ctime, mode } = r.file;
cb(0, {
mtime,
atime,
ctime,
nlink: 1,
blocks: 1,
ino: r.file.id,
nlink: rNlinks.nLinks?.length || 1,
size: rSize.size,
mode: mode,
// TODO: enable posix mode where real uid/gid are returned
Expand Down
2 changes: 1 addition & 1 deletion packages/fuse-client/syscalls/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const init: (backend: SQLiteBackend) => MountOptions["init"] = (
backend
) => {
return async (cb) => {
console.log("init");
console.info("init");

//@ts-expect-error fix types
const context = fuse.context();
Expand Down
25 changes: 18 additions & 7 deletions packages/fuse-client/syscalls/link.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { SQLiteBackend } from "@zoid-fs/sqlite-backend";
import { MountOptions } from "@zoid-fs/node-fuse-bindings";
import { symlink } from "./symlink";
import fuse, { MountOptions } from "@zoid-fs/node-fuse-bindings";
import { match } from "ts-pattern";

export const link: (backend: SQLiteBackend) => MountOptions["link"] = (
backend
) => {
return async (src, dest, cb) => {
console.log("link(%s, %s)", src, dest);
//@ts-expect-error fix types
// TODO: implement link properly
symlink(backend)(src, dest, cb);
return async (srcPath, destPath, cb) => {
console.info("link(%s, %s)", srcPath, destPath);

// TODO: throw if destination doesn't exist

// TODO: double check if mode for link is correct
// https://unix.stackexchange.com/questions/193465/what-file-mode-is-a-link
const r = await backend.createLink(srcPath, destPath);
match(r)
.with({ status: "ok" }, () => {
cb(0);
})
.with({ status: "not_found" }, () => {
cb(fuse.ENOENT);
})
.exhaustive();
};
};
2 changes: 1 addition & 1 deletion packages/fuse-client/syscalls/open.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const open: (backend: SQLiteBackend) => MountOptions["open"] = (
backend
) => {
return async (path, flags, cb) => {
console.log("open(%s, %d)", path, flags);
console.info("open(%s, %d)", path, flags);
const r = await backend.getFile(path);

match(r)
Expand Down
2 changes: 1 addition & 1 deletion packages/fuse-client/syscalls/opendir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const opendir: (backend: SQLiteBackend) => MountOptions["opendir"] = (
backend
) => {
return async (path, flags, cb) => {
console.log("opendir(%s, %d)", path, flags);
console.info("opendir(%s, %d)", path, flags);

if (path === "/") {
cb(0, 42); // TODO: Universal FD for root dir, it should probably be in the database as bootstrap
Expand Down
4 changes: 2 additions & 2 deletions packages/fuse-client/syscalls/readdir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const readdir: (backend: SQLiteBackend) => MountOptions["readdir"] = (
// TODO: figure out how are these directories in output of ls -la
const dotDirs = [".", ".."];

const files = await backend.getFiles(path);
const fileNames = dotDirs.concat(files.map((file) => file.name));
const links = await backend.getLinks(path);
const fileNames = dotDirs.concat(links.map((link) => link.name));

return cb(0, fileNames);
};
Expand Down
29 changes: 18 additions & 11 deletions packages/fuse-client/syscalls/readlink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ export const readlink: (backend: SQLiteBackend) => MountOptions["readlink"] = (
backend
) => {
return async (path, cb) => {
console.log("readlink(%s)", path);
const r = await backend.getFile(path);
match(r)
.with({ status: "ok" }, (r) => {
cb(0, r.file.name);
})
.with({ status: "not_found" }, () => {
//@ts-expect-error fix types, what to do if readlink fails?
cb(fuse.ENOENT);
})
.exhaustive();
console.info("readlink(%s)", path);
try {
const r = await backend.getLink(path);
match(r)
.with({ status: "ok" }, (r) => {
cb(0, r.link.targetPath);
})
.with({ status: "not_found" }, () => {
//@ts-expect-error fix types, what to do if readlink fails?
cb(fuse.ENOENT);
})
.exhaustive();
} catch (e) {
console.error(e);
return {
status: "not_found" as const,
};
}
};
};
22 changes: 15 additions & 7 deletions packages/fuse-client/syscalls/symlink.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { SQLiteBackend } from "@zoid-fs/sqlite-backend";
import fuse, { MountOptions } from "@zoid-fs/node-fuse-bindings";
import { match } from "ts-pattern";
import { constants } from "fs";
import path from "path";

export const symlink: (backend: SQLiteBackend) => MountOptions["symlink"] = (
backend
) => {
return async (srcPath, destPath, cb) => {
console.log("symlink(%s, %s)", srcPath, destPath);
console.info("symlink(%s, %s)", srcPath, destPath);

const targetFile = await backend.getFile(srcPath);
console.log({ targetFile });
if (targetFile.status === "not_found") {
cb(fuse.ENOENT);
const parsedDestPath = path.parse(destPath);
// Note: actually 255 as per the spec but we get an extra / in the dest path
if (parsedDestPath.base.length > 255) {
cb(fuse.ENAMETOOLONG);
return;
}

// Note: actually 1023 as per the spec but we get an extra / in the dest path
if (srcPath.length > 1023 || destPath.length > 1023) {
cb(fuse.ENAMETOOLONG);
return;
}

Expand All @@ -24,10 +32,10 @@ export const symlink: (backend: SQLiteBackend) => MountOptions["symlink"] = (
const r = await backend.createFile(
destPath,
"symlink",
33188,
constants.S_IFLNK,
uid,
gid,
targetFile.file.id
srcPath
);
match(r)
.with({ status: "ok" }, () => {
Expand Down
Loading

0 comments on commit 58b5fb8

Please sign in to comment.