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

fs::read_dir doesn't work. #94

Closed
MitchellMarinoDev opened this issue May 17, 2022 · 1 comment
Closed

fs::read_dir doesn't work. #94

MitchellMarinoDev opened this issue May 17, 2022 · 1 comment

Comments

@MitchellMarinoDev
Copy link

When using std::fs::read_dir to try to iterate through a spiffs mounted directory, It gives the correct number of entries but all are wrong. The file name is always an empty string, and the file.metadata() is always Err("No such file or directory (os error 2)").
Spiffs mounts fine, the files do exist and I can read and write to them, I only have issues when trying to use std::fs::read_dir.

ESP32. ESP-WROOM-32

Partition Table:

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,    Size,    Flags
nvs,      data, nvs,     0x9000,   0x6000,
phy_init, data, phy,     0xf000,   0x1000,
factory,  app,  factory, 0x10000,  1M,
spiffs,    data, spiffs,   0x110000, 1M,

Code:

use esp_idf_sys; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use esp_idf_sys::c_types::c_char;
use std::ffi::CString;
use std::fs;
use std::fs::File;
use std::io::Write;

fn main() {
    // Temporary. Will disappear once ESP-IDF 4.4 is released, but for now it is necessary to call this function once,
    // or else some patches to the runtime implemented by esp-idf-sys might not link properly.
    esp_idf_sys::link_patches();

    // Initializes the spiffs and mounts it to "/fs".
    init_spiffs(Some("spiffs"), "/fs");

    // Formats the spiffs.
    format_spiffs(Some("spiffs"));

    // Create two test files.
    let mut f = File::create("/fs/test-file-1.txt").unwrap();
    write!(f, "test file 1").unwrap();
    drop(f);
    let mut f = File::create("/fs/test-file-2.txt").unwrap();
    write!(f, "test file 2").unwrap();
    drop(f);

    let path = "/fs";
    println!("Iterating through dir.");
    // This will yield entries for all files with the file name "" regardless of their actual file name.
    // This also yields an extra io error after all the files.
    for entry in fs::read_dir(path).unwrap() {
        println!("entry: {:?}", entry);
        if let Ok(entry) = entry {
            // Always prints `File: ""`
            println!("File: {:?}", entry.file_name());
            // Metadata always Err
            println!("Metadata: {}", entry.metadata().unwrap_err());
        }
    }
}

/// Initializes the SPI Flash File System (SPIFFS).
///
/// - `label` is the name of the partition containing the spiffs. If None, gets the first spiffs
/// partition. ex. "fs"
/// - `mount` is the mount location of the spiffs to the virtual file system. ex. "/fs".
pub fn init_spiffs(label: Option<&str>, mount: &str) {
    const MAX_FILES: u32 = 255;
    const NULL: *const c_char = 0 as _;

    // Create a CString from the label slice (or null if None).
    let c_label = label.map(|l| CString::new(l.as_bytes().to_vec()).unwrap());

    let label_ptr = match c_label {
        None => NULL,
        Some(ref l) => l.as_ptr(),
    };

    // Create a CString from the mount slice
    let c_mnt = CString::new(mount.as_bytes().to_vec()).unwrap();
    let mnt_ptr = c_mnt.as_ptr();

    // Create config
    let conf = esp_idf_sys::esp_vfs_spiffs_conf_t {
        base_path: mnt_ptr,
        partition_label: label_ptr,
        max_files: MAX_FILES,
        format_if_mount_failed: true,
    };

    let err;
    unsafe {
        // Initializes the SPIFFS to a virtual file system.
        err = esp_idf_sys::esp_vfs_spiffs_register(
            &conf as *const esp_idf_sys::esp_vfs_spiffs_conf_t,
        );
    }
    // Make sure the CStrings outlives the FFI call.
    drop((conf, c_label, c_mnt));

    handle_esp_err("SPIFFS mount", err);
}

