defaultFileName replaced unsafe characters before cutting the name short, so the cut could leave a device name: `CONSOLE.` before a 251-letter extension became `CON.` and that extension, and `NULL.` became `NUL.`. A name the cut leaves as a device name now gets a leading `_`, as sanitizeFileName gives one, and is cut a byte shorter to leave room for it. The backup's links and album folders and the `backup-metadata` album folders need no change: the ID comes right after or right before the part that is cut, so that part can never be a device name. Model: opus-5-5
This commit is contained in:
+8
-8
@@ -92,7 +92,10 @@ export const shortenKeepingExtension = (
|
|||||||
// short so that the whole fits in a file name, keeping the title's extension
|
// short so that the whole fits in a file name, keeping the title's extension
|
||||||
// whenever it fits. `ext` (".mov"), when given, takes the place of the
|
// whenever it fits. `ext` (".mov"), when given, takes the place of the
|
||||||
// title's extension before the name is cut short; a live photo's image and
|
// title's extension before the name is cut short; a live photo's image and
|
||||||
// video are each named with their own.
|
// video are each named with their own. The cut can leave a device name
|
||||||
|
// (`CONSOLE.<long extension>` becomes `CON.<long extension>`); that name gets
|
||||||
|
// a leading `_`, as `sanitizeFileName` gives one, and is cut a byte shorter to
|
||||||
|
// leave room for it.
|
||||||
export const defaultFileName = (
|
export const defaultFileName = (
|
||||||
title: string,
|
title: string,
|
||||||
fileID: number,
|
fileID: number,
|
||||||
@@ -101,11 +104,8 @@ export const defaultFileName = (
|
|||||||
const { prefix = "", ext } = opts;
|
const { prefix = "", ext } = opts;
|
||||||
const safe = sanitizeFileName(title, `file-${fileID}`);
|
const safe = sanitizeFileName(title, `file-${fileID}`);
|
||||||
const name = ext === undefined ? safe : withExtension(safe, ext);
|
const name = ext === undefined ? safe : withExtension(safe, ext);
|
||||||
return (
|
const room = MAX_NAME_BYTES - Buffer.byteLength(prefix);
|
||||||
prefix +
|
const cut = prefix + shortenKeepingExtension(name, room);
|
||||||
shortenKeepingExtension(
|
if (!RESERVED_DEVICE_NAME.test(cut)) return cut;
|
||||||
name,
|
return `_${prefix}${shortenKeepingExtension(name, room - 1)}`;
|
||||||
MAX_NAME_BYTES - Buffer.byteLength(prefix),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -216,4 +216,13 @@ describe("defaultFileName", () => {
|
|||||||
`${"t".repeat(250)}.heic`,
|
`${"t".repeat(250)}.heic`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Cutting `CONSOLE` or `NULL` short before a long extension leaves `CON`
|
||||||
|
// or `NUL`, so the name gets the `_` `sanitizeFileName` gives a device
|
||||||
|
// name, and the part before the extension gives up a byte for it.
|
||||||
|
it("never returns a Windows device name, even once cut short", () => {
|
||||||
|
const ext = `.${"e".repeat(251)}`;
|
||||||
|
expect(defaultFileName(`CONSOLE${ext}`, 42)).toBe(`_CO${ext}`);
|
||||||
|
expect(defaultFileName(`NULL${ext}`, 42)).toBe(`_NU${ext}`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user