@photostructure/fs-metadata 1.1.0 → 1.3.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 +12 -0
- package/binding.gyp +1 -0
- package/dist/index.cjs +169 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.mts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.mjs +168 -121
- package/dist/index.mjs.map +1 -1
- package/doc/SECURITY_AUDIT_2026.md +1 -0
- package/package.json +5 -5
- package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+fs-metadata.glibc.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/darwin/get_mount_point.cpp +96 -0
- package/src/darwin/get_mount_point.h +13 -0
- package/src/index.ts +32 -1
- package/src/mount_point_for_path.ts +54 -0
- package/src/types/native_bindings.ts +7 -0
- package/src/types/options.ts +14 -0
- package/src/volume_metadata.ts +32 -10
package/dist/index.d.cts
CHANGED
|
@@ -132,6 +132,18 @@ interface MountPoint {
|
|
|
132
132
|
* @see {@link OptionsDefault} for the default values
|
|
133
133
|
*/
|
|
134
134
|
interface Options {
|
|
135
|
+
/**
|
|
136
|
+
* Pre-fetched mount points to use instead of querying the system.
|
|
137
|
+
*
|
|
138
|
+
* When provided, functions like {@link getMountPointForPath} and
|
|
139
|
+
* {@link getVolumeMetadataForPath} will use these mount points for device ID
|
|
140
|
+
* matching instead of calling {@link getVolumeMountPoints} internally. This
|
|
141
|
+
* avoids redundant system queries when resolving multiple paths.
|
|
142
|
+
*
|
|
143
|
+
* Obtain via `getVolumeMountPoints({ includeSystemVolumes: true })` — system
|
|
144
|
+
* volumes must be included for device ID matching to work correctly.
|
|
145
|
+
*/
|
|
146
|
+
mountPoints?: MountPoint[];
|
|
135
147
|
/**
|
|
136
148
|
* Timeout in milliseconds for filesystem operations.
|
|
137
149
|
*
|
|
@@ -367,7 +379,23 @@ declare function getVolumeMetadata(mountPoint: string, opts?: Partial<Pick<Optio
|
|
|
367
379
|
* @param pathname Path to any file or directory
|
|
368
380
|
* @param opts Optional filesystem operation settings
|
|
369
381
|
*/
|
|
370
|
-
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths">>): Promise<VolumeMetadata>;
|
|
382
|
+
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<VolumeMetadata>;
|
|
383
|
+
/**
|
|
384
|
+
* Get the mount point path for an arbitrary file or directory path.
|
|
385
|
+
*
|
|
386
|
+
* This is a lightweight alternative to {@link getVolumeMetadataForPath} when
|
|
387
|
+
* you only need the mount point string. On macOS it uses a single fstatfs()
|
|
388
|
+
* call (no DiskArbitration, IOKit, or space calculations). On Linux/Windows
|
|
389
|
+
* it uses device ID matching against the mount table.
|
|
390
|
+
*
|
|
391
|
+
* Symlinks are resolved, and macOS APFS firmlinks (e.g. `/Users` →
|
|
392
|
+
* `/System/Volumes/Data`) are handled correctly.
|
|
393
|
+
*
|
|
394
|
+
* @param pathname Path to any file or directory
|
|
395
|
+
* @param opts Optional settings (timeoutMs, linuxMountTablePaths)
|
|
396
|
+
* @returns The mount point path (e.g., "/", "/System/Volumes/Data", "C:\\")
|
|
397
|
+
*/
|
|
398
|
+
declare function getMountPointForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<string>;
|
|
371
399
|
/**
|
|
372
400
|
* Retrieves metadata for all mounted volumes with optional filtering and
|
|
373
401
|
* concurrency control.
|
|
@@ -429,4 +457,4 @@ declare function getHiddenMetadata(pathname: string): Promise<HiddenMetadata>;
|
|
|
429
457
|
*/
|
|
430
458
|
declare function setHidden(pathname: string, hidden: boolean, method?: HideMethod): Promise<SetHiddenResult>;
|
|
431
459
|
|
|
432
|
-
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
|
460
|
+
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getMountPointForPath, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
package/dist/index.d.mts
CHANGED
|
@@ -132,6 +132,18 @@ interface MountPoint {
|
|
|
132
132
|
* @see {@link OptionsDefault} for the default values
|
|
133
133
|
*/
|
|
134
134
|
interface Options {
|
|
135
|
+
/**
|
|
136
|
+
* Pre-fetched mount points to use instead of querying the system.
|
|
137
|
+
*
|
|
138
|
+
* When provided, functions like {@link getMountPointForPath} and
|
|
139
|
+
* {@link getVolumeMetadataForPath} will use these mount points for device ID
|
|
140
|
+
* matching instead of calling {@link getVolumeMountPoints} internally. This
|
|
141
|
+
* avoids redundant system queries when resolving multiple paths.
|
|
142
|
+
*
|
|
143
|
+
* Obtain via `getVolumeMountPoints({ includeSystemVolumes: true })` — system
|
|
144
|
+
* volumes must be included for device ID matching to work correctly.
|
|
145
|
+
*/
|
|
146
|
+
mountPoints?: MountPoint[];
|
|
135
147
|
/**
|
|
136
148
|
* Timeout in milliseconds for filesystem operations.
|
|
137
149
|
*
|
|
@@ -367,7 +379,23 @@ declare function getVolumeMetadata(mountPoint: string, opts?: Partial<Pick<Optio
|
|
|
367
379
|
* @param pathname Path to any file or directory
|
|
368
380
|
* @param opts Optional filesystem operation settings
|
|
369
381
|
*/
|
|
370
|
-
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths">>): Promise<VolumeMetadata>;
|
|
382
|
+
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<VolumeMetadata>;
|
|
383
|
+
/**
|
|
384
|
+
* Get the mount point path for an arbitrary file or directory path.
|
|
385
|
+
*
|
|
386
|
+
* This is a lightweight alternative to {@link getVolumeMetadataForPath} when
|
|
387
|
+
* you only need the mount point string. On macOS it uses a single fstatfs()
|
|
388
|
+
* call (no DiskArbitration, IOKit, or space calculations). On Linux/Windows
|
|
389
|
+
* it uses device ID matching against the mount table.
|
|
390
|
+
*
|
|
391
|
+
* Symlinks are resolved, and macOS APFS firmlinks (e.g. `/Users` →
|
|
392
|
+
* `/System/Volumes/Data`) are handled correctly.
|
|
393
|
+
*
|
|
394
|
+
* @param pathname Path to any file or directory
|
|
395
|
+
* @param opts Optional settings (timeoutMs, linuxMountTablePaths)
|
|
396
|
+
* @returns The mount point path (e.g., "/", "/System/Volumes/Data", "C:\\")
|
|
397
|
+
*/
|
|
398
|
+
declare function getMountPointForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<string>;
|
|
371
399
|
/**
|
|
372
400
|
* Retrieves metadata for all mounted volumes with optional filtering and
|
|
373
401
|
* concurrency control.
|
|
@@ -429,4 +457,4 @@ declare function getHiddenMetadata(pathname: string): Promise<HiddenMetadata>;
|
|
|
429
457
|
*/
|
|
430
458
|
declare function setHidden(pathname: string, hidden: boolean, method?: HideMethod): Promise<SetHiddenResult>;
|
|
431
459
|
|
|
432
|
-
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
|
460
|
+
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getMountPointForPath, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,18 @@ interface MountPoint {
|
|
|
132
132
|
* @see {@link OptionsDefault} for the default values
|
|
133
133
|
*/
|
|
134
134
|
interface Options {
|
|
135
|
+
/**
|
|
136
|
+
* Pre-fetched mount points to use instead of querying the system.
|
|
137
|
+
*
|
|
138
|
+
* When provided, functions like {@link getMountPointForPath} and
|
|
139
|
+
* {@link getVolumeMetadataForPath} will use these mount points for device ID
|
|
140
|
+
* matching instead of calling {@link getVolumeMountPoints} internally. This
|
|
141
|
+
* avoids redundant system queries when resolving multiple paths.
|
|
142
|
+
*
|
|
143
|
+
* Obtain via `getVolumeMountPoints({ includeSystemVolumes: true })` — system
|
|
144
|
+
* volumes must be included for device ID matching to work correctly.
|
|
145
|
+
*/
|
|
146
|
+
mountPoints?: MountPoint[];
|
|
135
147
|
/**
|
|
136
148
|
* Timeout in milliseconds for filesystem operations.
|
|
137
149
|
*
|
|
@@ -367,7 +379,23 @@ declare function getVolumeMetadata(mountPoint: string, opts?: Partial<Pick<Optio
|
|
|
367
379
|
* @param pathname Path to any file or directory
|
|
368
380
|
* @param opts Optional filesystem operation settings
|
|
369
381
|
*/
|
|
370
|
-
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths">>): Promise<VolumeMetadata>;
|
|
382
|
+
declare function getVolumeMetadataForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<VolumeMetadata>;
|
|
383
|
+
/**
|
|
384
|
+
* Get the mount point path for an arbitrary file or directory path.
|
|
385
|
+
*
|
|
386
|
+
* This is a lightweight alternative to {@link getVolumeMetadataForPath} when
|
|
387
|
+
* you only need the mount point string. On macOS it uses a single fstatfs()
|
|
388
|
+
* call (no DiskArbitration, IOKit, or space calculations). On Linux/Windows
|
|
389
|
+
* it uses device ID matching against the mount table.
|
|
390
|
+
*
|
|
391
|
+
* Symlinks are resolved, and macOS APFS firmlinks (e.g. `/Users` →
|
|
392
|
+
* `/System/Volumes/Data`) are handled correctly.
|
|
393
|
+
*
|
|
394
|
+
* @param pathname Path to any file or directory
|
|
395
|
+
* @param opts Optional settings (timeoutMs, linuxMountTablePaths)
|
|
396
|
+
* @returns The mount point path (e.g., "/", "/System/Volumes/Data", "C:\\")
|
|
397
|
+
*/
|
|
398
|
+
declare function getMountPointForPath(pathname: string, opts?: Partial<Pick<Options, "timeoutMs" | "linuxMountTablePaths" | "mountPoints">>): Promise<string>;
|
|
371
399
|
/**
|
|
372
400
|
* Retrieves metadata for all mounted volumes with optional filtering and
|
|
373
401
|
* concurrency control.
|
|
@@ -429,4 +457,4 @@ declare function getHiddenMetadata(pathname: string): Promise<HiddenMetadata>;
|
|
|
429
457
|
*/
|
|
430
458
|
declare function setHidden(pathname: string, hidden: boolean, method?: HideMethod): Promise<SetHiddenResult>;
|
|
431
459
|
|
|
432
|
-
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
|
460
|
+
export { type GetVolumeMountPointOptions, type HiddenMetadata, type HideMethod, IncludeSystemVolumesDefault, LinuxMountTablePathsDefault, type MountPoint, NetworkFsTypesDefault, type Options, OptionsDefault, type SetHiddenResult, SkipNetworkVolumesDefault, type StringEnum, type StringEnumKeys, type StringEnumType, SystemFsTypesDefault, SystemPathPatternsDefault, type SystemVolumeConfig, type VolumeHealthStatus, VolumeHealthStatuses, type VolumeMetadata, getAllVolumeMetadata, getHiddenMetadata, getMountPointForPath, getTimeoutMsDefault, getVolumeMetadata, getVolumeMetadataForPath, getVolumeMountPoints, isHidden, isHiddenRecursive, optionsWithDefaults, setHidden };
|
package/dist/index.mjs
CHANGED
|
@@ -586,6 +586,74 @@ async function setHiddenImpl(pathname, hide, method, nativeFn2) {
|
|
|
586
586
|
return { pathname: norm, actions };
|
|
587
587
|
}
|
|
588
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
|
+
|
|
589
657
|
// src/options.ts
|
|
590
658
|
import { availableParallelism as availableParallelism2 } from "os";
|
|
591
659
|
import { env as env2 } from "process";
|
|
@@ -786,113 +854,6 @@ function optionsWithDefaults(overrides = {}) {
|
|
|
786
854
|
};
|
|
787
855
|
}
|
|
788
856
|
|
|
789
|
-
// src/string_enum.ts
|
|
790
|
-
function stringEnum(...o) {
|
|
791
|
-
const set = new Set(o);
|
|
792
|
-
const dict = {};
|
|
793
|
-
for (const key of o) {
|
|
794
|
-
dict[key] = key;
|
|
795
|
-
}
|
|
796
|
-
return {
|
|
797
|
-
...dict,
|
|
798
|
-
values: Object.freeze([...set]),
|
|
799
|
-
size: set.size,
|
|
800
|
-
get: (s) => s != null && set.has(s) ? s : void 0
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// src/volume_health_status.ts
|
|
805
|
-
var VolumeHealthStatuses = stringEnum(
|
|
806
|
-
"healthy",
|
|
807
|
-
"timeout",
|
|
808
|
-
"inaccessible",
|
|
809
|
-
"disconnected",
|
|
810
|
-
"unknown"
|
|
811
|
-
);
|
|
812
|
-
async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
|
|
813
|
-
try {
|
|
814
|
-
if (await canReaddirImpl(dir, timeoutMs)) {
|
|
815
|
-
return { status: VolumeHealthStatuses.healthy };
|
|
816
|
-
}
|
|
817
|
-
} catch (error) {
|
|
818
|
-
debug("[directoryStatus] %s: %s", dir, error);
|
|
819
|
-
let status = VolumeHealthStatuses.unknown;
|
|
820
|
-
if (error instanceof TimeoutError) {
|
|
821
|
-
status = VolumeHealthStatuses.timeout;
|
|
822
|
-
} else if (isObject(error) && error instanceof Error && "code" in error) {
|
|
823
|
-
if (error.code === "EPERM" || error.code === "EACCES") {
|
|
824
|
-
status = VolumeHealthStatuses.inaccessible;
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
return { status, error: toError(error) };
|
|
828
|
-
}
|
|
829
|
-
return { status: VolumeHealthStatuses.unknown };
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// src/volume_metadata.ts
|
|
833
|
-
import { realpath } from "fs/promises";
|
|
834
|
-
import { dirname as dirname4 } from "path";
|
|
835
|
-
|
|
836
|
-
// src/linux/dev_disk.ts
|
|
837
|
-
import { readdir, readlink } from "fs/promises";
|
|
838
|
-
import { join as join3, resolve as resolve3 } from "path";
|
|
839
|
-
async function getUuidFromDevDisk(devicePath) {
|
|
840
|
-
try {
|
|
841
|
-
const result = await getBasenameLinkedTo(
|
|
842
|
-
"/dev/disk/by-uuid",
|
|
843
|
-
resolve3(devicePath)
|
|
844
|
-
);
|
|
845
|
-
debug("[getUuidFromDevDisk] result: %o", result);
|
|
846
|
-
return result;
|
|
847
|
-
} catch (error) {
|
|
848
|
-
debug("[getUuidFromDevDisk] failed: " + error);
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
async function getLabelFromDevDisk(devicePath) {
|
|
853
|
-
try {
|
|
854
|
-
const result = await getBasenameLinkedTo(
|
|
855
|
-
"/dev/disk/by-label",
|
|
856
|
-
resolve3(devicePath)
|
|
857
|
-
);
|
|
858
|
-
debug("[getLabelFromDevDisk] result: %o", result);
|
|
859
|
-
return result;
|
|
860
|
-
} catch (error) {
|
|
861
|
-
debug("[getLabelFromDevDisk] failed: " + error);
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
async function getBasenameLinkedTo(linkDir, linkPath) {
|
|
866
|
-
for await (const ea of readLinks(linkDir)) {
|
|
867
|
-
if (ea.linkTarget === linkPath) {
|
|
868
|
-
return decodeEscapeSequences(ea.dirent.name);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
async function* readLinks(directory) {
|
|
874
|
-
for (const dirent of await readdir(directory, { withFileTypes: true })) {
|
|
875
|
-
if (dirent.isSymbolicLink()) {
|
|
876
|
-
try {
|
|
877
|
-
const linkTarget = resolve3(
|
|
878
|
-
directory,
|
|
879
|
-
await readlink(join3(directory, dirent.name))
|
|
880
|
-
);
|
|
881
|
-
yield { dirent, linkTarget };
|
|
882
|
-
} catch {
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
// src/linux/mount_points.ts
|
|
889
|
-
import { readFile } from "fs/promises";
|
|
890
|
-
|
|
891
|
-
// src/mount_point.ts
|
|
892
|
-
function isMountPoint(obj) {
|
|
893
|
-
return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
857
|
// src/remote_info.ts
|
|
897
858
|
function isRemoteInfo(obj) {
|
|
898
859
|
if (!isObject(obj)) return false;
|
|
@@ -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();
|
|
@@ -1443,22 +1447,31 @@ async function getVolumeMetadataForPathImpl(pathname, opts, nativeFn2) {
|
|
|
1443
1447
|
nativeFn2
|
|
1444
1448
|
);
|
|
1445
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) {
|
|
1446
1459
|
const targetDev = resolvedStat.dev;
|
|
1447
|
-
const mountPoints = await getVolumeMountPointsImpl(
|
|
1460
|
+
const mountPoints = opts.mountPoints ?? await getVolumeMountPointsImpl(
|
|
1448
1461
|
{ ...opts, includeSystemVolumes: true },
|
|
1449
1462
|
nativeFn2
|
|
1450
1463
|
);
|
|
1451
1464
|
const prefixMatches = [];
|
|
1452
1465
|
const deviceMatches = [];
|
|
1453
1466
|
await Promise.all(
|
|
1454
|
-
mountPoints.map(async ({ mountPoint
|
|
1467
|
+
mountPoints.map(async ({ mountPoint }) => {
|
|
1455
1468
|
try {
|
|
1456
|
-
const mpDev = (await statAsync(
|
|
1469
|
+
const mpDev = (await statAsync(mountPoint)).dev;
|
|
1457
1470
|
if (mpDev !== targetDev) return;
|
|
1458
|
-
if (isAncestorOrSelf(
|
|
1459
|
-
prefixMatches.push(
|
|
1471
|
+
if (isAncestorOrSelf(mountPoint, resolved)) {
|
|
1472
|
+
prefixMatches.push(mountPoint);
|
|
1460
1473
|
} else {
|
|
1461
|
-
deviceMatches.push(
|
|
1474
|
+
deviceMatches.push(mountPoint);
|
|
1462
1475
|
}
|
|
1463
1476
|
} catch {
|
|
1464
1477
|
}
|
|
@@ -1467,13 +1480,10 @@ async function getVolumeMetadataForPathImpl(pathname, opts, nativeFn2) {
|
|
|
1467
1480
|
const candidates = prefixMatches.length > 0 ? prefixMatches : deviceMatches;
|
|
1468
1481
|
if (candidates.length === 0) {
|
|
1469
1482
|
throw new Error(
|
|
1470
|
-
"No mount point found for path: " + JSON.stringify(
|
|
1483
|
+
"No mount point found for path: " + JSON.stringify(resolved)
|
|
1471
1484
|
);
|
|
1472
1485
|
}
|
|
1473
|
-
|
|
1474
|
-
(a, b) => a.length >= b.length ? a : b
|
|
1475
|
-
);
|
|
1476
|
-
return getVolumeMetadataImpl({ ...opts, mountPoint }, nativeFn2);
|
|
1486
|
+
return candidates.reduce((a, b) => a.length >= b.length ? a : b);
|
|
1477
1487
|
}
|
|
1478
1488
|
async function getAllVolumeMetadataImpl(opts, nativeFn2) {
|
|
1479
1489
|
const o = optionsWithDefaults(opts);
|
|
@@ -1526,15 +1536,44 @@ async function getAllVolumeMetadataImpl(opts, nativeFn2) {
|
|
|
1526
1536
|
);
|
|
1527
1537
|
}
|
|
1528
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
|
+
|
|
1529
1568
|
// src/index.ts
|
|
1530
1569
|
var nativeFn = defer2(async () => {
|
|
1531
1570
|
const start = Date.now();
|
|
1532
1571
|
try {
|
|
1533
|
-
const
|
|
1534
|
-
const dir = await findAncestorDir(
|
|
1572
|
+
const dirname6 = _dirname();
|
|
1573
|
+
const dir = await findAncestorDir(dirname6, "binding.gyp");
|
|
1535
1574
|
if (dir == null) {
|
|
1536
1575
|
throw new Error(
|
|
1537
|
-
"Could not find bindings.gyp in any ancestor directory of " +
|
|
1576
|
+
"Could not find bindings.gyp in any ancestor directory of " + dirname6
|
|
1538
1577
|
);
|
|
1539
1578
|
}
|
|
1540
1579
|
const bindings = NodeGypBuild(dir);
|
|
@@ -1564,6 +1603,13 @@ function getVolumeMetadataForPath(pathname, opts) {
|
|
|
1564
1603
|
nativeFn
|
|
1565
1604
|
);
|
|
1566
1605
|
}
|
|
1606
|
+
function getMountPointForPath(pathname, opts) {
|
|
1607
|
+
return getMountPointForPathImpl(
|
|
1608
|
+
pathname,
|
|
1609
|
+
optionsWithDefaults(opts),
|
|
1610
|
+
nativeFn
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1567
1613
|
function getAllVolumeMetadata(opts) {
|
|
1568
1614
|
return getAllVolumeMetadataImpl(optionsWithDefaults(opts), nativeFn);
|
|
1569
1615
|
}
|
|
@@ -1590,6 +1636,7 @@ export {
|
|
|
1590
1636
|
VolumeHealthStatuses,
|
|
1591
1637
|
getAllVolumeMetadata,
|
|
1592
1638
|
getHiddenMetadata,
|
|
1639
|
+
getMountPointForPath,
|
|
1593
1640
|
getTimeoutMsDefault,
|
|
1594
1641
|
getVolumeMetadata,
|
|
1595
1642
|
getVolumeMetadataForPath,
|