Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document LittleFS path length limitation #42

Open
aliphys opened this issue Apr 25, 2024 · 1 comment
Open

Document LittleFS path length limitation #42

aliphys opened this issue Apr 25, 2024 · 1 comment
Assignees
Labels
topic: documentation Related to documentation for the project type: enhancement Proposed improvement

Comments

@aliphys
Copy link
Member

aliphys commented Apr 25, 2024

Following testing with both Renesas configurations (Portenta C33 with Vision Shield & Breakout) as well as mbed (Portenta H7 + Vision Shield), it is observed that the maximum path length is 255 characters. This limitation is present for LittleFS partitions on internal storage, SD and USB.

This limitation, if part of design, should be documented.

This is demonstrated through the test sketches below which creates a 255/256 character file (including the extension) and then reads it. As a representative example, the following two sketches are provided for the Portenta H7 with the Vision Shield and internal storage. Similar observations are made for the Portenta C33 as well as USB and SD storage.

255 Character Filename - PASS

Sketch
#include "Arduino_UnifiedStorage.h"
#include "CRC.h" // https://github.com/RobTillaart/CRC

InternalStorage storage;
CRC8 crc;

const char testCaseID[] = "AUS_SPIS_FNBLFS_009";

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("---");
  Serial.print("Test Case ID: ");
  Serial.println(testCaseID);
  Serial.println("---");

  Arduino_UnifiedStorage::debuggingModeEnabled = false;  
  if (Arduino_UnifiedStorage::debuggingModeEnabled) {
    Serial.println("Arduino_UnifiedStorage debug messages ON.");
  }

  storage = InternalStorage();
  storage.format(FS_LITTLEFS);
  if(!storage.begin()){
    Serial.println("Error mounting storage device.");
  }

  // specify Test strings & CRC
  const char testContent[] = "Hello World!";
  for (int i = 0; i < strlen(testContent); i++) {
    crc.add(testContent[i]);
  }
  uint8_t testContentCRC8 = crc.calc();
  crc.reset();
  Serial.println("testContent value:" + String(testContent) + ". With CRC value:" + String(testContentCRC8));

  const char testFilename[] = "255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt";
  for (int i = 0; i < strlen(testFilename); i++) {
    crc.add(testFilename[i]);
  }
  uint8_t testFilenameCRC8 = crc.calc();
  crc.reset();
  Serial.println("testFilename value:" + String(testFilename) + ". With CRC value:" + String(testFilenameCRC8));

  // Create empty file and set to WRITE mode
  Folder root = storage.getRootFolder();
  UFile file1 = root.createFile(testFilename, FileMode::WRITE);
 
  file1.write(testContent);
  file1.changeMode(FileMode::READ);

  file1.seek(0);
  String dataRead = "";
  while (file1.available()) {
    char data = file1.read();
    crc.add(data);
    dataRead += data;
  }
  Serial.println();

  uint8_t dataReadCRC = crc.calc();

  Serial.println("Files found:");
  std::vector<UFile> files = root.getFiles();
  // Print files
  for (UFile file : files) {
    Serial.print("[F] ");
    Serial.println(file.getPath());
  }

  Serial.println("Data read was " + dataRead + " with CRC value " + String(dataReadCRC));

}

void loop() {

}

Serial Monitor

---
Test Case ID: AUS_SPIS_FNBLFS_009
---
testContent value:Hello World!. With CRC value:28
testFilename value:255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt. With CRC value:127

Files found:
[F] /internal/255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt
Data read was Hello World! with CRC value 28

256 Character Filename - FAIL

Sketch
  #include "Arduino_UnifiedStorage.h"
#include "CRC.h" // https://github.com/RobTillaart/CRC

InternalStorage storage;
CRC8 crc;

const char testCaseID[] = "AUS_SPIS_FNBLFS_010";

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("---");
  Serial.print("Test Case ID: ");
  Serial.println(testCaseID);
  Serial.println("---");

  Arduino_UnifiedStorage::debuggingModeEnabled = false;  
  if (Arduino_UnifiedStorage::debuggingModeEnabled) {
    Serial.println("Arduino_UnifiedStorage debug messages ON.");
  }

  storage = InternalStorage();
  storage.format(FS_LITTLEFS);
  if(!storage.begin()){
    Serial.println("Error mounting storage device.");
  }

  // specify Test strings & CRC
  const char testContent[] = "Hello World!";
  for (int i = 0; i < strlen(testContent); i++) {
    crc.add(testContent[i]);
  }
  uint8_t testContentCRC8 = crc.calc();
  crc.reset();
  Serial.println("testContent value:" + String(testContent) + ". With CRC value:" + String(testContentCRC8));

  const char testFilename[] = "256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256c.txt";
  for (int i = 0; i < strlen(testFilename); i++) {
    crc.add(testFilename[i]);
  }
  uint8_t testFilenameCRC8 = crc.calc();
  crc.reset();
  Serial.println("testFilename value:" + String(testFilename) + ". With CRC value:" + String(testFilenameCRC8));

  // Create empty file and set to WRITE mode
  Folder root = storage.getRootFolder();
  UFile file1 = root.createFile(testFilename, FileMode::WRITE);
 
  file1.write(testContent);
  file1.changeMode(FileMode::READ);

  file1.seek(0);
  String dataRead = "";
  while (file1.available()) {
    char data = file1.read();
    crc.add(data);
    dataRead += data;
  }
  Serial.println();

  uint8_t dataReadCRC = crc.calc();

  Serial.println("Files found:");
  std::vector<UFile> files = root.getFiles();
  // Print files
  for (UFile file : files) {
    Serial.print("[F] ");
    Serial.println(file.getPath());
  }

  Serial.println("Data read was " + dataRead + " with CRC value " + String(dataReadCRC));

}

