Warning, cross-references for /kernel/fs/vfat/fsys_vfat.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 #include "fs/filesys.h"
0040 #include "drivers/usb/umsc.h"
0041 #include "arch/i386.h"
0042 #include "util/printf.h"
0043 #include "types.h"
0044
0045
0046 #ifdef DEBUG_VFAT
0047 #define DLOG(fmt,...) DLOG_PREFIX("vfat",fmt,##__VA_ARGS__)
0048 #else
0049 #define DLOG(fmt,...) ;
0050 #endif
0051
0052 #define UMSC_DEVICE_INDEX 0
0053 #define VFAT_FIRST_PARTITION 63
0054
0055 static int
0056 devread_vfat (int sector, int byte_offset, int byte_len, char *buf)
0057 {
0058 uint8 s[512];
0059 int len = byte_len;
0060 sector+=VFAT_FIRST_PARTITION;
0061 DLOG ("fsys_vfat: devread_vfat (%d, %d, %d, %p)",
0062 sector, byte_offset, byte_len, buf);
0063 while (len > 0) {
0064 if (umsc_read_sector (UMSC_DEVICE_INDEX, sector, s, sizeof (s)) != sizeof (s))
0065 return 0;
0066 int seclen;
0067 if (len > sizeof (s) - byte_offset)
0068 seclen = sizeof (s) - byte_offset;
0069 else
0070 seclen = len;
0071 memcpy (buf, &s[byte_offset], seclen);
0072 len -= seclen;
0073 buf += seclen;
0074 sector++;
0075 byte_offset = 0;
0076 }
0077 return byte_len;
0078 }
0079
0080 static int
0081 tolower (int c)
0082 {
0083 if (c >= 'A' && c <= 'Z')
0084 return (c + ('a' - 'A'));
0085
0086 return c;
0087 }
0088
0089 static int
0090 isspace (int c)
0091 {
0092 switch (c)
0093 {
0094 case ' ':
0095 case '\t':
0096 case '\r':
0097 case '\n':
0098 return 1;
0099 default:
0100 break;
0101 }
0102
0103 return 0;
0104 }
0105
0106 static int
0107 substring (const char *s1, const char *s2)
0108 {
0109 while (*s1 == *s2)
0110 {
0111
0112 if (! *(s1++))
0113 return 0;
0114 s2 ++;
0115 }
0116
0117
0118 if (*s1 == 0)
0119 return -1;
0120
0121
0122 return 1;
0123 }
0124
0125 #ifndef NULL
0126 #define NULL ((void *)0)
0127 #endif
0128
0129 #define MAXINT 0x7FFFFFFF
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 typedef __signed__ char __s8;
0141 typedef unsigned char __u8;
0142 typedef __signed__ short __s16;
0143 typedef unsigned short __u16;
0144 typedef __signed__ int __s32;
0145 typedef unsigned int __u32;
0146
0147
0148
0149
0150 struct fat_bpb {
0151 __s8 ignored[3];
0152 __s8 system_id[8];
0153
0154 __u8 bytes_per_sect[2];
0155 __u8 sects_per_clust;
0156 __u8 reserved_sects[2];
0157 __u8 num_fats;
0158 __u8 dir_entries[2];
0159 __u8 short_sectors[2];
0160 __u8 media;
0161 __u16 fat_length;
0162 __u16 secs_track;
0163 __u16 heads;
0164 __u32 hidden;
0165 __u32 long_sectors;
0166
0167
0168 __u32 fat32_length;
0169 __u16 flags;
0170 __u8 version[2];
0171 __u32 root_cluster;
0172 __u16 info_sector;
0173 __u16 backup_boot;
0174 __u16 reserved2[6];
0175 };
0176
0177 #define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
0178
0179
0180
0181
0182
0183 #define FAT_MAX_12BIT_CLUST 4087
0184
0185
0186
0187
0188
0189 #define FAT_ATTRIB_OK_MASK 0x37
0190 #define FAT_ATTRIB_NOT_OK_MASK 0xC8
0191 #define FAT_ATTRIB_DIR 0x10
0192 #define FAT_ATTRIB_LONGNAME 0x0F
0193
0194
0195
0196
0197
0198 #define FAT_DIRENTRY_LENGTH 32
0199
0200 #define FAT_DIRENTRY_ATTRIB(entry) \
0201 (*((unsigned char *) (entry+11)))
0202 #define FAT_DIRENTRY_VALID(entry) \
0203 ( ((*((unsigned char *) entry)) != 0) \
0204 && ((*((unsigned char *) entry)) != 0xE5) \
0205 && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
0206 #define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
0207 ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
0208 #define FAT_DIRENTRY_FILELENGTH(entry) \
0209 (*((unsigned long *) (entry+28)))
0210
0211 #define FAT_LONGDIR_ID(entry) \
0212 (*((unsigned char *) (entry)))
0213 #define FAT_LONGDIR_ALIASCHECKSUM(entry) \
0214 (*((unsigned char *) (entry+13)))
0215
0216 struct fat_superblock
0217 {
0218 int fat_offset;
0219 int fat_length;
0220 int fat_size;
0221 int root_offset;
0222 int root_max;
0223 int data_offset;
0224
0225 int num_sectors;
0226 int num_clust;
0227 int clust_eof_marker;
0228 int sects_per_clust;
0229 int sectsize_bits;
0230 int clustsize_bits;
0231 int root_cluster;
0232
0233 int cached_fat;
0234 int file_cluster;
0235 int current_cluster_num;
0236 int current_cluster;
0237 };
0238
0239 static int errnum;
0240 static char fsys_buf[0x8000];
0241 static int filepos;
0242 static int filemax;
0243
0244
0245
0246 #define FAT_SUPER ( (struct fat_superblock *) \
0247 ( fsys_buf + 32256) )
0248 #define FAT_BUF ( fsys_buf + 30208 )
0249 #define NAME_BUF ( fsys_buf + 29184 )
0250
0251 #define FAT_CACHE_SIZE 2048
0252
0253 static __inline__ unsigned long
0254 log2 (unsigned long word)
0255 {
0256 __asm__ ("bsfl %1,%0"
0257 : "=r" (word)
0258 : "r" (word));
0259 return word;
0260 }
0261
0262 static bool mounted = FALSE;
0263 int
0264 vfat_mount (void)
0265 {
0266 struct fat_bpb bpb;
0267 __u32 magic, first_fat;
0268
0269
0270 if (! devread_vfat (0, 0, sizeof (bpb), (char *) &bpb))
0271 return 0;
0272
0273
0274
0275 if (bpb.sects_per_clust == 0)
0276 return 0;
0277
0278 FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect));
0279 FAT_SUPER->clustsize_bits
0280 = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
0281
0282
0283 FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors)
0284 ? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors;
0285
0286
0287 FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects);
0288 FAT_SUPER->fat_length =
0289 bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
0290
0291
0292 FAT_SUPER->root_offset =
0293 FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
0294 FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
0295
0296
0297 FAT_SUPER->data_offset =
0298 FAT_SUPER->root_offset
0299 + ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
0300 FAT_SUPER->num_clust =
0301 2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset)
0302 / bpb.sects_per_clust);
0303 FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
0304
0305 if (!bpb.fat_length)
0306 {
0307
0308 if (FAT_CVT_U16(bpb.dir_entries))
0309 return 0;
0310
0311 if (bpb.flags & 0x0080)
0312 {
0313
0314 int active_fat = bpb.flags & 0x000f;
0315 if (active_fat >= bpb.num_fats)
0316 return 0;
0317 FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
0318 }
0319
0320 FAT_SUPER->fat_size = 8;
0321 FAT_SUPER->root_cluster = bpb.root_cluster;
0322
0323
0324 FAT_SUPER->clust_eof_marker = 0xffffff8;
0325 }
0326 else
0327 {
0328 if (!FAT_SUPER->root_max)
0329 return 0;
0330
0331 FAT_SUPER->root_cluster = -1;
0332 if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST)
0333 {
0334 FAT_SUPER->fat_size = 4;
0335 FAT_SUPER->clust_eof_marker = 0xfff8;
0336 }
0337 else
0338 {
0339 FAT_SUPER->fat_size = 3;
0340 FAT_SUPER->clust_eof_marker = 0xff8;
0341 }
0342 }
0343
0344
0345
0346 if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
0347 || FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
0348 || bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
0349 - FAT_SUPER->sectsize_bits))
0350 || FAT_SUPER->num_clust <= 2
0351 || (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
0352 > FAT_SUPER->fat_length))
0353 return 0;
0354
0355
0356
0357 if (!devread_vfat(FAT_SUPER->fat_offset, 0,
0358 sizeof(first_fat), (char *)&first_fat))
0359 return 0;
0360
0361 if (FAT_SUPER->fat_size == 8)
0362 {
0363 first_fat &= 0x0fffffff;
0364 magic = 0x0fffff00;
0365 }
0366 else if (FAT_SUPER->fat_size == 4)
0367 {
0368 first_fat &= 0x0000ffff;
0369 magic = 0xff00;
0370 }
0371 else
0372 {
0373 first_fat &= 0x00000fff;
0374 magic = 0x0f00;
0375 }
0376
0377
0378
0379
0380
0381 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
0382 return 0;
0383
0384 FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
0385 mounted = TRUE;
0386 return 1;
0387 }
0388
0389 int
0390 vfat_read (char *buf, int len)
0391 {
0392 int logical_clust;
0393 int offset;
0394 int ret = 0;
0395 int size;
0396
0397 errnum=0;
0398
0399 if (FAT_SUPER->file_cluster < 0)
0400 {
0401
0402 size = FAT_SUPER->root_max - filepos;
0403 if (size > len)
0404 size = len;
0405 if (!devread_vfat(FAT_SUPER->root_offset, filepos, size, buf))
0406 return 0;
0407 filepos += size;
0408 return size;
0409 }
0410
0411 logical_clust = filepos >> FAT_SUPER->clustsize_bits;
0412 offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
0413 if (logical_clust < FAT_SUPER->current_cluster_num)
0414 {
0415 FAT_SUPER->current_cluster_num = 0;
0416 FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
0417 }
0418
0419 while (len > 0)
0420 {
0421 int sector;
0422 while (logical_clust > FAT_SUPER->current_cluster_num)
0423 {
0424
0425 int fat_entry =
0426 FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
0427 int next_cluster;
0428 int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
0429
0430 if (cached_pos < 0 ||
0431 (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
0432 {
0433 FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
0434 cached_pos = (fat_entry - FAT_SUPER->cached_fat);
0435 sector = FAT_SUPER->fat_offset
0436 + FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
0437 if (!devread_vfat (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
0438 return 0;
0439 }
0440 next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
0441 if (FAT_SUPER->fat_size == 3)
0442 {
0443 if (cached_pos & 1)
0444 next_cluster >>= 4;
0445 next_cluster &= 0xFFF;
0446 }
0447 else if (FAT_SUPER->fat_size == 4)
0448 next_cluster &= 0xFFFF;
0449
0450 if (next_cluster >= FAT_SUPER->clust_eof_marker)
0451 return ret;
0452 if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
0453 {
0454 errnum = ERR_FSYS_CORRUPT;
0455 return 0;
0456 }
0457
0458 FAT_SUPER->current_cluster = next_cluster;
0459 FAT_SUPER->current_cluster_num++;
0460 }
0461
0462 sector = FAT_SUPER->data_offset +
0463 ((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
0464 - FAT_SUPER->sectsize_bits));
0465 size = (1 << FAT_SUPER->clustsize_bits) - offset;
0466 if (size > len)
0467 size = len;
0468
0469 devread_vfat(sector, offset, size, buf);
0470
0471 len -= size;
0472 buf += size;
0473 ret += size;
0474 filepos += size;
0475 logical_clust++;
0476 offset = 0;
0477 }
0478 return errnum ? 0 : ret;
0479 }
0480
0481 int
0482 vfat_dir (char *dirname)
0483 {
0484 if (!mounted) vfat_mount ();
0485 DLOG ("vfat_dir (\"%s\")", dirname);
0486 char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
0487 char *filename = (char *) NAME_BUF;
0488 int attrib = FAT_ATTRIB_DIR;
0489
0490
0491
0492
0493 static unsigned char longdir_pos[] =
0494 { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
0495 int slot = -2;
0496 int alias_checksum = -1;
0497
0498 FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
0499 filepos = 0;
0500 FAT_SUPER->current_cluster_num = MAXINT;
0501
0502
0503 loop:
0504
0505
0506
0507
0508 if (!*dirname || isspace (*dirname))
0509 {
0510 if (attrib & FAT_ATTRIB_DIR)
0511 {
0512 errnum = ERR_BAD_FILETYPE;
0513 return -1;
0514 }
0515
0516 return filemax;
0517 }
0518
0519
0520
0521 while (*dirname == '/')
0522 dirname++;
0523
0524 if (!(attrib & FAT_ATTRIB_DIR))
0525 {
0526 errnum = ERR_BAD_FILETYPE;
0527 return -1;
0528 }
0529
0530 filemax = MAXINT;
0531
0532 for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
0533
0534 *rest = 0;
0535
0536 while (1)
0537 {
0538 if (vfat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
0539 || dir_buf[0] == 0)
0540 {
0541 if (!errnum)
0542 {
0543 errnum = ERR_FILE_NOT_FOUND;
0544 *rest = ch;
0545 }
0546
0547 return -1;
0548 }
0549
0550 if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
0551 {
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 int i, offset;
0565 unsigned char id = FAT_LONGDIR_ID(dir_buf);
0566
0567 if ((id & 0x40))
0568 {
0569 id &= 0x3f;
0570 slot = id;
0571 filename[slot * 13] = 0;
0572 alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
0573 }
0574
0575 if (id != slot || slot == 0
0576 || alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
0577 {
0578 alias_checksum = -1;
0579 continue;
0580 }
0581
0582 slot--;
0583 offset = slot * 13;
0584
0585 for (i=0; i < 13; i++)
0586 filename[offset+i] = dir_buf[longdir_pos[i]];
0587 continue;
0588 }
0589
0590 if (!FAT_DIRENTRY_VALID (dir_buf))
0591 continue;
0592
0593 if (alias_checksum != -1 && slot == 0)
0594 {
0595 int i;
0596 unsigned char sum;
0597
0598 slot = -2;
0599 for (sum = 0, i = 0; i< 11; i++)
0600 sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
0601
0602 if (sum == alias_checksum)
0603 {
0604 if (substring (dirname, filename) == 0)
0605 break;
0606 }
0607 }
0608
0609
0610 {
0611 int i, j, c;
0612
0613 for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
0614 && !isspace (c); i++);
0615
0616 filename[i++] = '.';
0617
0618 for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
0619 && !isspace (c); j++);
0620
0621 if (j == 0)
0622 i--;
0623
0624 filename[i + j] = 0;
0625 }
0626
0627 if (substring (dirname, filename) == 0)
0628 break;
0629 }
0630
0631 *(dirname = rest) = ch;
0632
0633 attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
0634 filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
0635 filepos = 0;
0636 FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
0637 FAT_SUPER->current_cluster_num = MAXINT;
0638
0639
0640 goto loop;
0641 }
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652