@openclaw/fs-safe 0.5.3 → 0.5.5

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.5 - 2026-08-12
4
+
5
+ ### Security and Correctness
6
+
7
+ - Prevent nondeterministic Windows read failures with `path-mismatch` when path-based stat reports zero file identity through libuv's FindFirstFile fallback under antivirus or indexer contention; zero Windows inodes are now treated as unknown identity like zero device serials.
8
+
9
+ ## 0.5.4 - 2026-08-10
10
+
11
+ **Highlight:** two security fixes in the publication path. If you run fs-safe on
12
+ Windows, the identity fix is the one that matters — rounded file indexes could
13
+ previously let a replaced path pass as the original.
14
+
15
+ ### Security and Correctness
16
+
17
+ - Compare exact bigint filesystem identities during exclusive publication and rollback cleanup. Windows rounds file indexes, so a replaced source or target path could previously masquerade as the original — and, worse, authorize deletion of an attacker's replacement. Identity comparisons are now exact.
18
+ - Open pinned and standalone regular-file reads nonblocking on POSIX before validating the descriptor type, so a raced FIFO or device cannot stall the worker. The same read-open flags are now shared by root reads, hashing, and move-copy fallbacks, so the guarantee holds on every path rather than just the one that was fixed.
19
+
20
+ ### Dependencies and maintenance
21
+
22
+ - Refresh the napi toolchain (napi 3.12.1, napi-derive 3.6.3, napi-build 2.4.1) and the Rust and Node development dependency graph.
23
+
3
24
  ## 0.5.3 - 2026-08-08
4
25
 
5
26
  ### Security and Correctness
