From ddb8ec293c89ef5c66696ae040c60fe57fd75f57 Mon Sep 17 00:00:00 2001 From: dangreen Date: Wed, 21 Oct 2026 14:26:28 +0400 Subject: [PATCH] fix(frontend): warn about FAT32, not exFAT, for an installer over 4 GiB The note before the build said that a file over 4 GB does not fit on an exFAT card, which a player pointed out is the limit of FAT32: exFAT was made to lift it. It now says that the installer is too big for a FAT32 drive, as USB sticks and memory cards up to 32 GB usually are, and points to exFAT or the network. It names no size beside the archive's, since the site counts in decimal GB and the limit is a byte short of 4 GiB, about 4.29 GB. The limit moves to that byte as well: an archive of exactly 4 GiB went without the note. --- SPEC.md | 2 +- .../frontend/app/services/checks/checks.spec.ts | 16 +++++++++++++--- packages/frontend/app/services/checks/checks.ts | 16 +++++++++++----- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/SPEC.md b/SPEC.md index 1580e3e..ba0da60 100644 --- a/SPEC.md +++ b/SPEC.md @@ -560,7 +560,7 @@ All of them warn, and none of them blocks the button: - there is not a single `.exe` in the archive (the select is empty, there is nothing to build) - the UTF-8 bit 11 is not set **and** there are non-ASCII names → Cyrillic names will arrive garbled, suggest 7-Zip -- the size is > 4 GB → a reminder about exFAT +- the size is 4 GiB or more → the installer does not fit on FAT32, which caps a file a byte short of 4 GiB and is how USB sticks and memory cards up to 32 GB usually come; exFAT has no such limit - `navigator.storage.estimate()` < the size of the archive → there will not be enough space (Chrome writes into a temporary swap file and swaps it in at the end). Only where the picker is: Firefox 157 reports the quota of the site instead, 7.4 GiB on a disk with 51 GB free - the chosen exe got a negative weight under 7.2.1 (the person picked by hand what we ranked down): warn, but do not stand in the way - the artwork is not filled in diff --git a/packages/frontend/app/services/checks/checks.spec.ts b/packages/frontend/app/services/checks/checks.spec.ts index 01e60e6..1af86c6 100644 --- a/packages/frontend/app/services/checks/checks.spec.ts +++ b/packages/frontend/app/services/checks/checks.spec.ts @@ -40,13 +40,23 @@ describe('services', () => { expect(messages.join(' ')).toContain('7-Zip') }) - it('should mention exFAT past 4 GiB', () => { + it('should warn about FAT32 once the archive reaches 4 GiB, and point to exFAT', () => { const messages = preflight({ ...CLEAN, - archiveSize: 5 * 1024 ** 3 + archiveSize: 4 * 1024 ** 3 }).map(check => check.message) - expect(messages.join(' ')).toContain('exFAT') + expect(messages.join(' ')).toContain('too big for a drive formatted as FAT32') + expect(messages.join(' ')).toContain('Use one formatted as exFAT') + }) + + it('should leave an archive of 4 GB in decimal units alone: FAT32 holds it', () => { + const messages = preflight({ + ...CLEAN, + archiveSize: 4_000_000_000 + }).map(check => check.message) + + expect(messages.join(' ')).not.toContain('FAT32') }) it('should warn when the browser has less free space than the archive', () => { diff --git a/packages/frontend/app/services/checks/checks.ts b/packages/frontend/app/services/checks/checks.ts index 042f051..6b7661d 100644 --- a/packages/frontend/app/services/checks/checks.ts +++ b/packages/frontend/app/services/checks/checks.ts @@ -4,8 +4,13 @@ import type { CheckInput } from './checks.types.ts' -/** 4 GiB: a single file past this does not fit on a default-formatted exFAT card. */ -const EXFAT_FILE_LIMIT = 4294967296 +/** + * The largest file FAT32 holds, a byte short of 4 GiB. exFAT has no such limit, + * but USB sticks and memory cards up to 32 GB usually come formatted as FAT32. + * The check goes by the archive, which the installer outgrows only by its + * header and meta: an archive that close to the limit is the one case it misses. + */ +const FAT32_FILE_LIMIT = 4294967295 /** * Everything here warns and nothing blocks (6.3). Games are strange, and a @@ -32,11 +37,12 @@ export function preflight(input: CheckInput): Check[] { }) } - if (input.archiveSize > EXFAT_FILE_LIMIT) { + if (input.archiveSize > FAT32_FILE_LIMIT) { checks.push({ level: 'note', - message: `The archive is ${formatSize(input.archiveSize)}. A single file over 4 GB does not fit ` - + 'on an exFAT card formatted with the default settings - check the card before copying.' + message: `The archive is ${formatSize(input.archiveSize)}, so the installer will be a little bigger: ` + + 'too big for a drive formatted as FAT32, as USB sticks and memory cards up to 32 GB usually are. ' + + 'Use one formatted as exFAT, or copy the file over the network.' }) }