⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libfat.c

📁 Support library to access and manipulate FAT12 / FAT16 / FAT32 file systems - Includes a FUSE filesy
💻 C
📖 第 1 页 / 共 5 页
字号:
    // 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 + -