Root/userspace/glue/fat.ccp

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
9static unsigned _free
10extern unsigned _end
11
12void init_alloc ():
13    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
14
15char *alloc_space (unsigned pages):
16    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
17    _free = ret + (pages << PAGE_BITS)
18    return (char *)ret
19
20void *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
39void *operator new (unsigned size):
40    return new char[size]
41
42static Iris::WBlock dev
43static Iris::Num device_size
44static Iris::Page page
45static char *data
46static Iris::Num current_block
47static 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
63struct 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
491Iris::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

Archive Download this file

Branches:
master



interactive