📄 libfat.c
字号:
// Cluster must be a valid cluster number set up by fat_read_entry. fprintf(stderr,"offset >= clustersz, but next cluster exist.\n"); } *Offset = 0; } while (count > 0) { int numbytes; int newoffset; numbytes = MIN(byteleftperclus, count); newoffset = *Offset + numbytes; off = byte_offset(V, *Cluster, *Offset); fprintf(stderr,"Cluster: %u, Offset: %u, off: %lld, numbyts:%d\n",*Cluster, *Offset, off, numbytes); seekres = lseek64(V->blkDevFd,(off64_t) off , SEEK_SET); if (seekres != off ) { perror("lseek() error in read_data"); return -1; } res = readn(V->blkDevFd, &(buf[dataread]), (size_t) numbytes); if (res < 0) { fprintf(stderr,"readn() error, line:%d\n",__LINE__); return -1; } dataread += res; count -= res; i++; // NB: readn implies it has to read numbytes bytes or fail, so // if count is now > 0, then we automatically have to jump to next cluster. //update cluster and offset -- if we reach end of clusterchain, count must have been too large. if (count > 0) { // lets fetch next cluster. DWORD c = *Cluster; fat_read_entry(V, c, 0, Cluster); // lets check if wehave reached the end of clusterchain if (fat_iseoc(V,*Cluster)) { //we reached EOC so count is too big. Caller have to check *Cluster by himself fprintf(stderr,"read_data() error: EOC reached\n"); return(datasize -count); } *Offset = 0; //lets reset byteleftperclus byteleftperclus = clustersz; } else { // count <=0. We are done. lets set *Offset properly *Offset = newoffset; if ( *Offset >= clustersz ) { //it cant actually be greater, just equal DWORD c = *Cluster; fat_read_entry(V, c, 0, Cluster); // if this is the last cluster in the chain, the function will return EOC/0 pair for clus/off *Offset = 0; } return datasize; } } return -2; // we shouldnt reach here}/* Write from the buffer data to the file who own the cluster Cluster, starting at *//* the offset Offset in the cluster Cluster. This is low level function. *//* it returns number of bytes written or -1 on error. It does not make any change to Cluster and Offset *//* NB: F can be NULL if we are writing on a directory file *//* Please NOTE: the function does not make any check on Cluster. */int fat_write_data(Volume_t *V, File_t *F, DWORD *Cluster, DWORD *Offset, char *buf, int count ) {#ifdef FATWRITE int cnt = count; off64_t off = 0; int datasize = count; int datawritten = 0; int clustersz= V->bpc; int byteleftperclus; int res; off64_t seekres; int i=0; DWORD orig_filesz = 0; if (F != NULL) { orig_filesz = EFD(F->DirEntry->DIR_FileSize); } 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 DWORD newclus; int r; newclus = fat_getFreeCluster(V); if (newclus == (DWORD) 0) { // no newclusters available fprintf(stderr,"getFreeCluster() error. line %d\n",__LINE__); return -1; } /* lets write newclus into *Cluster in the fat. */ //tofix: writen_entry instead of write_entry??? if ((r = fat_writen_entry(V, c, newclus)) != 0) return -1; /* lets write EOC into newclus in the fat. */ if ((r = fat_writen_entry(V, newclus, fat_eocvalue(V))) != 0) return -1; /* lets set *Cluster to newclus */ *Cluster = newclus; } else { // Cluster must be a valid cluster number set up by fat_read_entry. fprintf(stderr,"offset >= clustersz, but next cluster exist.\n"); } *Offset = 0; } byteleftperclus = clustersz - *Offset; fprintf(stderr,"off: %u, bytleft %d, cnt: %d\n",*Offset, byteleftperclus,cnt); while (cnt > 0) { int numbytes; int newoffset; numbytes = MIN(byteleftperclus, cnt); newoffset = *Offset + numbytes; off = byte_offset(V, *Cluster, *Offset); fprintf(stderr,"Cluster: %u, Offset: %u, off: %lld, numbyts:%d, i:%d\n",*Cluster, *Offset, off, numbytes,i); seekres = lseek64(V->blkDevFd,(off64_t) off , SEEK_SET); if (seekres != off ) { fprintf(stderr,"lseek() error in read_data\n"); return -1; } res = writen(V->blkDevFd, &(buf[datawritten]), (size_t) numbytes); if (res != numbytes) { fprintf(stderr,"writen() error in write data\n"); return -1; } if (F != NULL) F->CurAbsOff += res; datawritten += res; cnt -= res; i++; // NB: readn implies it has to read numbytes bytes or fail, so // if cnt is now > 0, then we automatically have to jump to next cluster. //update cluster and offset -- if we reach end of clusterchain, cnt must have been too large.// fprintf(stderr,"value of cnt: %d\n",cnt); if (cnt > 0) { // lets fetch next cluster. DWORD c = *Cluster; fat_read_entry(V, c, 0, Cluster); fprintf(stderr,"reading value of cluster %u: %u\n",c, *Cluster); if (fat_isfree(V,*Cluster)) { fprintf(stderr,"fat_write_data wrote on an unlinked cluster\n"); return -1; } // lets check if wehave reached the end of clusterchain if (fat_iseoc(V,*Cluster)) { //we reached EOC. so we have to get a free cluster and link it to the file DWORD newclus; int r; newclus = fat_getFreeCluster(V); if (newclus == 0) { if ((F != NULL) && (EFD(F->DirEntry->DIR_FileSize) < F->CurAbsOff)) F->DirEntry->DIR_FileSize = EFD(F->CurAbsOff); fprintf(stderr,"getFreeCluster() error. line:%d\n",__LINE__); return -1; } /* lets write newclus into *Cluster in the fat. */ //tofix: writen_entry instead of write_entry??? if ((r = fat_writen_entry(V, c, newclus)) != 0) return -1; /* lets write EOC into newclus in the fat. */ if ((r = fat_writen_entry(V, newclus, fat_eocvalue(V))) != 0) return -1; /* lets set *Cluster to newclus */ *Cluster = newclus; } else { // Cluster must be a valid cluster number set up by fat_read_entry. } *Offset = 0; //lets reset byteleftperclus byteleftperclus = clustersz; } else { // cnt <=0. We are done. lets set *Offset properly DWORD c = *Cluster; *Offset = newoffset; if ( *Offset >= clustersz ) { //it cant actually be greater, just equal 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. if (fat_iseoc(V,*Cluster)) { //we reached EOC. so we have to get a free cluster and link it to the file // reset cluster value and just left offset value to clustersize *Cluster = c; } else { // Cluster must be a valid cluster number set up by fat_read_entry. fprintf(stderr,"offset >= clustersz, but next cluster exist.\n"); *Offset = 0; } } else { //offset < clustersize fprintf(stderr,"offset !>= clustersz, so everything is fine and we dont have to allocate a new cluster\n"); } if ((F != NULL) && (EFD(F->DirEntry->DIR_FileSize) < F->CurAbsOff)) F->DirEntry->DIR_FileSize = EFD(F->CurAbsOff); return datasize; } } #endif /* #ifdef FATWRITE */ return -2; // we shouldnt reach here}static ssize_t fat_write0data(Volume_t *V, File_t *F, DWORD *Cluster, DWORD *Offset, size_t count) { int res; int retval = count; char *buf = V->zerobuf; if ((count <= 0)) { fprintf(stderr,"write0 error: count <= 0\n"); return -1; } while (count > 0) { int size; size = MIN(ZERO_BFSZ, count); count -= size; if ((res = fat_write_data(V, F, Cluster, Offset, buf, size )) != size) { fprintf(stderr,"write0data error. size: %d, res: %d\n",size, res); return -1; } } return retval;}/* Update the DirEntry_t of the file F into the volume V */int fat_update_file(File_t *F) {#ifdef FATWRITE int res; off64_t seekres; if (F == NULL) return 0; seekres = lseek64(F->V->blkDevFd,(off64_t) F->D.direntoff , SEEK_SET); if (seekres != F->D.direntoff ) { perror("lseek() error in update file"); return -1; } res = writen(F->V->blkDevFd, (char *) F->DirEntry, (size_t) sizeof(DirEntry_t)); if (res < 0) { perror("writen() error in update file"); return -1; }#endif /* #ifdef FATWRITE */ return 0;}/* set first cluster */int set_fstclus(Volume_t *V, DirEntry_t *D, DWORD c) { if (D==NULL) return -1; c=EFD(c); // c is now little endian char *src = (char *) &c; char *dst = (char *) &(D->DIR_FstClusLO); dst[0] = src[0]; dst[1] = src[1]; if (V->FatType == FAT32) { dst = (char *) &(D->DIR_FstClusHI); dst[0] = src[2]; dst[1] = src[3]; } return 0;}/* get first cluster */DWORD get_fstclus(Volume_t *V, DirEntry_t *D) { DWORD val = 0; char *dst = (char *) &val; char *src = (char *) &(D->DIR_FstClusLO); dst[0] = src[0]; dst[1] = src[1]; if (V->FatType == FAT32) { src = (char *) &(D->DIR_FstClusHI); dst[2] = src[0]; dst[3] = src[1]; } val=EFD(val); return val;}static int erase_dirent(DirEnt_t *D) { BYTE b; int i; if (D->last == 0) { b = FREEENT; } else { b = ENDOFDIR; } for (i=0; i < D->len; i++) D->entry[i].LDIR_Ord = b; return 0;}/* find a direntry by sfn name. require a buffer of 11 char containing the sfn name */static int find_direntry_bysfn(Volume_t *V, BYTE *sfnname, DWORD *Cluster, DWORD *Offset) { int res; DWORD bkclu, bkoff; DirEnt_t D; LfnEntry_t *buffer = D.entry; 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. /* checking if this is what we are lookin for */ res= utf8_strncmp((char *) sfnname, (char *) ((DirEntry_t *) &(buffer[res -1]))->DIR_Name, 11); // possible because Ascii are utf8 if (res == 0) { // we won! good. *Cluster = bkclu; *Offset = bkoff; return 0; } } return -2;}/* static routine to generate an lfn chain. utf8name must be null terminated */static int generate_lfn_chain(char *utf8name, LfnEntry_t *buf, BYTE checksum) { int res; int len; int i; int size; WORD lfn_name[256]; memset(lfn_name, 0, 256*sizeof(WORD)); len = res = utf8_strlen(utf8name); fprintf(stderr,"filename: %s, len:%d\n", utf8name, len); if ((res <= 0) || (res >255)) { perror("generate lfn chain() error: illegal filename length"); return -1; } size = ((len -1) /13) +1; // it is correct res = utf8to16(utf8name, lfn_name); if (res < 0) { perror("utf8to16() error: illegal filename length %d"); return -1; } // lets memset the buffer to FFFF (padding for lf name memset(buf,0xFF, (21 * sizeof(LfnEntry_t))); // lets begin writing the name, properly setting checksum and other fields to 0; for(i=0; i <len; i++) { res = set_lfn_char((LfnEntry_t *) &(buf[(size - 1 - (i / 13))]), lfn_name[i] , i); if (res != 0) return -1; } if ( (len % 13) != 0 ) { //if we dont have to go next entry res = set_lfn_char((LfnEntry_t *) &(buf[0]), 0x0000 , (len % 13)); if (res != 0) return -1; } for(i=1; i <=size; i++) { buf[size -i].LDIR_Ord = i; buf[size -i].LDIR_Attr = ATTR_LONG_NAME; buf[size -i].LDIR_Chksum = checksum; buf[size -i].LDIR_Type = 0; buf[size -i].LDIR_FstClusLO = 0; } buf[0].LDIR_Ord |= LFN_LASTENTRY; //lets return number of used entries return ( size ); // i suppose ((len -1) /13) +1 is wrong. im wrong}/* find n 32byte slots to store a file entry . it sets properly cluster and offset and returns absolute offset */static off64_t fat_find_lfnslots(Volume_t *V, File_t *dir, DWORD *Cluster , DWORD *Offset, int n) { DWORD oldclus,clus,newclus; DWORD off=0; int res; int found =0; char *cluster; int rootdirflag = 0; if ((dir == NULL) || (dir->rootdir == 1)) rootdirflag =1; if ((rootdirflag != 1)){ if (!ATTR_ISDIR(dir->DirEntry->DIR_Attr)) { perror("find lfnslots error: file is not a directory"); return -1; } clus = get_fstclus(V, dir->DirEntry); dir->CurAbsOff = 0; } else { if (V->FatType == FAT32) { clus = 2; } else clus = 1; } if ( fat_iseoc(V,clus) || fat_isfree(V,clus) ) { // this case should never happen since every directories cointain . and .. //we should fetch a new cluster here.. // when they are create so at least 1 cluster. return -1; } oldclus = newclus = clus; if ((V->FatType == FAT32) || (rootdirflag !=1)) { // FAT32 or not rootdir // now time to allocate space to read clusters; cluster = alloca(V->bpc); while (found < n) { if ((off % V->bpc) == 0) { //fetch new cluster off = 0; if ( fat_iseoc(V,newclus) || fat_isfree(V,newclus) ) { //set properly clus and off according with found, then allocate new cluster, link it and update the file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -