XModemAdapter: ensure file truncation before receiving and add isBusy() method to prevent concurrent writes
This commit is contained in:
+14
-1
@@ -123,15 +123,24 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
filename[sizeof(filename) - 1] = '\0';
|
filename[sizeof(filename) - 1] = '\0';
|
||||||
|
|
||||||
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
|
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
|
||||||
|
// Truncate the destination before opening. On Adafruit_LittleFS,
|
||||||
|
// `open(path, FILE_O_WRITE)` is *append* semantics (O_RDWR|O_CREAT +
|
||||||
|
// seek-to-EOF), so without a prior remove, our XModem-streamed
|
||||||
|
// payload would be concatenated onto whatever was there, producing
|
||||||
|
// a corrupt mixed file.
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
|
if (FSCom.exists(filename))
|
||||||
|
FSCom.remove(filename);
|
||||||
file = FSCom.open(filename, FILE_O_WRITE);
|
file = FSCom.open(filename, FILE_O_WRITE);
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
if (file) {
|
if (file) {
|
||||||
|
LOG_INFO("XModem: receiving %s", filename);
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
isReceiving = true;
|
isReceiving = true;
|
||||||
packetno = 1;
|
packetno = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
LOG_WARN("XModem: open(%s, WRITE) failed", filename);
|
||||||
sendControl(meshtastic_XModem_Control_NAK);
|
sendControl(meshtastic_XModem_Control_NAK);
|
||||||
isReceiving = false;
|
isReceiving = false;
|
||||||
break;
|
break;
|
||||||
@@ -169,8 +178,12 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
|
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
|
||||||
// valid packet
|
// valid packet
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
size_t written = file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
|
if (written != xmodemPacket.buffer.size) {
|
||||||
|
LOG_WARN("XModem: short write seq=%d expected=%d wrote=%d (LittleFS partition full?)",
|
||||||
|
(int)xmodemPacket.seq, (int)xmodemPacket.buffer.size, (int)written);
|
||||||
|
}
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
packetno++;
|
packetno++;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ class XModemAdapter
|
|||||||
meshtastic_XModem getForPhone();
|
meshtastic_XModem getForPhone();
|
||||||
void resetForPhone();
|
void resetForPhone();
|
||||||
|
|
||||||
|
// True while a file is being received from or transmitted to the phone.
|
||||||
|
// Callers (e.g. NodeDB::saveNodeDatabaseToDisk) consult this to avoid
|
||||||
|
// opening the same on-disk file for write in parallel, which races our
|
||||||
|
// long-lived xmodem `file` handle and ends up producing a 0-byte file.
|
||||||
|
bool isBusy() const { return isReceiving || isTransmitting; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isReceiving = false;
|
bool isReceiving = false;
|
||||||
bool isTransmitting = false;
|
bool isTransmitting = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user