@photostructure/fs-metadata 0.4.0 → 0.5.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.
Files changed (179) hide show
  1. package/C++_REVIEW_TODO.md +291 -0
  2. package/CHANGELOG.md +29 -1
  3. package/CLAUDE.md +169 -0
  4. package/CONTRIBUTING.md +25 -0
  5. package/coverage/base.css +224 -0
  6. package/coverage/block-navigation.js +87 -0
  7. package/coverage/favicon.png +0 -0
  8. package/coverage/index.html +131 -0
  9. package/coverage/lcov-report/base.css +224 -0
  10. package/coverage/lcov-report/block-navigation.js +87 -0
  11. package/coverage/lcov-report/favicon.png +0 -0
  12. package/coverage/lcov-report/index.html +131 -0
  13. package/coverage/lcov-report/prettify.css +1 -0
  14. package/coverage/lcov-report/prettify.js +2 -0
  15. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  16. package/coverage/lcov-report/sorter.js +196 -0
  17. package/coverage/lcov-report/src/array.ts.html +217 -0
  18. package/coverage/lcov-report/src/async.ts.html +547 -0
  19. package/coverage/lcov-report/src/debuglog.ts.html +187 -0
  20. package/coverage/lcov-report/src/defer.ts.html +175 -0
  21. package/coverage/lcov-report/src/dirname.ts.html +124 -0
  22. package/coverage/lcov-report/src/error.ts.html +322 -0
  23. package/coverage/lcov-report/src/fs.ts.html +316 -0
  24. package/coverage/lcov-report/src/glob.ts.html +472 -0
  25. package/coverage/lcov-report/src/hidden.ts.html +724 -0
  26. package/coverage/lcov-report/src/index.html +521 -0
  27. package/coverage/lcov-report/src/index.ts.html +676 -0
  28. package/coverage/lcov-report/src/linux/dev_disk.ts.html +316 -0
  29. package/coverage/lcov-report/src/linux/index.html +146 -0
  30. package/coverage/lcov-report/src/linux/mount_points.ts.html +364 -0
  31. package/coverage/lcov-report/src/linux/mtab.ts.html +493 -0
  32. package/coverage/lcov-report/src/mount_point.ts.html +106 -0
  33. package/coverage/lcov-report/src/number.ts.html +148 -0
  34. package/coverage/lcov-report/src/object.ts.html +265 -0
  35. package/coverage/lcov-report/src/options.ts.html +475 -0
  36. package/coverage/lcov-report/src/path.ts.html +268 -0
  37. package/coverage/lcov-report/src/platform.ts.html +112 -0
  38. package/coverage/lcov-report/src/random.ts.html +205 -0
  39. package/coverage/lcov-report/src/remote_info.ts.html +553 -0
  40. package/coverage/lcov-report/src/stack_path.ts.html +298 -0
  41. package/coverage/lcov-report/src/string.ts.html +382 -0
  42. package/coverage/lcov-report/src/string_enum.ts.html +208 -0
  43. package/coverage/lcov-report/src/system_volume.ts.html +301 -0
  44. package/coverage/lcov-report/src/unc.ts.html +274 -0
  45. package/coverage/lcov-report/src/units.ts.html +274 -0
  46. package/coverage/lcov-report/src/uuid.ts.html +157 -0
  47. package/coverage/lcov-report/src/volume_health_status.ts.html +259 -0
  48. package/coverage/lcov-report/src/volume_metadata.ts.html +787 -0
  49. package/coverage/lcov-report/src/volume_mount_points.ts.html +388 -0
  50. package/coverage/lcov.info +3581 -0
  51. package/coverage/prettify.css +1 -0
  52. package/coverage/prettify.js +2 -0
  53. package/coverage/sort-arrow-sprite.png +0 -0
  54. package/coverage/sorter.js +196 -0
  55. package/coverage/src/array.ts.html +217 -0
  56. package/coverage/src/async.ts.html +547 -0
  57. package/coverage/src/debuglog.ts.html +187 -0
  58. package/coverage/src/defer.ts.html +175 -0
  59. package/coverage/src/dirname.ts.html +124 -0
  60. package/coverage/src/error.ts.html +322 -0
  61. package/coverage/src/fs.ts.html +316 -0
  62. package/coverage/src/glob.ts.html +472 -0
  63. package/coverage/src/hidden.ts.html +724 -0
  64. package/coverage/src/index.html +521 -0
  65. package/coverage/src/index.ts.html +676 -0
  66. package/coverage/src/linux/dev_disk.ts.html +316 -0
  67. package/coverage/src/linux/index.html +146 -0
  68. package/coverage/src/linux/mount_points.ts.html +364 -0
  69. package/coverage/src/linux/mtab.ts.html +493 -0
  70. package/coverage/src/mount_point.ts.html +106 -0
  71. package/coverage/src/number.ts.html +148 -0
  72. package/coverage/src/object.ts.html +265 -0
  73. package/coverage/src/options.ts.html +475 -0
  74. package/coverage/src/path.ts.html +268 -0
  75. package/coverage/src/platform.ts.html +112 -0
  76. package/coverage/src/random.ts.html +205 -0
  77. package/coverage/src/remote_info.ts.html +553 -0
  78. package/coverage/src/stack_path.ts.html +298 -0
  79. package/coverage/src/string.ts.html +382 -0
  80. package/coverage/src/string_enum.ts.html +208 -0
  81. package/coverage/src/system_volume.ts.html +301 -0
  82. package/coverage/src/unc.ts.html +274 -0
  83. package/coverage/src/units.ts.html +274 -0
  84. package/coverage/src/uuid.ts.html +157 -0
  85. package/coverage/src/volume_health_status.ts.html +259 -0
  86. package/coverage/src/volume_metadata.ts.html +787 -0
  87. package/coverage/src/volume_mount_points.ts.html +388 -0
  88. package/jest.config.cjs +67 -6
  89. package/package.json +51 -41
  90. package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
  91. package/scripts/check-memory.mjs +243 -0
  92. package/scripts/clang-tidy.mjs +73 -0
  93. package/scripts/is-platform.mjs +12 -0
  94. package/scripts/post-build.mjs +21 -0
  95. package/scripts/run-asan.sh +92 -0
  96. package/scripts/valgrind-test.mjs +83 -0
  97. package/scripts/valgrind.sh +70 -0
  98. package/src/async.ts +3 -3
  99. package/src/binding.cpp +3 -3
  100. package/src/error.ts +3 -3
  101. package/src/fs.ts +1 -1
  102. package/src/glob.ts +2 -2
  103. package/src/hidden.ts +6 -6
  104. package/src/index.ts +19 -23
  105. package/src/linux/blkid_cache.cpp +15 -12
  106. package/src/linux/dev_disk.ts +2 -2
  107. package/src/linux/gio_mount_points.cpp +7 -7
  108. package/src/linux/gio_utils.cpp +19 -8
  109. package/src/linux/gio_volume_metadata.cpp +15 -15
  110. package/src/linux/mount_points.ts +9 -9
  111. package/src/linux/mtab.ts +7 -7
  112. package/src/linux/volume_metadata.cpp +6 -1
  113. package/src/object.ts +1 -1
  114. package/src/options.ts +3 -3
  115. package/src/path.ts +2 -2
  116. package/src/remote_info.ts +5 -5
  117. package/src/system_volume.ts +8 -8
  118. package/src/test-utils/assert.ts +2 -2
  119. package/src/test-utils/debuglog-child.ts +1 -3
  120. package/src/test-utils/debuglog-enabled-child.ts +10 -0
  121. package/src/test-utils/hidden-tests.ts +1 -1
  122. package/src/test-utils/platform.ts +3 -3
  123. package/src/types/native_bindings.ts +3 -3
  124. package/src/types/volume_metadata.ts +2 -2
  125. package/src/unc.ts +2 -2
  126. package/src/uuid.ts +1 -1
  127. package/src/volume_health_status.ts +6 -6
  128. package/src/volume_metadata.ts +20 -23
  129. package/src/volume_mount_points.ts +12 -17
  130. package/src/windows/drive_status.h +30 -13
  131. package/src/windows/hidden.cpp +12 -0
  132. package/src/windows/volume_metadata.cpp +17 -7
  133. package/tsup.config.ts +8 -2
  134. package/dist/index.cjs +0 -1439
  135. package/dist/index.cjs.map +0 -1
  136. package/dist/index.mjs +0 -1396
  137. package/dist/index.mjs.map +0 -1
  138. package/dist/types/array.d.ts +0 -25
  139. package/dist/types/async.d.ts +0 -42
  140. package/dist/types/debuglog.d.ts +0 -3
  141. package/dist/types/defer.d.ts +0 -10
  142. package/dist/types/dirname.d.ts +0 -1
  143. package/dist/types/error.d.ts +0 -17
  144. package/dist/types/fs.d.ts +0 -22
  145. package/dist/types/glob.d.ts +0 -17
  146. package/dist/types/hidden.d.ts +0 -29
  147. package/dist/types/index.d.ts +0 -91
  148. package/dist/types/linux/dev_disk.d.ts +0 -13
  149. package/dist/types/linux/mount_points.d.ts +0 -6
  150. package/dist/types/linux/mtab.d.ts +0 -47
  151. package/dist/types/mount_point.d.ts +0 -2
  152. package/dist/types/number.d.ts +0 -3
  153. package/dist/types/object.d.ts +0 -18
  154. package/dist/types/options.d.ts +0 -33
  155. package/dist/types/path.d.ts +0 -17
  156. package/dist/types/platform.d.ts +0 -4
  157. package/dist/types/random.d.ts +0 -12
  158. package/dist/types/remote_info.d.ts +0 -6
  159. package/dist/types/stack_path.d.ts +0 -2
  160. package/dist/types/string.d.ts +0 -37
  161. package/dist/types/string_enum.d.ts +0 -19
  162. package/dist/types/system_volume.d.ts +0 -14
  163. package/dist/types/types/hidden_metadata.d.ts +0 -32
  164. package/dist/types/types/mount_point.d.ts +0 -46
  165. package/dist/types/types/native_bindings.d.ts +0 -51
  166. package/dist/types/types/options.d.ts +0 -47
  167. package/dist/types/types/remote_info.d.ts +0 -33
  168. package/dist/types/types/volume_metadata.d.ts +0 -46
  169. package/dist/types/unc.d.ts +0 -11
  170. package/dist/types/units.d.ts +0 -38
  171. package/dist/types/uuid.d.ts +0 -16
  172. package/dist/types/volume_health_status.d.ts +0 -24
  173. package/dist/types/volume_metadata.d.ts +0 -8
  174. package/dist/types/volume_mount_points.d.ts +0 -6
  175. package/jest.config.base.cjs +0 -63
  176. package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
  177. package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
  178. package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
  179. package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
