aboutsummaryrefslogtreecommitdiffstats
path: root/src/filesystem.c
blob: 2da77bece77235e0b254f8c4188aa2acda53096c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// We need 64 * 32 bytes (2K) of SRAM for file indexes. To avoid corruption
// issues we ignore the first file (32 bytes).
// Note that the filename should include the null terminator if we want to use
// strcmp.
#define FILE_NAME_SIZE     27
#define FILE_CAPACITY      63
#define FILE_HEADER_OFFSET 2
#define FILE_INDEX_OFFSET  32
#define FILE_DATA_OFFSET   KB(2)
#define FILE_MAX_SIZE      KB(1)
#define SRAM               ((vu8*)(MEM_CART))

typedef struct File {
    char name[FILE_NAME_SIZE + 1];
    u16 size;
    u16 mem_offset; // NOTE: Unused...
} File;

// The filesystem header.
typedef struct FileSystem {
    u16 num_files;
    u16 data_size; // NOTE: Unused...
    u16 data_capacity; // NOTE: Unused...
    File files[FILE_CAPACITY];
} FileSystem;

static FileSystem filesystem;

void
_fs_read(u8 *dst, size_t pos, size_t n_bytes) {
    for (size_t i = 0; i < n_bytes; ++i) {
        dst[i] = SRAM[pos + i];
    }
}

void
_fs_write(u8 *src, size_t pos, size_t n_bytes) {
    for (size_t i = 0; i < n_bytes; ++i) {
        SRAM[pos + i] = src[i];
    }
}

void
fs_init() {
    // Load header if existing.
    _fs_read(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
    if (filesystem.num_files == 0xFFFF
            && filesystem.data_capacity == 0xFFFF
            && filesystem.data_size == 0xFFFF) {
        filesystem.num_files = 0;
        filesystem.data_size = 0;
        filesystem.data_capacity = 27 * FILE_MAX_SIZE;
        memset(&filesystem.files, 0, FILE_CAPACITY * sizeof(File));
        _fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));
    } else {
        _fs_read(&filesystem.files, FILE_INDEX_OFFSET, sizeof(File) * filesystem.num_files);
    }
}

int
fs_open_file(char *name) {
    // Try to find an existing file.
    for (size_t i = 0; i < filesystem.num_files; ++i) {
        // TODO: Replace strcmp with vectorized fixed size char comparison.
        if (strcmp(name, filesystem.files[i].name) == 0) {
            return i;
        }
    }
    // Create a new file if there is space.
    if (filesystem.num_files < FILE_CAPACITY) {
        size_t index = filesystem.num_files++;
        size_t k = 0;
        while(*name) {
            filesystem.files[index].name[k++] = *name++;
        }
        filesystem.files[index].size = 0;
        filesystem.files[index].mem_offset = 0;

        // Update file index.
        _fs_write(&filesystem.files[index],
                FILE_INDEX_OFFSET + index * sizeof(File),
                sizeof(File));

        // Update header.
        _fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));

        return index;
    }
    return -1;
}

int
fs_write(u8 *src, size_t n_bytes, u16 file_index, u16 offset, bool append) {
    File *file = &filesystem.files[file_index];

    // Check if there is enough capacity for this write operation.
    if (offset + n_bytes >= FILE_MAX_SIZE) {
        return -1;
    }

    // Write data to file block.
    _fs_write(src, FILE_DATA_OFFSET + FILE_MAX_SIZE * file_index + offset, n_bytes);

    // Update file index.
    if (append) {
        if (offset + n_bytes > file->size) {
            file->size = offset + n_bytes;
        }
    } else {
        file->size = offset + n_bytes;
    }
    _fs_write(file, FILE_INDEX_OFFSET + file_index * sizeof(File), sizeof(File));

    // Update header.
    _fs_write(&filesystem, FILE_HEADER_OFFSET, offsetof(FileSystem, files));

    return n_bytes;
}