This commit is contained in:
+24
-3
@@ -226,26 +226,47 @@ export async function fileReadStream(config: AppConfig, storagePath: string) {
|
||||
return safeReadStream(config.filesDir, storagePath);
|
||||
}
|
||||
|
||||
function mapReadError(error: unknown): unknown {
|
||||
if (error instanceof AppError) return error;
|
||||
const code = (error as NodeJS.ErrnoException | undefined)?.code;
|
||||
if (code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP") {
|
||||
return new AppError(410, "ATTACHMENT_MISSING", "附件文件已不可用");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/** Open a private file by descriptor and keep the no-follow guarantee through
|
||||
* the subsequent read. Used for both attachment and export downloads. */
|
||||
export async function safeReadStream(root: string, relativePath: string) {
|
||||
const handle = await open(safeStoragePath(root, relativePath), fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
||||
let handle: Awaited<ReturnType<typeof open>>;
|
||||
try {
|
||||
handle = await open(safeStoragePath(root, relativePath), fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
||||
} catch (error) {
|
||||
throw mapReadError(error);
|
||||
}
|
||||
try {
|
||||
const info = await handle.stat();
|
||||
if (!info.isFile()) throw new AppError(410, "ATTACHMENT_MISSING", "附件文件已不可用");
|
||||
return handle.createReadStream({ autoClose: true });
|
||||
} catch (error) {
|
||||
await handle.close().catch(() => undefined);
|
||||
throw error;
|
||||
throw mapReadError(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function readStorageFile(config: AppConfig, storagePath: string): Promise<Buffer> {
|
||||
const handle = await open(safeStoragePath(config.filesDir, storagePath), fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
||||
let handle: Awaited<ReturnType<typeof open>>;
|
||||
try {
|
||||
handle = await open(safeStoragePath(config.filesDir, storagePath), fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
||||
} catch (error) {
|
||||
throw mapReadError(error);
|
||||
}
|
||||
try {
|
||||
const info = await handle.stat();
|
||||
if (!info.isFile()) throw new AppError(410, "ATTACHMENT_MISSING", "附件文件已不可用");
|
||||
return await handle.readFile();
|
||||
} catch (error) {
|
||||
throw mapReadError(error);
|
||||
} finally {
|
||||
await handle.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user