Names quak builds from server data fit in 255 bytes #213

Merged
clawbot merged 3 commits from fix/205-long-names into next 2026-10-18 20:01:35 +02:00
Collaborator

Closes #205.

A file system refuses a file name over 255 bytes. A long album name stopped backup-metadata, a long title made quak get and quak get-thumb fail without --out, and a long extension made quak backup fail one original on every run.

What changed:

  • src/filename.ts: shortenKeepingExtension(name, maxBytes, insert) cuts the part before the extension first, and cuts the extension only when it leaves no room for the first character before it, so a cut name never starts with a dot. The backup's withID uses it to put an ID before the extension.
  • defaultFileName(title, fileID, { prefix, ext }) there gives the name a file is saved under when the caller gives no path; originalName, thumbnailName, downloadFile and downloadThumbnail call it. A live photo's image and video are each named with their own extension before the cut. A path from --out or outPath is kept as given.
  • safeExtension gives .bin for an extension of more than 16 letters and digits.
  • backup-metadata: an album's folder is its ID and -, then its name cut short so that the whole fits in 255 bytes.
  • README: these rules, in "CLI surface" and "Backup layout".

Worth knowing:

  • The same rule names quak backup's link for a title whose extension leaves no room for its ID: the title's first character comes before the ID (a (1).LLL…). Two backup tests change to match.
  • Judgement call: downloadFile passes decryptLivePhoto a flag saying its destination is the default name, as a live photo's extensions are known only once it is unpacked.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/quak/issues/205. A file system refuses a file name over 255 bytes. A long album name stopped `backup-metadata`, a long title made `quak get` and `quak get-thumb` fail without `--out`, and a long extension made `quak backup` fail one original on every run. What changed: - `src/filename.ts`: `shortenKeepingExtension(name, maxBytes, insert)` cuts the part before the extension first, and cuts the extension only when it leaves no room for the first character before it, so a cut name never starts with a dot. The backup's `withID` uses it to put an ID before the extension. - `defaultFileName(title, fileID, { prefix, ext })` there gives the name a file is saved under when the caller gives no path; `originalName`, `thumbnailName`, `downloadFile` and `downloadThumbnail` call it. A live photo's image and video are each named with their own extension before the cut. A path from `--out` or `outPath` is kept as given. - `safeExtension` gives `.bin` for an extension of more than 16 letters and digits. - `backup-metadata`: an album's folder is its ID and `-`, then its name cut short so that the whole fits in 255 bytes. - README: these rules, in "CLI surface" and "Backup layout". Worth knowing: - The same rule names `quak backup`'s link for a title whose extension leaves no room for its ID: the title's first character comes before the ID (`a (1).LLL…`). Two backup tests change to match. - Judgement call: `downloadFile` passes `decryptLivePhoto` a flag saying its destination is the default name, as a live photo's extensions are known only once it is unpacked. Model: opus-5-5
clawbot added the needs-review label 2026-10-18 18:27:02 +02:00
clawbot self-assigned this 2026-10-18 18:27:06 +02:00
Author
Collaborator
  1. A live photo's default names can still be over 255 bytes. In src/cli-commands.ts lines 329-331 and src/download/index.ts lines 495-496, the title's extension is swapped for the live photo's own (.heic, .mov) after the title has been cut short. A title of exactly 255 bytes ending in .jpg, or a 300-byte title with no extension, still makes quak get fail with ENAMETOOLONG and exit 1. The definition of done in #205 says every default name must fit in 255 bytes with everything added to it, and the new README paragraph (lines 678-682) says a name over 255 bytes is cut short. Acceptable: the default names of a live photo's image and video are cut short after their extension is chosen (a path given with --out or outPath stays exactly as given), with a test for each of the two titles above.

  2. quak get can write a hidden file. shortenKeepingExtension in src/filename.ts (line 68) keeps nothing before the extension when the extension alone is 255 bytes or more. So quak get and downloadFile save the title b. followed by 300 es as .eee..., a hidden file. The header of src/filename.ts (line 6) promises that a name from server data is never hidden, which is why sanitizeFileName turns a leading dot into _. The test at test/filename/filename.test.ts line 144 expects the hidden name. Acceptable: this function never returns a name that starts with a dot. For example, when the extension alone does not fit, cut the whole name from its start as shortenToBytes does. Update the tests to match.

  3. TODO.md no longer matches the tracker or the code. Line 20 says "No bug is open.", but #210 is open. The Completed Steps entry (line 34) says the default names of quak get and downloadFile are cut short to 255 bytes, which is not true for a live photo. Acceptable: "Next Step" names the bugs that are open, and the entry describes what the code does.

  4. The default-name rule is written out four times. The rule (the title with unsafe characters replaced, cut short to 255 bytes, with or without thumb_ in front) appears in originalName and thumbnailName in src/cli-output.ts (lines 43-56) and again in the defaults of downloadFile and downloadThumbnail in src/download/index.ts (lines 594-626). Before this change, thumbnailName reused originalName. Acceptable: one function in src/filename.ts, which both files already import, that returns the default name for a title with an optional prefix, called from all four places.

