source: mainline/uspace/dist/src/bithenge/fat.bh@ 2988aec7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2988aec7 was 2988aec7, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: read FAT files/subdirs; self-recursion and more operators

  • Property mode set to 100644
File size: 5.5 KB
Line 
1# Copyright (c) 2012 Sean Bartell
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7#
8# - Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# - Redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution.
13# - The name of the author may not be used to endorse or promote products
14# derived from this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27# FAT filesystem script.
28# Largely based on https://en.wikipedia.org/wiki/File_Allocation_Table
29# Currently only FAT12 and FAT16 are supported.
30
31transform u8 = uint8;
32transform u16 = uint16le;
33transform u32 = uint32le;
34
35transform fat_attributes = struct {
36 .read_only <- bit;
37 .hidden <- bit;
38 .system <- bit;
39 .volume_label <- bit;
40 .subdirectory <- bit;
41 .archive <- bit;
42 .device <- bit;
43 .reserved <- bit;
44} <- bits_le <- known_length(1);
45
46transform file_data(data, bits, fat, cluster_size, start) = (in.data) <- struct {
47 .cluster <- (data[(start-2)*cluster_size, cluster_size]);
48 .last_cluster_number <- switch (bits) {
49 12: (488); # 0x00000ff8
50 16: (65528); # 0x0000fff8
51 32: (268435448); # 0x0ffffff8
52 };
53 .next <- (fat[start]);
54 if (.next == 0 || .next >= .last_cluster_number) {
55 .data <- (.cluster);
56 } else {
57 .rest <- file_data(data, bits, fat, cluster_size, .next);
58 .data <- (.cluster ++ .rest);
59 }
60};
61
62transform fat_dir_entry(data, bits, fat, cluster_size, self_start, parent) = struct {
63 .filename <- known_length(8);
64 .extension <- known_length(3);
65 .attrs <- fat_attributes;
66 .flags <- u8;
67 .ctime_fine <- u8;
68 .ctime <- u16;
69 .cdate <- u16;
70 .adate <- u16;
71 .permissions <- u16;
72 .mtime <- u16;
73 .mdate <- u16;
74 .start <- u16;
75 .size <- u32;
76 .size_shown <- if (.size > 32) { (32) } else { (.size) };
77
78 if (.start != 0 && .start != self_start && .start != parent) {
79 .data
80 <- if (.attrs.subdirectory) {
81 repeat { fat_dir_entry(data, bits, fat, cluster_size, .start, self_start) }
82 } else {
83 (in[0,.size_shown])
84 }
85 <- if (.size != 0) { (in[0,.size]) } else { (in) }
86 <- file_data(data, bits, fat, cluster_size, .start);
87 }
88};
89
90transform fat_table(bits, num_clusters) = switch (bits) {
91 12: partial {repeat(num_clusters) { uint_le(12) }} <- bits_le;
92 16: partial {repeat(num_clusters) { u16 }};
93 32: partial {repeat(num_clusters) { u32 }};
94};
95
96transform fat_super(disk) = struct {
97 .jump_instruction <- known_length(3);
98 .oem_name <- ascii <- known_length(8);
99
100 # DOS 2.0 BPB
101 .bytes_per_sector <- u16; # must be power of two, at least 32
102 .sectors_per_cluster <- u8; # must be power of two
103 .num_reserved_sectors <- u16;
104 .num_fats <- u8; # at least 1
105 .num_root_entries <- u16; # 0 for FAT32
106 .num_sectors_16 <- u16;
107 .media_descriptor <- u8;
108 .sectors_per_fat <- u16; # 0 for FAT32
109
110 # DOS 3.0/3.2/3.31 BPB
111 .sectors_per_track <- u16;
112 .num_heads <- u16;
113
114 # DOS 3.31 BPB
115 .bpb331 <- struct {
116 .ignore <- nonzero_boolean <- (.num_sectors_16);
117 .num_hidden_sectors <- u32;
118 .num_sectors_32 <- u32;
119 };
120
121 .drive_number <- u8;
122 .chkdsk_flags <- u8;
123 .extended_boot_signature <- u8;
124 if (.extended_boot_signature == 41) {
125 .volume_id <- u32;
126 .volume_label <- ascii <- known_length(11);
127 .type <- ascii <- known_length(8);
128 }
129
130 .boot_signature <- (disk[510,2]); # b"\x55\xaa"; TODO: what if .bytes_per_sector < 512?
131};
132
133transform fat_filesystem_tree(disk) = struct {
134 .super <- partial{fat_super(disk)} <- (disk);
135
136 .num_sectors <- if (.super.bpb331.ignore) {
137 (.super.num_sectors_16)
138 } else {
139 (.super.bpb331.num_sectors_32)
140 };
141
142 .cluster_size <- (.super.sectors_per_cluster * .super.bytes_per_sector);
143 .first_root_sector <- (.super.num_reserved_sectors + .super.num_fats * .super.sectors_per_fat);
144 .first_data_sector <- (.first_root_sector +
145 (.super.num_root_entries * 32 + .super.bytes_per_sector - 1) //
146 .super.bytes_per_sector);
147 .num_clusters <- (2 + (.num_sectors - .first_data_sector) // .super.sectors_per_cluster);
148 .bits <- if (.num_clusters < 4085) { (12) }
149 else { if (.num_clusters < 65525) { (16) } else { (32) } };
150
151 .fats <- partial(.super.num_reserved_sectors * .super.bytes_per_sector) {
152 repeat(.super.num_fats) {
153 fat_table(.bits, .num_clusters) <-
154 known_length(.super.sectors_per_fat * .super.bytes_per_sector)
155 }
156 } <- (disk);
157
158 .root <- partial(.first_root_sector * .super.bytes_per_sector) {
159 repeat(.super.num_root_entries) {
160 fat_dir_entry(disk[.first_data_sector * .super.bytes_per_sector:],
161 .bits, .fats[0], .cluster_size, 0, 0)
162 }
163 } <- (disk);
164};
165
166transform fat_filesystem = partial {fat_filesystem_tree(in)};
167
168transform main = fat_filesystem;
Note: See TracBrowser for help on using the repository browser.