@photostructure/fs-metadata 1.0.1 → 1.2.0
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 +44 -0
- package/CLAUDE.md +13 -0
- package/binding.gyp +1 -0
- package/claude.sh +29 -5
- package/dist/index.cjs +237 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -3
- package/dist/index.d.mts +55 -3
- package/dist/index.d.ts +55 -3
- package/dist/index.mjs +236 -130
- package/dist/index.mjs.map +1 -1
- package/doc/SECURITY_AUDIT_2025.md +1 -1
- package/doc/SECURITY_AUDIT_2026.md +361 -0
- package/doc/TPP-GUIDE.md +144 -0
- package/doc/system-volume-detection.md +268 -0
- package/package.json +12 -12
- 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/src/binding.cpp +11 -0
- package/src/common/volume_metadata.h +10 -3
- package/src/common/volume_mount_points.h +7 -1
- package/src/darwin/da_mutex.h +23 -0
- package/src/darwin/get_mount_point.cpp +96 -0
- package/src/darwin/get_mount_point.h +13 -0
- package/src/darwin/raii_utils.h +39 -0
- package/src/darwin/system_volume.h +156 -0
- package/src/darwin/volume_metadata.cpp +18 -2
- package/src/darwin/volume_mount_points.cpp +46 -14
- package/src/index.ts +49 -0
- package/src/linux/mtab.ts +6 -0
- package/src/mount_point_for_path.ts +54 -0
- package/src/options.ts +7 -17
- package/src/path.ts +16 -1
- package/src/system_volume.ts +5 -9
- package/src/test-utils/assert.ts +4 -0
- package/src/types/mount_point.ts +28 -1
- package/src/types/native_bindings.ts +7 -0
- package/src/volume_metadata.ts +117 -2
- package/src/windows/system_volume.h +21 -16
- package/src/windows/volume_metadata.cpp +13 -7
- package/src/windows/volume_mount_points.cpp +11 -7
package/dist/index.mjs
CHANGED
|
@@ -388,7 +388,7 @@ function toError(cause) {
|
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
// src/path.ts
|
|
391
|
-
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
391
|
+
import { dirname as dirname2, resolve as resolve2, sep } from "path";
|
|
392
392
|
function normalizePath(mountPoint) {
|
|
393
393
|
if (isBlank(mountPoint)) return void 0;
|
|
394
394
|
if (mountPoint.includes("..")) {
|
|
@@ -417,6 +417,11 @@ function isRootDirectory(path2) {
|
|
|
417
417
|
const n = normalizePath(path2);
|
|
418
418
|
return n == null ? false : isWindows ? dirname2(n) === n : n === "/";
|
|
419
419
|
}
|
|
420
|
+
function isAncestorOrSelf(ancestor, descendant) {
|
|
421
|
+
if (ancestor === descendant) return true;
|
|
422
|
+
const prefix = isRootDirectory(ancestor) ? ancestor : ancestor + sep;
|
|
423
|
+
return descendant.startsWith(prefix);
|
|
424
|
+
}
|
|
420
425
|
|
|
421
426
|
// src/hidden.ts
|
|
422
427
|
var HiddenSupportByPlatform = {
|
|
@@ -581,6 +586,74 @@ async function setHiddenImpl(pathname, hide, method, nativeFn2) {
|
|
|
581
586
|
return { pathname: norm, actions };
|
|
582
587
|
}
|
|
583
588
|
|
|
589
|
+
// src/mount_point_for_path.ts
|
|
590
|
+
import { realpath as realpath2 } from "fs/promises";
|
|
591
|
+
import { dirname as dirname5 } from "path";
|
|
592
|
+
|
|
593
|
+
// src/volume_metadata.ts
|
|
594
|
+
import { realpath } from "fs/promises";
|
|
595
|
+
import { dirname as dirname4 } from "path";
|
|
596
|
+
|
|
597
|
+
// src/linux/dev_disk.ts
|
|
598
|
+
import { readdir, readlink } from "fs/promises";
|
|
599
|
+
import { join as join3, resolve as resolve3 } from "path";
|
|
600
|
+
async function getUuidFromDevDisk(devicePath) {
|
|
601
|
+
try {
|
|
602
|
+
const result = await getBasenameLinkedTo(
|
|
603
|
+
"/dev/disk/by-uuid",
|
|
604
|
+
resolve3(devicePath)
|
|
605
|
+
);
|
|
606
|
+
debug("[getUuidFromDevDisk] result: %o", result);
|
|
607
|
+
return result;
|
|
608
|
+
} catch (error) {
|
|
609
|
+
debug("[getUuidFromDevDisk] failed: " + error);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
async function getLabelFromDevDisk(devicePath) {
|
|
614
|
+
try {
|
|
615
|
+
const result = await getBasenameLinkedTo(
|
|
616
|
+
"/dev/disk/by-label",
|
|
617
|
+
resolve3(devicePath)
|
|
618
|
+
);
|
|
619
|
+
debug("[getLabelFromDevDisk] result: %o", result);
|
|
620
|
+
return result;
|
|
621
|
+
} catch (error) {
|
|
622
|
+
debug("[getLabelFromDevDisk] failed: " + error);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
async function getBasenameLinkedTo(linkDir, linkPath) {
|
|
627
|
+
for await (const ea of readLinks(linkDir)) {
|
|
628
|
+
if (ea.linkTarget === linkPath) {
|
|
629
|
+
return decodeEscapeSequences(ea.dirent.name);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
async function* readLinks(directory) {
|
|
635
|
+
for (const dirent of await readdir(directory, { withFileTypes: true })) {
|
|
636
|
+
if (dirent.isSymbolicLink()) {
|
|
637
|
+
try {
|
|
638
|
+
const linkTarget = resolve3(
|
|
639
|
+
directory,
|
|
640
|
+
await readlink(join3(directory, dirent.name))
|
|
641
|
+
);
|
|
642
|
+
yield { dirent, linkTarget };
|
|
643
|
+
} catch {
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// src/linux/mount_points.ts
|
|
650
|
+
import { readFile } from "fs/promises";
|
|
651
|
+
|
|
652
|
+
// src/mount_point.ts
|
|
653
|
+
function isMountPoint(obj) {
|
|
654
|
+
return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
|
|
655
|
+
}
|
|
656
|
+
|
|
584
657
|
// src/options.ts
|
|
585
658
|
import { availableParallelism as availableParallelism2 } from "os";
|
|
586
659
|
import { env as env2 } from "process";
|
|
@@ -643,23 +716,13 @@ var SystemPathPatternsDefault = [
|
|
|
643
716
|
"/mnt/wslg/doc",
|
|
644
717
|
"/mnt/wslg/versions.txt",
|
|
645
718
|
"/usr/lib/wsl/drivers",
|
|
646
|
-
// macOS system
|
|
647
|
-
"
|
|
648
|
-
//
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
"/
|
|
653
|
-
"/System/Volumes/Reserved",
|
|
654
|
-
"/System/Volumes/Update",
|
|
655
|
-
"/System/Volumes/VM",
|
|
656
|
-
"/System/Volumes/xarts",
|
|
657
|
-
// macOS per-volume metadata (Spotlight, FSEvents, versioning, Trash):
|
|
658
|
-
// https://eclecticlight.co/2021/01/28/spotlight-on-search-how-spotlight-works/
|
|
659
|
-
"**/.DocumentRevisions-V100",
|
|
660
|
-
"**/.fseventsd",
|
|
661
|
-
"**/.Spotlight-V100",
|
|
662
|
-
"**/.Trashes"
|
|
719
|
+
// macOS system volumes are detected natively via APFS volume roles
|
|
720
|
+
// (IOKit IOMedia "Role" property) with MNT_SNAPSHOT as a fallback.
|
|
721
|
+
// No path patterns needed. See src/darwin/system_volume.h.
|
|
722
|
+
//
|
|
723
|
+
// /private/var/vm is the macOS swap directory (not a mount point on most
|
|
724
|
+
// systems, but included for completeness if it appears as one).
|
|
725
|
+
"/private/var/vm"
|
|
663
726
|
];
|
|
664
727
|
var SystemFsTypesDefault = [
|
|
665
728
|
"autofs",
|
|
@@ -791,109 +854,6 @@ function optionsWithDefaults(overrides = {}) {
|
|
|
791
854
|
};
|
|
792
855
|
}
|
|
793
856
|
|
|
794
|
-
// src/string_enum.ts
|
|
795
|
-
function stringEnum(...o) {
|
|
796
|
-
const set = new Set(o);
|
|
797
|
-
const dict = {};
|
|
798
|
-
for (const key of o) {
|
|
799
|
-
dict[key] = key;
|
|
800
|
-
}
|
|
801
|
-
return {
|
|
802
|
-
...dict,
|
|
803
|
-
values: Object.freeze([...set]),
|
|
804
|
-
size: set.size,
|
|
805
|
-
get: (s) => s != null && set.has(s) ? s : void 0
|
|
806
|
-
};
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
// src/volume_health_status.ts
|
|
810
|
-
var VolumeHealthStatuses = stringEnum(
|
|
811
|
-
"healthy",
|
|
812
|
-
"timeout",
|
|
813
|
-
"inaccessible",
|
|
814
|
-
"disconnected",
|
|
815
|
-
"unknown"
|
|
816
|
-
);
|
|
817
|
-
async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
|
|
818
|
-
try {
|
|
819
|
-
if (await canReaddirImpl(dir, timeoutMs)) {
|
|
820
|
-
return { status: VolumeHealthStatuses.healthy };
|
|
821
|
-
}
|
|
822
|
-
} catch (error) {
|
|
823
|
-
debug("[directoryStatus] %s: %s", dir, error);
|
|
824
|
-
let status = VolumeHealthStatuses.unknown;
|
|
825
|
-
if (error instanceof TimeoutError) {
|
|
826
|
-
status = VolumeHealthStatuses.timeout;
|
|
827
|
-
} else if (isObject(error) && error instanceof Error && "code" in error) {
|
|
828
|
-
if (error.code === "EPERM" || error.code === "EACCES") {
|
|
829
|
-
status = VolumeHealthStatuses.inaccessible;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
return { status, error: toError(error) };
|
|
833
|
-
}
|
|
834
|
-
return { status: VolumeHealthStatuses.unknown };
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// src/linux/dev_disk.ts
|
|
838
|
-
import { readdir, readlink } from "fs/promises";
|
|
839
|
-
import { join as join3, resolve as resolve3 } from "path";
|
|
840
|
-
async function getUuidFromDevDisk(devicePath) {
|
|
841
|
-
try {
|
|
842
|
-
const result = await getBasenameLinkedTo(
|
|
843
|
-
"/dev/disk/by-uuid",
|
|
844
|
-
resolve3(devicePath)
|
|
845
|
-
);
|
|
846
|
-
debug("[getUuidFromDevDisk] result: %o", result);
|
|
847
|
-
return result;
|
|
848
|
-
} catch (error) {
|
|
849
|
-
debug("[getUuidFromDevDisk] failed: " + error);
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
async function getLabelFromDevDisk(devicePath) {
|
|
854
|
-
try {
|
|
855
|
-
const result = await getBasenameLinkedTo(
|
|
856
|
-
"/dev/disk/by-label",
|
|
857
|
-
resolve3(devicePath)
|
|
858
|
-
);
|
|
859
|
-
debug("[getLabelFromDevDisk] result: %o", result);
|
|
860
|
-
return result;
|
|
861
|
-
} catch (error) {
|
|
862
|
-
debug("[getLabelFromDevDisk] failed: " + error);
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
async function getBasenameLinkedTo(linkDir, linkPath) {
|
|
867
|
-
for await (const ea of readLinks(linkDir)) {
|
|
868
|
-
if (ea.linkTarget === linkPath) {
|
|
869
|
-
return decodeEscapeSequences(ea.dirent.name);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
async function* readLinks(directory) {
|
|
875
|
-
for (const dirent of await readdir(directory, { withFileTypes: true })) {
|
|
876
|
-
if (dirent.isSymbolicLink()) {
|
|
877
|
-
try {
|
|
878
|
-
const linkTarget = resolve3(
|
|
879
|
-
directory,
|
|
880
|
-
await readlink(join3(directory, dirent.name))
|
|
881
|
-
);
|
|
882
|
-
yield { dirent, linkTarget };
|
|
883
|
-
} catch {
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// src/linux/mount_points.ts
|
|
890
|
-
import { readFile } from "fs/promises";
|
|
891
|
-
|
|
892
|
-
// src/mount_point.ts
|
|
893
|
-
function isMountPoint(obj) {
|
|
894
|
-
return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
857
|
// src/remote_info.ts
|
|
898
858
|
function isRemoteInfo(obj) {
|
|
899
859
|
if (!isObject(obj)) return false;
|
|
@@ -1118,20 +1078,20 @@ function isSystemVolume(mountPoint, fstype, config = {}) {
|
|
|
1118
1078
|
}
|
|
1119
1079
|
function assignSystemVolume(mp, config) {
|
|
1120
1080
|
const result = isSystemVolume(mp.mountPoint, mp.fstype, config);
|
|
1121
|
-
|
|
1122
|
-
mp.isSystemVolume ??= result;
|
|
1123
|
-
} else {
|
|
1124
|
-
mp.isSystemVolume = result;
|
|
1125
|
-
}
|
|
1081
|
+
mp.isSystemVolume = mp.isSystemVolume || result;
|
|
1126
1082
|
}
|
|
1127
1083
|
|
|
1128
1084
|
// src/linux/mtab.ts
|
|
1085
|
+
function isReadOnlyMount(fs_mntops) {
|
|
1086
|
+
return fs_mntops?.split(",").includes("ro") ?? false;
|
|
1087
|
+
}
|
|
1129
1088
|
function mountEntryToMountPoint(entry) {
|
|
1130
1089
|
const mountPoint = normalizePosixPath(entry.fs_file);
|
|
1131
1090
|
const fstype = toNotBlank(entry.fs_vfstype) ?? toNotBlank(entry.fs_spec);
|
|
1132
1091
|
return mountPoint == null || fstype == null ? void 0 : {
|
|
1133
1092
|
mountPoint,
|
|
1134
|
-
fstype
|
|
1093
|
+
fstype,
|
|
1094
|
+
isReadOnly: isReadOnlyMount(entry.fs_mntops)
|
|
1135
1095
|
};
|
|
1136
1096
|
}
|
|
1137
1097
|
function mountEntryToPartialVolumeMetadata(entry, options = {}) {
|
|
@@ -1141,6 +1101,7 @@ function mountEntryToPartialVolumeMetadata(entry, options = {}) {
|
|
|
1141
1101
|
fstype: entry.fs_vfstype,
|
|
1142
1102
|
mountFrom: entry.fs_spec,
|
|
1143
1103
|
isSystemVolume: isSystemVolume(entry.fs_file, entry.fs_vfstype, options),
|
|
1104
|
+
isReadOnly: isReadOnlyMount(entry.fs_mntops),
|
|
1144
1105
|
remote: false,
|
|
1145
1106
|
// < default to false, but it may be overridden by extractRemoteInfo
|
|
1146
1107
|
...extractRemoteInfo(entry.fs_spec, networkFsTypes)
|
|
@@ -1274,6 +1235,49 @@ function extractUUID(uuid) {
|
|
|
1274
1235
|
return toS(uuid).match(uuidRegex)?.[0];
|
|
1275
1236
|
}
|
|
1276
1237
|
|
|
1238
|
+
// src/string_enum.ts
|
|
1239
|
+
function stringEnum(...o) {
|
|
1240
|
+
const set = new Set(o);
|
|
1241
|
+
const dict = {};
|
|
1242
|
+
for (const key of o) {
|
|
1243
|
+
dict[key] = key;
|
|
1244
|
+
}
|
|
1245
|
+
return {
|
|
1246
|
+
...dict,
|
|
1247
|
+
values: Object.freeze([...set]),
|
|
1248
|
+
size: set.size,
|
|
1249
|
+
get: (s) => s != null && set.has(s) ? s : void 0
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// src/volume_health_status.ts
|
|
1254
|
+
var VolumeHealthStatuses = stringEnum(
|
|
1255
|
+
"healthy",
|
|
1256
|
+
"timeout",
|
|
1257
|
+
"inaccessible",
|
|
1258
|
+
"disconnected",
|
|
1259
|
+
"unknown"
|
|
1260
|
+
);
|
|
1261
|
+
async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
|
|
1262
|
+
try {
|
|
1263
|
+
if (await canReaddirImpl(dir, timeoutMs)) {
|
|
1264
|
+
return { status: VolumeHealthStatuses.healthy };
|
|
1265
|
+
}
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
debug("[directoryStatus] %s: %s", dir, error);
|
|
1268
|
+
let status = VolumeHealthStatuses.unknown;
|
|
1269
|
+
if (error instanceof TimeoutError) {
|
|
1270
|
+
status = VolumeHealthStatuses.timeout;
|
|
1271
|
+
} else if (isObject(error) && error instanceof Error && "code" in error) {
|
|
1272
|
+
if (error.code === "EPERM" || error.code === "EACCES") {
|
|
1273
|
+
status = VolumeHealthStatuses.inaccessible;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return { status, error: toError(error) };
|
|
1277
|
+
}
|
|
1278
|
+
return { status: VolumeHealthStatuses.unknown };
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1277
1281
|
// src/array.ts
|
|
1278
1282
|
function uniqBy(arr, keyFn) {
|
|
1279
1283
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -1424,6 +1428,63 @@ async function _getVolumeMetadata(o, nativeFn2) {
|
|
|
1424
1428
|
debug("[getVolumeMetadata] final result for %s: %o", o.mountPoint, result);
|
|
1425
1429
|
return compactValues(result);
|
|
1426
1430
|
}
|
|
1431
|
+
async function getVolumeMetadataForPathImpl(pathname, opts, nativeFn2) {
|
|
1432
|
+
if (isBlank(pathname)) {
|
|
1433
|
+
throw new TypeError("Invalid pathname: got " + JSON.stringify(pathname));
|
|
1434
|
+
}
|
|
1435
|
+
const resolved = await realpath(pathname);
|
|
1436
|
+
const resolvedStat = await statAsync(resolved);
|
|
1437
|
+
const dir = resolvedStat.isDirectory() ? resolved : dirname4(resolved);
|
|
1438
|
+
if (isMacOS) {
|
|
1439
|
+
const probe = await getVolumeMetadataImpl(
|
|
1440
|
+
{ ...opts, mountPoint: dir },
|
|
1441
|
+
nativeFn2
|
|
1442
|
+
);
|
|
1443
|
+
const canonicalMountPoint = isNotBlank(probe.mountName) ? probe.mountName : dir;
|
|
1444
|
+
if (canonicalMountPoint === dir) return probe;
|
|
1445
|
+
return getVolumeMetadataImpl(
|
|
1446
|
+
{ ...opts, mountPoint: canonicalMountPoint },
|
|
1447
|
+
nativeFn2
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
const mountPoint = await findMountPointByDeviceId(
|
|
1451
|
+
resolved,
|
|
1452
|
+
resolvedStat,
|
|
1453
|
+
opts,
|
|
1454
|
+
nativeFn2
|
|
1455
|
+
);
|
|
1456
|
+
return getVolumeMetadataImpl({ ...opts, mountPoint }, nativeFn2);
|
|
1457
|
+
}
|
|
1458
|
+
async function findMountPointByDeviceId(resolved, resolvedStat, opts, nativeFn2) {
|
|
1459
|
+
const targetDev = resolvedStat.dev;
|
|
1460
|
+
const mountPoints = await getVolumeMountPointsImpl(
|
|
1461
|
+
{ ...opts, includeSystemVolumes: true },
|
|
1462
|
+
nativeFn2
|
|
1463
|
+
);
|
|
1464
|
+
const prefixMatches = [];
|
|
1465
|
+
const deviceMatches = [];
|
|
1466
|
+
await Promise.all(
|
|
1467
|
+
mountPoints.map(async ({ mountPoint }) => {
|
|
1468
|
+
try {
|
|
1469
|
+
const mpDev = (await statAsync(mountPoint)).dev;
|
|
1470
|
+
if (mpDev !== targetDev) return;
|
|
1471
|
+
if (isAncestorOrSelf(mountPoint, resolved)) {
|
|
1472
|
+
prefixMatches.push(mountPoint);
|
|
1473
|
+
} else {
|
|
1474
|
+
deviceMatches.push(mountPoint);
|
|
1475
|
+
}
|
|
1476
|
+
} catch {
|
|
1477
|
+
}
|
|
1478
|
+
})
|
|
1479
|
+
);
|
|
1480
|
+
const candidates = prefixMatches.length > 0 ? prefixMatches : deviceMatches;
|
|
1481
|
+
if (candidates.length === 0) {
|
|
1482
|
+
throw new Error(
|
|
1483
|
+
"No mount point found for path: " + JSON.stringify(resolved)
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
return candidates.reduce((a, b) => a.length >= b.length ? a : b);
|
|
1487
|
+
}
|
|
1427
1488
|
async function getAllVolumeMetadataImpl(opts, nativeFn2) {
|
|
1428
1489
|
const o = optionsWithDefaults(opts);
|
|
1429
1490
|
debug("[getAllVolumeMetadata] starting with options: %o", o);
|
|
@@ -1475,15 +1536,44 @@ async function getAllVolumeMetadataImpl(opts, nativeFn2) {
|
|
|
1475
1536
|
);
|
|
1476
1537
|
}
|
|
1477
1538
|
|
|
1539
|
+
// src/mount_point_for_path.ts
|
|
1540
|
+
async function getMountPointForPathImpl(pathname, opts, nativeFn2) {
|
|
1541
|
+
if (isBlank(pathname)) {
|
|
1542
|
+
throw new TypeError("Invalid pathname: got " + JSON.stringify(pathname));
|
|
1543
|
+
}
|
|
1544
|
+
const resolved = await realpath2(pathname);
|
|
1545
|
+
const resolvedStat = await statAsync(resolved);
|
|
1546
|
+
const dir = resolvedStat.isDirectory() ? resolved : dirname5(resolved);
|
|
1547
|
+
if (isMacOS) {
|
|
1548
|
+
const native = await nativeFn2();
|
|
1549
|
+
if (native.getMountPoint) {
|
|
1550
|
+
debug("[getMountPointForPath] using native getMountPoint for %s", dir);
|
|
1551
|
+
const p = native.getMountPoint(dir);
|
|
1552
|
+
const mountPoint = await withTimeout({
|
|
1553
|
+
desc: "getMountPoint()",
|
|
1554
|
+
timeoutMs: opts.timeoutMs,
|
|
1555
|
+
promise: p
|
|
1556
|
+
});
|
|
1557
|
+
if (isNotBlank(mountPoint)) {
|
|
1558
|
+
debug("[getMountPointForPath] resolved to %s", mountPoint);
|
|
1559
|
+
return mountPoint;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
throw new Error("getMountPoint native function unavailable");
|
|
1563
|
+
}
|
|
1564
|
+
debug("[getMountPointForPath] using device matching for %s", resolved);
|
|
1565
|
+
return findMountPointByDeviceId(resolved, resolvedStat, opts, nativeFn2);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1478
1568
|
// src/index.ts
|
|
1479
1569
|
var nativeFn = defer2(async () => {
|
|
1480
1570
|
const start = Date.now();
|
|
1481
1571
|
try {
|
|
1482
|
-
const
|
|
1483
|
-
const dir = await findAncestorDir(
|
|
1572
|
+
const dirname6 = _dirname();
|
|
1573
|
+
const dir = await findAncestorDir(dirname6, "binding.gyp");
|
|
1484
1574
|
if (dir == null) {
|
|
1485
1575
|
throw new Error(
|
|
1486
|
-
"Could not find bindings.gyp in any ancestor directory of " +
|
|
1576
|
+
"Could not find bindings.gyp in any ancestor directory of " + dirname6
|
|
1487
1577
|
);
|
|
1488
1578
|
}
|
|
1489
1579
|
const bindings = NodeGypBuild(dir);
|
|
@@ -1506,6 +1596,20 @@ function getVolumeMetadata(mountPoint, opts) {
|
|
|
1506
1596
|
nativeFn
|
|
1507
1597
|
);
|
|
1508
1598
|
}
|
|
1599
|
+
function getVolumeMetadataForPath(pathname, opts) {
|
|
1600
|
+
return getVolumeMetadataForPathImpl(
|
|
1601
|
+
pathname,
|
|
1602
|
+
optionsWithDefaults(opts),
|
|
1603
|
+
nativeFn
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
function getMountPointForPath(pathname, opts) {
|
|
1607
|
+
return getMountPointForPathImpl(
|
|
1608
|
+
pathname,
|
|
1609
|
+
optionsWithDefaults(opts),
|
|
1610
|
+
nativeFn
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1509
1613
|
function getAllVolumeMetadata(opts) {
|
|
1510
1614
|
return getAllVolumeMetadataImpl(optionsWithDefaults(opts), nativeFn);
|
|
1511
1615
|
}
|
|
@@ -1532,8 +1636,10 @@ export {
|
|
|
1532
1636
|
VolumeHealthStatuses,
|
|
1533
1637
|
getAllVolumeMetadata,
|
|
1534
1638
|
getHiddenMetadata,
|
|
1639
|
+
getMountPointForPath,
|
|
1535
1640
|
getTimeoutMsDefault,
|
|
1536
1641
|
getVolumeMetadata,
|
|
1642
|
+
getVolumeMetadataForPath,
|
|
1537
1643
|
getVolumeMountPoints,
|
|
1538
1644
|
isHidden,
|
|
1539
1645
|
isHiddenRecursive,
|