@poe-platform/safe-fs 0.1.82 → 0.1.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FsError } from "../../contracts/errors.js";
|
|
1
2
|
import { quotaCapabilities } from "../capabilities.js";
|
|
2
3
|
export class FileSystemQuotaError extends Error {
|
|
3
4
|
maxBytes;
|
|
@@ -7,19 +8,46 @@ export class FileSystemQuotaError extends Error {
|
|
|
7
8
|
this.name = "FileSystemQuotaError";
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
|
-
async function usedBytes(fs, options) {
|
|
11
|
+
async function usedBytes(fs, options, change) {
|
|
11
12
|
let total = 0;
|
|
13
|
+
let possibleAliases = 0;
|
|
12
14
|
const pending = ["/"];
|
|
13
15
|
while (pending.length) {
|
|
16
|
+
options?.signal?.throwIfAborted();
|
|
14
17
|
const directory = pending.pop();
|
|
15
18
|
for (const entry of await fs.readdir(directory, options)) {
|
|
19
|
+
options?.signal?.throwIfAborted();
|
|
16
20
|
const path = `${directory === "/" ? "" : directory}/${entry.name}`;
|
|
17
21
|
if (entry.type === "directory")
|
|
18
22
|
pending.push(path);
|
|
19
|
-
else
|
|
20
|
-
|
|
23
|
+
else {
|
|
24
|
+
const stat = await fs.lstat(path, options);
|
|
25
|
+
total += stat.size;
|
|
26
|
+
if (!change || stat.type !== "file")
|
|
27
|
+
continue;
|
|
28
|
+
const scope = change.stat.identityScope;
|
|
29
|
+
const comparable = [scope, stat.identityScope].every(value => typeof value === "symbol" || typeof value === "object" && value !== null)
|
|
30
|
+
&& [change.stat.dev, change.stat.ino, stat.dev, stat.ino].every(value => typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
|
|
31
|
+
const compare = comparable ? undefined : fs.compareEntry;
|
|
32
|
+
const comparison = comparable
|
|
33
|
+
? scope === stat.identityScope && change.stat.dev === stat.dev && change.stat.ino === stat.ino ? "same" : "distinct"
|
|
34
|
+
: compare === undefined ? "unknown" : await compare.call(fs, change.path, fs, path, options);
|
|
35
|
+
options?.signal?.throwIfAborted();
|
|
36
|
+
if (comparison !== "same" && comparison !== "distinct" && comparison !== "unknown")
|
|
37
|
+
throw new FsError("EIO", { syscall: "compareEntry", path: change.path, dest: path, message: "invalid entry comparison" });
|
|
38
|
+
if (comparison === "same") {
|
|
39
|
+
total += change.delta;
|
|
40
|
+
possibleAliases++;
|
|
41
|
+
}
|
|
42
|
+
else if (comparison !== "distinct") {
|
|
43
|
+
total += Math.max(0, change.delta);
|
|
44
|
+
possibleAliases++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
21
47
|
}
|
|
22
48
|
}
|
|
49
|
+
if (change && possibleAliases === 0)
|
|
50
|
+
total += Math.max(0, change.delta);
|
|
23
51
|
return total;
|
|
24
52
|
}
|
|
25
53
|
async function existingBytes(fs, path, options) {
|
|
@@ -43,8 +71,20 @@ export function withFileSystemQuota(fs, options) {
|
|
|
43
71
|
return result;
|
|
44
72
|
};
|
|
45
73
|
const assertDelta = async (path, nextBytes, fsOptions) => {
|
|
46
|
-
|
|
47
|
-
|
|
74
|
+
fsOptions?.signal?.throwIfAborted();
|
|
75
|
+
let current;
|
|
76
|
+
try {
|
|
77
|
+
current = await fs.stat(path, fsOptions);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
const projected = current?.type === "file" && nextBytes > current.size
|
|
84
|
+
? await usedBytes(fs, fsOptions, { path, stat: current, delta: nextBytes - current.size })
|
|
85
|
+
: await usedBytes(fs, fsOptions) - (current?.type === "directory" ? 0 : current?.size ?? 0) + nextBytes;
|
|
86
|
+
fsOptions?.signal?.throwIfAborted();
|
|
87
|
+
if (projected > options.maxBytes)
|
|
48
88
|
throw new FileSystemQuotaError(options.maxBytes);
|
|
49
89
|
};
|
|
50
90
|
const mutations = {
|