2010-06-07 00:03:25 +03:00
|
|
|
#pypp 0
|
|
|
|
#include <iris.hh>
|
|
|
|
#include <devices.hh>
|
|
|
|
|
|
|
|
#define SECTOR_BITS 9
|
|
|
|
#define BLOCK_MASK (~((1 << SECTOR_BITS) - 1))
|
|
|
|
#define ROOT_CLUSTER 0x7fffffff
|
|
|
|
|
|
|
|
static unsigned _free
|
|
|
|
extern unsigned _end
|
|
|
|
|
|
|
|
void init_alloc ():
|
|
|
|
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
|
|
|
|
|
|
|
|
char *alloc_space (unsigned pages):
|
|
|
|
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
|
|
|
|
_free = ret + (pages << PAGE_BITS)
|
|
|
|
return (char *)ret
|
|
|
|
|
|
|
|
void *operator new[] (unsigned size):
|
|
|
|
//kdebug ("new ")
|
|
|
|
void *ret = (void *)_free
|
|
|
|
size = (size + 3) & ~3
|
|
|
|
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
|
|
|
|
if rest < size:
|
|
|
|
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
|
|
|
|
for unsigned p = 0; p < pages; ++p:
|
|
|
|
Iris::Page page = Iris::my_memory.create_page ()
|
2010-06-22 21:55:02 +03:00
|
|
|
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
2010-06-07 00:03:25 +03:00
|
|
|
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
|
|
|
|
Iris::free_cap (page)
|
|
|
|
_free += size
|
|
|
|
//kdebug_num ((unsigned)ret)
|
|
|
|
//kdebug ("+")
|
|
|
|
//kdebug_num (size)
|
|
|
|
//kdebug ("\n")
|
|
|
|
return ret
|
|
|
|
|
|
|
|
void *operator new (unsigned size):
|
|
|
|
return new char[size]
|
|
|
|
|
|
|
|
static Iris::WString dev
|
|
|
|
static Iris::Num device_size
|
|
|
|
static Iris::Page page
|
|
|
|
static char *data
|
|
|
|
static Iris::Num current_block
|
|
|
|
static void read_block (Iris::Num idx, Iris::Page p = page, unsigned size = 1 << SECTOR_BITS, unsigned offset = 0):
|
|
|
|
if p.code == page.code:
|
|
|
|
if idx.value () == current_block.value () && offset == 0 && size == 1 << SECTOR_BITS:
|
|
|
|
return
|
|
|
|
current_block = idx
|
|
|
|
//kdebug ("fat getting block: ")
|
|
|
|
//kdebug_num (idx.h)
|
|
|
|
//kdebug (":")
|
|
|
|
//kdebug_num (idx.l)
|
|
|
|
//kdebug ("+")
|
|
|
|
//kdebug_num (size)
|
|
|
|
//kdebug ("@")
|
|
|
|
//kdebug_num (offset)
|
|
|
|
//kdebug ("\n")
|
|
|
|
dev.get_block (idx, size, offset, p)
|
|
|
|
|
|
|
|
struct Fat:
|
|
|
|
char oem[8]
|
|
|
|
unsigned sector_size_bits
|
|
|
|
unsigned sectors_per_cluster_bits
|
|
|
|
unsigned reserved_sectors
|
|
|
|
unsigned num_fats
|
|
|
|
unsigned root_entries
|
|
|
|
unsigned sectors
|
|
|
|
unsigned media
|
|
|
|
unsigned sectors_per_fat
|
|
|
|
unsigned sectors_per_track
|
|
|
|
unsigned heads
|
|
|
|
unsigned hidden_sectors
|
|
|
|
unsigned active_fat
|
|
|
|
bool write_all_fats
|
|
|
|
unsigned fs_version
|
|
|
|
unsigned root_cluster
|
|
|
|
unsigned fsinfo_sector
|
|
|
|
unsigned boot_backup_sector
|
|
|
|
unsigned drive
|
|
|
|
unsigned current_head
|
|
|
|
unsigned volume_id
|
|
|
|
char label[0xb]
|
|
|
|
|
|
|
|
unsigned bits
|
|
|
|
unsigned clusters
|
|
|
|
unsigned cluster_size_bits
|
|
|
|
unsigned root_sectors
|
|
|
|
unsigned header_sectors
|
|
|
|
unsigned bad_clusters
|
|
|
|
|
|
|
|
unsigned free_clusters
|
|
|
|
unsigned last_alloced
|
|
|
|
|
|
|
|
unsigned *fat
|
|
|
|
unsigned first_free_cluster, first_bad_cluster
|
|
|
|
|
|
|
|
void print_num (char const *pre, unsigned data):
|
|
|
|
kdebug ("\t")
|
|
|
|
kdebug (pre)
|
|
|
|
unsigned bytes = 1
|
|
|
|
while bytes < 8 && data >> (bytes * 4):
|
|
|
|
++bytes
|
|
|
|
kdebug_num (data, bytes)
|
|
|
|
kdebug ("\n")
|
|
|
|
|
|
|
|
void print_br ():
|
|
|
|
kdebug ("\tOEM: '")
|
|
|
|
for unsigned i = 0; i < 8; ++i:
|
|
|
|
kdebug_char (oem[i])
|
|
|
|
kdebug ("'\n")
|
|
|
|
print_num ("bytes per sector: ", 1 << sector_size_bits)
|
|
|
|
print_num ("sectors per cluster: ", 1 << sectors_per_cluster_bits)
|
|
|
|
print_num ("reserved sectors: ", reserved_sectors)
|
|
|
|
print_num ("number of fats: ", num_fats)
|
|
|
|
print_num ("entries in root directory: ", root_entries)
|
|
|
|
print_num ("sectors: ", sectors)
|
|
|
|
print_num ("media descriptor: ", media)
|
|
|
|
print_num ("sectors per fat: ", sectors_per_fat)
|
|
|
|
print_num ("sectors per track: ", sectors_per_track)
|
|
|
|
print_num ("heads: ", heads)
|
|
|
|
print_num ("hidden sectors: ", hidden_sectors)
|
|
|
|
print_num ("active_fat: ", active_fat)
|
|
|
|
kdebug ("\twrite all: ")
|
|
|
|
kdebug (write_all_fats ? "yes\n" : "no\n")
|
|
|
|
print_num ("fs version: ", fs_version)
|
|
|
|
print_num ("root cluster: ", root_cluster)
|
|
|
|
print_num ("fsinfo sector: ", fsinfo_sector)
|
|
|
|
print_num ("boot sector backup sector: ", boot_backup_sector)
|
|
|
|
print_num ("drive: ", drive)
|
|
|
|
print_num ("current head: ", current_head)
|
|
|
|
print_num ("volume id: ", volume_id)
|
|
|
|
kdebug ("\tlabel: '")
|
|
|
|
for unsigned i = 0; i < 0xb; ++i:
|
|
|
|
kdebug_char (label[i])
|
|
|
|
kdebug ("'\n")
|
|
|
|
print_num ("bits: ", bits)
|
|
|
|
print_num ("clusters: ", clusters)
|
|
|
|
print_num ("header sectors: ", header_sectors)
|
|
|
|
|
|
|
|
unsigned read_num (char *data, unsigned bytes):
|
|
|
|
unsigned ret = 0
|
|
|
|
for unsigned i = 0; i < bytes; ++i:
|
|
|
|
ret |= (data[i] & 0xff) << (i * 8)
|
|
|
|
return ret
|
|
|
|
|
|
|
|
void map_fat_cluster (unsigned c, unsigned offset = 0):
|
2010-06-22 21:55:02 +03:00
|
|
|
//unsigned b = current_block.l
|
|
|
|
read_block ((reserved_sectors + ((c * bits + 8 * offset) >> (sector_size_bits + 3))) << sector_size_bits)
|
|
|
|
//if b != current_block.l:
|
|
|
|
//for unsigned i = 0; i < 0x20; ++i:
|
|
|
|
//kdebug (" ")
|
|
|
|
//kdebug_num (data[i], 2)
|
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
|
|
|
|
unsigned make_bits (unsigned orig):
|
|
|
|
unsigned ret
|
|
|
|
for ret = 0; ret < 32; ++ret:
|
|
|
|
if orig == 1 << ret:
|
|
|
|
return ret
|
2010-06-22 21:55:02 +03:00
|
|
|
//Iris::panic (orig, "non-power of 2")
|
|
|
|
kdebug ("not a power of two, using 16\n")
|
|
|
|
return 16
|
2010-06-07 00:03:25 +03:00
|
|
|
|
|
|
|
void reset ():
|
|
|
|
read_block (0)
|
|
|
|
if data[0x1fe] != 0x55 || (data[0x1ff] & 0xff) != 0xaa:
|
|
|
|
kdebug ("invalid boot record signature in fat device\n")
|
|
|
|
for unsigned i = 0; i < 8; ++i:
|
|
|
|
oem[i] = data[3 + i]
|
|
|
|
sector_size_bits = make_bits (read_num (data + 0xb, 2))
|
|
|
|
sectors_per_cluster_bits = make_bits (read_num (data + 0xd, 1))
|
|
|
|
cluster_size_bits = sector_size_bits + sectors_per_cluster_bits
|
|
|
|
reserved_sectors = read_num (data + 0xe, 2)
|
|
|
|
num_fats = read_num (data + 0x10, 1)
|
|
|
|
root_entries = read_num (data + 0x11, 2)
|
|
|
|
sectors = read_num (data + 0x13, 2)
|
|
|
|
media = read_num (data + 0x15, 1)
|
|
|
|
sectors_per_fat = read_num (data + 0x16, 2)
|
|
|
|
sectors_per_track = read_num (data + 0x18, 2)
|
|
|
|
heads = read_num (data + 0x1a, 2)
|
|
|
|
hidden_sectors = read_num (data + 0x1c, 4)
|
|
|
|
if !sectors:
|
|
|
|
sectors = read_num (data + 0x20, 4)
|
|
|
|
if Iris::Num (sectors).value () << sector_size_bits > device_size.value ():
|
|
|
|
sectors = device_size.value () >> sector_size_bits
|
|
|
|
kdebug ("warning: limiting sectors because of limited device size\n")
|
|
|
|
|
|
|
|
root_sectors = (root_entries * 32 + (1 << sector_size_bits) - 1) >> sector_size_bits
|
2010-06-22 21:55:02 +03:00
|
|
|
header_sectors = reserved_sectors + sectors_per_fat * num_fats + root_sectors
|
2010-06-07 00:03:25 +03:00
|
|
|
clusters = (sectors - header_sectors) >> sectors_per_cluster_bits
|
|
|
|
unsigned skip
|
|
|
|
if clusters >= 65525:
|
|
|
|
bits = 32
|
|
|
|
sectors_per_fat = read_num (data + 0x24, 4)
|
|
|
|
active_fat = read_num (data + 0x28, 2)
|
|
|
|
write_all_fats = active_fat & 0x80
|
|
|
|
active_fat &= 0xf
|
|
|
|
fs_version = read_num (data + 0x2a, 2)
|
|
|
|
root_cluster = read_num (data + 0x2c, 4)
|
|
|
|
fsinfo_sector = read_num (data + 0x30, 2)
|
|
|
|
boot_backup_sector = read_num (data + 0x32, 2)
|
|
|
|
skip = 0x40 - 0x24
|
|
|
|
else:
|
|
|
|
if clusters < 4085:
|
|
|
|
bits = 12
|
|
|
|
else:
|
|
|
|
bits = 16
|
|
|
|
skip = 0
|
|
|
|
active_fat = 0
|
|
|
|
write_all_fats = true
|
|
|
|
fs_version = 0
|
|
|
|
root_cluster = 0
|
|
|
|
fsinfo_sector = 0
|
|
|
|
boot_backup_sector = 0
|
|
|
|
unsigned fat_entries_per_sector = (8 << sector_size_bits) / bits
|
|
|
|
unsigned fat_entries = sectors_per_fat * fat_entries_per_sector
|
|
|
|
if clusters + 2 > fat_entries:
|
|
|
|
clusters = fat_entries - 2
|
|
|
|
kdebug ("warning: limiting clusters because of limited sector count\n")
|
|
|
|
drive = read_num (data + skip + 0x24, 1)
|
|
|
|
current_head = read_num (data + skip + 0x25, 1)
|
|
|
|
if data[skip + 0x26] == 0x29:
|
|
|
|
volume_id = read_num (data + skip + 0x27, 4)
|
|
|
|
for unsigned i = 0; i < 0xb; ++i:
|
|
|
|
label[i] = data[skip + 0x2b + i]
|
|
|
|
char *id = data + skip + 0x36
|
|
|
|
if id[0] != 'F' || id[1] != 'A' || id[2] != 'T' || id[5] != ' ' || id[6] != ' ' || id[7] != ' ':
|
|
|
|
kdebug ("warning: file system type field was not 'FATxx '\n")
|
|
|
|
else:
|
|
|
|
switch bits:
|
|
|
|
case 12:
|
|
|
|
if id[3] != '1' || id[4] != '2':
|
|
|
|
kdebug ("warning: id for fat12 is not FAT12\n")
|
|
|
|
break
|
|
|
|
case 16:
|
|
|
|
if id[3] != '1' || id[4] != '6':
|
|
|
|
kdebug ("warning: id for fat16 is not FAT16\n")
|
|
|
|
break
|
|
|
|
case 32:
|
|
|
|
if id[3] != '3' || id[4] != '2':
|
|
|
|
kdebug ("warning: id for fat32 wat not FAT32")
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
volume_id = 0
|
|
|
|
for unsigned i = 0; i < 0xb; ++i:
|
|
|
|
label[i] = 0
|
|
|
|
if fsinfo_sector:
|
|
|
|
read_block (fsinfo_sector << sector_size_bits)
|
|
|
|
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:
|
|
|
|
kdebug ("invalid signature in fsinfo structure\n")
|
|
|
|
free_clusters = read_num (data + 0x1e8, 4)
|
|
|
|
last_alloced = read_num (data + 0x1ec, 4)
|
|
|
|
else:
|
|
|
|
free_clusters = ~0
|
|
|
|
last_alloced = ~0
|
|
|
|
|
|
|
|
// Now read the FAT.
|
|
|
|
bad_clusters = 0
|
|
|
|
fat = new unsigned[clusters]
|
|
|
|
unsigned counted_free_clusters = 0
|
2010-06-22 21:55:02 +03:00
|
|
|
first_free_cluster = ~0
|
2010-06-07 00:03:25 +03:00
|
|
|
for unsigned c = 0; c < clusters; ++c:
|
|
|
|
// reduced cluster.
|
|
|
|
unsigned rc = c & (1 << sector_size_bits) - 1
|
|
|
|
// The next line does nothing most of the time.
|
|
|
|
map_fat_cluster (c)
|
|
|
|
switch bits:
|
|
|
|
case 12:
|
|
|
|
fat[c] = data[(rc + 2) * 2] & 0xff
|
|
|
|
// There may be a sector boundary in the middle of the entry, so optionally reread.
|
|
|
|
map_fat_cluster (c, 1)
|
|
|
|
fat[c] |= (data[(rc + 2) * 2 + 1] & 0xff) << 8
|
|
|
|
if c & 1:
|
|
|
|
fat[c] >>= 4
|
|
|
|
else:
|
|
|
|
fat[c] &= 0xfff
|
|
|
|
break
|
|
|
|
case 16:
|
|
|
|
fat[c] = read_num (data + (rc + 2) * 2, 2)
|
|
|
|
break
|
|
|
|
case 32:
|
|
|
|
fat[c] = read_num (data + (rc + 2) * 4, 4)
|
|
|
|
break
|
|
|
|
// Correct for the crazy +2 offset, and keep a list of bad and free clusters.
|
|
|
|
if fat[c] == 0:
|
|
|
|
// Free cluster.
|
|
|
|
fat[c] = first_free_cluster
|
|
|
|
first_free_cluster = c
|
|
|
|
++counted_free_clusters
|
|
|
|
else if fat[c] == 1:
|
|
|
|
// Invalid value.
|
|
|
|
Iris::panic (0, "entry is '1' in fat.")
|
|
|
|
else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff:
|
|
|
|
// Last cluster in chain.
|
|
|
|
fat[c] = ~0
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug ("last cluster: ")
|
|
|
|
//kdebug_num (c)
|
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7:
|
|
|
|
// Bad cluster.
|
|
|
|
fat[c] = first_bad_cluster
|
|
|
|
first_bad_cluster = c
|
|
|
|
++bad_clusters
|
|
|
|
else:
|
|
|
|
// Non-last cluster in chain.
|
|
|
|
fat[c] -= 2
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug_num (c)
|
|
|
|
//kdebug (" -> ")
|
|
|
|
//kdebug_num (fat[c])
|
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
unsigned fat_lookup (unsigned first_cluster, unsigned cluster):
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("looking up ")
|
|
|
|
//kdebug_num (first_cluster)
|
|
|
|
//kdebug ("+")
|
|
|
|
//kdebug_num (cluster)
|
|
|
|
//kdebug (":")
|
2010-06-07 00:03:25 +03:00
|
|
|
while cluster--:
|
|
|
|
first_cluster = fat[first_cluster]
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("->")
|
|
|
|
//kdebug_num (first_cluster)
|
2010-06-07 00:03:25 +03:00
|
|
|
if first_cluster == ~0:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("sector beyond end of file requested\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
return ~0
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
return first_cluster
|
|
|
|
struct File:
|
|
|
|
Fat *fat
|
|
|
|
unsigned size
|
|
|
|
unsigned first_cluster
|
|
|
|
char name[11]
|
|
|
|
bool archive, readonly, system, hidden, directory, volume
|
|
|
|
unsigned create_second, create_minute_hour, create_date, access_date, time, date
|
2010-06-22 21:55:02 +03:00
|
|
|
unsigned checksum
|
2010-07-08 13:38:36 +03:00
|
|
|
void load_cluster (unsigned idx, unsigned offset_in_cluster, Iris::Page p = page, unsigned offset = 0):
|
2010-06-07 00:03:25 +03:00
|
|
|
unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits)
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("loading cluster ")
|
|
|
|
//kdebug_num (idx)
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug ("+")
|
|
|
|
//kdebug_num (offset_in_cluster)
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("@")
|
|
|
|
//kdebug_num (cluster)
|
|
|
|
//kdebug (" from file\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
if cluster == ~0:
|
|
|
|
kdebug ("invalid cluster requested from file\n")
|
|
|
|
return
|
2010-07-08 13:38:36 +03:00
|
|
|
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)
|
2010-06-22 21:55:02 +03:00
|
|
|
char *load_dir_entry (unsigned dir, unsigned idx):
|
2010-06-07 00:03:25 +03:00
|
|
|
unsigned sector = idx >> (sector_size_bits - 5)
|
|
|
|
unsigned num = (idx << 5) & ~BLOCK_MASK
|
|
|
|
Iris::Num hwsector
|
|
|
|
if dir == ROOT_CLUSTER:
|
|
|
|
if sector < root_sectors:
|
|
|
|
hwsector = header_sectors - root_sectors + sector
|
|
|
|
else:
|
2010-06-22 21:55:02 +03:00
|
|
|
return NULL
|
2010-06-07 00:03:25 +03:00
|
|
|
else:
|
|
|
|
unsigned entry = fat_lookup (dir, sector)
|
|
|
|
if entry == ~0:
|
2010-06-22 21:55:02 +03:00
|
|
|
return NULL
|
|
|
|
hwsector = header_sectors + (Iris::Num (entry).value () << sectors_per_cluster_bits)
|
2010-06-07 00:03:25 +03:00
|
|
|
read_block (hwsector.value () << sector_size_bits)
|
2010-06-22 21:55:02 +03:00
|
|
|
return &data[num]
|
|
|
|
char *find_idx (unsigned dir, unsigned *idx, unsigned *count = NULL):
|
|
|
|
unsigned todo = *idx + 1
|
|
|
|
char *e
|
|
|
|
if count:
|
|
|
|
*count = 0
|
|
|
|
for *idx = 0; todo; ++*idx:
|
|
|
|
e = load_dir_entry (dir, *idx)
|
|
|
|
if !e:
|
|
|
|
return NULL
|
|
|
|
if (e[0xb] & 0xff) == 0xf:
|
|
|
|
// This is part of a long filename.
|
|
|
|
continue
|
|
|
|
if (e[0] & 0xff) == 0xe5:
|
|
|
|
// This is a deleted file.
|
|
|
|
continue
|
|
|
|
if !e[0]:
|
|
|
|
// This is a free entry.
|
|
|
|
continue
|
|
|
|
if count:
|
|
|
|
++*count
|
|
|
|
--todo
|
|
|
|
--*idx
|
|
|
|
return e
|
|
|
|
unsigned get_dir_size (unsigned dir):
|
|
|
|
unsigned num = 0 - 2
|
|
|
|
unsigned ret
|
|
|
|
find_idx (dir, &num, &ret)
|
|
|
|
return ret
|
|
|
|
bool get_dir_entry (unsigned dir, unsigned idx, File *f):
|
|
|
|
char *e = load_dir_entry (dir, idx)
|
|
|
|
if !e:
|
|
|
|
kdebug ("unable to load dir entry\n")
|
|
|
|
return false
|
|
|
|
f->fat = this
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug ("loading dir entry for ")
|
2010-06-07 00:03:25 +03:00
|
|
|
for unsigned i = 0; i < 11; ++i:
|
|
|
|
f->name[i] = e[i]
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug_char (f->name[i])
|
|
|
|
//kdebug ("\n")
|
2010-06-22 21:55:02 +03:00
|
|
|
f->readonly = e[0xb] & 0x1
|
|
|
|
f->system = e[0xb] & 0x2
|
2010-06-07 00:03:25 +03:00
|
|
|
f->hidden = e[0xb] & 0x4
|
2010-06-22 21:55:02 +03:00
|
|
|
f->volume = e[0xb] & 0x8
|
|
|
|
f->directory = e[0xb] & 0x10
|
|
|
|
f->archive = e[0xb] & 0x20
|
2010-06-07 00:03:25 +03:00
|
|
|
f->create_second = read_num (e + 0xd, 1)
|
|
|
|
f->create_minute_hour = read_num (e + 0xe, 2)
|
|
|
|
f->create_date = read_num (e + 0x10, 2)
|
|
|
|
f->access_date = read_num (e + 0x12, 2)
|
|
|
|
f->time = read_num (e + 0x16, 1)
|
|
|
|
f->date = read_num (e + 0x18, 1)
|
|
|
|
f->size = read_num (e + 0x1c, 4)
|
|
|
|
f->first_cluster = (read_num (e + 0x14, 2) << 16 | read_num (e + 0x1a, 2)) - 2
|
2010-06-22 21:55:02 +03:00
|
|
|
f->checksum = 0
|
|
|
|
for unsigned i = 0; i < 11; ++i:
|
|
|
|
f->checksum = ((((f->checksum & 1) << 7) | ((f->checksum & 0xfe) >> 1)) + f->name[i]) & 0xff
|
|
|
|
//kdebug ("loaded dir entry, first cluster = ")
|
|
|
|
//kdebug_num (f->first_cluster)
|
|
|
|
//kdebug ("\n")
|
|
|
|
return true
|
|
|
|
struct LFN:
|
|
|
|
unsigned ordinal
|
|
|
|
unsigned name[13]
|
|
|
|
unsigned checksum
|
|
|
|
bool load_lfn (unsigned dir, unsigned idx, unsigned t, unsigned checksum, LFN *lfn):
|
|
|
|
if t >= idx:
|
|
|
|
return false
|
|
|
|
char *e = load_dir_entry (dir, idx - t - 1)
|
|
|
|
if (e[0xb] & 0xff) != 0xf:
|
|
|
|
return false
|
|
|
|
lfn->ordinal = read_num (e + 0x00, 1)
|
|
|
|
for unsigned i = 0; i < 5; ++i:
|
|
|
|
lfn->name[i] = read_num (e + 0x01 + 2 * i, 2)
|
|
|
|
lfn->checksum = read_num (e + 0xd, 1)
|
|
|
|
for unsigned i = 0; i < 6; ++i:
|
|
|
|
lfn->name[i + 5] = read_num (e + 0xe + 2 * i, 2)
|
|
|
|
for unsigned i = 0; i < 2; ++i:
|
|
|
|
lfn->name[i + 11] = read_num (e + 0x1c + 2 * i, 2)
|
|
|
|
return true
|
|
|
|
unsigned parse_shortname (File const &f, char *name):
|
|
|
|
if f.name[0] == ' ':
|
|
|
|
Iris::panic (0, "fat name starts with space")
|
|
|
|
unsigned len = 8
|
|
|
|
while f.name[len - 1] == ' ':
|
|
|
|
--len
|
|
|
|
char *ptr = name
|
|
|
|
for unsigned i = 0; i < len; ++i:
|
|
|
|
*ptr++ = f.name[i]
|
|
|
|
if f.name[8] == ' ':
|
|
|
|
return len
|
|
|
|
*ptr++ = '.'
|
|
|
|
len = 3
|
|
|
|
while f.name[8 + len - 1] == ' ':
|
|
|
|
--len
|
|
|
|
for unsigned i = 0; i < len; ++i:
|
|
|
|
*ptr++ = f.name[8 + i]
|
|
|
|
return ptr - name
|
|
|
|
unsigned get_name_size (unsigned dir, unsigned idx, File const &f):
|
|
|
|
LFN lfn
|
|
|
|
unsigned num = 0
|
|
|
|
if !load_lfn (dir, idx, 0, f.checksum, &lfn):
|
|
|
|
// Not a long filename.
|
|
|
|
char n[12]
|
|
|
|
return parse_shortname (f, n)
|
|
|
|
unsigned ordinal = 0
|
|
|
|
while true:
|
|
|
|
if !load_lfn (dir, idx, num, f.checksum, &lfn):
|
|
|
|
Iris::panic (0, "error parsing long filename")
|
|
|
|
if (lfn.ordinal & 0x3f) != ++ordinal:
|
|
|
|
Iris::panic (lfn.ordinal, "error in sequence for long filename")
|
|
|
|
if lfn.ordinal & 0x40:
|
|
|
|
break
|
|
|
|
++num
|
|
|
|
unsigned i
|
|
|
|
for i = 0; i < 13; ++i:
|
|
|
|
if !lfn.name[i]:
|
|
|
|
break
|
|
|
|
return num * 13 + i
|
2010-06-07 00:03:25 +03:00
|
|
|
|
|
|
|
// Capability encoding.
|
|
|
|
// 0:ROOT_CLUSTER = non fat-32 root directory.
|
|
|
|
// 0:cluster = other directory.
|
|
|
|
// cluster:index = file index from directory at cluster.
|
|
|
|
// cluster|0x80000000:index = filename for file with index from directory at cluster.
|
|
|
|
|
|
|
|
Iris::Num start ():
|
|
|
|
init_alloc ()
|
|
|
|
current_block = ~0
|
|
|
|
dev = Iris::my_parent.get_capability <Iris::WString> ()
|
|
|
|
if dev.get_align_bits () > SECTOR_BITS:
|
|
|
|
kdebug ("fat device doesn't support 512 byte access")
|
|
|
|
return 1
|
|
|
|
device_size = dev.get_size ()
|
|
|
|
data = (char *)0x15000; //alloc_space (1)
|
|
|
|
page = Iris::my_memory.create_page ()
|
2010-06-22 21:55:02 +03:00
|
|
|
page.set_flags (Iris::Page::PAYING)
|
2010-06-07 00:03:25 +03:00
|
|
|
Iris::my_memory.map (page, (unsigned)data)
|
|
|
|
|
|
|
|
Fat fat
|
|
|
|
|
|
|
|
fat.reset ()
|
|
|
|
fat.print_br ()
|
|
|
|
|
|
|
|
Iris::Cap root
|
|
|
|
if fat.root_cluster:
|
|
|
|
root = Iris::my_receiver.create_capability (Iris::Num (fat.root_cluster, 0))
|
|
|
|
else:
|
|
|
|
root = Iris::my_receiver.create_capability (Iris::Num (ROOT_CLUSTER, 0))
|
|
|
|
|
|
|
|
Iris::my_parent.provide_capability <Iris::Directory> (root.copy ())
|
|
|
|
Iris::free_cap (root)
|
|
|
|
|
|
|
|
while true:
|
|
|
|
Iris::wait ()
|
|
|
|
unsigned dir = Iris::recv.protected_data.h
|
|
|
|
if dir & 0x80000000:
|
2010-06-22 21:55:02 +03:00
|
|
|
dir &= ~0x80000000
|
2010-06-07 00:03:25 +03:00
|
|
|
// File name.
|
|
|
|
unsigned idx = Iris::recv.protected_data.l
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
unsigned num = Iris::recv.data[1].l
|
|
|
|
unsigned size = Iris::recv.data[0].h >> 16
|
|
|
|
unsigned cmd = Iris::recv.data[0].l
|
|
|
|
Fat::File f
|
2010-06-22 21:55:02 +03:00
|
|
|
if !fat.find_idx (dir, &idx):
|
|
|
|
Iris::panic (Iris::recv.protected_data.l, "invalid index")
|
|
|
|
if !fat.get_dir_entry (dir, idx, &f):
|
|
|
|
Iris::panic (Iris::recv.protected_data.l, "invalid dir entry requested for filename")
|
2010-06-07 00:03:25 +03:00
|
|
|
switch cmd:
|
|
|
|
case Iris::String::GET_SIZE:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("filename size requested\n")
|
|
|
|
reply.invoke (fat.get_name_size (dir, idx, f))
|
2010-06-07 00:03:25 +03:00
|
|
|
break
|
|
|
|
case Iris::String::GET_CHARS:
|
|
|
|
//kdebug ("filename chars requested\n")
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("flags: ")
|
|
|
|
//kdebug_char (f.readonly ? 'R' : 'r')
|
|
|
|
//kdebug_char (f.system ? 'S' : 's')
|
|
|
|
//kdebug_char (f.hidden ? 'H' : 'h')
|
|
|
|
//kdebug_char (f.volume ? 'V' : 'v')
|
|
|
|
//kdebug_char (f.directory ? 'D' : 'd')
|
|
|
|
//kdebug_char (f.archive ? 'A' : 'a')
|
|
|
|
//kdebug_char ('\n')
|
|
|
|
|
2010-06-07 00:03:25 +03:00
|
|
|
/**/union { unsigned u[4]; char c[16]; } u
|
|
|
|
for unsigned k = 0; k < 4; ++k:
|
|
|
|
u.u[k] = 0
|
2010-06-22 21:55:02 +03:00
|
|
|
Fat::LFN lfn
|
|
|
|
if !fat.load_lfn (dir, idx, 0, f.checksum, &lfn):
|
|
|
|
// Not a long filename.
|
|
|
|
char n[12]
|
|
|
|
unsigned len = fat.parse_shortname (f, n)
|
|
|
|
//kdebug ("short filename: ")
|
|
|
|
for unsigned k = 0; k + num < len; ++k:
|
|
|
|
u.c[k] = n[k + num]
|
|
|
|
//kdebug_char (u.c[k])
|
|
|
|
//kdebug ("\n")
|
|
|
|
else:
|
|
|
|
// Very inefficient, but it works: reload everything for every character.
|
|
|
|
//kdebug ("filename: ")
|
|
|
|
for unsigned c = 0; c < 16; ++c:
|
|
|
|
if !fat.load_lfn (dir, idx, (num + c) / 13, f.checksum, &lfn):
|
|
|
|
// Filename isn't this long: keep the rest at 0.
|
|
|
|
break
|
|
|
|
u.c[c] = lfn.name[(num + c) % 13]
|
|
|
|
if u.c[c] == 0:
|
|
|
|
break
|
|
|
|
//kdebug_char (u.c[c])
|
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
reply.invoke (Iris::Num (u.u[0], u.u[1]), Iris::Num (u.u[2], u.u[3]))
|
|
|
|
break
|
|
|
|
case Iris::String::GET_ALIGN_BITS:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("filename align requested\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
reply.invoke (0)
|
|
|
|
break
|
|
|
|
case Iris::String::GET_BLOCK:
|
|
|
|
default:
|
|
|
|
Iris::panic (Iris::recv.data[0].l, "invalid request for fat filename")
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
else if dir:
|
2010-06-22 21:55:02 +03:00
|
|
|
// If it *has* a directory, it *is* a file.
|
2010-06-07 00:03:25 +03:00
|
|
|
unsigned idx = Iris::recv.protected_data.l
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
Iris::Cap arg = Iris::get_arg ()
|
|
|
|
Iris::Num num = Iris::recv.data[1]
|
|
|
|
unsigned size = Iris::recv.data[0].h >> 16
|
|
|
|
unsigned offset = Iris::recv.data[0].h & 0xffff
|
|
|
|
unsigned cmd = Iris::recv.data[0].l
|
|
|
|
Fat::File f
|
|
|
|
fat.get_dir_entry (dir, idx, &f)
|
|
|
|
switch cmd:
|
|
|
|
case Iris::String::GET_SIZE:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("file size requested\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
reply.invoke (f.size)
|
|
|
|
break
|
|
|
|
case Iris::String::GET_CHARS:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("file chars requested\n")
|
2010-07-08 13:38:36 +03:00
|
|
|
unsigned mask = (1 << fat.cluster_size_bits) - 1
|
|
|
|
f.load_cluster (num.l & ~mask, num.l & mask)
|
2010-06-07 00:03:25 +03:00
|
|
|
unsigned n = num.l & mask & ~0xf
|
|
|
|
unsigned *dat = (unsigned *)(data + n)
|
|
|
|
reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3]))
|
|
|
|
break
|
|
|
|
case Iris::String::GET_ALIGN_BITS:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("file align requested\n")
|
2010-07-08 13:38:36 +03:00
|
|
|
reply.invoke (fat.cluster_size_bits <= PAGE_BITS ? fat.cluster_size_bits : PAGE_BITS)
|
2010-06-07 00:03:25 +03:00
|
|
|
break
|
|
|
|
case Iris::String::GET_BLOCK:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("file block requested\n")
|
2010-07-08 13:38:36 +03:00
|
|
|
unsigned mask = (1 << fat.cluster_size_bits) - 1
|
|
|
|
//kdebug ("mask = ")
|
|
|
|
//kdebug_num (mask)
|
|
|
|
//kdebug ("\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
if offset > PAGE_SIZE:
|
2010-06-22 21:55:02 +03:00
|
|
|
//kdebug ("invalid offset requested\n")
|
2010-06-07 00:03:25 +03:00
|
|
|
break
|
|
|
|
if size + offset > PAGE_SIZE:
|
2010-07-08 13:38:36 +03:00
|
|
|
Iris::panic (size, "invalid size requested")
|
2010-06-07 00:03:25 +03:00
|
|
|
size = PAGE_SIZE - offset
|
|
|
|
for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits:
|
2010-07-08 13:38:36 +03:00
|
|
|
f.load_cluster ((num.l & ~mask) + i, num.l & mask, arg, i + offset)
|
2010-06-07 00:03:25 +03:00
|
|
|
reply.invoke ()
|
|
|
|
break
|
|
|
|
case Iris::WString::TRUNCATE:
|
|
|
|
case Iris::WString::SET_CHARS:
|
|
|
|
case Iris::WString::SET_BLOCK:
|
|
|
|
Iris::panic (Iris::recv.data[0].l, "writing to files not supported yet")
|
|
|
|
default:
|
|
|
|
Iris::panic (Iris::recv.data[0].l, "invalid request for fat file")
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
Iris::free_cap (arg)
|
|
|
|
else:
|
|
|
|
// Directory.
|
2010-06-22 21:55:02 +03:00
|
|
|
switch Iris::recv.data[0].l:
|
|
|
|
case Iris::Directory::GET_SIZE:
|
|
|
|
//kdebug ("dir size requested\n")
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
reply.invoke (fat.get_dir_size (Iris::recv.protected_data.l))
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
break
|
|
|
|
case Iris::Directory::GET_NAME:
|
|
|
|
//kdebug ("dir name requested\n")
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
Iris::Cap ret = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, Iris::recv.protected_data.l | 0x80000000))
|
|
|
|
reply.invoke (0, 0, ret.copy ())
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
Iris::free_cap (ret)
|
|
|
|
break
|
|
|
|
case Iris::Directory::GET_FILE_RO:
|
|
|
|
//kdebug ("dir file requested\n")
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
dir = Iris::recv.protected_data.l
|
|
|
|
unsigned idx = Iris::recv.data[1].l
|
2010-07-08 13:38:36 +03:00
|
|
|
unsigned oldidx = idx
|
2010-06-22 21:55:02 +03:00
|
|
|
if !fat.find_idx (dir, &idx):
|
2010-07-08 13:38:36 +03:00
|
|
|
kdebug_num (oldidx)
|
|
|
|
kdebug ("\n")
|
|
|
|
Iris::panic (1, "file not found")
|
2010-06-22 21:55:02 +03:00
|
|
|
Fat::File f
|
|
|
|
fat.get_dir_entry (dir, idx, &f)
|
|
|
|
Iris::Cap ret
|
|
|
|
if f.directory:
|
2010-07-08 13:38:36 +03:00
|
|
|
//kdebug ("dir provided: ")
|
|
|
|
//kdebug_num (f.first_cluster)
|
|
|
|
//kdebug ("\n")
|
2010-06-22 21:55:02 +03:00
|
|
|
ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0))
|
|
|
|
else:
|
|
|
|
ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir))
|
|
|
|
reply.invoke (0, 0, ret.copy ())
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
Iris::free_cap (ret)
|
|
|
|
break
|
|
|
|
case Iris::Directory::GET_FILE_INFO:
|
|
|
|
//kdebug ("dir file info requested\n")
|
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
dir = Iris::recv.protected_data.l
|
|
|
|
unsigned idx = Iris::recv.data[1].l
|
2010-07-08 13:38:36 +03:00
|
|
|
unsigned oldidx = idx
|
2010-06-22 21:55:02 +03:00
|
|
|
if !fat.find_idx (dir, &idx):
|
2010-07-08 13:38:36 +03:00
|
|
|
kdebug_num (oldidx)
|
|
|
|
kdebug ("\n")
|
|
|
|
Iris::panic (2, "file not found")
|
2010-06-22 21:55:02 +03:00
|
|
|
unsigned type = Iris::recv.data[0].h
|
|
|
|
Fat::File f
|
|
|
|
fat.get_dir_entry (dir, idx, &f)
|
|
|
|
reply.invoke (f.directory ? 1 : 0)
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
break
|
|
|
|
case Iris::Directory::LOCK_RO:
|
|
|
|
case Iris::Directory::UNLOCK_RO:
|
|
|
|
//kdebug ("dir lock or unlock requested\n")
|
|
|
|
Iris::recv.reply.invoke ()
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
//kdebug ("invalid dir operation requested\n")
|
|
|
|
Iris::recv.reply.invoke ()
|
|
|
|
break
|