Sherlock-Holo / fuse3

an async version fuse library for rust
MIT License
83 stars 17 forks source link

Use Timespec instead of SystemTime in raw::reply::FileAttr #6

Closed asomers closed 3 years ago

asomers commented 3 years ago

std::time::SystemTime may be convenient for passthrough file systems, where the time will come from std::fs::Metadata already in that format. But it's not so convenient for raw file systems. Raw file systems more likely store the timestamps in a serialized format. Converting between serialized timestamps and SystemTime requires needless comparisons with UNIX_EPOCH. It would be more convenient if raw::reply::FileAttr used libc::timespec, which is pretty close to what the FUSE protocol wants anyway.

asomers commented 3 years ago

Actually, the problem is worse than I initially thought. Currently, fuse3 does not allow a raw file system to express a timestamp older than the Epoch. Since Duration is always positive, the code in fuse_attr::from in raw/reply.rs, line 63, will change all negative timestamps into 0.

BTW, even thought the FUSE ABI uses unsigned numbers everywhere, the seconds fields are actually signed. The ABI is just defined wrong. The get cast to signed time_t in C.

Sherlock-Holo commented 3 years ago

there must be some files are earlier than 1970-1-1, so provide a way to create a timestamp that is earlier than Epoch is a good idea. However, limited by the Linux fuse protocol, we can't mount an fs and it contains a file which creation time is earlier than Epoch. Maybe we should document it on the new struct Timestamp

asomers commented 3 years ago

Sure, it's possible to have a FUSE-mounted file with timestamps older than the Epoch. The kernel header is just kind of wrong. The unsigned timestamp fields in struct fuse_attr are actually treated as signed by the kernel.

struct fuse_attr {
    uint64_t    ino;
    uint64_t    size;
    uint64_t    blocks;
    uint64_t    atime;
    uint64_t    mtime;
    uint64_t    ctime;
    uint32_t    atimensec;
    uint32_t    mtimensec;
    uint32_t    ctimensec;
    uint32_t    mode;
    uint32_t    nlink;
    uint32_t    uid;
    uint32_t    gid;
    uint32_t    rdev;
    uint32_t    blksize;
    uint32_t    padding;
};