📄 ff.c
字号:
}
#endif
}
#endif /* _FS_MINIMIZE <= 1 */
/*-----------------------------------------------------------------------*/
/* Follow a file path */
/*-----------------------------------------------------------------------*/
static
FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
DIR *dj, /* Directory object to return last directory and found object */
const TCHAR *path /* Full-path string to find a file or directory */
)
{
FRESULT res;
BYTE *dir, ns;
#if _FS_RPATH
if (*path == '/' || *path == '\\') { /* There is a heading separator */
path++; dj->sclust = 0; /* Strip it and start from the root dir */
} else { /* No heading separator */
dj->sclust = dj->fs->cdir; /* Start from the current dir */
}
#else
if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
path++;
dj->sclust = 0; /* Start from the root dir */
#endif
if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
res = dir_sdi(dj, 0);
dj->dir = 0;
} else { /* Follow path */
for (;;) {
res = create_name(dj, &path); /* Get a segment */
if (res != FR_OK) break;
res = dir_find(dj); /* Find it */
ns = *(dj->fn+NS);
if (res != FR_OK) { /* Failed to find the object */
if (res != FR_NO_FILE) break; /* Abort if any hard error occured */
/* Object not found */
if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
dj->sclust = 0; dj->dir = 0; /* It is the root dir */
res = FR_OK;
if (!(ns & NS_LAST)) continue;
} else { /* Could not find the object */
if (!(ns & NS_LAST)) res = FR_NO_PATH;
}
break;
}
if (ns & NS_LAST) break; /* Last segment match. Function completed. */
dir = dj->dir; /* There is next segment. Follow the sub directory */
if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
res = FR_NO_PATH; break;
}
dj->sclust = LD_CLUST(dir);
}
}
return res;
}
/*-----------------------------------------------------------------------*/
/* Load boot record and check if it is an FAT boot record */
/*-----------------------------------------------------------------------*/
static
BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
FATFS *fs, /* File system object */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
)
{
if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
return 3;
if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
return 2;
if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
return 0;
if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
return 0;
return 1;
}
/*-----------------------------------------------------------------------*/
/* Check if the file system object is valid or not */
/*-----------------------------------------------------------------------*/
static
FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
FATFS **rfs, /* Pointer to pointer to the found file system object */
BYTE chk_wp /* !=0: Check media write protection for write access */
)
{
BYTE fmt, b, *tbl;
UINT vol;
DSTATUS stat;
DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
WORD nrsv;
const TCHAR *p = *path;
FATFS *fs;
/* Get logical drive number from the path name */
vol = p[0] - '0'; /* Is there a drive number? */
if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
p += 2; *path = p; /* Return pointer to the path name */
} else { /* No drive number is given */
#if _FS_RPATH
vol = CurrVol; /* Use current drive */
#else
vol = 0; /* Use drive 0 */
#endif
}
/* Check if the logical drive is valid or not */
if (vol >= _VOLUMES) /* Is the drive number valid? */
return FR_INVALID_DRIVE;
*rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */
if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
ENTER_FF(fs); /* Lock file system */
if (fs->fs_type) { /* If the logical drive has been mounted */
stat = disk_status(fs->drv);
if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
#if !_FS_READONLY
if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
return FR_WRITE_PROTECTED;
#endif
return FR_OK; /* The file system object is valid */
}
}
/* The logical drive must be mounted. */
/* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */
fs->fs_type = 0; /* Clear the file system object */
fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
if (stat & STA_NOINIT) /* Check if the initialization succeeded */
return FR_NOT_READY; /* Failed to initialize due to no media or hard error */
#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
return FR_DISK_ERR;
#endif
#if !_FS_READONLY
if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
return FR_WRITE_PROTECTED;
#endif
/* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */
/* Check the partition listed in top of the partition table */
tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
if (tbl[4]) { /* Is the partition existing? */
bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
fmt = check_fs(fs, bsect); /* Check the partition */
}
}
if (fmt == 3) return FR_DISK_ERR;
if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
/* Following code initializes the file system object */
if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
return FR_NO_FILESYSTEM;
fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
fs->fsize = fasize;
fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
fasize *= b; /* Number of sectors for FAT area */
fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
/* Determine the FAT sub type */
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
fmt = FS_FAT12;
if (nclst >= MIN_FAT16) fmt = FS_FAT16;
if (nclst >= MIN_FAT32) fmt = FS_FAT32;
/* Boundaries and Limits */
fs->n_fatent = nclst + 2; /* Number of FAT entries */
fs->database = bsect + sysect; /* Data start sector */
fs->fatbase = bsect + nrsv; /* FAT start sector */
if (fmt == FS_FAT32) {
if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
szbfat = fs->n_fatent * 4; /* (Required FAT size) */
} else {
if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
}
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */
return FR_NO_FILESYSTEM;
#if !_FS_READONLY
/* Initialize cluster allocation information */
fs->free_clust = 0xFFFFFFFF;
fs->last_clust = 0;
/* Get fsinfo if available */
if (fmt == FS_FAT32) {
fs->fsi_flag = 0;
fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
}
}
#endif
fs->fs_type = fmt; /* FAT sub-type */
fs->id = ++Fsid; /* File system mount ID */
fs->winsect = 0; /* Invalidate sector cache */
fs->wflag = 0;
#if _FS_RPATH
fs->cdir = 0; /* Current directory (root dir) */
#endif
#if _FS_SHARE /* Clear file lock semaphores */
clear_lock(fs);
#endif
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Check if the file/dir object is valid or not */
/*-----------------------------------------------------------------------*/
static
FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
FATFS *fs, /* Pointer to the file system object */
WORD id /* Member id of the target object to be checked */
)
{
if (!fs || !fs->fs_type || fs->id != id)
return FR_INVALID_OBJECT;
ENTER_FF(fs); /* Lock file system */
if (disk_status(fs->drv) & STA_NOINIT)
return FR_NOT_READY;
return FR_OK;
}
/*--------------------------------------------------------------------------
Public Functions
--------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Logical Drive */
/*-----------------------------------------------------------------------*/
FRESULT f_mount (
BYTE vol, /* Logical drive number to be mounted/unmounted */
FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
)
{
FATFS *rfs;
if (vol >= _VOLUMES) /* Check if the drive number is valid */
return FR_INVALID_DRIVE;
rfs = FatFs[vol]; /* Get current fs object */
if (rfs) {
#if _FS_SHARE
clear_lock(rfs);
#endif
#if _FS_REENTRANT /* Discard sync object of the current volume */
if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
#endif
rfs->fs_type = 0; /* Clear old fs object */
}
if (fs) {
fs->fs_type = 0; /* Clear new fs object */
#if _FS_REENTRANT /* Create sync object for the new volume */
if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
#endif
}
FatFs[vol] = fs; /* Register new fs object */
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Open or Create a File */
/*-----------------------------------------------------------------------*/
FRESULT f_open (
FIL *fp, /* Pointer to the blank file object */
const TCHAR *path, /* Pointer to the file name */
BYTE mode /* Access mode and file open mode flags */
)
{
FRESULT res;
DIR dj;
BYTE *dir;
DEF_NAMEBUF;
fp->fs = 0; /* Clear file object */
#if !_FS_READONLY
mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
#else
mode &= FA_READ;
res = chk_mounted(&path, &dj.fs, 0);
#endif
INIT_BUF(dj);
if (res == FR_OK)
res = follow_path(&dj, path); /* Follow the file path */
dir = dj.dir;
#if !_FS_READONLY /* R/W configuration */
if (res == FR_OK) {
if (!dir) /* Current dir itself */
res = FR_INVALID_NAME;
#if _FS_SHARE
else
res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
#endif
}
/* Create or Open a file */
if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
DWORD dw, cl;
if (res != FR_OK) { /* No file, create new */
if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
#if _FS_SHARE
res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
#else
res = dir_register(&dj);
#endif
mode |= FA_CREATE_ALWAYS; /* File is created */
dir = dj.dir; /* New entry */
}
else { /* Any object is already existing */
if (mode & FA_CREATE_NEW) { /* Cannot create new */
res = FR_EXIST;
} else {
if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */
res = FR_DENIED;
}
}
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
dw = get_fattime(); /* Created time */
ST_DWORD(dir+DIR_CrtTime, dw);
dir[DIR_Attr] = 0; /* Reset attribute */
ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
cl = LD_CLUST(dir); /* Get start cluster */
ST_CLUST(dir, 0); /* cluster = 0 */
dj.fs->wflag = 1;
if (cl) { /* Remove the cluster chain if exist */
dw = dj.fs->winsect;
res = remove_chain(dj.fs, cl);
if (res == FR_OK) {
dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
res = move_window(dj.fs, dw);
}
}
}
}
else { /* Open an existing file */
if (res == FR_OK) { /* Follow
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -