fix(storage): 本地写入口拒绝 Alist 虚拟路径,补字幕在 Alist 库根上明确失败
虚拟前缀 /@alist/… 读到本地是 ENOENT,但 mkdir -p、复制 / 移动目标、写文件、回收站落点会在本机真建出 /@alist 并写入文件。统一守卫:任何本地写类操作参数是虚拟路径即抛 REMOTE_PATH_ON_LOCAL_FS (remote_path_on_local_fs),不落盘。 - adapters:fs/remote-guard.ts,接在 runFsOp、FsProxy.run(父进程拒绝不起子进程)、copyWithVerify、 crossDeviceMove、moveSafe、commitNoClobber、sweepStalePartials、writeRootSentinel - server:storage/local-fs.ts 带守卫的写函数,整理 / 替换 / 刮削 / 回收站 / 上传 / 字幕 / vfs 本地分支改用它 - 补字幕目标在 Alist 媒体库上返回失败原因,撤销同样拒绝 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
a54905e571
commit
521c86d730
23 files changed
+371
-13
No files matched your search
@@ -0,0 +1,61 @@
|
||||
import * as fsp from "node:fs/promises";
|
||||
import { assertLocalPaths } from "@umt/adapters";
|
||||
|
||||
// 本地写入口的远端路径守卫(server 侧):整理 / 刮削 / 字幕 / 回收站 / 上传里直接调 node:fs 写文件的地方都从这里取函数。
|
||||
// 参数是 Alist 虚拟路径(/@alist/…)就抛 FsError("REMOTE_PATH_ON_LOCAL_FS"),不在本机建出 /@alist 目录或写进文件。
|
||||
// 读类函数(stat / readdir / readFile …)原样转出:对虚拟路径只会 ENOENT。
|
||||
|
||||
export * from "node:fs/promises";
|
||||
|
||||
type P = Parameters<typeof fsp.mkdir>[0];
|
||||
const s = (p: unknown) => (typeof p === "string" ? p : p instanceof URL ? p.pathname : undefined);
|
||||
|
||||
export const mkdir: typeof fsp.mkdir = (async (p: P, o?: Parameters<typeof fsp.mkdir>[1]) => {
|
||||
assertLocalPaths("mkdir", s(p));
|
||||
return fsp.mkdir(p, o);
|
||||
}) as typeof fsp.mkdir;
|
||||
|
||||
export const writeFile: typeof fsp.writeFile = async (p, data, o) => {
|
||||
assertLocalPaths("writeFile", s(p));
|
||||
return fsp.writeFile(p, data, o);
|
||||
};
|
||||
|
||||
export const rename: typeof fsp.rename = async (a, b) => {
|
||||
assertLocalPaths("rename", s(a), s(b));
|
||||
return fsp.rename(a, b);
|
||||
};
|
||||
|
||||
export const copyFile: typeof fsp.copyFile = async (a, b, mode) => {
|
||||
assertLocalPaths("copyFile", s(a), s(b));
|
||||
return fsp.copyFile(a, b, mode);
|
||||
};
|
||||
|
||||
export const rm: typeof fsp.rm = async (p, o) => {
|
||||
assertLocalPaths("rm", s(p));
|
||||
return fsp.rm(p, o);
|
||||
};
|
||||
|
||||
export const rmdir: typeof fsp.rmdir = async (p, o) => {
|
||||
assertLocalPaths("rmdir", s(p));
|
||||
return fsp.rmdir(p, o);
|
||||
};
|
||||
|
||||
export const unlink: typeof fsp.unlink = async (p) => {
|
||||
assertLocalPaths("unlink", s(p));
|
||||
return fsp.unlink(p);
|
||||
};
|
||||
|
||||
export const link: typeof fsp.link = async (a, b) => {
|
||||
assertLocalPaths("link", s(a), s(b));
|
||||
return fsp.link(a, b);
|
||||
};
|
||||
|
||||
/** open:写 / 追加 / 新建模式才拦;只读打开放行(虚拟路径只会 ENOENT) */
|
||||
export const open: typeof fsp.open = (async (
|
||||
p: Parameters<typeof fsp.open>[0],
|
||||
flags?: string | number,
|
||||
mode?: number,
|
||||
) => {
|
||||
if (flags !== undefined && flags !== "r") assertLocalPaths("open", s(p));
|
||||
return fsp.open(p, flags, mode);
|
||||
}) as typeof fsp.open;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { mkdir, rename, rm, stat, unlink } from "node:fs/promises";
|
||||
import { basename, dirname, join, posix } from "node:path";
|
||||
import { AlistError, type ProgressCallback } from "@umt/adapters";
|
||||
import { mkdir, rename, rm, stat, unlink } from "./local-fs.ts";
|
||||
import { invalidateRemote, relayDir, remote, remoteError } from "./vfs.ts";
|
||||
import { parseVPath, sameStorage } from "./vpath.ts";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { lstat, mkdir, readdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, dirname, join, posix } from "node:path";
|
||||
import {
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
type StatResult,
|
||||
statSafe,
|
||||
} from "@umt/adapters";
|
||||
import { lstat, mkdir, readdir, readFile, realpath, rename, rm, writeFile } from "./local-fs.ts";
|
||||
import { storageDataDir, storageEntry } from "./registry.ts";
|
||||
import { parseVPath, toVPath, type VPath } from "./vpath.ts";
|
||||
|
||||
|
||||
Reference in new issue
Block a user