Index: uspace/dist/src/bithenge/fat.bh
===================================================================
--- uspace/dist/src/bithenge/fat.bh	(revision c97970674c89cafa26e21448d401fd022ab67473)
+++ uspace/dist/src/bithenge/fat.bh	(revision 0153c87e5c9c1080a884969b29e7aa3388bd5a64)
@@ -32,4 +32,26 @@
 transform u32 = uint32le;
 
+transform fat_dir_entry(disk) = struct {
+	.filename <- known_length(8);
+	.extension <- known_length(3);
+	.attrs <- u8;
+	.flags <- u8;
+	.ctime_fine <- u8;
+	.ctime <- u16;
+	.cdate <- u16;
+	.adate <- u16;
+	.permissions <- u16;
+	.mtime <- u16;
+	.mdate <- u16;
+	.start <- u16;
+	.size <- u32;
+};
+
+transform fat_table(bits, num_clusters) = switch (bits) {
+	12: partial {repeat(num_clusters) { uint_le(12) }} <- bits_le;
+	16: partial {repeat(num_clusters) { u16 }};
+	32: partial {repeat(num_clusters) { u32 }};
+};
+
 transform fat_super(disk) = struct {
 	.jump_instruction <- known_length(3);
@@ -63,4 +85,22 @@
 	};
 
+	.first_root_sector <- (.num_reserved_sectors + .num_fats * .sectors_per_fat);
+	.first_data_sector <- (.first_root_sector +
+	    (.num_root_entries * 32 + .bytes_per_sector - 1) //
+	    .bytes_per_sector);
+	.num_clusters <- (2 + (.num_sectors - .first_data_sector) // .sectors_per_cluster);
+	.bits <- if (.num_clusters < 4085) { (12) }
+	    else { if (.num_clusters < 65525) { (16) } else { (32) } };
+
+	.fats <- partial(.num_reserved_sectors * .bytes_per_sector) {
+		repeat(.num_fats) {
+			fat_table(.bits, .num_clusters) <-
+				known_length(.sectors_per_fat * .bytes_per_sector)
+		}
+	} <- (disk);
+
+	.root <- partial(.first_root_sector * .bytes_per_sector) {
+		repeat(.num_root_entries) { fat_dir_entry(disk) } } <- (disk);
+
 	.boot_signature <- (disk[510,2]); # b"\x55\xaa"; TODO: what if .bytes_per_sector < 512?
 };
