Path: blob/master/src/packages/file-server/btrfs/subvolume-fs.ts
1539 views
import {1appendFile,2chmod,3cp,4copyFile,5link,6readFile,7realpath,8rename,9rm,10rmdir,11mkdir,12stat,13symlink,14truncate,15writeFile,16unlink,17utimes,18watch,19} from "node:fs/promises";20import { exists } from "@cocalc/backend/misc/async-utils-node";21import { type DirectoryListingEntry } from "@cocalc/util/types";22import getListing from "@cocalc/backend/get-listing";23import { type Subvolume } from "./subvolume";24import { isdir, sudo } from "./util";2526export class SubvolumeFilesystem {27constructor(private subvolume: Subvolume) {}2829private normalize = this.subvolume.normalize;3031ls = async (32path: string,33{ hidden, limit }: { hidden?: boolean; limit?: number } = {},34): Promise<DirectoryListingEntry[]> => {35return await getListing(this.normalize(path), hidden, {36limit,37home: "/",38});39};4041readFile = async (path: string, encoding?: any): Promise<string | Buffer> => {42return await readFile(this.normalize(path), encoding);43};4445writeFile = async (path: string, data: string | Buffer) => {46return await writeFile(this.normalize(path), data);47};4849appendFile = async (path: string, data: string | Buffer, encoding?) => {50return await appendFile(this.normalize(path), data, encoding);51};5253unlink = async (path: string) => {54await unlink(this.normalize(path));55};5657stat = async (path: string) => {58return await stat(this.normalize(path));59};6061exists = async (path: string) => {62return await exists(this.normalize(path));63};6465// hard link66link = async (existingPath: string, newPath: string) => {67return await link(this.normalize(existingPath), this.normalize(newPath));68};6970symlink = async (target: string, path: string) => {71return await symlink(this.normalize(target), this.normalize(path));72};7374realpath = async (path: string) => {75const x = await realpath(this.normalize(path));76return x.slice(this.subvolume.path.length + 1);77};7879rename = async (oldPath: string, newPath: string) => {80await rename(this.normalize(oldPath), this.normalize(newPath));81};8283utimes = async (84path: string,85atime: number | string | Date,86mtime: number | string | Date,87) => {88await utimes(this.normalize(path), atime, mtime);89};9091watch = (filename: string, options?) => {92return watch(this.normalize(filename), options);93};9495truncate = async (path: string, len?: number) => {96await truncate(this.normalize(path), len);97};9899copyFile = async (src: string, dest: string) => {100await copyFile(this.normalize(src), this.normalize(dest));101};102103cp = async (src: string, dest: string, options?) => {104await cp(this.normalize(src), this.normalize(dest), options);105};106107chmod = async (path: string, mode: string | number) => {108await chmod(this.normalize(path), mode);109};110111mkdir = async (path: string, options?) => {112await mkdir(this.normalize(path), options);113};114115rsync = async ({116src,117target,118args = ["-axH"],119timeout = 5 * 60 * 1000,120}: {121src: string;122target: string;123args?: string[];124timeout?: number;125}): Promise<{ stdout: string; stderr: string; exit_code: number }> => {126let srcPath = this.normalize(src);127let targetPath = this.normalize(target);128if (!srcPath.endsWith("/") && (await isdir(srcPath))) {129srcPath += "/";130if (!targetPath.endsWith("/")) {131targetPath += "/";132}133}134return await sudo({135command: "rsync",136args: [...args, srcPath, targetPath],137err_on_exit: false,138timeout: timeout / 1000,139});140};141142rmdir = async (path: string, options?) => {143await rmdir(this.normalize(path), options);144};145146rm = async (path: string, options?) => {147await rm(this.normalize(path), options);148};149}150151152