(db: Database, parts: string[], canonical: string)
| 41 | // final segment is handled by the caller. Returns the parent inode or |
| 42 | // throws ENOENT/ENOTDIR. |
| 43 | function resolveParent(db: Database, parts: string[], canonical: string): number { |
| 44 | let parentInode = ROOT_INODE; |
| 45 | for (let i = 0; i < parts.length - 1; i++) { |
| 46 | const name = parts[i]; |
| 47 | const child = db.one<{ child_inode: number }>( |
| 48 | "SELECT child_inode FROM vfs_dirents WHERE parent_inode = ? AND name = ?", |
| 49 | parentInode, |
| 50 | name, |
| 51 | ); |
| 52 | if (child === undefined) { |
| 53 | throw createWorkspaceError("ENOENT", `parent directory missing: ${canonical}`, canonical); |
| 54 | } |
| 55 | const next = db.one<{ inode: number; type: "file" | "dir" }>( |
| 56 | "SELECT inode, type FROM vfs_nodes WHERE inode = ?", |
| 57 | child.child_inode, |
| 58 | ); |
| 59 | if (next === undefined) { |
| 60 | throw createWorkspaceError("ENOENT", `dangling dirent: ${canonical}`, canonical); |
| 61 | } |
| 62 | if (next.type !== "dir") { |
| 63 | throw createWorkspaceError( |
| 64 | "ENOTDIR", |
| 65 | `parent path segment is not a directory: ${canonical}`, |
| 66 | canonical, |
| 67 | ); |
| 68 | } |
| 69 | parentInode = next.inode; |
| 70 | } |
| 71 | return parentInode; |
| 72 | } |
| 73 | |
| 74 | async function materialize(content: string | Uint8Array): Promise<Uint8Array> { |
| 75 | if (typeof content === "string") { |
no test coverage detected