Root/
| 1 | #pypp 0 |
| 2 | #include <iris.hh> |
| 3 | #include <devices.hh> |
| 4 | |
| 5 | #define SECTOR_BITS 9 |
| 6 | #define BLOCK_MASK (~((1 << SECTOR_BITS) - 1)) |
| 7 | #define ROOT_CLUSTER 0x7fffffff |
| 8 | |
| 9 | static unsigned _free |
| 10 | extern unsigned _end |
| 11 | |
| 12 | void init_alloc (): |
| 13 | _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK |
| 14 | |
| 15 | char *alloc_space (unsigned pages): |
| 16 | unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK |
| 17 | _free = ret + (pages << PAGE_BITS) |
| 18 | return (char *)ret |
| 19 | |
| 20 | void *operator new[] (unsigned size): |
| 21 | //kdebug ("new ") |
| 22 | void *ret = (void *)_free |
| 23 | size = (size + 3) & ~3 |
| 24 | unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1) |
| 25 | if rest < size: |
| 26 | unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS |
| 27 | for unsigned p = 0; p < pages; ++p: |
| 28 | Iris::Page page = Iris::my_memory.create_page () |
| 29 | page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 30 | Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS)) |
| 31 | Iris::free_cap (page) |
| 32 | _free += size |
| 33 | //kdebug_num ((unsigned)ret) |
| 34 | //kdebug ("+") |
| 35 | //kdebug_num (size) |
| 36 | //kdebug ("\n") |
| 37 | return ret |
| 38 | |
| 39 | void *operator new (unsigned size): |
| 40 | return new char[size] |
| 41 | |
| 42 | static Iris::WBlock dev |
| 43 | static Iris::Num device_size |
| 44 | static Iris::Page page |
| 45 | static char *data |
| 46 | static Iris::Num current_block |
| 47 | static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0): |
| 48 | if p.code == page.code: |
| 49 | if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS: |
| 50 | return |
| 51 | current_block = idx |
| 52 | //kdebug ("fat getting block: ") |
| 53 | //kdebug_num (idx.h) |
| 54 | //kdebug (":") |
| 55 | //kdebug_num (idx.l) |
| 56 | //kdebug ("+") |
| 57 | //kdebug_num (size) |
| 58 | //kdebug ("@") |
| 59 | //kdebug_num (offset) |
| 60 | //kdebug ("\n") |
| 61 | dev.get_block (idx, size, offset, p) |
| 62 | |
| 63 | struct Fat: |
| 64 | char oem[8] |
| 65 | unsigned sector_size_bits |
| 66 | unsigned sectors_per_cluster_bits |
| 67 | unsigned reserved_sectors |
| 68 | unsigned num_fats |
| 69 | unsigned root_entries |
| 70 | unsigned sectors |
| 71 | unsigned media |
| 72 | unsigned sectors_per_fat |
| 73 | unsigned sectors_per_track |
| 74 | unsigned heads |
| 75 | unsigned hidden_sectors |
| 76 | unsigned active_fat |
| 77 | bool write_all_fats |
| 78 | unsigned fs_version |
| 79 | unsigned root_cluster |
| 80 | unsigned fsinfo_sector |
| 81 | unsigned boot_backup_sector |
| 82 | unsigned drive |
| 83 | unsigned current_head |
| 84 | unsigned volume_id |
| 85 | char label[0xb] |
| 86 | |
| 87 | unsigned bits |
| 88 | unsigned clusters |
| 89 | unsigned cluster_size_bits |
| 90 | unsigned root_sectors |
| 91 | unsigned header_sectors |
| 92 | unsigned bad_clusters |
| 93 | |
| 94 | unsigned free_clusters |
| 95 | unsigned last_alloced |
| 96 | |
| 97 | unsigned *fat |
| 98 | unsigned first_free_cluster, first_bad_cluster |
| 99 | |
| 100 | void print_num (char const *pre, unsigned data): |
| 101 | kdebug ("\t") |
| 102 | kdebug (pre) |
| 103 | unsigned bytes = 1 |
| 104 | while bytes < 8 && data >> (bytes * 4): |
| 105 | ++bytes |
| 106 | kdebug_num (data, bytes) |
| 107 | kdebug ("\n") |
| 108 | |
| 109 | void print_br (): |
| 110 | kdebug ("\tOEM: '") |
| 111 | for unsigned i = 0; i < 8; ++i: |
| 112 | kdebug_char (oem[i]) |
| 113 | kdebug ("'\n") |
| 114 | print_num ("bytes per sector: ", 1 << sector_size_bits) |
| 115 | print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits) |
| 116 | print_num ("reserved sectors: ", reserved_sectors) |
| 117 | print_num ("number of fats: ", num_fats) |
| 118 | print_num ("entries in root directory: ", root_entries) |
| 119 | print_num ("sectors: ", sectors) |
| 120 | print_num ("media descriptor: ", media) |
| 121 | print_num ("sectors per fat: ", sectors_per_fat) |
| 122 | print_num ("sectors per track: ", sectors_per_track) |
| 123 | print_num ("heads: ", heads) |
| 124 | print_num ("hidden sectors: ", hidden_sectors) |
| 125 | print_num ("active_fat: ", active_fat) |
| 126 | kdebug ("\twrite all: ") |
| 127 | kdebug (write_all_fats ? "yes\n" : "no\n") |
| 128 | print_num ("fs version: ", fs_version) |
| 129 | print_num ("root cluster: ", root_cluster) |
| 130 | print_num ("fsinfo sector: ", fsinfo_sector) |
| 131 | print_num ("boot sector backup sector: ", boot_backup_sector) |
| 132 | print_num ("drive: ", drive) |
| 133 | print_num ("current head: ", current_head) |
| 134 | print_num ("volume id: ", volume_id) |
| 135 | kdebug ("\tlabel: '") |
| 136 | for unsigned i = 0; i < 0xb; ++i: |
| 137 | kdebug_char (label[i]) |
| 138 | kdebug ("'\n") |
| 139 | print_num ("bits: ", bits) |
| 140 | print_num ("clusters: ", clusters) |
| 141 | print_num ("header sectors: ", header_sectors) |
| 142 | |
| 143 | unsigned read_num (char *data, unsigned bytes): |
| 144 | unsigned ret = 0 |
| 145 | for unsigned i = 0; i < bytes; ++i: |
| 146 | ret |= (data[i] & 0xff) << (i * 8) |
| 147 | return ret |
| 148 | |
| 149 | void map_fat_cluster (unsigned c, unsigned offset = 0): |
| 150 | //unsigned b = current_block.l |
| 151 | read_block ((reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits) |
| 152 | //if b != current_block.l: |
| 153 | //for unsigned i = 0; i < 0x20; ++i: |
| 154 | //kdebug (" ") |
| 155 | //kdebug_num (data[i], 2) |
| 156 | //kdebug ("\n") |
| 157 | |
| 158 | unsigned make_bits (unsigned orig): |
| 159 | unsigned ret |
| 160 | for ret = 0; ret < 32; ++ret: |
| 161 | if orig == 1 << ret: |
| 162 | return ret |
| 163 | //Iris::panic (orig, "non-power of 2") |
| 164 | kdebug ("not a power of two, using 16\n") |
| 165 | return 16 |
| 166 | |
| 167 | void reset (): |
| 168 | read_block (0) |
| 169 | if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa: |
| 170 | kdebug ("invalid boot record signature in fat device\n") |
| 171 | for unsigned i = 0; i < 8; ++i: |
| 172 | oem[i] = data[3 + i] |
| 173 | sector_size_bits = make_bits (read_num (data + 0xb, 2)) |
| 174 | sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1)) |
| 175 | cluster_size_bits = sector_size_bits + sectors_per_cluster_bits |
| 176 | reserved_sectors = read_num (data + 0xe, 2) |
| 177 | num_fats = read_num (data + 0x10, 1) |
| 178 | root_entries = read_num (data + 0x11, 2) |
| 179 | sectors = read_num (data + 0x13, 2) |
| 180 | media = read_num (data + 0x15, 1) |
| 181 | sectors_per_fat = read_num (data + 0x16, 2) |
| 182 | sectors_per_track = read_num (data + 0x18, 2) |
| 183 | heads = read_num (data + 0x1a, 2) |
| 184 | hidden_sectors = read_num (data + 0x1c, 4) |
| 185 | if !sectors: |
| 186 | sectors = read_num (data + 0x20, 4) |
| 187 | if Iris::Num (sectors).value () << sector_size_bits > device_size.value (): |
| 188 | sectors = device_size.value () >> sector_size_bits |
| 189 | kdebug ("warning: limiting sectors because of limited device size\n") |
| 190 | |
| 191 | root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits |
| 192 | header_sectors = reserved_sectors + sectors_per_fat * num_fats + root_sectors |
| 193 | clusters = (sectors - header_sectors) >> sectors_per_cluster_bits |
| 194 | unsigned skip |
| 195 | if clusters >= 65525: |
| 196 | bits = 32 |
| 197 | sectors_per_fat = read_num (data + 0x24, 4) |
| 198 | active_fat = read_num (data + 0x28, 2) |
| 199 | write_all_fats = active_fat & 0x80 |
| 200 | active_fat &= 0xf |
| 201 | fs_version = read_num (data + 0x2a, 2) |
| 202 | root_cluster = read_num (data + 0x2c, 4) |
| 203 | fsinfo_sector = read_num (data + 0x30, 2) |
| 204 | boot_backup_sector = read_num (data + 0x32, 2) |
| 205 | skip = 0x40 - 0x24 |
| 206 | else: |
| 207 | if clusters < 4085: |
| 208 | bits = 12 |
| 209 | else: |
| 210 | bits = 16 |
| 211 | skip = 0 |
| 212 | active_fat = 0 |
| 213 | write_all_fats = true |
| 214 | fs_version = 0 |
| 215 | root_cluster = 0 |
| 216 | fsinfo_sector = 0 |
| 217 | boot_backup_sector = 0 |
| 218 | unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits |
| 219 | unsigned fat_entries = sectors_per_fat * fat_entries_per_sector |
| 220 | if clusters + 2 > fat_entries: |
| 221 | clusters = fat_entries - 2 |
| 222 | kdebug ("warning: limiting clusters because of limited sector count\n") |
| 223 | drive = read_num (data + skip + 0x24, 1) |
| 224 | current_head = read_num (data + skip + 0x25, 1) |
| 225 | if data[skip + 0x26] == 0x29: |
| 226 | volume_id = read_num (data + skip + 0x27, 4) |
| 227 | for unsigned i = 0; i < 0xb; ++i: |
| 228 | label[i] = data[skip + 0x2b + i] |
| 229 | char *id = data + skip + 0x36 |
| 230 | if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ': |
| 231 | kdebug ("warning: file system type field was not 'FATxx '\n") |
| 232 | else: |
| 233 | switch bits: |
| 234 | case 12: |
| 235 | if id[3] != '1' || id[4] != '2': |
| 236 | kdebug ("warning: id for fat12 is not FAT12\n") |
| 237 | break |
| 238 | case 16: |
| 239 | if id[3] != '1' || id[4] != '6': |
| 240 | kdebug ("warning: id for fat16 is not FAT16\n") |
| 241 | break |
| 242 | case 32: |
| 243 | if id[3] != '3' || id[4] != '2': |
| 244 | kdebug ("warning: id for fat32 wat not FAT32") |
| 245 | break |
| 246 | else: |
| 247 | volume_id = 0 |
| 248 | for unsigned i = 0; i < 0xb; ++i: |
| 249 | label[i] = 0 |
| 250 | if fsinfo_sector: |
| 251 | read_block (fsinfo_sector << sector_size_bits) |
| 252 | if (data[0] & 0xff) != 0x52 || (data[1] & 0xff) != 0x52 || (data[2] & 0xff) != 0x6a || (data[3] & 0xff) != 0x41 || (data[0x1e4] & 0xff) != 0x72 || (data[0x1e5] & 0xff) != 0x72 || (data[0x1e6] & 0xff) != 0x4a || (data[0x1e7] & 0xff) != 0x61 || (data[0x1fe] & 0xff) != 0x55 || (data[0x1ff] & 0xff) != 0xaa: |
| 253 | kdebug ("invalid signature in fsinfo structure\n") |
| 254 | free_clusters = read_num (data + 0x1e8, 4) |
| 255 | last_alloced = read_num (data + 0x1ec, 4) |
| 256 | else: |
| 257 | free_clusters = ~0 |
| 258 | last_alloced = ~0 |
| 259 | |
| 260 | // Now read the FAT. |
| 261 | bad_clusters = 0 |
| 262 | fat = new unsigned[clusters] |
| 263 | unsigned counted_free_clusters = 0 |
| 264 | first_free_cluster = ~0 |
| 265 | for unsigned c = 0; c < clusters; ++c: |
| 266 | // reduced cluster. |
| 267 | unsigned rc = c & (1 << sector_size_bits) - 1 |
| 268 | // The next line does nothing most of the time. |
| 269 | map_fat_cluster (c) |
| 270 | switch bits: |
| 271 | case 12: |
| 272 | fat[c] = data[(rc + 2) * 2] & 0xff |
| 273 | // There may be a sector boundary in the middle of the entry, so optionally reread. |
| 274 | map_fat_cluster (c, 1) |
| 275 | fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8 |
| 276 | if c & 1: |
| 277 | fat[c] >>= 4 |
| 278 | else: |
| 279 | fat[c] &= 0xfff |
| 280 | break |
| 281 | case 16: |
| 282 | fat[c] = read_num (data + (rc + 2) * 2, 2) |
| 283 | break |
| 284 | case 32: |
| 285 | fat[c] = read_num (data + (rc + 2) * 4, 4) |
| 286 | break |
| 287 | // Correct for the crazy +2 offset, and keep a list of bad and free clusters. |
| 288 | if fat[c] == 0: |
| 289 | // Free cluster. |
| 290 | fat[c] = first_free_cluster |
| 291 | first_free_cluster = c |
| 292 | ++counted_free_clusters |
| 293 | else if fat[c] == 1: |
| 294 | // Invalid value. |
| 295 | Iris::panic (0, "entry is '1' in fat.") |
| 296 | else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff: |
| 297 | // Last cluster in chain. |
| 298 | fat[c] = ~0 |
| 299 | //kdebug ("last cluster: ") |
| 300 | //kdebug_num (c) |
| 301 | //kdebug ("\n") |
| 302 | else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7: |
| 303 | // Bad cluster. |
| 304 | fat[c] = first_bad_cluster |
| 305 | first_bad_cluster = c |
| 306 | ++bad_clusters |
| 307 | else: |
| 308 | // Non-last cluster in chain. |
| 309 | fat[c] -= 2 |
| 310 | //kdebug_num (c) |
| 311 | //kdebug (" -> ") |
| 312 | //kdebug_num (fat[c]) |
| 313 | //kdebug ("\n") |
| 314 | unsigned fat_lookup (unsigned first_cluster, unsigned cluster): |
| 315 | //kdebug ("looking up ") |
| 316 | //kdebug_num (first_cluster) |
| 317 | //kdebug ("+") |
| 318 | //kdebug_num (cluster) |
| 319 | //kdebug (":") |
| 320 | while cluster--: |
| 321 | first_cluster = fat[first_cluster] |
| 322 | //kdebug ("->") |
| 323 | //kdebug_num (first_cluster) |
| 324 | if first_cluster == ~0: |
| 325 | //kdebug ("sector beyond end of file requested\n") |
| 326 | return ~0 |
| 327 | //kdebug ("\n") |
| 328 | return first_cluster |
| 329 | struct File: |
| 330 | Fat *fat |
| 331 | unsigned size |
| 332 | unsigned first_cluster |
| 333 | char name[11] |
| 334 | bool archive, readonly, system, hidden, directory, volume |
| 335 | unsigned create_second, create_minute_hour, create_date, access_date, time, date |
| 336 | unsigned checksum |
| 337 | void load_cluster (unsigned idx, unsigned offset_in_cluster, Iris::Page p = page, unsigned offset = 0): |
| 338 | unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits) |
| 339 | //kdebug ("loading cluster ") |
| 340 | //kdebug_num (idx) |
| 341 | //kdebug ("+") |
| 342 | //kdebug_num (offset_in_cluster) |
| 343 | //kdebug ("@") |
| 344 | //kdebug_num (cluster) |
| 345 | //kdebug (" from file\n") |
| 346 | if cluster == ~0: |
| 347 | kdebug ("invalid cluster requested from file\n") |
| 348 | return |
| 349 | read_block (((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits) + offset_in_cluster, p, fat->cluster_size_bits < PAGE_BITS ? 1 << fat->cluster_size_bits : PAGE_SIZE, offset) |
| 350 | char *load_dir_entry (unsigned dir, unsigned idx): |
| 351 | unsigned sector = idx >> (sector_size_bits - 5) |
| 352 | unsigned num = (idx << 5) & ~BLOCK_MASK |
| 353 | Iris::Num hwsector |
| 354 | if dir == ROOT_CLUSTER: |
| 355 | if sector < root_sectors: |
| 356 | hwsector = header_sectors - root_sectors + sector |
| 357 | else: |
| 358 | return NULL |
| 359 | else: |
| 360 | unsigned entry = fat_lookup (dir, sector) |
| 361 | if entry == ~0: |
| 362 | return NULL |
| 363 | hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits) |
| 364 | read_block (hwsector.value () << sector_size_bits) |
| 365 | return &data[num] |
| 366 | char *find_idx (unsigned dir, unsigned *idx, unsigned *count = NULL): |
| 367 | unsigned todo = *idx + 1 |
| 368 | char *e |
| 369 | if count: |
| 370 | *count = 0 |
| 371 | for *idx = 0; todo; ++*idx: |
| 372 | e = load_dir_entry (dir, *idx) |
| 373 | if !e: |
| 374 | return NULL |
| 375 | if (e[0xb] & 0xff) == 0xf: |
| 376 | // This is part of a long filename. |
| 377 | continue |
| 378 | if (e[0] & 0xff) == 0xe5: |
| 379 | // This is a deleted file. |
| 380 | continue |
| 381 | if !e[0]: |
| 382 | // This is a free entry. |
| 383 | continue |
| 384 | if count: |
| 385 | ++*count |
| 386 | --todo |
| 387 | --*idx |
| 388 | return e |
| 389 | unsigned get_dir_size (unsigned dir): |
| 390 | unsigned num = 0 - 2 |
| 391 | unsigned ret |
| 392 | find_idx (dir, &num, &ret) |
| 393 | return ret |
| 394 | bool get_dir_entry (unsigned dir, unsigned idx, File *f): |
| 395 | char *e = load_dir_entry (dir, idx) |
| 396 | if !e: |
| 397 | kdebug ("unable to load dir entry\n") |
| 398 | return false |
| 399 | f->fat = this |
| 400 | //kdebug ("loading dir entry for ") |
| 401 | for unsigned i = 0; i < 11; ++i: |
| 402 | f->name[i] = e[i] |
| 403 | //kdebug_char (f->name[i]) |
| 404 | //kdebug ("\n") |
| 405 | f->readonly = e[0xb] & 0x1 |
| 406 | f->system = e[0xb] & 0x2 |
| 407 | f->hidden = e[0xb] & 0x4 |
| 408 | f->volume = e[0xb] & 0x8 |
| 409 | f->directory = e[0xb] & 0x10 |
| 410 | f->archive = e[0xb] & 0x20 |
| 411 | f->create_second = read_num (e + 0xd, 1) |
| 412 | f->create_minute_hour = read_num (e + 0xe, 2) |
| 413 | f->create_date = read_num (e + 0x10, 2) |
| 414 | f->access_date = read_num (e + 0x12, 2) |
| 415 | f->time = read_num (e + 0x16, 1) |
| 416 | f->date = read_num (e + 0x18, 1) |
| 417 | f->size = read_num (e + 0x1c, 4) |
| 418 | f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2 |
| 419 | f->checksum = 0 |
| 420 | for unsigned i = 0; i < 11; ++i: |
| 421 | f->checksum = ((((f->checksum & 1) << 7) | ((f->checksum & 0xfe) >> 1)) + f->name[i]) & 0xff |
| 422 | //kdebug ("loaded dir entry, first cluster = ") |
| 423 | //kdebug_num (f->first_cluster) |
| 424 | //kdebug ("\n") |
| 425 | return true |
| 426 | struct LFN: |
| 427 | unsigned ordinal |
| 428 | unsigned name[13] |
| 429 | unsigned checksum |
| 430 | bool load_lfn (unsigned dir, unsigned idx, unsigned t, unsigned checksum, LFN *lfn): |
| 431 | if t >= idx: |
| 432 | return false |
| 433 | char *e = load_dir_entry (dir, idx - t - 1) |
| 434 | if (e[0xb] & 0xff) != 0xf: |
| 435 | return false |
| 436 | lfn->ordinal = read_num (e + 0x00, 1) |
| 437 | for unsigned i = 0; i < 5; ++i: |
| 438 | lfn->name[i] = read_num (e + 0x01 + 2 * i, 2) |
| 439 | lfn->checksum = read_num (e + 0xd, 1) |
| 440 | for unsigned i = 0; i < 6; ++i: |
| 441 | lfn->name[i + 5] = read_num (e + 0xe + 2 * i, 2) |
| 442 | for unsigned i = 0; i < 2; ++i: |
| 443 | lfn->name[i + 11] = read_num (e + 0x1c + 2 * i, 2) |
| 444 | return true |
| 445 | unsigned parse_shortname (File const &f, char *name): |
| 446 | if f.name[0] == ' ': |
| 447 | Iris::panic (0, "fat name starts with space") |
| 448 | unsigned len = 8 |
| 449 | while f.name[len - 1] == ' ': |
| 450 | --len |
| 451 | char *ptr = name |
| 452 | for unsigned i = 0; i < len; ++i: |
| 453 | *ptr++ = f.name[i] |
| 454 | if f.name[8] == ' ': |
| 455 | return len |
| 456 | *ptr++ = '.' |
| 457 | len = 3 |
| 458 | while f.name[8 + len - 1] == ' ': |
| 459 | --len |
| 460 | for unsigned i = 0; i < len; ++i: |
| 461 | *ptr++ = f.name[8 + i] |
| 462 | return ptr - name |
| 463 | unsigned get_name_size (unsigned dir, unsigned idx, File const &f): |
| 464 | LFN lfn |
| 465 | unsigned num = 0 |
| 466 | if !load_lfn (dir, idx, 0, f.checksum, &lfn): |
| 467 | // Not a long filename. |
| 468 | char n[12] |
| 469 | return parse_shortname (f, n) |
| 470 | unsigned ordinal = 0 |
| 471 | while true: |
| 472 | if !load_lfn (dir, idx, num, f.checksum, &lfn): |
| 473 | Iris::panic (0, "error parsing long filename") |
| 474 | if (lfn.ordinal & 0x3f) != ++ordinal: |
| 475 | Iris::panic (lfn.ordinal, "error in sequence for long filename") |
| 476 | if lfn.ordinal & 0x40: |
| 477 | break |
| 478 | ++num |
| 479 | unsigned i |
| 480 | for i = 0; i < 13; ++i: |
| 481 | if !lfn.name[i]: |
| 482 | break |
| 483 | return num * 13 + i |
| 484 | |
| 485 | // Capability encoding. |
| 486 | // 0:ROOT_CLUSTER = non fat-32 root directory. |
| 487 | // 0:cluster = other directory. |
| 488 | // cluster:index = file index from directory at cluster. |
| 489 | // cluster|0x80000000:index = filename for file with index from directory at cluster. |
| 490 | |
| 491 | Iris::Num start (): |
| 492 | init_alloc () |
| 493 | current_block = ~0 |
| 494 | dev = Iris::my_parent.get_capability <Iris::WBlock> () |
| 495 | if dev.get_align_bits () > SECTOR_BITS: |
| 496 | kdebug ("fat device doesn't support 512 byte access") |
| 497 | return 1 |
| 498 | device_size = dev.get_size () |
| 499 | data = (char *)0x15000; //alloc_space (1) |
| 500 | page = Iris::my_memory.create_page () |
| 501 | page.set_flags (Iris::Page::PAYING) |
| 502 | Iris::my_memory.map (page, (unsigned)data) |
| 503 | |
| 504 | Fat fat |
| 505 | |
| 506 | fat.reset () |
| 507 | fat.print_br () |
| 508 | |
| 509 | Iris::Cap root |
| 510 | if fat.root_cluster: |
| 511 | root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0)) |
| 512 | else: |
| 513 | root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0)) |
| 514 | |
| 515 | Iris::my_parent.provide_capability <Iris::Directory> (root.copy ()) |
| 516 | Iris::free_cap (root) |
| 517 | |
| 518 | while true: |
| 519 | Iris::wait () |
| 520 | unsigned dir = Iris::recv.protected_data.h |
| 521 | if dir & 0x80000000: |
| 522 | dir &= ~0x80000000 |
| 523 | // File name. |
| 524 | unsigned idx = Iris::recv.protected_data.l |
| 525 | Iris::Cap reply = Iris::get_reply () |
| 526 | unsigned num = Iris::recv.data[1].l |
| 527 | unsigned size = Iris::recv.data[0].h >> 16 |
| 528 | unsigned cmd = Iris::recv.data[0].l |
| 529 | Fat::File f |
| 530 | if !fat.find_idx (dir, &idx): |
| 531 | Iris::panic (Iris::recv.protected_data.l, "invalid index") |
| 532 | if !fat.get_dir_entry (dir, idx, &f): |
| 533 | Iris::panic (Iris::recv.protected_data.l, "invalid dir entry requested for filename") |
| 534 | switch cmd: |
| 535 | case Iris::String::GET_SIZE: |
| 536 | //kdebug ("filename size requested\n") |
| 537 | reply.invoke (fat.get_name_size (dir, idx, f)) |
| 538 | break |
| 539 | case Iris::String::GET_CHARS: |
| 540 | //kdebug ("filename chars requested\n") |
| 541 | //kdebug ("flags: ") |
| 542 | //kdebug_char (f.readonly ? 'R' : 'r') |
| 543 | //kdebug_char (f.system ? 'S' : 's') |
| 544 | //kdebug_char (f.hidden ? 'H' : 'h') |
| 545 | //kdebug_char (f.volume ? 'V' : 'v') |
| 546 | //kdebug_char (f.directory ? 'D' : 'd') |
| 547 | //kdebug_char (f.archive ? 'A' : 'a') |
| 548 | //kdebug_char ('\n') |
| 549 | |
| 550 | /**/union { unsigned u[4]; char c[16]; } u |
| 551 | for unsigned k = 0; k < 4; ++k: |
| 552 | u.u[k] = 0 |
| 553 | Fat::LFN lfn |
| 554 | if !fat.load_lfn (dir, idx, 0, f.checksum, &lfn): |
| 555 | // Not a long filename. |
| 556 | char n[12] |
| 557 | unsigned len = fat.parse_shortname (f, n) |
| 558 | //kdebug ("short filename: ") |
| 559 | for unsigned k = 0; k + num < len; ++k: |
| 560 | u.c[k] = n[k + num] |
| 561 | //kdebug_char (u.c[k]) |
| 562 | //kdebug ("\n") |
| 563 | else: |
| 564 | // Very inefficient, but it works: reload everything for every character. |
| 565 | //kdebug ("filename: ") |
| 566 | for unsigned c = 0; c < 16; ++c: |
| 567 | if !fat.load_lfn (dir, idx, (num + c) / 13, f.checksum, &lfn): |
| 568 | // Filename isn't this long: keep the rest at 0. |
| 569 | break |
| 570 | u.c[c] = lfn.name[(num + c) % 13] |
| 571 | if u.c[c] == 0: |
| 572 | break |
| 573 | //kdebug_char (u.c[c]) |
| 574 | //kdebug ("\n") |
| 575 | reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3])) |
| 576 | break |
| 577 | default: |
| 578 | Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename") |
| 579 | Iris::free_cap (reply) |
| 580 | else if dir: |
| 581 | // If it *has* a directory, it *is* a file. |
| 582 | unsigned idx = Iris::recv.protected_data.l |
| 583 | Iris::Cap reply = Iris::get_reply () |
| 584 | Iris::Cap arg = Iris::get_arg () |
| 585 | Iris::Num num = Iris::recv.data[1] |
| 586 | unsigned size = Iris::recv.data[0].h >> 16 |
| 587 | unsigned offset = Iris::recv.data[0].h & 0xffff |
| 588 | unsigned cmd = Iris::recv.data[0].l |
| 589 | Fat::File f |
| 590 | fat.get_dir_entry (dir, idx, &f) |
| 591 | switch cmd: |
| 592 | case Iris::Block::GET_SIZE: |
| 593 | //kdebug ("file size requested\n") |
| 594 | reply.invoke (f.size) |
| 595 | break |
| 596 | case Iris::Block::GET_ALIGN_BITS: |
| 597 | //kdebug ("file align requested\n") |
| 598 | reply.invoke (fat.cluster_size_bits <= PAGE_BITS ? fat.cluster_size_bits : PAGE_BITS) |
| 599 | break |
| 600 | case Iris::Block::GET_BLOCK: |
| 601 | //kdebug ("file block requested\n") |
| 602 | unsigned mask = (1 << fat.cluster_size_bits) - 1 |
| 603 | //kdebug ("mask = ") |
| 604 | //kdebug_num (mask) |
| 605 | //kdebug ("\n") |
| 606 | if offset > PAGE_SIZE: |
| 607 | //kdebug ("invalid offset requested\n") |
| 608 | break |
| 609 | if size + offset > PAGE_SIZE: |
| 610 | Iris::panic (size, "invalid size requested") |
| 611 | size = PAGE_SIZE - offset |
| 612 | for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits: |
| 613 | f.load_cluster ((num.l & ~mask) + i, num.l & mask, arg, i + offset) |
| 614 | reply.invoke () |
| 615 | break |
| 616 | case Iris::WBlock::TRUNCATE: |
| 617 | case Iris::WBlock::SET_BLOCK: |
| 618 | Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet") |
| 619 | default: |
| 620 | Iris::panic (Iris::recv.data[0].l, "invalid request for fat file") |
| 621 | Iris::free_cap (reply) |
| 622 | Iris::free_cap (arg) |
| 623 | else: |
| 624 | // Directory. |
| 625 | switch Iris::recv.data[0].l: |
| 626 | case Iris::Directory::GET_SIZE: |
| 627 | //kdebug ("dir size requested\n") |
| 628 | Iris::Cap reply = Iris::get_reply () |
| 629 | reply.invoke (fat.get_dir_size (Iris::recv.protected_data.l)) |
| 630 | Iris::free_cap (reply) |
| 631 | break |
| 632 | case Iris::Directory::GET_NAME: |
| 633 | //kdebug ("dir name requested\n") |
| 634 | Iris::Cap reply = Iris::get_reply () |
| 635 | Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000)) |
| 636 | reply.invoke (0, 0, ret.copy ()) |
| 637 | Iris::free_cap (reply) |
| 638 | Iris::free_cap (ret) |
| 639 | break |
| 640 | case Iris::Directory::GET_FILE_RO: |
| 641 | //kdebug ("dir file requested\n") |
| 642 | Iris::Cap reply = Iris::get_reply () |
| 643 | dir = Iris::recv.protected_data.l |
| 644 | unsigned idx = Iris::recv.data[1].l |
| 645 | unsigned oldidx = idx |
| 646 | if !fat.find_idx (dir, &idx): |
| 647 | kdebug_num (oldidx) |
| 648 | kdebug ("\n") |
| 649 | Iris::panic (1, "file not found") |
| 650 | Fat::File f |
| 651 | fat.get_dir_entry (dir, idx, &f) |
| 652 | Iris::Cap ret |
| 653 | if f.directory: |
| 654 | //kdebug ("dir provided: ") |
| 655 | //kdebug_num (f.first_cluster) |
| 656 | //kdebug ("\n") |
| 657 | ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0)) |
| 658 | else: |
| 659 | ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir)) |
| 660 | reply.invoke (0, 0, ret.copy ()) |
| 661 | Iris::free_cap (reply) |
| 662 | Iris::free_cap (ret) |
| 663 | break |
| 664 | case Iris::Directory::GET_FILE_INFO: |
| 665 | //kdebug ("dir file info requested\n") |
| 666 | Iris::Cap reply = Iris::get_reply () |
| 667 | dir = Iris::recv.protected_data.l |
| 668 | unsigned idx = Iris::recv.data[1].l |
| 669 | unsigned oldidx = idx |
| 670 | if !fat.find_idx (dir, &idx): |
| 671 | kdebug_num (oldidx) |
| 672 | kdebug ("\n") |
| 673 | Iris::panic (2, "file not found") |
| 674 | unsigned type = Iris::recv.data[0].h |
| 675 | Fat::File f |
| 676 | fat.get_dir_entry (dir, idx, &f) |
| 677 | reply.invoke (f.directory ? 1 : 0) |
| 678 | Iris::free_cap (reply) |
| 679 | break |
| 680 | case Iris::Directory::LOCK_RO: |
| 681 | case Iris::Directory::UNLOCK_RO: |
| 682 | //kdebug ("dir lock or unlock requested\n") |
| 683 | Iris::recv.reply.invoke () |
| 684 | break |
| 685 | default: |
| 686 | //kdebug ("invalid dir operation requested\n") |
| 687 | Iris::recv.reply.invoke () |
| 688 | break |
| 689 |
Branches:
master