@@ -1 +1 @@
1
- {"version":3,"file":"file-hash.d.ts","sourceRoot":"","sources":["../src/file-hash.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEnE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,CAAC;AAElD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAcF,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,aAAa,GAAG,SAA8B,GACrD,OAAO,CAAC,gBAAgB,CAAC,CAoB3B;AA2CD,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAElF"}
1
+ {"version":3,"file":"file-hash.d.ts","sourceRoot":"","sources":["../src/file-hash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGnE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,CAAC;AAElD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,aAAa,GAAG,SAA8B,GACrD,OAAO,CAAC,gBAAgB,CAAC,CAoB3B;AA2CD,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAElF"}
package/dist/file-hash.js CHANGED
@@ -1,18 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import fsSync from "node:fs";
3
2
  import fs from "node:fs/promises";
4
3
  import { FsSafeError } from "./errors.js";
5
4
  import { sameFileIdentity } from "./file-identity.js";
6
5
  import { getNativeBinding } from "./native.js";
7
- function readFlags() {
8
- return (fsSync.constants.O_RDONLY |
9
- (process.platform !== "win32" && typeof fsSync.constants.O_NOFOLLOW === "number"
10
- ? fsSync.constants.O_NOFOLLOW
11
- : 0) |
12
- (process.platform !== "win32" && typeof fsSync.constants.O_NONBLOCK === "number"
13
- ? fsSync.constants.O_NONBLOCK
14
- : 0));
15
- }
6
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
16
7
  export async function hashFileHandle(handle, native = getNativeBinding()) {
17
8
  const stat = await handle.stat();
18
9
  if (!stat.isFile()) {
@@ -43,7 +34,7 @@ async function hashPath(filePath) {
43
34
  }
44
35
  let handle;
45
36
  try {
46
- handle = await fs.open(filePath, readFlags());
37
+ handle = await fs.open(filePath, resolveReadOpenFlags());
47
38
  }
48
39
  catch (error) {
49
40
  if (error?.code === "ELOOP") {
@@ -1 +1 @@
1
- {"version":3,"file":"file-identity.d.ts","sourceRoot":"","sources":["../src/file-identity.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB,CAAC;AAUF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAGlF;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAWT"}
1
+ {"version":3,"file":"file-identity.d.ts","sourceRoot":"","sources":["../src/file-identity.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB,CAAC;AAsBF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAGlF;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAQT"}
@@ -5,18 +5,20 @@ function isZero(value) {
5
5
  function sameStatValue(left, right) {
6
6
  return typeof left === typeof right ? left === right : BigInt(left) === BigInt(right);
7
7
  }
8
+ function isStatValueProvablyDifferent(left, right, platform) {
9
+ if (sameStatValue(left, right)) {
10
+ return false;
11
+ }
12
+ return platform !== "win32" || (!isZero(left) && !isZero(right));
13
+ }
8
14
  export function sha256Hex(data, encoding) {
9
15
  const buffer = typeof data === "string" ? Buffer.from(data, encoding ?? "utf8") : data;
10
16
  return createHash("sha256").update(buffer).digest("hex");
11
17
  }
12
18
  export function sameFileIdentity(left, right, platform = process.platform) {
13
- if (!sameStatValue(left.ino, right.ino)) {
14
- return false;
15
- }
16
- // On Windows, path-based stat calls can report dev=0 while fd-based stat
17
- // reports a real volume serial; treat either-side dev=0 as "unknown device".
18
- if (sameStatValue(left.dev, right.dev)) {
19
- return true;
20
- }
21
- return platform === "win32" && (isZero(left.dev) || isZero(right.dev));
19
+ // When Windows cannot open a path for stat, libuv's FindFirstFile fallback reports dev=0 and
20
+ // ino=0. Treating either unknown value as a mismatch caused nondeterministic path-mismatch
21
+ // failures on legitimate reads under antivirus or indexer contention.
22
+ return (!isStatValueProvablyDifferent(left.dev, right.dev, platform) &&
23
+ !isStatValueProvablyDifferent(left.ino, right.ino, platform));
22
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;AA6VD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CA2Df"}
1
+ {"version":3,"file":"move-path.d.ts","sourceRoot":"","sources":["../src/move-path.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,sBAAsB,GAAG,cAAc,GAAG,uBAAuB,CAAC;AAEvE,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,sBAAsB,GAAG,SAAS,CASpC;AAiVD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CA2Df"}
package/dist/move-path.js CHANGED
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { FsSafeError } from "./errors.js";
6
6
  import { guardedRename } from "./guarded-mutation.js";
7
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
7
8
  import { registerTempPathForExit } from "./temp-cleanup.js";
8
9
  export function moveCopyFallbackReasonForRenameError(error, platform = process.platform) {
9
10
  const code = error?.code;
@@ -94,15 +95,6 @@ async function assertSourceStillMatches(sourcePath, identity) {
94
95
  throw sourceChangedError(sourcePath);
95
96
  }
96
97
  }
97
- function regularReadFlags() {
98
- return (fsConstants.O_RDONLY |
99
- (typeof fsConstants.O_NOFOLLOW === "number" && process.platform !== "win32"
100
- ? fsConstants.O_NOFOLLOW
101
- : 0) |
102
- (typeof fsConstants.O_NONBLOCK === "number" && process.platform !== "win32"
103
- ? fsConstants.O_NONBLOCK
104
- : 0));
105
- }
106
98
  async function chmodDirectoryPinned(directoryPath, mode) {
107
99
  if (process.platform === "win32") {
108
100
  // Node cannot portably open a Windows directory for descriptor-bound
@@ -129,7 +121,7 @@ async function copyRegularFilePinned(params) {
129
121
  let destinationCreated = false;
130
122
  let sourceHandle;
131
123
  try {
132
- sourceHandle = await fs.open(params.from, regularReadFlags());
124
+ sourceHandle = await fs.open(params.from, resolveReadOpenFlags());
133
125
  }
134
126
  catch (error) {
135
127
  const code = error?.code;
@@ -1 +1 @@
1
- {"version":3,"file":"pinned-open.d.ts","sourceRoot":"","sources":["../src/pinned-open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAKzB,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;AAEvE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,2BAA2B,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,WAAW,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,OAAO,EAAE,EACT,WAAW,GAAG,WAAW,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CACpF,CAAC;AAYF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB,GAAG,oBAAoB,CAiFvB"}
1
+ {"version":3,"file":"pinned-open.d.ts","sourceRoot":"","sources":["../src/pinned-open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAMzB,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;AAEvE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,2BAA2B,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAExE,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,WAAW,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,OAAO,EAAE,EACT,WAAW,GAAG,WAAW,GAAG,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CACpF,CAAC;AAYF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB,GAAG,oBAAoB,CA+EvB"}
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import { isUnsafeDeviceReadPath } from "./device-path.js";
3
3
  import { FsSafeError } from "./errors.js";
4
4
  import { sameFileIdentity as hasSameFileIdentity } from "./file-identity.js";
5
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
5
6
  function isExpectedPathError(error) {
6
7
  const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
7
8
  return code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP";
@@ -12,8 +13,7 @@ function sameFileIdentity(left, right) {
12
13
  export function openPinnedFileSync(params) {
13
14
  const ioFs = params.ioFs ?? fs;
14
15
  const allowedType = params.allowedType ?? "file";
15
- const openReadFlags = ioFs.constants.O_RDONLY |
16
- (typeof ioFs.constants.O_NOFOLLOW === "number" ? ioFs.constants.O_NOFOLLOW : 0);
16
+ const openReadFlags = resolveReadOpenFlags({ constants: ioFs.constants });
17
17
  let fd = null;
18
18
  try {
19
19
  if (isUnsafeDeviceReadPath(params.filePath)) {
@@ -18,6 +18,7 @@ export type PublishFailureState = {
18
18
  phase: PublishFileExclusiveFailurePhase;
19
19
  targetCreated: boolean;
20
20
  targetIdentity?: FileIdentityStat;
21
+ targetCleanupIdentity?: FileIdentityStat;
21
22
  preserveTarget: boolean;
22
23
  directorySync?: PublishFileExclusiveDirectorySyncFailure;
23
24
  };
@@ -1 +1 @@
1
- {"version":3,"file":"publish-file-failure.d.ts","sourceRoot":"","sources":["../src/publish-file-failure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,MAAM,qCAAqC,GAAG,UAAU,GAAG,UAAU,CAAC;AAC5E,MAAM,MAAM,wCAAwC,GAAG;IACrD,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,gCAAgC,GACxC,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,eAAe,CAAC;AACpB,MAAM,MAAM,2BAA2B,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAC9E,MAAM,MAAM,kCAAkC,GAAG;IAC/C,KAAK,EAAE,gCAAgC,CAAC;IACxC,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,2BAA2B,CAAC;IACrC,aAAa,CAAC,EAAE,wCAAwC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,gCAAgC,CAAC;IACxC,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,wCAAwC,CAAC;CAC1D,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,gCAAgC,GACtC,IAAI,CAIN;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,2BAA2B,GACnC,WAAW,CAcb;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,GACb,wCAAwC,CAG1C"}
1
+ {"version":3,"file":"publish-file-failure.d.ts","sourceRoot":"","sources":["../src/publish-file-failure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,MAAM,qCAAqC,GAAG,UAAU,GAAG,UAAU,CAAC;AAC5E,MAAM,MAAM,wCAAwC,GAAG;IACrD,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,gCAAgC,GACxC,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,eAAe,CAAC;AACpB,MAAM,MAAM,2BAA2B,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAC9E,MAAM,MAAM,kCAAkC,GAAG;IAC/C,KAAK,EAAE,gCAAgC,CAAC;IACxC,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,2BAA2B,CAAC;IACrC,aAAa,CAAC,EAAE,wCAAwC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,gCAAgC,CAAC;IACxC,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,gBAAgB,CAAC;IACzC,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,wCAAwC,CAAC;CAC1D,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,gCAAgC,GACtC,IAAI,CAKN;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,2BAA2B,GACnC,WAAW,CAcb;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,GACb,wCAAwC,CAG1C"}
@@ -1,7 +1,8 @@
1
1
  import { FsSafeError } from "./errors.js";
2
2
  export function rememberCreatedTarget(state, identity, phase) {
3
3
  state.targetCreated = true;
4
- state.targetIdentity = { dev: identity.dev, ino: identity.ino };
4
+ state.targetIdentity = { dev: Number(identity.dev), ino: Number(identity.ino) };
5
+ state.targetCleanupIdentity = { dev: identity.dev, ino: identity.ino };
5
6
  state.phase = phase;
6
7
  }
7
8
  export function publicationFailure(error, state, cleanup) {
@@ -1 +1 @@
1
- {"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI7C,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,2BAA2B,EAC3B,wCAAwC,EACxC,kCAAkC,EAClC,gCAAgC,EAChC,qCAAqC,GACtC,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,4BAA4B,GACpC,cAAc,GACd,eAAe,GACf,kBAAkB,CAAC;AAEvB,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAkBF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AAoND,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,aAAa,CAAC,EAAE,qCAAqC,CAAC;IACtD,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA8LtC"}
1
+ {"version":3,"file":"publish-file.d.ts","sourceRoot":"","sources":["../src/publish-file.ts"],"names":[],"mappings":"AACA,OAAe,EAAoB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG7E,OAAO,EAML,KAAK,qCAAqC,EAC3C,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,2BAA2B,EAC3B,wCAAwC,EACxC,kCAAkC,EAClC,gCAAgC,EAChC,qCAAqC,GACtC,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,4BAA4B,GACpC,cAAc,GACd,eAAe,GACf,kBAAkB,CAAC;AAEvB,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;IAC3D,QAAQ,EAAE,KAAK,CAAC;IAChB,aAAa,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAkBF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AA2ND,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,4BAA4B,CAAC;IACvC,aAAa,CAAC,EAAE,qCAAqC,CAAC;IACtD,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC,GAAG,OAAO,CAAC,0BAA0B,CAAC,CA4MtC"}
@@ -38,12 +38,12 @@ function directoryOpenFlags() {
38
38
  return (fsSync.constants.O_RDONLY |
39
39
  (typeof fsSync.constants.O_DIRECTORY === "number" ? fsSync.constants.O_DIRECTORY : 0));
40
40
  }
41
- async function openNativeParent(binding, filePath) {
41
+ async function openNativeParent(filePath) {
42
42
  const parentPath = path.dirname(filePath);
43
43
  const handle = await fs.open(parentPath, directoryOpenFlags());
44
44
  try {
45
- const pathname = await fs.lstat(parentPath);
46
- const opened = binding.fstatIdentity(handle.fd);
45
+ const pathname = await fs.lstat(parentPath, { bigint: true });
46
+ const opened = await handle.stat({ bigint: true });
47
47
  if (pathname.isSymbolicLink() || !sameFileIdentity(pathname, opened)) {
48
48
  throw new FsSafeError("path-mismatch", "publication parent changed while opening");
49
49
  }
@@ -55,8 +55,10 @@ async function openNativeParent(binding, filePath) {
55
55
  }
56
56
  }
57
57
  async function assertPinnedSourceCurrent(params) {
58
- const opened = await params.handle.stat();
59
- const current = await fs.lstat(params.sourcePath);
58
+ // Windows file indexes can exceed Number.MAX_SAFE_INTEGER, so publication
59
+ // fences must compare bigint stats instead of rounded numeric identities.
60
+ const opened = await params.handle.stat({ bigint: true });
61
+ const current = await fs.lstat(params.sourcePath, { bigint: true });
60
62
  if (!opened.isFile() ||
61
63
  current.isSymbolicLink() ||
62
64
  !current.isFile() ||
@@ -90,13 +92,13 @@ async function copyPinnedSource(params) {
90
92
  throw error;
91
93
  }
92
94
  let target;
93
- const createdIdentity = params.native.fstatIdentity(nativeFd);
95
+ const createdIdentity = fsSync.fstatSync(nativeFd, { bigint: true });
94
96
  rememberCreatedTarget(params.failure, createdIdentity, "copy-verify");
95
97
  try {
96
98
  await getFsSafeTestHooks()?.afterPublishTargetCreated?.("exclusive-copy", params.targetPath, createdIdentity);
97
- const identity = await fs.lstat(params.targetPath);
99
+ const identity = await fs.lstat(params.targetPath, { bigint: true });
98
100
  target = await fs.open(params.targetPath, sourceOpenFlags());
99
- const opened = await target.stat();
101
+ const opened = await target.stat({ bigint: true });
100
102
  if (identity.isSymbolicLink() ||
101
103
  !identity.isFile() ||
102
104
  !sameFileIdentity(createdIdentity, identity) ||
@@ -108,7 +110,7 @@ async function copyPinnedSource(params) {
108
110
  nativeFd = undefined;
109
111
  return {
110
112
  handle: target,
111
- stat: await target.stat(),
113
+ exactIdentity: opened,
112
114
  digest: hashed.digest,
113
115
  bytes: hashed.bytes,
114
116
  };
@@ -124,10 +126,10 @@ async function copyPinnedSource(params) {
124
126
  }
125
127
  }
126
128
  const target = await fs.open(params.targetPath, "wx+", 0o600);
127
- const identity = await target.stat();
128
- rememberCreatedTarget(params.failure, identity, "copy-verify");
129
+ const exactIdentity = await target.stat({ bigint: true });
130
+ rememberCreatedTarget(params.failure, exactIdentity, "copy-verify");
129
131
  try {
130
- await getFsSafeTestHooks()?.afterPublishTargetCreated?.("exclusive-copy", params.targetPath, identity);
132
+ await getFsSafeTestHooks()?.afterPublishTargetCreated?.("exclusive-copy", params.targetPath, exactIdentity);
131
133
  const hash = createHash("sha256");
132
134
  const buffer = Buffer.allocUnsafe(64 * 1024);
133
135
  let position = 0;
@@ -148,7 +150,7 @@ async function copyPinnedSource(params) {
148
150
  position += bytesRead;
149
151
  }
150
152
  await target.sync();
151
- return { handle: target, stat: identity, digest: hash.digest("hex"), bytes: position };
153
+ return { handle: target, exactIdentity, digest: hash.digest("hex"), bytes: position };
152
154
  }
153
155
  catch (error) {
154
156
  await target.close().catch(() => undefined);
@@ -160,7 +162,7 @@ async function removeCreatedTargetIfUnchanged(targetPath, identity) {
160
162
  return "unknown";
161
163
  }
162
164
  try {
163
- const current = await fs.lstat(targetPath);
165
+ const current = await fs.lstat(targetPath, { bigint: true });
164
166
  if (!current.isSymbolicLink() && sameFileIdentity(current, identity)) {
165
167
  await fs.rm(targetPath);
166
168
  return "removed";
@@ -209,31 +211,38 @@ export async function publishFileExclusive(params) {
209
211
  label: "publication parent",
210
212
  });
211
213
  const sourceIdentity = await source.stat();
212
- if (!sameFileIdentity(sourcePathStat, sourceIdentity) ||
214
+ const sourceExactIdentity = await source.stat({ bigint: true });
215
+ const sourcePathExactIdentity = await fs.lstat(sourcePath, { bigint: true });
216
+ if (sourcePathExactIdentity.isSymbolicLink() ||
217
+ !sourcePathExactIdentity.isFile() ||
218
+ !sameFileIdentity(sourcePathExactIdentity, sourceExactIdentity) ||
213
219
  (params.expectedSourceIdentity &&
214
- !sameFileIdentity(params.expectedSourceIdentity, sourceIdentity))) {
220
+ !sameFileIdentity(params.expectedSourceIdentity, typeof params.expectedSourceIdentity.dev === "bigint" ||
221
+ typeof params.expectedSourceIdentity.ino === "bigint"
222
+ ? sourceExactIdentity
223
+ : sourceIdentity))) {
215
224
  throw new FsSafeError("path-mismatch", "publication source identity did not match");
216
225
  }
217
226
  await parent.assertCurrent();
218
- await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceIdentity });
227
+ await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceExactIdentity });
219
228
  const native = params.strategy === "rename-noreplace"
220
229
  ? requireNativeBinding()
221
230
  : getNativeBinding();
222
231
  if (native) {
223
- sourceNativeParent = await openNativeParent(native, sourcePath);
224
- targetNativeParent = await openNativeParent(native, targetPath);
232
+ sourceNativeParent = await openNativeParent(sourcePath);
233
+ targetNativeParent = await openNativeParent(targetPath);
225
234
  }
226
235
  if (params.strategy === "rename-noreplace") {
227
236
  const binding = requireNativeBinding();
228
237
  binding.renameNoReplace(sourceNativeParent.handle.fd, sourceNativeParent.basename, targetNativeParent.handle.fd, targetNativeParent.basename);
229
- rememberCreatedTarget(failure, sourceIdentity, "rename-verify");
238
+ rememberCreatedTarget(failure, sourceExactIdentity, "rename-verify");
230
239
  // A failed post-rename fence must not delete the only remaining name.
231
240
  failure.preserveTarget = true;
232
- await getFsSafeTestHooks()?.afterPublishTargetCreated?.("rename-noreplace", targetPath, sourceIdentity);
233
- const targetIdentity = await fs.lstat(targetPath);
234
- if (targetIdentity.isSymbolicLink() ||
235
- !targetIdentity.isFile() ||
236
- !sameFileIdentity(targetIdentity, sourceIdentity)) {
241
+ await getFsSafeTestHooks()?.afterPublishTargetCreated?.("rename-noreplace", targetPath, sourceExactIdentity);
242
+ const targetExactIdentity = await fs.lstat(targetPath, { bigint: true });
243
+ if (targetExactIdentity.isSymbolicLink() ||
244
+ !targetExactIdentity.isFile() ||
245
+ !sameFileIdentity(targetExactIdentity, sourceExactIdentity)) {
237
246
  throw new FsSafeError("path-mismatch", "no-replace publication target changed");
238
247
  }
239
248
  try {
@@ -246,6 +255,7 @@ export async function publishFileExclusive(params) {
246
255
  }
247
256
  }
248
257
  syncNativeFileBestEffort(sourceNativeParent.handle.fd);
258
+ const targetIdentity = await fs.lstat(targetPath);
249
259
  return {
250
260
  method: "rename-noreplace",
251
261
  identity: targetIdentity,
@@ -264,15 +274,16 @@ export async function publishFileExclusive(params) {
264
274
  else {
265
275
  await fs.link(sourcePath, targetPath);
266
276
  }
267
- rememberCreatedTarget(failure, sourceIdentity, "hardlink-verify");
268
- await getFsSafeTestHooks()?.afterPublishTargetCreated?.("hardlink", targetPath, sourceIdentity);
269
- const targetIdentity = await fs.lstat(targetPath);
270
- if (targetIdentity.isSymbolicLink() ||
271
- !targetIdentity.isFile() ||
272
- !sameFileIdentity(targetIdentity, sourceIdentity)) {
277
+ rememberCreatedTarget(failure, sourceExactIdentity, "hardlink-verify");
278
+ await getFsSafeTestHooks()?.afterPublishTargetCreated?.("hardlink", targetPath, sourceExactIdentity);
279
+ const targetExactIdentity = await fs.lstat(targetPath, { bigint: true });
280
+ if (targetExactIdentity.isSymbolicLink() ||
281
+ !targetExactIdentity.isFile() ||
282
+ !sameFileIdentity(targetExactIdentity, sourceExactIdentity)) {
273
283
  throw new FsSafeError("path-mismatch", "hardlink publication target changed");
274
284
  }
275
- await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceIdentity });
285
+ await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceExactIdentity });
286
+ const targetIdentity = await fs.lstat(targetPath);
276
287
  return {
277
288
  method: "hardlink",
278
289
  identity: targetIdentity,
@@ -303,19 +314,21 @@ export async function publishFileExclusive(params) {
303
314
  failure,
304
315
  });
305
316
  target = copied.handle;
306
- targetIdentity = copied.stat;
317
+ targetIdentity = await target.stat();
307
318
  const targetPathStat = await fs.lstat(targetPath);
319
+ const targetPathExactStat = await fs.lstat(targetPath, { bigint: true });
308
320
  const copiedBack = await hashFileHandle(target, native);
309
321
  const sourceAfter = await hashFileHandle(source, native);
310
322
  if (targetPathStat.isSymbolicLink() ||
311
- !sameFileIdentity(targetPathStat, targetIdentity) ||
323
+ targetPathExactStat.isSymbolicLink() ||
324
+ !sameFileIdentity(targetPathExactStat, copied.exactIdentity) ||
312
325
  copiedBack.bytes !== copied.bytes ||
313
326
  copiedBack.digest !== copied.digest ||
314
327
  sourceAfter.bytes !== copied.bytes ||
315
328
  sourceAfter.digest !== copied.digest) {
316
329
  throw new FsSafeError("path-mismatch", "exclusive publication copy failed content fencing");
317
330
  }
318
- await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceIdentity });
331
+ await assertPinnedSourceCurrent({ sourcePath, handle: source, identity: sourceExactIdentity });
319
332
  const directorySync = await syncPublishedParent({
320
333
  parent,
321
334
  failure,
@@ -339,7 +352,7 @@ export async function publishFileExclusive(params) {
339
352
  const preserveSyncFailure = failure.phase === "directory-sync" && params.onSyncFailure === "preserve";
340
353
  const cleanup = failure.preserveTarget || preserveSyncFailure
341
354
  ? "preserved"
342
- : await removeCreatedTargetIfUnchanged(targetPath, failure.targetIdentity);
355
+ : await removeCreatedTargetIfUnchanged(targetPath, failure.targetCleanupIdentity);
343
356
  throw publicationFailure(error, failure, cleanup);
344
357
  }
345
358
  finally {
@@ -0,0 +1,8 @@
1
+ import fs from "node:fs";
2
+ type ReadOpenFlagConstants = Pick<typeof fs.constants, "O_RDONLY"> & Partial<Pick<typeof fs.constants, "O_NOFOLLOW" | "O_NONBLOCK">>;
3
+ export declare function resolveReadOpenFlags(options?: {
4
+ constants?: ReadOpenFlagConstants;
5
+ followSymlinks?: boolean;
6
+ }): number;
7
+ export {};
8
+ //# sourceMappingURL=read-open-flags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-open-flags.d.ts","sourceRoot":"","sources":["../src/read-open-flags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,KAAK,qBAAqB,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,GAChE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC;AAElE,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,MAAM,CAaT"}
@@ -0,0 +1,13 @@
1
+ import fs from "node:fs";
2
+ export function resolveReadOpenFlags(options) {
3
+ const constants = options?.constants ?? fs.constants;
4
+ const noFollow = process.platform !== "win32" &&
5
+ options?.followSymlinks !== true &&
6
+ typeof constants.O_NOFOLLOW === "number"
7
+ ? constants.O_NOFOLLOW
8
+ : 0;
9
+ const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number"
10
+ ? constants.O_NONBLOCK
11
+ : 0;
12
+ return constants.O_RDONLY | noFollow | nonBlocking;
13
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,MAAM,MAAM,SAAS,CAAC;AAW7B,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAExF,KAAK,8BAA8B,GAAG,IAAI,CACxC,OAAO,MAAM,CAAC,SAAS,EACvB,UAAU,GAAG,SAAS,GAAG,UAAU,CACpC,GACC,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,8BAAiD,GAC3D,MAAM,CAQR;AAsBD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CActF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAc3E;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAyD3C;AA6DD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;CACb,CA6BA;AAmBD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CA2D7E"}
1
+ {"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,MAAM,MAAM,SAAS,CAAC;AAY7B,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAExF,KAAK,8BAA8B,GAAG,IAAI,CACxC,OAAO,MAAM,CAAC,SAAS,EACvB,UAAU,GAAG,SAAS,GAAG,UAAU,CACpC,GACC,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,8BAAiD,GAC3D,MAAM,CAQR;AAaD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CActF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAc3E;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAyD3C;AA6DD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;CACb,CA6BA;AAmBD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CA2D7E"}
@@ -6,6 +6,7 @@ import { assertNoUnsafeDeviceReadPath } from "./device-path.js";
6
6
  import { FsSafeError } from "./errors.js";
7
7
  import { sameFileIdentity } from "./file-identity.js";
8
8
  import { isNotFoundPathError } from "./path.js";
9
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
9
10
  import { assertNoSymlinkParents, assertNoSymlinkParentsSync } from "./symlink-parents.js";
10
11
  export function resolveRegularFileAppendFlags(constants = fsSync.constants) {
11
12
  const noFollow = constants.O_NOFOLLOW;
@@ -14,12 +15,6 @@ export function resolveRegularFileAppendFlags(constants = fsSync.constants) {
14
15
  constants.O_WRONLY |
15
16
  (typeof noFollow === "number" ? noFollow : 0));
16
17
  }
17
- function resolveRegularFileReadFlags() {
18
- return (fsSync.constants.O_RDONLY |
19
- (typeof fsSync.constants.O_NOFOLLOW === "number" && process.platform !== "win32"
20
- ? fsSync.constants.O_NOFOLLOW
21
- : 0));
22
- }
23
18
  function regularFileTooLargeError(filePath, maxBytes, cause) {
24
19
  return new FsSafeError("too-large", `File exceeds ${maxBytes} bytes: ${filePath}`, { cause });
25
20
  }
@@ -72,7 +67,7 @@ export async function readRegularFile(params) {
72
67
  }
73
68
  let handle;
74
69
  try {
75
- handle = await fs.open(params.filePath, resolveRegularFileReadFlags());
70
+ handle = await fs.open(params.filePath, resolveReadOpenFlags());
76
71
  }
77
72
  catch (err) {
78
73
  if (isNotFoundPathError(err)) {
@@ -180,7 +175,7 @@ export function readRegularFileSync(params) {
180
175
  }
181
176
  let fd;
182
177
  try {
183
- fd = fsSync.openSync(params.filePath, resolveRegularFileReadFlags());
178
+ fd = fsSync.openSync(params.filePath, resolveReadOpenFlags());
184
179
  }
185
180
  catch (error) {
186
181
  if (isNotFoundPathError(error)) {
@@ -1 +1 @@
1
- {"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"root-impl.d.ts","sourceRoot":"","sources":["../src/root-impl.ts"],"names":[],"mappings":"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"}
package/dist/root-impl.js CHANGED
@@ -16,6 +16,7 @@ import { validatePinnedOperationPayload } from "./pinned-operation.js";
16
16
  import { assertNoPathAliasEscape, PATH_ALIAS_POLICIES } from "./path-policy.js";
17
17
  import { assertNoNulPathInput, assertNoUnsafeDeviceReadPath, hasNodeErrorCode, isNotFoundPathError, isPathInside, isSymlinkOpenError, } from "./path.js";
18
18
  import { readOpenedFileSafely } from "./read-opened-file.js";
19
+ import { resolveReadOpenFlags } from "./read-open-flags.js";
19
20
  import { resolveRootPath } from "./root-path.js";
20
21
  import { assertRootIdentityCurrent, assertValidRootDestinationPath, assertValidRootRelativePath, ensureTrailingSep, expandRelativePathWithHome, resolvePathInRoot, resolveRootContext, } from "./root-context.js";
21
22
  import { fileNotFoundError, hardlinkedPathNotAllowedError, isAlreadyExistsError, normalizePinnedPathError, normalizePinnedWriteError, normalizeRemoveGuardError, normalizeRemovePathError, outsideWorkspaceError, } from "./root-errors.js";
@@ -31,11 +32,8 @@ function logWarn(message) {
31
32
  }
32
33
  }
33
34
  const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in fsConstants;
34
- const NONBLOCK_OPEN_FLAG = process.platform !== "win32" && "O_NONBLOCK" in fsConstants ? fsConstants.O_NONBLOCK : 0;
35
- const OPEN_READ_FLAGS = fsConstants.O_RDONLY |
36
- (SUPPORTS_NOFOLLOW ? fsConstants.O_NOFOLLOW : 0) |
37
- NONBLOCK_OPEN_FLAG;
38
- const OPEN_READ_FOLLOW_FLAGS = fsConstants.O_RDONLY | NONBLOCK_OPEN_FLAG;
35
+ const OPEN_READ_FLAGS = resolveReadOpenFlags();
36
+ const OPEN_READ_FOLLOW_FLAGS = resolveReadOpenFlags({ followSymlinks: true });
39
37
  const OPEN_WRITE_EXISTING_FLAGS = fsConstants.O_WRONLY | (SUPPORTS_NOFOLLOW ? fsConstants.O_NOFOLLOW : 0);
40
38
  const OPEN_WRITE_CREATE_FLAGS = fsConstants.O_WRONLY |
41
39
  fsConstants.O_CREAT |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/fs-safe",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Capability-style filesystem roots for Node.js apps that handle untrusted relative paths.",
5
5
  "keywords": [
6
6
  "filesystem",
@@ -155,7 +155,7 @@
155
155
  "devDependencies": {
156
156
  "@emnapi/runtime": "2.0.0-alpha.3",
157
157
  "@napi-rs/cli": "3.8.2",
158
- "@types/node": "^26.1.2",
158
+ "@types/node": "^26.2.0",
159
159
  "@vitest/coverage-v8": "4.1.10",
160
160
  "fast-check": "^4.9.0",
161
161
  "istanbul-lib-coverage": "3.2.2",