diff options
Diffstat (limited to 'bfs/file.ha')
| -rw-r--r-- | bfs/file.ha | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/bfs/file.ha b/bfs/file.ha new file mode 100644 index 0000000..b8f91cb --- /dev/null +++ b/bfs/file.ha @@ -0,0 +1,172 @@ +use io; + +// BFS file's implementation of stream +const file_impl: io::vtable = io::vtable { + writer = &file_write, + reader = &file_read, + ... +}; + +// BFS file +export type file = struct { + // File implements stream trait + stream_trait: io::stream, + + // Filesystem that underlies the file + fs: *bfs, + + // Inode ID associated with file + inid: u64, + + // Inode associated with file (owned) + in: *inode, + + // Seeking offset in BFS file + off: io::off, + + // Block IDs of the successive pages leading to + // the resolution of the file content at specified index + page_addrs: [16]u64, + + // Indices of entry in each of the successive pages + page_idxs: [16]u64 +}; + +fn file_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { + return io::EOF; +}; + +fn file_write(s: *io::stream, buf: const []u8) (size | io::error) = { + return 0z; +}; + +fn file_seek(s: *io::stream, off: io::off, w: io::whence) (io::off | io::error) = { + let file = s: *file; + + switch (w) { + case io::whence::SET => + file.off = off; + case io::whence::CUR => + file.off += off; + case io::whence::END => + file.off = file.in.length: io::off + off; + }; + + return file.off; +}; + +// Builds the indices to reach an address +export fn file_mkindices(self: *file, off: u64) size = { + const endshift = self.fs.bootsector.blocksize; + const pageshift = endshift - 3; + + const endmask = masklsb(pageshift); + const pagemask = endmask >> pageshift; + + self.page_idxs[0] = off & endmask; + off >>= endshift; + + let different = 0z; + + for (let i = 1z; i < len(self.page_idxs); i += 1) { + const idx = off & pagemask; + off >> pageshift; + + if (self.page_idxs[i] != idx) + different = i; + }; + + return different; +}; + +// Translate a file offset into a device offset +export fn file_translate(self: *file, off: u64) (u64 | error | io::error) = { + // Calculate the indices + const different = file_mkindices(self, off); + + // Calculate the level implied by given address + let level = 0u8; + for (let i = 0u8; i < 16; i += 1) + if (self.page_idxs[i] != 0) + level = i; + + // If it is higher than map level of inode, miss + if (level > self.in.map_levels) + return filehole; + + // Set the level address to be the base + self.page_addrs[self.in.map_levels] = self.in.block; + + // DEBUG: + const different = self.in.map_levels; + + // Resolve every successive page from + // the highest changed index in the address + const sz = exp2(self.fs.bootsector.blocksize); + let next = self.page_addrs[different]; + + for (let i = different; i > 0; i -= 1) { + self.page_addrs[i] = next; + + const loc = next * sz + self.page_idxs[i]*8; + pread(self.fs.device, &next: *[8]u8, loc: io::off)?; + + if (next == 0) + return filehole; + }; + + if (next == 0) + return filehole; + + // Set the block id of final page + self.page_addrs[0] = next; + + // Finally, return the offset in terms of physical + // address + return next * sz + self.page_idxs[0]; +}; + +export fn file_map(self: *file, off: u64) (void | error | io::error) = { + file_mkindices(self, off); + let level = 0u8; + for (let i = 0u8; i < 16; i += 1) + if (self.page_idxs[i] != 0) + level = i; + + // Add as many paging levels as necessary + for (let i = level; i < self.in.map_levels; i += 1) + file_levelup(self)!; +}; + +// Increment the level of pages used to address +// file contents by one +export fn file_levelup(self: *file) (void | io::error) = { + // Allocate new base block + const base = allocblock(self.fs)?; + + // Write the address of previous base + // as first entry of new base block + const sz = exp2(self.fs.bootsector.blocksize); + pwrite(self.fs.device, &self.page_addrs[self.in.map_levels]: *[8]u8, (base * sz): io::off)!; + + // Update inode + self.in.block = base; + self.in.map_levels += 1; + setinode(self.fs, self.inid, self.in)!; +}; + +// Decrement the amount of pages used to address +// file contents by one +export fn file_leveldown(self: *file) (void | io::error) = { + return; +}; + +// Return 1 << n +fn exp2(n: uint) uint = { + return 1u << n; +}; + +// Create a mask with the n least significant bits on +fn masklsb(n: u64) u64 = { + return ~(-1i64 << n: i64): u64; +}; |