package/dist/index.mjs DELETED
@@ -1,1396 +0,0 @@
1
- // node_modules/tsup/assets/esm_shims.js
2
- import { fileURLToPath } from "url";
3
- import path from "path";
4
- var getFilename = () => fileURLToPath(import.meta.url);
5
- var getDirname = () => path.dirname(getFilename());
6
- var __dirname = /* @__PURE__ */ getDirname();
7
-
8
- // src/index.ts
9
- import NodeGypBuild from "node-gyp-build";
10
-
11
- // src/debuglog.ts
12
- import { debuglog, format } from "node:util";
13
- function defer(thunk) {
14
- let t;
15
- return () => t ??= thunk();
16
- }
17
- var debugLogContext = defer(() => {
18
- for (const ea of ["fs-metadata", "fs-meta"]) {
19
- if (debuglog(ea).enabled) {
20
- return ea;
21
- }
22
- if (debuglog(ea.toUpperCase()).enabled) {
23
- return ea;
24
- }
25
- }
26
- return "photostructure:fs-metadata";
27
- });
28
- var isDebugEnabled = defer(() => {
29
- return debuglog(debugLogContext()).enabled ?? false;
30
- });
31
- function debug(msg, ...args) {
32
- if (!isDebugEnabled()) return;
33
- const now = /* @__PURE__ */ new Date();
34
- const timestamp = `[${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}.${now.getMilliseconds().toString().padStart(3, "0")}] ${debugLogContext()} `;
35
- process.stderr.write(timestamp + format(msg, ...args) + "\n");
36
- }
37
-
38
- // src/defer.ts
39
- function defer2(thunk) {
40
- let computed = false;
41
- let value;
42
- const fn = () => {
43
- if (!computed) {
44
- computed = true;
45
- value = thunk();
46
- }
47
- return value;
48
- };
49
- fn.reset = () => {
50
- computed = false;
51
- };
52
- return fn;
53
- }
54
-
55
- // src/stack_path.ts
56
- import { dirname } from "node:path";
57
-
58
- // src/platform.ts
59
- import { arch, platform } from "node:process";
60
- var isLinux = platform === "linux";
61
- var isWindows = platform === "win32";
62
- var isMacOS = platform === "darwin";
63
- var isArm = isLinux && arch.startsWith("arm");
64
-
65
- // src/string.ts
66
- function isString(input) {
67
- return typeof input === "string";
68
- }
69
- function toS(input) {
70
- return isString(input) ? input : input == null ? "" : String(input);
71
- }
72
- function isNotBlank(input) {
73
- return typeof input === "string" && input.trim().length > 0;
74
- }
75
- function isBlank(input) {
76
- return !isNotBlank(input);
77
- }
78
- function toNotBlank(input) {
79
- return isNotBlank(input) ? input : void 0;
80
- }
81
- function decodeEscapeSequences(input) {
82
- const escapeRegex = /\\(?:([0-7]{2,6})|x([0-9a-fA-F]{2,4}))/g;
83
- return input.replace(escapeRegex, (match, octal, hex) => {
84
- if (octal != null) {
85
- return String.fromCharCode(parseInt(octal, 8));
86
- }
87
- if (hex != null) {
88
- return String.fromCharCode(parseInt(hex, 16));
89
- }
90
- throw new Error(`Invalid escape sequence: ${match}`);
91
- });
92
- }
93
- function sortObjectsByLocale(arr, fn, locales, options) {
94
- return arr.sort((a, b) => fn(a).localeCompare(fn(b), locales, options));
95
- }
96
-
97
- // src/stack_path.ts
98
- function getCallerDirname() {
99
- const e = new Error();
100
- if (e.stack == null) {
101
- Error.captureStackTrace(e);
102
- }
103
- return dirname(extractCallerPath(e.stack));
104
- }
105
- var patterns = isWindows ? [
106
- // Standard: "at functionName (C:\path\file.js:1:1)"
107
- /\bat\s.+?\((?<path>[A-Z]:\\.+):\d+:\d+\)$/,
108
- // direct: "at C:\path\file.js:1:1"
109
- /\bat\s(?<path>[A-Z]:\\.+):\d+:\d+$/,
110
- // UNC: "at functionName (\\server\share\path\file.js:1:1)"
111
- /\bat\s.+?\((?<path>\\\\.+):\d+:\d+\)$/,
112
- // direct: "at \\server\share\path\file.js:1:1"
113
- /\bat\s(?<path>\\\\.+):\d+:\d+$/
114
- ] : [
115
- // Standard: "at functionName (/path/file.js:1:1)"
116
- /\bat\s.+?\((?<path>\/.+?):\d+:\d+\)$/,
117
- // Anonymous or direct: "at /path/file.js:1:1"
118
- /\bat\s(.+[^/]\s)?(?<path>\/.+?):\d+:\d+$/
119
- ];
120
- var MaybeUrlRE = /^[a-z]{2,5}:\/\//i;
121
- function extractCallerPath(stack) {
122
- const frames = stack.split("\n").filter(Boolean);
123
- const callerFrame = frames.findIndex(
124
- (frame) => frame.includes("getCallerDirname")
125
- );
126
- if (callerFrame === -1) {
127
- throw new Error("Invalid stack trace format: missing caller frame");
128
- }
129
- for (let i = callerFrame + 1; i < frames.length; i++) {
130
- const frame = frames[i];
131
- for (const pattern of patterns) {
132
- const g = toS(frame).trim().match(pattern)?.groups;
133
- if (g != null && isNotBlank(g["path"])) {
134
- const path2 = g["path"];
135
- if (MaybeUrlRE.test(path2)) {
136
- try {
137
- return new URL(path2).pathname;
138
- } catch {
139
- }
140
- }
141
- return path2;
142
- }
143
- }
144
- }
145
- throw new Error("Invalid stack trace format: no parsable frames");
146
- }
147
-
148
- // src/dirname.ts
149
- function _dirname() {
150
- try {
151
- if (typeof __dirname !== "undefined") return __dirname;
152
- } catch {
153
- }
154
- return getCallerDirname();
155
- }
156
-
157
- // src/fs.ts
158
- import { opendir, stat } from "node:fs/promises";
159
- import { join, resolve } from "node:path";
160
-
161
- // src/async.ts
162
- import { availableParallelism } from "node:os";
163
- import { env } from "node:process";
164
-
165
- // src/number.ts
166
- function isNumber(value) {
167
- return typeof value === "number" && isFinite(value);
168
- }
169
- var INTEGER_REGEX = /^-?\d+$/;
170
- function toInt(value) {
171
- try {
172
- if (value == null) return;
173
- const s = String(value).trim();
174
- return INTEGER_REGEX.test(s) ? parseInt(s) : void 0;
175
- } catch {
176
- return;
177
- }
178
- }
179
- function gt0(value) {
180
- return isNumber(value) && value > 0;
181
- }
182
-
183
- // src/units.ts
184
- var SecondMs = 1e3;
185
- var MinuteMs = 60 * SecondMs;
186
- var HourMs = 60 * MinuteMs;
187
- var DayMs = 24 * HourMs;
188
- var KiB = 1024;
189
- var MiB = 1024 * KiB;
190
- var GiB = 1024 * MiB;
191
- var TiB = 1024 * GiB;
192
- var f = 1023.995 / 1024;
193
-
194
- // src/async.ts
195
- var TimeoutError = class extends Error {
196
- constructor(message, captureStackTrace = true) {
197
- super(message);
198
- this.name = "TimeoutError";
199
- if (captureStackTrace && Error.captureStackTrace) {
200
- Error.captureStackTrace(this, this.constructor);
201
- }
202
- }
203
- };
204
- async function withTimeout(opts) {
205
- const desc = isBlank(opts.desc) ? "thenOrTimeout()" : opts.desc;
206
- if (!isNumber(opts.timeoutMs)) {
207
- throw new TypeError(
208
- desc + ": Expected timeoutMs to be numeric, but got " + JSON.stringify(opts.timeoutMs)
209
- );
210
- }
211
- const timeoutMs = Math.floor(opts.timeoutMs);
212
- if (timeoutMs < 0) {
213
- throw new TypeError(
214
- desc + ": Expected timeoutMs to be > 0, but got " + timeoutMs
215
- );
216
- }
217
- if (timeoutMs > DayMs) {
218
- throw new TypeError(
219
- desc + ": Invalid timeoutMs is too large: must be less than one day, but got " + timeoutMs
220
- );
221
- }
222
- if (timeoutMs === 0) {
223
- return opts.promise;
224
- }
225
- const timeoutError = new TimeoutError(
226
- `${desc}: timeout after ${timeoutMs}ms`
227
- );
228
- if (env["NODE_ENV"] === "test" && timeoutMs === 1) {
229
- timeoutError.message += "(timeout test)";
230
- opts.promise.catch(() => {
231
- });
232
- throw timeoutError;
233
- }
234
- let timeoutId;
235
- opts.promise.catch(() => {
236
- }).finally(() => {
237
- if (timeoutId != null) {
238
- clearTimeout(timeoutId);
239
- timeoutId = void 0;
240
- }
241
- });
242
- const timeoutPromise = new Promise((_, reject) => {
243
- timeoutId = setTimeout(() => {
244
- if (timeoutId != null) {
245
- timeoutError.message += "(timeout callback)";
246
- reject(timeoutError);
247
- }
248
- timeoutId = void 0;
249
- }, timeoutMs);
250
- });
251
- return Promise.race([opts.promise, timeoutPromise]);
252
- }
253
- async function mapConcurrent({
254
- items,
255
- fn,
256
- maxConcurrency = availableParallelism()
257
- }) {
258
- if (!gt0(maxConcurrency)) {
259
- throw new Error(
260
- `maxConcurrency must be a positive integer, got: ${maxConcurrency}`
261
- );
262
- }
263
- if (typeof fn !== "function") {
264
- throw new TypeError(`fn must be a function, got: ${typeof fn}`);
265
- }
266
- const results = [];
267
- const executing = /* @__PURE__ */ new Set();
268
- for (const [index, item] of items.entries()) {
269
- while (executing.size >= maxConcurrency) {
270
- await Promise.race(executing);
271
- }
272
- const p = results[index] = fn(item).catch((error) => error);
273
- executing.add(p);
274
- p.finally(() => executing.delete(p));
275
- }
276
- return Promise.all(results);
277
- }
278
-
279
- // src/fs.ts
280
- async function statAsync(path2, options) {
281
- return stat(path2, options);
282
- }
283
- async function canStatAsync(path2) {
284
- try {
285
- return null != await statAsync(path2);
286
- } catch {
287
- return false;
288
- }
289
- }
290
- async function findAncestorDir(dir, file) {
291
- dir = resolve(dir);
292
- try {
293
- const s = await statAsync(join(dir, file));
294
- if (s.isFile()) return dir;
295
- } catch {
296
- }
297
- const parent = resolve(dir, "..");
298
- return parent === dir ? void 0 : findAncestorDir(parent, file);
299
- }
300
- async function canReaddir(dir, timeoutMs) {
301
- return withTimeout({
302
- desc: "canReaddir()",
303
- promise: _canReaddir(dir),
304
- timeoutMs
305
- });
306
- }
307
- async function _canReaddir(dir) {
308
- await (await opendir(dir)).close();
309
- return true;
310
- }
311
-
312
- // src/hidden.ts
313
- import { rename } from "node:fs/promises";
314
- import { basename, dirname as dirname3, join as join2 } from "node:path";
315
-
316
- // src/object.ts
317
- function isObject(value) {
318
- return value != null && typeof value === "object" && !Array.isArray(value);
319
- }
320
- function map(obj, fn) {
321
- return obj == null ? void 0 : fn(obj);
322
- }
323
- function omit(obj, ...keys) {
324
- const result = {};
325
- const keysSet = new Set(keys);
326
- for (const key of Object.keys(obj)) {
327
- if (!keysSet.has(key)) {
328
- result[key] = obj[key];
329
- }
330
- }
331
- return result;
332
- }
333
- function compactValues(obj) {
334
- const result = {};
335
- if (obj == null || !isObject(obj)) return {};
336
- for (const [key, value] of Object.entries(obj)) {
337
- if (value != null && (!isString(value) || isNotBlank(value))) {
338
- result[key] = value;
339
- }
340
- }
341
- return result;
342
- }
343
-
344
- // src/error.ts
345
- function toMessage(context, cause) {
346
- const causeStr = cause instanceof Error ? cause.message : typeof cause === "string" ? cause : cause ? JSON.stringify(cause) : "";
347
- return context + (isBlank(causeStr) ? "" : ": " + causeStr);
348
- }
349
- var WrappedError = class extends Error {
350
- errno;
351
- code;
352
- syscall;
353
- path;
354
- constructor(context, options) {
355
- super(toMessage(context, options?.cause));
356
- const cause = map(options?.cause, toError);
357
- const opts = { ...compactValues(cause), ...compactValues(options) };
358
- if (isNotBlank(options?.name)) {
359
- this.name = options.name;
360
- }
361
- if (cause != null) {
362
- this.cause = cause;
363
- if (cause instanceof Error) {
364
- this.stack = `${this.stack}
365
- Caused by: ${cause.stack}`;
366
- }
367
- }
368
- if (isNumber(opts.errno)) {
369
- this.errno = opts.errno;
370
- }
371
- if (isNotBlank(opts.code)) {
372
- this.code = opts.code;
373
- }
374
- if (isNotBlank(opts.syscall)) {
375
- this.syscall = opts.syscall;
376
- }
377
- if (isNotBlank(options?.path)) {
378
- this.path = options.path;
379
- }
380
- }
381
- get details() {
382
- return compactValues(omit(this, "name", "message", "cause"));
383
- }
384
- toString() {
385
- const details = this.details;
386
- const detailsStr = Object.keys(details).length === 0 ? "" : " " + JSON.stringify(details);
387
- return `${super.toString()}${detailsStr}`;
388
- }
389
- };
390
- function toError(cause) {
391
- return cause instanceof Error ? cause : new Error(String(cause));
392
- }
393
-
394
- // src/path.ts
395
- import { dirname as dirname2, resolve as resolve2 } from "node:path";
396
- function normalizePath(mountPoint) {
397
- if (isBlank(mountPoint)) return void 0;
398
- const result = isWindows ? normalizeWindowsPath(mountPoint) : normalizePosixPath(mountPoint);
399
- return result != null ? resolve2(result) : void 0;
400
- }
401
- function normalizePosixPath(mountPoint) {
402
- if (isBlank(mountPoint)) return void 0;
403
- if (mountPoint === "/") return mountPoint;
404
- if (mountPoint[mountPoint.length - 1] !== "/") return mountPoint;
405
- let end = mountPoint.length - 1;
406
- while (end > 0 && mountPoint[end] === "/") {
407
- end--;
408
- }
409
- return mountPoint.slice(0, end + 1);
410
- }
411
- function normalizeWindowsPath(mountPoint) {
412
- return /^[a-z]:$/i.test(mountPoint) ? mountPoint.toUpperCase() + "\\" : mountPoint;
413
- }
414
- function isRootDirectory(path2) {
415
- const n = normalizePath(path2);
416
- return n == null ? false : isWindows ? dirname2(n) === n : n === "/";
417
- }
418
-
419
- // src/hidden.ts
420
- var HiddenSupportByPlatform = {
421
- win32: {
422
- supported: {
423
- dotPrefix: false,
424
- systemFlag: true
425
- }
426
- },
427
- darwin: {
428
- supported: {
429
- dotPrefix: true,
430
- systemFlag: true
431
- }
432
- },
433
- linux: {
434
- supported: {
435
- dotPrefix: true,
436
- systemFlag: false
437
- }
438
- }
439
- };
440
- var LocalSupport = HiddenSupportByPlatform[process.platform]?.supported ?? {
441
- dotPrefix: false,
442
- systemFlag: false
443
- };
444
- async function isHiddenImpl(pathname, nativeFn2) {
445
- const norm = normalizePath(pathname);
446
- if (norm == null) {
447
- throw new Error("Invalid pathname: " + JSON.stringify(pathname));
448
- }
449
- return LocalSupport.dotPrefix && isPosixHidden(norm) || LocalSupport.systemFlag && isSystemHidden(norm, nativeFn2);
450
- }
451
- async function isHiddenRecursiveImpl(path2, nativeFn2) {
452
- let norm = normalizePath(path2);
453
- if (norm == null) {
454
- throw new Error("Invalid path: " + JSON.stringify(path2));
455
- }
456
- while (!isRootDirectory(norm)) {
457
- if (await isHiddenImpl(norm, nativeFn2)) {
458
- return true;
459
- }
460
- norm = dirname3(norm);
461
- }
462
- return false;
463
- }
464
- function createHiddenPosixPath(pathname, hidden) {
465
- const norm = normalizePath(pathname);
466
- if (norm == null) {
467
- throw new Error("Invalid pathname: " + JSON.stringify(pathname));
468
- }
469
- const dir = dirname3(norm);
470
- const srcBase = basename(norm).replace(/^\./, "");
471
- const dest = join2(dir, (hidden ? "." : "") + srcBase);
472
- return dest;
473
- }
474
- async function setHiddenPosix(pathname, hidden) {
475
- if (LocalSupport.dotPrefix) {
476
- const dest = createHiddenPosixPath(pathname, hidden);
477
- if (pathname !== dest) await rename(pathname, dest);
478
- return dest;
479
- }
480
- throw new Error("Unsupported platform");
481
- }
482
- function isPosixHidden(pathname) {
483
- if (!LocalSupport.dotPrefix) return false;
484
- const b = basename(pathname);
485
- return b.startsWith(".") && b !== "." && b !== "..";
486
- }
487
- async function isSystemHidden(pathname, nativeFn2) {
488
- if (!LocalSupport.systemFlag) {
489
- return false;
490
- }
491
- if (isWindows && isRootDirectory(pathname)) {
492
- return false;
493
- }
494
- return await canStatAsync(pathname) && await (await nativeFn2()).isHidden(pathname);
495
- }
496
- async function getHiddenMetadataImpl(pathname, nativeFn2) {
497
- const norm = normalizePath(pathname);
498
- if (norm == null) {
499
- throw new Error("Invalid pathname: " + JSON.stringify(pathname));
500
- }
501
- const dotPrefix = isPosixHidden(norm);
502
- const systemFlag = await isSystemHidden(norm, nativeFn2);
503
- return {
504
- hidden: dotPrefix || systemFlag,
505
- dotPrefix,
506
- systemFlag,
507
- supported: LocalSupport
508
- };
509
- }
510
- async function setHiddenImpl(pathname, hide, method, nativeFn2) {
511
- let norm = normalizePath(pathname);
512
- if (norm == null) {
513
- throw new Error("Invalid pathname: " + JSON.stringify(pathname));
514
- }
515
- if (method === "dotPrefix" && !LocalSupport.dotPrefix) {
516
- throw new Error("Dot prefix hiding is not supported on this platform");
517
- }
518
- if (method === "systemFlag" && !LocalSupport.systemFlag) {
519
- throw new Error("System flag hiding is not supported on this platform");
520
- }
521
- try {
522
- await statAsync(norm);
523
- } catch (cause) {
524
- throw new WrappedError("setHidden()", { cause });
525
- }
526
- if (isWindows && isRootDirectory(norm)) {
527
- throw new Error("Cannot hide root directory on Windows");
528
- }
529
- const actions = {
530
- dotPrefix: false,
531
- systemFlag: false
532
- };
533
- let acted = false;
534
- if (LocalSupport.dotPrefix && ["auto", "all", "dotPrefix"].includes(method)) {
535
- if (isPosixHidden(norm) !== hide) {
536
- norm = await setHiddenPosix(norm, hide);
537
- actions.dotPrefix = true;
538
- }
539
- acted = true;
540
- }
541
- if (LocalSupport.systemFlag && (["all", "systemFlag"].includes(method) || !acted && method === "auto")) {
542
- await (await nativeFn2()).setHidden(norm, hide);
543
- actions.systemFlag = true;
544
- }
545
- return { pathname: norm, actions };
546
- }
547
-
548
- // src/options.ts
549
- import { availableParallelism as availableParallelism2 } from "node:os";
550
- var TimeoutMsDefault = 5e3;
551
- var SystemPathPatternsDefault = [
552
- "/boot",
553
- "/boot/efi",
554
- "/dev",
555
- "/dev/**",
556
- "/proc/**",
557
- "/run",
558
- "/run/credentials/**",
559
- "/run/lock",
560
- "/run/snapd/**",
561
- "/run/user/*/doc",
562
- "/run/user/*/gvfs",
563
- "/snap/**",
564
- "/sys/**",
565
- "/tmp",
566
- "/var/tmp",
567
- // we aren't including /tmp/**, as some people temporarily mount volumes there, like /tmp/project.
568
- "**/#snapshot",
569
- // Synology and Kubernetes volume snapshots
570
- // windows for linux:
571
- "/mnt/wslg/distro",
572
- "/mnt/wslg/doc",
573
- "/mnt/wslg/versions.txt",
574
- "/usr/lib/wsl/drivers",
575
- // MacOS stuff:
576
- "/private/var/vm",
577
- // macOS swap
578
- "/System/Volumes/Hardware",
579
- "/System/Volumes/iSCPreboot",
580
- "/System/Volumes/Preboot",
581
- "/System/Volumes/Recovery",
582
- "/System/Volumes/Reserved",
583
- "/System/Volumes/Update",
584
- "/System/Volumes/VM",
585
- "/System/Volumes/xarts"
586
- ];
587
- var SystemFsTypesDefault = [
588
- "autofs",
589
- "binfmt_misc",
590
- "cgroup",
591
- "cgroup2",
592
- "configfs",
593
- "debugfs",
594
- "devpts",
595
- "devtmpfs",
596
- "efivarfs",
597
- "fusectl",
598
- "fuse.snapfuse",
599
- "hugetlbfs",
600
- "mqueue",
601
- "none",
602
- "proc",
603
- "pstore",
604
- "rootfs",
605
- "securityfs",
606
- "snap*",
607
- "squashfs",
608
- "sysfs",
609
- "tmpfs"
610
- ];
611
- var LinuxMountTablePathsDefault = [
612
- "/proc/self/mounts",
613
- "/proc/mounts",
614
- "/etc/mtab"
615
- ];
616
- var IncludeSystemVolumesDefault = isWindows;
617
- var OptionsDefault = {
618
- timeoutMs: TimeoutMsDefault,
619
- maxConcurrency: availableParallelism2(),
620
- systemPathPatterns: [...SystemPathPatternsDefault],
621
- systemFsTypes: [...SystemFsTypesDefault],
622
- linuxMountTablePaths: [...LinuxMountTablePathsDefault],
623
- includeSystemVolumes: IncludeSystemVolumesDefault
624
- };
625
- function optionsWithDefaults(overrides = {}) {
626
- if (!isObject(overrides)) {
627
- throw new TypeError(
628
- "options(): expected an object, got " + typeof overrides + ": " + JSON.stringify(overrides)
629
- );
630
- }
631
- return {
632
- ...OptionsDefault,
633
- ...compactValues(overrides)
634
- };
635
- }
636
-
637
- // src/string_enum.ts
638
- function stringEnum(...o) {
639
- const set = new Set(o);
640
- const dict = {};
641
- for (const key of o) {
642
- dict[key] = key;
643
- }
644
- return {
645
- ...dict,
646
- values: Object.freeze([...set]),
647
- size: set.size,
648
- get: (s) => s != null && set.has(s) ? s : void 0
649
- };
650
- }
651
-
652
- // src/volume_health_status.ts
653
- var VolumeHealthStatuses = stringEnum(
654
- "healthy",
655
- "timeout",
656
- "inaccessible",
657
- "disconnected",
658
- "unknown"
659
- );
660
- async function directoryStatus(dir, timeoutMs, canReaddirImpl = canReaddir) {
661
- try {
662
- if (await canReaddirImpl(dir, timeoutMs)) {
663
- return { status: VolumeHealthStatuses.healthy };
664
- }
665
- } catch (error) {
666
- debug("[directoryStatus] %s: %s", dir, error);
667
- let status = VolumeHealthStatuses.unknown;
668
- if (error instanceof TimeoutError) {
669
- status = VolumeHealthStatuses.timeout;
670
- } else if (isObject(error) && error instanceof Error && "code" in error) {
671
- if (error.code === "EPERM" || error.code === "EACCES") {
672
- status = VolumeHealthStatuses.inaccessible;
673
- }
674
- }
675
- return { status, error: toError(error) };
676
- }
677
- return { status: VolumeHealthStatuses.unknown };
678
- }
679
-
680
- // src/linux/dev_disk.ts
681
- import { readdir, readlink } from "node:fs/promises";
682
- import { join as join3, resolve as resolve3 } from "node:path";
683
- async function getUuidFromDevDisk(devicePath) {
684
- try {
685
- const result = await getBasenameLinkedTo(
686
- "/dev/disk/by-uuid",
687
- resolve3(devicePath)
688
- );
689
- debug("[getUuidFromDevDisk] result: %o", result);
690
- return result;
691
- } catch (error) {
692
- debug("[getUuidFromDevDisk] failed: " + error);
693
- return;
694
- }
695
- }
696
- async function getLabelFromDevDisk(devicePath) {
697
- try {
698
- const result = await getBasenameLinkedTo(
699
- "/dev/disk/by-label",
700
- resolve3(devicePath)
701
- );
702
- debug("[getLabelFromDevDisk] result: %o", result);
703
- return result;
704
- } catch (error) {
705
- debug("[getLabelFromDevDisk] failed: " + error);
706
- return;
707
- }
708
- }
709
- async function getBasenameLinkedTo(linkDir, linkPath) {
710
- for await (const ea of readLinks(linkDir)) {
711
- if (ea.linkTarget === linkPath) {
712
- return decodeEscapeSequences(ea.dirent.name);
713
- }
714
- }
715
- return;
716
- }
717
- async function* readLinks(directory) {
718
- for (const dirent of await readdir(directory, { withFileTypes: true })) {
719
- if (dirent.isSymbolicLink()) {
720
- try {
721
- const linkTarget = resolve3(
722
- directory,
723
- await readlink(join3(directory, dirent.name))
724
- );
725
- yield { dirent, linkTarget };
726
- } catch {
727
- }
728
- }
729
- }
730
- }
731
-
732
- // src/linux/mount_points.ts
733
- import { readFile } from "node:fs/promises";
734
-
735
- // src/mount_point.ts
736
- function isMountPoint(obj) {
737
- return isObject(obj) && "mountPoint" in obj && isNotBlank(obj.mountPoint);
738
- }
739
-
740
- // src/remote_info.ts
741
- function isRemoteInfo(obj) {
742
- if (!isObject(obj)) return false;
743
- const { remoteHost, remoteShare } = obj;
744
- return isNotBlank(remoteHost) && isNotBlank(remoteShare);
745
- }
746
- var NETWORK_FS_TYPE_ARRAY = [
747
- "9p",
748
- "afp",
749
- "afs",
750
- "beegfs",
751
- "ceph",
752
- "cifs",
753
- "ftp",
754
- "fuse",
755
- "gfs2",
756
- "glusterfs",
757
- "lustre",
758
- "ncpfs",
759
- "nfs",
760
- "nfs4",
761
- "smb",
762
- "smbfs",
763
- "sshfs",
764
- "webdav"
765
- ];
766
- var NETWORK_FS_TYPES = new Set(NETWORK_FS_TYPE_ARRAY);
767
- var FS_TYPE_ALIASES = /* @__PURE__ */ new Map([
768
- ["nfs1", "nfs"],
769
- ["nfs2", "nfs"],
770
- ["nfs3", "nfs"],
771
- ["nfs4", "nfs4"],
772
- ["fuse.sshfs", "sshfs"],
773
- ["sshfs.fuse", "sshfs"],
774
- ["davfs2", "webdav"],
775
- ["davfs", "webdav"],
776
- ["cifs.smb", "cifs"],
777
- ["smbfs", "cifs"],
778
- ["cephfs", "ceph"],
779
- ["fuse.ceph", "ceph"],
780
- ["fuse.cephfs", "ceph"],
781
- ["rbd", "ceph"],
782
- ["fuse.glusterfs", "glusterfs"]
783
- ]);
784
- function normalizeFsType(fstype) {
785
- const norm = toS(fstype).toLowerCase().replace(/:$/, "");
786
- return FS_TYPE_ALIASES.get(norm) ?? norm;
787
- }
788
- function isRemoteFsType(fstype) {
789
- return isNotBlank(fstype) && NETWORK_FS_TYPES.has(normalizeFsType(fstype));
790
- }
791
- function parseURL(s) {
792
- try {
793
- return isBlank(s) ? void 0 : new URL(s);
794
- } catch {
795
- return;
796
- }
797
- }
798
- function extractRemoteInfo(fsSpec) {
799
- if (fsSpec == null || isBlank(fsSpec)) return;
800
- if (isWindows) {
801
- fsSpec = fsSpec.replace(/\\/g, "/");
802
- }
803
- const url = parseURL(fsSpec);
804
- if (url?.protocol === "file:") {
805
- return {
806
- remote: false,
807
- uri: fsSpec
808
- };
809
- }
810
- const patterns2 = [
811
- {
812
- // CIFS/SMB pattern: //hostname/share or //user@host/share
813
- regex: /^\/\/(?:(?<remoteUser>[^/@]+)@)?(?<remoteHost>[^/@]+)\/(?<remoteShare>.+)$/
814
- },
815
- {
816
- // sshfs pattern: sshfs#USER@HOST:REMOTE_PATH
817
- regex: /^(?:(?<protocol>\w+)#)?(?<remoteUser>[^@]+)@(?<remoteHost>[^:]+):(?<remoteShare>.+)$/
818
- },
819
- {
820
- // NFS pattern: hostname:/share
821
- protocol: "nfs",
822
- regex: /^(?<remoteHost>[^:]+):\/(?!\/)(?<remoteShare>.+)$/
823
- }
824
- ];
825
- for (const { protocol, regex } of patterns2) {
826
- const o = compactValues({
827
- protocol,
828
- remote: true,
829
- ...fsSpec.match(regex)?.groups ?? {}
830
- });
831
- if (isRemoteInfo(o)) {
832
- debug("[extractRemoteInfo] matched pattern: %o", o);
833
- return o;
834
- }
835
- }
836
- try {
837
- const parsed = new URL(fsSpec);
838
- if (parsed != null) {
839
- debug("[extractRemoteInfo] parsed URL: %o", parsed);
840
- const fstype = normalizeFsType(parsed.protocol);
841
- if (!isRemoteFsType(fstype)) {
842
- return {
843
- uri: fsSpec,
844
- remote: false
845
- };
846
- } else {
847
- return compactValues({
848
- uri: fsSpec,
849
- protocol: fstype,
850
- remote: true,
851
- remoteUser: parsed.username,
852
- remoteHost: parsed.hostname,
853
- // URL pathname includes leading slash:
854
- remoteShare: parsed.pathname.replace(/^\//, "")
855
- });
856
- }
857
- }
858
- } catch {
859
- }
860
- return;
861
- }
862
-
863
- // src/glob.ts
864
- var cache = /* @__PURE__ */ new Map();
865
- function compileGlob(patterns2) {
866
- if (patterns2 == null || patterns2.length === 0) {
867
- return NeverMatchRE;
868
- }
869
- const patternsKey = JSON.stringify(patterns2);
870
- {
871
- const prior = cache.get(patternsKey);
872
- if (prior != null) {
873
- return prior;
874
- }
875
- }
876
- const sorted = patterns2.slice().filter(isNotBlank).sort();
877
- const sortedKey = JSON.stringify(sorted);
878
- {
879
- const prior = cache.get(sortedKey);
880
- if (prior != null) {
881
- cache.set(patternsKey, prior);
882
- return prior;
883
- }
884
- }
885
- const result = _compileGlob(sorted);
886
- if (cache.size > 256) {
887
- cache.clear();
888
- }
889
- cache.set(patternsKey, result);
890
- cache.set(sortedKey, result);
891
- return result;
892
- }
893
- function _compileGlob(patterns2) {
894
- const regexPatterns = patterns2.map((pattern) => {
895
- let regex = "";
896
- let i = 0;
897
- while (i < pattern.length) {
898
- if (pattern[i] === "*" && pattern[i + 1] === "*") {
899
- regex += ".*";
900
- i += 2;
901
- if (pattern[i] === "/") {
902
- i++;
903
- }
904
- continue;
905
- }
906
- if (pattern[i] === "*") {
907
- regex += "[^/]*";
908
- i++;
909
- continue;
910
- }
911
- if (pattern[i] === "?") {
912
- regex += "[^/]";
913
- i++;
914
- continue;
915
- }
916
- if (pattern[i] === ".") {
917
- regex += "\\.";
918
- i++;
919
- continue;
920
- }
921
- if (pattern[i] === "/") {
922
- if (i === pattern.length - 1) {
923
- regex += "(?:/|$)";
924
- i++;
925
- continue;
926
- } else if (isWindows) {
927
- regex += "[\\/\\\\]";
928
- i++;
929
- continue;
930
- }
931
- }
932
- if (/[+^${}()|[\]\\]/.test(pattern[i])) {
933
- regex += "\\" + pattern[i];
934
- i++;
935
- continue;
936
- }
937
- regex += pattern[i];
938
- i++;
939
- }
940
- return regex;
941
- });
942
- const final = regexPatterns.filter((ea) => ea.length > 0);
943
- return final.length === 0 ? (
944
- // Empty pattern matches nothing
945
- NeverMatchRE
946
- ) : new RegExp(`^(?:${final.join("|")})$`, "i");
947
- }
948
- var NeverMatchRE = /(?!)/;
949
-
950
- // src/system_volume.ts
951
- function isSystemVolume(mountPoint, fstype, config = {}) {
952
- if (isWindows) {
953
- const systemDrive = normalizePath(process.env["SystemDrive"]);
954
- if (systemDrive != null && mountPoint === systemDrive) {
955
- debug("[isSystemVolume] %s is the Windows system drive", mountPoint);
956
- return true;
957
- }
958
- }
959
- const isSystemFsType = isNotBlank(fstype) && (config.systemFsTypes ?? SystemFsTypesDefault).includes(
960
- fstype
961
- );
962
- const hasSystemPath = compileGlob(
963
- config.systemPathPatterns ?? SystemPathPatternsDefault
964
- ).test(mountPoint);
965
- const result = isSystemFsType || hasSystemPath;
966
- debug("[isSystemVolume]", {
967
- mountPoint,
968
- fstype,
969
- result,
970
- isSystemFsType,
971
- hasSystemPath
972
- });
973
- return result;
974
- }
975
- function assignSystemVolume(mp, config) {
976
- const result = isSystemVolume(mp.mountPoint, mp.fstype, config);
977
- if (isWindows) {
978
- mp.isSystemVolume ??= result;
979
- } else {
980
- mp.isSystemVolume = result;
981
- }
982
- }
983
-
984
- // src/linux/mtab.ts
985
- function mountEntryToMountPoint(entry) {
986
- const mountPoint = normalizePosixPath(entry.fs_file);
987
- const fstype = toNotBlank(entry.fs_vfstype) ?? toNotBlank(entry.fs_spec);
988
- return mountPoint == null || fstype == null ? void 0 : {
989
- mountPoint,
990
- fstype
991
- };
992
- }
993
- function mountEntryToPartialVolumeMetadata(entry, options = {}) {
994
- return {
995
- mountPoint: entry.fs_file,
996
- fstype: entry.fs_vfstype,
997
- mountFrom: entry.fs_spec,
998
- isSystemVolume: isSystemVolume(entry.fs_file, entry.fs_vfstype, options),
999
- remote: false,
1000
- // < default to false, but it may be overridden by extractRemoteInfo
1001
- ...extractRemoteInfo(entry.fs_spec)
1002
- };
1003
- }
1004
- function parseMtab(content) {
1005
- const entries = [];
1006
- const lines = content.split("\n");
1007
- for (const line of lines) {
1008
- if (isBlank(line) || line.trim().startsWith("#")) {
1009
- continue;
1010
- }
1011
- const fields = line.trim().match(/(?:[^\s\\]|\\.)+/g)?.map(decodeEscapeSequences);
1012
- if (!fields || fields.length < 3) {
1013
- continue;
1014
- }
1015
- const fs_file = normalizePosixPath(fields[1]);
1016
- if (fs_file != null) {
1017
- entries.push({
1018
- fs_spec: fields[0],
1019
- // normalizeLinuxPath DOES NOT resolve()!
1020
- fs_file,
1021
- fs_vfstype: fields[2],
1022
- fs_mntops: fields[3],
1023
- fs_freq: toInt(fields[4]),
1024
- fs_passno: toInt(fields[5])
1025
- });
1026
- }
1027
- }
1028
- return entries;
1029
- }
1030
-
1031
- // src/linux/mount_points.ts
1032
- async function getLinuxMountPoints(native, opts) {
1033
- const o = optionsWithDefaults(opts);
1034
- const raw = [];
1035
- try {
1036
- const arr = await (await native()).getGioMountPoints?.();
1037
- debug("[getLinuxMountPoints] GIO mount points: %o", arr);
1038
- if (arr != null) raw.push(...arr);
1039
- } catch (error) {
1040
- debug("Failed to get GIO mount points: %s", error);
1041
- }
1042
- let cause;
1043
- for (const input of o.linuxMountTablePaths) {
1044
- try {
1045
- const mtabContent = await readFile(input, "utf8");
1046
- const arr = parseMtab(mtabContent).map((ea) => mountEntryToMountPoint(ea)).filter((ea) => ea != null);
1047
- debug("[getLinuxMountPoints] %s mount points: %o", input, arr);
1048
- if (arr.length > 0) {
1049
- raw.push(...arr);
1050
- break;
1051
- }
1052
- } catch (error) {
1053
- cause ??= toError(error);
1054
- }
1055
- }
1056
- const byMountPoint = /* @__PURE__ */ new Map();
1057
- for (const ea of raw) {
1058
- const prior = byMountPoint.get(ea.mountPoint);
1059
- const merged = { ...compactValues(prior), ...compactValues(ea) };
1060
- if (isMountPoint(merged)) {
1061
- byMountPoint.set(merged.mountPoint, merged);
1062
- }
1063
- }
1064
- if (byMountPoint.size === 0) {
1065
- throw new WrappedError(
1066
- `Failed to find any mount points (tried: ${JSON.stringify(o.linuxMountTablePaths)})`,
1067
- { cause }
1068
- );
1069
- }
1070
- const results = [...byMountPoint.values()];
1071
- debug("[getLinuxMountPoints] %o", {
1072
- results: results.map((ea) => ea.mountPoint)
1073
- });
1074
- return results;
1075
- }
1076
- async function getLinuxMtabMetadata(mountPoint, opts) {
1077
- let caughtError;
1078
- const inputs = optionsWithDefaults(opts).linuxMountTablePaths;
1079
- for (const input of inputs) {
1080
- try {
1081
- const mtabContent = await readFile(input, "utf8");
1082
- for (const ea of parseMtab(mtabContent)) {
1083
- if (ea.fs_file === mountPoint) {
1084
- return ea;
1085
- }
1086
- }
1087
- } catch (error) {
1088
- caughtError ??= toError(error);
1089
- }
1090
- }
1091
- throw new WrappedError(
1092
- `Failed to find mount point ${mountPoint} in an linuxMountTablePaths (tried: ${JSON.stringify(inputs)})`,
1093
- caughtError
1094
- );
1095
- }
1096
-
1097
- // src/unc.ts
1098
- function parseUNCPath(path2) {
1099
- if (path2 == null || isBlank(path2) || !isString(path2)) {
1100
- return;
1101
- }
1102
- if (!path2.startsWith("\\\\") && !path2.startsWith("//")) {
1103
- return;
1104
- }
1105
- const isForwardSlash = path2.startsWith("//");
1106
- const slashChar = isForwardSlash ? "/" : "\\";
1107
- const parts = path2.slice(2).split(slashChar);
1108
- if (parts.length < 2) {
1109
- return;
1110
- }
1111
- const [remoteHost, remoteShare] = parts;
1112
- if (remoteHost == null || isBlank(remoteHost) || remoteShare == null || isBlank(remoteShare)) {
1113
- return;
1114
- }
1115
- const invalidChars = /[<>:"|?*]/;
1116
- if (invalidChars.test(remoteHost) || invalidChars.test(remoteShare)) {
1117
- return;
1118
- }
1119
- const wrongSlash = isForwardSlash ? "\\" : "/";
1120
- if (path2.includes(wrongSlash)) {
1121
- return;
1122
- }
1123
- return { remoteHost, remoteShare, remote: true };
1124
- }
1125
-
1126
- // src/uuid.ts
1127
- var uuidRegex = /[a-z0-9][a-z0-9-]{7,}/i;
1128
- function extractUUID(uuid) {
1129
- return toS(uuid).match(uuidRegex)?.[0];
1130
- }
1131
-
1132
- // src/array.ts
1133
- function uniqBy(arr, keyFn) {
1134
- const seen = /* @__PURE__ */ new Set();
1135
- return arr.filter((item) => {
1136
- const key = keyFn(item);
1137
- if (key == null || seen.has(key)) return false;
1138
- seen.add(key);
1139
- return true;
1140
- });
1141
- }
1142
-
1143
- // src/volume_mount_points.ts
1144
- async function getVolumeMountPointsImpl(opts, nativeFn2) {
1145
- const p = _getVolumeMountPoints(opts, nativeFn2);
1146
- return isWindows ? p : withTimeout({ desc: "getVolumeMountPoints", ...opts, promise: p });
1147
- }
1148
- async function _getVolumeMountPoints(o, nativeFn2) {
1149
- debug("[getVolumeMountPoints] gathering mount points with options: %o", o);
1150
- const raw = await (isWindows || isMacOS ? (async () => {
1151
- debug("[getVolumeMountPoints] using native implementation");
1152
- const points = await (await nativeFn2()).getVolumeMountPoints(o);
1153
- debug(
1154
- "[getVolumeMountPoints] native returned %d mount points",
1155
- points.length
1156
- );
1157
- return points;
1158
- })() : getLinuxMountPoints(nativeFn2, o));
1159
- debug("[getVolumeMountPoints] raw mount points: %o", raw);
1160
- const compacted = raw.map((ea) => compactValues(ea)).filter((ea) => isNotBlank(ea.mountPoint));
1161
- for (const ea of compacted) {
1162
- assignSystemVolume(ea, o);
1163
- }
1164
- const filtered = o.includeSystemVolumes ? compacted : compacted.filter((ea) => !ea.isSystemVolume);
1165
- const uniq = uniqBy(filtered, (ea) => toNotBlank(ea.mountPoint));
1166
- debug("[getVolumeMountPoints] found %d unique mount points", uniq.length);
1167
- const results = sortObjectsByLocale(uniq, (ea) => ea.mountPoint);
1168
- debug(
1169
- "[getVolumeMountPoints] getting status for %d mount points",
1170
- results.length
1171
- );
1172
- await mapConcurrent({
1173
- maxConcurrency: o.maxConcurrency,
1174
- items: results.filter(
1175
- // trust but verify
1176
- (ea) => isBlank(ea.status) || ea.status === "healthy"
1177
- ),
1178
- fn: async (mp) => {
1179
- debug("[getVolumeMountPoints] checking status of %s", mp.mountPoint);
1180
- mp.status = (await directoryStatus(mp.mountPoint, o.timeoutMs)).status;
1181
- debug(
1182
- "[getVolumeMountPoints] status for %s: %s",
1183
- mp.mountPoint,
1184
- mp.status
1185
- );
1186
- }
1187
- });
1188
- debug(
1189
- "[getVolumeMountPoints] completed with %d mount points",
1190
- results.length
1191
- );
1192
- return results;
1193
- }
1194
-
1195
- // src/volume_metadata.ts
1196
- async function getVolumeMetadataImpl(o, nativeFn2) {
1197
- if (isBlank(o.mountPoint)) {
1198
- throw new TypeError(
1199
- "Invalid mountPoint: got " + JSON.stringify(o.mountPoint)
1200
- );
1201
- }
1202
- const p = _getVolumeMetadata(o, nativeFn2);
1203
- return isWindows ? p : withTimeout({
1204
- desc: "getVolumeMetadata()",
1205
- timeoutMs: o.timeoutMs,
1206
- promise: p
1207
- });
1208
- }
1209
- async function _getVolumeMetadata(o, nativeFn2) {
1210
- o = optionsWithDefaults(o);
1211
- const norm = normalizePath(o.mountPoint);
1212
- if (norm == null) {
1213
- throw new Error("Invalid mountPoint: " + JSON.stringify(o.mountPoint));
1214
- }
1215
- o.mountPoint = norm;
1216
- debug(
1217
- "[getVolumeMetadata] starting metadata collection for %s",
1218
- o.mountPoint
1219
- );
1220
- debug("[getVolumeMetadata] options: %o", o);
1221
- const { status, error } = await directoryStatus(o.mountPoint, o.timeoutMs);
1222
- if (status !== VolumeHealthStatuses.healthy) {
1223
- debug("[getVolumeMetadata] directoryStatus error: %s", error);
1224
- throw error ?? new Error("Volume not healthy: " + status);
1225
- }
1226
- debug("[getVolumeMetadata] readdir status: %s", status);
1227
- let remote = false;
1228
- let mtabInfo;
1229
- let device;
1230
- if (isLinux) {
1231
- debug("[getVolumeMetadata] collecting Linux mtab info");
1232
- try {
1233
- const m = await getLinuxMtabMetadata(o.mountPoint, o);
1234
- mtabInfo = mountEntryToPartialVolumeMetadata(m, o);
1235
- debug("[getVolumeMetadata] mtab info: %o", mtabInfo);
1236
- if (mtabInfo.remote) {
1237
- remote = true;
1238
- }
1239
- if (isNotBlank(m.fs_spec)) {
1240
- device = m.fs_spec;
1241
- }
1242
- } catch (err) {
1243
- debug("[getVolumeMetadata] failed to get mtab info: " + err);
1244
- }
1245
- }
1246
- if (isNotBlank(device)) {
1247
- o.device = device;
1248
- debug("[getVolumeMetadata] using device: %s", device);
1249
- }
1250
- debug("[getVolumeMetadata] requesting native metadata");
1251
- const metadata = await (await nativeFn2()).getVolumeMetadata(o);
1252
- debug("[getVolumeMetadata] native metadata: %o", metadata);
1253
- const remoteInfo = mtabInfo ?? extractRemoteInfo(metadata.uri) ?? extractRemoteInfo(metadata.mountFrom) ?? (isWindows ? parseUNCPath(o.mountPoint) : void 0);
1254
- debug("[getVolumeMetadata] extracted remote info: %o", remoteInfo);
1255
- remote ||= isRemoteFsType(metadata.fstype) || (remoteInfo?.remote ?? metadata.remote ?? false);
1256
- debug("[getVolumeMetadata] assembling: %o", {
1257
- status,
1258
- mtabInfo,
1259
- remoteInfo,
1260
- metadata,
1261
- mountPoint: o.mountPoint,
1262
- remote
1263
- });
1264
- const result = compactValues({
1265
- status,
1266
- // < let the implementation's status win by having this first
1267
- ...compactValues(remoteInfo),
1268
- ...compactValues(metadata),
1269
- ...compactValues(mtabInfo),
1270
- mountPoint: o.mountPoint,
1271
- remote
1272
- });
1273
- if (isLinux && isNotBlank(device)) {
1274
- result.uuid ??= await getUuidFromDevDisk(device) ?? "";
1275
- result.label ??= await getLabelFromDevDisk(device) ?? "";
1276
- }
1277
- assignSystemVolume(result, o);
1278
- result.uuid = extractUUID(result.uuid) ?? result.uuid ?? "";
1279
- debug("[getVolumeMetadata] final result for %s: %o", o.mountPoint, result);
1280
- return compactValues(result);
1281
- }
1282
- async function getAllVolumeMetadataImpl(opts, nativeFn2) {
1283
- const o = optionsWithDefaults(opts);
1284
- debug("[getAllVolumeMetadata] starting with options: %o", o);
1285
- const arr = await getVolumeMountPointsImpl(o, nativeFn2);
1286
- debug("[getAllVolumeMetadata] found %d mount points", arr.length);
1287
- const unhealthyMountPoints = arr.filter(
1288
- (ea) => ea.status != null && ea.status !== VolumeHealthStatuses.healthy
1289
- ).map((ea) => ({
1290
- mountPoint: ea.mountPoint,
1291
- error: new WrappedError("volume not healthy: " + ea.status, {
1292
- name: "Skipped"
1293
- })
1294
- }));
1295
- const includeSystemVolumes = opts?.includeSystemVolumes ?? IncludeSystemVolumesDefault;
1296
- const systemMountPoints = includeSystemVolumes ? [] : arr.filter((ea) => ea.isSystemVolume).map((ea) => ({
1297
- mountPoint: ea.mountPoint,
1298
- error: new WrappedError("system volume", { name: "Skipped" })
1299
- }));
1300
- const healthy = arr.filter(
1301
- (ea) => ea.status == null || ea.status === VolumeHealthStatuses.healthy
1302
- );
1303
- debug("[getAllVolumeMetadata] ", {
1304
- allMountPoints: arr.map((ea) => ea.mountPoint),
1305
- healthyMountPoints: healthy.map((ea) => ea.mountPoint)
1306
- });
1307
- debug(
1308
- "[getAllVolumeMetadata] processing %d healthy volumes with max concurrency %d",
1309
- healthy.length,
1310
- o.maxConcurrency
1311
- );
1312
- const results = await mapConcurrent({
1313
- maxConcurrency: o.maxConcurrency,
1314
- items: opts?.includeSystemVolumes ?? IncludeSystemVolumesDefault ? healthy : healthy.filter((ea) => !ea.isSystemVolume),
1315
- fn: async (mp) => getVolumeMetadataImpl({ ...mp, ...o }, nativeFn2).catch((error) => ({
1316
- mountPoint: mp.mountPoint,
1317
- error
1318
- }))
1319
- });
1320
- debug("[getAllVolumeMetadata] completed processing all volumes");
1321
- return arr.map(
1322
- (result) => results.find((ea) => ea.mountPoint === result.mountPoint) ?? unhealthyMountPoints.find(
1323
- (ea) => ea.mountPoint === result.mountPoint
1324
- ) ?? systemMountPoints.find((ea) => ea.mountPoint === result.mountPoint) ?? {
1325
- ...result,
1326
- error: new WrappedError("Mount point metadata not retrieved", {
1327
- name: "NotApplicableError"
1328
- })
1329
- }
1330
- );
1331
- }
1332
-
1333
- // src/index.ts
1334
- var nativeFn = defer2(async () => {
1335
- const start = Date.now();
1336
- try {
1337
- const dirname4 = _dirname();
1338
- const dir = await findAncestorDir(dirname4, "binding.gyp");
1339
- if (dir == null) {
1340
- throw new Error(
1341
- "Could not find bindings.gyp in any ancestor directory of " + dirname4
1342
- );
1343
- }
1344
- const bindings = NodeGypBuild(dir);
1345
- bindings.setDebugLogging(isDebugEnabled());
1346
- bindings.setDebugPrefix(debugLogContext() + ":native");
1347
- return bindings;
1348
- } catch (error) {
1349
- debug("Loading native bindings failed: %s", error);
1350
- throw error;
1351
- } finally {
1352
- debug(`Native bindings took %d ms to load`, Date.now() - start);
1353
- }
1354
- });
1355
- function getVolumeMountPoints(opts) {
1356
- return getVolumeMountPointsImpl(optionsWithDefaults(opts), nativeFn);
1357
- }
1358
- function getVolumeMetadata(mountPoint, opts) {
1359
- return getVolumeMetadataImpl(
1360
- { ...optionsWithDefaults(opts), mountPoint },
1361
- nativeFn
1362
- );
1363
- }
1364
- function getAllVolumeMetadata(opts) {
1365
- return getAllVolumeMetadataImpl(optionsWithDefaults(opts), nativeFn);
1366
- }
1367
- function isHidden(pathname) {
1368
- return isHiddenImpl(pathname, nativeFn);
1369
- }
1370
- function isHiddenRecursive(pathname) {
1371
- return isHiddenRecursiveImpl(pathname, nativeFn);
1372
- }
1373
- function getHiddenMetadata(pathname) {
1374
- return getHiddenMetadataImpl(pathname, nativeFn);
1375
- }
1376
- function setHidden(pathname, hidden, method = "auto") {
1377
- return setHiddenImpl(pathname, hidden, method, nativeFn);
1378
- }
1379
- export {
1380
- IncludeSystemVolumesDefault,
1381
- LinuxMountTablePathsDefault,
1382
- OptionsDefault,
1383
- SystemFsTypesDefault,
1384
- SystemPathPatternsDefault,
1385
- TimeoutMsDefault,
1386
- VolumeHealthStatuses,
1387
- getAllVolumeMetadata,
1388
- getHiddenMetadata,
1389
- getVolumeMetadata,
1390
- getVolumeMountPoints,
1391
- isHidden,
1392
- isHiddenRecursive,
1393
- optionsWithDefaults,
1394
- setHidden
1395
- };
1396
- //# sourceMappingURL=index.mjs.map