DWORD allocate_contiguous_clusters ( /* Returns the first sector in LBA (0:error or not contiguous) */ FIL* fp, /* Pointer to the open file object */ DWORD len /* Number of bytes to allocate */ ) { DWORD csz, tcl, ncl, ccl, cl; if (f_lseek(fp, 0) || !len) /* Check if the given parameters are valid */ return 0; csz = 512UL * fp->fs->csize; /* Cluster size in unit of byte (assuming 512 bytes/sector) */ tcl = (len + csz - 1) / csz; /* Total number of clusters required */ len = tcl * csz; /* Round-up file size to the cluster boundary */ /* Check if the existing cluster chain is contiguous */ if (len == fp->fsize) { ncl = 0; ccl = fp->sclust; do { cl = get_fat(fp->fs, ccl); /* Get the cluster status */ if (cl + 1 < 3) return 0; /* Hard error? */ if (cl != ccl + 1 && cl < fp->fs->n_fatent) break; /* Not contiguous? */ ccl = cl; } while (++ncl < tcl); if (ncl == tcl) /* Is the file contiguous? */ return clust2sect(fp->fs, fp->sclust); /* File is contiguous. Return the start sector */ } /* File is not contiguous */ #if _FS_READONLY return 0; /* Exit if in read-only cfg. */ #else if (!(fp->flag & FA_WRITE)) return 0; /* Exit if the file object is for read-only */ if (f_truncate(fp)) return 0; /* Remove the non-contiguous chain */ /* Find a free contiguous area */ ccl = cl = 2; ncl = 0; do { if (cl >= fp->fs->n_fatent) return 0; /* No contiguous area is found. */ if (get_fat(fp->fs, cl)) { /* Encounterd a cluster in use */ do { /* Skip the block of used clusters */ cl++; if (cl >= fp->fs->n_fatent) return 0; /* No contiguous area is found. */ } while (get_fat(fp->fs, cl)); ccl = cl; ncl = 0; } cl++; ncl++; } while (ncl < tcl); /* Create a contiguous cluster chain */ fp->fs->last_clust = ccl - 1; if (f_lseek(fp, len)) return 0; return clust2sect(fp->fs, fp->sclust); /* Return file start sector */ #endif }
FRESULT pf_write ( const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write (0:Finalize the current write operation) */ UINT* bw /* Pointer to number of bytes written */ ) { CLUST clst; DWORD sect, remain; const BYTE *p = buff; BYTE cs; UINT wcnt; FATFS *fs = FatFs; *bw = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; if (!btw) { /* Finalize request */ if ((fs->flag & FA__WIP) && disk_writep(0, 0)) ABORT(FR_DISK_ERR); fs->flag &= ~FA__WIP; return FR_OK; } else { /* Write data request */ if (!(fs->flag & FA__WIP)) /* Round-down fptr to the sector boundary */ fs->fptr &= 0xFFFFFE00; } remain = fs->fsize - fs->fptr; if (btw > remain) btw = (UINT)remain; /* Truncate btw by remaining bytes */ while (btw) { /* Repeat until all data transferred */ if ((UINT)fs->fptr % 512 == 0) { /* On the sector boundary? */ cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ if (!cs) { /* On the cluster boundary? */ if (fs->fptr == 0) /* On the top of the file? */ clst = fs->org_clust; else clst = get_fat(fs->curr_clust); if (clst <= 1) ABORT(FR_DISK_ERR); fs->curr_clust = clst; /* Update current cluster */ } sect = clust2sect(fs->curr_clust); /* Get current sector */ if (!sect) ABORT(FR_DISK_ERR); fs->dsect = sect + cs; if (disk_writep(0, fs->dsect)) ABORT(FR_DISK_ERR); /* Initiate a sector write operation */ fs->flag |= FA__WIP; } wcnt = 512 - (UINT)fs->fptr % 512; /* Number of bytes to write to the sector */ if (wcnt > btw) wcnt = btw; if (disk_writep(p, wcnt)) ABORT(FR_DISK_ERR); /* Send data to the sector */ fs->fptr += wcnt; p += wcnt; /* Update pointers and counters */ btw -= wcnt; *bw += wcnt; if ((UINT)fs->fptr % 512 == 0) { if (disk_writep(0, 0)) ABORT(FR_DISK_ERR); /* Finalize the currtent secter write operation */ fs->flag &= ~FA__WIP; } } return FR_OK; }
static FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table */ DIR *dj /* Pointer to directory object */ ) { CLUST clst; u16 i; FATFS *fs = FatFs; i = dj->index + 1; if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ return FR_NO_FILE; if (!(i & (16-1))) { /* Sector changed? */ dj->sect++; /* Next sector */ if (dj->clust == 0) { /* Static table */ if (i >= fs->n_rootdir) /* Report EOT when end of table */ return FR_NO_FILE; } else { /* Dynamic table */ if (((i / 16) & (fs->csize-1)) == 0) { /* Cluster changed? */ clst = get_fat(dj->clust); /* Get next cluster */ if (clst <= 1) return FR_DISK_ERR; if (clst >= fs->max_clust) /* When it reached end of dynamic table */ return FR_NO_FILE; /* Report EOT */ dj->clust = clst; /* Initialize data for new cluster */ dj->sect = clust2sect(clst); } } } dj->index = i; return FR_OK; }
FRESULT pf_write ( const void* buff, /* Pointer to the data to be written */ u16 btw, /* Number of bytes to write (0:Finalize the current write operation) */ u16* bw /* Pointer to number of bytes written */ ) { CLUST clst; u32 sect, remain; const u8 *p = buff; u16 wcnt; FATFS *fs = FatFs; *bw = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; if (!btw) { /* Finalize request */ if ((fs->flag & FA__WIP) && disk_writep(0, 0)) goto fw_abort; fs->flag &= ~FA__WIP; return FR_OK; } else { /* Write data request */ if (!(fs->flag & FA__WIP)) /* Round down fptr to the sector boundary */ fs->fptr &= 0xFFFFFE00; } remain = fs->fsize - fs->fptr; if (btw > remain) btw = (u16)remain; /* Truncate btw by remaining bytes */ while (btw) { /* Repeat until all data transferred */ if (((u16)fs->fptr % 512) == 0) { /* On the sector boundary? */ if ((fs->fptr / 512 % fs->csize) == 0) { /* On the cluster boundary? */ clst = (fs->fptr == 0) ? /* On the top of the file? */ fs->org_clust : get_fat(fs->curr_clust); if (clst <= 1) goto fw_abort; fs->curr_clust = clst; /* Update current cluster */ fs->csect = 0; /* Reset sector offset in the cluster */ } sect = clust2sect(fs->curr_clust); /* Get current sector */ if (!sect) goto fw_abort; fs->dsect = sect + fs->csect++; if (disk_writep(0, fs->dsect)) goto fw_abort; /* Initiate a sector write operation */ fs->flag |= FA__WIP; } wcnt = 512 - ((u16)fs->fptr % 512); /* Number of bytes to write to the sector */ if (wcnt > btw) wcnt = btw; if (disk_writep(p, wcnt)) goto fw_abort; /* Send data to the sector */ fs->fptr += wcnt; p += wcnt; /* Update pointers and counters */ btw -= wcnt; *bw += wcnt; if (((u16)fs->fptr % 512) == 0) { if (disk_writep(0, 0)) goto fw_abort; /* Finalize the currtent secter write operation */ fs->flag &= ~FA__WIP; } } return FR_OK; fw_abort: fs->flag = 0; return FR_DISK_ERR; }
FRESULT pf_read ( void* dest, /* Pointer to the destination object */ WORD btr, /* Number of bytes to read (bit15:destination) */ WORD* br /* Pointer to number of bytes read */ ) { DRESULT dr; CLUST clst; DWORD sect, remain; WORD rcnt; BYTE *rbuff = dest; FATFS *fs = FatFs; *br = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_READ)) return FR_INVALID_OBJECT; remain = fs->fsize - fs->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fs->fptr += rcnt, *br += rcnt, btr -= rcnt) { if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ if ((fs->fptr / 512 % fs->csize) == 0) { /* On the cluster boundary? */ clst = (fs->fptr == 0) ? /* On the top of the file? */ fs->org_clust : get_fat(fs->curr_clust); if (clst <= 1) { fs->flag = 0; return FR_DISK_ERR; } fs->curr_clust = clst; /* Update current cluster */ fs->csect = 0; /* Reset sector offset in the cluster */ } sect = clust2sect(fs->curr_clust); /* Get current sector */ if (!sect) { fs->flag = 0; return FR_DISK_ERR; } sect += fs->csect; fs->dsect = sect; fs->csect++; /* Next sector address in the cluster */ } rcnt = 512 - ((WORD)fs->fptr % 512); /* Get partial sector data from sector buffer */ if (rcnt > btr) rcnt = btr; if (fs->flag & FA_STREAM) { dr = disk_readp(dest, fs->dsect, (WORD)(fs->fptr % 512), (WORD)(rcnt | 0x8000)); } else { dr = disk_readp(rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt); } if (dr) { fs->flag = 0; return (dr == RES_STRERR) ? FR_STREAM_ERR : FR_DISK_ERR; } } return FR_OK; }
FRESULT pf_write ( const void* buff, /* Pointer to the data to be written */ WORD btw, /* Number of bytes to write (0:Finalize the current write operation) */ WORD* bw /* Pointer to number of bytes written */ ) { DRESULT dr; CLUST clst; DWORD sect, remain; WORD rcnt; BYTE cs; const BYTE *rbuff = buff; FATFS *fs = FatFs; *bw = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; remain = fs->fsize - fs->fptr; if (btw > remain) btw = (WORD)remain; /* Truncate btr by remaining bytes */ while (btw) { /* Repeat until all data transferred */ if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ if (!cs) { /* On the cluster boundary? */ clst = (fs->fptr == 0) ? /* On the top of the file? */ fs->org_clust : get_fat(fs->curr_clust); if (clst <= 1) goto fr_abort; fs->curr_clust = clst; /* Update current cluster */ } sect = clust2sect(fs->curr_clust); /* Get current sector */ if (!sect) goto fr_abort; fs->dsect = sect + cs; } rcnt = (WORD)(512 - (fs->fptr % 512)); /* Get partial sector data from sector buffer */ if (rcnt > btw) rcnt = btw; dr = disk_writep(!buff ? 0 : rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt); if (dr) goto fr_abort; fs->fptr += rcnt; rbuff += rcnt; /* Update pointers and counters */ btw -= rcnt; *bw += rcnt; } return FR_OK; fr_abort: fs->flag = 0; return FR_DISK_ERR; }
FRESULT pf_read ( void* buff, /* Pointer to the read buffer (NULL:Forward data to the stream)*/ WORD btr, /* Number of bytes to read */ WORD* br /* Pointer to number of bytes read */ ) { DRESULT dr; CLUST clst; DWORD sect, remain; WORD rcnt; BYTE cs, *rbuff = buff; FATFS *fs = FatFs; *br = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; //led_sign_ff(5); remain = fs->fsize - fs->fptr; if (btr > remain) btr = (WORD)remain; /* Truncate btr by remaining bytes */ while (btr) { /* Repeat until all data transferred */ if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ if (!cs) { /* On the cluster boundary? */ clst = (fs->fptr == 0) ? /* On the top of the file? */ fs->org_clust : get_fat(fs->curr_clust); if (clst <= 1) goto fr_abort; fs->curr_clust = clst; /* Update current cluster */ } sect = clust2sect(fs->curr_clust); /* Get current sector */ if (!sect) goto fr_abort; fs->dsect = sect + cs; } rcnt = (WORD)(512 - (fs->fptr % 512)); /* Get partial sector data from sector buffer */ if (rcnt > btr) rcnt = btr; dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt); if (dr) goto fr_abort; fs->fptr += rcnt; rbuff += rcnt; /* Update pointers and counters */ btr -= rcnt; *br += rcnt; } return FR_OK; fr_abort: fs->flag = 0; return FR_DISK_ERR; }
FRESULT pf_lseek ( DWORD ofs /* File pointer from top of file */ ) { CLUST clst; DWORD bcs, sect, ifptr; FATFS *fs = FatFs; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; if (ofs > fs->fsize) ofs = fs->fsize; /* Clip offset with the file size */ ifptr = fs->fptr; fs->fptr = 0; if (ofs > 0) { bcs = (DWORD)fs->csize * 512; /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fs->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ ofs -= fs->fptr; clst = fs->curr_clust; } else { /* When seek to back cluster, */ clst = fs->org_clust; /* start from the first cluster */ fs->curr_clust = clst; } while (ofs > bcs) { /* Cluster following loop */ clst = get_fat(clst); /* Follow cluster chain */ if (clst <= 1 || clst >= fs->max_clust) goto fe_abort; fs->curr_clust = clst; fs->fptr += bcs; ofs -= bcs; } fs->fptr += ofs; sect = clust2sect(clst); /* Current sector */ if (!sect) goto fe_abort; fs->csect = (BYTE)(ofs / 512); /* Sector offset in the cluster */ if (ofs % 512) fs->dsect = sect + fs->csect++; } return FR_OK; fe_abort: fs->flag = 0; return FR_DISK_ERR; }
FRESULT pf_read ( FATFS* fs, /* Filesystem descriptor */ void* buff, /* Pointer to the read buffer (NULL:Forward data to the stream)*/ UINT btr, /* Number of bytes to read */ UINT* br /* Pointer to number of bytes read */ ) { DRESULT dr; CLUST clst; DWORD sect, remain; UINT rcnt; BYTE cs, *rbuff = buff; *br = 0; if (!fs) return FR_NOT_ENABLED; /* Check file system */ if (!(fs->flag & FA_OPENED)) /* Check if opened */ return FR_NOT_OPENED; remain = fs->fsize - fs->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ while (btr) { /* Repeat until all data transferred */ if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ if (!cs) { /* On the cluster boundary? */ if (fs->fptr == 0) /* On the top of the file? */ clst = fs->org_clust; else clst = get_fat(fs, fs->curr_clust); if (clst <= 1) ABORT(FR_DISK_ERR); fs->curr_clust = clst; /* Update current cluster */ } sect = clust2sect(fs, fs->curr_clust); /* Get current sector */ if (!sect) ABORT(FR_DISK_ERR); fs->dsect = sect + cs; } rcnt = 512 - (UINT)fs->fptr % 512; /* Get partial sector data from sector buffer */ if (rcnt > btr) rcnt = btr; dr = disk_readp(&fs->disk, !buff ? 0 : rbuff, fs->dsect, (UINT)fs->fptr % 512, rcnt); if (dr) ABORT(FR_DISK_ERR); fs->fptr += rcnt; rbuff += rcnt; /* Update pointers and counters */ btr -= rcnt; *br += rcnt; } return FR_OK; }
static FRESULT dir_rewind( FATFS* fs, /* Filesystem descriptor */ DIR *dj /* Pointer to directory object */ ) { CLUST clst; dj->index = 0; clst = dj->sclust; if (clst == 1 || clst >= fs->n_fatent) /* Check start cluster range */ return FR_DISK_ERR; if (_FS_FAT32 && !clst && (_FS_32ONLY || fs->fs_type == FS_FAT32)) /* Replace cluster# 0 with root cluster# if in FAT32 */ clst = (CLUST)fs->dirbase; dj->clust = clst; /* Current cluster */ dj->sect = (_FS_32ONLY || clst) ? clust2sect(fs, clst) : fs->dirbase; /* Current sector */ return FR_OK; /* Seek succeeded */ }
static FRESULT dir_rewind ( DIR *dj /* Pointer to directory object */ ) { CLUST clst; FATFS *fs = FatFs; dj->index = 0; clst = dj->sclust; if (clst == 1 || clst >= fs->max_clust) /* Check start cluster range */ return FR_DISK_ERR; #if _FS_FAT32 if (!clst && fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ clst = fs->dirbase; #endif dj->clust = clst; /* Current cluster */ dj->sect = clst ? clust2sect(clst) : fs->dirbase; /* Current sector */ return FR_OK; /* Seek succeeded */ }
int ev_file_get_next_block(struct ev_file_status *st) { uint32_t sector_offset, clust; /* Reset st->state here by default, so we can just return error code in all error cases without worrying about forgetting to reset state in some corner case. */ uint8_t state = st->state; st->state = ST_STARTING; switch (state) { case ST_STARTING: ++st->st_get_block_done.sector; /* Figure out if we need to cross a cluster boundary. */ sector_offset = st->st_get_block_done.sector - st->data_first_sector; if (sector_offset % st->cluster_size) return EV_FILE_ST_DONE; /* Load next cluster entry from FAT. */ clust = st->file_cluster; if (clust < 2 || clust >= st->number_of_clusters + 2) return EV_FILE_ST_EUNSPC; return prep_read_fat_entry(clust, ST_LOOKUP_FILE_FAT, st); case ST_LOOKUP_FILE_FAT: st->file_cluster = st->locate_dir.cur_cluster; st->st_get_block_done.sector = clust2sect(st->file_cluster, st); return EV_FILE_ST_DONE; default: return EV_FILE_ST_EUNSPC; }; }
int ev_file_get_first_block(const char *filename, struct ev_file_status *st) { uint8_t si, di; char c; uint32_t clust; /* Reset st->state here by default, so we can just return error code in all error cases without worrying about forgetting to reset state in some corner case. */ uint8_t state = st->state; st->state = ST_STARTING; switch (state) { case ST_STARTING: /* First we need to read sector 0 to look for the root of a FAT file system, or possibly a BIOS partition table. (We don't strictly need the first few bytes, but it seems cleaner to just read a full sector). */ st->st_stream_bytes.sec = 0; st->st_stream_bytes.offset = 0; st->st_stream_bytes.len = 512; st->state = ST_STREAM_BLOCK_0; st->idx = 0; st->locate_fat.flags = 0; DEBUG(("Start reading FAT\n")); return EV_FILE_ST_STREAM_BYTES; case ST_STREAM_BLOCK_0: if (st->locate_fat.flags & FL_FAT_NO55AA) return EV_FILE_ST_EBADFS; /* We've read the first block on the device. Check if it is a FAT file system; if not check if it is a BIOS partition table and try the first partition. */ if ((st->locate_fat.flags & (FL_FAT_NOFAT16|FL_FAT_NOFAT32)) == (FL_FAT_NOFAT16|FL_FAT_NOFAT32)) { /* Not a FAT file system, try find partition 0 in a BIOS partition table. */ DEBUG(("Not FAT in sector 0, try first BIOS partion\n")); if (!(st->locate_fat.flags & FL_FAT_PART1)) return EV_FILE_ST_EBADFS; /* Save partition start temporarily, as partition_start_lba will be overwritten during the next sector read. */ st->fat_first_sector = st->locate_fat.partition_start_lba; st->st_stream_bytes.sec = st->locate_fat.partition_start_lba; st->st_stream_bytes.offset = 0; st->st_stream_bytes.len = 512; st->state = ST_STREAM_PART_BLOCK_0; st->idx = 0; st->locate_fat.flags = 0; return EV_FILE_ST_STREAM_BYTES; } DEBUG(("Using FAT file system in sector 0\n")); /* Fallthrough. */ case ST_STREAM_PART_BLOCK_0: if ((st->locate_fat.flags & FL_FAT_NO55AA) || (st->locate_fat.flags & (FL_FAT_NOFAT16|FL_FAT_NOFAT32)) == (FL_FAT_NOFAT16|FL_FAT_NOFAT32)) return EV_FILE_ST_EBADFS; /* We found something that has the signatures to look like a FAT file system. Now do some sanity checks on the read data, and load it into the permanent part of our structure if it looks ok. */ uint32_t base_sector = (state == ST_STREAM_PART_BLOCK_0 ? st->fat_first_sector : 0); uint32_t remain_sectors = st->locate_fat.number_of_sectors; if (st->locate_fat.reserved_sectors >= remain_sectors) return EV_FILE_ST_EBADFS; remain_sectors -= st->locate_fat.reserved_sectors; st->fat_first_sector = base_sector + st->locate_fat.reserved_sectors; uint32_t fat_tot_size = st->locate_fat.fat_sector_size * st->locate_fat.number_of_fats; if (fat_tot_size >= remain_sectors) return EV_FILE_ST_EBADFS; remain_sectors -= fat_tot_size; uint16_t num_rootdir_sectors = (st->num_rootdir_entries + 15)/16; if (num_rootdir_sectors >= remain_sectors) return EV_FILE_ST_EBADFS; remain_sectors -= num_rootdir_sectors; st->number_of_clusters = remain_sectors / st->cluster_size; st->data_first_sector = st->fat_first_sector + fat_tot_size + num_rootdir_sectors; if (st->number_of_clusters >= 0xfff5) st->flags = FL_FAT32; else if (st->number_of_clusters >= 0xff5) st->flags = FL_FAT16; else st->flags = FL_FAT12; DEBUG(("Found %s in sector %u\n", st->flags == FL_FAT32 ? "FAT32" : (st->flags == FL_FAT16 ? "FAT16" : "FAT12"), base_sector)); /* For FAT12/FAT16, root dir is of fixed size, just after the FAT. */ if ((st->flags & FL_TYPEMASK) != FL_FAT32) { st->root_dir_start = st->fat_first_sector + fat_tot_size; st->flags |= FL_FIXED_DIR; } DEBUG(("#sectors=%u #clusters=%u FAT size=%u rootdir at %u\n", st->locate_fat.number_of_sectors, st->number_of_clusters, st->locate_fat.fat_sector_size, st->root_dir_start)); state = ST_FIND_IN_DIR; /* Fall through ...*/ case ST_FIND_IN_DIR: /* Read the first sector of the directory, looking for the file name. */ si = 0; di = 0; /* Copy over file name, padding and uppercasing for easy comparison. */ for (;;) { c = filename[si++]; if (c == '\0' || c == '.') break; if (di >= 8) return EV_FILE_ST_ENAME; if (c >= 'a' && c <= 'z') c = c - ('a' - 'A'); st->locate_dir.name[di++] = c; } while (di < 8) st->locate_dir.name[di++] = ' '; if (c) { for (;;) { c = filename[si++]; if (c == '\0') break; if (di >= 11 || c == '.') return EV_FILE_ST_ENAME; if (c >= 'a' && c <= 'z') c = c - ('a' - 'A'); st->locate_dir.name[di++] = c; } } while (di < 11) st->locate_dir.name[di++] = ' '; st->idx = 0; st->locate_dir.remain_entries_in_dir = 16; st->locate_dir.flags = 0; st->locate_dir.cur_sector = 0; if (st->flags & FL_FIXED_DIR) st->st_stream_bytes.sec = st->root_dir_start; else { st->locate_dir.cur_cluster = st->root_dir_start; st->st_stream_bytes.sec = clust2sect(st->locate_dir.cur_cluster, st); } st->st_stream_bytes.offset = 0; st->st_stream_bytes.len = 512; st->state = ST_STREAM_DIR; return EV_FILE_ST_STREAM_BYTES; case ST_STREAM_DIR: /* We read and scanned a directory entry. Check if we found what we were looking for, else read the FAT to find the next directory entry, if any. */ if (st->locate_dir.flags & FL_DIR_FOUND) { /* Found it! */ st->file_cluster = st->locate_dir.start_cluster; st->st_get_block_done.length = st->locate_dir.file_length; st->st_get_block_done.sector = clust2sect(st->file_cluster, st); DEBUG(("File found! sector=%u len=%u cluster=%u\n", st->st_get_block_done.sector, st->locate_dir.file_length, st->locate_dir.start_cluster)); return EV_FILE_ST_DONE; } if (st->locate_dir.flags & FL_DIR_END) { /* Reached the end without finding anything. */ DEBUG(("Reached end of directory without finding file.\n")); return EV_FILE_ST_ENOENTRY; } /* We need to go scan the next sector of the directory, if any. */ ++st->locate_dir.cur_sector; if (st->locate_dir.cur_sector < (st->flags & FL_FIXED_DIR ? st->num_rootdir_entries : st->cluster_size)) { /* Scan the next sector in this cluster. */ st->idx = 0; st->locate_dir.remain_entries_in_dir = 16; st->locate_dir.flags = 0; st->st_stream_bytes.sec = (st->flags & FL_FIXED_DIR ? st->root_dir_start : clust2sect(st->locate_dir.cur_cluster, st)) + st->locate_dir.cur_sector; st->st_stream_bytes.offset = 0; st->st_stream_bytes.len = 512; st->state = ST_STREAM_DIR; return EV_FILE_ST_STREAM_BYTES; } /* Read FAT entry to get next cluster. */ state = ST_NEXT_CLUSTER_DIR; /* Fall through ... */ case ST_NEXT_CLUSTER_DIR: clust = st->locate_dir.cur_cluster; if (clust == 0) return EV_FILE_ST_ENOENTRY; if (clust < 2 || clust >= st->number_of_clusters + 2) return EV_FILE_ST_EBADFS; /* Now compute the sector(s) we need to read to get the FAT entry, as well as the offset/length. */ return prep_read_fat_entry(clust, ST_LOOKUP_DIR_FAT, st); case ST_LOOKUP_DIR_FAT: if (st->locate_dir.cur_cluster >= (uint32_t)0xfffffff8) { /* End of directory reached. */ return EV_FILE_ST_ENOENTRY; } if (st->locate_dir.cur_cluster < 2 || st->locate_dir.cur_cluster - 2 >= st->number_of_clusters) return EV_FILE_ST_EBADFS; /* Now go read the first sector of the next cluster in directory. */ st->idx = 0; st->locate_dir.remain_entries_in_dir = 16; st->locate_dir.flags = 0; st->st_stream_bytes.sec = clust2sect(st->locate_dir.cur_cluster, st); st->st_stream_bytes.offset = 0; st->st_stream_bytes.len = 512; st->state = ST_STREAM_DIR; return EV_FILE_ST_STREAM_BYTES; default: return EV_FILE_ST_EUNSPC; }; }