Index: uspace/dist/src/bithenge/fat.bh
===================================================================
--- uspace/dist/src/bithenge/fat.bh	(revision c97970674c89cafa26e21448d401fd022ab67473)
+++ uspace/dist/src/bithenge/fat.bh	(revision c97970674c89cafa26e21448d401fd022ab67473)
@@ -0,0 +1,70 @@
+# Copyright (c) 2012 Sean Bartell
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# FAT filesystem script.
+# Largely based on https://en.wikipedia.org/wiki/File_Allocation_Table
+
+transform u8 = uint8;
+transform u16 = uint16le;
+transform u32 = uint32le;
+
+transform fat_super(disk) = struct {
+	.jump_instruction <- known_length(3);
+	.oem_name <- ascii <- known_length(8);
+
+	# DOS 2.0 BPB
+	.bytes_per_sector <- u16; # must be power of two, at least 32
+	.sectors_per_cluster <- u8; # must be power of two
+	.num_reserved_sectors <- u16;
+	.num_fats <- u8; # at least 1
+	.num_root_entries <- u16; # 0 for FAT32
+	.num_sectors_16 <- u16;
+	.media_descriptor <- u8;
+	.sectors_per_fat <- u16; # 0 for FAT32
+
+	# DOS 3.0/3.2/3.31 BPB
+	.sectors_per_track <- u16;
+	.num_heads <- u16;
+
+	# DOS 3.31 BPB
+	.bpb331 <- struct {
+		.ignore <- nonzero_boolean <- (.num_sectors_16);
+		.num_hidden_sectors <- u32;
+		.num_sectors_32 <- u32;
+	};
+
+	.num_sectors <- if (.bpb331.ignore) {
+		(.num_sectors_16)
+	} else {
+		(.bpb331.num_sectors_32)
+	};
+
+	.boot_signature <- (disk[510,2]); # b"\x55\xaa"; TODO: what if .bytes_per_sector < 512?
+};
+
+transform fat_filesystem = partial { fat_super(in) };
+
+transform main = fat_filesystem;
