hfs 3.3.0-beta2 → 3.3.0-beta3

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.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "hfs",
3
- "version": "3.3.0-beta2",
3
+ "version": "3.3.0-beta3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "hfs",
9
- "version": "3.3.0-beta2",
9
+ "version": "3.3.0-beta3",
10
10
  "license": "GPL-3.0",
11
11
  "dependencies": {
12
12
  "@gregoranders/csv": "^0.0.13",
@@ -1710,9 +1710,9 @@
1710
1710
  }
1711
1711
  },
1712
1712
  "node_modules/pvutils": {
1713
- "version": "1.1.5",
1714
- "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz",
1715
- "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==",
1713
+ "version": "1.2.0",
1714
+ "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz",
1715
+ "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==",
1716
1716
  "license": "MIT",
1717
1717
  "engines": {
1718
1718
  "node": ">=16.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hfs",
3
- "version": "3.3.0-beta2",
3
+ "version": "3.3.0-beta3",
4
4
  "description": "HTTP File Server",
5
5
  "keywords": [
6
6
  "file server",
package/src/vfs.js CHANGED
@@ -261,6 +261,8 @@ function nodeIsFolder(node) {
261
261
  }
262
262
  // we mark folder paths with a final slash – the UI already does so, but the config may be modified
263
263
  function persistFolderMarker(node) {
264
+ if ('original' in node && !node.original)
265
+ return; // disk-derived nodes are temporary and must not persist VFS changes
264
266
  const stored = node.original || node; // temporary VFS nodes must update their stored original for saveVfs to persist the marker
265
267
  if (!stored.source || (0, misc_1.hasFinalSlash)(stored.source))
266
268
  return;
package/src/watchLoad.js CHANGED
@@ -19,6 +19,8 @@ function watchLoad(path, parser, { failedOnFirstAttempt, immediateFirst } = {})
19
19
  let last;
20
20
  const emitter = new events_1.BetterEventEmitter();
21
21
  const save = (0, debounceAsync_1.debounceAsync)(async (data, { reparse = false } = {}) => {
22
+ if (doing)
23
+ await debounced.isWorking();
22
24
  await promises_1.default.writeFile(path, data, 'utf8');
23
25
  last = data;
24
26
  if (reparse)
@@ -59,9 +61,10 @@ function watchLoad(path, parser, { failedOnFirstAttempt, immediateFirst } = {})
59
61
  async function load() {
60
62
  if (doing)
61
63
  return;
64
+ const saving = save.flush(); // saves started after this handoff wait for the read, while we wait only for the save captured here
62
65
  doing = true;
63
66
  try {
64
- await save.flush(); // apply pending saves first
67
+ await saving; // apply pending saves first
65
68
  const text = await (0, util_files_1.readFileWithBusyRetry)(path).catch(e => {
66
69
  if (e.code === 'EPERM')
67
70
  console.error("Missing permissions on file", path); // warn user, who could be clueless about this problem
package/src/webdav.js CHANGED
@@ -452,14 +452,18 @@ async function applyProppatchProp(prop, node, path, ctx) {
452
452
  const k = prop.name.toLowerCase();
453
453
  if (PROPPATCH_PROTECTED_LIVE_PROPS.has(k))
454
454
  return cross_1.HTTP_FORBIDDEN;
455
- if (node.source && (PROPPATCH_UTIME_PROPS.has(k) || const_1.IS_WINDOWS && k === 'win32fileattributes')) {
456
- // WebDAV clients patch metadata right after upload; outside that short same-username grace, metadata writes are file modifications
457
- const missingWritePerm = canOverwrite.has(path + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx))) ? 0
458
- : (0, vfs_1.statusCodeForMissingPerm)(node, 'can_delete', ctx, false);
459
- if (missingWritePerm)
460
- return missingWritePerm;
461
- }
462
- if (node.source && PROPPATCH_UTIME_PROPS.has(k)) {
455
+ if (!PROPPATCH_UTIME_PROPS.has(k)
456
+ && !(const_1.IS_WINDOWS && k === 'win32fileattributes'))
457
+ return cross_1.HTTP_OK; // PROPPATCH is only persisted when HFS gets real dead-property storage; no-op success keeps Windows and macOS clients from aborting writes
458
+ const { source } = node;
459
+ if (!source)
460
+ return cross_1.HTTP_FORBIDDEN;
461
+ // WebDAV clients patch metadata right after upload; outside that short same-username grace, metadata writes are file modifications
462
+ const missingWritePerm = canOverwrite.has(path + (0, cross_1.prefix)('|', (0, auth_1.getCurrentUsername)(ctx))) ? 0
463
+ : (0, vfs_1.statusCodeForMissingPerm)(node, 'can_delete', ctx, false);
464
+ if (missingWritePerm)
465
+ return missingWritePerm;
466
+ if (PROPPATCH_UTIME_PROPS.has(k)) {
463
467
  const date = new Date(String(prop.value));
464
468
  if (isNaN(Number(date)))
465
469
  return cross_1.HTTP_BAD_REQUEST;
@@ -467,18 +471,17 @@ async function applyProppatchProp(prop, node, path, ctx) {
467
471
  const atime = k === 'win32lastaccesstime' ? date : stats?.atime ?? new Date();
468
472
  const mtime = k === 'win32lastmodifiedtime' ? date : stats?.mtime ?? new Date();
469
473
  // WebDAV clients often use dead properties for file times; apply the portable subset instead of only pretending success
470
- await (0, promises_1.utimes)(node.source, atime, mtime);
474
+ await (0, promises_1.utimes)(source, atime, mtime);
471
475
  }
472
- if (node.source && const_1.IS_WINDOWS && k === 'win32fileattributes') {
476
+ else {
473
477
  const attributes = parseWindowsFileAttributes(prop.value);
474
478
  if (attributes === undefined)
475
479
  return cross_1.HTTP_BAD_REQUEST;
476
480
  // fswin is already our Windows attribute bridge; this keeps PROPPATCH metadata aligned with the actual filesystem
477
- const ok = await new Promise(resolve => fswin_1.default.setAttributes(node.source, lodash_1.default.mapValues(WINDOWS_FILE_ATTRIBUTE_FLAGS, flag => Boolean(attributes & flag)), ok => resolve(Boolean(ok))));
481
+ const ok = await new Promise(resolve => fswin_1.default.setAttributes(source, lodash_1.default.mapValues(WINDOWS_FILE_ATTRIBUTE_FLAGS, flag => Boolean(attributes & flag)), ok => resolve(Boolean(ok))));
478
482
  if (!ok)
479
483
  return cross_1.HTTP_SERVER_ERROR;
480
484
  }
481
- // PROPPATCH is only persisted when HFS gets real dead-property storage; no-op success keeps Windows and macOS clients from aborting writes
482
485
  return cross_1.HTTP_OK;
483
486
  }
484
487
  function parseWindowsFileAttributes(v) {