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

Last change on this file since f1bed857 was 7871c69, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 4 years ago

update bithenge/fat.bh

  • Property mode set to 100644
File size: 4.2 KB
Line 
1#!/usr/bin/perl -w
2#
3# SPDX-FileCopyrightText: 2012 Sean Bartell
4#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8# FAT filesystem script.
9# Largely based on https://en.wikipedia.org/wiki/File_Allocation_Table
10# Currently only FAT12 and FAT16 are supported.
11
12transform u8 = uint8;
13transform u16 = uint16le;
14transform u32 = uint32le;
15
16transform fat_attributes = struct {
17 .read_only <- bit;
18 .hidden <- bit;
19 .system <- bit;
20 .volume_label <- bit;
21 .subdirectory <- bit;
22 .archive <- bit;
23 .device <- bit;
24 .reserved <- bit;
25} <- bits_le <- known_length(1);
26
27transform file_data(data, bits, fat, cluster_size, start) = (in.data) <- struct {
28 .cluster <- (data[(start-2)*cluster_size, cluster_size]);
29 .last_cluster_number <- switch (bits) {
30 12: (488); # 0x00000ff8
31 16: (65528); # 0x0000fff8
32 32: (268435448); # 0x0ffffff8
33 };
34 .next <- (fat[start]);
35 if (.next == 0 || .next >= .last_cluster_number) {
36 .data <- (.cluster);
37 } else {
38 .rest <- file_data(data, bits, fat, cluster_size, .next) <- known_length(0);
39 .data <- (.cluster ++ .rest);
40 }
41};
42
43transform fat_dir_entry(data, bits, fat, cluster_size, self_start, parent) = struct {
44 .filename <- known_length(8);
45 .extension <- known_length(3);
46 .attrs <- fat_attributes;
47 .flags <- u8;
48 .ctime_fine <- u8;
49 .ctime <- u16;
50 .cdate <- u16;
51 .adate <- u16;
52 .permissions <- u16;
53 .mtime <- u16;
54 .mdate <- u16;
55 .start <- u16;
56 .size <- u32;
57 .size_shown <- if (.size > 32) { (32) } else { (.size) };
58
59 if (.start != 0 && .start != self_start && .start != parent && .filename[0] != 229) {
60 .data
61 <- if (.attrs.subdirectory) {
62 repeat { fat_dir_entry(data, bits, fat, cluster_size, .start, self_start) }
63 } else {
64 (in[0,.size_shown])
65 }
66 <- if (.size != 0) { (in[0,.size]) } else { (in) }
67 <- file_data(data, bits, fat, cluster_size, .start);
68 }
69};
70
71transform fat_table(bits, num_clusters) = switch (bits) {
72 12: partial {repeat(num_clusters) { uint_le(12) }} <- bits_le;
73 16: partial {repeat(num_clusters) { u16 }};
74 32: partial {repeat(num_clusters) { u32 }};
75};
76
77transform fat_super(disk) = struct {
78 .jump_instruction <- known_length(3);
79 .oem_name <- ascii <- known_length(8);
80
81 # DOS 2.0 BPB
82 .bytes_per_sector <- u16; # must be power of two, at least 32
83 .sectors_per_cluster <- u8; # must be power of two
84 .num_reserved_sectors <- u16;
85 .num_fats <- u8; # at least 1
86 .num_root_entries <- u16; # 0 for FAT32
87 .num_sectors_16 <- u16;
88 .media_descriptor <- u8;
89 .sectors_per_fat <- u16; # 0 for FAT32
90
91 # DOS 3.0/3.2/3.31 BPB
92 .sectors_per_track <- u16;
93 .num_heads <- u16;
94
95 # DOS 3.31 BPB
96 .bpb331 <- struct {
97 .ignore <- nonzero_boolean <- (.num_sectors_16);
98 .num_hidden_sectors <- u32;
99 .num_sectors_32 <- u32;
100 };
101
102 .drive_number <- u8;
103 .chkdsk_flags <- u8;
104 .extended_boot_signature <- u8;
105 if (.extended_boot_signature == 41) {
106 .volume_id <- u32;
107 .volume_label <- ascii <- known_length(11);
108 .type <- ascii <- known_length(8);
109 }
110
111 .boot_signature <- (disk[510,2]); # b"\x55\xaa"; TODO: what if .bytes_per_sector < 512?
112};
113
114transform fat_filesystem_tree(disk) = struct {
115 .super <- partial{fat_super(disk)} <- (disk);
116
117 .num_sectors <- if (.super.bpb331.ignore) {
118 (.super.num_sectors_16)
119 } else {
120 (.super.bpb331.num_sectors_32)
121 };
122
123 .cluster_size <- (.super.sectors_per_cluster * .super.bytes_per_sector);
124 .first_root_sector <- (.super.num_reserved_sectors + .super.num_fats * .super.sectors_per_fat);
125 .first_data_sector <- (.first_root_sector +
126 (.super.num_root_entries * 32 + .super.bytes_per_sector - 1) //
127 .super.bytes_per_sector);
128 .num_clusters <- (2 + (.num_sectors - .first_data_sector) // .super.sectors_per_cluster);
129 .bits <- if (.num_clusters < 4085) { (12) }
130 else { if (.num_clusters < 65525) { (16) } else { (32) } };
131
132 .fats <- partial(.super.num_reserved_sectors * .super.bytes_per_sector) {
133 repeat(.super.num_fats) {
134 fat_table(.bits, .num_clusters) <-
135 known_length(.super.sectors_per_fat * .super.bytes_per_sector)
136 }
137 } <- (disk);
138
139 .root <- partial(.first_root_sector * .super.bytes_per_sector) {
140 repeat(.super.num_root_entries) {
141 fat_dir_entry(disk[.first_data_sector * .super.bytes_per_sector:],
142 .bits, .fats[0], .cluster_size, 0, 0)
143 }
144 } <- (disk);
145};
146
147transform fat_filesystem = partial {fat_filesystem_tree(in)};
148
149transform main = fat_filesystem;
Note: See TracBrowser for help on using the repository browser.