📄 libfat.c
字号:
// this calculation sucks. it doesnt keep in account first rootdircluster can be different from 2 FirstDataSector = EFW(V->Bpb.BPB_ResvdSecCnt) + (V->Bpb.BPB_NumFATs * FATSz) + RootDirSectors; DataSec = TotSec - FirstDataSector; CountofClusters = (DWORD) (DataSec / V->Bpb.BPB_SecPerClus); V->DataClusters = CountofClusters; /* The total number of valid data clusters */ /* determine fat type and eventually fetch fsinfo sector */ res = libfat_determine_fattype(V); V->FirstDataSector = FirstDataSector; /* The first sector of the data region */ V->FirstRootCluster = EFD(V->Bpb.BPB_RootClus); /* The first cluster of FAT32 root, usually 2 */ V->bps64 = EFW(V->Bpb.BPB_BytsPerSec); V->spc64 = V->Bpb.BPB_SecPerClus; V->bpc64 = V->bps64 * V->spc64; V->fds64 = FirstDataSector; V->fdb64 = V->fds64 * V->bps64; V->bps = V->bps64; V->spc = V->spc64; V->bpc = V->bpc64; /* position and size of root dir in fat12/16 */ V->rootdir16off = (EFW(V->Bpb.BPB_ResvdSecCnt) + (V->Bpb.BPB_NumFATs * FATSz)) * V->bps64; V->rootdir16sz = RootDirSectors * V->bps; if ( V->FatType == FAT32) { V->fatsz = EFD(V->Bpb.BPB_FATSz32) * V->bps; } else V->fatsz = EFW(V->Bpb.BPB_FATSz16) * V->bps; V->rsvdbytecnt = EFW(V->Bpb.BPB_ResvdSecCnt) * V->bps; V->numfats = V->Bpb.BPB_NumFATs; /* setting mode for the volume -- TODO: get parameter for the mode and use those */ V->mode =0; V->mode |= (S_IRWXU | S_IRWXG); libfat_initialize_freelist(V); memset(V->zerobuf, 0, ZERO_BFSZ); //it is our buffer for write0 :)#ifdef LIBFAT_USE_MUTEX if (pthread_mutex_init(&(V->fat_mutex), NULL) != 0) { perror("pthread_mutex_init() error in partition_init():"); return -1; }#endif printVolumeData(V); #ifdef FATWRITE if (flags & FAT_WRITE_ACCESS_FLAG) fat_mark_dirty(V);#endif return 0;}/* sync the fats into the volume */int fat_fat_sync(Volume_t *V) { int fsioff; int res; if (V->FatType == FAT32) { V->Fsi.FSI_Free_Count = EFD(V->freecnt); V->Fsi.FSI_Nxt_Free = EFD(V->nextfree); // lets write down FSInfo Sector fsioff = (int) ((int) EFW(V->Bpb.BPB_FSInfo) * V->bps); res = lseek(V->blkDevFd, fsioff , SEEK_SET); if (res != fsioff ) { perror("lseek() error in partition finalize"); return -1; } res = writen(V->blkDevFd, (char *) &(V->Fsi), sizeof(FSInfo_t)); if (res < 0) { fprintf(stderr,"readn() error, line:%d\n",__LINE__); return -1; } } else if ((V->FatType == FAT12) || (V->FatType == FAT16)) { int i,size; off_t off; if (V->FatType == FAT16) { size = (V->DataClusters + 2) * sizeof(WORD); } else { size = ((V->DataClusters + 2) / 2) * 3; if (((V->DataClusters + 2) % 2) != 0) size += 2; } /* lets write down the whole fat in all copies */ for (i=0; i < V->numfats; i++) { off=V->rsvdbytecnt + ( i * V->fatsz); if ( (res = lseek64(V->blkDevFd, off, SEEK_SET)) < 0) { fprintf(stderr,"lseek() error in partition finalize(), off:%d\n",(int) off); return res; } /* write() */ if ( (res = writen(V->blkDevFd, V->fat, size)) != size) { fprintf(stderr,"writen() error in partition finalize. size: %d\n", size); return -1; } } } return 0;}/* Finalize the volume writing down new count of free clusters and new hint in FSinfo */int fat_partition_finalize(Volume_t *V) {#ifdef FATWRITE int res; if ((res = fat_fat_sync(V)) != 0) return -1; // Lets mark volume as clean// if (flags & FAT_WRITE_ACCESS_FLAG) // TO FIX THIS fat_mark_clean(V);#endif#ifdef LIBFAT_USE_MUTEX if (pthread_mutex_destroy(&(V->fat_mutex)) != 0) { perror("pthread_mutex_destroy() error in partition_finalize():"); }#endif if (V->fat != NULL) free(V->fat); // Lets close the fd close(V->blkDevFd); return 0;}/* populate free cluster array */int fat_populate_freelist(Volume_t *V) { int i=POPULATE_FREELIST_BUFSZ; DWORD buf[POPULATE_FREELIST_BUFSZ]; off64_t freeoff; off64_t lastoff; int count=POPULATE_FREELIST_BUFSZ; // value to compute amount of data to read. int res; int flag = 0; off64_t seekres; DWORD freeclus = V->freecnt; DWORD lastcluster = V->DataClusters + 1; //see specs in fatgen103 DWORD nextfree = V->nextfree; // value to put into our free cluster array. if (freeclus <= 0) { fprintf(stderr,"No free clusters left\n"); return -1; } if (nextfree > lastcluster) { // there are free clusters but not at the end of the volume. V->nextfree = nextfree = 3; } freeoff = (off64_t) V->rsvdbytecnt + ((off64_t) V->nextfree * (off64_t) sizeof(DWORD)); lastoff = (off64_t) V->rsvdbytecnt + ((off64_t) (lastcluster) * (off64_t) sizeof(DWORD)); // this is a legal cluster offset. // if ( ((off64_t) V->freecnt ) < (lastoff -freeoff + (off64_t) 1) ) { //little problem: there should be more free cluster than what is written in FSInfo Sec.// } /* ok, there is at least 1 cluster we can check */ V->fclusz = 0; V->fstfclus = 0; while (freeclus > 0) { if (freeoff > lastoff) { if (flag != 1) { flag = 1; nextfree = 2; freeoff = (off64_t) V->rsvdbytecnt + ((off64_t) 2 * (off64_t) sizeof(DWORD)); } else { // error: we already had a whole scan of the fat by already setting freeoff to 2// fprintf(stderr,"populate_freelist() error: there are no freeclusters left even if system think so\n"); return V->fclusz;// return -1; } } if (i >= count) { // we need to fetch another piece of fat. count = (int) MIN(((off64_t) (POPULATE_FREELIST_BUFSZ)), (((lastoff - freeoff) / (off64_t) sizeof(DWORD)) + (off64_t) 1)); // seems ok. seekres = lseek64(V->blkDevFd,(off64_t) freeoff , SEEK_SET); if (seekres != freeoff ) { perror("lseek() error in populate_freelist"); return -1; } res = readn(V->blkDevFd, buf, (size_t) (count * sizeof(DWORD))); if (res < 0) { fprintf(stderr,"readn() error, line:%d\n",__LINE__); return -1; } i=0; } if (V->fclusz < FCLUS_BUFSZ) { if (fat_isfree(V,buf[i])) { V->freeclus[V->fclusz] =nextfree; V->fclusz++; freeclus --; } } else { // we filled the whole freeclus buffer. let's exit. return (int) V->fclusz; } nextfree++; // we dont update here V->nextfree. i++; freeoff += (off64_t) sizeof(DWORD); } // no free clusters left. let's return what we fetched. return V->fclusz;}/* provides a free cluster to the caller, updating nextfree and count of free cluster. *//* once provided, that cluster is considered used. *//* The routine takes care to update fstfclus into V, and if needed to repopulate the free cluster array *//* PLEASE NOTE: this routine does not recover free clusters and does not work if no *//* nextfree hint is provided. TOFIX */static DWORD fat32_getFreeCluster(Volume_t *V) { int res; DWORD clus; while (V->fstfclus >= V->fclusz) { res = fat_populate_freelist(V); if (res <= 0) { fprintf(stderr,"populate freelist error: end of space on the volume\n"); return (DWORD) 0; } } clus = V->freeclus[V->fstfclus]; V->freecnt--; V->fstfclus++; V->nextfree = MAX(clus,V->nextfree); if (clus > (V->DataClusters + 1)) { fprintf(stderr,"getFreeCluster() error. clus num : %u, max clus: %u\n", clus, (V->DataClusters + 1)); return 0; }// fprintf(stderr,"gfc: cluster = %u\n", clus); return clus; }static DWORD fat16_getFreeCluster(Volume_t *V) { DWORD c, val; int res; if (V->freecnt <= 0) { fprintf(stderr,"getFreeCluster: end of free clusters in the volume\n"); return 0; } do { val = V->nextfree; if ((res = fat_read_entry(V, V->nextfree++, 0, &c)) < 0) { fprintf(stderr,"getFreeCluster16 error\n"); return 0; } if ( V->nextfree > (V->DataClusters + 1)) V->nextfree = 2; if (fat_isfree(V,c)) { V->freecnt--; return val; } } while (V->freecnt > 0); fprintf(stderr,"getFreeCluster: end of free clusters in the volume\n"); return 0;}DWORD fat_getFreeCluster(Volume_t *V) { DWORD val; if (V->FatType == FAT32) { val= fat32_getFreeCluster(V); } else { val= fat16_getFreeCluster(V); } fprintf(stderr,"- - fat_getFreeCluster: clus: %u; freecnt: %u\n",val,V->freecnt); return val;}/* Calculate the 8-bit checksum for the long file name from its *//* corresponding short name. *//* */BYTE lfn_checksum(BYTE *name) { int Sum = 0, i; for (i = 0; i < 11; i++) { Sum = (((Sum & 1) << 7) | ((Sum & 0xFE) >> 1)) + name[i]; } return Sum;}/* Given a 32byte dirent entry, determines what it is . If lfn entry (and if the last one) or sfn entry or free entry */int analyze_dirent(LfnEntry_t *D) { BYTE c; /* Empty entry */ if ( DIRENT_ISLAST(D->LDIR_Ord)) return LIBFAT_DIRENT_LASTFREE; if ( DIRENT_ISFREE(D->LDIR_Ord)) return LIBFAT_DIRENT_FREE; c = D->LDIR_Attr;#if 0 /* these are bits, more flags can be set at the same time */ if ( (c != ATTR_READ_ONLY) && (c != ATTR_HIDDEN) && (c != ATTR_SYSTEM) && (c != ATTR_VOLUME_ID) && (c != ATTR_DIRECTORY) && (c != ATTR_ARCHIVE) && (c != ATTR_LONG_NAME) ) { fprintf(stderr,"not a valid LDIR_Attr: %u",c); return -1; }#endif if ( (D->LDIR_Attr == ATTR_LONG_NAME) ) { if (LFN_ISLAST(D->LDIR_Ord)) { //Lfn Entry// fprintf(stderr,"LFN LAsT\n"); return LIBFAT_DIRENT_LFN_LAST; } else { // fprintf(stderr,"LFN\n"); return LIBFAT_DIRENT_LFN; } } else {// fprintf(stderr,"SFN\n"); return LIBFAT_DIRENT_SFN; //Sfn entry }}/* Check the cluster boundaries. if we reached the end of the cluster, thefunction goes and get next cluster in the clusterchain. if we reachedthe end of the file, it returns -1 *///TODO: range check that we are not over last cluster of the volume.int check_cluster_bound(Volume_t *V, DWORD *Cluster, DWORD *Offset) { WORD ClusterSz; int res; ClusterSz = V->bpc ; if (*Offset == 0) { // we are in the beginning return 0; } else if (*Cluster == 1) { if ( ( *Offset % V->rootdir16sz ) == 0 ) { fprintf(stderr,"No space left on rootdirectory\n"); return -1; } else return 0; } else if ( ( *Offset % ClusterSz ) == 0) { // we need to go in the next cluster DWORD value; if ((res = fat_read_entry(V, *Cluster, 0, &value)) != 0) { perror("check_cluster_bound() error"); return -1; }// printf("Cluster:%d\nOffset:%d\n,res: %u\n", *Cluster, *Offset, value); if (fat_iseoc(V,value)) {// printf("Cluster:%d\nOffset:%d\n", *Cluster, *Offset); *Cluster = fat_eocvalue(V); return -1; } else { *Cluster = value; *Offset = 0; return 0; } } else { // we havent reached the end of the cluster yet return 0; } }/* Fetches a 32byte dirent in a LfnEntry_t structure *//* from the specified volume at the specified cluster and offset *//* returns 0 if successful, or -1 if error *//* it moves forward the offset *//* Called by fat_readdir and find. */int fetch_entry(Volume_t *V, DWORD *Cluster, DWORD *Offset, LfnEntry_t *D) { int res; off64_t off; off = byte_offset(V, *Cluster, *Offset); if ( (res = lseek64(V->blkDevFd, off, SEEK_SET)) < 0 ) { perror("lseek() error in fetch_lfn():"); return -1; } /* Reading the dirent */ if ( (res = readn(V->blkDevFd, D, 32)) != 32) { fprintf(stderr,"readn() error in fetch_entry() at %d",__LINE__); return -1; } /* pushing forward the offset */ *Offset += 32; return 0;}/* Fetches a whole directory entry chain for a file, to the specified Buffer*//* Returns the number of directory entries used, 0 if nothing was read, or *//* or -1 if an error occurred. Please note that 1 means only SFN entry is */ /* present. It ensures also that the directory entries chain is correct *//* but not that the single entries are correct. (it make sure only that we *//* have LFNLAST,LFN,....,LFN,SFN or SFN */int fetch_next_direntry(Volume_t *V, DirEnt_t *D, DWORD *Cluster, DWORD *Offset) { DWORD lastclus; int lfnlast=0; // flag againist malformed entries int i=0; //index for Buffer[i] int res=LIBFAT_DIRENT_FREE; int count = 0; if ((fat_iseoc(V,*Cluster)) || (fat_isfree(V,*Cluster))) return -1; /* Skipping free entries */ while ( LIBFAT_DIRENT_ISFREE(res) ) { /* Checking cluster boundaries to see if we reached end of the cluster */ if ( (res = check_cluster_bound(V, Cluster, Offset)) != 0) { fprintf(stderr,"fetch_next_direntry: nothing left to read\n"); return -1; // Nothing left to read } lastclus = *Cluster; D->direntoff = D->off1 = byte_offset(V, *Cluster, *Offset); D->clus = *Cluster; D->off = *Offset; if ( fetch_entry(V, Cluster, Offset, &((D->entry)[i])) < 0 ) { return -1; // error fetching direntry } if ( ( res = analyze_dirent(&((D->entry)[i])) ) < 0) { return -1; // malformed 32byte block } if ( LIBFAT_DIRENT_ISLASTFREE(res) ) { // Nothing else after this 32byte direntry return 0; } } /* fetching the LFN entry chain */ while (LIBFAT_DIRENT_ISLFN(res)) { if (LIBFAT_DIRENT_ISLFNLAST(res)) { if (lfnlast > 0) { return -1; // We already encountered an LFNLAST entry without and no Sfn entry. } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -