Skip to content

Commit 6097fa2

Browse files
committed
Fix sporadic issues in RemoveBDRIEntry
This fixes #857
1 parent 321d14c commit 6097fa2

1 file changed

Lines changed: 19 additions & 7 deletions

File tree

arm9/source/game/bdri.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,17 @@ static u32 RemoveBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_of
288288
if (BDRIWrite(fht_offset + hash_bucket * sizeof(u32), sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK)
289289
return 1;
290290
} else {
291+
u32 prev_hash_index = 0;
291292
do {
292293
if (index_hash == 0) // This shouldn't happen if the entry was properly added
293294
break;
294295

296+
prev_hash_index = index_hash;
295297
if (BDRIRead(fet_offset + index_hash * sizeof(TdbFileEntry) + 0x28, sizeof(u32), &index_hash) != FR_OK)
296298
return 1;
297299
} while (index_hash != index);
298300

299-
if ((index_hash != 0) && BDRIWrite(fet_offset + index_hash * sizeof(TdbFileEntry) + 0x28, sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK)
301+
if ((prev_hash_index != 0) && BDRIWrite(fet_offset + prev_hash_index * sizeof(TdbFileEntry) + 0x28, sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK)
300302
return 1;
301303
}
302304

@@ -322,16 +324,26 @@ static u32 RemoveBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_of
322324
return 1;
323325
} while (getfatindex(fat_entry[1]) != 0);
324326

325-
fat_entry[1] |= next_free_index;
327+
// Bug fix: use buildfatuv to explicitly clear Bit 31 (the multi-block flag).
328+
// If the tail of the freed chain is a multi-block node start, Bit 31 is already
329+
// set in fat_entry[1]. A plain |= would keep it set, corrupting the free list.
330+
fat_entry[1] = buildfatuv(next_free_index, false);
326331

327-
if ((BDRIWrite(fat_offset + fat_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) ||
328-
(BDRIRead(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK))
332+
if (BDRIWrite(fat_offset + fat_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK)
329333
return 1;
330334

331-
fat_entry[0] = buildfatuv(fat_index, false);
335+
// Bug fix: guard against next_free_index == 0 (freed entry was the last free
336+
// block). Without this guard, FAT[0] (the free-list sentinel) gets corrupted
337+
// by a stray back-pointer write.
338+
if (next_free_index != 0) {
339+
if (BDRIRead(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK)
340+
return 1;
332341

333-
if (BDRIWrite(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK)
334-
return 1;
342+
fat_entry[0] = buildfatuv(fat_index, false);
343+
344+
if (BDRIWrite(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK)
345+
return 1;
346+
}
335347

336348
return 0;
337349
}

0 commit comments

Comments
 (0)