summaryrefslogtreecommitdiff
path: root/src/kernel/fs.c
blob: 0d51c22b550d22705003ab47f6460ae4a6c90b3d (plain) (blame)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdint.h>
#include "fs.h"
#include "ata.h"
#include "fat.h"
#include <stdbool.h>
#include "panic.h"
#include "util.h"

#define MAX_HANDLES 32
#define FILE_BUFFER(h) ((void *)(0x0002be00 + (h << 9)))
#define HANDLE(h) ((handles - 1)[h])
#define HEAD(h) (FILE_BUFFER(h) + HANDLE(h).seek % 512)

enum {
  FH_DIRTY     = 0x01,
  FH_NO_WRITE  = 0x02,
  FH_NO_EXPAND = 0x04,
  FH_ROOT      = 0x08
};

struct handle_info {
  uint16_t first_cluster;
  uint16_t loaded_cluster;
  uint32_t seek;
  uint32_t length;
  uint8_t flags;
};

struct handle_info handles[MAX_HANDLES];

void clear_fs_handles() {
  struct handle_info *f = handles;
  while (f < handles + MAX_HANDLES)
    (f++)->first_cluster = 0;
}

fs_handle next_handle() {
  fs_handle r = 0;
  while (HANDLE(++r).first_cluster)
    if (r == MAX_HANDLES)
      return 0;
  return r;
}

void write_buffer(fs_handle handle) {
  HANDLE(handle).flags &= ~FH_DIRTY;
  if (HANDLE(handle).flags & FH_ROOT)
    write_sectors(HANDLE(handle).loaded_cluster, 1, FILE_BUFFER(handle));
  else
    write_sectors(CTOS(HANDLE(handle).loaded_cluster), 1, FILE_BUFFER(handle));
}

void read_buffer(fs_handle handle) {
  if (HANDLE(handle).flags & FH_DIRTY)
    write_buffer(handle);
  uint16_t s = HANDLE(handle).seek >> 9;
  if (HANDLE(handle).flags & FH_ROOT) {
    HANDLE(handle).loaded_cluster = HANDLE(handle).first_cluster + s;
    read_sectors(HANDLE(handle).first_cluster + s, 1, FILE_BUFFER(handle));
  }
  else {
    uint16_t c = HANDLE(handle).first_cluster;
    while (s--)
      c = FAT[c];
    HANDLE(handle).loaded_cluster = c;
    read_sectors(CTOS(c), 1, FILE_BUFFER(handle));
  }
}

fs_handle fs_open(uint8_t *path) {
  fs_handle next = next_handle();
  if (!next)
    return 0;
  struct directory_entry e;
  if (get_entry(path, &e))
    return 0;
  HANDLE(next).first_cluster = e.first_cluster;
  HANDLE(next).seek = 0;
  HANDLE(next).length = e.length;
  HANDLE(next).flags = (e.attrib & FA_READ_ONLY ? FH_NO_WRITE  : 0) |
                       (e.attrib & FA_SYSTEM    ? FH_NO_EXPAND : 0);
  read_buffer(next);
  return next;
}

fs_handle fs_open_root() {
  fs_handle next = next_handle();
  if (!next)
    return 0;
  HANDLE(next).first_cluster = FAT_INFO->reserved_sectors + FAT_INFO->sectors_per_fat;
  HANDLE(next).seek = 0;
  HANDLE(next).length = FAT_INFO->root_entries * 32;
  HANDLE(next).flags = FH_NO_EXPAND | FH_ROOT;
  read_buffer(next);
  return next;
}

int32_t fs_seek(fs_handle handle, int32_t by) {
  uint32_t old = HANDLE(handle).seek;
  uint32_t to = -by > old ? 0 : old + by > HANDLE(handle).length ? HANDLE(handle).length : old + by;
  HANDLE(handle).seek = to;
  if ((to ^ old) & 0xfe00)
    read_buffer(handle);
  return to - old;
}

uint32_t fs_read(fs_handle handle, uint32_t max, void *buffer) {
  max = HANDLE(handle).seek + max > HANDLE(handle).length ? HANDLE(handle).length - HANDLE(handle).seek : max;
  uint32_t left = max, eos = 512 - (HANDLE(handle).seek & 0x1ff);
  if (left < eos) {
    memcpy(buffer, FILE_BUFFER(handle) + (HANDLE(handle).seek & 0x1ff), left);
    HANDLE(handle).seek += left;
    return max;
  }
  memcpy(buffer, FILE_BUFFER(handle) + (HANDLE(handle).seek & 0x1ff), eos);
  left -= eos;
  buffer += eos;
  HANDLE(handle).seek += eos;
  while (left >= 512) {
    read_buffer(handle);
    memcpy(buffer, FILE_BUFFER(handle), 512);
    left -= 512;
    buffer += 512;
    HANDLE(handle).seek += 512;
  }
  if (left) {
    read_buffer(handle);
    memcpy(buffer, FILE_BUFFER(handle), left);
    HANDLE(handle).seek += left;
  }
  return max;
}

uint32_t fs_write(fs_handle handle, uint32_t max, void *buffer) {
  if (HANDLE(handle).flags & FH_NO_WRITE)
    return 0;
  panic("Not implemented (fs_write).");
}

void fs_close(fs_handle handle) {
  if (HANDLE(handle).flags & FH_DIRTY)
    write_buffer(handle);
  HANDLE(handle).first_cluster = 0;
}