/..

#CONTENT

#TOP

fs.zig
RS
const std = @import("std");
const disk = @import("disk.zig");
const term = @import("term.zig");
const fs = @import("extended/fs.zig");
const mem = std.mem;
const Allocator = mem.Allocator;
const Parameters = fs.Parameters;

var parameters: Parameters = undefined;
var relative: usize = undefined;
var manager: Allocator = undefined;
var files: std.StringHashMap(*File) = undefined;

pub fn init(allocator: Allocator) void {
    parameters = @intToPtr(*Parameters, 0x7C00).*;

    var total_sectors = @as(u32, parameters.total_sectors16);
    if (total_sectors == 0) {
        total_sectors = parameters.total_sectors32;
    }
    var fat_size = parameters.extended32().table_size32;

    var first_data_sector = parameters.reserved_sectors + (parameters.fat_count * fat_size);
    var data_sectors = total_sectors - (parameters.reserved_sectors + parameters.fat_count * fat_size);

    relative = first_data_sector + data_sectors;
    manager = allocator;
    files = std.StringHashMap(*File).init(allocator);

    term.printf("first availible sector: {}\r\n", .{relative});
}

pub fn new(name: []const u8, size: usize) !*File {
    var file = try manager.create(File);
    try file.init(name, size);
    try files.put(name, file);
    return file;
}

pub fn open(name: []const u8) !*File {
    var file = files.get(name) orelse {
        term.printf("file `{s}` does not exist\r\n", .{name});
        return std.os.AcceptError.FileNotFound;
    };
    return file;
}

pub const File = struct {
    name: []const u8,
    cache: [512]u8,
    sector: usize,
    size: usize,
    offset: usize,

    const Self = @This();

    pub fn init(self: *Self, name: []const u8, size: usize) !void {
        const sectors = (size + 511 & ~@as(usize, 511)) / 512;

        defer self.name = name;
        self.sector = relative;
        self.size = size;
        self.offset = 0;

        try disk.read(self.sector, self.view());
        relative += sectors;
    }

    fn die(err: anyerror) void {
        term.printf("disk error: {s}\r\n", .{@errorName(err)});
    }

    pub fn write(self: *Self, buffer: []u8) !void {
        if (self.offset + buffer.len >= self.size) {
            return std.os.AccessError.InputTooLong;
        }

        var result = self.offset + buffer.len;
        defer self.offset = result;
        defer self.reload() catch |err| die(err);

        try disk.write(self.sector + self.offset / 512, @ptrCast([*]align(1) u16, buffer)[0 .. buffer.len / 2]);
    }

    pub fn seek(self: *Self, offset: usize) !void {
        if (offset >= self.size) {
            return std.os.AccessError.InputTooLong;
        }
        self.offset = offset;
        try self.reload();
    }

    pub fn peek(self: *Self) u8 {
        if (self.offset >= self.size) {
            return 0;
        }

        const ch = self.cache[self.offset % 512];
        return ch;
    }

    pub fn getchar(self: *Self) u8 {
        if (self.offset >= self.size) {
            return 0;
        }

        const ch = self.cache[self.offset % 512];
        self.offset += 1;
        if (self.offset % 512 == 0) {
            self.reload() catch |err| die(err);
        }
        return ch;
    }

    pub fn putback(self: *Self, ch: u8) void {
        _ = ch;
        if (self.offset > 0) {
            self.offset -= 1;
        }
        if (self.offset % 512 == 511) {
            self.reload() catch |err| die(err);
        }
    }

    fn view(self: *Self) []align(1) u16 {
        return @ptrCast([*]align(1) u16, &self.cache)[0..256];
    }

    fn reload(self: *Self) !void {
        try disk.read(self.sector + self.offset / 512, self.view());
    }
};