eclipse-threadx / filex

Eclipse ThreadX - FileX is a high-performance, FAT-compatible file system that’s fully integrated with Eclipse ThreadX RTOS
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/filex/index.md
MIT License
29 stars 23 forks source link

exFAT: fx_dir_entry_available_file_size is not updated when writing to a file #11

Open joel-jetcharge opened 2 years ago

joel-jetcharge commented 2 years ago

When calling fx_file_write on a file the fx_file_dir_entry.fx_dir_entry_available_file_size field is not being updated before saving the directory entry. This causes issues when a file is re-opened as the fx_file_current_available_size field will be set to 0 even though disk space has been allocated.

Example code to demonstrate issue:

FX_FILE test_file = { 0U };
const char test_data[] = "ABCD1234";

// Create a new file and open
fx_file_create(media_ptr, "test_file.txt");
fx_file_open(media_ptr, &test_file, "test_file.txt", FX_OPEN_FOR_WRITE);

// Write some data to the file
fx_file_write(&test_file, (void*)test_data, sizeof(test_data));

// Observe the fx_file_current_available_size value. This will be non-zero, 
// in my case 8192 (the size of my cluster).
uint64_t previous_available_size = test_file.fx_file_current_available_size;

// Close the file. It would be expected that the available_size would have been saved.
fx_file_close(&test_file);

memset(&test_file, 0U, sizeof(test_file));

// Re-open the file.
fx_file_open(media_ptr, &test_file, "test_file.txt", FX_OPEN_FOR_WRITE);

// Observe that the fx_file_current_available_size is 0!
uint64_t current_available_size = test_file.fx_file_current_available_size;

Continuing to write to a file in this state causes unexpected behaviour. As fx_file_current_file_offset is non-zero we get an underflow on fx_file_write.c:292:

    /* Next, determine if there is enough room to write the specified number of
       bytes to the clusters already allocated to this file.  */
    if (((file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset) < size)

The driver will continue to think there is enough space allocated even when there is not. Clusters will be written to even though they were not properly allocated.

I tested with both Fault Tolerant module on and off, with same results for exFAT. I also tested with FAT16 which does not have the issue as fx_file_current_available_size is calculated differently.

Workaround: As a temporary fix I've added the following code to fx_file_write.c:1603 and fx_file_write.c:1698 (i.e. below where fx_file_dir_entry.fx_dir_entry_file_size is updated):

#ifdef FX_ENABLE_EXFAT
        file_ptr -> fx_file_dir_entry.fx_dir_entry_available_file_size = 
            file_ptr -> fx_file_current_available_size;  
#endif /* FX_ENABLE_EXFAT */
gaelbourreau commented 2 years ago

Hi, thank you for the workaround. It works for me.

Also, it seems that the issue is related to the SEARCH_CACHE feature. When the macro FX_MEDIA_DISABLE_SEARCH_CACHE is defined, there is no problem. But the reopening process will be more expensive.