diff --git a/lib/stores/filesystem.js b/lib/stores/filesystem.js index f89821ca..369fa6da 100644 --- a/lib/stores/filesystem.js +++ b/lib/stores/filesystem.js @@ -14,6 +14,23 @@ const { concatStreams, walk } = require("../utils"); const S3RVER_SUFFIX = "%s._S3rver_%s"; class FilesystemStore { + static decodeKeyPath(keyPath) { + return process.platform === "win32" + ? keyPath.replace(/&../g, ent => + Buffer.from(ent.slice(1), "hex").toString() + ) + : keyPath; + } + + static encodeKeyPath(key) { + return process.platform === "win32" + ? key.replace( + /[<>:"\\|?*]/g, + ch => "&" + Buffer.from(ch, "utf8").toString("hex") + ) + : key; + } + constructor(rootDirectory) { this.rootDirectory = rootDirectory; } @@ -25,7 +42,7 @@ class FilesystemStore { } getResourcePath(bucket, key = "", resource) { - const parts = key.split("/"); + const parts = FilesystemStore.encodeKeyPath(key).split("/"); const suffix = format(S3RVER_SUFFIX, parts.pop(), resource); return path.join(this.rootDirectory, bucket, ...parts, suffix); } @@ -128,7 +145,10 @@ class FilesystemStore { const objectSuffix = format(S3RVER_SUFFIX, "", "object"); let keys = [...walk(bucketPath)] .filter(file => file.endsWith(objectSuffix)) - .map(key => key.slice(bucketPath.length + 1, -objectSuffix.length)); + .map(keyPath => + keyPath.slice(bucketPath.length + 1, -objectSuffix.length) + ) + .map(FilesystemStore.decodeKeyPath); if (!keys.length) { return {