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

📄 libfat.c

📁 Support library to access and manipulate FAT12 / FAT16 / FAT32 file systems - Includes a FUSE filesy
💻 C
📖 第 1 页 / 共 5 页
字号:
				lfnlast++;		    }				/*	LFNLAST must be the first entry in the lfn chain	*/			if ( lfnlast !=	1 ) {				return -1;	// malformed lfn chain	    	}		}			i++;		count++;			/*	Checking cluster boundaries to see if we reached end of the cluster	*/ 	   	if ( (res = check_cluster_bound(V, Cluster, Offset)) != 0) { 			perror("fetch_next_direntry(): nothing left to read");			return -1;	// Nothing left to read 		}				if (lastclus != *Cluster) {			D->off2 = byte_offset(V, *Cluster, *Offset);			D->len1 = i;		}			D->direntoff = byte_offset(V, *Cluster, *Offset);		if ( fetch_entry(V, Cluster, Offset, &((D->entry)[i])) < 0) {			return -1;			}		if ( (res = analyze_dirent(&((D->entry)[i]))) < 0) {			return -1;		}    }    /* We are out of the 2 whiles. So we got an SFN. Or an error :) */	if ( ! (LIBFAT_DIRENT_ISSFN(res)) ) {		return -1;	// we got the error, whatever this is    } else {		i++;		//	Please note (note for me haha) that i increasings are correct.		D->len = i;		D->len2 = i - D->len1;				/* Now we have to check beyond the sfn entry to see if anything else may be present or not. */				/*	Checking cluster boundaries to see if we reached end of the cluster	*/ 	   	if ( (res = check_cluster_bound(V, Cluster, Offset)) != 0) { 			D->last = 1;		} else {			off64_t off;			char buf;    			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 byte after	*/			if ( (res = readn(V->blkDevFd, &buf, 1)) != 1) {				fprintf(stderr,"readn() error in fetch_next_direntry() at %d",__LINE__);				return -1;    		}						if (buf != 0) { 				D->last = 0;			} else {				D->last = 1;			} 		}			return i;    }		return 0;}/*	Check if all the lfn entries in the chain are in the correct order		*/int check_lfn_order(LfnEntry_t *Buffer, int bufsize) { BYTE andmask = 0x3F;	// 00111111, to and with the lastlfnentry, who is or'ed with 01000000			//					or 0x40 int i = 1; int limit = bufsize - 1;   for (i=1; (limit - i) >=0; i++) {	// we check only lfn entries.    if ( ( Buffer[(limit - i)].LDIR_Ord & andmask ) != i ) return -1;  // entries not in order }  return 0;}					/*	check if all the lfn entries are related to the sfn in the buffer		*/int check_lfn_checksum(LfnEntry_t *Buffer, int bufsize) {    int i;    BYTE checksum;        checksum = lfn_checksum(((DirEntry_t *) &Buffer[bufsize -1])->DIR_Name );        for (i=(bufsize -2); i>=0; i--) {		if ( Buffer[i].LDIR_Chksum != checksum ) return -1;    }    /*	Ok, all the lfn entries are related to the sfn entry in the buffer 							    according to the checksum	*/    return 0;}/*	Return the i-th unicode character from the lfn entry. (i from 0 to 12)		*/WORD fetch_lfn_char(LfnEntry_t *D, int n) {    int i = (n % 13) ;	// only 13 char in the lfn entries        if ( i <= 4  ) return D->LDIR_Name1[i];    if ( i <= 10 ) return D->LDIR_Name2[i-5];    return D->LDIR_Name3[i-11];}/*	Return the i-th unicode character from the lfn entry. (i from 0 to 12)		*/static int set_lfn_char(LfnEntry_t *D, WORD c , int n) {    int i = (n % 13) ;	// only 13 char in the lfn entries    	if (D==NULL) return -1;	    if ( i <= 4  )  {		D->LDIR_Name1[i] = c;	} else if ( i <= 10 ) {		D->LDIR_Name2[i-5] = c;	} else D->LDIR_Name3[i-11] = c;		return 0;}/*	Return the length of a long file name *including the terminator* in WORDs		*/int find_lfn_length( LfnEntry_t *D, int bufsize) {    WORD buf;    int size = (bufsize - 2) * 13;    int i=0;        if (bufsize <= 1) return -1; // only sfn present        // it checks only the last lfn entry!        for (i=0; i<13; i++) {		buf = fetch_lfn_char(&(D[0]),i);		if ( LFN_ISNULL(buf) ) return ( ( i + 1 ) + size);    }        /* i should be 13 now	*/    return ((i + 1) + size);	//yes, we need space for the terminator as well}/*	Extract the long file name from a lfnentry chain to a buffer of WORDS (UTF-16)	*/int extract_lfn_name( LfnEntry_t *Buffer, int bufsize, WORD *dest, int length) {    int i;	int entry;        for (i=0; i < (length - 1); i++) {		entry = (bufsize - 2) - (i / 13);	// bufsize -1 is sfn entry		/*	if we got a terminator before the end --> Error		*/		dest[i] = fetch_lfn_char(&(Buffer[entry]) ,i);    }        // we add the terminator by ourselves    dest[length - 1] = LFN_NULL;    return 0;}/*	Return the length of a short file name including the terminator in chars		*/int find_sfn_length( DirEntry_t *D, int bufsize) { // to fix: strip trailing spaces from filename and extension.    int i;     int count=0;        if (  D[bufsize - 1].DIR_Name[0] == 0x20 ) return -1; // illegal first char	    for (i=0; i <8; i++) if (D[bufsize - 1].DIR_Name[i] != 0x20 ) count++;     // there must be no lead 0 in the sfn extension.        count++;    if ( D[bufsize - 1].DIR_Name[8] == 0x20 ) return count;    for (i=8; i <11; i++) if ( D[bufsize - 1].DIR_Name[i] != 0x20 ) count++;         return ++count;}/*	Extract the short file name from a sfn entry in a direntry block (in some kind of codepage)*//*	return name length. including null terminator									   */int extract_sfn_name(DirEntry_t *D, int bufsize, char *name) {    int i;    int count = 0;		if (  D[bufsize - 1].DIR_Name[0] == 0x20 ) return -1; // illegal first char	    for (i=0; i <8; i++) {        if (  D[bufsize - 1].DIR_Name[i] != 0x20 ) {			name[count] = D[bufsize - 1].DIR_Name[i];			count++;		}    }        // there must be no lead 0 in the sfn extension.        if ( D[bufsize - 1].DIR_Name[8] == 0x20 ) {		name[count] = 0;		return count;    }        name[count] = '.';	count ++;    for (i=8; i <11; i++) {        if ( D[bufsize - 1].DIR_Name[i] != 0x20 ) {			name[count] = D[bufsize - 1].DIR_Name[i];			count++;		}    }           name[count] = 0;//	fprintf(stderr, "-- - - -- - -extract_sfn: name extracted: %s\n", name);    return count;}/*	Generates a dirent structure from fat directory entries.		*/int fatentry_to_dirent(Volume_t *V, DirEnt_t *D, struct dirent *dirp) {    int res;	LfnEntry_t *Buffer;	int bufsize;    WORD utf16buf[261];    char utf8buf[521];    int namelen;    	Buffer= D->entry;	bufsize = D->len;	    memset(dirp, 0, sizeof(struct dirent));	// bzeroing the fields.    memset(utf8buf,0,521);    	    if ( bufsize < 2 ) {	// we have only sfn		namelen = find_sfn_length( (DirEntry_t *) Buffer, bufsize);//		fprintf(stderr," fatentry to dirent: bufsize: %s\n\n", ((DirEntry_t *) Buffer)[0].DIR_Name  );		if ( (namelen = res = extract_sfn_name( (DirEntry_t *) Buffer, bufsize, utf8buf)) <= 0) return res;			memcpy(dirp->d_name, utf8buf, namelen);    } else {			// lfn		namelen = find_lfn_length( Buffer, bufsize);		if ( (res = extract_lfn_name( Buffer, bufsize, utf16buf, namelen)) != 0) return res;		if ( (res = utf16to8(utf16buf, utf8buf)) != 0) return res;		memcpy(dirp->d_name, utf8buf, 255);	// copying at most 255 utf8 bytes. the last is already 0    }	dirp->d_ino = get_fstclus(V, (DirEntry_t *) &(Buffer[bufsize -1]) );	    if (ATTR_ISDIR(((DirEntry_t *) Buffer)[bufsize-1].DIR_Attr)) {	// the direntry refers to a directory		dirp->d_type = DT_DIR;    } else {	// the direntry refers to a file		dirp->d_type = DT_REG;    }    dirp->d_reclen = sizeof(struct dirent);    return 0;}/* find the direntry related to the given name in the given directory container specified by *cluster* and offset	*//* it overwrites cluster and offset fields with the values of the direntry related to name in the current directory *//* container (the one before). On fail, it returns -1 and it doesnt overwrite anything. 0 on success		*/int find_direntry(Volume_t *V, char *name, DWORD *Cluster, DWORD *Offset) {    int res;    DWORD bkclu, bkoff;	DirEnt_t D;    LfnEntry_t *buffer = D.entry;		//fprintf(stderr,"find_direntry. filename: %s\n",name);	    	for (;;) {		bkclu = *Cluster;		bkoff = *Offset;		res = fetch_next_direntry(V, &D, Cluster, Offset);		if (res <= 0)  return -1;	// this is the condition to exit : nothing left to fetch or something strange found by fetch_next_direntry.		/*	checking if this is what we are lookin for		*/		if (res == 1 ) {	// only sfn name is present.		    int i;		    char *entryname;		    i = find_sfn_length( (DirEntry_t *)buffer, res);		    entryname = alloca(i);		    extract_sfn_name((DirEntry_t *)buffer, res, entryname);		    res = utf8_stricmp(name, entryname);	// possible because Ascii are utf8		    if (res == 0) {	// we won! good.				*Cluster = bkclu;				*Offset = bkoff;				return 0;		    }		} else {		// we use lfn name.		    int i;		    WORD *entryname;			char *utf8name;		    i = find_lfn_length( buffer, res);		    entryname = alloca(i * sizeof(WORD));	//is it Possible to use alloca()?			utf8name = alloca(i * sizeof(WORD));			memset(utf8name, 0, i * sizeof(WORD));			memset(entryname, 0, i * sizeof(WORD));		    extract_lfn_name(buffer, res, entryname, i);	// res = size of buffer			utf16to8(entryname, utf8name);			//fprintf(stderr,"found 1 lfn direntry. name:%s\n",utf8name);					    res = utf8_stricmp(name, utf8name);		    if (res == 0) {	// we won! good.				*Cluster = bkclu;				*Offset = bkoff;				return 0;		    }	    		}	}    return -2;}/* It takes a path of directories (it must exist in the volume V) and the Cluster of		*//* the root dir. it return the cluster of the last dir in the path.				*//*	It returns 0 on success, -1 if the path does not exist.					*//*	Offset probably not needed								*/int traverse_path(Volume_t *V, gchar **parts, guint parts_len, DWORD *Cluster) {    DWORD Offset = 0;    DWORD Clus;//    char nextdir[255];    int i,res;	DirEnt_t D;    LfnEntry_t *buffer = D.entry;		if (V->FatType == FAT32) {		Clus = EFD(V->Bpb.BPB_RootClus);    } else {		Clus = 1;	}	    for (i=1; i < (int) (parts_len - 1); i++) {		if ( (res = find_direntry(V, (char *) parts[i] , &Clus, &Offset)) != 0 ) { //looking for the directory			    return -1;	//error: part of the path not found.		} else { // parth of the path found: we have to fetch the related direntry			DirEntry_t *sfnentry;		    if ( ( res = fetch_next_direntry(V, &D, &Clus, &Offset)) <= 0) {				return -1 ;	//fetching the dirent			}			sfnentry = (DirEntry_t *) &(buffer[res - 1]);			if ( ! (ATTR_ISDIR(sfnentry->DIR_Attr))) {				return -1; //name found but not directory			}			Offset = 0;			Clus = get_fstclus(V,sfnentry);		}													}	*Cluster = Clus;	return 0;}/* find the file (direntry) related to the given path. N.B. The path must exist exactly in the volume V.*//* it sets adequately Cluster and Offset. the caller has to fetch the direntry of the file of interest	*/int find_file(Volume_t *V, const char *path, File_t *F, DWORD *Cluster, DWORD *Offset) {    char *filename;    int res;    /*	splitting the path	*/    gchar **parts = g_strsplit(path, "/", -1);    guint parts_len = g_strv_length(parts);	    filename=(char *) parts[parts_len - 1];    /*	Initialising Cluster and Offset with root directory values. Passed by the caller	*/	/*	not needed! done in traverse_path()													*/    /*  walking through the directory tree until we find the parent directory of our file/directory	*/    /*	FIrst DIR = Rootdir				*/    /*  We take one by one directories in the path, and look for them in the current dir. If it		*/    /*	exists, we put DIR=that dir. If not throws an exception						*/	if ( (res=traverse_path(V, parts, parts_len, Cluster)) != 0) { 		g_strfreev(parts);		return -1; 	}	//error 	if (F!=NULL) {		F->ParentFstClus = *Cluster;		F->ParentOffset = 0;	// not used atm.	}	*Offset = 0;	res = find_direntry(V, filename , Cluster, Offset); //looking for the directory	g_strfreev(parts);		if  (res != 0 ) { 		return -1;  //error: part of the path not found.	} else { // file found. Cluster and offset are related to its direntry.		F->DirEntryClus = *Cluster;		F->DirEntryOffset = *Offset;		return 0;	}}/* Read into the buffer data belonging to the file in which is the cluster Cluster. This is low level function.	*//* it returns number of bytes read or -1 on error. It does not make any change to Cluster and Offset	*/int fat_read_data(Volume_t *V, DWORD *Cluster, DWORD *Offset, char *buf, size_t count ) {	off64_t off = 0;	int datasize = count;	int dataread = 0;	int clustersz= EFW(V->Bpb.BPB_BytsPerSec) * V->Bpb.BPB_SecPerClus;	int byteleftperclus = clustersz - *Offset;	int res;	off64_t seekres;	int i=0;//	fprintf(stderr,"off: %u, bytleft %d, count: %d\n",*Offset, byteleftperclus,count);	if (*Offset > clustersz) {		fprintf(stderr,"Offset too big\n");		return -1;	} else if (*Offset == clustersz) {		DWORD c =  *Cluster;		*Offset = 0;		fat_read_entry(V, c, 0, Cluster); // if this is the last cluster in the chain, the function will allocate a new cluster.				if (fat_isfree(V,*Cluster)) { // must be eoc or  a valid cluster number			fprintf(stderr,"fat_write_data wrote on an unlinked cluster\n"); 			return -1; 						/* workaround to avoid to return an invalid *Cluster	*/		// lets check if wehave reached EOC. in this case this function allocate a free cluster to the file even if it does not need it.		} else if (fat_iseoc(V,*Cluster)) {	//we reached EOC. so we have to get a free cluster and link it to the file			fprintf(stderr,"read_data error: EOC reached.\n"); 			return -1; 		} else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -