From 2365936f52a35f0ac27ebdb2c71a5910f966b0d1 Mon Sep 17 00:00:00 2001 From: xmutantson Date: Sun, 18 Oct 2026 17:57:50 -0700 Subject: [PATCH] libfatx: Allow 42-character file names A FATX directory entry holds names of up to 42 bytes (FATX_MAX_FILENAME_LEN), and retail games ship files with names of exactly that length. The length checks in fatx_create_dirent() and fatx_rename() used >=, so those names were rejected and copying such a file failed with EPERM. The in-memory name buffers are FATX_MAX_FILENAME_LEN+1 bytes and the on-disk field is FATX_MAX_FILENAME_LEN bytes with the length stored separately, so a 42-character name already fits everywhere it is copied. --- libfatx/fatx_dir.c | 2 +- libfatx/fatx_file.c | 4 ++-- pyfatx/tests/test.py | 26 ++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/libfatx/fatx_dir.c b/libfatx/fatx_dir.c index a5f55a9..d7cf5f2 100644 --- a/libfatx/fatx_dir.c +++ b/libfatx/fatx_dir.c @@ -470,7 +470,7 @@ int fatx_create_dirent(struct fatx_fs *fs, char const *path, struct fatx_dir *di /* Check basename is not too long */ path_basename = fatx_basename(path); - if (strlen(path_basename) >= FATX_MAX_FILENAME_LEN) + if (strlen(path_basename) > FATX_MAX_FILENAME_LEN) { free(path_basename); fatx_error(fs, "filename is too long\n"); diff --git a/libfatx/fatx_file.c b/libfatx/fatx_file.c index 51a1769..f496eea 100644 --- a/libfatx/fatx_file.c +++ b/libfatx/fatx_file.c @@ -427,7 +427,7 @@ int fatx_rename(struct fatx_fs *fs, char const *from, char const *to, bool excha /* Check that the new filename is not too long */ to_basename = fatx_basename(to); - if (strlen(to_basename) >= FATX_MAX_FILENAME_LEN) + if (strlen(to_basename) > FATX_MAX_FILENAME_LEN) { fatx_error(fs, "destination name too long\n"); status = FATX_STATUS_ERROR; @@ -435,7 +435,7 @@ int fatx_rename(struct fatx_fs *fs, char const *from, char const *to, bool excha } from_basename = fatx_basename(from); - if (strlen(from_basename) >= FATX_MAX_FILENAME_LEN) + if (strlen(from_basename) > FATX_MAX_FILENAME_LEN) { fatx_error(fs, "source name too long\n"); status = FATX_STATUS_ERROR; diff --git a/pyfatx/tests/test.py b/pyfatx/tests/test.py index a139798..72e32c4 100755 --- a/pyfatx/tests/test.py +++ b/pyfatx/tests/test.py @@ -446,5 +446,31 @@ def test_rename_no_replace_with_nonexistent_destination_works(self, path): assert d2 == b1 + @with_formatted_disk + def test_filename_max_length(self, path): + fs = Fatx(path) + + # 42 characters is the longest name a FATX directory entry holds + name42 = '/' + 'a' * 38 + '.bin' + fs.write(name42, b'42') + assert fs.read(name42) == b'42' + assert [a.filename for a in fs.listdir('/')] == [name42[1:]] + + renamed42 = '/' + 'b' * 38 + '.bin' + fs.rename(name42, renamed42) + assert fs.read(renamed42) == b'42' + + name43 = '/' + 'c' * 39 + '.bin' + created = False + try: + fs.write(name43, b'43') + created = True + except AssertionError: + pass + assert not created + + fs.unlink(renamed42) + + if __name__ == '__main__': unittest.main()