/// Initializes the SPI Flash File System (SPIFFS).
///
/// - `label` is the name of the partition containing the spiffs. If None, gets the first spiffs
/// partition. ex. "fs"
/// - `mount` is the mount location of the spiffs to the virtual file system. ex. "/fs".
pub fn format_spiffs(label: Option<&str>) {
    const NULL: *const c_char = 0 as _;

    // Create a CString from the label slice (or null if None).
    let c_label = label.map(|l| CString::new(l.as_bytes().to_vec()).unwrap());

    let label_ptr = match c_label {
        None => NULL,
        Some(ref l) => l.as_ptr(),
    };

    let err;
    unsafe {
        err = esp_idf_sys::esp_spiffs_format(label_ptr);
    }
    // Make sure the CString outlives the FFI call.
    drop(c_label);

    handle_esp_err("SPIFFS format", err);
}

/// Handles an esp error by printing to console.
///
/// Returns whether there was an error.
fn handle_esp_err(operation: &str, err: i32) -> bool {
    use esp_idf_sys::{ESP_ERR_INVALID_STATE, ESP_ERR_NOT_FOUND, ESP_ERR_NO_MEM, ESP_FAIL, ESP_OK};

    if err == ESP_OK {
        println!("{operation} OK.");
        return false;
    }

    let e_msg = match err {
        ESP_ERR_INVALID_STATE => Some("Invalid state"),
        ESP_ERR_NO_MEM => Some("No memory"),
        ESP_ERR_NOT_FOUND => Some("Not found"),
        ESP_FAIL => Some("ESP fail"),
        _ => None,
    };

    if let Some(e_msg) = e_msg {
        println!("ERROR: {operation} FAILED with code {err} ({e_msg}).");
    } else {
        println!(
            "ERROR: {operation} FAILED with code {err} (Unrecognized error).
ERR ENUM VALUES:
{ESP_OK}\tESP_OK
{ESP_ERR_NO_MEM}\tESP_ERR_NO_MEM
{ESP_ERR_INVALID_STATE}\tESP_ERR_INVALID_STATE
{ESP_ERR_NOT_FOUND}\tESP_ERR_NOT_FOUND
{ESP_FAIL}\tESP_FAIL"
        );
    }

    true
}

Terminal output:

� �ets Jun  8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0048,len:12
ho 0 tail 12 room 4
load:0x3fff0054,len:4800
load:0x40078000 [__udivmoddi4:??:??],len:17448
load:0x4007c428 [__udivmoddi4:??:??],len:4840
entry 0x4007c6a0 [__udivmoddi4:??:??]
I (141) cpu_start: Pro cpu up.
I (142) cpu_start: Starting app cpu, entry point is 0x40081234 [call_start_cpu1:/home/mitchell/rust/esp-read-dir-issue/.embuild/espressif/esp-idf/v4.3.2/components/esp_system/port/cpu_start.c:150]
I (0) cpu_start: App cpu up.
I (156) cpu_start: Pro cpu start user code
I (156) cpu_start: cpu freq: 160000000
I (156) cpu_start: Application information:
I (160) cpu_start: Project name:     libespidf
I (165) cpu_start: App version:      1
I (170) cpu_start: Compile time:     May 16 2022 20:26:17
I (176) cpu_start: ELF file SHA256:  0000000000000000...
I (182) cpu_start: ESP-IDF:          v4.3.2-dirty
I (188) heap_init: Initializing. RAM available for dynamic allocation:
I (195) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (201) heap_init: At 3FFB3490 len 0002CB70 (178 KiB): DRAM
I (207) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (213) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (220) heap_init: At 4008B754 len 000148AC (82 KiB): IRAM
I (227) spi_flash: detected chip: generic
I (231) spi_flash: flash io: dio
I (236) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
SPIFFS mount OK.
SPIFFS format OK.
Iterating through dir.
entry: Ok(DirEntry("/fs/"))
File: ""
Metadata: No such file or directory (os error 2)
entry: Ok(DirEntry("/fs/"))
File: ""
Metadata: No such file or directory (os error 2)
entry: Err(Os { code: 5, kind: Uncategorized, message: "I/O error" })
@MabezDev
Copy link
Member

Duplicate of esp-rs/rust#117. Thanks for the extra info though, I'm just about to start looking into this - should come in handy :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants