From 3a60c6b9b2377a3ac28735601d0d25c256d0d1b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Janosch=20Gr=C3=A4f?= Date: Sun, 23 Nov 2008 18:36:32 +0100 Subject: [PATCH] fat: reading directories (with long names) and files works now (tested with FAT12) --- apps/fat/cluster.c | 12 ++++--- apps/fat/dir.c | 80 ++++++++++++++++++++++++++++++++------------- apps/fat/dirent.h | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++-- apps/fat/fat_cdi.h | 6 ++-- apps/fat/file.c | 1 + apps/fat/init.c | 5 ++- apps/fat/resources.c | 2 +- apps/fat/sector.c | 5 +++ 8 files changed, 169 insertions(+), 33 deletions(-) diff --git a/apps/fat/cluster.c b/apps/fat/cluster.c index fe89354..91be83c 100644 --- a/apps/fat/cluster.c +++ b/apps/fat/cluster.c @@ -40,7 +40,11 @@ struct fat_cluster_chain *fat_clchain_create(struct cdi_fs_filesystem *fs,size_t clchain->clusters = realloc(clchain->clusters,cur_size*sizeof(uint64_t)); } - clchain->clusters[clchain->num_clusters++] = fat_fs->data_area+((uint64_t)cur_cluster-2)*fat_fs->bootsector->cluster_size*fat_fs->bootsector->sector_size; + if (fat_fs->data_area/fat_fs->bootsector->sector_size+((uint64_t)cur_cluster-2)*fat_fs->bootsector->cluster_size>=fat_num_sectors(fat_fs->bootsector)) { + debug("fat: Found illegal sector in cluster chain (#%d): %d [%d] (0x%x)%s\n",clchain->num_clusters,fat_fs->data_area/fat_fs->bootsector->sector_size+((uint64_t)cur_cluster-2)*fat_fs->bootsector->cluster_size,cur_cluster,cur_cluster==first_cluster?" (first cluster)":""); + debug("fat: Last sector: %d\n",clchain->clusters[clchain->num_clusters-1]/fat_fs->bootsector->sector_size); + } + else clchain->clusters[clchain->num_clusters++] = fat_fs->data_area+((uint64_t)cur_cluster-2)*fat_fs->bootsector->cluster_size*fat_fs->bootsector->sector_size; size_t next_cluster; if (fat_fs->type==FAT12) { @@ -48,20 +52,20 @@ struct fat_cluster_chain *fat_clchain_create(struct cdi_fs_filesystem *fs,size_t fat_read(fs,fat_start+cur_cluster*3/2,2,&ent); if (cur_cluster%2==1) ent = (ent>>4); ent &= 0xFFF; - if (ent>0xFF7) last = 1; + if (ent<0x3 || ent>0xFF7) last = 1; next_cluster = ent; } else if (fat_fs->type==FAT16) { uint16_t ent; fat_read(fs,fat_start+cur_cluster*2,2,&ent); - if (ent>0xFFF7) last = 1; + if (ent<0x3 || ent>0xFFF7) last = 1; next_cluster = ent; } else if (fat_fs->type==FAT32) { uint32_t ent; fat_read(fs,fat_start+cur_cluster*4,4,&ent); ent &= 0x0FFFFFFF; - if (ent>0xFFFFFFF7) last = 1; + if (ent<0x3 || ent>0xFFFFFFF7) last = 1; next_cluster = ent; } diff --git a/apps/fat/dir.c b/apps/fat/dir.c index fcbf0d4..f658a56 100644 --- a/apps/fat/dir.c +++ b/apps/fat/dir.c @@ -29,6 +29,20 @@ #include #endif +static int check_filename(char *name) { + size_t i,j; + char illegal[] = {0x22,0x2A,0x2B,0x2C,0x2E,0x2F,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x5B,0x5C,0x5D,0x7C}; + + if (name[0]==' ') return 0; + for (i=0;i<11;i++) { + if (name[i]<' ') return 0; + for (j=0;jfilename,(char*)dirent->filename_ext); + struct fat_fs_filesystem *fat_fs = parent->fs->opaque; + static cdi_list_t long_dirents = NULL; - if (dirent->attr.hidden && dirent->attr.system && dirent->attr.volume && dirent->attr.readonly) { - /// @todo Long names + if (dirent->attr.hidden && dirent->attr.system && dirent->attr.volume && dirent->attr.readonly && ((struct fat_dirent_long*)dirent)->type==0) { + if (long_dirents==NULL) long_dirents = cdi_list_create(); + cdi_list_push(long_dirents,memcpy(malloc(sizeof(struct fat_dirent)),dirent,sizeof(struct fat_dirent))); } - else if (!dirent->attr.volume) { - if (strcmp(name,".")!=0 && strcmp(name,"..")!=0) { + else if (!dirent->attr.volume && !dirent->attr.system && !dirent->attr.hidden) { + if (dirent->filename[0]!='.') { + char *name; + if (long_dirents==NULL) { + if (!check_filename((char*)dirent->filename)) return NULL; + name = parse_name((char*)dirent->filename,(char*)dirent->filename_ext); + } + else { + struct fat_dirent_long *long_dirent; + /// @todo Measure correctly how many bytes needed (UTF-8) + name = malloc(cdi_list_size(long_dirents)*13+1); + name[cdi_list_size(long_dirents)*13] = 0; + size_t cur = 0; + while ((long_dirent = cdi_list_pop(long_dirents))) { + ucs2toutf8((uint8_t*)name+cur,long_dirent->name1,5); + ucs2toutf8((uint8_t*)name+cur+5,long_dirent->name2,6); + ucs2toutf8((uint8_t*)name+cur+11,long_dirent->name3,2); + cur += 13; + free(long_dirent); + } + cdi_list_destroy(long_dirents); + long_dirents = NULL; + } cdi_fs_res_class_t class = dirent->attr.dir?CDI_FS_CLASS_DIR:CDI_FS_CLASS_FILE; cdi_fs_res_type_t type = 0; struct fat_fs_res *res = fat_fs_res_create(name,parent,class,type); res->readonly = dirent->attr.readonly; - res->system = dirent->attr.system; res->filesize = dirent->file_size; - res->clusters = fat_clchain_create(parent->fs,dirent->first_cluster); + if (fat_fs->type==FAT32) res->clusters = fat_clchain_create(parent->fs,fat32_first_cluster(dirent)); + else res->clusters = fat_clchain_create(parent->fs,dirent->first_cluster); free(name); return res; } } - free(name); return NULL; } @@ -129,18 +178,5 @@ cdi_list_t fat_dir_load(struct fat_fs_res *res) { cdi_list_t fat_fs_dir_list(struct cdi_fs_stream *stream) { struct fat_fs_res *res = (struct fat_fs_res*)stream->res; - struct fat_fs_res *child; - static cdi_list_t dirlist = NULL; - size_t i; - - if (dirlist==NULL) dirlist = cdi_list_create(); - else { - while ((child = cdi_list_pop(dirlist))); - } - - for (i=0;(child = cdi_list_get(res->res.children,i));i++) { - if (!child->system) cdi_list_push(dirlist,child); - } - - return dirlist; + return res->res.children; } diff --git a/apps/fat/dirent.h b/apps/fat/dirent.h index fc05d98..2698587 100644 --- a/apps/fat/dirent.h +++ b/apps/fat/dirent.h @@ -22,6 +22,8 @@ #include +#define fat32_first_cluster(de) ((((uint32_t)(de)->first_cluster_high)<<16)|(de)->first_cluster) + struct fat_dirent { /// Filename uint8_t filename[8]; @@ -53,10 +55,49 @@ struct fat_dirent { } __attribute__ ((packed)) attr; /// Reserved - uint16_t res0[5]; + uint8_t res0; /// Creation date struct { + /// Decisecond + uint8_t deci_second; + + /// Hour + unsigned hour:5; + + /// Minute + unsigned minute:6; + + /// 2 Seconds + unsigned two_secs:5; + + /// Year (since 1980) + unsigned year:7; + + /// Month + unsigned month:4; + + /// Day of month + unsigned day:5; + } __attribute__ ((packed)) create_date; + + /// Last access date + struct { + /// Year (since 1980) + unsigned year:7; + + /// Month + unsigned month:4; + + /// Day of month + unsigned day:5; + } __attribute__ ((packed)) access_date; + + /// Higher 16 bits of first cluster (for FAT32) + uint16_t first_cluster_high; + + /// Last write date + struct { /// Hour unsigned hour:5; @@ -74,7 +115,7 @@ struct fat_dirent { /// Day of month unsigned day:5; - } __attribute__ ((packed)) date; + } __attribute__ ((packed)) write_date; /// First cluster uint16_t first_cluster; @@ -83,4 +124,50 @@ struct fat_dirent { uint32_t file_size; } __attribute__ ((packed)); +struct fat_dirent_long { + /// Order + uint8_t order; + + /// Name (part 1) + uint16_t name1[5]; + + /// File attributes + struct { + /// Read only + unsigned readonly:1; + + /// File is hidden + unsigned hidden:1; + + /// System file + unsigned system:1; + + /// Volume label + unsigned volume:1; + + /// Directory + unsigned dir:1; + + /// Archiv + unsigned archiv:1; + + unsigned :2; + } __attribute__ ((packed)) attr; + + /// Type of log directory entry (should be 0) + uint8_t type; + + /// Checksum of name + uint8_t checksum; + + /// Name (part 2) + uint16_t name2[6]; + + /// Zero + uint16_t zero; + + /// Name (part 3) + uint16_t name3[2]; +} __attribute__ ((packed)); + #endif diff --git a/apps/fat/fat_cdi.h b/apps/fat/fat_cdi.h index 990679b..8fee597 100644 --- a/apps/fat/fat_cdi.h +++ b/apps/fat/fat_cdi.h @@ -73,9 +73,6 @@ struct fat_fs_res { /// Read only int readonly; - /// System file - int system; - /// Cluster chain struct fat_cluster_chain *clusters; }; @@ -94,6 +91,9 @@ int fat_fs_res_destroy(struct fat_fs_res *res); int fat_fs_res_load(struct cdi_fs_stream *stream); int fat_fs_res_unload(struct cdi_fs_stream *stream); +// file.c +size_t fat_fs_file_read(struct cdi_fs_stream *stream,uint64_t start,size_t size,void *buffer); + // dir.c cdi_list_t fat12_16_rootdir_load(struct cdi_fs_filesystem *fs); cdi_list_t fat_dir_load(struct fat_fs_res *res); diff --git a/apps/fat/file.c b/apps/fat/file.c index c456ea9..77b78a9 100644 --- a/apps/fat/file.c +++ b/apps/fat/file.c @@ -33,6 +33,7 @@ * @return How many bytes read */ size_t fat_fs_file_read(struct cdi_fs_stream *stream,uint64_t start,size_t size,void *buffer) { + debug("fat_fs_file_read(0x%x,0x%x,0x%x,0x%x)\n",stream,start,size,buffer); struct fat_fs_res *res = (struct fat_fs_res*)stream->res; if (start>res->filesize) return 0; diff --git a/apps/fat/init.c b/apps/fat/init.c index c577ccc..847d843 100644 --- a/apps/fat/init.c +++ b/apps/fat/init.c @@ -44,7 +44,10 @@ int fat_fs_init(struct cdi_fs_filesystem *fs) { if ((fat_fs->bootsector = fat_bootsector_load(fs))!=NULL) { // get FAT type fat_fs->type = fat_type(fat_fs->bootsector); - debug("fat: type: FAT%d\n",fat_fs->type); + + debug("fat: type=fat%d\n",fat_fs->type); + debug("fat: total sectors = %d\n",fat_num_sectors(fat_fs->bootsector)); + debug("fat: total bytes = %d\n",fat_num_sectors(fat_fs->bootsector)*fat_fs->bootsector->sector_size); // create cache fat_fs->cache = cdi_cache_create(fat_fs->bootsector->sector_size,0,fat_sector_read_cache,NULL,fs); diff --git a/apps/fat/resources.c b/apps/fat/resources.c index 8199663..8961ac9 100644 --- a/apps/fat/resources.c +++ b/apps/fat/resources.c @@ -30,7 +30,7 @@ struct cdi_fs_res_file fat_fs_res_file = { // Berechtigungen geregelt .executable = 1, - //.read = fat_fs_file_read, + .read = fat_fs_file_read, //.write = fat_fs_file_write }; diff --git a/apps/fat/sector.c b/apps/fat/sector.c index decfd4b..76160ac 100644 --- a/apps/fat/sector.c +++ b/apps/fat/sector.c @@ -33,6 +33,7 @@ * @return How many sectors read */ int fat_sector_read_cache(struct cdi_cache *cache,uint64_t block,size_t count,void *dest,void *prv) { + debug("fat_sector_read_cache(0x%x,0x%x,0x%x,0x%x,0x%x)\n",cache,block,count,dest,prv); struct fat_fs_filesystem *fat_fs = ((struct cdi_fs_filesystem*)prv)->opaque; uint64_t start = block*fat_fs->bootsector->sector_size; size_t size = count*fat_fs->bootsector->sector_size; @@ -50,6 +51,10 @@ int fat_sector_read_cache(struct cdi_cache *cache,uint64_t block,size_t count,vo size_t fat_read(struct cdi_fs_filesystem *fs,uint64_t pos,size_t size,void *buffer) { struct fat_fs_filesystem *fat_fs = fs->opaque; size_t block = pos/fat_fs->bootsector->sector_size; + if (block>=fat_num_sectors(fat_fs->bootsector)) { + debug("fat: KRITIKEL! Want to read block %d, but there are only %d\n",block,fat_num_sectors(fat_fs->bootsector)); + return 0; + } size_t offset = pos%fat_fs->bootsector->sector_size; size_t rem_size = size; -- 2.11.4.GIT