hfs 0.53.0 → 0.53.2

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/src/upload.js CHANGED
@@ -61,9 +61,9 @@ function uploadWriter(base, path, ctx) {
61
61
  else
62
62
  try {
63
63
  // refer to the source of the closest node that actually belongs to the vfs, so that cache is more effective
64
- let closestVfsNode = base;
65
- while (closestVfsNode && !closestVfsNode.original)
66
- closestVfsNode = closestVfsNode.parent;
64
+ let closestVfsNode = base; // if base=root, there's no parent and no original
65
+ while ((closestVfsNode === null || closestVfsNode === void 0 ? void 0 : closestVfsNode.parent) && !closestVfsNode.original)
66
+ closestVfsNode = closestVfsNode.parent; // if it's not original, it surely has a parent
67
67
  const statDir = closestVfsNode.source;
68
68
  if (!Object.hasOwn(diskSpaceCache, statDir)) {
69
69
  const c = diskSpaceCache[statDir] = (0, util_os_1.getDiskSpaceSync)(statDir);
@@ -88,12 +88,12 @@ function uploadWriter(base, path, ctx) {
88
88
  openFiles.add(fullPath);
89
89
  try {
90
90
  // if upload creates a folder, then add meta to it too
91
- if (fs_1.default.mkdirSync(dir, { recursive: true }))
91
+ if (!dir.endsWith(':\\') && fs_1.default.mkdirSync(dir, { recursive: true }))
92
92
  setUploadMeta(dir, ctx);
93
93
  // use temporary name while uploading
94
94
  const keepName = (0, path_1.basename)(fullPath).slice(-200);
95
95
  let tempName = (0, path_1.join)(dir, 'hfs$upload-' + keepName);
96
- const resumable = fs_1.default.existsSync(tempName) && !openFiles.has(tempName) && tempName;
96
+ const resumable = fs_1.default.existsSync(tempName) && !openFiles.has(tempName) && tempName; // resumable is temp-file-1
97
97
  if (resumable)
98
98
  tempName = (0, path_1.join)(dir, 'hfs$upload2-' + keepName);
99
99
  // checks for resume feature
@@ -101,15 +101,19 @@ function uploadWriter(base, path, ctx) {
101
101
  const size = resumable && (0, misc_1.try_)(() => fs_1.default.statSync(resumable).size);
102
102
  if (size === undefined) // stat failed
103
103
  return fail(const_1.HTTP_SERVER_ERROR);
104
- if (resume > size)
104
+ if (lodash_1.default.isNumber(size) && resume > size)
105
105
  return fail(const_1.HTTP_RANGE_NOT_SATISFIABLE);
106
106
  // warn frontend about resume possibility
107
+ let resumableLost = false;
107
108
  if (!resume && resumable) {
108
109
  const timeout = 30;
109
110
  (0, frontEndApis_1.notifyClient)(ctx, 'upload.resumable', { [path]: size, expires: Date.now() + timeout * 1000 });
110
- delayedDelete(resumable, timeout, () => fs_1.default.rename(tempName, resumable, err => {
111
- if (!err)
112
- tempName = resumable;
111
+ delayedDelete(resumable, timeout, () => // if user resumes, this upload is interrupted, and next upload will cancel this delayedDelete
112
+ fs_1.default.rename(tempName, resumable, err => {
113
+ if (err)
114
+ return;
115
+ tempName = resumable;
116
+ resumableLost = true;
113
117
  }));
114
118
  }
115
119
  // append if resuming
@@ -136,9 +140,10 @@ function uploadWriter(base, path, ctx) {
136
140
  const lockMiddleware = (0, misc_1.pendingPromise)(); // outside we need to know when all operations stopped
137
141
  writeStream.once('close', async () => {
138
142
  try {
143
+ await new Promise(res => fileStream.close(res)); // this only seem to be necessary on Windows
139
144
  if (ctx.req.aborted) {
140
- if (resumable) // we don't want to be left with 2 temp files
141
- return delayedDelete(tempName, 0);
145
+ if (resumable && !resumableLost && !resuming) // we don't want to be left with 2 temp files
146
+ return (0, promises_1.rm)(tempName);
142
147
  const sec = exports.deleteUnfinishedUploadsAfter.get();
143
148
  return lodash_1.default.isNumber(sec) && delayedDelete(tempName, sec);
144
149
  }
@@ -153,12 +158,13 @@ function uploadWriter(base, path, ctx) {
153
158
  }
154
159
  try {
155
160
  await (0, promises_1.rename)(tempName, dest);
161
+ cancelDeletion(tempName); // not necessary, as deletion's failure is silent, but still
156
162
  ctx.state.uploadDestinationPath = dest;
157
163
  setUploadMeta(dest, ctx);
158
164
  if (ctx.query.comment)
159
165
  void (0, comments_1.setCommentFor)(dest, String(ctx.query.comment));
160
- if (resumable)
161
- delayedDelete(resumable, 0);
166
+ if (resumable && !resuming) // this happens if user decided to not resume and the new upload finished before delayedDelete
167
+ (0, promises_1.rm)(resumable).catch(console.warn);
162
168
  events_1.default.emit('uploadFinished', obj);
163
169
  if (resEvent)
164
170
  for (const cb of resEvent)
package/src/util-files.js CHANGED
@@ -154,7 +154,7 @@ function createFileWithPath(path, options) {
154
154
  }
155
155
  exports.createFileWithPath = createFileWithPath;
156
156
  function isValidFileName(name) {
157
- return !/[/*?<>|\\]/.test(name) && !dirTraversal(name);
157
+ return !(const_1.IS_WINDOWS ? /[/:"*?<>|\\]/ : /\//).test(name) && !dirTraversal(name);
158
158
  }
159
159
  exports.isValidFileName = isValidFileName;
160
160
  function exists(path) {
package/src/vfs.js CHANGED
@@ -103,8 +103,6 @@ async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
103
103
  exports.urlToNode = urlToNode;
104
104
  async function getNodeByName(name, parent) {
105
105
  var _a;
106
- if (!(0, misc_1.isValidFileName)(name))
107
- return;
108
106
  // does the tree node have a child that goes by this name, otherwise attempt disk
109
107
  const child = ((_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(isSameFilenameAs(name))) || childFromDisk();
110
108
  return child && applyParentToChild(child, parent, name);
@@ -121,6 +119,8 @@ async function getNodeByName(name, parent) {
121
119
  }
122
120
  ret.rename = renameUnderPath(parent.rename, name);
123
121
  }
122
+ if (!(0, misc_1.isValidFileName)(onDisk))
123
+ return;
124
124
  ret.source = (0, path_1.join)(parent.source, onDisk);
125
125
  ret.original = undefined; // overwrite in applyParentToChild, so we know this is not part of the vfs
126
126
  return ret;
@@ -233,7 +233,7 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
233
233
  const name = prefixPath + nodeName;
234
234
  took === null || took === void 0 ? void 0 : took.add(normalizeFilename(name));
235
235
  const item = { ...child, name };
236
- if (!canSee(item))
236
+ if (!await canSee(item))
237
237
  continue;
238
238
  if (item.source) // real items must be accessible
239
239
  try {
@@ -279,7 +279,7 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
279
279
  };
280
280
  if (isFolder) // store it even if we can't see it (masks), as its children can be produced by dirStream
281
281
  parentsCache.set(name, item);
282
- if (canSee(item))
282
+ if (await canSee(item))
283
283
  yield item;
284
284
  }
285
285
  }
@@ -287,9 +287,9 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
287
287
  console.debug('glob', source, e); // ENOTDIR, or lacking permissions
288
288
  }
289
289
  // item will be changed, so be sure to pass a temp node
290
- function canSee(item) {
290
+ async function canSee(item) {
291
291
  // we basename for depth>0 where we already have the rest of the path in the parent's url, and would be duplicated
292
- maskApplier(item, (0, path_1.basename)(getNodeName(item)));
292
+ await maskApplier(item, (0, path_1.basename)(getNodeName(item)));
293
293
  inheritFromParent(parent, item);
294
294
  if (ctx && !hasPermission(item, 'can_see', ctx))
295
295
  return;