Describe the bug
After the rework of the StorageOperation command (nanoframework/nf-interpreter#3502), deploying a file that already exists on the device fails with WriteError, deterministically, on every retry. Only files up to a single Wire Protocol packet (WP_PACKET_SIZE, 1024 bytes) can be overwritten; a fresh device or a freshly erased file system still works, which is why this is easy to miss.
Cause
HAL_StorageOperation() in src/HAL/nanoHAL_StorageOperation.cpp opens the target file with volume->Open(relativePath, fileHandle) and relies on it to start from an empty file. Open() has no truncate semantics: a stream driver that opens an existing file for read/write keeps the previous length. The ESP32 littlefs driver does exactly that — targets/ESP32/_littlefs/littlefs_FS_Driver.cpp selects "r+" when stat() finds the file.
A file larger than one packet is sent as one StorageOperation_Write chunk followed by StorageOperation_Append chunks:
Write writes the first ~1 KB at position 0. Because the file was not truncated, its length is still the old one.
- The first
Append opens the file, seeks to the end and validates position != offset → WriteError.
The per-target implementations that the common one replaced did not have this problem: targets/ESP32/_common/targetHAL_StorageOperation.cpp called remove() on the target path before writing ("Remove the file if already exists").
Steps to reproduce
- Take an ESP32 target with accessible storage (reproduced on ESP32-S3 with littlefs,
I: drive).
- Deploy any file larger than 1 KB, e.g.
nanoff --filedeployment with I:\www\app.css (~26 KB). It succeeds — the file did not exist.
- Deploy the very same file again, without erasing the file system.
- The second deployment fails with
WriteError on that file and keeps failing on every retry.
Expected behaviour
A write replaces the existing file, as it did before #3502.
Affected
Every target whose stream driver opens an existing file without truncating it. Confirmed on ESP32/littlefs; targets/ESP32/_FatFs/fatfs_FS_Driver.cpp should be checked too.
Proposed fix
Delete the file before opening it in the StorageOperation_Write branch, restoring the previous behaviour. Both the littlefs and the FatFs driver return CLR_E_FILE_NOT_FOUND for a missing file without touching anything, so the result can be ignored. PR follows.
Describe the bug
After the rework of the
StorageOperationcommand (nanoframework/nf-interpreter#3502), deploying a file that already exists on the device fails withWriteError, deterministically, on every retry. Only files up to a single Wire Protocol packet (WP_PACKET_SIZE, 1024 bytes) can be overwritten; a fresh device or a freshly erased file system still works, which is why this is easy to miss.Cause
HAL_StorageOperation()insrc/HAL/nanoHAL_StorageOperation.cppopens the target file withvolume->Open(relativePath, fileHandle)and relies on it to start from an empty file.Open()has no truncate semantics: a stream driver that opens an existing file for read/write keeps the previous length. The ESP32 littlefs driver does exactly that —targets/ESP32/_littlefs/littlefs_FS_Driver.cppselects"r+"whenstat()finds the file.A file larger than one packet is sent as one
StorageOperation_Writechunk followed byStorageOperation_Appendchunks:Writewrites the first ~1 KB at position 0. Because the file was not truncated, its length is still the old one.Appendopens the file, seeks to the end and validatesposition != offset→WriteError.The per-target implementations that the common one replaced did not have this problem:
targets/ESP32/_common/targetHAL_StorageOperation.cppcalledremove()on the target path before writing ("Remove the file if already exists").Steps to reproduce
I:drive).nanoff --filedeploymentwithI:\www\app.css(~26 KB). It succeeds — the file did not exist.WriteErroron that file and keeps failing on every retry.Expected behaviour
A write replaces the existing file, as it did before #3502.
Affected
Every target whose stream driver opens an existing file without truncating it. Confirmed on ESP32/littlefs;
targets/ESP32/_FatFs/fatfs_FS_Driver.cppshould be checked too.Proposed fix
Delete the file before opening it in the
StorageOperation_Writebranch, restoring the previous behaviour. Both the littlefs and the FatFs driver returnCLR_E_FILE_NOT_FOUNDfor a missing file without touching anything, so the result can be ignored. PR follows.