Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions packages/frontend/app/services/checks/checks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
16 changes: 11 additions & 5 deletions packages/frontend/app/services/checks/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.'
})
}

Expand Down
Loading