diff --git a/mkfs/main.rs b/mkfs/main.rs index 738a07edf26410351c3a2fcd3eb806c2dafcf815..e0f6f00b04089b4bc069cadf175ccd5205da372c 100644 --- a/mkfs/main.rs +++ b/mkfs/main.rs @@ -3,7 +3,7 @@ extern crate redoxfs; extern crate syscall; -use std::{env, process, str}; +use std::{env, process, str, time}; use redoxfs::FileSystem; @@ -14,9 +14,11 @@ pub mod image; fn main() { let mut args = env::args(); if let Some(path) = args.nth(1) { + let ctime = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap(); + //Open an existing image match Image::open(&path) { - Ok(disk) => match FileSystem::create(Box::new(disk)) { + Ok(disk) => match FileSystem::create(Box::new(disk), ctime.as_secs(), ctime.subsec_nanos()) { Ok(filesystem) => { println!("redoxfs-mkfs: created filesystem on {}, size {} MB", path, filesystem.header.1.size/1024/1024); }, diff --git a/mount/fuse.rs b/mount/fuse.rs index b51fe77cda0318863ff53e7c9ac6e1d68b8b3b1f..69cf53a1dca948b39dd59d616827438e07034510 100644 --- a/mount/fuse.rs +++ b/mount/fuse.rs @@ -4,6 +4,7 @@ extern crate time; use redoxfs; use std::path::Path; use std::os::unix::ffi::OsStrExt; +use std::time::{SystemTime, UNIX_EPOCH}; use self::fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyCreate, ReplyDirectory, ReplyEmpty, ReplyStatfs, ReplyWrite}; use self::time::Timespec; @@ -12,7 +13,7 @@ pub use self::fuse::mount; const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second -const CREATE_TIME: Timespec = Timespec { sec: 0, nsec: 0 }; +const NULL_TIME: Timespec = Timespec { sec: 0, nsec: 0 }; pub struct Fuse { pub fs: redoxfs::FileSystem, @@ -23,10 +24,16 @@ fn node_attr(node: &(u64, redoxfs::Node)) -> FileAttr { ino: node.0, size: node.1.extents[0].length, blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, + atime: NULL_TIME, + mtime: Timespec { + sec: node.1.mtime as i64, + nsec: node.1.mtime_nsec as i32, + }, + ctime: Timespec { + sec: node.1.ctime as i64, + nsec: node.1.ctime_nsec as i32, + }, + crtime: NULL_TIME, kind: if node.1.is_dir() { FileType::Directory } else if node.1.is_symlink() { @@ -68,7 +75,7 @@ impl Filesystem for Fuse { fn setattr(&mut self, _req: &Request, block: u64, mode: Option<u32>, uid: Option<u32>, gid: Option<u32>, size: Option<u64>, - _atime: Option<Timespec>, _mtime: Option<Timespec>, _fh: Option<u64>, + _atime: Option<Timespec>, mtime: Option<Timespec>, _fh: Option<u64>, _crtime: Option<Timespec>, _chgtime: Option<Timespec>, _bkuptime: Option<Timespec>, _flags: Option<u32>, reply: ReplyAttr) { if let Some(mode) = mode { @@ -127,6 +134,23 @@ impl Filesystem for Fuse { } } + if let Some(mtime) = mtime { + match self.fs.node(block) { + Ok(mut node) => if mtime.sec as u64 > node.1.mtime || (mtime.sec as u64 == node.1.mtime && mtime.nsec as u32 > node.1.mtime_nsec) { + node.1.mtime = mtime.sec as u64; + node.1.mtime_nsec = mtime.nsec as u32; + if let Err(err) = self.fs.write_at(node.0, &node.1) { + reply.error(err.errno as i32); + return; + } + }, + Err(err) => { + reply.error(err.errno as i32); + return; + } + } + } + match self.fs.node(block) { Ok(node) => { reply.attr(&TTL, &node_attr(&node)); @@ -150,7 +174,8 @@ impl Filesystem for Fuse { } fn write(&mut self, _req: &Request, block: u64, _fh: u64, offset: u64, data: &[u8], _flags: u32, reply: ReplyWrite) { - match self.fs.write_node(block, offset, &data) { + let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + match self.fs.write_node(block, offset, &data, mtime.as_secs(), mtime.subsec_nanos()) { Ok(count) => { reply.written(count as u32); }, @@ -196,7 +221,8 @@ impl Filesystem for Fuse { } fn create(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, flags: u32, reply: ReplyCreate) { - match self.fs.create_node(redoxfs::Node::MODE_FILE | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { + let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + match self.fs.create_node(redoxfs::Node::MODE_FILE | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block, ctime.as_secs(), ctime.subsec_nanos()) { Ok(node) => { // println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.created(&TTL, &node_attr(&node), 0, 0, flags); @@ -208,7 +234,8 @@ impl Filesystem for Fuse { } fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, reply: ReplyEntry) { - match self.fs.create_node(redoxfs::Node::MODE_DIR | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { + let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + match self.fs.create_node(redoxfs::Node::MODE_DIR | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block, ctime.as_secs(), ctime.subsec_nanos()) { Ok(node) => { // println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.entry(&TTL, &node_attr(&node), 0); @@ -257,9 +284,11 @@ impl Filesystem for Fuse { } fn symlink(&mut self, _req: &Request, parent_block: u64, name: &Path, link: &Path, reply: ReplyEntry) { - match self.fs.create_node(redoxfs::Node::MODE_SYMLINK | 0o777, name.to_str().unwrap(), parent_block) { + let ctime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + match self.fs.create_node(redoxfs::Node::MODE_SYMLINK | 0o777, name.to_str().unwrap(), parent_block, ctime.as_secs(), ctime.subsec_nanos()) { Ok(node) => { - match self.fs.write_node(node.0, 0, link.as_os_str().as_bytes()) { + let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + match self.fs.write_node(node.0, 0, link.as_os_str().as_bytes(), mtime.as_secs(), mtime.subsec_nanos()) { Ok(_count) => { reply.entry(&TTL, &node_attr(&node), 0); }, diff --git a/src/filesystem.rs b/src/filesystem.rs index c4ca2a7be365ded803d5699f51b93fe7e47063cb..38408f4df706471899d7b29f58ba10262e3a959c 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -37,15 +37,15 @@ impl FileSystem { } /// Create a file system on a disk - pub fn create(mut disk: Box<Disk>) -> Result<Self> { + pub fn create(mut disk: Box<Disk>, ctime: u64, ctime_nsec: u32) -> Result<Self> { let size = disk.size()?; if size >= 4 * 512 { - let mut free = (2, Node::new(Node::MODE_FILE, "free", 0)); + let mut free = (2, Node::new(Node::MODE_FILE, "free", 0, ctime, ctime_nsec)); free.1.extents[0] = Extent::new(4, size - 4 * 512); disk.write_at(free.0, &free.1)?; - let root = (1, Node::new(Node::MODE_DIR | 0o755, "root", 0)); + let root = (1, Node::new(Node::MODE_DIR | 0o755, "root", 0, ctime, ctime_nsec)); disk.write_at(root.0, &root.1)?; let header = (0, Header::new(size, root.0, free.0)); @@ -194,11 +194,11 @@ impl FileSystem { } } - pub fn create_node(&mut self, mode: u16, name: &str, parent_block: u64) -> Result<(u64, Node)> { + pub fn create_node(&mut self, mode: u16, name: &str, parent_block: u64, ctime: u64, ctime_nsec: u32) -> Result<(u64, Node)> { if self.find_node(name, parent_block).is_ok() { Err(Error::new(EEXIST)) } else { - let node = (self.allocate(1)?, Node::new(mode, name, parent_block)); + let node = (self.allocate(1)?, Node::new(mode, name, parent_block, ctime, ctime_nsec)); self.write_at(node.0, &node.1)?; self.insert_blocks(node.0, 512, parent_block)?; @@ -276,6 +276,7 @@ impl FileSystem { } } + // TODO: modification time fn node_ensure_len(&mut self, block: u64, mut length: u64) -> Result<()> { if block == 0 { return Err(Error::new(ENOENT)); @@ -319,6 +320,7 @@ impl FileSystem { } } + //TODO: modification time pub fn node_set_len(&mut self, block: u64, mut length: u64) -> Result<()> { if block == 0 { return Err(Error::new(ENOENT)); @@ -450,7 +452,7 @@ impl FileSystem { Ok(i) } - pub fn write_node(&mut self, block: u64, offset: u64, buf: &[u8]) -> Result<usize> { + pub fn write_node(&mut self, block: u64, offset: u64, buf: &[u8], mtime: u64, mtime_nsec: u32) -> Result<usize> { let block_offset = offset / 512; let mut byte_offset = (offset % 512) as usize; @@ -512,6 +514,15 @@ impl FileSystem { assert_eq!(block, extent.block + (extent.length + 511)/512); } + if i > 0 { + let mut node = self.node(block)?; + if mtime > node.1.mtime || (mtime == node.1.mtime && mtime_nsec > node.1.mtime_nsec) { + node.1.mtime = mtime; + node.1.mtime_nsec = mtime_nsec; + self.write_at(node.0, &node.1)?; + } + } + Ok(i) } diff --git a/src/header.rs b/src/header.rs index 589339a00b02ff00635ca932c7e89a6c82eef6d8..82ce62f9b6ad1cd70613cd4b0d1a7ad31f836832 100644 --- a/src/header.rs +++ b/src/header.rs @@ -22,7 +22,7 @@ pub struct Header { impl Header { pub const SIGNATURE: &'static [u8; 8] = b"RedoxFS\0"; - pub const VERSION: u64 = 1; + pub const VERSION: u64 = 2; pub fn default() -> Header { Header { diff --git a/src/node.rs b/src/node.rs index a6ecaf6caf69a5c72467821faa4a81a3372ff400..58e426d0898147328ce6a2646d83b9a946e0fec9 100644 --- a/src/node.rs +++ b/src/node.rs @@ -8,7 +8,11 @@ pub struct Node { pub mode: u16, pub uid: u32, pub gid: u32, - pub name: [u8; 246], + pub ctime: u64, + pub ctime_nsec: u32, + pub mtime: u64, + pub mtime_nsec: u32, + pub name: [u8; 222], pub parent: u64, pub next: u64, pub extents: [Extent; 15], @@ -30,15 +34,19 @@ impl Node { mode: 0, uid: 0, gid: 0, - name: [0; 246], + ctime: 0, + ctime_nsec: 0, + mtime: 0, + mtime_nsec: 0, + name: [0; 222], parent: 0, next: 0, extents: [Extent::default(); 15], } } - pub fn new(mode: u16, name: &str, parent: u64) -> Node { - let mut bytes = [0; 246]; + pub fn new(mode: u16, name: &str, parent: u64, ctime: u64, ctime_nsec: u32) -> Node { + let mut bytes = [0; 222]; for (mut b, c) in bytes.iter_mut().zip(name.bytes()) { *b = c; } @@ -47,6 +55,10 @@ impl Node { mode: mode, uid: 0, gid: 0, + ctime: ctime, + ctime_nsec: ctime_nsec, + mtime: ctime, + mtime_nsec: ctime_nsec, name: bytes, parent: parent, next: 0, @@ -105,6 +117,10 @@ impl fmt::Debug for Node { .field("mode", &self.mode) .field("uid", &self.uid) .field("gid", &self.gid) + .field("ctime", &self.ctime) + .field("ctime_nsec", &self.ctime_nsec) + .field("mtime", &self.mtime) + .field("mtime_nsec", &self.mtime_nsec) .field("name", &self.name()) .field("next", &self.next) .field("extents", &extents)