void loop() {

}

Serial Monitor
---
Test Case ID: AUS_SPIS_FNBLFS_010
---
testContent value:Hello World!. With CRC value:28
testFilename value:256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256c.txt. With CRC value:182

Files found:
[F] /internal/
Data read was  with CRC value 0

Additional information

On the Renasas core (Portenta C33), the LittleFS driver sets the maximum character length to 255 characters via LFS_NAME_MAX.

// Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255
#endif

On the mbed core (Portenta H7), the LittleFS driver also sets the maximum character length to 255 characters via LFS_NAME_MAX.


// Max name size in bytes
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255
#endif

In both cases for both the mbed and Renasas core, a lfs_info structure adds an addtion byte LFS_NAME_MAX+1 to account for a null terminated string that corresponds to the test outcome.

@per1234 per1234 added topic: documentation Related to documentation for the project type: enhancement Proposed improvement labels Apr 25, 2024
@aliphys
Copy link
Member Author

aliphys commented Apr 29, 2024

LFS_NAME_MAX in Arduino implementations of LittleFS

Repo LFS_NAME_MAX value Location
arduino/mbed-os 255 storage/filesystem/littlefs/littlefs/lfs.h
arduino/ArduinoCore-renesas 255 extras/Filesystems/littlefs/lfs.h
arduino/ArduinoCore-mbed 255 cores/arduino/mbed/storage/filesystem/littlefs/littlefs/lfs.h

LFS_NAME_MAX in selected third party implementations of LittleFS

Repo LFS_NAME_MAX value Location
esp8266/Arduino 32 libraries/LittleFS/src/lfs.c
littlefs-project/littlefs 255 lfs.h
alibaba/AliOS-Things 255 components/littlefs/src/littlefs-v220/include/lfs.h
adafruit/Adafruit_nRF52_Arduino 255 libraries/Adafruit_LittleFS/src/littlefs/lfs.h
RAKWireless/RAK-nRF52-Arduino 255 libraries/Adafruit_LittleFS/src/littlefs/lfs.h

Additional context:

LFS_NAME_MAX only applies to filenames... There is no limit on the path length other then the RAM and storage you have on your device.

  • The esp8266/Arduino repo, is the only repo above which has a LFS_NAME_MAX value of less than 255.
  • While the LFS_NAME_MAX may be set to 255, build flags (-DLFS_NAME_MAX=XX) may modify this during compilation. For example, in adafruit/Adafruit_nRF52_Arduino we have
build.flags.nrf= -DSOFTDEVICE_PRESENT -DARDUINO_NRF52_ADAFRUIT -DNRF52_SERIES -DDX_CC_TEE -DLFS_NAME_MAX=64 {compiler.optimization_flag} {build.debug_flags} {build.logger_flags} {build.sysview_flags} {compiler.arm.cmsis.c.flags} "-I{nordic.path}" "-I{nordic.path}/nrfx" "-I{nordic.path}/nrfx/hal" "-I{nordic.path}/nrfx/mdk" "-I{nordic.path}/nrfx/soc" "-I{nordic.path}/nrfx/drivers/include" "-I{nordic.path}/nrfx/drivers/src" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include" "-I{nordic.path}/softdevice/{build.sd_name}_nrf52_{build.sd_version}_API/include/nrf52" "-I{rtos.path}/Source/include" "-I{rtos.path}/config" "-I{rtos.path}/portable/GCC/nrf52" "-I{rtos.path}/portable/CMSIS/nrf52" "-I{build.core.path}/sysview/SEGGER" "-I{build.core.path}/sysview/Config" "-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"
  • According to the Makefile for the mklittlefs utility - commonly used for building LittleFS images - the LFS_NAME_MAX value is overwritten to 32. This may create issues when interacting with images created with this tool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: documentation Related to documentation for the project type: enhancement Proposed improvement
Projects
None yet
Development

No branches or pull requests

3 participants