@photostructure/fs-metadata 0.6.1 → 0.7.1
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 +7 -1
- package/CLAUDE.md +141 -315
- package/CODE_OF_CONDUCT.md +11 -11
- package/CONTRIBUTING.md +1 -1
- package/README.md +34 -103
- package/binding.gyp +97 -22
- package/claude.sh +23 -0
- package/dist/index.cjs +51 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +51 -21
- package/dist/index.mjs.map +1 -1
- package/doc/C++_REVIEW_TODO.md +97 -25
- package/doc/GPG_RELEASE_HOWTO.md +44 -13
- package/doc/MACOS_API_REFERENCE.md +469 -0
- package/doc/SECURITY_AUDIT_2025.md +809 -0
- package/doc/SSH_RELEASE_HOWTO.md +28 -24
- package/doc/WINDOWS_API_REFERENCE.md +422 -0
- package/doc/WINDOWS_ARM64_SECURITY.md +161 -0
- package/doc/WINDOWS_DEBUG_GUIDE.md +9 -2
- package/doc/examples.md +267 -0
- package/doc/gotchas.md +297 -0
- package/doc/logo.png +0 -0
- package/doc/logo.svg +85 -0
- package/doc/macos-asan-sip-issue.md +71 -0
- package/doc/social.png +0 -0
- package/doc/social.svg +125 -0
- package/doc/windows-build.md +226 -0
- package/doc/windows-clang-tidy.md +72 -0
- package/doc/windows-memory-testing.md +108 -0
- package/doc/windows-prebuildify-arm64.md +232 -0
- package/jest.config.cjs +23 -0
- package/package.json +61 -36
- package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/win32-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/scripts/check-memory.ts +186 -0
- package/scripts/clang-tidy.ts +690 -99
- package/scripts/install.cjs +42 -0
- package/scripts/is-platform.mjs +1 -1
- package/scripts/macos-asan.sh +155 -0
- package/scripts/post-build.mjs +3 -3
- package/scripts/prebuild-linux-glibc.sh +12 -1
- package/scripts/prebuildify-wrapper.ts +77 -0
- package/scripts/precommit.ts +45 -20
- package/scripts/sanitizers-test.sh +1 -1
- package/src/common/volume_metadata.h +6 -0
- package/src/darwin/hidden.cpp +73 -25
- package/src/darwin/path_security.h +149 -0
- package/src/darwin/raii_utils.h +104 -4
- package/src/darwin/volume_metadata.cpp +132 -58
- package/src/darwin/volume_mount_points.cpp +80 -47
- package/src/hidden.ts +36 -13
- package/src/linux/gio_mount_points.cpp +17 -18
- package/src/linux/gio_utils.cpp +92 -37
- package/src/linux/gio_utils.h +11 -5
- package/src/linux/gio_volume_metadata.cpp +111 -48
- package/src/linux/volume_metadata.cpp +67 -4
- package/src/object.ts +1 -0
- package/src/options.ts +6 -0
- package/src/path.ts +11 -0
- package/src/remote_info.ts +5 -3
- package/src/stack_path.ts +8 -6
- package/src/string_enum.ts +1 -0
- package/src/test-utils/memory-test-core.ts +336 -0
- package/src/test-utils/memory-test-runner.ts +108 -0
- package/src/test-utils/platform.ts +46 -1
- package/src/test-utils/worker-thread-helper.cjs +154 -27
- package/src/types/native_bindings.ts +1 -1
- package/src/types/options.ts +6 -0
- package/src/windows/drive_status.h +133 -163
- package/src/windows/error_utils.h +54 -3
- package/src/windows/fs_meta.h +1 -1
- package/src/windows/hidden.cpp +60 -43
- package/src/windows/security_utils.h +250 -0
- package/src/windows/string.h +68 -11
- package/src/windows/system_volume.h +1 -1
- package/src/windows/thread_pool.h +206 -0
- package/src/windows/volume_metadata.cpp +11 -6
- package/src/windows/volume_mount_points.cpp +8 -7
- package/src/windows/windows_arch.h +39 -0
- package/scripts/check-memory.mjs +0 -123
package/dist/index.mjs
CHANGED
|
@@ -105,18 +105,19 @@ function getCallerDirname() {
|
|
|
105
105
|
}
|
|
106
106
|
var patterns = isWindows ? [
|
|
107
107
|
// Standard: "at functionName (C:\path\file.js:1:1)"
|
|
108
|
-
/\bat\s
|
|
108
|
+
/\bat\s[^(]*\((?<path>[A-Z]:\\.+?):\d+:\d+\)$/,
|
|
109
109
|
// direct: "at C:\path\file.js:1:1"
|
|
110
|
-
/\bat\s(?<path>[A-Z]
|
|
110
|
+
/\bat\s(?<path>[A-Z]:\\.+?):\d+:\d+$/,
|
|
111
111
|
// UNC: "at functionName (\\server\share\path\file.js:1:1)"
|
|
112
|
-
/\bat\s
|
|
112
|
+
/\bat\s[^(]*\((?<path>\\\\.+?):\d+:\d+\)$/,
|
|
113
113
|
// direct: "at \\server\share\path\file.js:1:1"
|
|
114
|
-
/\bat\s(?<path
|
|
114
|
+
/\bat\s(?<path>\\\\.+?):\d+:\d+$/
|
|
115
115
|
] : [
|
|
116
116
|
// Standard: "at functionName (/path/file.js:1:1)"
|
|
117
|
-
/\bat\s
|
|
117
|
+
/\bat\s[^(]*\((?<path>\/.*?):\d+:\d+\)$/,
|
|
118
118
|
// Anonymous or direct: "at /path/file.js:1:1"
|
|
119
|
-
|
|
119
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- parsing trusted Node.js stack traces, bounded by line anchors
|
|
120
|
+
/\bat\s(?:[^/\s]+\s+)?(?<path>\/.*?):\d+:\d+$/
|
|
120
121
|
];
|
|
121
122
|
var MaybeUrlRE = /^[a-z]{2,5}:\/\//i;
|
|
122
123
|
function extractCallerPath(stack) {
|
|
@@ -282,13 +283,6 @@ async function mapConcurrent({
|
|
|
282
283
|
async function statAsync(path2, options) {
|
|
283
284
|
return stat(path2, options);
|
|
284
285
|
}
|
|
285
|
-
async function canStatAsync(path2) {
|
|
286
|
-
try {
|
|
287
|
-
return null != await statAsync(path2);
|
|
288
|
-
} catch {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
286
|
async function findAncestorDir(dir, file) {
|
|
293
287
|
dir = resolve(dir);
|
|
294
288
|
try {
|
|
@@ -397,6 +391,12 @@ function toError(cause) {
|
|
|
397
391
|
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
398
392
|
function normalizePath(mountPoint) {
|
|
399
393
|
if (isBlank(mountPoint)) return void 0;
|
|
394
|
+
if (mountPoint.includes("..")) {
|
|
395
|
+
throw new Error("Invalid path: contains directory traversal pattern");
|
|
396
|
+
}
|
|
397
|
+
if (mountPoint.includes("\uFFFD") || mountPoint.includes("\0")) {
|
|
398
|
+
throw new Error("Invalid path: contains invalid characters");
|
|
399
|
+
}
|
|
400
400
|
const result = isWindows ? normalizeWindowsPath(mountPoint) : normalizePosixPath(mountPoint);
|
|
401
401
|
return result != null ? resolve2(result) : void 0;
|
|
402
402
|
}
|
|
@@ -444,11 +444,20 @@ var LocalSupport = HiddenSupportByPlatform[process.platform]?.supported ?? {
|
|
|
444
444
|
systemFlag: false
|
|
445
445
|
};
|
|
446
446
|
async function isHiddenImpl(pathname, nativeFn2) {
|
|
447
|
+
debug("isHiddenImpl called with pathname: %s", pathname);
|
|
447
448
|
const norm = normalizePath(pathname);
|
|
448
449
|
if (norm == null) {
|
|
449
450
|
throw new Error("Invalid pathname: " + JSON.stringify(pathname));
|
|
450
451
|
}
|
|
451
|
-
|
|
452
|
+
debug("Normalized path: %s", norm);
|
|
453
|
+
debug(
|
|
454
|
+
"LocalSupport: dotPrefix=%s, systemFlag=%s",
|
|
455
|
+
LocalSupport.dotPrefix,
|
|
456
|
+
LocalSupport.systemFlag
|
|
457
|
+
);
|
|
458
|
+
const result = LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && await isSystemHidden(norm, nativeFn2);
|
|
459
|
+
debug("isHiddenImpl returning: %s", result);
|
|
460
|
+
return result;
|
|
452
461
|
}
|
|
453
462
|
async function isHiddenRecursiveImpl(path2, nativeFn2) {
|
|
454
463
|
let norm = normalizePath(path2);
|
|
@@ -487,13 +496,26 @@ function isPosixHidden(pathname) {
|
|
|
487
496
|
return b.startsWith(".") && b !== "." && b !== "..";
|
|
488
497
|
}
|
|
489
498
|
async function isSystemHidden(pathname, nativeFn2) {
|
|
499
|
+
debug("isSystemHidden called with pathname: %s", pathname);
|
|
490
500
|
if (!LocalSupport.systemFlag) {
|
|
501
|
+
debug("systemFlag not supported on this platform");
|
|
491
502
|
return false;
|
|
492
503
|
}
|
|
493
|
-
|
|
494
|
-
|
|
504
|
+
const native = await nativeFn2();
|
|
505
|
+
debug("Calling native isHidden for: %s", pathname);
|
|
506
|
+
try {
|
|
507
|
+
const isHidden2 = await native.isHidden(pathname);
|
|
508
|
+
debug("Native isHidden returned: %s", isHidden2);
|
|
509
|
+
return isHidden2;
|
|
510
|
+
} catch (error) {
|
|
511
|
+
debug("Native isHidden threw error: %s", error);
|
|
512
|
+
const errorStr = String(error);
|
|
513
|
+
if (errorStr.includes("Path not found")) {
|
|
514
|
+
debug("Path not found, returning false");
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
throw error;
|
|
495
518
|
}
|
|
496
|
-
return await canStatAsync(pathname) && await (await nativeFn2()).isHidden(pathname);
|
|
497
519
|
}
|
|
498
520
|
async function getHiddenMetadataImpl(pathname, nativeFn2) {
|
|
499
521
|
const norm = normalizePath(pathname);
|
|
@@ -616,13 +638,15 @@ var LinuxMountTablePathsDefault = [
|
|
|
616
638
|
"/etc/mtab"
|
|
617
639
|
];
|
|
618
640
|
var IncludeSystemVolumesDefault = isWindows;
|
|
641
|
+
var SkipNetworkVolumesDefault = false;
|
|
619
642
|
var OptionsDefault = {
|
|
620
643
|
timeoutMs: TimeoutMsDefault,
|
|
621
644
|
maxConcurrency: availableParallelism2(),
|
|
622
645
|
systemPathPatterns: [...SystemPathPatternsDefault],
|
|
623
646
|
systemFsTypes: [...SystemFsTypesDefault],
|
|
624
647
|
linuxMountTablePaths: [...LinuxMountTablePathsDefault],
|
|
625
|
-
includeSystemVolumes: IncludeSystemVolumesDefault
|
|
648
|
+
includeSystemVolumes: IncludeSystemVolumesDefault,
|
|
649
|
+
skipNetworkVolumes: SkipNetworkVolumesDefault
|
|
626
650
|
};
|
|
627
651
|
function optionsWithDefaults(overrides = {}) {
|
|
628
652
|
if (!isObject(overrides)) {
|
|
@@ -812,16 +836,22 @@ function extractRemoteInfo(fsSpec) {
|
|
|
812
836
|
const patterns2 = [
|
|
813
837
|
{
|
|
814
838
|
// CIFS/SMB pattern: //hostname/share or //user@host/share
|
|
815
|
-
regex:
|
|
839
|
+
regex: (
|
|
840
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- parsing trusted mount paths from OS, bounded by line anchors
|
|
841
|
+
/^\/\/(?:(?<remoteUser>[^/@]+)@)?(?<remoteHost>[^/@]+)\/(?<remoteShare>.*)$/
|
|
842
|
+
)
|
|
816
843
|
},
|
|
817
844
|
{
|
|
818
845
|
// sshfs pattern: sshfs#USER@HOST:REMOTE_PATH
|
|
819
|
-
regex:
|
|
846
|
+
regex: (
|
|
847
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- parsing trusted mount paths from OS, bounded by line anchors
|
|
848
|
+
/^(?:(?<protocol>\w+)#)?(?<remoteUser>[^@]+)@(?<remoteHost>[^:]+):(?<remoteShare>.*)$/
|
|
849
|
+
)
|
|
820
850
|
},
|
|
821
851
|
{
|
|
822
852
|
// NFS pattern: hostname:/share
|
|
823
853
|
protocol: "nfs",
|
|
824
|
-
regex: /^(?<remoteHost>[^:]+):\/(?!\/)(?<remoteShare
|
|
854
|
+
regex: /^(?<remoteHost>[^:]+):\/(?!\/)(?<remoteShare>.*)$/
|
|
825
855
|
}
|
|
826
856
|
];
|
|
827
857
|
for (const { protocol, regex } of patterns2) {
|