Filename Compatibility Pack
The fastest way to find out what your file handling does to a difficult name is to extract this archive on each operating system you support and diff the results. Windows will refuse several outright, macOS will quietly change one of them, and Linux will accept them all.
SHA-256 9c63d68a8b7d98d962a035a78f1bae2adb129a61e9872051ad8accd96984aba0
What is inside
| File | Format | Size | Expected result |
|---|---|---|---|
| .hidden-leading-dot | TXT | 142 bytes | Directory listings that filter dotfiles, and extension parsers that see an empty basename. |
| 🦊-emoji-name.txt | TXT | 142 bytes | Systems that store names as UTF-16 and count length in code units, or databases on utf8 rather than utf8mb4 - MySQL will reject or truncate this. |
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt | TXT | 142 bytes | Filesystem limits (255 bytes on ext4, and 255 UTF-16 units on NTFS), plus database columns sized at VARCHAR(100) or VARCHAR(255) that truncate on insert. |
| ampersand&name.txt | TXT | 142 bytes | Query-string construction and unescaped HTML rendering of the name. |
| archive.tar.gz | TXT | 142 bytes | The control case for the double-extension test: this one must be accepted. |
| backslash\name.txt | TXT | 142 bytes | Cross-platform path handling - Windows treats this as a directory separator, POSIX does not. |
| CON.txt | TXT | 142 bytes | Windows cannot create files named CON, PRN, AUX, NUL, COM1-9 or LPT1-9, even with an extension. Extraction and download on Windows will fail unless the name is sanitised. |
| dots.in.the.name.txt | TXT | 142 bytes | Extension detection that splits on the first dot rather than the last. |
| double"quote.txt | TXT | 142 bytes | Content-Disposition header construction - an unescaped quote terminates the filename parameter early and can inject further header directives. |
| hash#name.txt | TXT | 142 bytes | URL handling - everything after # becomes a fragment and never reaches the server. |
| invoicegnp.txt | TXT | 142 bytes | A spoofing vector: the displayed name misrepresents the real extension. Filename display should strip or escape bidi control characters. |
| nfc-café.txt | TXT | 142 bytes | Pair with the NFD file. They look identical but differ byte-for-byte, so dedupe and lookup by name must normalise first. macOS stores NFD, Linux stores what it is given. |
| nfd-café.txt | TXT | 142 bytes | The other half of the normalisation pair. |
| no-extension-at-all | TXT | 142 bytes | Type detection that depends on extension rather than content sniffing. |
| NUL.txt | TXT | 142 bytes | Same as CON.txt - writes silently go to the null device on some Windows APIs. |
| percent%20encoded.txt | TXT | 142 bytes | Double-decoding bugs, where the stored name becomes "percent encoded.txt" after one decode too many. |
| plus+name.txt | TXT | 142 bytes | Form-encoded decoding that turns + into a space. |
| question?name.txt | TXT | 142 bytes | URL handling - everything after ? becomes a query string. |
| report.pdf.exe | TXT | 142 bytes | Blocklists that check only the first extension, and UI that truncates the displayed name and hides the dangerous suffix. |
| semicolon;name.txt | TXT | 142 bytes | Content-Disposition parsing, where semicolon separates parameters. |
| single'quote.txt | TXT | 142 bytes | SQL string building and unquoted shell arguments. |
| spaces in name.txt | TXT | 142 bytes | URL construction that forgets to percent-encode, and shell commands built by string concatenation. |
| trailing-dot.txt. | TXT | 142 bytes | Windows silently strips trailing dots, so this file can collide with trailing-dot.txt on save. |
| UPPERCASE.TXT | TXT | 142 bytes | Case-sensitivity mismatches between a case-insensitive dev machine (macOS, Windows) and a case-sensitive production filesystem (Linux) or object store (S3/R2 are case-sensitive). |
| файл-кириллица.txt | TXT | 142 bytes | As above, with a different script. |
| 日本語ファイル名.txt | TXT | 142 bytes | Non-ASCII names require RFC 5987 filename* encoding in Content-Disposition; the plain filename parameter cannot carry them. |
sha256sum -c. Every file is generated from source, carries no third-party copyright, and is free to redistribute.Questions
Which filenames break on Windows?
Reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9) with or without an extension, names containing < > : " / \ | ? *, and names ending in a dot or a space, which Windows silently strips. All of them are in this pack.
Why are there two versions of café.txt?
One is NFC, where é is a single code point, and one is NFD, where it is an e followed by a combining accent. They look identical and differ in bytes. macOS stores filenames decomposed, so a file copied from a Mac can fail to match the same name typed on Windows, which is how you end up with two copies.
How long can a filename be?
Most file systems allow 255 bytes per component, which is fewer than 255 characters as soon as the name is not ASCII. The 200-character name in this pack sits under the limit as characters and over it as UTF-8 bytes in some encodings, which is exactly where truncation bugs live.
Other packs
Upload Torture Test Pack · Encoding and Unicode Pack · Archive and ZIP Security Pack · Document Parser Pack · Image Pipeline Pack · Structured Data Pack · Email Parser Pack