Skip to content

Commit

Permalink
Add time to dir entry (#215)
Browse files Browse the repository at this point in the history
* Add creation time to dir entry

* Update and publish fuse script

* Change boot offset in doc

* Change creation time into last modified time

* Add sort parameter to list command

* Add error for missing sort key

* Add shortcut params for sort
  • Loading branch information
vinc authored Jul 26, 2021
1 parent 1575b40 commit bbcfc66
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 51 deletions.
17 changes: 9 additions & 8 deletions doc/filesystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
A hard drive is separated in blocks of 512 bytes, grouped into 4 areas:

+------------+
| Boot | (2048 blocks)
| Boot | (4096 blocks)
+------------+
| Superblock | (2 blocks)
+------------+
Expand Down Expand Up @@ -103,16 +103,17 @@ Structure:
A directory entry represents a file or a directory contained inside a
directory. Each entry use a variable number of bytes that must fit inside the
data of one block. Those bytes represent the kind of entry (file or dir), the
address of the first block, the filesize (max 4GB), the length of the filename,
and the filename (max 255 chars) of the entry.
address of the first block, the filesize (max 4GB), the last modified time in
seconds since Unix Epoch, the length of the filename, and the filename (max
255 chars) of the entry.

Structure:

0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 m
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+
|k| addr | size |n| name buffer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 m
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+
|k| addr | size | time |n| name buffer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+

k = kind of entry
n = length of name buffer
Expand Down
110 changes: 110 additions & 0 deletions run/moros-fuse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python

from errno import ENOENT
from fuse import FUSE, FuseOSError, Operations, LoggingMixIn
from stat import S_IFDIR, S_IFREG

class MorosFuse(Operations):
chmod = None
chown = None
create = None
mkdir = None
readlink = None
rename = None
rmdir = None
symlink = None
truncate = None
unlink = None
utimens = None
write = None

def __init__(self, path):
self.image = open(path, "rb")
self.image_offset = 4096
self.block_size = 512
addr = self.image_offset * self.block_size
self.image.seek(addr)
block = self.image.read(self.block_size)

def destroy(self, path):
self.image.close()
return

def getattr(self, path, fh=None):
(kind, addr, size, time, name) = self.__scan(path)
if addr == 0:
raise FuseOSError(ENOENT)
mode = S_IFDIR | 0o755 if kind == 0 else S_IFREG | 0o644
return { "st_atime": 0, "st_mtime": time, "st_uid": 0, "st_gid": 0, "st_mode": mode, "st_size": size }

def read(self, path, size, offset, fh):
(kind, next_block_addr, size, time, name) = self.__scan(path)
res = b""
while next_block_addr != 0:
self.image.seek(next_block_addr)
next_block_addr = int.from_bytes(self.image.read(4), "big") * self.block_size
if offset < self.block_size - 4:
buf = self.image.read(min(self.block_size - 4, size))
res = b"".join([res, buf[offset:]])
offset = 0
else:
offset -= self.block_size - 4
size -= self.block_size - 4
return res

def readdir(self, path, fh):
files = [".", ".."]
(_, next_block_addr, _, _, _) = self.__scan(path)
while next_block_addr != 0:
self.image.seek(next_block_addr)
next_block_addr = int.from_bytes(self.image.read(4), "big")
offset = 4
while offset < self.block_size:
kind = int.from_bytes(self.image.read(1), "big")
addr = int.from_bytes(self.image.read(4), "big") * self.block_size
if addr == 0:
break
size = int.from_bytes(self.image.read(4), "big")
time = int.from_bytes(self.image.read(8), "big")
n = int.from_bytes(self.image.read(1), "big")
name = self.image.read(n).decode("utf-8")
offset += 1 + 4 + 4 + 8 + 1 + n
files.append(name)
return files

def __scan(self, path):
dirs = path[1:].split("/")
d = dirs.pop(0)
next_block_addr = (self.image_offset + 2 + self.block_size) * self.block_size
if d == "":
return (0, next_block_addr, 0, 0, d)
while next_block_addr != 0:
self.image.seek(next_block_addr)
next_block_addr = int.from_bytes(self.image.read(4), "big")
offset = 4
while offset < self.block_size:
kind = int.from_bytes(self.image.read(1), "big")
addr = int.from_bytes(self.image.read(4), "big") * self.block_size
if addr == 0:
break
size = int.from_bytes(self.image.read(4), "big")
time = int.from_bytes(self.image.read(8), "big")
n = int.from_bytes(self.image.read(1), "big")
name = self.image.read(n).decode("utf-8")
offset += 1 + 4 + 4 + 1 + n
if name == d:
if len(dirs) == 0:
return (kind, addr, size, time, name)
else:
next_block_addr = addr
d = dirs.pop(0)
break
return (0, 0, 0, 0, "")

if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('image')
parser.add_argument('mount')
args = parser.parse_args()
fuse = FUSE(MorosFuse(args.image), args.mount, ro=True, foreground=True, allow_other=True)
9 changes: 9 additions & 0 deletions run/moros-fuse.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

img="disk.img"
path="/tmp/moros"

# pip install fusepy
mkdir -p $path
echo "Mounting $img in $path"
python run/moros-fuse.py $img $path
1 change: 1 addition & 0 deletions src/api/console.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::sys;
use core::fmt;

#[derive(Clone, Copy)]
pub struct Style {
foreground: Option<usize>,
background: Option<usize>,
Expand Down
98 changes: 67 additions & 31 deletions src/sys/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub struct File {
name: String,
addr: u32,
size: u32,
time: u64,
dir: Dir, // TODO: Replace with `parent: Some(Dir)` and also add it to `Dir`
offset: u32,
}
Expand Down Expand Up @@ -192,7 +193,7 @@ impl File {
block.write();
}
self.size = self.offset;
self.dir.update_entry_size(&self.name, self.size);
self.dir.update_entry(&self.name, self.size);
Ok(bytes)
}

Expand Down Expand Up @@ -371,13 +372,14 @@ pub struct DirEntry {
kind: FileType,
addr: u32,
size: u32,
time: u64,
name: String,
}

impl DirEntry {
pub fn new(dir: Dir, kind: FileType, addr: u32, size: u32, name: &str) -> Self {
pub fn new(dir: Dir, kind: FileType, addr: u32, size: u32, time: u64, name: &str) -> Self {
let name = String::from(name);
Self { dir, kind, addr, size, name }
Self { dir, kind, addr, size, time, name }
}

pub fn is_dir(&self) -> bool {
Expand All @@ -392,6 +394,10 @@ impl DirEntry {
self.size
}

pub fn time(&self) -> u64 {
self.time
}

pub fn name(&self) -> String {
self.name.clone()
}
Expand All @@ -407,13 +413,14 @@ impl DirEntry {
name: self.name.clone(),
addr: self.addr,
size: self.size,
time: self.time,
dir: self.dir,
offset: 0,
}
}

pub fn len(&self) -> usize {
1 + 4 + 4 + 1 + self.name.len()
1 + 4 + 4 + 8 + 1 + self.name.len()
}
}

Expand Down Expand Up @@ -509,28 +516,37 @@ impl Dir {

let entry_kind = kind;
let entry_size = 0;
let entry_time = sys::clock::realtime() as u64;
let entry_addr = new_block.addr();
let entry_name = name.as_bytes();

let n = entry_name.len();
let i = read_dir.data_offset;
let data = read_dir.block.data_mut();
data[i + 0] = entry_kind as u8;
data[i + 1] = entry_addr.get_bits(24..32) as u8;
data[i + 2] = entry_addr.get_bits(16..24) as u8;
data[i + 3] = entry_addr.get_bits(8..16) as u8;
data[i + 4] = entry_addr.get_bits(0..8) as u8;
data[i + 5] = entry_size.get_bits(24..32) as u8;
data[i + 6] = entry_size.get_bits(16..24) as u8;
data[i + 7] = entry_size.get_bits(8..16) as u8;
data[i + 8] = entry_size.get_bits(0..8) as u8;
data[i + 9] = n as u8;
data[i + 0] = entry_kind as u8;
data[i + 1] = entry_addr.get_bits(24..32) as u8;
data[i + 2] = entry_addr.get_bits(16..24) as u8;
data[i + 3] = entry_addr.get_bits(8..16) as u8;
data[i + 4] = entry_addr.get_bits(0..8) as u8;
data[i + 5] = entry_size.get_bits(24..32) as u8;
data[i + 6] = entry_size.get_bits(16..24) as u8;
data[i + 7] = entry_size.get_bits(8..16) as u8;
data[i + 8] = entry_size.get_bits(0..8) as u8;
data[i + 9] = entry_time.get_bits(56..64) as u8;
data[i + 10] = entry_time.get_bits(48..56) as u8;
data[i + 11] = entry_time.get_bits(40..48) as u8;
data[i + 12] = entry_time.get_bits(32..40) as u8;
data[i + 13] = entry_time.get_bits(24..32) as u8;
data[i + 14] = entry_time.get_bits(16..24) as u8;
data[i + 15] = entry_time.get_bits(8..16) as u8;
data[i + 16] = entry_time.get_bits(0..8) as u8;
data[i + 17] = n as u8;
for j in 0..n {
data[i + 10 + j] = entry_name[j];
data[i + 18 + j] = entry_name[j];
}
read_dir.block.write();

Some(DirEntry::new(*self, kind, entry_addr, entry_size, name))
Some(DirEntry::new(*self, kind, entry_addr, entry_size, entry_time, name))
}

// Deleting an entry is done by setting the entry address to 0
Expand Down Expand Up @@ -564,16 +580,25 @@ impl Dir {
Err(())
}

fn update_entry_size(&mut self, name: &str, size: u32) {
fn update_entry(&mut self, name: &str, size: u32) {
let mut read_dir = self.read();
for entry in &mut read_dir {
if entry.name == name {
let time = sys::clock::realtime() as u64;
let data = read_dir.block.data_mut();
let i = read_dir.data_offset - entry.len();
data[i + 5] = size.get_bits(24..32) as u8;
data[i + 6] = size.get_bits(16..24) as u8;
data[i + 7] = size.get_bits(8..16) as u8;
data[i + 8] = size.get_bits(0..8) as u8;
data[i + 5] = size.get_bits(24..32) as u8;
data[i + 6] = size.get_bits(16..24) as u8;
data[i + 7] = size.get_bits(8..16) as u8;
data[i + 8] = size.get_bits(0..8) as u8;
data[i + 9] = time.get_bits(56..64) as u8;
data[i + 10] = time.get_bits(48..56) as u8;
data[i + 11] = time.get_bits(40..48) as u8;
data[i + 12] = time.get_bits(32..40) as u8;
data[i + 13] = time.get_bits(24..32) as u8;
data[i + 14] = time.get_bits(16..24) as u8;
data[i + 15] = time.get_bits(8..16) as u8;
data[i + 16] = time.get_bits(0..8) as u8;
read_dir.block.write();
break;
}
Expand Down Expand Up @@ -624,15 +649,26 @@ impl Iterator for ReadDir {
1 => FileType::File,
_ => break,
};
let entry_addr = (data[i + 1] as u32) << 24
| (data[i + 2] as u32) << 16
| (data[i + 3] as u32) << 8
| (data[i + 4] as u32);
let entry_size = (data[i + 5] as u32) << 24
| (data[i + 6] as u32) << 16
| (data[i + 7] as u32) << 8
| (data[i + 8] as u32);
i += 9;

let entry_addr = (data[i + 1] as u32) << 24
| (data[i + 2] as u32) << 16
| (data[i + 3] as u32) << 8
| (data[i + 4] as u32);

let entry_size = (data[i + 5] as u32) << 24
| (data[i + 6] as u32) << 16
| (data[i + 7] as u32) << 8
| (data[i + 8] as u32);

let entry_time = (data[i + 9] as u64) << 56
| (data[i + 10] as u64) << 48
| (data[i + 11] as u64) << 40
| (data[i + 12] as u64) << 32
| (data[i + 13] as u64) << 24
| (data[i + 14] as u64) << 16
| (data[i + 15] as u64) << 8
| (data[i + 16] as u64);
i += 17;

let mut n = data[i];
if n == 0 || n as usize >= data.len() - i {
Expand All @@ -658,7 +694,7 @@ impl Iterator for ReadDir {
continue;
}

return Some(DirEntry::new(self.dir, entry_kind, entry_addr, entry_size, &entry_name));
return Some(DirEntry::new(self.dir, entry_kind, entry_addr, entry_size, entry_time, &entry_name));
}

match self.block.next() {
Expand Down
Loading

0 comments on commit bbcfc66

Please sign in to comment.