diff --git a/source/fatfs/00history.txt b/source/fatfs/00history.txt index 5d40fb6..ab22088 100644 --- a/source/fatfs/00history.txt +++ b/source/fatfs/00history.txt @@ -260,8 +260,20 @@ R0.12a (July 10, 2016) Added support for creating exFAT volume with some changes of f_mkfs(). Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. f_forward() is available regardless of _FS_TINY. - Fixed f_mkfs() creates wrong volume. + Fixed f_mkfs() creates wrong volume. (appeared at R0.12) + Fixed wrong memory read in create_name(). (appeared at R0.12) Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. - Fixed wrong memory read in create_name(). + +R0.12b (September 04, 2016) + + Improved f_rename() to be able to rename objects with the same name but case. + Fixed an error in the case conversion teble of code page 866. (ff.c) + Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) + Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) + Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) + Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) + Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) + Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) + diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index ad483fe..89472b3 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -45,9 +45,9 @@ FATpartition DriveInfo[11] = { { TYPE_EMUNAND, SUBTYPE_CTRN }, // 4 - EMUNAND CTRNAND { TYPE_EMUNAND, SUBTYPE_TWLN }, // 5 - EMUNAND TWLN { TYPE_EMUNAND, SUBTYPE_TWLP }, // 6 - EMUNAND TWLP - { TYPE_IMGNAND, SUBTYPE_CTRN }, // 7 - EMUNAND CTRNAND - { TYPE_IMGNAND, SUBTYPE_TWLN }, // 8 - EMUNAND TWLN - { TYPE_IMGNAND, SUBTYPE_TWLP }, // 9 - EMUNAND TWLP + { TYPE_IMGNAND, SUBTYPE_CTRN }, // 7 - IMGNAND CTRNAND + { TYPE_IMGNAND, SUBTYPE_TWLN }, // 8 - IMGNAND TWLN + { TYPE_IMGNAND, SUBTYPE_TWLP }, // 9 - IMGNAND TWLP { TYPE_IMAGE, SUBTYPE_NONE } // X - IMAGE }; diff --git a/source/fatfs/diskio.h b/source/fatfs/diskio.h index 9ca0c7e..945f391 100644 --- a/source/fatfs/diskio.h +++ b/source/fatfs/diskio.h @@ -67,6 +67,9 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); #define MMC_GET_CID 12 /* Get CID */ #define MMC_GET_OCR 13 /* Get OCR */ #define MMC_GET_SDSTAT 14 /* Get SD status */ +#define ISDIO_READ 55 /* Read data form SD iSDIO register */ +#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ +#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ /* ATA/CF specific ioctl command */ #define ATA_GET_REV 20 /* Get F/W revision */ diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c index 9c1ad98..84ca874 100644 --- a/source/fatfs/ff.c +++ b/source/fatfs/ff.c @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12a / +/ FatFs - Generic FAT file system module R0.12b / /-----------------------------------------------------------------------------/ / / Copyright (C) 2016, ChaN, all right reserved. @@ -29,7 +29,7 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 80186 /* Revision ID */ +#if _FATFS != 68020 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -299,7 +299,7 @@ typedef struct { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #elif _CODE_PAGE == 869 /* Greek 2 */ @@ -397,7 +397,7 @@ typedef struct { #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ #define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ -#define BPB_Media 21 /* Media descriptor (BYTE) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ #define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ @@ -410,6 +410,7 @@ typedef struct { #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* File system type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ @@ -463,8 +464,6 @@ typedef struct { #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define BS_55AA 510 /* Signature word (WORD) */ - #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ #define DIR_NTres 12 /* Lower case flag (BYTE) */ @@ -521,7 +520,7 @@ typedef struct { / at start-up. If not, either the linker or start-up routine being used is / not compliance with C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 10 // increased by one >:) +#if _VOLUMES < 1 || _VOLUMES > 10 // increased by 1 >:) #error Wrong _VOLUMES setting #endif static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ @@ -1142,7 +1141,7 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { @@ -1181,7 +1180,7 @@ FRESULT change_bitmap ( clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ i = clst / 8 % SS(fs); /* Byte offset in the sector */ bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { @@ -1195,6 +1194,7 @@ FRESULT change_bitmap ( } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ + i = 0; } } @@ -1264,7 +1264,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } - if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */ + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } @@ -1321,7 +1321,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (clst == 0) { /* Create a new chain */ - scl = fs->last_clst; /* Get suggested cluster to start at */ + scl = fs->last_clst; /* Get suggested cluster to start from */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch current chain */ @@ -1333,7 +1333,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err } #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ @@ -1349,7 +1349,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err } } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ @@ -1775,7 +1775,7 @@ void gen_numname ( /* itoa (hexdecimal) */ i = 7; do { - c = (seq % 16) + '0'; + c = (BYTE)((seq % 16) + '0'); if (c > '9') c += 7; ns[i--] = c; seq /= 16; @@ -2105,7 +2105,7 @@ FRESULT dir_read ( c = dp->dir[DIR_Name]; /* Test for the entry type */ if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (_USE_LABEL && vol) { if (c == 0x83) break; /* Volume label entry? */ } else { @@ -2120,7 +2120,7 @@ FRESULT dir_read ( } } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if _USE_LFN != 0 /* LFN configuration */ if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ @@ -2129,7 +2129,7 @@ FRESULT dir_read ( if (a == AM_LFN) { /* An LFN entry is found */ if (c & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; + c &= (BYTE)~LLEF; ord = c; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ @@ -2178,7 +2178,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ @@ -2194,7 +2194,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ return res; } #endif - /* At the FAT12/16/32 */ + /* On the FAT12/16/32 volume */ #if _USE_LFN != 0 ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif @@ -2212,7 +2212,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; /* LFN start order */ + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ @@ -2258,7 +2258,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ DIR dj; nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ @@ -2266,7 +2266,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ - if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */ + if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ dp->obj.stat &= 3; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ @@ -2284,7 +2284,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S return FR_OK; } #endif - /* At the FAT12/16/32 */ + /* On the FAT12/16/32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ @@ -2361,9 +2361,9 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ res = move_window(fs, dp->sect); if (res != FR_OK) break; /* Mark an entry 'deleted' */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; - } else { /* At the FAT12/16/32 */ + } else { /* On the FAT12/16/32 volume */ dp->dir[DIR_Name] = DDEM; } fs->wflag = 1; @@ -2413,12 +2413,12 @@ void get_fileinfo ( /* No return code */ #if _USE_LFN != 0 /* LFN configuration */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ get_xdir_info(fs->dirbuf, fno); return; } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ i = j = 0; while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ @@ -2430,7 +2430,7 @@ void get_fileinfo ( /* No return code */ } #endif if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ - fno->fname[i++] = (char)w; + fno->fname[i++] = (TCHAR)w; } fno->fname[i] = 0; /* Terminate the LFN */ } @@ -2628,7 +2628,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ if (si) cf |= NS_LOSS | NS_LFN; while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ - b = i = 0; ni = 8; + i = b = 0; ni = 8; for (;;) { w = lfn[si++]; /* Get an LFN character */ if (!w) break; /* Break on end of the LFN */ @@ -2955,7 +2955,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ UINT i; - /* Get logical drive number from the path name */ + /* Get logical drive number */ *rfs = 0; vol = get_ldnumber(path); if (vol < 0) return FR_INVALID_DRIVE; @@ -2967,7 +2967,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ ENTER_FF(fs); /* Lock the volume */ *rfs = fs; /* Return pointer to the file system object */ - mode &= ~FA_READ; /* Desired access mode, write access or not */ + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type) { /* If the volume has been mounted */ stat = disk_status(fs->drv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ @@ -3045,7 +3045,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Check if bitmap location is in assumption (at the first cluster) */ @@ -3162,15 +3162,14 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - void* dfp, /* Pointer to the FIL/DIR object to check validity */ + _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ FATFS** fs /* Pointer to pointer to the owner file system object to return */ ) { - _FDID *obj = (_FDID*)dfp; /* Assuming .obj in the FIL/DIR is the first member */ FRESULT res; - if (!dfp || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { + if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { *fs = 0; /* The object is invalid */ res = FR_INVALID_OBJECT; } else { @@ -3208,6 +3207,7 @@ FRESULT f_mount ( const TCHAR *rp = path; + /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; cfs = FatFs[vol]; /* Pointer to fs object */ @@ -3261,7 +3261,7 @@ FRESULT f_open ( if (!fp) return FR_INVALID_OBJECT; - /* Get logical drive number */ + /* Get logical drive */ mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; res = find_volume(&path, &fs, mode); if (res == FR_OK) { @@ -3460,7 +3460,7 @@ FRESULT f_read ( *br = 0; /* Clear read byte counter */ - res = validate(fp, &fs); + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; @@ -3495,9 +3495,7 @@ FRESULT f_read ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if _FS_TINY if (fs->wflag && fs->winsect - sect < cc) { @@ -3517,12 +3515,10 @@ FRESULT f_read ( #if !_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -3563,13 +3559,12 @@ FRESULT f_write ( *bw = 0; /* Clear write byte counter */ - res = validate(fp, &fs); + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */ - if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr) - || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) { + /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ + if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } @@ -3604,7 +3599,7 @@ FRESULT f_write ( #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clust2sect(fs, fp->clust); /* Get current sector */ @@ -3615,9 +3610,7 @@ FRESULT f_write ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if _FS_MINIMIZE <= 2 #if _FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ @@ -3627,7 +3620,7 @@ FRESULT f_write ( #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif #endif @@ -3635,16 +3628,15 @@ FRESULT f_write ( continue; } #if _FS_TINY - if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling at growing edge */ + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; } #else - if (fp->sect != sect) { /* Fill sector cache with file data */ - if (fp->fptr < fp->obj.objsize && - disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); } #endif fp->sect = sect; @@ -3661,7 +3653,7 @@ FRESULT f_write ( #endif } - fp->flag |= FA_MODIFIED; /* Set file change flag */ + fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } @@ -3681,18 +3673,16 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; -#if _FS_EXFAT DEF_NAMBUF -#endif - res = validate(fp, &fs); /* Check validity of the object */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif /* Update the directory entry */ @@ -3717,7 +3707,7 @@ FRESULT f_sync ( res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); - fp->flag &= ~FA_MODIFIED; + fp->flag &= (BYTE)~FA_MODIFIED; } } FREE_NAMBUF(); @@ -3735,7 +3725,7 @@ FRESULT f_sync ( st_word(dir + DIR_LstAccDate, 0); fs->wflag = 1; res = sync_fs(fs); /* Restore it to the directory */ - fp->flag &= ~FA_MODIFIED; + fp->flag &= (BYTE)~FA_MODIFIED; } } } @@ -3765,7 +3755,7 @@ FRESULT f_close ( if (res == FR_OK) #endif { - res = validate(fp, &fs); /* Lock volume */ + res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { #if _FS_LOCK != 0 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ @@ -3798,10 +3788,11 @@ FRESULT f_chdrive ( int vol; + /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; - CurrVol = (BYTE)vol; + CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } @@ -3817,7 +3808,7 @@ FRESULT f_chdir ( FATFS *fs; DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; @@ -3876,7 +3867,7 @@ FRESULT f_getcwd ( *buff = 0; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; @@ -3953,7 +3944,7 @@ FRESULT f_lseek ( DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif - res = validate(fp, &fs); /* Check validity of the object */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ @@ -3994,13 +3985,11 @@ FRESULT f_lseek ( #if !_FS_TINY #if !_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fp, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } @@ -4011,6 +4000,9 @@ FRESULT f_lseek ( /* Normal Seek */ { +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#endif if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } @@ -4020,7 +4012,7 @@ FRESULT f_lseek ( bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ - fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ @@ -4037,20 +4029,25 @@ FRESULT f_lseek ( } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; #if !_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */ - if (clst == 0) { /* When disk gets full, clip file size */ - ofs = bcs; break; + if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; } } else #endif + { clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; - fp->fptr += bcs; - ofs -= bcs; } fp->fptr += ofs; if (ofs % SS(fs)) { @@ -4060,26 +4057,22 @@ FRESULT f_lseek ( } } } + if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } -#if !_FS_READONLY - if (fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ - fp->obj.objsize = fp->fptr; - fp->flag |= FA_MODIFIED; - } -#endif } LEAVE_FF(fs, res); @@ -4105,7 +4098,7 @@ FRESULT f_opendir ( if (!dp) return FR_INVALID_OBJECT; - /* Get logical drive number */ + /* Get logical drive */ obj = &dp->obj; res = find_volume(&path, &fs, 0); if (res == FR_OK) { @@ -4170,7 +4163,7 @@ FRESULT f_closedir ( FATFS *fs; - res = validate(dp, &fs); + res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { #if _FS_LOCK != 0 if (dp->obj.lockid) { /* Decrement sub-directory open counter */ @@ -4205,7 +4198,7 @@ FRESULT f_readdir ( DEF_NAMBUF - res = validate(dp, &fs); /* Check validity of the object */ + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ @@ -4293,7 +4286,7 @@ FRESULT f_stat ( DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); @@ -4332,7 +4325,7 @@ FRESULT f_getfree ( _FDID obj; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { *fatfs = fs; /* Return ptr to the fs object */ @@ -4414,8 +4407,8 @@ FRESULT f_truncate ( DWORD ncl; - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ if (fp->obj.objsize > fp->fptr) { @@ -4438,7 +4431,7 @@ FRESULT f_truncate ( if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } } #endif @@ -4469,7 +4462,7 @@ FRESULT f_unlink ( DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); dj.obj.fs = fs; if (res == FR_OK) { @@ -4563,7 +4556,7 @@ FRESULT f_mkdir ( DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); dj.obj.fs = fs; if (res == FR_OK) { @@ -4657,7 +4650,7 @@ FRESULT f_rename ( get_ldnumber(&path_new); /* Ignore drive number of new name */ - res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive number of the old object */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); @@ -4674,10 +4667,12 @@ FRESULT f_rename ( mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ mem_cpy(&djn, &djo, sizeof djo); - res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); @@ -4694,7 +4689,9 @@ FRESULT f_rename ( mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { @@ -4757,7 +4754,7 @@ FRESULT f_chmod ( DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ dj.obj.fs = fs; if (res == FR_OK) { INIT_NAMBUF(fs); @@ -4801,7 +4798,7 @@ FRESULT f_utime ( DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ dj.obj.fs = fs; if (res == FR_OK) { INIT_NAMBUF(fs); @@ -4849,7 +4846,7 @@ FRESULT f_getlabel ( WCHAR w; #endif - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); /* Get volume label */ @@ -4937,7 +4934,7 @@ FRESULT f_setlabel ( static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); dj.obj.fs = fs; @@ -4946,7 +4943,7 @@ FRESULT f_setlabel ( for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ w = label[i++]; #if !_LFN_UNICODE @@ -4963,7 +4960,7 @@ FRESULT f_setlabel ( slen = j; } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ if (slen) { /* Is there a volume label to be set? */ dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ @@ -5004,7 +5001,7 @@ FRESULT f_setlabel ( res = dir_read(&dj, 1); /* Get volume label entry */ if (res == FR_OK) { if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_NumLabel] = slen / 2; /* Change the volume label */ + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { if (slen) { @@ -5024,7 +5021,7 @@ FRESULT f_setlabel ( mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ - dj.dir[XDIR_NumLabel] = slen / 2; + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ @@ -5062,8 +5059,8 @@ FRESULT f_expand ( DWORD n, clst, stcl, scl, ncl, tcl, lclst; - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); #if _FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ @@ -5104,8 +5101,8 @@ FRESULT f_expand ( } if (res == FR_OK) { if (opt) { - for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */ - res = put_fat(fs, clst, (tcl == 1) ? 0xFFFFFFFF : clst + 1); + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } @@ -5115,12 +5112,18 @@ FRESULT f_expand ( } } - if (opt && res == FR_OK) { + if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ - fp->obj.sclust = scl; /* Update object allocation information */ - fp->obj.objsize = fsz; - if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ - fp->flag |= FA_MODIFIED; + if (opt) { + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } } LEAVE_FF(fs, res); @@ -5151,8 +5154,8 @@ FRESULT f_forward ( *bf = 0; /* Clear transfer byte counter */ - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; @@ -5181,7 +5184,7 @@ FRESULT f_forward ( #if !_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= ~FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); @@ -5216,14 +5219,14 @@ FRESULT f_mkfs ( { const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ - static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4KS unit) */ - static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128KS unit) */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ BYTE fmt, sys, *buf, *pte, pdrv, part; WORD ss; - DWORD n, pau, n_clst, sz_blk, sect, szb_buf, sz_buf; + DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ - UINT i, ns; + UINT i; int vol; DSTATUS stat; #if _USE_TRIM || _FS_EXFAT @@ -5236,34 +5239,33 @@ FRESULT f_mkfs ( if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear mounted volume */ pdrv = LD2PD(vol); /* Physical drive */ - part = LD2PT(vol); /* Partition (0:create as new, 1-4:get by partition table) */ + part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ /* Check physical drive status */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ #if _MAX_SS != _MIN_SS /* Get sector size of the medium */ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = _MAX_SS; #endif - if ((au != 0 && au < ss) || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ - au /= ss; /* Cluster size in byte to in sector */ - if (au > 32768) return FR_INVALID_PARAMETER; + if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in unit of sector */ - /* Set size and pointer of the working buffer */ - buf = (BYTE*)work; /* Use given working buffer */ - if (len < ss) return FR_MKFS_ABORTED; - szb_buf = len & ~(ss - 1); /* Round-down by sector size [byte] */ - sz_buf = szb_buf / ss; /* Size of sector buffer [sector] */ + /* Get working buffer */ + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + if (!szb_buf) return FR_MKFS_ABORTED; /* Determine where the volume to be located (b_vol, sz_vol) */ if (_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ - if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check MBR is valid */ + if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ pte = buf + (MBR_Table + (part - 1) * SZ_PTE); if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ @@ -5275,16 +5277,16 @@ FRESULT f_mkfs ( if (sz_vol < b_vol) return FR_MKFS_ABORTED; sz_vol -= b_vol; /* Volume size */ } - if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check volume size (>=128s) */ + if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check if volume size is >=128s */ - /* Pre-determine the FAT type by argument */ + /* Pre-determine the FAT type */ do { if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ - if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au >= 256) { /* exFAT only, vol >= 64Ms or au >= 256s ? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ fmt = FS_EXFAT; break; } } - if (au >= 256) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ if (opt & FM_FAT32) { /* FAT32 possible? */ if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ fmt = FS_FAT32; break; @@ -5296,7 +5298,7 @@ FRESULT f_mkfs ( #if _FS_EXFAT if (fmt == FS_EXFAT) { /* Create an exFAT volume */ - DWORD sum, szb_bit, szb_case; + DWORD szb_bit, szb_case, sum, nb, cl; WCHAR ch, si; UINT j, st; BYTE b; @@ -5309,20 +5311,19 @@ FRESULT f_mkfs ( /* Determine FAT location, data location and number of clusters */ if (!au) { /* au auto-selection */ au = 8; - if (sz_vol >= 0x80000) au = 64; /* >= 512KS */ - if (sz_vol >= 0x4000000) au = 256; /* >= 64MS */ + if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ } b_fat = b_vol + 32; /* FAT start at offset 32 */ - sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Numbef of FAT sectors */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ - n_clst = (sz_vol - (b_data - b_vol)) / au; /* Nunber of clusters */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ - szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ - tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of bitmap clusters */ - tbl[2] = 1; /* Number of rootdir clusters */ + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ /* Create a compressed up-case table */ sect = b_data + au * tbl[0]; /* Table start sector */ @@ -5353,43 +5354,49 @@ FRESULT f_mkfs ( sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ - ns = (i + ss - 1) / ss; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; i = 0; + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; i = 0; } } while (si); - tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case clusters */ + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[2] = 1; /* Number of root dir clusters */ /* Initialize the allocation bitmap */ - mem_set(buf, 0, szb_buf); /* Set in-use flags of bitmap, up-case and root dir */ - for (i = 0, n = tbl[0] + tbl[1] + tbl[2]; n >= 8; buf[i++] = 0xFF, n -= 8) ; - for (b = 1; n; buf[i] |= b, b <<= 1, n--) ; - sect = b_data; n = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of the sectors */ - do { /* Fill allocation bitmap sectors */ - ns = (n > sz_buf) ? sz_buf : n; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; - mem_set(buf, 0, ss); - } while (n -= ns); + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); /* Initialize the FAT */ - st_qword(buf, 0xFFFFFFFFFFFFFFF8); /* Entry 0 and 1 */ - for (j = 0, i = 2; j < 3; j++) { /* Set entries of bitmap, up-case and root dir */ - for (n = tbl[j]; n; n--) { - st_dword(buf + i * 4, (n >= 2) ? i + 1 : 0xFFFFFFFF); - i++; + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } - } - sect = b_fat; n = sz_fat; /* Start of FAT and number of the sectors */ - do { /* Fill FAT sectors */ - ns = (n > sz_buf) ? sz_buf : n; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; - mem_set(buf, 0, ss); - } while (n -= ns); + do { /* Create chains of bitmap, up-case and root dir */ + while (nb && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb && i < szb_buf); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); /* Initialize the root directory */ - mem_set(buf, 0, ss); + mem_set(buf, 0, szb_buf); buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ st_dword(buf + SZDIRE * 1 + 20, 2); @@ -5398,13 +5405,13 @@ FRESULT f_mkfs ( st_dword(buf + SZDIRE * 2 + 4, sum); st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); st_dword(buf + SZDIRE * 2 + 24, szb_case); - sect = b_data + au * (tbl[0] + tbl[1]); n = au; /* Start of directory and number of the sectors */ - do { /* Fill root direcotry sectors */ - ns = (n > sz_buf) ? sz_buf : n; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; + sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; mem_set(buf, 0, ss); - } while (n -= ns); + sect += n; nsect -= n; + } while (nsect); /* Create two set of the exFAT VBR blocks */ sect = b_vol; @@ -5450,7 +5457,7 @@ FRESULT f_mkfs ( } } else -#endif +#endif /* _FS_EXFAT */ { /* Create an FAT12/16/32 volume */ do { pau = au; @@ -5533,14 +5540,14 @@ FRESULT f_mkfs ( st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ - buf[BPB_NumFATs] = n_fats; /* Number of FATs */ + buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ if (sz_vol < 0x10000) { st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { - st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 12-bit LBA */ + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ } - buf[BPB_Media] = 0xF8; /* Media descriptor */ + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ @@ -5577,8 +5584,8 @@ FRESULT f_mkfs ( } /* Initialize FAT area */ - mem_set(buf, 0, szb_buf); - sect = b_fat; /* Start sector */ + mem_set(buf, 0, (UINT)szb_buf); + sect = b_fat; /* FAT start sector */ for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ if (fmt == FS_FAT32) { st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ @@ -5587,22 +5594,22 @@ FRESULT f_mkfs ( } else { st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ } - n = sz_fat; /* Sector count of a FAT */ + nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ - ns = (n > sz_buf) ? sz_buf : n; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; mem_set(buf, 0, ss); - } while (n -= ns); + sect += n; nsect -= n; + } while (nsect); } /* Initialize root directory (fill with zero) */ - n = (fmt == FS_FAT32) ? pau : sz_dir; /* Sector count of root directory */ + nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { - ns = (n > sz_buf) ? sz_buf : n; - if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; - } while (n -= ns); + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); } /* Determine system ID in the partition table */ diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h index 26748b9..905dd66 100644 --- a/source/fatfs/ff.h +++ b/source/fatfs/ff.h @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12a / +/ FatFs - Generic FAT file system module R0.12b / /-----------------------------------------------------------------------------/ / / Copyright (C) 2016, ChaN, all right reserved. @@ -19,7 +19,7 @@ #ifndef _FATFS -#define _FATFS 80186 /* Revision ID */ +#define _FATFS 68020 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -159,7 +159,7 @@ typedef struct { /* File object structure (FIL) */ typedef struct { - _FDID obj; /* Object identifier */ + _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h index f0fe182..ce860e4 100644 --- a/source/fatfs/ffconf.h +++ b/source/fatfs/ffconf.h @@ -2,7 +2,7 @@ / FatFs - FAT file system module configuration file /---------------------------------------------------------------------------*/ -#define _FFCONF 80186 /* Revision ID */ +#define _FFCONF 68020 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -204,14 +204,14 @@ #define _FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. +/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the file system object (FATFS) is used for the file data transfer. */ #define _FS_EXFAT 0 -/* This option switches support of exFAT file system in addition to the traditional -/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. +/* This option switches support of exFAT file system. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) / Note that enabling exFAT discards C89 compatibility. */ @@ -259,7 +259,9 @@ / The _FS_TIMEOUT defines timeout period in unit of time tick. / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.c. */ +/ included somewhere in the scope of ff.h. */ + +/* #include // O/S definitions */ /*--- End of configuration options ---*/ diff --git a/source/fs.c b/source/fs.c index 6776354..b9528cc 100644 --- a/source/fs.c +++ b/source/fs.c @@ -329,21 +329,6 @@ u32 GetWritePermissions() { return write_permissions; } -bool GetTempFileName(char* path) { - // this assumes path is initialized with enough room - char* tempname = strrchr(path, '/'); - if (!tempname) return false; - tempname++; - strncpy(tempname, "AAAAAAAA.TMP", 255 - (tempname - path)); - char* cc = tempname; - // this does not try all permutations - for (; (*cc <= 'Z') && (cc - tempname < 8); (*cc)++) { - if (fa_stat(path, NULL) != FR_OK) break; - if (*cc == 'Z') cc++; - } - return (cc - tempname < 8) ? true : false; -} - bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset, bool create) { int drvtype = DriveType(path); if (!CheckWritePermissions(path)) return false; @@ -985,19 +970,7 @@ bool PathRename(const char* path, const char* newname) { strncpy(npath, path, oldname - path); strncpy(npath + (oldname - path), newname, 255 - (oldname - path)); - FRESULT res = f_rename(path, npath); - if (res == FR_EXIST) { // new path already exists (possible LFN/case issue) - char temp[256]; - strncpy(temp, path, oldname - path); - if (!GetTempFileName(temp)) return false; - if (f_rename(path, temp) == FR_OK) { - if ((fa_stat(npath, NULL) == FR_OK) || (f_rename(temp, npath) != FR_OK)) { - ShowPrompt(false, "Destination exists in folder"); - f_rename(temp, path); // something went wrong - try renaming back - return false; - } else return true; - } else return false; - } else return (res == FR_OK) ? true : false; + return (f_rename(path, npath) == FR_OK); } bool DirCreate(const char* cpath, const char* dirname) {