static FRESULT follow_path( /* FR_OK(0): successful, !=0: error code */ DIR* dp, /* Directory object to return last directory and found object */ const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; FATFS *fs = dp->obj.fs;
// 1. 跳过分隔符 { /* With heading separator */ while (IsSeparator(*path)) path++; /* Strip separators */ dp->obj.sclust = 0; /* Start from the root directory */ }
// 2. 这里主要是处理根目录的场景 if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); } else { /* Follow path */ // 3. 逐级目录进行处理 for (;;) { // 3.1. 找到top的目录的名字,保存在dp->fn中,如 /a/b/c,先得到A,下一次进来再得到B(会转为大写) res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; // 3.2 找到目录项 res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; // 3.2 如果没有找到 if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } } break; } // 如果找到了,并且follow_path已经到了最后,那么退出 if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ // 如果找到了,但是它并不是一个目录(如/a/b 并不是一个目录项,那么它是不能follow的) if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } // 如果都符合,那么找到了对应这一级的目录项,更新sclust为这个目录项起始的簇(也可以理解为进入子目录) { dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } }
static FRESULT dir_find( /* FR_OK(0):succeeded, !=0:error */ DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; #if FF_USE_LFN BYTE a, ord, sum; #endif // 从父目录的头开始查找,set index 为0 res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res;
do { // 不断地更新窗口 res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; // 比较目录项的名字,如果相同,就是找到了 if (!(dp->dir[DIR_Attr] & AM_VOL) && !memcmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ // 否则,继续找下一个目录项 res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK);
static FRESULT move_window( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector LBA to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK;
if (sect != fs->winsect) { /* Window offset changed? */ #if !FF_FS_READONLY res = sync_window(fs); /* Flush the window */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) { sect = (LBA_t)0 - 1; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sect; } } return res; }
static FRESULT dir_next( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ DIR* dp, /* Pointer to the directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs;
ofs = dp->dptr + SZDIRE; /* Next entry */ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */
if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */
if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ #if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ dp->sect = clst2sect(fs, clst); } } } dp->dptr = ofs; /* Current entry */ dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */
// 我们要新建一个chain,因此 clst传入的是0, 如果不是0,表示在原先的簇链上再添加一个簇。 if (clst == 0) { /* Create a new chain */ scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ if (cs < 2) return1; /* Test for insanity */ if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; /* Cluster to start to find */ } if (fs->free_clst == 0) return0; /* No free cluster */
{ /* On the FAT/FAT32 volume */ ncl = 0; if (scl == clst) { /* Stretching an existing chain? */ ncl = scl + 1; /* Test if next cluster is free */ if (ncl >= fs->n_fatent) ncl = 2; cs = get_fat(obj, ncl); /* Get next cluster status */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (cs != 0) { /* Not free? */ cs = fs->last_clst; /* Start at suggested cluster if it is valid */ if (cs >= 2 && cs < fs->n_fatent) scl = cs; ncl = 0; } } if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ if (ncl >= fs->n_fatent) { /* Check wrap-around */ ncl = 2; if (ncl > scl) return0; /* No free cluster found? */ } cs = get_fat(obj, ncl); /* Get the cluster status */ if (cs == 0) break; /* Found a free cluster? */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (ncl == scl) return0; /* No free cluster found? */ } } res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } }
if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ }
return ncl; /* Return new cluster number or error status */ }
static FRESULT dir_register( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs;
res = dir_alloc(dp, 1); // 分配一个目录项
/* Set SFN entry */ if (res == FR_OK) { res = move_window(fs, dp->sect); if (res == FR_OK) { memset(dp->dir, 0, SZDIRE); /* Clean the entry */ // 保存名字 memcpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */