/* allocate a DirEntry in the directory `dirEntry' * its address in filesystem is returned in addr */ int allocateDirEntry(DirEntry *dirEntry,ULONG * value_addr) { int result = _traverse(dirEntry,traverse_availableDirEntry,value_addr); /* result == 1 means all clusters of dirEntry were searched * which means we can not found a available entry * allocate a new cluster to get one */ if( result == 1 ) { #ifdef DEBUG printf("No available Dir Entry in current cluster !\n"); #endif /* search the last cluster in the FAT chain * allocate a new cluster and append it to the last cluster */ ULONG startCluster = getDirClusterNum(dirEntry); ULONG last = getLastCluster(startCluster); ULONG newCluster = allocateCluster(); if( newCluster == 0 ) report_exit("Not enough space!\n"); FAT[last] = newCluster; FAT[newCluster] = EOD; updateAllFat(); /* allocate the first dir entry in the cluster */ *value_addr = (cluster2sector( newCluster ) * bps); } #ifdef DEBUG printf("Allocated dirEntry address: 0x%08x\n",(int)*value_addr); #endif return 1; }
int fat_blockread(int fd, void *buffer) { uint32_t block; uint32_t temp; fhandle_t *handle = fd_handles[fd]; if ( (fd > MAX_FILES) || (fd < 0) ) // if not valid index return (uint32_t) -1; // return failure if (handle == NULL) // if slot is not in use return (uint32_t) -1; // return failure if (handle->foffset > handle->highwater) { return 0; } block = cluster2sector(handle->cluster); // get the start block temp = handle->foffset % bytes_per_cluster; // for later use // add local block within a cluster block += temp / bytes_per_sector; TRACE_FAT("blockread: %ld\n",block); // read the data sd_readsector(block, buffer, 0, 0); /*handle->foffset += bytes_per_sector;*/ handle->foffset += bytes_per_sector - (handle->foffset%bytes_per_sector); if (handle->foffset % bytes_per_cluster == 0) // cluster boundary { // need to get a new cluster handle->cluster = fat_nextcluster(handle->cluster); // follow FAT chain //if (fd->cluster == -1) // if we're at end of chain //{ //break; // we're finished, there is no more data //} } return bytes_per_sector; }
/* * traverse all cluster belonged to the DirEntry de, * pass the cluster read to func for processing * set a value `value_addr' to indicate the stop address */ int _traverse(DirEntry * de,int (*func)(unsigned char *,int,ULONG *), ULONG * value_addr) { int result=0; ULONG base_sector,dir_cluster; ULONG nRemain = de->DIR_FileSize; dir_cluster = getDirClusterNum(de); if( nRemain == 0 ) { /* for a Directory DirEntry.size= 0 * set to INF to keep the traverse going*/ if( de->DIR_Attr & ATTR_DIR ) nRemain = INF; /* some normal file may have size=0,no allocated cluster for it */ else return 1; } /* traverse the FAT chain */ ULONG stopat,len=0; do { base_sector = data_secNum + spc*(dir_cluster-2); /* read the whole cluster */ len = read_sectors(base_sector,buffer,spc); #ifdef DEBUG printf("Cluster : %lu\n",dir_cluster); printf("Sector : %lu\n",base_sector); printf("Read: %lu\nRemain: %lu\n",len,nRemain); #endif /* pass the buffer content to func for processing * NOTE: result=1 means keep traversing * result=0 means stop traversing, and stopat point to * the stop position in buffer * */ if(nRemain<len) result = func(buffer,nRemain,&stopat); else result = func(buffer,len,&stopat); if( result == 0 ) { *value_addr = (cluster2sector(dir_cluster)*bps + stopat); break; } nRemain -= len; dir_cluster=FAT[dir_cluster]; } while( dir_cluster < END_MARK ); return result; }
/** * Read specific number of bytes from file * * \param fd File handle * \param buffer Buffer to store data * \param len Number of bytes to read * \return Number of bytes successful read. * */ int fat_read(int fd, char *buffer, int len) { uint16_t nbytes; uint32_t block; uint16_t dcount; uint16_t loffset; fhandle_t *handle = fd_handles[fd]; TRACE_FAT("fat_read %d,%08x,%d\n",fd,buffer,len); if ( (fd > MAX_FILES) || (fd < 0) ) // if not valid index return -1; // return failure if (handle == NULL) // if slot is not in use return -1; // return failure // limit max read to size of file if (len > (handle->highwater - handle->foffset) ) len = handle->highwater - handle->foffset; dcount = len; TRACE_FAT("fat_read\n"); while (dcount) { loffset = handle->foffset % bytes_per_sector; // local offset within a block block = cluster2sector(handle->cluster); // get the start block // add local block within a cluster block += (handle->foffset % bytes_per_cluster) / bytes_per_sector; // limit to max one block nbytes = dcount < bytes_per_sector ? dcount : bytes_per_sector; //limit to remaining bytes in a block if (nbytes > (bytes_per_sector - loffset) ) nbytes = bytes_per_sector - loffset; // read the data sd_read_n(block, loffset, nbytes, (uint8_t*) buffer); // bump buffer pointer buffer += nbytes; handle->foffset += nbytes; dcount -= nbytes; if (handle->foffset % bytes_per_cluster == 0) // cluster boundary { // need to get a new cluster handle->cluster = fat_nextcluster(handle->cluster); // follow FAT chain if (handle->cluster == -1) // if we're at end of chain { break; // we're finished, there is no more data } } } TRACE_FAT("fat_read return %d\n",len - dcount); return len - dcount; }
/** * Scan through directory entries to find the given file or directory * * \param ff_data FatFind helper structure * \return Error code * */ static int ff_scan(fatffdata_t * ff_data) { uint16_t i,j, eindex; uint16_t sectoroffset, entryoffset, maxsector; uint32_t cluster; uint32_t sector; uint8_t match,longmatch; char matchspace[13]; fatdirentry_t *de; uint8_t n; uint8_t nameoffset; eindex = ff_data->ff_offset; cluster = ff_data->ff_cluster; sectoroffset = eindex / (bytes_per_sector/sizeof(fatdirentry_t)); entryoffset = eindex % (bytes_per_sector/sizeof(fatdirentry_t)); if (isFAT32 == 0 && cluster == root_dir_cluster ) // if not FAT32 and this is the root dir maxsector = root_dir_sectors; // set max sector count for root dir else maxsector = sectors_per_cluster; longmatch = 0; // loop until entry found or end of list while (1) { sector = cluster2sector(cluster); for (i=sectoroffset;i<maxsector;i++) { readsector(sector+i, (uint8_t*) sector_buffer); // request a sector de = (fatdirentry_t *) sector_buffer; de += entryoffset; for (j=entryoffset;j<bytes_per_sector/sizeof(fatdirentry_t);j++) // 32 entries per sector { if (*de->deName == SLOT_EMPTY) { return -1; } if (*de->deName != SLOT_DELETED) { if ((de->deAttributes & ATTR_LONG_FILENAME) == ATTR_LONG_FILENAME) { // found long name entry if ( ((struct winentry *)de)->weCnt & WIN_LAST ) // first part of a long name memset(ff_data->ff_name,0,sizeof(ff_data->ff_name)); // clear name // piece together a fragment of the long name // and place it at the correct spot nameoffset = ((((struct winentry *)de)->weCnt & WIN_CNT)-1) * WIN_CHARS; for (n=0;n<5;n++) ff_data->ff_name[nameoffset+n] = ((struct winentry *)de)->wePart1[n*2]; for (n=0;n<6;n++) ff_data->ff_name[nameoffset+5+n] = ((struct winentry *)de)->wePart2[n*2]; for (n=0;n<2;n++) ff_data->ff_name[nameoffset+11+n] = ((struct winentry *)de)->wePart3[n*2]; if ( (((struct winentry *)de)->weCnt & WIN_CNT) == 1 ) // long name complete { // set match flag longmatch = szWildMatch8(ff_data->ff_search, ff_data->ff_name); } } else { // found short name entry, determine a match dos2str(matchspace,(char*)de->deName,(char*)de->deExtension); match = szWildMatch8(ff_data->ff_search, matchspace); // special! // skip the single dot entry if (strcmp(matchspace,".") != 0) { if ((match || longmatch) && ((de->deAttributes & ATTR_VOLUME) == 0)) { // found ff_data->ff_cluster = cluster; ff_data->ff_offset = eindex; // save index of file memcpy(&ff_data->ff_de,de,sizeof(fatdirentry_t)); if (!longmatch) { strcpy(ff_data->ff_name, matchspace); } return 0; } } } }//if !SLOT_DELETED eindex++; de++; // next entry }//for (j=entryoffset entryoffset = 0; }//for (i=sectoroffset sectoroffset = 0; cluster = fat_nextcluster(cluster); if (cluster == 0) // if end of chain { TRACE_FAT("ff_scan end of chain\n"); return -1; } eindex = 0; }//while }