Model: opus-5-5

1. **A live photo's default names can still be over 255 bytes.** In `src/cli-commands.ts` lines 329-331 and `src/download/index.ts` lines 495-496, the title's extension is swapped for the live photo's own (`.heic`, `.mov`) after the title has been cut short. A title of exactly 255 bytes ending in `.jpg`, or a 300-byte title with no extension, still makes `quak get` fail with `ENAMETOOLONG` and exit 1. The definition of done in https://git.eeqj.de/sneak/quak/issues/205 says every default name must fit in 255 bytes with everything added to it, and the new README paragraph (lines 678-682) says a name over 255 bytes is cut short. Acceptable: the default names of a live photo's image and video are cut short after their extension is chosen (a path given with `--out` or `outPath` stays exactly as given), with a test for each of the two titles above. 2. **`quak get` can write a hidden file.** `shortenKeepingExtension` in `src/filename.ts` (line 68) keeps nothing before the extension when the extension alone is 255 bytes or more. So `quak get` and `downloadFile` save the title `b.` followed by 300 `e`s as `.eee...`, a hidden file. The header of `src/filename.ts` (line 6) promises that a name from server data is never hidden, which is why `sanitizeFileName` turns a leading dot into `_`. The test at `test/filename/filename.test.ts` line 144 expects the hidden name. Acceptable: this function never returns a name that starts with a dot. For example, when the extension alone does not fit, cut the whole name from its start as `shortenToBytes` does. Update the tests to match. 3. **TODO.md no longer matches the tracker or the code.** Line 20 says "No bug is open.", but https://git.eeqj.de/sneak/quak/issues/210 is open. The Completed Steps entry (line 34) says the default names of `quak get` and `downloadFile` are cut short to 255 bytes, which is not true for a live photo. Acceptable: "Next Step" names the bugs that are open, and the entry describes what the code does. 4. **The default-name rule is written out four times.** The rule (the title with unsafe characters replaced, cut short to 255 bytes, with or without `thumb_` in front) appears in `originalName` and `thumbnailName` in `src/cli-output.ts` (lines 43-56) and again in the defaults of `downloadFile` and `downloadThumbnail` in `src/download/index.ts` (lines 594-626). Before this change, `thumbnailName` reused `originalName`. Acceptable: one function in `src/filename.ts`, which both files already import, that returns the default name for a title with an optional prefix, called from all four places. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-18 18:47:01 +02:00
clawbot added 2 commits 2026-10-18 19:08:22 +02:00
The default names of `quak get`, `quak get-thumb`, `downloadFile` and
`downloadThumbnail`, and the album folders of `backup-metadata`, could be
over 255 bytes, which a file system refuses. `shortenKeepingExtension` in
`src/filename.ts` cuts a name short, keeping its extension when it fits,
and can put text right before the extension; the backup's `withID` now
calls it instead of doing the same itself. The `get` defaults use it with
`thumb_` counted. A `backup-metadata` folder keeps its `<id>-` and has the
name after it cut short. `safeExtension` gives `.bin` for an extension of
more than 16 letters and digits, so a save path's name always fits.

Model: opus-5-5
`defaultFileName` in `src/filename.ts` now gives the name a file is saved
under when the caller gives no path, and `originalName`, `thumbnailName`,
`downloadFile` and `downloadThumbnail` all call it. For a live photo's image
and video it puts the part's own extension in before cutting the name short,
so those names fit too; a path from `--out` or `outPath` is kept as given.
`shortenKeepingExtension` keeps the first character before the extension,
cutting a long extension short to leave room for it, so a cut name no longer
starts with a dot. The backup's links for such a title change to match.
TODO.md names the open bug and describes what the code does.

Model: opus-5-5
clawbot force-pushed fix/205-long-names from d372283900 to e03e99b486 2026-10-18 19:08:22 +02:00 Compare
Author
Collaborator

Rework of #213 (comment):

  1. A live photo's image and video names come from defaultFileName with each part's own extension, so the cut comes after it, in getCommand and in decryptLivePhoto; --out and outPath are kept as given. New tests for a 255-byte title ending in .jpg and a 300-byte title with no extension, for quak get and for downloadFile.
  2. shortenKeepingExtension keeps the first character before the extension and cuts the extension short to leave room for it. I did not cut the whole name from its start: with an ID put in, two backup links could then get the same name, as the backup test "keeps names unique when a title's extension leaves no room for the ID" shows. Tests updated, two backup tests included.
  3. TODO.md: "Next Step" says no bug is open, since #210 closed during the rework, and names #211 and #212. The entry says what the code does and links the issue in full.
  4. defaultFileName(title, fileID, { prefix, ext }) in src/filename.ts; originalName, thumbnailName, downloadFile and downloadThumbnail all call it.

Also rebased onto next after the fix for #210 landed: the two long-title get and get-thumb tests now expect its progress line on stderr.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/quak/pulls/213#issuecomment-145589: 1. A live photo's image and video names come from `defaultFileName` with each part's own extension, so the cut comes after it, in `getCommand` and in `decryptLivePhoto`; `--out` and `outPath` are kept as given. New tests for a 255-byte title ending in `.jpg` and a 300-byte title with no extension, for `quak get` and for `downloadFile`. 2. `shortenKeepingExtension` keeps the first character before the extension and cuts the extension short to leave room for it. I did not cut the whole name from its start: with an ID put in, two backup links could then get the same name, as the backup test "keeps names unique when a title's extension leaves no room for the ID" shows. Tests updated, two backup tests included. 3. TODO.md: "Next Step" says no bug is open, since https://git.eeqj.de/sneak/quak/issues/210 closed during the rework, and names https://git.eeqj.de/sneak/quak/issues/211 and https://git.eeqj.de/sneak/quak/issues/212. The entry says what the code does and links the issue in full. 4. `defaultFileName(title, fileID, { prefix, ext })` in `src/filename.ts`; `originalName`, `thumbnailName`, `downloadFile` and `downloadThumbnail` all call it. Also rebased onto `next` after the fix for https://git.eeqj.de/sneak/quak/issues/210 landed: the two long-title `get` and `get-thumb` tests now expect its progress line on stderr. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-18 19:13:02 +02:00
Author
Collaborator
  1. A default name can be a Windows device name. defaultFileName in src/filename.ts (line 96) replaces unsafe characters first and cuts the name short afterwards, so the cut can leave a reserved name that sanitizeFileName would have changed. The title CONSOLE. followed by 251 letters becomes CON. and those letters, and NULL. followed by 251 letters becomes NUL. and those letters. These are the names quak get and downloadFile write when no path is given. The header of src/filename.ts (line 6) promises that a name made from server data is never a Windows device name. Acceptable: defaultFileName never returns a Windows device name, for example by applying the device-name rule to the name after it is cut short and leaving room for the _ that rule adds, with a test for the CONSOLE. title above.

Model: opus-5-5

1. **A default name can be a Windows device name.** `defaultFileName` in `src/filename.ts` (line 96) replaces unsafe characters first and cuts the name short afterwards, so the cut can leave a reserved name that `sanitizeFileName` would have changed. The title `CONSOLE.` followed by 251 letters becomes `CON.` and those letters, and `NULL.` followed by 251 letters becomes `NUL.` and those letters. These are the names `quak get` and `downloadFile` write when no path is given. The header of `src/filename.ts` (line 6) promises that a name made from server data is never a Windows device name. Acceptable: `defaultFileName` never returns a Windows device name, for example by applying the device-name rule to the name after it is cut short and leaving room for the `_` that rule adds, with a test for the `CONSOLE.` title above. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-18 19:30:16 +02:00
clawbot added 1 commit 2026-10-18 19:38:18 +02:00
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
Author
Collaborator

Rework of #213 (comment): when the cut leaves a Windows device name, defaultFileName now puts a _ in front and cuts the name one byte shorter so it still fits. There are new tests for the CONSOLE. and NULL. titles.
The backup's links and album folders and the backup-metadata album folders need no change: the ID sits right next to the part that is cut, so that part can never be a device name.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/quak/pulls/213#issuecomment-145641: when the cut leaves a Windows device name, `defaultFileName` now puts a `_` in front and cuts the name one byte shorter so it still fits. There are new tests for the `CONSOLE.` and `NULL.` titles. The backup's links and album folders and the `backup-metadata` album folders need no change: the ID sits right next to the part that is cut, so that part can never be a device name. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-18 19:47:14 +02:00
Author
Collaborator

Review passed.
Model: opus-5-5

Review passed. Model: opus-5-5
clawbot merged commit 66e3ac77e8 into next 2026-10-18 20:01:35 +02:00
clawbot deleted branch fix/205-long-names 2026-10-18 20:01:35 +02:00
Sign in to join this conversation.