littlefs-project / littlefs

A little fail-safe filesystem designed for microcontrollers
BSD 3-Clause "New" or "Revised" License
4.92k stars 774 forks source link

Can I set the time with the lfs_setattr function and see the time on windows #879

Closed Johnxjj closed 8 months ago

geky commented 9 months ago

Hi @Johnxjj, this depends on the Windows driver, what Windows driver are you using?

The is the intention of lfs_setattr, but littlefs hasn't committed to any standard custom attributes yet. (In theory not hard, but easy to make mistakes that stick around forever). So at the moment it's up to the library/driver to decide the custom attribute mapping and encoding and if they want to store timestamps in a custom attribute.

Johnxjj commented 9 months ago

Hi, @geky, I guess you may have understood me wrong, I intended to use it on an embedded device and then extract it to view on windows, Like running log files for embedded devices.

Johnxjj commented 9 months ago

I used the rt-thread vfat filesystem earlier, which is able to extract to windows and check the time. Currently I want to use the littlefs filesystem and also be able to check the time on the window.

Johnxjj commented 9 months ago

I uploaded logs to the cloud on the embedded device, and then downloaded files from the cloud to the window.

geky commented 9 months ago

Hmm, I think this depends on the library that is uploading the files to the cloud.

littlefs's custom attributes are nothing more than typed arrays of bytes. You can use them to store timestamps, but it's up to the upload-layer to convert what you store to timestamps on the Window's filesystem.


If you control that layer, it's possible. It's just up to you to decide what exact encoding to use.

If you want to store timestamps as 64-bit integers (to avoid year 2038 problems), you can use lfs_setattr/lfs_getattr on a file path like so:

// this is arbitrary, choose a new 8-bit number for each custom attribute
#define MY_ATTR_TIMESTAMP 0

// little-endian encoding/decoding functions
static inline uint64_t lfs_fromle64(uint64_t a) {
    return    (((uint8_t*)&a)[0] <<  0)
            | (((uint8_t*)&a)[1] <<  8)
            | (((uint8_t*)&a)[2] << 16)
            | (((uint8_t*)&a)[3] << 24)
            | (((uint8_t*)&a)[4] << 32)
            | (((uint8_t*)&a)[5] << 40)
            | (((uint8_t*)&a)[6] << 48)
            | (((uint8_t*)&a)[7] << 56);
}

static inline uint64_t tole64(uint32_t a) {
    return fromle642(a);
}
// store a timestamp on a file
uint64_t timestamp = my_gettime64();
timestamp = lfs_tole64(timestamp);
int err = lfs_setattr(&lfs, "my_file",
        MY_ATTR_TIMESTAMP, &timestamp, sizeof(uint64_t));
if (err) {
    return err;
}
// get a timestamp on a file
uint64_t timestamp;
lfs_ssize_t size = lfs_setattr(&lfs, "my_file",
        MY_ATTR_TIMESTAMP, &timestamp, sizeof(uint64_t));
if (size < 0 && size != LFS_ERR_NOATTR) {
    return size;
}
if (size == LFS_ERR_NOATTR || size != sizeof(uint64_t)) {
    // maybe assume arbitrary timestamp if missing?
    timestamp = 0;
}
timestamp = lfs_fromle64(timestamp);

Alternatively, littlefs has APIs that let you update/read custom attributes at the same time you open/close files, though these get a bit messy:

uint64_t timestamp;
struct lfs_attr attrs[1] = {
    {MY_ATTR_TIMESTAMP, &timestamp, sizeof(uint64_t)}
};

struct lfs_file_config file_cfg = {
    .attrs = attrs,
    .attr_count = 1,
};
lfs_file_t file;
int err = lfs_file_opencfg(&lfs, &file, "my_file", LFS_O_WRONLY | LFS_CREAT);
if (err) {
    return err;
}

// write to file, etc...

// update timestamp before syncing file
timestamp = my_gettime64();
timestamp = lfs_tole64(timestamp);
err = lfs_file_close(&lfs, &file);
if (err) {
    return err;
}
uint64_t timestamp;
struct lfs_attr attrs[1] = {
    {MY_ATTR_TIMESTAMP, &timestamp, sizeof(uint64_t)}
};

struct lfs_file_config file_cfg = {
    .attrs = attrs,
    .attr_count = 1,
};
lfs_file_t file;
int err = lfs_file_opencfg(&lfs, &file, "my_file", LFS_O_RDONLY);
if (err) {
    return err;
}

uint64_t timestamp_ = lfs_fromle64(timestamp);
printf("last timestamp: %lld\n", timestamp_);

err = lfs_file_close(&lfs, &file);
if (err) {
    return err;
}
Johnxjj commented 9 months ago

Thank you very much for your reply. Now I have the idea. I missed something before. Before upload to the cloud, it is transmitted from MCU to MPU through YMODE protocol, and then uploaded to the cloud from MPU.

Johnxjj commented 9 months ago

YMODE protocol, will first transfer the attributes of the file, through the stat function to obtain the modification time, and then transfer in the past, and littlefs stat function may not have this related function, need additional by setting the attribute function to convert.