Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

Committer:
AjK
Date:
Mon Oct 11 10:34:55 2010 +0000
Revision:
0:0a841b89d614
Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:0a841b89d614 1 /*----------------------------------------------------------------------------/
AjK 0:0a841b89d614 2 / FatFs - FAT file system module R0.08a (C)ChaN, 2010
AjK 0:0a841b89d614 3 /-----------------------------------------------------------------------------/
AjK 0:0a841b89d614 4 / FatFs module is a generic FAT file system module for small embedded systems.
AjK 0:0a841b89d614 5 / This is a free software that opened for education, research and commercial
AjK 0:0a841b89d614 6 / developments under license policy of following terms.
AjK 0:0a841b89d614 7 /
AjK 0:0a841b89d614 8 / Copyright (C) 2010, ChaN, all right reserved.
AjK 0:0a841b89d614 9 /
AjK 0:0a841b89d614 10 / * The FatFs module is a free software and there is NO WARRANTY.
AjK 0:0a841b89d614 11 / * No restriction on use. You can use, modify and redistribute it for
AjK 0:0a841b89d614 12 / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
AjK 0:0a841b89d614 13 / * Redistributions of source code must retain the above copyright notice.
AjK 0:0a841b89d614 14 /
AjK 0:0a841b89d614 15 /-----------------------------------------------------------------------------/
AjK 0:0a841b89d614 16 / Feb 26,'06 R0.00 Prototype.
AjK 0:0a841b89d614 17 /
AjK 0:0a841b89d614 18 / Apr 29,'06 R0.01 First stable version.
AjK 0:0a841b89d614 19 /
AjK 0:0a841b89d614 20 / Jun 01,'06 R0.02 Added FAT12 support.
AjK 0:0a841b89d614 21 / Removed unbuffered mode.
AjK 0:0a841b89d614 22 / Fixed a problem on small (<32M) partition.
AjK 0:0a841b89d614 23 / Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
AjK 0:0a841b89d614 24 /
AjK 0:0a841b89d614 25 / Sep 22,'06 R0.03 Added f_rename().
AjK 0:0a841b89d614 26 / Changed option _FS_MINIMUM to _FS_MINIMIZE.
AjK 0:0a841b89d614 27 / Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
AjK 0:0a841b89d614 28 / Fixed f_mkdir() creates incorrect directory on FAT32.
AjK 0:0a841b89d614 29 /
AjK 0:0a841b89d614 30 / Feb 04,'07 R0.04 Supported multiple drive system.
AjK 0:0a841b89d614 31 / Changed some interfaces for multiple drive system.
AjK 0:0a841b89d614 32 / Changed f_mountdrv() to f_mount().
AjK 0:0a841b89d614 33 / Added f_mkfs().
AjK 0:0a841b89d614 34 / Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
AjK 0:0a841b89d614 35 / Added a capability of extending file size to f_lseek().
AjK 0:0a841b89d614 36 / Added minimization level 3.
AjK 0:0a841b89d614 37 / Fixed an endian sensitive code in f_mkfs().
AjK 0:0a841b89d614 38 / May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
AjK 0:0a841b89d614 39 / Added FSInfo support.
AjK 0:0a841b89d614 40 / Fixed DBCS name can result FR_INVALID_NAME.
AjK 0:0a841b89d614 41 / Fixed short seek (<= csize) collapses the file object.
AjK 0:0a841b89d614 42 /
AjK 0:0a841b89d614 43 / Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
AjK 0:0a841b89d614 44 / Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
AjK 0:0a841b89d614 45 / Fixed f_mkdir() on FAT32 creates incorrect directory.
AjK 0:0a841b89d614 46 / Feb 03,'08 R0.05a Added f_truncate() and f_utime().
AjK 0:0a841b89d614 47 / Fixed off by one error at FAT sub-type determination.
AjK 0:0a841b89d614 48 / Fixed btr in f_read() can be mistruncated.
AjK 0:0a841b89d614 49 / Fixed cached sector is not flushed when create and close without write.
AjK 0:0a841b89d614 50 /
AjK 0:0a841b89d614 51 / Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
AjK 0:0a841b89d614 52 / Improved performance of f_lseek() on moving to the same or following cluster.
AjK 0:0a841b89d614 53 /
AjK 0:0a841b89d614 54 / Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option. (_FS_TINY)
AjK 0:0a841b89d614 55 / Added long file name support.
AjK 0:0a841b89d614 56 / Added multiple code page support.
AjK 0:0a841b89d614 57 / Added re-entrancy for multitask operation.
AjK 0:0a841b89d614 58 / Added auto cluster size selection to f_mkfs().
AjK 0:0a841b89d614 59 / Added rewind option to f_readdir().
AjK 0:0a841b89d614 60 / Changed result code of critical errors.
AjK 0:0a841b89d614 61 / Renamed string functions to avoid name collision.
AjK 0:0a841b89d614 62 / Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
AjK 0:0a841b89d614 63 / Added multiple sector size support.
AjK 0:0a841b89d614 64 / Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
AjK 0:0a841b89d614 65 / Fixed wrong cache control in f_lseek().
AjK 0:0a841b89d614 66 / Added relative path feature.
AjK 0:0a841b89d614 67 / Added f_chdir() and f_chdrive().
AjK 0:0a841b89d614 68 / Added proper case conversion to extended char.
AjK 0:0a841b89d614 69 / Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
AjK 0:0a841b89d614 70 / Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
AjK 0:0a841b89d614 71 / Fixed name matching error on the 13 char boundary.
AjK 0:0a841b89d614 72 / Added a configuration option, _LFN_UNICODE.
AjK 0:0a841b89d614 73 / Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
AjK 0:0a841b89d614 74 /
AjK 0:0a841b89d614 75 / May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3)
AjK 0:0a841b89d614 76 / Added file lock feature. (_FS_SHARE)
AjK 0:0a841b89d614 77 / Added fast seek feature. (_USE_FASTSEEK)
AjK 0:0a841b89d614 78 / Changed some types on the API, XCHAR->TCHAR.
AjK 0:0a841b89d614 79 / Changed fname member in the FILINFO structure on Unicode cfg.
AjK 0:0a841b89d614 80 / String functions support UTF-8 encoding files on Unicode cfg.
AjK 0:0a841b89d614 81 / Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
AjK 0:0a841b89d614 82 / Added sector erase feature. (_USE_ERASE)
AjK 0:0a841b89d614 83 / Moved file lock semaphore table from fs object to the bss.
AjK 0:0a841b89d614 84 / Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
AjK 0:0a841b89d614 85 / Fixed f_mkfs() creates wrong FAT32 volume.
AjK 0:0a841b89d614 86 /---------------------------------------------------------------------------*/
AjK 0:0a841b89d614 87
AjK 0:0a841b89d614 88 #include "ff.h" /* FatFs configurations and declarations */
AjK 0:0a841b89d614 89 #include "diskio.h" /* Declarations of low level disk I/O functions */
AjK 0:0a841b89d614 90
AjK 0:0a841b89d614 91
AjK 0:0a841b89d614 92 /*--------------------------------------------------------------------------
AjK 0:0a841b89d614 93
AjK 0:0a841b89d614 94 Module Private Definitions
AjK 0:0a841b89d614 95
AjK 0:0a841b89d614 96 ---------------------------------------------------------------------------*/
AjK 0:0a841b89d614 97
AjK 0:0a841b89d614 98 #if _FATFS != 8255
AjK 0:0a841b89d614 99 #error Wrong include file (ff.h).
AjK 0:0a841b89d614 100 #endif
AjK 0:0a841b89d614 101
AjK 0:0a841b89d614 102 /* Definitions on sector size */
AjK 0:0a841b89d614 103 #if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
AjK 0:0a841b89d614 104 #error Wrong sector size.
AjK 0:0a841b89d614 105 #endif
AjK 0:0a841b89d614 106 #if _MAX_SS != 512
AjK 0:0a841b89d614 107 #define SS(fs) ((fs)->ssize) /* Multiple sector size */
AjK 0:0a841b89d614 108 #else
AjK 0:0a841b89d614 109 #define SS(fs) 512U /* Fixed sector size */
AjK 0:0a841b89d614 110 #endif
AjK 0:0a841b89d614 111
AjK 0:0a841b89d614 112
AjK 0:0a841b89d614 113 /* Reentrancy related */
AjK 0:0a841b89d614 114 #if _FS_REENTRANT
AjK 0:0a841b89d614 115 #if _USE_LFN == 1
AjK 0:0a841b89d614 116 #error Static LFN work area must not be used in re-entrant configuration.
AjK 0:0a841b89d614 117 #endif
AjK 0:0a841b89d614 118 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
AjK 0:0a841b89d614 119 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
AjK 0:0a841b89d614 120 #else
AjK 0:0a841b89d614 121 #define ENTER_FF(fs)
AjK 0:0a841b89d614 122 #define LEAVE_FF(fs, res) return res
AjK 0:0a841b89d614 123 #endif
AjK 0:0a841b89d614 124
AjK 0:0a841b89d614 125 #define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
AjK 0:0a841b89d614 126
AjK 0:0a841b89d614 127
AjK 0:0a841b89d614 128 /* File shareing feature */
AjK 0:0a841b89d614 129 #if _FS_SHARE
AjK 0:0a841b89d614 130 #if _FS_READONLY
AjK 0:0a841b89d614 131 #error _FS_SHARE must be 0 on read-only cfg.
AjK 0:0a841b89d614 132 #endif
AjK 0:0a841b89d614 133 typedef struct {
AjK 0:0a841b89d614 134 FATFS *fs; /* File ID 1, volume (NULL:blank entry) */
AjK 0:0a841b89d614 135 DWORD clu; /* File ID 2, directory */
AjK 0:0a841b89d614 136 WORD idx; /* File ID 3, directory index */
AjK 0:0a841b89d614 137 WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
AjK 0:0a841b89d614 138 } FILESEM;
AjK 0:0a841b89d614 139 #endif
AjK 0:0a841b89d614 140
AjK 0:0a841b89d614 141
AjK 0:0a841b89d614 142 /* Misc definitions */
AjK 0:0a841b89d614 143 #define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
AjK 0:0a841b89d614 144 #define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);}
AjK 0:0a841b89d614 145
AjK 0:0a841b89d614 146
AjK 0:0a841b89d614 147 /* Character code support macros */
AjK 0:0a841b89d614 148 #define IsUpper(c) (((c)>='A')&&((c)<='Z'))
AjK 0:0a841b89d614 149 #define IsLower(c) (((c)>='a')&&((c)<='z'))
AjK 0:0a841b89d614 150 #define IsDigit(c) (((c)>='0')&&((c)<='9'))
AjK 0:0a841b89d614 151
AjK 0:0a841b89d614 152 #if _DF1S /* Code page is DBCS */
AjK 0:0a841b89d614 153
AjK 0:0a841b89d614 154 #ifdef _DF2S /* Two 1st byte areas */
AjK 0:0a841b89d614 155 #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
AjK 0:0a841b89d614 156 #else /* One 1st byte area */
AjK 0:0a841b89d614 157 #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
AjK 0:0a841b89d614 158 #endif
AjK 0:0a841b89d614 159
AjK 0:0a841b89d614 160 #ifdef _DS3S /* Three 2nd byte areas */
AjK 0:0a841b89d614 161 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
AjK 0:0a841b89d614 162 #else /* Two 2nd byte areas */
AjK 0:0a841b89d614 163 #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
AjK 0:0a841b89d614 164 #endif
AjK 0:0a841b89d614 165
AjK 0:0a841b89d614 166 #else /* Code page is SBCS */
AjK 0:0a841b89d614 167
AjK 0:0a841b89d614 168 #define IsDBCS1(c) 0
AjK 0:0a841b89d614 169 #define IsDBCS2(c) 0
AjK 0:0a841b89d614 170
AjK 0:0a841b89d614 171 #endif /* _DF1S */
AjK 0:0a841b89d614 172
AjK 0:0a841b89d614 173
AjK 0:0a841b89d614 174 /* Name status flags */
AjK 0:0a841b89d614 175 #define NS 11 /* Offset of name status byte */
AjK 0:0a841b89d614 176 #define NS_LOSS 0x01 /* Out of 8.3 format */
AjK 0:0a841b89d614 177 #define NS_LFN 0x02 /* Force to create LFN entry */
AjK 0:0a841b89d614 178 #define NS_LAST 0x04 /* Last segment */
AjK 0:0a841b89d614 179 #define NS_BODY 0x08 /* Lower case flag (body) */
AjK 0:0a841b89d614 180 #define NS_EXT 0x10 /* Lower case flag (ext) */
AjK 0:0a841b89d614 181 #define NS_DOT 0x20 /* Dot entry */
AjK 0:0a841b89d614 182
AjK 0:0a841b89d614 183
AjK 0:0a841b89d614 184 /* FAT sub-type boundaries */
AjK 0:0a841b89d614 185 /* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
AjK 0:0a841b89d614 186 #define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
AjK 0:0a841b89d614 187 #define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
AjK 0:0a841b89d614 188
AjK 0:0a841b89d614 189
AjK 0:0a841b89d614 190 /* FatFs refers the members in the FAT structures as byte array instead of
AjK 0:0a841b89d614 191 / structure member because there are incompatibility of the packing option
AjK 0:0a841b89d614 192 / between compilers. */
AjK 0:0a841b89d614 193
AjK 0:0a841b89d614 194 #define BS_jmpBoot 0
AjK 0:0a841b89d614 195 #define BS_OEMName 3
AjK 0:0a841b89d614 196 #define BPB_BytsPerSec 11
AjK 0:0a841b89d614 197 #define BPB_SecPerClus 13
AjK 0:0a841b89d614 198 #define BPB_RsvdSecCnt 14
AjK 0:0a841b89d614 199 #define BPB_NumFATs 16
AjK 0:0a841b89d614 200 #define BPB_RootEntCnt 17
AjK 0:0a841b89d614 201 #define BPB_TotSec16 19
AjK 0:0a841b89d614 202 #define BPB_Media 21
AjK 0:0a841b89d614 203 #define BPB_FATSz16 22
AjK 0:0a841b89d614 204 #define BPB_SecPerTrk 24
AjK 0:0a841b89d614 205 #define BPB_NumHeads 26
AjK 0:0a841b89d614 206 #define BPB_HiddSec 28
AjK 0:0a841b89d614 207 #define BPB_TotSec32 32
AjK 0:0a841b89d614 208 #define BS_DrvNum 36
AjK 0:0a841b89d614 209 #define BS_BootSig 38
AjK 0:0a841b89d614 210 #define BS_VolID 39
AjK 0:0a841b89d614 211 #define BS_VolLab 43
AjK 0:0a841b89d614 212 #define BS_FilSysType 54
AjK 0:0a841b89d614 213 #define BPB_FATSz32 36
AjK 0:0a841b89d614 214 #define BPB_ExtFlags 40
AjK 0:0a841b89d614 215 #define BPB_FSVer 42
AjK 0:0a841b89d614 216 #define BPB_RootClus 44
AjK 0:0a841b89d614 217 #define BPB_FSInfo 48
AjK 0:0a841b89d614 218 #define BPB_BkBootSec 50
AjK 0:0a841b89d614 219 #define BS_DrvNum32 64
AjK 0:0a841b89d614 220 #define BS_BootSig32 66
AjK 0:0a841b89d614 221 #define BS_VolID32 67
AjK 0:0a841b89d614 222 #define BS_VolLab32 71
AjK 0:0a841b89d614 223 #define BS_FilSysType32 82
AjK 0:0a841b89d614 224 #define FSI_LeadSig 0
AjK 0:0a841b89d614 225 #define FSI_StrucSig 484
AjK 0:0a841b89d614 226 #define FSI_Free_Count 488
AjK 0:0a841b89d614 227 #define FSI_Nxt_Free 492
AjK 0:0a841b89d614 228 #define MBR_Table 446
AjK 0:0a841b89d614 229 #define BS_55AA 510
AjK 0:0a841b89d614 230
AjK 0:0a841b89d614 231 #define DIR_Name 0
AjK 0:0a841b89d614 232 #define DIR_Attr 11
AjK 0:0a841b89d614 233 #define DIR_NTres 12
AjK 0:0a841b89d614 234 #define DIR_CrtTime 14
AjK 0:0a841b89d614 235 #define DIR_CrtDate 16
AjK 0:0a841b89d614 236 #define DIR_FstClusHI 20
AjK 0:0a841b89d614 237 #define DIR_WrtTime 22
AjK 0:0a841b89d614 238 #define DIR_WrtDate 24
AjK 0:0a841b89d614 239 #define DIR_FstClusLO 26
AjK 0:0a841b89d614 240 #define DIR_FileSize 28
AjK 0:0a841b89d614 241 #define LDIR_Ord 0
AjK 0:0a841b89d614 242 #define LDIR_Attr 11
AjK 0:0a841b89d614 243 #define LDIR_Type 12
AjK 0:0a841b89d614 244 #define LDIR_Chksum 13
AjK 0:0a841b89d614 245 #define LDIR_FstClusLO 26
AjK 0:0a841b89d614 246
AjK 0:0a841b89d614 247
AjK 0:0a841b89d614 248
AjK 0:0a841b89d614 249 /*------------------------------------------------------------*/
AjK 0:0a841b89d614 250 /* Work area */
AjK 0:0a841b89d614 251
AjK 0:0a841b89d614 252 #if _VOLUMES
AjK 0:0a841b89d614 253 static
AjK 0:0a841b89d614 254 FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
AjK 0:0a841b89d614 255 #else
AjK 0:0a841b89d614 256 #error Number of drives must not be 0.
AjK 0:0a841b89d614 257 #endif
AjK 0:0a841b89d614 258
AjK 0:0a841b89d614 259 static
AjK 0:0a841b89d614 260 WORD Fsid; /* File system mount ID */
AjK 0:0a841b89d614 261
AjK 0:0a841b89d614 262 #if _FS_RPATH
AjK 0:0a841b89d614 263 static
AjK 0:0a841b89d614 264 BYTE CurrVol; /* Current drive */
AjK 0:0a841b89d614 265 #endif
AjK 0:0a841b89d614 266
AjK 0:0a841b89d614 267 #if _FS_SHARE
AjK 0:0a841b89d614 268 static
AjK 0:0a841b89d614 269 FILESEM Files[_FS_SHARE]; /* File lock semaphores */
AjK 0:0a841b89d614 270 #endif
AjK 0:0a841b89d614 271
AjK 0:0a841b89d614 272 #if _USE_LFN == 0 /* No LFN */
AjK 0:0a841b89d614 273 #define DEF_NAMEBUF BYTE sfn[12]
AjK 0:0a841b89d614 274 #define INIT_BUF(dobj) (dobj).fn = sfn
AjK 0:0a841b89d614 275 #define FREE_BUF()
AjK 0:0a841b89d614 276
AjK 0:0a841b89d614 277 #elif _USE_LFN == 1 /* LFN with static LFN working buffer */
AjK 0:0a841b89d614 278 static WCHAR LfnBuf[_MAX_LFN+1];
AjK 0:0a841b89d614 279 #define DEF_NAMEBUF BYTE sfn[12]
AjK 0:0a841b89d614 280 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
AjK 0:0a841b89d614 281 #define FREE_BUF()
AjK 0:0a841b89d614 282
AjK 0:0a841b89d614 283 #elif _USE_LFN == 2 /* LFN with dynamic LFN working buffer on the stack */
AjK 0:0a841b89d614 284 #define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
AjK 0:0a841b89d614 285 #define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
AjK 0:0a841b89d614 286 #define FREE_BUF()
AjK 0:0a841b89d614 287
AjK 0:0a841b89d614 288 #elif _USE_LFN == 3 /* LFN with dynamic LFN working buffer on the heap */
AjK 0:0a841b89d614 289 #define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn
AjK 0:0a841b89d614 290 #define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
AjK 0:0a841b89d614 291 if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
AjK 0:0a841b89d614 292 (dobj).lfn = lfn; (dobj).fn = sfn; }
AjK 0:0a841b89d614 293 #define FREE_BUF() ff_memfree(lfn)
AjK 0:0a841b89d614 294
AjK 0:0a841b89d614 295 #else
AjK 0:0a841b89d614 296 #error Wrong LFN configuration.
AjK 0:0a841b89d614 297 #endif
AjK 0:0a841b89d614 298
AjK 0:0a841b89d614 299
AjK 0:0a841b89d614 300
AjK 0:0a841b89d614 301
AjK 0:0a841b89d614 302 /*--------------------------------------------------------------------------
AjK 0:0a841b89d614 303
AjK 0:0a841b89d614 304 Module Private Functions
AjK 0:0a841b89d614 305
AjK 0:0a841b89d614 306 ---------------------------------------------------------------------------*/
AjK 0:0a841b89d614 307
AjK 0:0a841b89d614 308
AjK 0:0a841b89d614 309 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 310 /* String functions */
AjK 0:0a841b89d614 311 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 312
AjK 0:0a841b89d614 313 /* Copy memory to memory */
AjK 0:0a841b89d614 314 static
AjK 0:0a841b89d614 315 void mem_cpy (void* dst, const void* src, UINT cnt) {
AjK 0:0a841b89d614 316 BYTE *d = (BYTE*)dst;
AjK 0:0a841b89d614 317 const BYTE *s = (const BYTE*)src;
AjK 0:0a841b89d614 318
AjK 0:0a841b89d614 319 #if _WORD_ACCESS == 1
AjK 0:0a841b89d614 320 while (cnt >= sizeof(int)) {
AjK 0:0a841b89d614 321 *(int*)d = *(int*)s;
AjK 0:0a841b89d614 322 d += sizeof(int); s += sizeof(int);
AjK 0:0a841b89d614 323 cnt -= sizeof(int);
AjK 0:0a841b89d614 324 }
AjK 0:0a841b89d614 325 #endif
AjK 0:0a841b89d614 326 while (cnt--)
AjK 0:0a841b89d614 327 *d++ = *s++;
AjK 0:0a841b89d614 328 }
AjK 0:0a841b89d614 329
AjK 0:0a841b89d614 330 /* Fill memory */
AjK 0:0a841b89d614 331 static
AjK 0:0a841b89d614 332 void mem_set (void* dst, int val, UINT cnt) {
AjK 0:0a841b89d614 333 BYTE *d = (BYTE*)dst;
AjK 0:0a841b89d614 334
AjK 0:0a841b89d614 335 while (cnt--)
AjK 0:0a841b89d614 336 *d++ = (BYTE)val;
AjK 0:0a841b89d614 337 }
AjK 0:0a841b89d614 338
AjK 0:0a841b89d614 339 /* Compare memory to memory */
AjK 0:0a841b89d614 340 static
AjK 0:0a841b89d614 341 int mem_cmp (const void* dst, const void* src, UINT cnt) {
AjK 0:0a841b89d614 342 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
AjK 0:0a841b89d614 343 int r = 0;
AjK 0:0a841b89d614 344
AjK 0:0a841b89d614 345 while (cnt-- && (r = *d++ - *s++) == 0) ;
AjK 0:0a841b89d614 346 return r;
AjK 0:0a841b89d614 347 }
AjK 0:0a841b89d614 348
AjK 0:0a841b89d614 349 /* Check if chr is contained in the string */
AjK 0:0a841b89d614 350 static
AjK 0:0a841b89d614 351 int chk_chr (const char* str, int chr) {
AjK 0:0a841b89d614 352 while (*str && *str != chr) str++;
AjK 0:0a841b89d614 353 return *str;
AjK 0:0a841b89d614 354 }
AjK 0:0a841b89d614 355
AjK 0:0a841b89d614 356
AjK 0:0a841b89d614 357
AjK 0:0a841b89d614 358 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 359 /* Request/Release grant to access the volume */
AjK 0:0a841b89d614 360 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 361 #if _FS_REENTRANT
AjK 0:0a841b89d614 362
AjK 0:0a841b89d614 363 static
AjK 0:0a841b89d614 364 int lock_fs (
AjK 0:0a841b89d614 365 FATFS *fs /* File system object */
AjK 0:0a841b89d614 366 )
AjK 0:0a841b89d614 367 {
AjK 0:0a841b89d614 368 return ff_req_grant(fs->sobj);
AjK 0:0a841b89d614 369 }
AjK 0:0a841b89d614 370
AjK 0:0a841b89d614 371
AjK 0:0a841b89d614 372 static
AjK 0:0a841b89d614 373 void unlock_fs (
AjK 0:0a841b89d614 374 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 375 FRESULT res /* Result code to be returned */
AjK 0:0a841b89d614 376 )
AjK 0:0a841b89d614 377 {
AjK 0:0a841b89d614 378 if (res != FR_NOT_ENABLED &&
AjK 0:0a841b89d614 379 res != FR_INVALID_DRIVE &&
AjK 0:0a841b89d614 380 res != FR_INVALID_OBJECT &&
AjK 0:0a841b89d614 381 res != FR_TIMEOUT) {
AjK 0:0a841b89d614 382 ff_rel_grant(fs->sobj);
AjK 0:0a841b89d614 383 }
AjK 0:0a841b89d614 384 }
AjK 0:0a841b89d614 385 #endif
AjK 0:0a841b89d614 386
AjK 0:0a841b89d614 387
AjK 0:0a841b89d614 388
AjK 0:0a841b89d614 389 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 390 /* File shareing control functions */
AjK 0:0a841b89d614 391 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 392 #if _FS_SHARE
AjK 0:0a841b89d614 393
AjK 0:0a841b89d614 394 static
AjK 0:0a841b89d614 395 FRESULT chk_lock ( /* Check if the file can be accessed */
AjK 0:0a841b89d614 396 DIR* dj, /* Directory object pointing the file to be checked */
AjK 0:0a841b89d614 397 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
AjK 0:0a841b89d614 398 )
AjK 0:0a841b89d614 399 {
AjK 0:0a841b89d614 400 UINT i, be;
AjK 0:0a841b89d614 401
AjK 0:0a841b89d614 402 /* Search file semaphore table */
AjK 0:0a841b89d614 403 for (i = be = 0; i < _FS_SHARE; i++) {
AjK 0:0a841b89d614 404 if (Files[i].fs) { /* Existing entry */
AjK 0:0a841b89d614 405 if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */
AjK 0:0a841b89d614 406 Files[i].clu == dj->sclust &&
AjK 0:0a841b89d614 407 Files[i].idx == dj->index) break;
AjK 0:0a841b89d614 408 } else { /* Blank entry */
AjK 0:0a841b89d614 409 be++;
AjK 0:0a841b89d614 410 }
AjK 0:0a841b89d614 411 }
AjK 0:0a841b89d614 412 if (i == _FS_SHARE) /* The file is not opened */
AjK 0:0a841b89d614 413 return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */
AjK 0:0a841b89d614 414
AjK 0:0a841b89d614 415 /* The file has been opened. Reject any open against writing file and all write mode open */
AjK 0:0a841b89d614 416 return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
AjK 0:0a841b89d614 417 }
AjK 0:0a841b89d614 418
AjK 0:0a841b89d614 419
AjK 0:0a841b89d614 420 static
AjK 0:0a841b89d614 421 int enq_lock ( /* Check if an entry is available for a new file */
AjK 0:0a841b89d614 422 FATFS* fs /* File system object */
AjK 0:0a841b89d614 423 )
AjK 0:0a841b89d614 424 {
AjK 0:0a841b89d614 425 UINT i;
AjK 0:0a841b89d614 426
AjK 0:0a841b89d614 427 for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
AjK 0:0a841b89d614 428 return (i == _FS_SHARE) ? 0 : 1;
AjK 0:0a841b89d614 429 }
AjK 0:0a841b89d614 430
AjK 0:0a841b89d614 431
AjK 0:0a841b89d614 432 static
AjK 0:0a841b89d614 433 UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
AjK 0:0a841b89d614 434 DIR* dj, /* Directory object pointing the file to register or increment */
AjK 0:0a841b89d614 435 int acc /* Desired access mode (0:Read, !0:Write) */
AjK 0:0a841b89d614 436 )
AjK 0:0a841b89d614 437 {
AjK 0:0a841b89d614 438 UINT i;
AjK 0:0a841b89d614 439
AjK 0:0a841b89d614 440
AjK 0:0a841b89d614 441 for (i = 0; i < _FS_SHARE; i++) { /* Find the file */
AjK 0:0a841b89d614 442 if (Files[i].fs == dj->fs &&
AjK 0:0a841b89d614 443 Files[i].clu == dj->sclust &&
AjK 0:0a841b89d614 444 Files[i].idx == dj->index) break;
AjK 0:0a841b89d614 445 }
AjK 0:0a841b89d614 446
AjK 0:0a841b89d614 447 if (i == _FS_SHARE) { /* Not opened. Register it as new. */
AjK 0:0a841b89d614 448 for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
AjK 0:0a841b89d614 449 if (i == _FS_SHARE) return 0; /* No space to register (int err) */
AjK 0:0a841b89d614 450 Files[i].fs = dj->fs;
AjK 0:0a841b89d614 451 Files[i].clu = dj->sclust;
AjK 0:0a841b89d614 452 Files[i].idx = dj->index;
AjK 0:0a841b89d614 453 Files[i].ctr = 0;
AjK 0:0a841b89d614 454 }
AjK 0:0a841b89d614 455
AjK 0:0a841b89d614 456 if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
AjK 0:0a841b89d614 457
AjK 0:0a841b89d614 458 Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
AjK 0:0a841b89d614 459
AjK 0:0a841b89d614 460 return i + 1;
AjK 0:0a841b89d614 461 }
AjK 0:0a841b89d614 462
AjK 0:0a841b89d614 463
AjK 0:0a841b89d614 464 static
AjK 0:0a841b89d614 465 FRESULT dec_lock ( /* Decrement file open counter */
AjK 0:0a841b89d614 466 UINT i /* Semaphore index */
AjK 0:0a841b89d614 467 )
AjK 0:0a841b89d614 468 {
AjK 0:0a841b89d614 469 WORD n;
AjK 0:0a841b89d614 470 FRESULT res;
AjK 0:0a841b89d614 471
AjK 0:0a841b89d614 472
AjK 0:0a841b89d614 473 if (--i < _FS_SHARE) {
AjK 0:0a841b89d614 474 n = Files[i].ctr;
AjK 0:0a841b89d614 475 if (n == 0x100) n = 0;
AjK 0:0a841b89d614 476 if (n) n--;
AjK 0:0a841b89d614 477 Files[i].ctr = n;
AjK 0:0a841b89d614 478 if (!n) Files[i].fs = 0;
AjK 0:0a841b89d614 479 res = FR_OK;
AjK 0:0a841b89d614 480 } else {
AjK 0:0a841b89d614 481 res = FR_INT_ERR;
AjK 0:0a841b89d614 482 }
AjK 0:0a841b89d614 483 return res;
AjK 0:0a841b89d614 484 }
AjK 0:0a841b89d614 485
AjK 0:0a841b89d614 486
AjK 0:0a841b89d614 487 static
AjK 0:0a841b89d614 488 void clear_lock ( /* Clear lock entries of the volume */
AjK 0:0a841b89d614 489 FATFS *fs
AjK 0:0a841b89d614 490 )
AjK 0:0a841b89d614 491 {
AjK 0:0a841b89d614 492 UINT i;
AjK 0:0a841b89d614 493
AjK 0:0a841b89d614 494 for (i = 0; i < _FS_SHARE; i++) {
AjK 0:0a841b89d614 495 if (Files[i].fs == fs) Files[i].fs = 0;
AjK 0:0a841b89d614 496 }
AjK 0:0a841b89d614 497 }
AjK 0:0a841b89d614 498 #endif
AjK 0:0a841b89d614 499
AjK 0:0a841b89d614 500
AjK 0:0a841b89d614 501
AjK 0:0a841b89d614 502 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 503 /* Change window offset */
AjK 0:0a841b89d614 504 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 505
AjK 0:0a841b89d614 506 static
AjK 0:0a841b89d614 507 FRESULT move_window (
AjK 0:0a841b89d614 508 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 509 DWORD sector /* Sector number to make appearance in the fs->win[] */
AjK 0:0a841b89d614 510 ) /* Move to zero only writes back dirty window */
AjK 0:0a841b89d614 511 {
AjK 0:0a841b89d614 512 DWORD wsect;
AjK 0:0a841b89d614 513
AjK 0:0a841b89d614 514
AjK 0:0a841b89d614 515 wsect = fs->winsect;
AjK 0:0a841b89d614 516 if (wsect != sector) { /* Changed current window */
AjK 0:0a841b89d614 517 #if !_FS_READONLY
AjK 0:0a841b89d614 518 if (fs->wflag) { /* Write back dirty window if needed */
AjK 0:0a841b89d614 519 if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
AjK 0:0a841b89d614 520 return FR_DISK_ERR;
AjK 0:0a841b89d614 521 fs->wflag = 0;
AjK 0:0a841b89d614 522 if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */
AjK 0:0a841b89d614 523 BYTE nf;
AjK 0:0a841b89d614 524 for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */
AjK 0:0a841b89d614 525 wsect += fs->fsize;
AjK 0:0a841b89d614 526 disk_write(fs->drv, fs->win, wsect, 1);
AjK 0:0a841b89d614 527 }
AjK 0:0a841b89d614 528 }
AjK 0:0a841b89d614 529 }
AjK 0:0a841b89d614 530 #endif
AjK 0:0a841b89d614 531 if (sector) {
AjK 0:0a841b89d614 532 if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
AjK 0:0a841b89d614 533 return FR_DISK_ERR;
AjK 0:0a841b89d614 534 fs->winsect = sector;
AjK 0:0a841b89d614 535 }
AjK 0:0a841b89d614 536 }
AjK 0:0a841b89d614 537
AjK 0:0a841b89d614 538 return FR_OK;
AjK 0:0a841b89d614 539 }
AjK 0:0a841b89d614 540
AjK 0:0a841b89d614 541
AjK 0:0a841b89d614 542
AjK 0:0a841b89d614 543
AjK 0:0a841b89d614 544 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 545 /* Clean-up cached data */
AjK 0:0a841b89d614 546 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 547 #if !_FS_READONLY
AjK 0:0a841b89d614 548 static
AjK 0:0a841b89d614 549 FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
AjK 0:0a841b89d614 550 FATFS *fs /* File system object */
AjK 0:0a841b89d614 551 )
AjK 0:0a841b89d614 552 {
AjK 0:0a841b89d614 553 FRESULT res;
AjK 0:0a841b89d614 554
AjK 0:0a841b89d614 555
AjK 0:0a841b89d614 556 res = move_window(fs, 0);
AjK 0:0a841b89d614 557 if (res == FR_OK) {
AjK 0:0a841b89d614 558 /* Update FSInfo sector if needed */
AjK 0:0a841b89d614 559 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
AjK 0:0a841b89d614 560 fs->winsect = 0;
AjK 0:0a841b89d614 561 mem_set(fs->win, 0, 512);
AjK 0:0a841b89d614 562 ST_WORD(fs->win+BS_55AA, 0xAA55);
AjK 0:0a841b89d614 563 ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
AjK 0:0a841b89d614 564 ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
AjK 0:0a841b89d614 565 ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
AjK 0:0a841b89d614 566 ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
AjK 0:0a841b89d614 567 disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
AjK 0:0a841b89d614 568 fs->fsi_flag = 0;
AjK 0:0a841b89d614 569 }
AjK 0:0a841b89d614 570 /* Make sure that no pending write process in the physical drive */
AjK 0:0a841b89d614 571 if (disk_ioctl(fs->drv, CTRL_SYNC, (void*)0) != RES_OK)
AjK 0:0a841b89d614 572 res = FR_DISK_ERR;
AjK 0:0a841b89d614 573 }
AjK 0:0a841b89d614 574
AjK 0:0a841b89d614 575 return res;
AjK 0:0a841b89d614 576 }
AjK 0:0a841b89d614 577 #endif
AjK 0:0a841b89d614 578
AjK 0:0a841b89d614 579
AjK 0:0a841b89d614 580
AjK 0:0a841b89d614 581
AjK 0:0a841b89d614 582 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 583 /* Get sector# from cluster# */
AjK 0:0a841b89d614 584 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 585
AjK 0:0a841b89d614 586
AjK 0:0a841b89d614 587 DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
AjK 0:0a841b89d614 588 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 589 DWORD clst /* Cluster# to be converted */
AjK 0:0a841b89d614 590 )
AjK 0:0a841b89d614 591 {
AjK 0:0a841b89d614 592 clst -= 2;
AjK 0:0a841b89d614 593 if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */
AjK 0:0a841b89d614 594 return clst * fs->csize + fs->database;
AjK 0:0a841b89d614 595 }
AjK 0:0a841b89d614 596
AjK 0:0a841b89d614 597
AjK 0:0a841b89d614 598
AjK 0:0a841b89d614 599
AjK 0:0a841b89d614 600 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 601 /* FAT access - Read value of a FAT entry */
AjK 0:0a841b89d614 602 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 603
AjK 0:0a841b89d614 604
AjK 0:0a841b89d614 605 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
AjK 0:0a841b89d614 606 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 607 DWORD clst /* Cluster# to get the link information */
AjK 0:0a841b89d614 608 )
AjK 0:0a841b89d614 609 {
AjK 0:0a841b89d614 610 UINT wc, bc;
AjK 0:0a841b89d614 611 BYTE *p;
AjK 0:0a841b89d614 612
AjK 0:0a841b89d614 613
AjK 0:0a841b89d614 614 if (clst < 2 || clst >= fs->n_fatent) /* Chack range */
AjK 0:0a841b89d614 615 return 1;
AjK 0:0a841b89d614 616
AjK 0:0a841b89d614 617 switch (fs->fs_type) {
AjK 0:0a841b89d614 618 case FS_FAT12 :
AjK 0:0a841b89d614 619 bc = (UINT)clst; bc += bc / 2;
AjK 0:0a841b89d614 620 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
AjK 0:0a841b89d614 621 wc = fs->win[bc % SS(fs)]; bc++;
AjK 0:0a841b89d614 622 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
AjK 0:0a841b89d614 623 wc |= fs->win[bc % SS(fs)] << 8;
AjK 0:0a841b89d614 624 return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
AjK 0:0a841b89d614 625
AjK 0:0a841b89d614 626 case FS_FAT16 :
AjK 0:0a841b89d614 627 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
AjK 0:0a841b89d614 628 p = &fs->win[clst * 2 % SS(fs)];
AjK 0:0a841b89d614 629 return LD_WORD(p);
AjK 0:0a841b89d614 630
AjK 0:0a841b89d614 631 case FS_FAT32 :
AjK 0:0a841b89d614 632 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
AjK 0:0a841b89d614 633 p = &fs->win[clst * 4 % SS(fs)];
AjK 0:0a841b89d614 634 return LD_DWORD(p) & 0x0FFFFFFF;
AjK 0:0a841b89d614 635 }
AjK 0:0a841b89d614 636
AjK 0:0a841b89d614 637 return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
AjK 0:0a841b89d614 638 }
AjK 0:0a841b89d614 639
AjK 0:0a841b89d614 640
AjK 0:0a841b89d614 641
AjK 0:0a841b89d614 642
AjK 0:0a841b89d614 643 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 644 /* FAT access - Change value of a FAT entry */
AjK 0:0a841b89d614 645 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 646 #if !_FS_READONLY
AjK 0:0a841b89d614 647
AjK 0:0a841b89d614 648 FRESULT put_fat (
AjK 0:0a841b89d614 649 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 650 DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
AjK 0:0a841b89d614 651 DWORD val /* New value to mark the cluster */
AjK 0:0a841b89d614 652 )
AjK 0:0a841b89d614 653 {
AjK 0:0a841b89d614 654 UINT bc;
AjK 0:0a841b89d614 655 BYTE *p;
AjK 0:0a841b89d614 656 FRESULT res;
AjK 0:0a841b89d614 657
AjK 0:0a841b89d614 658
AjK 0:0a841b89d614 659 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
AjK 0:0a841b89d614 660 res = FR_INT_ERR;
AjK 0:0a841b89d614 661
AjK 0:0a841b89d614 662 } else {
AjK 0:0a841b89d614 663 switch (fs->fs_type) {
AjK 0:0a841b89d614 664 case FS_FAT12 :
AjK 0:0a841b89d614 665 bc = clst; bc += bc / 2;
AjK 0:0a841b89d614 666 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
AjK 0:0a841b89d614 667 if (res != FR_OK) break;
AjK 0:0a841b89d614 668 p = &fs->win[bc % SS(fs)];
AjK 0:0a841b89d614 669 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
AjK 0:0a841b89d614 670 bc++;
AjK 0:0a841b89d614 671 fs->wflag = 1;
AjK 0:0a841b89d614 672 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
AjK 0:0a841b89d614 673 if (res != FR_OK) break;
AjK 0:0a841b89d614 674 p = &fs->win[bc % SS(fs)];
AjK 0:0a841b89d614 675 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
AjK 0:0a841b89d614 676 break;
AjK 0:0a841b89d614 677
AjK 0:0a841b89d614 678 case FS_FAT16 :
AjK 0:0a841b89d614 679 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
AjK 0:0a841b89d614 680 if (res != FR_OK) break;
AjK 0:0a841b89d614 681 p = &fs->win[clst * 2 % SS(fs)];
AjK 0:0a841b89d614 682 ST_WORD(p, (WORD)val);
AjK 0:0a841b89d614 683 break;
AjK 0:0a841b89d614 684
AjK 0:0a841b89d614 685 case FS_FAT32 :
AjK 0:0a841b89d614 686 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
AjK 0:0a841b89d614 687 if (res != FR_OK) break;
AjK 0:0a841b89d614 688 p = &fs->win[clst * 4 % SS(fs)];
AjK 0:0a841b89d614 689 val |= LD_DWORD(p) & 0xF0000000;
AjK 0:0a841b89d614 690 ST_DWORD(p, val);
AjK 0:0a841b89d614 691 break;
AjK 0:0a841b89d614 692
AjK 0:0a841b89d614 693 default :
AjK 0:0a841b89d614 694 res = FR_INT_ERR;
AjK 0:0a841b89d614 695 }
AjK 0:0a841b89d614 696 fs->wflag = 1;
AjK 0:0a841b89d614 697 }
AjK 0:0a841b89d614 698
AjK 0:0a841b89d614 699 return res;
AjK 0:0a841b89d614 700 }
AjK 0:0a841b89d614 701 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 702
AjK 0:0a841b89d614 703
AjK 0:0a841b89d614 704
AjK 0:0a841b89d614 705
AjK 0:0a841b89d614 706 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 707 /* FAT handling - Remove a cluster chain */
AjK 0:0a841b89d614 708 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 709 #if !_FS_READONLY
AjK 0:0a841b89d614 710 static
AjK 0:0a841b89d614 711 FRESULT remove_chain (
AjK 0:0a841b89d614 712 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 713 DWORD clst /* Cluster# to remove a chain from */
AjK 0:0a841b89d614 714 )
AjK 0:0a841b89d614 715 {
AjK 0:0a841b89d614 716 FRESULT res;
AjK 0:0a841b89d614 717 DWORD nxt;
AjK 0:0a841b89d614 718 #if _USE_ERASE
AjK 0:0a841b89d614 719 DWORD scl = clst, ecl = clst, resion[2];
AjK 0:0a841b89d614 720 #endif
AjK 0:0a841b89d614 721
AjK 0:0a841b89d614 722 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
AjK 0:0a841b89d614 723 res = FR_INT_ERR;
AjK 0:0a841b89d614 724
AjK 0:0a841b89d614 725 } else {
AjK 0:0a841b89d614 726 res = FR_OK;
AjK 0:0a841b89d614 727 while (clst < fs->n_fatent) { /* Not a last link? */
AjK 0:0a841b89d614 728 nxt = get_fat(fs, clst); /* Get cluster status */
AjK 0:0a841b89d614 729 if (nxt == 0) break; /* Empty cluster? */
AjK 0:0a841b89d614 730 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
AjK 0:0a841b89d614 731 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
AjK 0:0a841b89d614 732 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
AjK 0:0a841b89d614 733 if (res != FR_OK) break;
AjK 0:0a841b89d614 734 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
AjK 0:0a841b89d614 735 fs->free_clust++;
AjK 0:0a841b89d614 736 fs->fsi_flag = 1;
AjK 0:0a841b89d614 737 }
AjK 0:0a841b89d614 738 #if _USE_ERASE
AjK 0:0a841b89d614 739 if (ecl + 1 == nxt) { /* Next cluster is contiguous */
AjK 0:0a841b89d614 740 ecl = nxt;
AjK 0:0a841b89d614 741 } else { /* End of contiguous clusters */
AjK 0:0a841b89d614 742 resion[0] = clust2sect(fs, scl); /* Start sector */
AjK 0:0a841b89d614 743 resion[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
AjK 0:0a841b89d614 744 disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion); /* Erase the block */
AjK 0:0a841b89d614 745 scl = ecl = nxt;
AjK 0:0a841b89d614 746 }
AjK 0:0a841b89d614 747 #endif
AjK 0:0a841b89d614 748 clst = nxt; /* Next cluster */
AjK 0:0a841b89d614 749 }
AjK 0:0a841b89d614 750 }
AjK 0:0a841b89d614 751
AjK 0:0a841b89d614 752 return res;
AjK 0:0a841b89d614 753 }
AjK 0:0a841b89d614 754 #endif
AjK 0:0a841b89d614 755
AjK 0:0a841b89d614 756
AjK 0:0a841b89d614 757
AjK 0:0a841b89d614 758
AjK 0:0a841b89d614 759 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 760 /* FAT handling - Stretch or Create a cluster chain */
AjK 0:0a841b89d614 761 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 762 #if !_FS_READONLY
AjK 0:0a841b89d614 763 static
AjK 0:0a841b89d614 764 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
AjK 0:0a841b89d614 765 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 766 DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
AjK 0:0a841b89d614 767 )
AjK 0:0a841b89d614 768 {
AjK 0:0a841b89d614 769 DWORD cs, ncl, scl;
AjK 0:0a841b89d614 770 FRESULT res;
AjK 0:0a841b89d614 771
AjK 0:0a841b89d614 772
AjK 0:0a841b89d614 773 if (clst == 0) { /* Create a new chain */
AjK 0:0a841b89d614 774 scl = fs->last_clust; /* Get suggested start point */
AjK 0:0a841b89d614 775 if (!scl || scl >= fs->n_fatent) scl = 1;
AjK 0:0a841b89d614 776 }
AjK 0:0a841b89d614 777 else { /* Stretch the current chain */
AjK 0:0a841b89d614 778 cs = get_fat(fs, clst); /* Check the cluster status */
AjK 0:0a841b89d614 779 if (cs < 2) return 1; /* It is an invalid cluster */
AjK 0:0a841b89d614 780 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
AjK 0:0a841b89d614 781 scl = clst;
AjK 0:0a841b89d614 782 }
AjK 0:0a841b89d614 783
AjK 0:0a841b89d614 784 ncl = scl; /* Start cluster */
AjK 0:0a841b89d614 785 for (;;) {
AjK 0:0a841b89d614 786 ncl++; /* Next cluster */
AjK 0:0a841b89d614 787 if (ncl >= fs->n_fatent) { /* Wrap around */
AjK 0:0a841b89d614 788 ncl = 2;
AjK 0:0a841b89d614 789 if (ncl > scl) return 0; /* No free cluster */
AjK 0:0a841b89d614 790 }
AjK 0:0a841b89d614 791 cs = get_fat(fs, ncl); /* Get the cluster status */
AjK 0:0a841b89d614 792 if (cs == 0) break; /* Found a free cluster */
AjK 0:0a841b89d614 793 if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
AjK 0:0a841b89d614 794 return cs;
AjK 0:0a841b89d614 795 if (ncl == scl) return 0; /* No free cluster */
AjK 0:0a841b89d614 796 }
AjK 0:0a841b89d614 797
AjK 0:0a841b89d614 798 res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
AjK 0:0a841b89d614 799 if (res == FR_OK && clst != 0) {
AjK 0:0a841b89d614 800 res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
AjK 0:0a841b89d614 801 }
AjK 0:0a841b89d614 802 if (res == FR_OK) {
AjK 0:0a841b89d614 803 fs->last_clust = ncl; /* Update FSINFO */
AjK 0:0a841b89d614 804 if (fs->free_clust != 0xFFFFFFFF) {
AjK 0:0a841b89d614 805 fs->free_clust--;
AjK 0:0a841b89d614 806 fs->fsi_flag = 1;
AjK 0:0a841b89d614 807 }
AjK 0:0a841b89d614 808 } else {
AjK 0:0a841b89d614 809 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
AjK 0:0a841b89d614 810 }
AjK 0:0a841b89d614 811
AjK 0:0a841b89d614 812 return ncl; /* Return new cluster number or error code */
AjK 0:0a841b89d614 813 }
AjK 0:0a841b89d614 814 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 815
AjK 0:0a841b89d614 816
AjK 0:0a841b89d614 817
AjK 0:0a841b89d614 818
AjK 0:0a841b89d614 819 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 820 /* Directory handling - Set directory index */
AjK 0:0a841b89d614 821 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 822
AjK 0:0a841b89d614 823 static
AjK 0:0a841b89d614 824 FRESULT dir_sdi (
AjK 0:0a841b89d614 825 DIR *dj, /* Pointer to directory object */
AjK 0:0a841b89d614 826 WORD idx /* Directory index number */
AjK 0:0a841b89d614 827 )
AjK 0:0a841b89d614 828 {
AjK 0:0a841b89d614 829 DWORD clst;
AjK 0:0a841b89d614 830 WORD ic;
AjK 0:0a841b89d614 831
AjK 0:0a841b89d614 832
AjK 0:0a841b89d614 833 dj->index = idx;
AjK 0:0a841b89d614 834 clst = dj->sclust;
AjK 0:0a841b89d614 835 if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
AjK 0:0a841b89d614 836 return FR_INT_ERR;
AjK 0:0a841b89d614 837 if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
AjK 0:0a841b89d614 838 clst = dj->fs->dirbase;
AjK 0:0a841b89d614 839
AjK 0:0a841b89d614 840 if (clst == 0) { /* Static table (root-dir in FAT12/16) */
AjK 0:0a841b89d614 841 dj->clust = clst;
AjK 0:0a841b89d614 842 if (idx >= dj->fs->n_rootdir) /* Index is out of range */
AjK 0:0a841b89d614 843 return FR_INT_ERR;
AjK 0:0a841b89d614 844 dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */
AjK 0:0a841b89d614 845 }
AjK 0:0a841b89d614 846 else { /* Dynamic table (sub-dirs or root-dir in FAT32) */
AjK 0:0a841b89d614 847 ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */
AjK 0:0a841b89d614 848 while (idx >= ic) { /* Follow cluster chain */
AjK 0:0a841b89d614 849 clst = get_fat(dj->fs, clst); /* Get next cluster */
AjK 0:0a841b89d614 850 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
AjK 0:0a841b89d614 851 if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */
AjK 0:0a841b89d614 852 return FR_INT_ERR;
AjK 0:0a841b89d614 853 idx -= ic;
AjK 0:0a841b89d614 854 }
AjK 0:0a841b89d614 855 dj->clust = clst;
AjK 0:0a841b89d614 856 dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */
AjK 0:0a841b89d614 857 }
AjK 0:0a841b89d614 858
AjK 0:0a841b89d614 859 dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
AjK 0:0a841b89d614 860
AjK 0:0a841b89d614 861 return FR_OK; /* Seek succeeded */
AjK 0:0a841b89d614 862 }
AjK 0:0a841b89d614 863
AjK 0:0a841b89d614 864
AjK 0:0a841b89d614 865
AjK 0:0a841b89d614 866
AjK 0:0a841b89d614 867 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 868 /* Directory handling - Move directory index next */
AjK 0:0a841b89d614 869 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 870
AjK 0:0a841b89d614 871 static
AjK 0:0a841b89d614 872 FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
AjK 0:0a841b89d614 873 DIR *dj, /* Pointer to directory object */
AjK 0:0a841b89d614 874 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
AjK 0:0a841b89d614 875 )
AjK 0:0a841b89d614 876 {
AjK 0:0a841b89d614 877 DWORD clst;
AjK 0:0a841b89d614 878 WORD i;
AjK 0:0a841b89d614 879
AjK 0:0a841b89d614 880
AjK 0:0a841b89d614 881 i = dj->index + 1;
AjK 0:0a841b89d614 882 if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
AjK 0:0a841b89d614 883 return FR_NO_FILE;
AjK 0:0a841b89d614 884
AjK 0:0a841b89d614 885 if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
AjK 0:0a841b89d614 886 dj->sect++; /* Next sector */
AjK 0:0a841b89d614 887
AjK 0:0a841b89d614 888 if (dj->clust == 0) { /* Static table */
AjK 0:0a841b89d614 889 if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
AjK 0:0a841b89d614 890 return FR_NO_FILE;
AjK 0:0a841b89d614 891 }
AjK 0:0a841b89d614 892 else { /* Dynamic table */
AjK 0:0a841b89d614 893 if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
AjK 0:0a841b89d614 894 clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
AjK 0:0a841b89d614 895 if (clst <= 1) return FR_INT_ERR;
AjK 0:0a841b89d614 896 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
AjK 0:0a841b89d614 897 if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
AjK 0:0a841b89d614 898 #if !_FS_READONLY
AjK 0:0a841b89d614 899 BYTE c;
AjK 0:0a841b89d614 900 if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */
AjK 0:0a841b89d614 901 clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
AjK 0:0a841b89d614 902 if (clst == 0) return FR_DENIED; /* No free cluster */
AjK 0:0a841b89d614 903 if (clst == 1) return FR_INT_ERR;
AjK 0:0a841b89d614 904 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
AjK 0:0a841b89d614 905 /* Clean-up stretched table */
AjK 0:0a841b89d614 906 if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
AjK 0:0a841b89d614 907 mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
AjK 0:0a841b89d614 908 dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
AjK 0:0a841b89d614 909 for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
AjK 0:0a841b89d614 910 dj->fs->wflag = 1;
AjK 0:0a841b89d614 911 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
AjK 0:0a841b89d614 912 dj->fs->winsect++;
AjK 0:0a841b89d614 913 }
AjK 0:0a841b89d614 914 dj->fs->winsect -= c; /* Rewind window address */
AjK 0:0a841b89d614 915 #else
AjK 0:0a841b89d614 916 return FR_NO_FILE; /* Report EOT */
AjK 0:0a841b89d614 917 #endif
AjK 0:0a841b89d614 918 }
AjK 0:0a841b89d614 919 dj->clust = clst; /* Initialize data for new cluster */
AjK 0:0a841b89d614 920 dj->sect = clust2sect(dj->fs, clst);
AjK 0:0a841b89d614 921 }
AjK 0:0a841b89d614 922 }
AjK 0:0a841b89d614 923 }
AjK 0:0a841b89d614 924
AjK 0:0a841b89d614 925 dj->index = i;
AjK 0:0a841b89d614 926 dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
AjK 0:0a841b89d614 927
AjK 0:0a841b89d614 928 return FR_OK;
AjK 0:0a841b89d614 929 }
AjK 0:0a841b89d614 930
AjK 0:0a841b89d614 931
AjK 0:0a841b89d614 932
AjK 0:0a841b89d614 933
AjK 0:0a841b89d614 934 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 935 /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
AjK 0:0a841b89d614 936 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 937 #if _USE_LFN
AjK 0:0a841b89d614 938 static
AjK 0:0a841b89d614 939 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
AjK 0:0a841b89d614 940
AjK 0:0a841b89d614 941
AjK 0:0a841b89d614 942 static
AjK 0:0a841b89d614 943 int cmp_lfn ( /* 1:Matched, 0:Not matched */
AjK 0:0a841b89d614 944 WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
AjK 0:0a841b89d614 945 BYTE *dir /* Pointer to the directory entry containing a part of LFN */
AjK 0:0a841b89d614 946 )
AjK 0:0a841b89d614 947 {
AjK 0:0a841b89d614 948 UINT i, s;
AjK 0:0a841b89d614 949 WCHAR wc, uc;
AjK 0:0a841b89d614 950
AjK 0:0a841b89d614 951
AjK 0:0a841b89d614 952 i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */
AjK 0:0a841b89d614 953 s = 0; wc = 1;
AjK 0:0a841b89d614 954 do {
AjK 0:0a841b89d614 955 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
AjK 0:0a841b89d614 956 if (wc) { /* Last char has not been processed */
AjK 0:0a841b89d614 957 wc = ff_wtoupper(uc); /* Convert it to upper case */
AjK 0:0a841b89d614 958 if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
AjK 0:0a841b89d614 959 return 0; /* Not matched */
AjK 0:0a841b89d614 960 } else {
AjK 0:0a841b89d614 961 if (uc != 0xFFFF) return 0; /* Check filler */
AjK 0:0a841b89d614 962 }
AjK 0:0a841b89d614 963 } while (++s < 13); /* Repeat until all chars in the entry are checked */
AjK 0:0a841b89d614 964
AjK 0:0a841b89d614 965 if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */
AjK 0:0a841b89d614 966 return 0;
AjK 0:0a841b89d614 967
AjK 0:0a841b89d614 968 return 1; /* The part of LFN matched */
AjK 0:0a841b89d614 969 }
AjK 0:0a841b89d614 970
AjK 0:0a841b89d614 971
AjK 0:0a841b89d614 972
AjK 0:0a841b89d614 973 static
AjK 0:0a841b89d614 974 int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
AjK 0:0a841b89d614 975 WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
AjK 0:0a841b89d614 976 BYTE *dir /* Pointer to the directory entry */
AjK 0:0a841b89d614 977 )
AjK 0:0a841b89d614 978 {
AjK 0:0a841b89d614 979 UINT i, s;
AjK 0:0a841b89d614 980 WCHAR wc, uc;
AjK 0:0a841b89d614 981
AjK 0:0a841b89d614 982
AjK 0:0a841b89d614 983 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
AjK 0:0a841b89d614 984
AjK 0:0a841b89d614 985 s = 0; wc = 1;
AjK 0:0a841b89d614 986 do {
AjK 0:0a841b89d614 987 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
AjK 0:0a841b89d614 988 if (wc) { /* Last char has not been processed */
AjK 0:0a841b89d614 989 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
AjK 0:0a841b89d614 990 lfnbuf[i++] = wc = uc; /* Store it */
AjK 0:0a841b89d614 991 } else {
AjK 0:0a841b89d614 992 if (uc != 0xFFFF) return 0; /* Check filler */
AjK 0:0a841b89d614 993 }
AjK 0:0a841b89d614 994 } while (++s < 13); /* Read all character in the entry */
AjK 0:0a841b89d614 995
AjK 0:0a841b89d614 996 if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */
AjK 0:0a841b89d614 997 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
AjK 0:0a841b89d614 998 lfnbuf[i] = 0;
AjK 0:0a841b89d614 999 }
AjK 0:0a841b89d614 1000
AjK 0:0a841b89d614 1001 return 1;
AjK 0:0a841b89d614 1002 }
AjK 0:0a841b89d614 1003
AjK 0:0a841b89d614 1004
AjK 0:0a841b89d614 1005 #if !_FS_READONLY
AjK 0:0a841b89d614 1006 static
AjK 0:0a841b89d614 1007 void fit_lfn (
AjK 0:0a841b89d614 1008 const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
AjK 0:0a841b89d614 1009 BYTE *dir, /* Pointer to the directory entry */
AjK 0:0a841b89d614 1010 BYTE ord, /* LFN order (1-20) */
AjK 0:0a841b89d614 1011 BYTE sum /* SFN sum */
AjK 0:0a841b89d614 1012 )
AjK 0:0a841b89d614 1013 {
AjK 0:0a841b89d614 1014 UINT i, s;
AjK 0:0a841b89d614 1015 WCHAR wc;
AjK 0:0a841b89d614 1016
AjK 0:0a841b89d614 1017
AjK 0:0a841b89d614 1018 dir[LDIR_Chksum] = sum; /* Set check sum */
AjK 0:0a841b89d614 1019 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
AjK 0:0a841b89d614 1020 dir[LDIR_Type] = 0;
AjK 0:0a841b89d614 1021 ST_WORD(dir+LDIR_FstClusLO, 0);
AjK 0:0a841b89d614 1022
AjK 0:0a841b89d614 1023 i = (ord - 1) * 13; /* Get offset in the LFN buffer */
AjK 0:0a841b89d614 1024 s = wc = 0;
AjK 0:0a841b89d614 1025 do {
AjK 0:0a841b89d614 1026 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
AjK 0:0a841b89d614 1027 ST_WORD(dir+LfnOfs[s], wc); /* Put it */
AjK 0:0a841b89d614 1028 if (!wc) wc = 0xFFFF; /* Padding chars following last char */
AjK 0:0a841b89d614 1029 } while (++s < 13);
AjK 0:0a841b89d614 1030 if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */
AjK 0:0a841b89d614 1031 dir[LDIR_Ord] = ord; /* Set the LFN order */
AjK 0:0a841b89d614 1032 }
AjK 0:0a841b89d614 1033
AjK 0:0a841b89d614 1034 #endif
AjK 0:0a841b89d614 1035 #endif
AjK 0:0a841b89d614 1036
AjK 0:0a841b89d614 1037
AjK 0:0a841b89d614 1038
AjK 0:0a841b89d614 1039 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1040 /* Create numbered name */
AjK 0:0a841b89d614 1041 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1042 #if _USE_LFN
AjK 0:0a841b89d614 1043 void gen_numname (
AjK 0:0a841b89d614 1044 BYTE *dst, /* Pointer to generated SFN */
AjK 0:0a841b89d614 1045 const BYTE *src, /* Pointer to source SFN to be modified */
AjK 0:0a841b89d614 1046 const WCHAR *lfn, /* Pointer to LFN */
AjK 0:0a841b89d614 1047 WORD seq /* Sequence number */
AjK 0:0a841b89d614 1048 )
AjK 0:0a841b89d614 1049 {
AjK 0:0a841b89d614 1050 BYTE ns[8], c;
AjK 0:0a841b89d614 1051 UINT i, j;
AjK 0:0a841b89d614 1052
AjK 0:0a841b89d614 1053
AjK 0:0a841b89d614 1054 mem_cpy(dst, src, 11);
AjK 0:0a841b89d614 1055
AjK 0:0a841b89d614 1056 if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
AjK 0:0a841b89d614 1057 do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
AjK 0:0a841b89d614 1058 }
AjK 0:0a841b89d614 1059
AjK 0:0a841b89d614 1060 /* itoa */
AjK 0:0a841b89d614 1061 i = 7;
AjK 0:0a841b89d614 1062 do {
AjK 0:0a841b89d614 1063 c = (seq % 16) + '0';
AjK 0:0a841b89d614 1064 if (c > '9') c += 7;
AjK 0:0a841b89d614 1065 ns[i--] = c;
AjK 0:0a841b89d614 1066 seq /= 16;
AjK 0:0a841b89d614 1067 } while (seq);
AjK 0:0a841b89d614 1068 ns[i] = '~';
AjK 0:0a841b89d614 1069
AjK 0:0a841b89d614 1070 /* Append the number */
AjK 0:0a841b89d614 1071 for (j = 0; j < i && dst[j] != ' '; j++) {
AjK 0:0a841b89d614 1072 if (IsDBCS1(dst[j])) {
AjK 0:0a841b89d614 1073 if (j == i - 1) break;
AjK 0:0a841b89d614 1074 j++;
AjK 0:0a841b89d614 1075 }
AjK 0:0a841b89d614 1076 }
AjK 0:0a841b89d614 1077 do {
AjK 0:0a841b89d614 1078 dst[j++] = (i < 8) ? ns[i++] : ' ';
AjK 0:0a841b89d614 1079 } while (j < 8);
AjK 0:0a841b89d614 1080 }
AjK 0:0a841b89d614 1081 #endif
AjK 0:0a841b89d614 1082
AjK 0:0a841b89d614 1083
AjK 0:0a841b89d614 1084
AjK 0:0a841b89d614 1085
AjK 0:0a841b89d614 1086 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1087 /* Calculate sum of an SFN */
AjK 0:0a841b89d614 1088 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1089 #if _USE_LFN
AjK 0:0a841b89d614 1090 static
AjK 0:0a841b89d614 1091 BYTE sum_sfn (
AjK 0:0a841b89d614 1092 const BYTE *dir /* Ptr to directory entry */
AjK 0:0a841b89d614 1093 )
AjK 0:0a841b89d614 1094 {
AjK 0:0a841b89d614 1095 BYTE sum = 0;
AjK 0:0a841b89d614 1096 UINT n = 11;
AjK 0:0a841b89d614 1097
AjK 0:0a841b89d614 1098 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
AjK 0:0a841b89d614 1099 return sum;
AjK 0:0a841b89d614 1100 }
AjK 0:0a841b89d614 1101 #endif
AjK 0:0a841b89d614 1102
AjK 0:0a841b89d614 1103
AjK 0:0a841b89d614 1104
AjK 0:0a841b89d614 1105
AjK 0:0a841b89d614 1106 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1107 /* Directory handling - Find an object in the directory */
AjK 0:0a841b89d614 1108 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1109
AjK 0:0a841b89d614 1110 static
AjK 0:0a841b89d614 1111 FRESULT dir_find (
AjK 0:0a841b89d614 1112 DIR *dj /* Pointer to the directory object linked to the file name */
AjK 0:0a841b89d614 1113 )
AjK 0:0a841b89d614 1114 {
AjK 0:0a841b89d614 1115 FRESULT res;
AjK 0:0a841b89d614 1116 BYTE c, *dir;
AjK 0:0a841b89d614 1117 #if _USE_LFN
AjK 0:0a841b89d614 1118 BYTE a, ord, sum;
AjK 0:0a841b89d614 1119 #endif
AjK 0:0a841b89d614 1120
AjK 0:0a841b89d614 1121 res = dir_sdi(dj, 0); /* Rewind directory object */
AjK 0:0a841b89d614 1122 if (res != FR_OK) return res;
AjK 0:0a841b89d614 1123
AjK 0:0a841b89d614 1124 #if _USE_LFN
AjK 0:0a841b89d614 1125 ord = sum = 0xFF;
AjK 0:0a841b89d614 1126 #endif
AjK 0:0a841b89d614 1127 do {
AjK 0:0a841b89d614 1128 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1129 if (res != FR_OK) break;
AjK 0:0a841b89d614 1130 dir = dj->dir; /* Ptr to the directory entry of current index */
AjK 0:0a841b89d614 1131 c = dir[DIR_Name];
AjK 0:0a841b89d614 1132 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
AjK 0:0a841b89d614 1133 #if _USE_LFN /* LFN configuration */
AjK 0:0a841b89d614 1134 a = dir[DIR_Attr] & AM_MASK;
AjK 0:0a841b89d614 1135 if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
AjK 0:0a841b89d614 1136 ord = 0xFF;
AjK 0:0a841b89d614 1137 } else {
AjK 0:0a841b89d614 1138 if (a == AM_LFN) { /* An LFN entry is found */
AjK 0:0a841b89d614 1139 if (dj->lfn) {
AjK 0:0a841b89d614 1140 if (c & 0x40) { /* Is it start of LFN sequence? */
AjK 0:0a841b89d614 1141 sum = dir[LDIR_Chksum];
AjK 0:0a841b89d614 1142 c &= 0xBF; ord = c; /* LFN start order */
AjK 0:0a841b89d614 1143 dj->lfn_idx = dj->index;
AjK 0:0a841b89d614 1144 }
AjK 0:0a841b89d614 1145 /* Check validity of the LFN entry and compare it with given name */
AjK 0:0a841b89d614 1146 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
AjK 0:0a841b89d614 1147 }
AjK 0:0a841b89d614 1148 } else { /* An SFN entry is found */
AjK 0:0a841b89d614 1149 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
AjK 0:0a841b89d614 1150 ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
AjK 0:0a841b89d614 1151 if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
AjK 0:0a841b89d614 1152 }
AjK 0:0a841b89d614 1153 }
AjK 0:0a841b89d614 1154 #else /* Non LFN configuration */
AjK 0:0a841b89d614 1155 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
AjK 0:0a841b89d614 1156 break;
AjK 0:0a841b89d614 1157 #endif
AjK 0:0a841b89d614 1158 res = dir_next(dj, 0); /* Next entry */
AjK 0:0a841b89d614 1159 } while (res == FR_OK);
AjK 0:0a841b89d614 1160
AjK 0:0a841b89d614 1161 return res;
AjK 0:0a841b89d614 1162 }
AjK 0:0a841b89d614 1163
AjK 0:0a841b89d614 1164
AjK 0:0a841b89d614 1165
AjK 0:0a841b89d614 1166
AjK 0:0a841b89d614 1167 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1168 /* Read an object from the directory */
AjK 0:0a841b89d614 1169 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1170 #if _FS_MINIMIZE <= 1
AjK 0:0a841b89d614 1171 static
AjK 0:0a841b89d614 1172 FRESULT dir_read (
AjK 0:0a841b89d614 1173 DIR *dj /* Pointer to the directory object that pointing the entry to be read */
AjK 0:0a841b89d614 1174 )
AjK 0:0a841b89d614 1175 {
AjK 0:0a841b89d614 1176 FRESULT res;
AjK 0:0a841b89d614 1177 BYTE c, *dir;
AjK 0:0a841b89d614 1178 #if _USE_LFN
AjK 0:0a841b89d614 1179 BYTE a, ord = 0xFF, sum = 0xFF;
AjK 0:0a841b89d614 1180 #endif
AjK 0:0a841b89d614 1181
AjK 0:0a841b89d614 1182 res = FR_NO_FILE;
AjK 0:0a841b89d614 1183 while (dj->sect) {
AjK 0:0a841b89d614 1184 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1185 if (res != FR_OK) break;
AjK 0:0a841b89d614 1186 dir = dj->dir; /* Ptr to the directory entry of current index */
AjK 0:0a841b89d614 1187 c = dir[DIR_Name];
AjK 0:0a841b89d614 1188 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
AjK 0:0a841b89d614 1189 #if _USE_LFN /* LFN configuration */
AjK 0:0a841b89d614 1190 a = dir[DIR_Attr] & AM_MASK;
AjK 0:0a841b89d614 1191 if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
AjK 0:0a841b89d614 1192 ord = 0xFF;
AjK 0:0a841b89d614 1193 } else {
AjK 0:0a841b89d614 1194 if (a == AM_LFN) { /* An LFN entry is found */
AjK 0:0a841b89d614 1195 if (c & 0x40) { /* Is it start of LFN sequence? */
AjK 0:0a841b89d614 1196 sum = dir[LDIR_Chksum];
AjK 0:0a841b89d614 1197 c &= 0xBF; ord = c;
AjK 0:0a841b89d614 1198 dj->lfn_idx = dj->index;
AjK 0:0a841b89d614 1199 }
AjK 0:0a841b89d614 1200 /* Check LFN validity and capture it */
AjK 0:0a841b89d614 1201 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
AjK 0:0a841b89d614 1202 } else { /* An SFN entry is found */
AjK 0:0a841b89d614 1203 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
AjK 0:0a841b89d614 1204 dj->lfn_idx = 0xFFFF; /* It has no LFN. */
AjK 0:0a841b89d614 1205 break;
AjK 0:0a841b89d614 1206 }
AjK 0:0a841b89d614 1207 }
AjK 0:0a841b89d614 1208 #else /* Non LFN configuration */
AjK 0:0a841b89d614 1209 if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
AjK 0:0a841b89d614 1210 break;
AjK 0:0a841b89d614 1211 #endif
AjK 0:0a841b89d614 1212 res = dir_next(dj, 0); /* Next entry */
AjK 0:0a841b89d614 1213 if (res != FR_OK) break;
AjK 0:0a841b89d614 1214 }
AjK 0:0a841b89d614 1215
AjK 0:0a841b89d614 1216 if (res != FR_OK) dj->sect = 0;
AjK 0:0a841b89d614 1217
AjK 0:0a841b89d614 1218 return res;
AjK 0:0a841b89d614 1219 }
AjK 0:0a841b89d614 1220 #endif
AjK 0:0a841b89d614 1221
AjK 0:0a841b89d614 1222
AjK 0:0a841b89d614 1223
AjK 0:0a841b89d614 1224 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1225 /* Register an object to the directory */
AjK 0:0a841b89d614 1226 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1227 #if !_FS_READONLY
AjK 0:0a841b89d614 1228 static
AjK 0:0a841b89d614 1229 FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
AjK 0:0a841b89d614 1230 DIR *dj /* Target directory with object name to be created */
AjK 0:0a841b89d614 1231 )
AjK 0:0a841b89d614 1232 {
AjK 0:0a841b89d614 1233 FRESULT res;
AjK 0:0a841b89d614 1234 BYTE c, *dir;
AjK 0:0a841b89d614 1235 #if _USE_LFN /* LFN configuration */
AjK 0:0a841b89d614 1236 WORD n, ne, is;
AjK 0:0a841b89d614 1237 BYTE sn[12], *fn, sum;
AjK 0:0a841b89d614 1238 WCHAR *lfn;
AjK 0:0a841b89d614 1239
AjK 0:0a841b89d614 1240
AjK 0:0a841b89d614 1241 fn = dj->fn; lfn = dj->lfn;
AjK 0:0a841b89d614 1242 mem_cpy(sn, fn, 12);
AjK 0:0a841b89d614 1243
AjK 0:0a841b89d614 1244 if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */
AjK 0:0a841b89d614 1245 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1246
AjK 0:0a841b89d614 1247 if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
AjK 0:0a841b89d614 1248 fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
AjK 0:0a841b89d614 1249 for (n = 1; n < 100; n++) {
AjK 0:0a841b89d614 1250 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
AjK 0:0a841b89d614 1251 res = dir_find(dj); /* Check if the name collides with existing SFN */
AjK 0:0a841b89d614 1252 if (res != FR_OK) break;
AjK 0:0a841b89d614 1253 }
AjK 0:0a841b89d614 1254 if (n == 100) return FR_DENIED; /* Abort if too many collisions */
AjK 0:0a841b89d614 1255 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
AjK 0:0a841b89d614 1256 fn[NS] = sn[NS]; dj->lfn = lfn;
AjK 0:0a841b89d614 1257 }
AjK 0:0a841b89d614 1258
AjK 0:0a841b89d614 1259 if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */
AjK 0:0a841b89d614 1260 for (ne = 0; lfn[ne]; ne++) ;
AjK 0:0a841b89d614 1261 ne = (ne + 25) / 13;
AjK 0:0a841b89d614 1262 } else { /* Otherwise reserve only an SFN entry. */
AjK 0:0a841b89d614 1263 ne = 1;
AjK 0:0a841b89d614 1264 }
AjK 0:0a841b89d614 1265
AjK 0:0a841b89d614 1266 /* Reserve contiguous entries */
AjK 0:0a841b89d614 1267 res = dir_sdi(dj, 0);
AjK 0:0a841b89d614 1268 if (res != FR_OK) return res;
AjK 0:0a841b89d614 1269 n = is = 0;
AjK 0:0a841b89d614 1270 do {
AjK 0:0a841b89d614 1271 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1272 if (res != FR_OK) break;
AjK 0:0a841b89d614 1273 c = *dj->dir; /* Check the entry status */
AjK 0:0a841b89d614 1274 if (c == 0xE5 || c == 0) { /* Is it a blank entry? */
AjK 0:0a841b89d614 1275 if (n == 0) is = dj->index; /* First index of the contiguous entry */
AjK 0:0a841b89d614 1276 if (++n == ne) break; /* A contiguous entry that required count is found */
AjK 0:0a841b89d614 1277 } else {
AjK 0:0a841b89d614 1278 n = 0; /* Not a blank entry. Restart to search */
AjK 0:0a841b89d614 1279 }
AjK 0:0a841b89d614 1280 res = dir_next(dj, 1); /* Next entry with table stretch */
AjK 0:0a841b89d614 1281 } while (res == FR_OK);
AjK 0:0a841b89d614 1282
AjK 0:0a841b89d614 1283 if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
AjK 0:0a841b89d614 1284 res = dir_sdi(dj, is);
AjK 0:0a841b89d614 1285 if (res == FR_OK) {
AjK 0:0a841b89d614 1286 sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
AjK 0:0a841b89d614 1287 ne--;
AjK 0:0a841b89d614 1288 do { /* Store LFN entries in bottom first */
AjK 0:0a841b89d614 1289 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1290 if (res != FR_OK) break;
AjK 0:0a841b89d614 1291 fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
AjK 0:0a841b89d614 1292 dj->fs->wflag = 1;
AjK 0:0a841b89d614 1293 res = dir_next(dj, 0); /* Next entry */
AjK 0:0a841b89d614 1294 } while (res == FR_OK && --ne);
AjK 0:0a841b89d614 1295 }
AjK 0:0a841b89d614 1296 }
AjK 0:0a841b89d614 1297
AjK 0:0a841b89d614 1298 #else /* Non LFN configuration */
AjK 0:0a841b89d614 1299 res = dir_sdi(dj, 0);
AjK 0:0a841b89d614 1300 if (res == FR_OK) {
AjK 0:0a841b89d614 1301 do { /* Find a blank entry for the SFN */
AjK 0:0a841b89d614 1302 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1303 if (res != FR_OK) break;
AjK 0:0a841b89d614 1304 c = *dj->dir;
AjK 0:0a841b89d614 1305 if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */
AjK 0:0a841b89d614 1306 res = dir_next(dj, 1); /* Next entry with table stretch */
AjK 0:0a841b89d614 1307 } while (res == FR_OK);
AjK 0:0a841b89d614 1308 }
AjK 0:0a841b89d614 1309 #endif
AjK 0:0a841b89d614 1310
AjK 0:0a841b89d614 1311 if (res == FR_OK) { /* Initialize the SFN entry */
AjK 0:0a841b89d614 1312 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1313 if (res == FR_OK) {
AjK 0:0a841b89d614 1314 dir = dj->dir;
AjK 0:0a841b89d614 1315 mem_set(dir, 0, 32); /* Clean the entry */
AjK 0:0a841b89d614 1316 mem_cpy(dir, dj->fn, 11); /* Put SFN */
AjK 0:0a841b89d614 1317 #if _USE_LFN
AjK 0:0a841b89d614 1318 dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
AjK 0:0a841b89d614 1319 #endif
AjK 0:0a841b89d614 1320 dj->fs->wflag = 1;
AjK 0:0a841b89d614 1321 }
AjK 0:0a841b89d614 1322 }
AjK 0:0a841b89d614 1323
AjK 0:0a841b89d614 1324 return res;
AjK 0:0a841b89d614 1325 }
AjK 0:0a841b89d614 1326 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 1327
AjK 0:0a841b89d614 1328
AjK 0:0a841b89d614 1329
AjK 0:0a841b89d614 1330
AjK 0:0a841b89d614 1331 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1332 /* Remove an object from the directory */
AjK 0:0a841b89d614 1333 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1334 #if !_FS_READONLY && !_FS_MINIMIZE
AjK 0:0a841b89d614 1335 static
AjK 0:0a841b89d614 1336 FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
AjK 0:0a841b89d614 1337 DIR *dj /* Directory object pointing the entry to be removed */
AjK 0:0a841b89d614 1338 )
AjK 0:0a841b89d614 1339 {
AjK 0:0a841b89d614 1340 FRESULT res;
AjK 0:0a841b89d614 1341 #if _USE_LFN /* LFN configuration */
AjK 0:0a841b89d614 1342 WORD i;
AjK 0:0a841b89d614 1343
AjK 0:0a841b89d614 1344 i = dj->index; /* SFN index */
AjK 0:0a841b89d614 1345 res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
AjK 0:0a841b89d614 1346 if (res == FR_OK) {
AjK 0:0a841b89d614 1347 do {
AjK 0:0a841b89d614 1348 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1349 if (res != FR_OK) break;
AjK 0:0a841b89d614 1350 *dj->dir = 0xE5; /* Mark the entry "deleted" */
AjK 0:0a841b89d614 1351 dj->fs->wflag = 1;
AjK 0:0a841b89d614 1352 if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
AjK 0:0a841b89d614 1353 res = dir_next(dj, 0); /* Next entry */
AjK 0:0a841b89d614 1354 } while (res == FR_OK);
AjK 0:0a841b89d614 1355 if (res == FR_NO_FILE) res = FR_INT_ERR;
AjK 0:0a841b89d614 1356 }
AjK 0:0a841b89d614 1357
AjK 0:0a841b89d614 1358 #else /* Non LFN configuration */
AjK 0:0a841b89d614 1359 res = dir_sdi(dj, dj->index);
AjK 0:0a841b89d614 1360 if (res == FR_OK) {
AjK 0:0a841b89d614 1361 res = move_window(dj->fs, dj->sect);
AjK 0:0a841b89d614 1362 if (res == FR_OK) {
AjK 0:0a841b89d614 1363 *dj->dir = 0xE5; /* Mark the entry "deleted" */
AjK 0:0a841b89d614 1364 dj->fs->wflag = 1;
AjK 0:0a841b89d614 1365 }
AjK 0:0a841b89d614 1366 }
AjK 0:0a841b89d614 1367 #endif
AjK 0:0a841b89d614 1368
AjK 0:0a841b89d614 1369 return res;
AjK 0:0a841b89d614 1370 }
AjK 0:0a841b89d614 1371 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 1372
AjK 0:0a841b89d614 1373
AjK 0:0a841b89d614 1374
AjK 0:0a841b89d614 1375
AjK 0:0a841b89d614 1376 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1377 /* Pick a segment and create the object name in directory form */
AjK 0:0a841b89d614 1378 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1379
AjK 0:0a841b89d614 1380 static
AjK 0:0a841b89d614 1381 FRESULT create_name (
AjK 0:0a841b89d614 1382 DIR *dj, /* Pointer to the directory object */
AjK 0:0a841b89d614 1383 const TCHAR **path /* Pointer to pointer to the segment in the path string */
AjK 0:0a841b89d614 1384 )
AjK 0:0a841b89d614 1385 {
AjK 0:0a841b89d614 1386 #ifdef _EXCVT
AjK 0:0a841b89d614 1387 static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
AjK 0:0a841b89d614 1388 #endif
AjK 0:0a841b89d614 1389
AjK 0:0a841b89d614 1390 #if _USE_LFN /* LFN configuration */
AjK 0:0a841b89d614 1391 BYTE b, cf;
AjK 0:0a841b89d614 1392 WCHAR w, *lfn;
AjK 0:0a841b89d614 1393 UINT i, ni, si, di;
AjK 0:0a841b89d614 1394 const TCHAR *p;
AjK 0:0a841b89d614 1395
AjK 0:0a841b89d614 1396 /* Create LFN in Unicode */
AjK 0:0a841b89d614 1397 si = di = 0;
AjK 0:0a841b89d614 1398 p = *path;
AjK 0:0a841b89d614 1399 lfn = dj->lfn;
AjK 0:0a841b89d614 1400 for (;;) {
AjK 0:0a841b89d614 1401 w = p[si++]; /* Get a character */
AjK 0:0a841b89d614 1402 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
AjK 0:0a841b89d614 1403 if (di >= _MAX_LFN) /* Reject too long name */
AjK 0:0a841b89d614 1404 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1405 #if !_LFN_UNICODE
AjK 0:0a841b89d614 1406 w &= 0xFF;
AjK 0:0a841b89d614 1407 if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
AjK 0:0a841b89d614 1408 b = (BYTE)p[si++]; /* Get 2nd byte */
AjK 0:0a841b89d614 1409 if (!IsDBCS2(b))
AjK 0:0a841b89d614 1410 return FR_INVALID_NAME; /* Reject invalid sequence */
AjK 0:0a841b89d614 1411 w = (w << 8) + b; /* Create a DBC */
AjK 0:0a841b89d614 1412 }
AjK 0:0a841b89d614 1413 w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
AjK 0:0a841b89d614 1414 if (!w) return FR_INVALID_NAME; /* Reject invalid code */
AjK 0:0a841b89d614 1415 #endif
AjK 0:0a841b89d614 1416 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
AjK 0:0a841b89d614 1417 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1418 lfn[di++] = w; /* Store the Unicode char */
AjK 0:0a841b89d614 1419 }
AjK 0:0a841b89d614 1420 *path = &p[si]; /* Return pointer to the next segment */
AjK 0:0a841b89d614 1421 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
AjK 0:0a841b89d614 1422 #if _FS_RPATH
AjK 0:0a841b89d614 1423 if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
AjK 0:0a841b89d614 1424 (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
AjK 0:0a841b89d614 1425 lfn[di] = 0;
AjK 0:0a841b89d614 1426 for (i = 0; i < 11; i++)
AjK 0:0a841b89d614 1427 dj->fn[i] = (i < di) ? '.' : ' ';
AjK 0:0a841b89d614 1428 dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
AjK 0:0a841b89d614 1429 return FR_OK;
AjK 0:0a841b89d614 1430 }
AjK 0:0a841b89d614 1431 #endif
AjK 0:0a841b89d614 1432 while (di) { /* Strip trailing spaces and dots */
AjK 0:0a841b89d614 1433 w = lfn[di-1];
AjK 0:0a841b89d614 1434 if (w != ' ' && w != '.') break;
AjK 0:0a841b89d614 1435 di--;
AjK 0:0a841b89d614 1436 }
AjK 0:0a841b89d614 1437 if (!di) return FR_INVALID_NAME; /* Reject nul string */
AjK 0:0a841b89d614 1438
AjK 0:0a841b89d614 1439 lfn[di] = 0; /* LFN is created */
AjK 0:0a841b89d614 1440
AjK 0:0a841b89d614 1441 /* Create SFN in directory form */
AjK 0:0a841b89d614 1442 mem_set(dj->fn, ' ', 11);
AjK 0:0a841b89d614 1443 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
AjK 0:0a841b89d614 1444 if (si) cf |= NS_LOSS | NS_LFN;
AjK 0:0a841b89d614 1445 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
AjK 0:0a841b89d614 1446
AjK 0:0a841b89d614 1447 b = i = 0; ni = 8;
AjK 0:0a841b89d614 1448 for (;;) {
AjK 0:0a841b89d614 1449 w = lfn[si++]; /* Get an LFN char */
AjK 0:0a841b89d614 1450 if (!w) break; /* Break on end of the LFN */
AjK 0:0a841b89d614 1451 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
AjK 0:0a841b89d614 1452 cf |= NS_LOSS | NS_LFN; continue;
AjK 0:0a841b89d614 1453 }
AjK 0:0a841b89d614 1454
AjK 0:0a841b89d614 1455 if (i >= ni || si == di) { /* Extension or end of SFN */
AjK 0:0a841b89d614 1456 if (ni == 11) { /* Long extension */
AjK 0:0a841b89d614 1457 cf |= NS_LOSS | NS_LFN; break;
AjK 0:0a841b89d614 1458 }
AjK 0:0a841b89d614 1459 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
AjK 0:0a841b89d614 1460 if (si > di) break; /* No extension */
AjK 0:0a841b89d614 1461 si = di; i = 8; ni = 11; /* Enter extension section */
AjK 0:0a841b89d614 1462 b <<= 2; continue;
AjK 0:0a841b89d614 1463 }
AjK 0:0a841b89d614 1464
AjK 0:0a841b89d614 1465 if (w >= 0x80) { /* Non ASCII char */
AjK 0:0a841b89d614 1466 #ifdef _EXCVT
AjK 0:0a841b89d614 1467 w = ff_convert(w, 0); /* Unicode -> OEM code */
AjK 0:0a841b89d614 1468 if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
AjK 0:0a841b89d614 1469 #else
AjK 0:0a841b89d614 1470 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
AjK 0:0a841b89d614 1471 #endif
AjK 0:0a841b89d614 1472 cf |= NS_LFN; /* Force create LFN entry */
AjK 0:0a841b89d614 1473 }
AjK 0:0a841b89d614 1474
AjK 0:0a841b89d614 1475 if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */
AjK 0:0a841b89d614 1476 if (i >= ni - 1) {
AjK 0:0a841b89d614 1477 cf |= NS_LOSS | NS_LFN; i = ni; continue;
AjK 0:0a841b89d614 1478 }
AjK 0:0a841b89d614 1479 dj->fn[i++] = (BYTE)(w >> 8);
AjK 0:0a841b89d614 1480 } else { /* Single byte char */
AjK 0:0a841b89d614 1481 if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */
AjK 0:0a841b89d614 1482 w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
AjK 0:0a841b89d614 1483 } else {
AjK 0:0a841b89d614 1484 if (IsUpper(w)) { /* ASCII large capital */
AjK 0:0a841b89d614 1485 b |= 2;
AjK 0:0a841b89d614 1486 } else {
AjK 0:0a841b89d614 1487 if (IsLower(w)) { /* ASCII small capital */
AjK 0:0a841b89d614 1488 b |= 1; w -= 0x20;
AjK 0:0a841b89d614 1489 }
AjK 0:0a841b89d614 1490 }
AjK 0:0a841b89d614 1491 }
AjK 0:0a841b89d614 1492 }
AjK 0:0a841b89d614 1493 dj->fn[i++] = (BYTE)w;
AjK 0:0a841b89d614 1494 }
AjK 0:0a841b89d614 1495
AjK 0:0a841b89d614 1496 if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */
AjK 0:0a841b89d614 1497
AjK 0:0a841b89d614 1498 if (ni == 8) b <<= 2;
AjK 0:0a841b89d614 1499 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
AjK 0:0a841b89d614 1500 cf |= NS_LFN;
AjK 0:0a841b89d614 1501 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
AjK 0:0a841b89d614 1502 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
AjK 0:0a841b89d614 1503 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
AjK 0:0a841b89d614 1504 }
AjK 0:0a841b89d614 1505
AjK 0:0a841b89d614 1506 dj->fn[NS] = cf; /* SFN is created */
AjK 0:0a841b89d614 1507
AjK 0:0a841b89d614 1508 return FR_OK;
AjK 0:0a841b89d614 1509
AjK 0:0a841b89d614 1510
AjK 0:0a841b89d614 1511 #else /* Non-LFN configuration */
AjK 0:0a841b89d614 1512 BYTE b, c, d, *sfn;
AjK 0:0a841b89d614 1513 UINT ni, si, i;
AjK 0:0a841b89d614 1514 const char *p;
AjK 0:0a841b89d614 1515
AjK 0:0a841b89d614 1516 /* Create file name in directory form */
AjK 0:0a841b89d614 1517 sfn = dj->fn;
AjK 0:0a841b89d614 1518 mem_set(sfn, ' ', 11);
AjK 0:0a841b89d614 1519 si = i = b = 0; ni = 8;
AjK 0:0a841b89d614 1520 p = *path;
AjK 0:0a841b89d614 1521 #if _FS_RPATH
AjK 0:0a841b89d614 1522 if (p[si] == '.') { /* Is this a dot entry? */
AjK 0:0a841b89d614 1523 for (;;) {
AjK 0:0a841b89d614 1524 c = (BYTE)p[si++];
AjK 0:0a841b89d614 1525 if (c != '.' || si >= 3) break;
AjK 0:0a841b89d614 1526 sfn[i++] = c;
AjK 0:0a841b89d614 1527 }
AjK 0:0a841b89d614 1528 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
AjK 0:0a841b89d614 1529 *path = &p[si]; /* Return pointer to the next segment */
AjK 0:0a841b89d614 1530 sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
AjK 0:0a841b89d614 1531 return FR_OK;
AjK 0:0a841b89d614 1532 }
AjK 0:0a841b89d614 1533 #endif
AjK 0:0a841b89d614 1534 for (;;) {
AjK 0:0a841b89d614 1535 c = (BYTE)p[si++];
AjK 0:0a841b89d614 1536 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
AjK 0:0a841b89d614 1537 if (c == '.' || i >= ni) {
AjK 0:0a841b89d614 1538 if (ni != 8 || c != '.') return FR_INVALID_NAME;
AjK 0:0a841b89d614 1539 i = 8; ni = 11;
AjK 0:0a841b89d614 1540 b <<= 2; continue;
AjK 0:0a841b89d614 1541 }
AjK 0:0a841b89d614 1542 if (c >= 0x80) { /* Extended char? */
AjK 0:0a841b89d614 1543 b |= 3; /* Eliminate NT flag */
AjK 0:0a841b89d614 1544 #ifdef _EXCVT
AjK 0:0a841b89d614 1545 c = excvt[c-0x80]; /* Upper conversion (SBCS) */
AjK 0:0a841b89d614 1546 #else
AjK 0:0a841b89d614 1547 #if !_DF1S /* ASCII only cfg */
AjK 0:0a841b89d614 1548 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1549 #endif
AjK 0:0a841b89d614 1550 #endif
AjK 0:0a841b89d614 1551 }
AjK 0:0a841b89d614 1552 if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
AjK 0:0a841b89d614 1553 d = (BYTE)p[si++]; /* Get 2nd byte */
AjK 0:0a841b89d614 1554 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
AjK 0:0a841b89d614 1555 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1556 sfn[i++] = c;
AjK 0:0a841b89d614 1557 sfn[i++] = d;
AjK 0:0a841b89d614 1558 } else { /* Single byte code */
AjK 0:0a841b89d614 1559 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
AjK 0:0a841b89d614 1560 return FR_INVALID_NAME;
AjK 0:0a841b89d614 1561 if (IsUpper(c)) { /* ASCII large capital? */
AjK 0:0a841b89d614 1562 b |= 2;
AjK 0:0a841b89d614 1563 } else {
AjK 0:0a841b89d614 1564 if (IsLower(c)) { /* ASCII small capital? */
AjK 0:0a841b89d614 1565 b |= 1; c -= 0x20;
AjK 0:0a841b89d614 1566 }
AjK 0:0a841b89d614 1567 }
AjK 0:0a841b89d614 1568 sfn[i++] = c;
AjK 0:0a841b89d614 1569 }
AjK 0:0a841b89d614 1570 }
AjK 0:0a841b89d614 1571 *path = &p[si]; /* Return pointer to the next segment */
AjK 0:0a841b89d614 1572 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
AjK 0:0a841b89d614 1573
AjK 0:0a841b89d614 1574 if (!i) return FR_INVALID_NAME; /* Reject nul string */
AjK 0:0a841b89d614 1575 if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */
AjK 0:0a841b89d614 1576
AjK 0:0a841b89d614 1577 if (ni == 8) b <<= 2;
AjK 0:0a841b89d614 1578 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
AjK 0:0a841b89d614 1579 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
AjK 0:0a841b89d614 1580
AjK 0:0a841b89d614 1581 sfn[NS] = c; /* Store NT flag, File name is created */
AjK 0:0a841b89d614 1582
AjK 0:0a841b89d614 1583 return FR_OK;
AjK 0:0a841b89d614 1584 #endif
AjK 0:0a841b89d614 1585 }
AjK 0:0a841b89d614 1586
AjK 0:0a841b89d614 1587
AjK 0:0a841b89d614 1588
AjK 0:0a841b89d614 1589
AjK 0:0a841b89d614 1590 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1591 /* Get file information from directory entry */
AjK 0:0a841b89d614 1592 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1593 #if _FS_MINIMIZE <= 1
AjK 0:0a841b89d614 1594 static
AjK 0:0a841b89d614 1595 void get_fileinfo ( /* No return code */
AjK 0:0a841b89d614 1596 DIR *dj, /* Pointer to the directory object */
AjK 0:0a841b89d614 1597 FILINFO *fno /* Pointer to the file information to be filled */
AjK 0:0a841b89d614 1598 )
AjK 0:0a841b89d614 1599 {
AjK 0:0a841b89d614 1600 UINT i;
AjK 0:0a841b89d614 1601 BYTE nt, *dir;
AjK 0:0a841b89d614 1602 TCHAR *p, c;
AjK 0:0a841b89d614 1603
AjK 0:0a841b89d614 1604
AjK 0:0a841b89d614 1605 p = fno->fname;
AjK 0:0a841b89d614 1606 if (dj->sect) {
AjK 0:0a841b89d614 1607 dir = dj->dir;
AjK 0:0a841b89d614 1608 nt = dir[DIR_NTres]; /* NT flag */
AjK 0:0a841b89d614 1609 for (i = 0; i < 8; i++) { /* Copy name body */
AjK 0:0a841b89d614 1610 c = dir[i];
AjK 0:0a841b89d614 1611 if (c == ' ') break;
AjK 0:0a841b89d614 1612 if (c == 0x05) c = (TCHAR)0xE5;
AjK 0:0a841b89d614 1613 if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
AjK 0:0a841b89d614 1614 #if _LFN_UNICODE
AjK 0:0a841b89d614 1615 if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
AjK 0:0a841b89d614 1616 c = (c << 8) | dir[++i];
AjK 0:0a841b89d614 1617 c = ff_convert(c, 1);
AjK 0:0a841b89d614 1618 if (!c) c = '?';
AjK 0:0a841b89d614 1619 #endif
AjK 0:0a841b89d614 1620 *p++ = c;
AjK 0:0a841b89d614 1621 }
AjK 0:0a841b89d614 1622 if (dir[8] != ' ') { /* Copy name extension */
AjK 0:0a841b89d614 1623 *p++ = '.';
AjK 0:0a841b89d614 1624 for (i = 8; i < 11; i++) {
AjK 0:0a841b89d614 1625 c = dir[i];
AjK 0:0a841b89d614 1626 if (c == ' ') break;
AjK 0:0a841b89d614 1627 if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
AjK 0:0a841b89d614 1628 #if _LFN_UNICODE
AjK 0:0a841b89d614 1629 if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
AjK 0:0a841b89d614 1630 c = (c << 8) | dir[++i];
AjK 0:0a841b89d614 1631 c = ff_convert(c, 1);
AjK 0:0a841b89d614 1632 if (!c) c = '?';
AjK 0:0a841b89d614 1633 #endif
AjK 0:0a841b89d614 1634 *p++ = c;
AjK 0:0a841b89d614 1635 }
AjK 0:0a841b89d614 1636 }
AjK 0:0a841b89d614 1637 fno->fattrib = dir[DIR_Attr]; /* Attribute */
AjK 0:0a841b89d614 1638 fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
AjK 0:0a841b89d614 1639 fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
AjK 0:0a841b89d614 1640 fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
AjK 0:0a841b89d614 1641 }
AjK 0:0a841b89d614 1642 *p = 0; /* Terminate SFN str by a \0 */
AjK 0:0a841b89d614 1643
AjK 0:0a841b89d614 1644 #if _USE_LFN
AjK 0:0a841b89d614 1645 if (fno->lfname && fno->lfsize) {
AjK 0:0a841b89d614 1646 TCHAR *tp = fno->lfname;
AjK 0:0a841b89d614 1647 WCHAR w, *lfn;
AjK 0:0a841b89d614 1648
AjK 0:0a841b89d614 1649 i = 0;
AjK 0:0a841b89d614 1650 if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
AjK 0:0a841b89d614 1651 lfn = dj->lfn;
AjK 0:0a841b89d614 1652 while ((w = *lfn++) != 0) { /* Get an LFN char */
AjK 0:0a841b89d614 1653 #if !_LFN_UNICODE
AjK 0:0a841b89d614 1654 w = ff_convert(w, 0); /* Unicode -> OEM conversion */
AjK 0:0a841b89d614 1655 if (!w) { i = 0; break; } /* Could not convert, no LFN */
AjK 0:0a841b89d614 1656 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
AjK 0:0a841b89d614 1657 tp[i++] = (TCHAR)(w >> 8);
AjK 0:0a841b89d614 1658 #endif
AjK 0:0a841b89d614 1659 if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
AjK 0:0a841b89d614 1660 tp[i++] = (TCHAR)w;
AjK 0:0a841b89d614 1661 }
AjK 0:0a841b89d614 1662 }
AjK 0:0a841b89d614 1663 tp[i] = 0; /* Terminate the LFN str by a \0 */
AjK 0:0a841b89d614 1664 }
AjK 0:0a841b89d614 1665 #endif
AjK 0:0a841b89d614 1666 }
AjK 0:0a841b89d614 1667 #endif /* _FS_MINIMIZE <= 1 */
AjK 0:0a841b89d614 1668
AjK 0:0a841b89d614 1669
AjK 0:0a841b89d614 1670
AjK 0:0a841b89d614 1671
AjK 0:0a841b89d614 1672 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1673 /* Follow a file path */
AjK 0:0a841b89d614 1674 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1675
AjK 0:0a841b89d614 1676 static
AjK 0:0a841b89d614 1677 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
AjK 0:0a841b89d614 1678 DIR *dj, /* Directory object to return last directory and found object */
AjK 0:0a841b89d614 1679 const TCHAR *path /* Full-path string to find a file or directory */
AjK 0:0a841b89d614 1680 )
AjK 0:0a841b89d614 1681 {
AjK 0:0a841b89d614 1682 FRESULT res;
AjK 0:0a841b89d614 1683 BYTE *dir, ns;
AjK 0:0a841b89d614 1684
AjK 0:0a841b89d614 1685
AjK 0:0a841b89d614 1686 #if _FS_RPATH
AjK 0:0a841b89d614 1687 if (*path == '/' || *path == '\\') { /* There is a heading separator */
AjK 0:0a841b89d614 1688 path++; dj->sclust = 0; /* Strip it and start from the root dir */
AjK 0:0a841b89d614 1689 } else { /* No heading separator */
AjK 0:0a841b89d614 1690 dj->sclust = dj->fs->cdir; /* Start from the current dir */
AjK 0:0a841b89d614 1691 }
AjK 0:0a841b89d614 1692 #else
AjK 0:0a841b89d614 1693 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
AjK 0:0a841b89d614 1694 path++;
AjK 0:0a841b89d614 1695 dj->sclust = 0; /* Start from the root dir */
AjK 0:0a841b89d614 1696 #endif
AjK 0:0a841b89d614 1697
AjK 0:0a841b89d614 1698 if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
AjK 0:0a841b89d614 1699 res = dir_sdi(dj, 0);
AjK 0:0a841b89d614 1700 dj->dir = 0;
AjK 0:0a841b89d614 1701
AjK 0:0a841b89d614 1702 } else { /* Follow path */
AjK 0:0a841b89d614 1703 for (;;) {
AjK 0:0a841b89d614 1704 res = create_name(dj, &path); /* Get a segment */
AjK 0:0a841b89d614 1705 if (res != FR_OK) break;
AjK 0:0a841b89d614 1706 res = dir_find(dj); /* Find it */
AjK 0:0a841b89d614 1707 ns = *(dj->fn+NS);
AjK 0:0a841b89d614 1708 if (res != FR_OK) { /* Failed to find the object */
AjK 0:0a841b89d614 1709 if (res != FR_NO_FILE) break; /* Abort if any hard error occured */
AjK 0:0a841b89d614 1710 /* Object not found */
AjK 0:0a841b89d614 1711 if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
AjK 0:0a841b89d614 1712 dj->sclust = 0; dj->dir = 0; /* It is the root dir */
AjK 0:0a841b89d614 1713 res = FR_OK;
AjK 0:0a841b89d614 1714 if (!(ns & NS_LAST)) continue;
AjK 0:0a841b89d614 1715 } else { /* Could not find the object */
AjK 0:0a841b89d614 1716 if (!(ns & NS_LAST)) res = FR_NO_PATH;
AjK 0:0a841b89d614 1717 }
AjK 0:0a841b89d614 1718 break;
AjK 0:0a841b89d614 1719 }
AjK 0:0a841b89d614 1720 if (ns & NS_LAST) break; /* Last segment match. Function completed. */
AjK 0:0a841b89d614 1721 dir = dj->dir; /* There is next segment. Follow the sub directory */
AjK 0:0a841b89d614 1722 if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
AjK 0:0a841b89d614 1723 res = FR_NO_PATH; break;
AjK 0:0a841b89d614 1724 }
AjK 0:0a841b89d614 1725 dj->sclust = LD_CLUST(dir);
AjK 0:0a841b89d614 1726 }
AjK 0:0a841b89d614 1727 }
AjK 0:0a841b89d614 1728
AjK 0:0a841b89d614 1729 return res;
AjK 0:0a841b89d614 1730 }
AjK 0:0a841b89d614 1731
AjK 0:0a841b89d614 1732
AjK 0:0a841b89d614 1733
AjK 0:0a841b89d614 1734
AjK 0:0a841b89d614 1735 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1736 /* Load boot record and check if it is an FAT boot record */
AjK 0:0a841b89d614 1737 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1738
AjK 0:0a841b89d614 1739 static
AjK 0:0a841b89d614 1740 BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
AjK 0:0a841b89d614 1741 FATFS *fs, /* File system object */
AjK 0:0a841b89d614 1742 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
AjK 0:0a841b89d614 1743 )
AjK 0:0a841b89d614 1744 {
AjK 0:0a841b89d614 1745 if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
AjK 0:0a841b89d614 1746 return 3;
AjK 0:0a841b89d614 1747 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
AjK 0:0a841b89d614 1748 return 2;
AjK 0:0a841b89d614 1749
AjK 0:0a841b89d614 1750 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
AjK 0:0a841b89d614 1751 return 0;
AjK 0:0a841b89d614 1752 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
AjK 0:0a841b89d614 1753 return 0;
AjK 0:0a841b89d614 1754
AjK 0:0a841b89d614 1755 return 1;
AjK 0:0a841b89d614 1756 }
AjK 0:0a841b89d614 1757
AjK 0:0a841b89d614 1758
AjK 0:0a841b89d614 1759
AjK 0:0a841b89d614 1760
AjK 0:0a841b89d614 1761 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1762 /* Check if the file system object is valid or not */
AjK 0:0a841b89d614 1763 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1764
AjK 0:0a841b89d614 1765 static
AjK 0:0a841b89d614 1766 FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
AjK 0:0a841b89d614 1767 const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
AjK 0:0a841b89d614 1768 FATFS **rfs, /* Pointer to pointer to the found file system object */
AjK 0:0a841b89d614 1769 BYTE chk_wp /* !=0: Check media write protection for write access */
AjK 0:0a841b89d614 1770 )
AjK 0:0a841b89d614 1771 {
AjK 0:0a841b89d614 1772 BYTE fmt, b, *tbl;
AjK 0:0a841b89d614 1773 UINT vol;
AjK 0:0a841b89d614 1774 DSTATUS stat;
AjK 0:0a841b89d614 1775 DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
AjK 0:0a841b89d614 1776 WORD nrsv;
AjK 0:0a841b89d614 1777 const TCHAR *p = *path;
AjK 0:0a841b89d614 1778 FATFS *fs;
AjK 0:0a841b89d614 1779
AjK 0:0a841b89d614 1780 /* Get logical drive number from the path name */
AjK 0:0a841b89d614 1781 vol = p[0] - '0'; /* Is there a drive number? */
AjK 0:0a841b89d614 1782 if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
AjK 0:0a841b89d614 1783 p += 2; *path = p; /* Return pointer to the path name */
AjK 0:0a841b89d614 1784 } else { /* No drive number is given */
AjK 0:0a841b89d614 1785 #if _FS_RPATH
AjK 0:0a841b89d614 1786 vol = CurrVol; /* Use current drive */
AjK 0:0a841b89d614 1787 #else
AjK 0:0a841b89d614 1788 vol = 0; /* Use drive 0 */
AjK 0:0a841b89d614 1789 #endif
AjK 0:0a841b89d614 1790 }
AjK 0:0a841b89d614 1791
AjK 0:0a841b89d614 1792 /* Check if the logical drive is valid or not */
AjK 0:0a841b89d614 1793 if (vol >= _VOLUMES) /* Is the drive number valid? */
AjK 0:0a841b89d614 1794 return FR_INVALID_DRIVE;
AjK 0:0a841b89d614 1795 *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */
AjK 0:0a841b89d614 1796 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
AjK 0:0a841b89d614 1797
AjK 0:0a841b89d614 1798 ENTER_FF(fs); /* Lock file system */
AjK 0:0a841b89d614 1799
AjK 0:0a841b89d614 1800 if (fs->fs_type) { /* If the logical drive has been mounted */
AjK 0:0a841b89d614 1801 stat = disk_status(fs->drv);
AjK 0:0a841b89d614 1802 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
AjK 0:0a841b89d614 1803 #if !_FS_READONLY
AjK 0:0a841b89d614 1804 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
AjK 0:0a841b89d614 1805 return FR_WRITE_PROTECTED;
AjK 0:0a841b89d614 1806 #endif
AjK 0:0a841b89d614 1807 return FR_OK; /* The file system object is valid */
AjK 0:0a841b89d614 1808 }
AjK 0:0a841b89d614 1809 }
AjK 0:0a841b89d614 1810
AjK 0:0a841b89d614 1811 /* The logical drive must be mounted. */
AjK 0:0a841b89d614 1812 /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */
AjK 0:0a841b89d614 1813
AjK 0:0a841b89d614 1814 fs->fs_type = 0; /* Clear the file system object */
AjK 0:0a841b89d614 1815 fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
AjK 0:0a841b89d614 1816 stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
AjK 0:0a841b89d614 1817 if (stat & STA_NOINIT) /* Check if the initialization succeeded */
AjK 0:0a841b89d614 1818 return FR_NOT_READY; /* Failed to initialize due to no media or hard error */
AjK 0:0a841b89d614 1819 #if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
AjK 0:0a841b89d614 1820 if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
AjK 0:0a841b89d614 1821 return FR_DISK_ERR;
AjK 0:0a841b89d614 1822 #endif
AjK 0:0a841b89d614 1823 #if !_FS_READONLY
AjK 0:0a841b89d614 1824 if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
AjK 0:0a841b89d614 1825 return FR_WRITE_PROTECTED;
AjK 0:0a841b89d614 1826 #endif
AjK 0:0a841b89d614 1827 /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
AjK 0:0a841b89d614 1828 fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
AjK 0:0a841b89d614 1829 if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */
AjK 0:0a841b89d614 1830 /* Check the partition listed in top of the partition table */
AjK 0:0a841b89d614 1831 tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
AjK 0:0a841b89d614 1832 if (tbl[4]) { /* Is the partition existing? */
AjK 0:0a841b89d614 1833 bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
AjK 0:0a841b89d614 1834 fmt = check_fs(fs, bsect); /* Check the partition */
AjK 0:0a841b89d614 1835 }
AjK 0:0a841b89d614 1836 }
AjK 0:0a841b89d614 1837 if (fmt == 3) return FR_DISK_ERR;
AjK 0:0a841b89d614 1838 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
AjK 0:0a841b89d614 1839
AjK 0:0a841b89d614 1840 /* Following code initializes the file system object */
AjK 0:0a841b89d614 1841
AjK 0:0a841b89d614 1842 if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
AjK 0:0a841b89d614 1843 return FR_NO_FILESYSTEM;
AjK 0:0a841b89d614 1844
AjK 0:0a841b89d614 1845 fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
AjK 0:0a841b89d614 1846 if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
AjK 0:0a841b89d614 1847 fs->fsize = fasize;
AjK 0:0a841b89d614 1848
AjK 0:0a841b89d614 1849 fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
AjK 0:0a841b89d614 1850 if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
AjK 0:0a841b89d614 1851 fasize *= b; /* Number of sectors for FAT area */
AjK 0:0a841b89d614 1852
AjK 0:0a841b89d614 1853 fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
AjK 0:0a841b89d614 1854 if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
AjK 0:0a841b89d614 1855
AjK 0:0a841b89d614 1856 fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
AjK 0:0a841b89d614 1857 if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
AjK 0:0a841b89d614 1858
AjK 0:0a841b89d614 1859 tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
AjK 0:0a841b89d614 1860 if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
AjK 0:0a841b89d614 1861
AjK 0:0a841b89d614 1862 nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
AjK 0:0a841b89d614 1863 if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
AjK 0:0a841b89d614 1864
AjK 0:0a841b89d614 1865 /* Determine the FAT sub type */
AjK 0:0a841b89d614 1866 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */
AjK 0:0a841b89d614 1867 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
AjK 0:0a841b89d614 1868 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
AjK 0:0a841b89d614 1869 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
AjK 0:0a841b89d614 1870 fmt = FS_FAT12;
AjK 0:0a841b89d614 1871 if (nclst >= MIN_FAT16) fmt = FS_FAT16;
AjK 0:0a841b89d614 1872 if (nclst >= MIN_FAT32) fmt = FS_FAT32;
AjK 0:0a841b89d614 1873
AjK 0:0a841b89d614 1874 /* Boundaries and Limits */
AjK 0:0a841b89d614 1875 fs->n_fatent = nclst + 2; /* Number of FAT entries */
AjK 0:0a841b89d614 1876 fs->database = bsect + sysect; /* Data start sector */
AjK 0:0a841b89d614 1877 fs->fatbase = bsect + nrsv; /* FAT start sector */
AjK 0:0a841b89d614 1878 if (fmt == FS_FAT32) {
AjK 0:0a841b89d614 1879 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
AjK 0:0a841b89d614 1880 fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
AjK 0:0a841b89d614 1881 szbfat = fs->n_fatent * 4; /* (Required FAT size) */
AjK 0:0a841b89d614 1882 } else {
AjK 0:0a841b89d614 1883 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
AjK 0:0a841b89d614 1884 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
AjK 0:0a841b89d614 1885 szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
AjK 0:0a841b89d614 1886 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
AjK 0:0a841b89d614 1887 }
AjK 0:0a841b89d614 1888 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */
AjK 0:0a841b89d614 1889 return FR_NO_FILESYSTEM;
AjK 0:0a841b89d614 1890
AjK 0:0a841b89d614 1891 #if !_FS_READONLY
AjK 0:0a841b89d614 1892 /* Initialize cluster allocation information */
AjK 0:0a841b89d614 1893 fs->free_clust = 0xFFFFFFFF;
AjK 0:0a841b89d614 1894 fs->last_clust = 0;
AjK 0:0a841b89d614 1895
AjK 0:0a841b89d614 1896 /* Get fsinfo if available */
AjK 0:0a841b89d614 1897 if (fmt == FS_FAT32) {
AjK 0:0a841b89d614 1898 fs->fsi_flag = 0;
AjK 0:0a841b89d614 1899 fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
AjK 0:0a841b89d614 1900 if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
AjK 0:0a841b89d614 1901 LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
AjK 0:0a841b89d614 1902 LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
AjK 0:0a841b89d614 1903 LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
AjK 0:0a841b89d614 1904 fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
AjK 0:0a841b89d614 1905 fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
AjK 0:0a841b89d614 1906 }
AjK 0:0a841b89d614 1907 }
AjK 0:0a841b89d614 1908 #endif
AjK 0:0a841b89d614 1909 fs->fs_type = fmt; /* FAT sub-type */
AjK 0:0a841b89d614 1910 fs->id = ++Fsid; /* File system mount ID */
AjK 0:0a841b89d614 1911 fs->winsect = 0; /* Invalidate sector cache */
AjK 0:0a841b89d614 1912 fs->wflag = 0;
AjK 0:0a841b89d614 1913 #if _FS_RPATH
AjK 0:0a841b89d614 1914 fs->cdir = 0; /* Current directory (root dir) */
AjK 0:0a841b89d614 1915 #endif
AjK 0:0a841b89d614 1916 #if _FS_SHARE /* Clear file lock semaphores */
AjK 0:0a841b89d614 1917 clear_lock(fs);
AjK 0:0a841b89d614 1918 #endif
AjK 0:0a841b89d614 1919
AjK 0:0a841b89d614 1920 return FR_OK;
AjK 0:0a841b89d614 1921 }
AjK 0:0a841b89d614 1922
AjK 0:0a841b89d614 1923
AjK 0:0a841b89d614 1924
AjK 0:0a841b89d614 1925
AjK 0:0a841b89d614 1926 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1927 /* Check if the file/dir object is valid or not */
AjK 0:0a841b89d614 1928 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1929
AjK 0:0a841b89d614 1930 static
AjK 0:0a841b89d614 1931 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
AjK 0:0a841b89d614 1932 FATFS *fs, /* Pointer to the file system object */
AjK 0:0a841b89d614 1933 WORD id /* Member id of the target object to be checked */
AjK 0:0a841b89d614 1934 )
AjK 0:0a841b89d614 1935 {
AjK 0:0a841b89d614 1936 if (!fs || !fs->fs_type || fs->id != id)
AjK 0:0a841b89d614 1937 return FR_INVALID_OBJECT;
AjK 0:0a841b89d614 1938
AjK 0:0a841b89d614 1939 ENTER_FF(fs); /* Lock file system */
AjK 0:0a841b89d614 1940
AjK 0:0a841b89d614 1941 if (disk_status(fs->drv) & STA_NOINIT)
AjK 0:0a841b89d614 1942 return FR_NOT_READY;
AjK 0:0a841b89d614 1943
AjK 0:0a841b89d614 1944 return FR_OK;
AjK 0:0a841b89d614 1945 }
AjK 0:0a841b89d614 1946
AjK 0:0a841b89d614 1947
AjK 0:0a841b89d614 1948
AjK 0:0a841b89d614 1949
AjK 0:0a841b89d614 1950 /*--------------------------------------------------------------------------
AjK 0:0a841b89d614 1951
AjK 0:0a841b89d614 1952 Public Functions
AjK 0:0a841b89d614 1953
AjK 0:0a841b89d614 1954 --------------------------------------------------------------------------*/
AjK 0:0a841b89d614 1955
AjK 0:0a841b89d614 1956
AjK 0:0a841b89d614 1957
AjK 0:0a841b89d614 1958 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1959 /* Mount/Unmount a Logical Drive */
AjK 0:0a841b89d614 1960 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1961
AjK 0:0a841b89d614 1962 FRESULT f_mount (
AjK 0:0a841b89d614 1963 BYTE vol, /* Logical drive number to be mounted/unmounted */
AjK 0:0a841b89d614 1964 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
AjK 0:0a841b89d614 1965 )
AjK 0:0a841b89d614 1966 {
AjK 0:0a841b89d614 1967 FATFS *rfs;
AjK 0:0a841b89d614 1968
AjK 0:0a841b89d614 1969
AjK 0:0a841b89d614 1970 if (vol >= _VOLUMES) /* Check if the drive number is valid */
AjK 0:0a841b89d614 1971 return FR_INVALID_DRIVE;
AjK 0:0a841b89d614 1972 rfs = FatFs[vol]; /* Get current fs object */
AjK 0:0a841b89d614 1973
AjK 0:0a841b89d614 1974 if (rfs) {
AjK 0:0a841b89d614 1975 #if _FS_SHARE
AjK 0:0a841b89d614 1976 clear_lock(rfs);
AjK 0:0a841b89d614 1977 #endif
AjK 0:0a841b89d614 1978 #if _FS_REENTRANT /* Discard sync object of the current volume */
AjK 0:0a841b89d614 1979 if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
AjK 0:0a841b89d614 1980 #endif
AjK 0:0a841b89d614 1981 rfs->fs_type = 0; /* Clear old fs object */
AjK 0:0a841b89d614 1982 }
AjK 0:0a841b89d614 1983
AjK 0:0a841b89d614 1984 if (fs) {
AjK 0:0a841b89d614 1985 fs->fs_type = 0; /* Clear new fs object */
AjK 0:0a841b89d614 1986 #if _FS_REENTRANT /* Create sync object for the new volume */
AjK 0:0a841b89d614 1987 if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
AjK 0:0a841b89d614 1988 #endif
AjK 0:0a841b89d614 1989 }
AjK 0:0a841b89d614 1990 FatFs[vol] = fs; /* Register new fs object */
AjK 0:0a841b89d614 1991
AjK 0:0a841b89d614 1992 return FR_OK;
AjK 0:0a841b89d614 1993 }
AjK 0:0a841b89d614 1994
AjK 0:0a841b89d614 1995
AjK 0:0a841b89d614 1996
AjK 0:0a841b89d614 1997
AjK 0:0a841b89d614 1998 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 1999 /* Open or Create a File */
AjK 0:0a841b89d614 2000 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2001
AjK 0:0a841b89d614 2002 FRESULT f_open (
AjK 0:0a841b89d614 2003 FIL *fp, /* Pointer to the blank file object */
AjK 0:0a841b89d614 2004 const TCHAR *path, /* Pointer to the file name */
AjK 0:0a841b89d614 2005 BYTE mode /* Access mode and file open mode flags */
AjK 0:0a841b89d614 2006 )
AjK 0:0a841b89d614 2007 {
AjK 0:0a841b89d614 2008 FRESULT res;
AjK 0:0a841b89d614 2009 DIR dj;
AjK 0:0a841b89d614 2010 BYTE *dir;
AjK 0:0a841b89d614 2011 DEF_NAMEBUF;
AjK 0:0a841b89d614 2012
AjK 0:0a841b89d614 2013
AjK 0:0a841b89d614 2014 fp->fs = 0; /* Clear file object */
AjK 0:0a841b89d614 2015
AjK 0:0a841b89d614 2016 #if !_FS_READONLY
AjK 0:0a841b89d614 2017 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
AjK 0:0a841b89d614 2018 res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
AjK 0:0a841b89d614 2019 #else
AjK 0:0a841b89d614 2020 mode &= FA_READ;
AjK 0:0a841b89d614 2021 res = chk_mounted(&path, &dj.fs, 0);
AjK 0:0a841b89d614 2022 #endif
AjK 0:0a841b89d614 2023 INIT_BUF(dj);
AjK 0:0a841b89d614 2024 if (res == FR_OK)
AjK 0:0a841b89d614 2025 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 2026 dir = dj.dir;
AjK 0:0a841b89d614 2027
AjK 0:0a841b89d614 2028 #if !_FS_READONLY /* R/W configuration */
AjK 0:0a841b89d614 2029 if (res == FR_OK) {
AjK 0:0a841b89d614 2030 if (!dir) /* Current dir itself */
AjK 0:0a841b89d614 2031 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 2032 #if _FS_SHARE
AjK 0:0a841b89d614 2033 else
AjK 0:0a841b89d614 2034 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
AjK 0:0a841b89d614 2035 #endif
AjK 0:0a841b89d614 2036 }
AjK 0:0a841b89d614 2037 /* Create or Open a file */
AjK 0:0a841b89d614 2038 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
AjK 0:0a841b89d614 2039 DWORD dw, cl;
AjK 0:0a841b89d614 2040
AjK 0:0a841b89d614 2041 if (res != FR_OK) { /* No file, create new */
AjK 0:0a841b89d614 2042 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
AjK 0:0a841b89d614 2043 #if _FS_SHARE
AjK 0:0a841b89d614 2044 res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
AjK 0:0a841b89d614 2045 #else
AjK 0:0a841b89d614 2046 res = dir_register(&dj);
AjK 0:0a841b89d614 2047 #endif
AjK 0:0a841b89d614 2048 mode |= FA_CREATE_ALWAYS; /* File is created */
AjK 0:0a841b89d614 2049 dir = dj.dir; /* New entry */
AjK 0:0a841b89d614 2050 }
AjK 0:0a841b89d614 2051 else { /* Any object is already existing */
AjK 0:0a841b89d614 2052 if (mode & FA_CREATE_NEW) { /* Cannot create new */
AjK 0:0a841b89d614 2053 res = FR_EXIST;
AjK 0:0a841b89d614 2054 } else {
AjK 0:0a841b89d614 2055 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */
AjK 0:0a841b89d614 2056 res = FR_DENIED;
AjK 0:0a841b89d614 2057 }
AjK 0:0a841b89d614 2058 }
AjK 0:0a841b89d614 2059 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
AjK 0:0a841b89d614 2060 dw = get_fattime(); /* Created time */
AjK 0:0a841b89d614 2061 ST_DWORD(dir+DIR_CrtTime, dw);
AjK 0:0a841b89d614 2062 dir[DIR_Attr] = 0; /* Reset attribute */
AjK 0:0a841b89d614 2063 ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
AjK 0:0a841b89d614 2064 cl = LD_CLUST(dir); /* Get start cluster */
AjK 0:0a841b89d614 2065 ST_CLUST(dir, 0); /* cluster = 0 */
AjK 0:0a841b89d614 2066 dj.fs->wflag = 1;
AjK 0:0a841b89d614 2067 if (cl) { /* Remove the cluster chain if exist */
AjK 0:0a841b89d614 2068 dw = dj.fs->winsect;
AjK 0:0a841b89d614 2069 res = remove_chain(dj.fs, cl);
AjK 0:0a841b89d614 2070 if (res == FR_OK) {
AjK 0:0a841b89d614 2071 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
AjK 0:0a841b89d614 2072 res = move_window(dj.fs, dw);
AjK 0:0a841b89d614 2073 }
AjK 0:0a841b89d614 2074 }
AjK 0:0a841b89d614 2075 }
AjK 0:0a841b89d614 2076 }
AjK 0:0a841b89d614 2077 else { /* Open an existing file */
AjK 0:0a841b89d614 2078 if (res == FR_OK) { /* Follow succeeded */
AjK 0:0a841b89d614 2079 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
AjK 0:0a841b89d614 2080 res = FR_NO_FILE;
AjK 0:0a841b89d614 2081 } else {
AjK 0:0a841b89d614 2082 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
AjK 0:0a841b89d614 2083 res = FR_DENIED;
AjK 0:0a841b89d614 2084 }
AjK 0:0a841b89d614 2085 }
AjK 0:0a841b89d614 2086 }
AjK 0:0a841b89d614 2087 if (res == FR_OK) {
AjK 0:0a841b89d614 2088 if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
AjK 0:0a841b89d614 2089 mode |= FA__WRITTEN;
AjK 0:0a841b89d614 2090 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
AjK 0:0a841b89d614 2091 fp->dir_ptr = dir;
AjK 0:0a841b89d614 2092 #if _FS_SHARE
AjK 0:0a841b89d614 2093 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
AjK 0:0a841b89d614 2094 if (!fp->lockid) res = FR_INT_ERR;
AjK 0:0a841b89d614 2095 #endif
AjK 0:0a841b89d614 2096 }
AjK 0:0a841b89d614 2097
AjK 0:0a841b89d614 2098 #else /* R/O configuration */
AjK 0:0a841b89d614 2099 if (res == FR_OK) { /* Follow succeeded */
AjK 0:0a841b89d614 2100 if (!dir) { /* Current dir itself */
AjK 0:0a841b89d614 2101 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 2102 } else {
AjK 0:0a841b89d614 2103 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
AjK 0:0a841b89d614 2104 res = FR_NO_FILE;
AjK 0:0a841b89d614 2105 }
AjK 0:0a841b89d614 2106 }
AjK 0:0a841b89d614 2107 #endif
AjK 0:0a841b89d614 2108 FREE_BUF();
AjK 0:0a841b89d614 2109
AjK 0:0a841b89d614 2110 if (res == FR_OK) {
AjK 0:0a841b89d614 2111 fp->flag = mode; /* File access mode */
AjK 0:0a841b89d614 2112 fp->org_clust = LD_CLUST(dir); /* File start cluster */
AjK 0:0a841b89d614 2113 fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
AjK 0:0a841b89d614 2114 fp->fptr = 0; /* File pointer */
AjK 0:0a841b89d614 2115 fp->dsect = 0;
AjK 0:0a841b89d614 2116 #if _USE_FASTSEEK
AjK 0:0a841b89d614 2117 fp->cltbl = 0; /* No cluster link map table */
AjK 0:0a841b89d614 2118 #endif
AjK 0:0a841b89d614 2119 fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
AjK 0:0a841b89d614 2120 }
AjK 0:0a841b89d614 2121
AjK 0:0a841b89d614 2122 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 2123 }
AjK 0:0a841b89d614 2124
AjK 0:0a841b89d614 2125
AjK 0:0a841b89d614 2126
AjK 0:0a841b89d614 2127
AjK 0:0a841b89d614 2128 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2129 /* Read File */
AjK 0:0a841b89d614 2130 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2131
AjK 0:0a841b89d614 2132 FRESULT f_read (
AjK 0:0a841b89d614 2133 FIL *fp, /* Pointer to the file object */
AjK 0:0a841b89d614 2134 void *buff, /* Pointer to data buffer */
AjK 0:0a841b89d614 2135 UINT btr, /* Number of bytes to read */
AjK 0:0a841b89d614 2136 UINT *br /* Pointer to number of bytes read */
AjK 0:0a841b89d614 2137 )
AjK 0:0a841b89d614 2138 {
AjK 0:0a841b89d614 2139 FRESULT res;
AjK 0:0a841b89d614 2140 DWORD clst, sect, remain;
AjK 0:0a841b89d614 2141 UINT rcnt, cc;
AjK 0:0a841b89d614 2142 BYTE csect, *rbuff = (BYTE *)buff;
AjK 0:0a841b89d614 2143
AjK 0:0a841b89d614 2144
AjK 0:0a841b89d614 2145 *br = 0; /* Initialize byte counter */
AjK 0:0a841b89d614 2146
AjK 0:0a841b89d614 2147 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 2148 if (res != FR_OK) LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2149 if (fp->flag & FA__ERROR) /* Check abort flag */
AjK 0:0a841b89d614 2150 LEAVE_FF(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2151 if (!(fp->flag & FA_READ)) /* Check access mode */
AjK 0:0a841b89d614 2152 LEAVE_FF(fp->fs, FR_DENIED);
AjK 0:0a841b89d614 2153 remain = fp->fsize - fp->fptr;
AjK 0:0a841b89d614 2154 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
AjK 0:0a841b89d614 2155
AjK 0:0a841b89d614 2156 for ( ; btr; /* Repeat until all data transferred */
AjK 0:0a841b89d614 2157 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
AjK 0:0a841b89d614 2158 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
AjK 0:0a841b89d614 2159 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
AjK 0:0a841b89d614 2160 if (!csect) { /* On the cluster boundary? */
AjK 0:0a841b89d614 2161 clst = (fp->fptr == 0) ? /* On the top of the file? */
AjK 0:0a841b89d614 2162 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
AjK 0:0a841b89d614 2163 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2164 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2165 fp->curr_clust = clst; /* Update current cluster */
AjK 0:0a841b89d614 2166 }
AjK 0:0a841b89d614 2167 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
AjK 0:0a841b89d614 2168 if (!sect) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2169 sect += csect;
AjK 0:0a841b89d614 2170 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
AjK 0:0a841b89d614 2171 if (cc) { /* Read maximum contiguous sectors directly */
AjK 0:0a841b89d614 2172 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
AjK 0:0a841b89d614 2173 cc = fp->fs->csize - csect;
AjK 0:0a841b89d614 2174 if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
AjK 0:0a841b89d614 2175 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2176 #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
AjK 0:0a841b89d614 2177 #if _FS_TINY
AjK 0:0a841b89d614 2178 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
AjK 0:0a841b89d614 2179 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
AjK 0:0a841b89d614 2180 #else
AjK 0:0a841b89d614 2181 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
AjK 0:0a841b89d614 2182 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
AjK 0:0a841b89d614 2183 #endif
AjK 0:0a841b89d614 2184 #endif
AjK 0:0a841b89d614 2185 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
AjK 0:0a841b89d614 2186 continue;
AjK 0:0a841b89d614 2187 }
AjK 0:0a841b89d614 2188 #if !_FS_TINY
AjK 0:0a841b89d614 2189 #if !_FS_READONLY
AjK 0:0a841b89d614 2190 if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */
AjK 0:0a841b89d614 2191 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
AjK 0:0a841b89d614 2192 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2193 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2194 }
AjK 0:0a841b89d614 2195 #endif
AjK 0:0a841b89d614 2196 if (fp->dsect != sect) { /* Fill sector buffer with file data */
AjK 0:0a841b89d614 2197 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
AjK 0:0a841b89d614 2198 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2199 }
AjK 0:0a841b89d614 2200 #endif
AjK 0:0a841b89d614 2201 fp->dsect = sect;
AjK 0:0a841b89d614 2202 }
AjK 0:0a841b89d614 2203 rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
AjK 0:0a841b89d614 2204 if (rcnt > btr) rcnt = btr;
AjK 0:0a841b89d614 2205 #if _FS_TINY
AjK 0:0a841b89d614 2206 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
AjK 0:0a841b89d614 2207 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2208 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
AjK 0:0a841b89d614 2209 #else
AjK 0:0a841b89d614 2210 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
AjK 0:0a841b89d614 2211 #endif
AjK 0:0a841b89d614 2212 }
AjK 0:0a841b89d614 2213
AjK 0:0a841b89d614 2214 LEAVE_FF(fp->fs, FR_OK);
AjK 0:0a841b89d614 2215 }
AjK 0:0a841b89d614 2216
AjK 0:0a841b89d614 2217
AjK 0:0a841b89d614 2218
AjK 0:0a841b89d614 2219
AjK 0:0a841b89d614 2220 #if !_FS_READONLY
AjK 0:0a841b89d614 2221 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2222 /* Write File */
AjK 0:0a841b89d614 2223 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2224
AjK 0:0a841b89d614 2225 FRESULT f_write (
AjK 0:0a841b89d614 2226 FIL *fp, /* Pointer to the file object */
AjK 0:0a841b89d614 2227 const void *buff, /* Pointer to the data to be written */
AjK 0:0a841b89d614 2228 UINT btw, /* Number of bytes to write */
AjK 0:0a841b89d614 2229 UINT *bw /* Pointer to number of bytes written */
AjK 0:0a841b89d614 2230 )
AjK 0:0a841b89d614 2231 {
AjK 0:0a841b89d614 2232 FRESULT res;
AjK 0:0a841b89d614 2233 DWORD clst, sect;
AjK 0:0a841b89d614 2234 UINT wcnt, cc;
AjK 0:0a841b89d614 2235 const BYTE *wbuff = (const BYTE *)buff;
AjK 0:0a841b89d614 2236 BYTE csect;
AjK 0:0a841b89d614 2237
AjK 0:0a841b89d614 2238
AjK 0:0a841b89d614 2239 *bw = 0; /* Initialize byte counter */
AjK 0:0a841b89d614 2240
AjK 0:0a841b89d614 2241 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 2242 if (res != FR_OK) LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2243 if (fp->flag & FA__ERROR) /* Check abort flag */
AjK 0:0a841b89d614 2244 LEAVE_FF(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2245 if (!(fp->flag & FA_WRITE)) /* Check access mode */
AjK 0:0a841b89d614 2246 LEAVE_FF(fp->fs, FR_DENIED);
AjK 0:0a841b89d614 2247 if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */
AjK 0:0a841b89d614 2248
AjK 0:0a841b89d614 2249 for ( ; btw; /* Repeat until all data transferred */
AjK 0:0a841b89d614 2250 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
AjK 0:0a841b89d614 2251 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
AjK 0:0a841b89d614 2252 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
AjK 0:0a841b89d614 2253 if (!csect) { /* On the cluster boundary? */
AjK 0:0a841b89d614 2254 if (fp->fptr == 0) { /* On the top of the file? */
AjK 0:0a841b89d614 2255 clst = fp->org_clust; /* Follow from the origin */
AjK 0:0a841b89d614 2256 if (clst == 0) /* When there is no cluster chain, */
AjK 0:0a841b89d614 2257 fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
AjK 0:0a841b89d614 2258 } else { /* Middle or end of the file */
AjK 0:0a841b89d614 2259 clst = create_chain(fp->fs, fp->curr_clust); /* Follow or stretch cluster chain */
AjK 0:0a841b89d614 2260 }
AjK 0:0a841b89d614 2261 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
AjK 0:0a841b89d614 2262 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2263 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2264 fp->curr_clust = clst; /* Update current cluster */
AjK 0:0a841b89d614 2265 }
AjK 0:0a841b89d614 2266 #if _FS_TINY
AjK 0:0a841b89d614 2267 if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */
AjK 0:0a841b89d614 2268 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2269 #else
AjK 0:0a841b89d614 2270 if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */
AjK 0:0a841b89d614 2271 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
AjK 0:0a841b89d614 2272 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2273 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2274 }
AjK 0:0a841b89d614 2275 #endif
AjK 0:0a841b89d614 2276 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
AjK 0:0a841b89d614 2277 if (!sect) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2278 sect += csect;
AjK 0:0a841b89d614 2279 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
AjK 0:0a841b89d614 2280 if (cc) { /* Write maximum contiguous sectors directly */
AjK 0:0a841b89d614 2281 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
AjK 0:0a841b89d614 2282 cc = fp->fs->csize - csect;
AjK 0:0a841b89d614 2283 if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
AjK 0:0a841b89d614 2284 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2285 #if _FS_TINY
AjK 0:0a841b89d614 2286 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
AjK 0:0a841b89d614 2287 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
AjK 0:0a841b89d614 2288 fp->fs->wflag = 0;
AjK 0:0a841b89d614 2289 }
AjK 0:0a841b89d614 2290 #else
AjK 0:0a841b89d614 2291 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
AjK 0:0a841b89d614 2292 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
AjK 0:0a841b89d614 2293 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2294 }
AjK 0:0a841b89d614 2295 #endif
AjK 0:0a841b89d614 2296 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
AjK 0:0a841b89d614 2297 continue;
AjK 0:0a841b89d614 2298 }
AjK 0:0a841b89d614 2299 #if _FS_TINY
AjK 0:0a841b89d614 2300 if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */
AjK 0:0a841b89d614 2301 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2302 fp->fs->winsect = sect;
AjK 0:0a841b89d614 2303 }
AjK 0:0a841b89d614 2304 #else
AjK 0:0a841b89d614 2305 if (fp->dsect != sect) { /* Fill sector buffer with file data */
AjK 0:0a841b89d614 2306 if (fp->fptr < fp->fsize &&
AjK 0:0a841b89d614 2307 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
AjK 0:0a841b89d614 2308 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2309 }
AjK 0:0a841b89d614 2310 #endif
AjK 0:0a841b89d614 2311 fp->dsect = sect;
AjK 0:0a841b89d614 2312 }
AjK 0:0a841b89d614 2313 wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
AjK 0:0a841b89d614 2314 if (wcnt > btw) wcnt = btw;
AjK 0:0a841b89d614 2315 #if _FS_TINY
AjK 0:0a841b89d614 2316 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
AjK 0:0a841b89d614 2317 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2318 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
AjK 0:0a841b89d614 2319 fp->fs->wflag = 1;
AjK 0:0a841b89d614 2320 #else
AjK 0:0a841b89d614 2321 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
AjK 0:0a841b89d614 2322 fp->flag |= FA__DIRTY;
AjK 0:0a841b89d614 2323 #endif
AjK 0:0a841b89d614 2324 }
AjK 0:0a841b89d614 2325
AjK 0:0a841b89d614 2326 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
AjK 0:0a841b89d614 2327 fp->flag |= FA__WRITTEN; /* Set file change flag */
AjK 0:0a841b89d614 2328
AjK 0:0a841b89d614 2329 LEAVE_FF(fp->fs, FR_OK);
AjK 0:0a841b89d614 2330 }
AjK 0:0a841b89d614 2331
AjK 0:0a841b89d614 2332
AjK 0:0a841b89d614 2333
AjK 0:0a841b89d614 2334
AjK 0:0a841b89d614 2335 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2336 /* Synchronize the File Object */
AjK 0:0a841b89d614 2337 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2338
AjK 0:0a841b89d614 2339 FRESULT f_sync (
AjK 0:0a841b89d614 2340 FIL *fp /* Pointer to the file object */
AjK 0:0a841b89d614 2341 )
AjK 0:0a841b89d614 2342 {
AjK 0:0a841b89d614 2343 FRESULT res;
AjK 0:0a841b89d614 2344 DWORD tim;
AjK 0:0a841b89d614 2345 BYTE *dir;
AjK 0:0a841b89d614 2346
AjK 0:0a841b89d614 2347
AjK 0:0a841b89d614 2348 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 2349 if (res == FR_OK) {
AjK 0:0a841b89d614 2350 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
AjK 0:0a841b89d614 2351 #if !_FS_TINY /* Write-back dirty buffer */
AjK 0:0a841b89d614 2352 if (fp->flag & FA__DIRTY) {
AjK 0:0a841b89d614 2353 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
AjK 0:0a841b89d614 2354 LEAVE_FF(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2355 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2356 }
AjK 0:0a841b89d614 2357 #endif
AjK 0:0a841b89d614 2358 /* Update the directory entry */
AjK 0:0a841b89d614 2359 res = move_window(fp->fs, fp->dir_sect);
AjK 0:0a841b89d614 2360 if (res == FR_OK) {
AjK 0:0a841b89d614 2361 dir = fp->dir_ptr;
AjK 0:0a841b89d614 2362 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
AjK 0:0a841b89d614 2363 ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
AjK 0:0a841b89d614 2364 ST_CLUST(dir, fp->org_clust); /* Update start cluster */
AjK 0:0a841b89d614 2365 tim = get_fattime(); /* Update updated time */
AjK 0:0a841b89d614 2366 ST_DWORD(dir+DIR_WrtTime, tim);
AjK 0:0a841b89d614 2367 fp->flag &= ~FA__WRITTEN;
AjK 0:0a841b89d614 2368 fp->fs->wflag = 1;
AjK 0:0a841b89d614 2369 res = sync(fp->fs);
AjK 0:0a841b89d614 2370 }
AjK 0:0a841b89d614 2371 }
AjK 0:0a841b89d614 2372 }
AjK 0:0a841b89d614 2373
AjK 0:0a841b89d614 2374 LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2375 }
AjK 0:0a841b89d614 2376
AjK 0:0a841b89d614 2377 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 2378
AjK 0:0a841b89d614 2379
AjK 0:0a841b89d614 2380
AjK 0:0a841b89d614 2381
AjK 0:0a841b89d614 2382 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2383 /* Close File */
AjK 0:0a841b89d614 2384 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2385
AjK 0:0a841b89d614 2386 FRESULT f_close (
AjK 0:0a841b89d614 2387 FIL *fp /* Pointer to the file object to be closed */
AjK 0:0a841b89d614 2388 )
AjK 0:0a841b89d614 2389 {
AjK 0:0a841b89d614 2390 FRESULT res;
AjK 0:0a841b89d614 2391
AjK 0:0a841b89d614 2392 #if _FS_READONLY
AjK 0:0a841b89d614 2393 FATFS *fs = fp->fs;
AjK 0:0a841b89d614 2394 res = validate(fs, fp->id);
AjK 0:0a841b89d614 2395 if (res == FR_OK) fp->fs = 0; /* Discard file object */
AjK 0:0a841b89d614 2396 LEAVE_FF(fs, res);
AjK 0:0a841b89d614 2397
AjK 0:0a841b89d614 2398 #else
AjK 0:0a841b89d614 2399 res = f_sync(fp); /* Flush cached data */
AjK 0:0a841b89d614 2400 #if _FS_SHARE
AjK 0:0a841b89d614 2401 if (res == FR_OK) { /* Decrement open counter */
AjK 0:0a841b89d614 2402 #if _FS_REENTRANT
AjK 0:0a841b89d614 2403 res = validate(fp->fs, fp->id);
AjK 0:0a841b89d614 2404 if (res == FR_OK) {
AjK 0:0a841b89d614 2405 res = dec_lock(fp->lockid);
AjK 0:0a841b89d614 2406 unlock_fs(fp->fs, FR_OK);
AjK 0:0a841b89d614 2407 }
AjK 0:0a841b89d614 2408 #else
AjK 0:0a841b89d614 2409 res = dec_lock(fp->lockid);
AjK 0:0a841b89d614 2410 #endif
AjK 0:0a841b89d614 2411 }
AjK 0:0a841b89d614 2412 #endif
AjK 0:0a841b89d614 2413 if (res == FR_OK) fp->fs = 0; /* Discard file object */
AjK 0:0a841b89d614 2414 return res;
AjK 0:0a841b89d614 2415 #endif
AjK 0:0a841b89d614 2416 }
AjK 0:0a841b89d614 2417
AjK 0:0a841b89d614 2418
AjK 0:0a841b89d614 2419
AjK 0:0a841b89d614 2420
AjK 0:0a841b89d614 2421 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2422 /* Current Drive/Directory Handlings */
AjK 0:0a841b89d614 2423 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2424
AjK 0:0a841b89d614 2425 #if _FS_RPATH >= 1
AjK 0:0a841b89d614 2426
AjK 0:0a841b89d614 2427 FRESULT f_chdrive (
AjK 0:0a841b89d614 2428 BYTE drv /* Drive number */
AjK 0:0a841b89d614 2429 )
AjK 0:0a841b89d614 2430 {
AjK 0:0a841b89d614 2431 if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
AjK 0:0a841b89d614 2432
AjK 0:0a841b89d614 2433 CurrVol = drv;
AjK 0:0a841b89d614 2434
AjK 0:0a841b89d614 2435 return FR_OK;
AjK 0:0a841b89d614 2436 }
AjK 0:0a841b89d614 2437
AjK 0:0a841b89d614 2438
AjK 0:0a841b89d614 2439
AjK 0:0a841b89d614 2440 FRESULT f_chdir (
AjK 0:0a841b89d614 2441 const TCHAR *path /* Pointer to the directory path */
AjK 0:0a841b89d614 2442 )
AjK 0:0a841b89d614 2443 {
AjK 0:0a841b89d614 2444 FRESULT res;
AjK 0:0a841b89d614 2445 DIR dj;
AjK 0:0a841b89d614 2446 DEF_NAMEBUF;
AjK 0:0a841b89d614 2447
AjK 0:0a841b89d614 2448
AjK 0:0a841b89d614 2449 res = chk_mounted(&path, &dj.fs, 0);
AjK 0:0a841b89d614 2450 if (res == FR_OK) {
AjK 0:0a841b89d614 2451 INIT_BUF(dj);
AjK 0:0a841b89d614 2452 res = follow_path(&dj, path); /* Follow the path */
AjK 0:0a841b89d614 2453 FREE_BUF();
AjK 0:0a841b89d614 2454 if (res == FR_OK) { /* Follow completed */
AjK 0:0a841b89d614 2455 if (!dj.dir) {
AjK 0:0a841b89d614 2456 dj.fs->cdir = dj.sclust; /* Start directory itself */
AjK 0:0a841b89d614 2457 } else {
AjK 0:0a841b89d614 2458 if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
AjK 0:0a841b89d614 2459 dj.fs->cdir = LD_CLUST(dj.dir);
AjK 0:0a841b89d614 2460 else
AjK 0:0a841b89d614 2461 res = FR_NO_PATH; /* Reached but a file */
AjK 0:0a841b89d614 2462 }
AjK 0:0a841b89d614 2463 }
AjK 0:0a841b89d614 2464 if (res == FR_NO_FILE) res = FR_NO_PATH;
AjK 0:0a841b89d614 2465 }
AjK 0:0a841b89d614 2466
AjK 0:0a841b89d614 2467 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 2468 }
AjK 0:0a841b89d614 2469
AjK 0:0a841b89d614 2470
AjK 0:0a841b89d614 2471 #if _FS_RPATH >= 2
AjK 0:0a841b89d614 2472 FRESULT f_getcwd (
AjK 0:0a841b89d614 2473 TCHAR *path, /* Pointer to the directory path */
AjK 0:0a841b89d614 2474 UINT sz_path /* Size of path */
AjK 0:0a841b89d614 2475 )
AjK 0:0a841b89d614 2476 {
AjK 0:0a841b89d614 2477 FRESULT res;
AjK 0:0a841b89d614 2478 DIR dj;
AjK 0:0a841b89d614 2479 UINT i, n;
AjK 0:0a841b89d614 2480 DWORD ccl;
AjK 0:0a841b89d614 2481 TCHAR *tp;
AjK 0:0a841b89d614 2482 FILINFO fno;
AjK 0:0a841b89d614 2483 DEF_NAMEBUF;
AjK 0:0a841b89d614 2484
AjK 0:0a841b89d614 2485
AjK 0:0a841b89d614 2486 *path = 0;
AjK 0:0a841b89d614 2487 res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */
AjK 0:0a841b89d614 2488 if (res == FR_OK) {
AjK 0:0a841b89d614 2489 INIT_BUF(dj);
AjK 0:0a841b89d614 2490 i = sz_path; /* Bottom of buffer (dir stack base) */
AjK 0:0a841b89d614 2491 dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */
AjK 0:0a841b89d614 2492 while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */
AjK 0:0a841b89d614 2493 res = dir_sdi(&dj, 1); /* Get parent dir */
AjK 0:0a841b89d614 2494 if (res != FR_OK) break;
AjK 0:0a841b89d614 2495 res = dir_read(&dj);
AjK 0:0a841b89d614 2496 if (res != FR_OK) break;
AjK 0:0a841b89d614 2497 dj.sclust = LD_CLUST(dj.dir); /* Goto parent dir */
AjK 0:0a841b89d614 2498 res = dir_sdi(&dj, 0);
AjK 0:0a841b89d614 2499 if (res != FR_OK) break;
AjK 0:0a841b89d614 2500 do { /* Find the entry links to the child dir */
AjK 0:0a841b89d614 2501 res = dir_read(&dj);
AjK 0:0a841b89d614 2502 if (res != FR_OK) break;
AjK 0:0a841b89d614 2503 if (ccl == LD_CLUST(dj.dir)) break; /* Found the entry */
AjK 0:0a841b89d614 2504 res = dir_next(&dj, 0);
AjK 0:0a841b89d614 2505 } while (res == FR_OK);
AjK 0:0a841b89d614 2506 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
AjK 0:0a841b89d614 2507 if (res != FR_OK) break;
AjK 0:0a841b89d614 2508 #if _USE_LFN
AjK 0:0a841b89d614 2509 fno.lfname = path;
AjK 0:0a841b89d614 2510 fno.lfsize = i;
AjK 0:0a841b89d614 2511 #endif
AjK 0:0a841b89d614 2512 get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */
AjK 0:0a841b89d614 2513 tp = fno.fname;
AjK 0:0a841b89d614 2514 if (_USE_LFN && *path) tp = path;
AjK 0:0a841b89d614 2515 for (n = 0; tp[n]; n++) ;
AjK 0:0a841b89d614 2516 if (i < n + 3) {
AjK 0:0a841b89d614 2517 res = FR_NOT_ENOUGH_CORE; break;
AjK 0:0a841b89d614 2518 }
AjK 0:0a841b89d614 2519 while (n) path[--i] = tp[--n];
AjK 0:0a841b89d614 2520 path[--i] = '/';
AjK 0:0a841b89d614 2521 }
AjK 0:0a841b89d614 2522 tp = path;
AjK 0:0a841b89d614 2523 if (res == FR_OK) {
AjK 0:0a841b89d614 2524 *tp++ = '0' + CurrVol; /* Put drive number */
AjK 0:0a841b89d614 2525 *tp++ = ':';
AjK 0:0a841b89d614 2526 if (i == sz_path) { /* Root-dir */
AjK 0:0a841b89d614 2527 *tp++ = '/';
AjK 0:0a841b89d614 2528 } else { /* Sub-dir */
AjK 0:0a841b89d614 2529 do /* Add stacked path str */
AjK 0:0a841b89d614 2530 *tp++ = path[i++];
AjK 0:0a841b89d614 2531 while (i < sz_path);
AjK 0:0a841b89d614 2532 }
AjK 0:0a841b89d614 2533 }
AjK 0:0a841b89d614 2534 *tp = 0;
AjK 0:0a841b89d614 2535 FREE_BUF();
AjK 0:0a841b89d614 2536 }
AjK 0:0a841b89d614 2537
AjK 0:0a841b89d614 2538 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 2539 }
AjK 0:0a841b89d614 2540 #endif /* _FS_RPATH >= 2 */
AjK 0:0a841b89d614 2541 #endif /* _FS_RPATH >= 1 */
AjK 0:0a841b89d614 2542
AjK 0:0a841b89d614 2543
AjK 0:0a841b89d614 2544
AjK 0:0a841b89d614 2545 #if _FS_MINIMIZE <= 2
AjK 0:0a841b89d614 2546 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2547 /* Seek File R/W Pointer */
AjK 0:0a841b89d614 2548 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2549
AjK 0:0a841b89d614 2550 FRESULT f_lseek (
AjK 0:0a841b89d614 2551 FIL *fp, /* Pointer to the file object */
AjK 0:0a841b89d614 2552 DWORD ofs /* File pointer from top of file */
AjK 0:0a841b89d614 2553 )
AjK 0:0a841b89d614 2554 {
AjK 0:0a841b89d614 2555 FRESULT res;
AjK 0:0a841b89d614 2556
AjK 0:0a841b89d614 2557
AjK 0:0a841b89d614 2558 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 2559 if (res != FR_OK) LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2560 if (fp->flag & FA__ERROR) /* Check abort flag */
AjK 0:0a841b89d614 2561 LEAVE_FF(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2562
AjK 0:0a841b89d614 2563 #if _USE_FASTSEEK
AjK 0:0a841b89d614 2564 if (fp->cltbl) { /* Fast seek */
AjK 0:0a841b89d614 2565 DWORD cl, pcl, ncl, tcl, dsc, tlen, *tbl = fp->cltbl;
AjK 0:0a841b89d614 2566 BYTE csc;
AjK 0:0a841b89d614 2567
AjK 0:0a841b89d614 2568 tlen = *tbl++;
AjK 0:0a841b89d614 2569 if (ofs == CREATE_LINKMAP) { /* Create link map table */
AjK 0:0a841b89d614 2570 cl = fp->org_clust;
AjK 0:0a841b89d614 2571 if (cl) {
AjK 0:0a841b89d614 2572 do {
AjK 0:0a841b89d614 2573 if (tlen < 4) { /* Not enough table items */
AjK 0:0a841b89d614 2574 res = FR_NOT_ENOUGH_CORE; break;
AjK 0:0a841b89d614 2575 }
AjK 0:0a841b89d614 2576 tcl = cl; ncl = 0;
AjK 0:0a841b89d614 2577 do { /* Get a fragment and store the top and length */
AjK 0:0a841b89d614 2578 pcl = cl; ncl++;
AjK 0:0a841b89d614 2579 cl = get_fat(fp->fs, cl);
AjK 0:0a841b89d614 2580 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2581 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2582 } while (cl == pcl + 1);
AjK 0:0a841b89d614 2583 *tbl++ = ncl; *tbl++ = tcl;
AjK 0:0a841b89d614 2584 tlen -= 2;
AjK 0:0a841b89d614 2585 } while (cl < fp->fs->n_fatent);
AjK 0:0a841b89d614 2586 }
AjK 0:0a841b89d614 2587 *tbl = 0; /* Terminate table */
AjK 0:0a841b89d614 2588
AjK 0:0a841b89d614 2589 } else { /* Fast seek */
AjK 0:0a841b89d614 2590 if (ofs > fp->fsize) /* Clip offset at the file size */
AjK 0:0a841b89d614 2591 ofs = fp->fsize;
AjK 0:0a841b89d614 2592 fp->fptr = ofs; /* Set file pointer */
AjK 0:0a841b89d614 2593 if (ofs) {
AjK 0:0a841b89d614 2594 dsc = (ofs - 1) / SS(fp->fs);
AjK 0:0a841b89d614 2595 cl = dsc / fp->fs->csize;
AjK 0:0a841b89d614 2596 for (;;) {
AjK 0:0a841b89d614 2597 ncl = *tbl++;
AjK 0:0a841b89d614 2598 if (!ncl) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2599 if (cl < ncl) break;
AjK 0:0a841b89d614 2600 cl -= ncl; tbl++;
AjK 0:0a841b89d614 2601 }
AjK 0:0a841b89d614 2602 fp->curr_clust = cl + *tbl;
AjK 0:0a841b89d614 2603 csc = (BYTE)(dsc & (fp->fs->csize - 1));
AjK 0:0a841b89d614 2604 dsc = clust2sect(fp->fs, fp->curr_clust);
AjK 0:0a841b89d614 2605 if (!dsc) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2606 dsc += csc;
AjK 0:0a841b89d614 2607 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {
AjK 0:0a841b89d614 2608 #if !_FS_TINY
AjK 0:0a841b89d614 2609 #if !_FS_READONLY
AjK 0:0a841b89d614 2610 if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */
AjK 0:0a841b89d614 2611 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
AjK 0:0a841b89d614 2612 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2613 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2614 }
AjK 0:0a841b89d614 2615 #endif
AjK 0:0a841b89d614 2616 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)
AjK 0:0a841b89d614 2617 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2618 #endif
AjK 0:0a841b89d614 2619 fp->dsect = dsc;
AjK 0:0a841b89d614 2620 }
AjK 0:0a841b89d614 2621 }
AjK 0:0a841b89d614 2622 }
AjK 0:0a841b89d614 2623 } else
AjK 0:0a841b89d614 2624 #endif
AjK 0:0a841b89d614 2625
AjK 0:0a841b89d614 2626 /* Normal Seek */
AjK 0:0a841b89d614 2627 {
AjK 0:0a841b89d614 2628 DWORD clst, bcs, nsect, ifptr;
AjK 0:0a841b89d614 2629
AjK 0:0a841b89d614 2630 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
AjK 0:0a841b89d614 2631 #if !_FS_READONLY
AjK 0:0a841b89d614 2632 && !(fp->flag & FA_WRITE)
AjK 0:0a841b89d614 2633 #endif
AjK 0:0a841b89d614 2634 ) ofs = fp->fsize;
AjK 0:0a841b89d614 2635
AjK 0:0a841b89d614 2636 ifptr = fp->fptr;
AjK 0:0a841b89d614 2637 fp->fptr = nsect = 0;
AjK 0:0a841b89d614 2638 if (ofs) {
AjK 0:0a841b89d614 2639 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
AjK 0:0a841b89d614 2640 if (ifptr > 0 &&
AjK 0:0a841b89d614 2641 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
AjK 0:0a841b89d614 2642 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
AjK 0:0a841b89d614 2643 ofs -= fp->fptr;
AjK 0:0a841b89d614 2644 clst = fp->curr_clust;
AjK 0:0a841b89d614 2645 } else { /* When seek to back cluster, */
AjK 0:0a841b89d614 2646 clst = fp->org_clust; /* start from the first cluster */
AjK 0:0a841b89d614 2647 #if !_FS_READONLY
AjK 0:0a841b89d614 2648 if (clst == 0) { /* If no cluster chain, create a new chain */
AjK 0:0a841b89d614 2649 clst = create_chain(fp->fs, 0);
AjK 0:0a841b89d614 2650 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2651 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2652 fp->org_clust = clst;
AjK 0:0a841b89d614 2653 }
AjK 0:0a841b89d614 2654 #endif
AjK 0:0a841b89d614 2655 fp->curr_clust = clst;
AjK 0:0a841b89d614 2656 }
AjK 0:0a841b89d614 2657 if (clst != 0) {
AjK 0:0a841b89d614 2658 while (ofs > bcs) { /* Cluster following loop */
AjK 0:0a841b89d614 2659 #if !_FS_READONLY
AjK 0:0a841b89d614 2660 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
AjK 0:0a841b89d614 2661 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
AjK 0:0a841b89d614 2662 if (clst == 0) { /* When disk gets full, clip file size */
AjK 0:0a841b89d614 2663 ofs = bcs; break;
AjK 0:0a841b89d614 2664 }
AjK 0:0a841b89d614 2665 } else
AjK 0:0a841b89d614 2666 #endif
AjK 0:0a841b89d614 2667 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
AjK 0:0a841b89d614 2668 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2669 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2670 fp->curr_clust = clst;
AjK 0:0a841b89d614 2671 fp->fptr += bcs;
AjK 0:0a841b89d614 2672 ofs -= bcs;
AjK 0:0a841b89d614 2673 }
AjK 0:0a841b89d614 2674 fp->fptr += ofs;
AjK 0:0a841b89d614 2675 if (ofs % SS(fp->fs)) {
AjK 0:0a841b89d614 2676 nsect = clust2sect(fp->fs, clst); /* Current sector */
AjK 0:0a841b89d614 2677 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 2678 nsect += ofs / SS(fp->fs);
AjK 0:0a841b89d614 2679 }
AjK 0:0a841b89d614 2680 }
AjK 0:0a841b89d614 2681 }
AjK 0:0a841b89d614 2682 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
AjK 0:0a841b89d614 2683 #if !_FS_TINY
AjK 0:0a841b89d614 2684 #if !_FS_READONLY
AjK 0:0a841b89d614 2685 if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */
AjK 0:0a841b89d614 2686 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
AjK 0:0a841b89d614 2687 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2688 fp->flag &= ~FA__DIRTY;
AjK 0:0a841b89d614 2689 }
AjK 0:0a841b89d614 2690 #endif
AjK 0:0a841b89d614 2691 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)
AjK 0:0a841b89d614 2692 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 2693 #endif
AjK 0:0a841b89d614 2694 fp->dsect = nsect;
AjK 0:0a841b89d614 2695 }
AjK 0:0a841b89d614 2696 #if !_FS_READONLY
AjK 0:0a841b89d614 2697 if (fp->fptr > fp->fsize) { /* Set change flag if the file size is extended */
AjK 0:0a841b89d614 2698 fp->fsize = fp->fptr;
AjK 0:0a841b89d614 2699 fp->flag |= FA__WRITTEN;
AjK 0:0a841b89d614 2700 }
AjK 0:0a841b89d614 2701 #endif
AjK 0:0a841b89d614 2702 }
AjK 0:0a841b89d614 2703
AjK 0:0a841b89d614 2704 LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2705 }
AjK 0:0a841b89d614 2706
AjK 0:0a841b89d614 2707
AjK 0:0a841b89d614 2708
AjK 0:0a841b89d614 2709 #if _FS_MINIMIZE <= 1
AjK 0:0a841b89d614 2710 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2711 /* Create a Directroy Object */
AjK 0:0a841b89d614 2712 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2713
AjK 0:0a841b89d614 2714 FRESULT f_opendir (
AjK 0:0a841b89d614 2715 DIR *dj, /* Pointer to directory object to create */
AjK 0:0a841b89d614 2716 const TCHAR *path /* Pointer to the directory path */
AjK 0:0a841b89d614 2717 )
AjK 0:0a841b89d614 2718 {
AjK 0:0a841b89d614 2719 FRESULT res;
AjK 0:0a841b89d614 2720 DEF_NAMEBUF;
AjK 0:0a841b89d614 2721
AjK 0:0a841b89d614 2722
AjK 0:0a841b89d614 2723 res = chk_mounted(&path, &dj->fs, 0);
AjK 0:0a841b89d614 2724 if (res == FR_OK) {
AjK 0:0a841b89d614 2725 INIT_BUF(*dj);
AjK 0:0a841b89d614 2726 res = follow_path(dj, path); /* Follow the path to the directory */
AjK 0:0a841b89d614 2727 FREE_BUF();
AjK 0:0a841b89d614 2728 if (res == FR_OK) { /* Follow completed */
AjK 0:0a841b89d614 2729 if (dj->dir) { /* It is not the root dir */
AjK 0:0a841b89d614 2730 if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
AjK 0:0a841b89d614 2731 dj->sclust = LD_CLUST(dj->dir);
AjK 0:0a841b89d614 2732 } else { /* The object is not a directory */
AjK 0:0a841b89d614 2733 res = FR_NO_PATH;
AjK 0:0a841b89d614 2734 }
AjK 0:0a841b89d614 2735 }
AjK 0:0a841b89d614 2736 if (res == FR_OK) {
AjK 0:0a841b89d614 2737 dj->id = dj->fs->id;
AjK 0:0a841b89d614 2738 res = dir_sdi(dj, 0); /* Rewind dir */
AjK 0:0a841b89d614 2739 }
AjK 0:0a841b89d614 2740 }
AjK 0:0a841b89d614 2741 if (res == FR_NO_FILE) res = FR_NO_PATH;
AjK 0:0a841b89d614 2742 }
AjK 0:0a841b89d614 2743
AjK 0:0a841b89d614 2744 LEAVE_FF(dj->fs, res);
AjK 0:0a841b89d614 2745 }
AjK 0:0a841b89d614 2746
AjK 0:0a841b89d614 2747
AjK 0:0a841b89d614 2748
AjK 0:0a841b89d614 2749
AjK 0:0a841b89d614 2750 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2751 /* Read Directory Entry in Sequense */
AjK 0:0a841b89d614 2752 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2753
AjK 0:0a841b89d614 2754 FRESULT f_readdir (
AjK 0:0a841b89d614 2755 DIR *dj, /* Pointer to the open directory object */
AjK 0:0a841b89d614 2756 FILINFO *fno /* Pointer to file information to return */
AjK 0:0a841b89d614 2757 )
AjK 0:0a841b89d614 2758 {
AjK 0:0a841b89d614 2759 FRESULT res;
AjK 0:0a841b89d614 2760 DEF_NAMEBUF;
AjK 0:0a841b89d614 2761
AjK 0:0a841b89d614 2762
AjK 0:0a841b89d614 2763 res = validate(dj->fs, dj->id); /* Check validity of the object */
AjK 0:0a841b89d614 2764 if (res == FR_OK) {
AjK 0:0a841b89d614 2765 if (!fno) {
AjK 0:0a841b89d614 2766 res = dir_sdi(dj, 0); /* Rewind the directory object */
AjK 0:0a841b89d614 2767 } else {
AjK 0:0a841b89d614 2768 INIT_BUF(*dj);
AjK 0:0a841b89d614 2769 res = dir_read(dj); /* Read an directory item */
AjK 0:0a841b89d614 2770 if (res == FR_NO_FILE) { /* Reached end of dir */
AjK 0:0a841b89d614 2771 dj->sect = 0;
AjK 0:0a841b89d614 2772 res = FR_OK;
AjK 0:0a841b89d614 2773 }
AjK 0:0a841b89d614 2774 if (res == FR_OK) { /* A valid entry is found */
AjK 0:0a841b89d614 2775 get_fileinfo(dj, fno); /* Get the object information */
AjK 0:0a841b89d614 2776 res = dir_next(dj, 0); /* Increment index for next */
AjK 0:0a841b89d614 2777 if (res == FR_NO_FILE) {
AjK 0:0a841b89d614 2778 dj->sect = 0;
AjK 0:0a841b89d614 2779 res = FR_OK;
AjK 0:0a841b89d614 2780 }
AjK 0:0a841b89d614 2781 }
AjK 0:0a841b89d614 2782 FREE_BUF();
AjK 0:0a841b89d614 2783 }
AjK 0:0a841b89d614 2784 }
AjK 0:0a841b89d614 2785
AjK 0:0a841b89d614 2786 LEAVE_FF(dj->fs, res);
AjK 0:0a841b89d614 2787 }
AjK 0:0a841b89d614 2788
AjK 0:0a841b89d614 2789
AjK 0:0a841b89d614 2790
AjK 0:0a841b89d614 2791 #if _FS_MINIMIZE == 0
AjK 0:0a841b89d614 2792 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2793 /* Get File Status */
AjK 0:0a841b89d614 2794 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2795
AjK 0:0a841b89d614 2796 FRESULT f_stat (
AjK 0:0a841b89d614 2797 const TCHAR *path, /* Pointer to the file path */
AjK 0:0a841b89d614 2798 FILINFO *fno /* Pointer to file information to return */
AjK 0:0a841b89d614 2799 )
AjK 0:0a841b89d614 2800 {
AjK 0:0a841b89d614 2801 FRESULT res;
AjK 0:0a841b89d614 2802 DIR dj;
AjK 0:0a841b89d614 2803 DEF_NAMEBUF;
AjK 0:0a841b89d614 2804
AjK 0:0a841b89d614 2805
AjK 0:0a841b89d614 2806 res = chk_mounted(&path, &dj.fs, 0);
AjK 0:0a841b89d614 2807 if (res == FR_OK) {
AjK 0:0a841b89d614 2808 INIT_BUF(dj);
AjK 0:0a841b89d614 2809 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 2810 if (res == FR_OK) { /* Follow completed */
AjK 0:0a841b89d614 2811 if (dj.dir) /* Found an object */
AjK 0:0a841b89d614 2812 get_fileinfo(&dj, fno);
AjK 0:0a841b89d614 2813 else /* It is root dir */
AjK 0:0a841b89d614 2814 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 2815 }
AjK 0:0a841b89d614 2816 FREE_BUF();
AjK 0:0a841b89d614 2817 }
AjK 0:0a841b89d614 2818
AjK 0:0a841b89d614 2819 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 2820 }
AjK 0:0a841b89d614 2821
AjK 0:0a841b89d614 2822
AjK 0:0a841b89d614 2823
AjK 0:0a841b89d614 2824 #if !_FS_READONLY
AjK 0:0a841b89d614 2825 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2826 /* Get Number of Free Clusters */
AjK 0:0a841b89d614 2827 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2828
AjK 0:0a841b89d614 2829 FRESULT f_getfree (
AjK 0:0a841b89d614 2830 const TCHAR *path, /* Pointer to the logical drive number (root dir) */
AjK 0:0a841b89d614 2831 DWORD *nclst, /* Pointer to the variable to return number of free clusters */
AjK 0:0a841b89d614 2832 FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
AjK 0:0a841b89d614 2833 )
AjK 0:0a841b89d614 2834 {
AjK 0:0a841b89d614 2835 FRESULT res;
AjK 0:0a841b89d614 2836 DWORD n, clst, sect, stat;
AjK 0:0a841b89d614 2837 UINT i;
AjK 0:0a841b89d614 2838 BYTE fat, *p;
AjK 0:0a841b89d614 2839
AjK 0:0a841b89d614 2840
AjK 0:0a841b89d614 2841 /* Get drive number */
AjK 0:0a841b89d614 2842 res = chk_mounted(&path, fatfs, 0);
AjK 0:0a841b89d614 2843 if (res == FR_OK) {
AjK 0:0a841b89d614 2844 /* If free_clust is valid, return it without full cluster scan */
AjK 0:0a841b89d614 2845 if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) {
AjK 0:0a841b89d614 2846 *nclst = (*fatfs)->free_clust;
AjK 0:0a841b89d614 2847 } else {
AjK 0:0a841b89d614 2848 /* Get number of free clusters */
AjK 0:0a841b89d614 2849 fat = (*fatfs)->fs_type;
AjK 0:0a841b89d614 2850 n = 0;
AjK 0:0a841b89d614 2851 if (fat == FS_FAT12) {
AjK 0:0a841b89d614 2852 clst = 2;
AjK 0:0a841b89d614 2853 do {
AjK 0:0a841b89d614 2854 stat = get_fat(*fatfs, clst);
AjK 0:0a841b89d614 2855 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
AjK 0:0a841b89d614 2856 if (stat == 1) { res = FR_INT_ERR; break; }
AjK 0:0a841b89d614 2857 if (stat == 0) n++;
AjK 0:0a841b89d614 2858 } while (++clst < (*fatfs)->n_fatent);
AjK 0:0a841b89d614 2859 } else {
AjK 0:0a841b89d614 2860 clst = (*fatfs)->n_fatent;
AjK 0:0a841b89d614 2861 sect = (*fatfs)->fatbase;
AjK 0:0a841b89d614 2862 i = 0; p = 0;
AjK 0:0a841b89d614 2863 do {
AjK 0:0a841b89d614 2864 if (!i) {
AjK 0:0a841b89d614 2865 res = move_window(*fatfs, sect++);
AjK 0:0a841b89d614 2866 if (res != FR_OK) break;
AjK 0:0a841b89d614 2867 p = (*fatfs)->win;
AjK 0:0a841b89d614 2868 i = SS(*fatfs);
AjK 0:0a841b89d614 2869 }
AjK 0:0a841b89d614 2870 if (fat == FS_FAT16) {
AjK 0:0a841b89d614 2871 if (LD_WORD(p) == 0) n++;
AjK 0:0a841b89d614 2872 p += 2; i -= 2;
AjK 0:0a841b89d614 2873 } else {
AjK 0:0a841b89d614 2874 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
AjK 0:0a841b89d614 2875 p += 4; i -= 4;
AjK 0:0a841b89d614 2876 }
AjK 0:0a841b89d614 2877 } while (--clst);
AjK 0:0a841b89d614 2878 }
AjK 0:0a841b89d614 2879 (*fatfs)->free_clust = n;
AjK 0:0a841b89d614 2880 if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
AjK 0:0a841b89d614 2881 *nclst = n;
AjK 0:0a841b89d614 2882 }
AjK 0:0a841b89d614 2883 }
AjK 0:0a841b89d614 2884 LEAVE_FF(*fatfs, res);
AjK 0:0a841b89d614 2885 }
AjK 0:0a841b89d614 2886
AjK 0:0a841b89d614 2887
AjK 0:0a841b89d614 2888
AjK 0:0a841b89d614 2889
AjK 0:0a841b89d614 2890 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2891 /* Truncate File */
AjK 0:0a841b89d614 2892 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2893
AjK 0:0a841b89d614 2894 FRESULT f_truncate (
AjK 0:0a841b89d614 2895 FIL *fp /* Pointer to the file object */
AjK 0:0a841b89d614 2896 )
AjK 0:0a841b89d614 2897 {
AjK 0:0a841b89d614 2898 FRESULT res;
AjK 0:0a841b89d614 2899 DWORD ncl;
AjK 0:0a841b89d614 2900
AjK 0:0a841b89d614 2901
AjK 0:0a841b89d614 2902 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 2903 if (res == FR_OK) {
AjK 0:0a841b89d614 2904 if (fp->flag & FA__ERROR) { /* Check abort flag */
AjK 0:0a841b89d614 2905 res = FR_INT_ERR;
AjK 0:0a841b89d614 2906 } else {
AjK 0:0a841b89d614 2907 if (!(fp->flag & FA_WRITE)) /* Check access mode */
AjK 0:0a841b89d614 2908 res = FR_DENIED;
AjK 0:0a841b89d614 2909 }
AjK 0:0a841b89d614 2910 }
AjK 0:0a841b89d614 2911 if (res == FR_OK) {
AjK 0:0a841b89d614 2912 if (fp->fsize > fp->fptr) {
AjK 0:0a841b89d614 2913 fp->fsize = fp->fptr; /* Set file size to current R/W point */
AjK 0:0a841b89d614 2914 fp->flag |= FA__WRITTEN;
AjK 0:0a841b89d614 2915 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
AjK 0:0a841b89d614 2916 res = remove_chain(fp->fs, fp->org_clust);
AjK 0:0a841b89d614 2917 fp->org_clust = 0;
AjK 0:0a841b89d614 2918 } else { /* When truncate a part of the file, remove remaining clusters */
AjK 0:0a841b89d614 2919 ncl = get_fat(fp->fs, fp->curr_clust);
AjK 0:0a841b89d614 2920 res = FR_OK;
AjK 0:0a841b89d614 2921 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
AjK 0:0a841b89d614 2922 if (ncl == 1) res = FR_INT_ERR;
AjK 0:0a841b89d614 2923 if (res == FR_OK && ncl < fp->fs->n_fatent) {
AjK 0:0a841b89d614 2924 res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
AjK 0:0a841b89d614 2925 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
AjK 0:0a841b89d614 2926 }
AjK 0:0a841b89d614 2927 }
AjK 0:0a841b89d614 2928 }
AjK 0:0a841b89d614 2929 if (res != FR_OK) fp->flag |= FA__ERROR;
AjK 0:0a841b89d614 2930 }
AjK 0:0a841b89d614 2931
AjK 0:0a841b89d614 2932 LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 2933 }
AjK 0:0a841b89d614 2934
AjK 0:0a841b89d614 2935
AjK 0:0a841b89d614 2936
AjK 0:0a841b89d614 2937
AjK 0:0a841b89d614 2938 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2939 /* Delete a File or Directory */
AjK 0:0a841b89d614 2940 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 2941
AjK 0:0a841b89d614 2942 FRESULT f_unlink (
AjK 0:0a841b89d614 2943 const TCHAR *path /* Pointer to the file or directory path */
AjK 0:0a841b89d614 2944 )
AjK 0:0a841b89d614 2945 {
AjK 0:0a841b89d614 2946 FRESULT res;
AjK 0:0a841b89d614 2947 DIR dj, sdj;
AjK 0:0a841b89d614 2948 BYTE *dir;
AjK 0:0a841b89d614 2949 DWORD dclst;
AjK 0:0a841b89d614 2950 DEF_NAMEBUF;
AjK 0:0a841b89d614 2951
AjK 0:0a841b89d614 2952
AjK 0:0a841b89d614 2953 res = chk_mounted(&path, &dj.fs, 1);
AjK 0:0a841b89d614 2954 if (res == FR_OK) {
AjK 0:0a841b89d614 2955 INIT_BUF(dj);
AjK 0:0a841b89d614 2956 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 2957 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
AjK 0:0a841b89d614 2958 res = FR_INVALID_NAME; /* Cannot remove dot entry */
AjK 0:0a841b89d614 2959 #if _FS_SHARE
AjK 0:0a841b89d614 2960 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */
AjK 0:0a841b89d614 2961 #endif
AjK 0:0a841b89d614 2962 if (res == FR_OK) { /* The object is accessible */
AjK 0:0a841b89d614 2963 dir = dj.dir;
AjK 0:0a841b89d614 2964 if (!dir) {
AjK 0:0a841b89d614 2965 res = FR_INVALID_NAME; /* Cannot remove the start directory */
AjK 0:0a841b89d614 2966 } else {
AjK 0:0a841b89d614 2967 if (dir[DIR_Attr] & AM_RDO)
AjK 0:0a841b89d614 2968 res = FR_DENIED; /* Cannot remove R/O object */
AjK 0:0a841b89d614 2969 }
AjK 0:0a841b89d614 2970 dclst = LD_CLUST(dir);
AjK 0:0a841b89d614 2971 if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
AjK 0:0a841b89d614 2972 if (dclst < 2) {
AjK 0:0a841b89d614 2973 res = FR_INT_ERR;
AjK 0:0a841b89d614 2974 } else {
AjK 0:0a841b89d614 2975 mem_cpy(&sdj, &dj, sizeof(DIR)); /* Check if the sub-dir is empty or not */
AjK 0:0a841b89d614 2976 sdj.sclust = dclst;
AjK 0:0a841b89d614 2977 res = dir_sdi(&sdj, 2); /* Exclude dot entries */
AjK 0:0a841b89d614 2978 if (res == FR_OK) {
AjK 0:0a841b89d614 2979 res = dir_read(&sdj);
AjK 0:0a841b89d614 2980 if (res == FR_OK /* Not empty dir */
AjK 0:0a841b89d614 2981 #if _FS_RPATH
AjK 0:0a841b89d614 2982 || dclst == sdj.fs->cdir /* Current dir */
AjK 0:0a841b89d614 2983 #endif
AjK 0:0a841b89d614 2984 ) res = FR_DENIED;
AjK 0:0a841b89d614 2985 if (res == FR_NO_FILE) res = FR_OK; /* Empty */
AjK 0:0a841b89d614 2986 }
AjK 0:0a841b89d614 2987 }
AjK 0:0a841b89d614 2988 }
AjK 0:0a841b89d614 2989 if (res == FR_OK) {
AjK 0:0a841b89d614 2990 res = dir_remove(&dj); /* Remove the directory entry */
AjK 0:0a841b89d614 2991 if (res == FR_OK) {
AjK 0:0a841b89d614 2992 if (dclst) /* Remove the cluster chain if exist */
AjK 0:0a841b89d614 2993 res = remove_chain(dj.fs, dclst);
AjK 0:0a841b89d614 2994 if (res == FR_OK) res = sync(dj.fs);
AjK 0:0a841b89d614 2995 }
AjK 0:0a841b89d614 2996 }
AjK 0:0a841b89d614 2997 }
AjK 0:0a841b89d614 2998 FREE_BUF();
AjK 0:0a841b89d614 2999 }
AjK 0:0a841b89d614 3000 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 3001 }
AjK 0:0a841b89d614 3002
AjK 0:0a841b89d614 3003
AjK 0:0a841b89d614 3004
AjK 0:0a841b89d614 3005
AjK 0:0a841b89d614 3006 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3007 /* Create a Directory */
AjK 0:0a841b89d614 3008 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3009
AjK 0:0a841b89d614 3010 FRESULT f_mkdir (
AjK 0:0a841b89d614 3011 const TCHAR *path /* Pointer to the directory path */
AjK 0:0a841b89d614 3012 )
AjK 0:0a841b89d614 3013 {
AjK 0:0a841b89d614 3014 FRESULT res;
AjK 0:0a841b89d614 3015 DIR dj;
AjK 0:0a841b89d614 3016 BYTE *dir, n;
AjK 0:0a841b89d614 3017 DWORD dsc, dcl, pcl, tim = get_fattime();
AjK 0:0a841b89d614 3018 DEF_NAMEBUF;
AjK 0:0a841b89d614 3019
AjK 0:0a841b89d614 3020
AjK 0:0a841b89d614 3021 res = chk_mounted(&path, &dj.fs, 1);
AjK 0:0a841b89d614 3022 if (res == FR_OK) {
AjK 0:0a841b89d614 3023 INIT_BUF(dj);
AjK 0:0a841b89d614 3024 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 3025 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
AjK 0:0a841b89d614 3026 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
AjK 0:0a841b89d614 3027 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3028 if (res == FR_NO_FILE) { /* Can create a new directory */
AjK 0:0a841b89d614 3029 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
AjK 0:0a841b89d614 3030 res = FR_OK;
AjK 0:0a841b89d614 3031 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
AjK 0:0a841b89d614 3032 if (dcl == 1) res = FR_INT_ERR;
AjK 0:0a841b89d614 3033 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
AjK 0:0a841b89d614 3034 if (res == FR_OK) /* Flush FAT */
AjK 0:0a841b89d614 3035 res = move_window(dj.fs, 0);
AjK 0:0a841b89d614 3036 if (res == FR_OK) { /* Initialize the new directory table */
AjK 0:0a841b89d614 3037 dsc = clust2sect(dj.fs, dcl);
AjK 0:0a841b89d614 3038 dir = dj.fs->win;
AjK 0:0a841b89d614 3039 mem_set(dir, 0, SS(dj.fs));
AjK 0:0a841b89d614 3040 mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
AjK 0:0a841b89d614 3041 dir[DIR_Name] = '.';
AjK 0:0a841b89d614 3042 dir[DIR_Attr] = AM_DIR;
AjK 0:0a841b89d614 3043 ST_DWORD(dir+DIR_WrtTime, tim);
AjK 0:0a841b89d614 3044 ST_CLUST(dir, dcl);
AjK 0:0a841b89d614 3045 mem_cpy(dir+32, dir, 32); /* Create ".." entry */
AjK 0:0a841b89d614 3046 dir[33] = '.'; pcl = dj.sclust;
AjK 0:0a841b89d614 3047 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
AjK 0:0a841b89d614 3048 pcl = 0;
AjK 0:0a841b89d614 3049 ST_CLUST(dir+32, pcl);
AjK 0:0a841b89d614 3050 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
AjK 0:0a841b89d614 3051 dj.fs->winsect = dsc++;
AjK 0:0a841b89d614 3052 dj.fs->wflag = 1;
AjK 0:0a841b89d614 3053 res = move_window(dj.fs, 0);
AjK 0:0a841b89d614 3054 if (res != FR_OK) break;
AjK 0:0a841b89d614 3055 mem_set(dir, 0, SS(dj.fs));
AjK 0:0a841b89d614 3056 }
AjK 0:0a841b89d614 3057 }
AjK 0:0a841b89d614 3058 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
AjK 0:0a841b89d614 3059 if (res != FR_OK) {
AjK 0:0a841b89d614 3060 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
AjK 0:0a841b89d614 3061 } else {
AjK 0:0a841b89d614 3062 dir = dj.dir;
AjK 0:0a841b89d614 3063 dir[DIR_Attr] = AM_DIR; /* Attribute */
AjK 0:0a841b89d614 3064 ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
AjK 0:0a841b89d614 3065 ST_CLUST(dir, dcl); /* Table start cluster */
AjK 0:0a841b89d614 3066 dj.fs->wflag = 1;
AjK 0:0a841b89d614 3067 res = sync(dj.fs);
AjK 0:0a841b89d614 3068 }
AjK 0:0a841b89d614 3069 }
AjK 0:0a841b89d614 3070 FREE_BUF();
AjK 0:0a841b89d614 3071 }
AjK 0:0a841b89d614 3072
AjK 0:0a841b89d614 3073 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 3074 }
AjK 0:0a841b89d614 3075
AjK 0:0a841b89d614 3076
AjK 0:0a841b89d614 3077
AjK 0:0a841b89d614 3078
AjK 0:0a841b89d614 3079 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3080 /* Change Attribute */
AjK 0:0a841b89d614 3081 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3082
AjK 0:0a841b89d614 3083 FRESULT f_chmod (
AjK 0:0a841b89d614 3084 const TCHAR *path, /* Pointer to the file path */
AjK 0:0a841b89d614 3085 BYTE value, /* Attribute bits */
AjK 0:0a841b89d614 3086 BYTE mask /* Attribute mask to change */
AjK 0:0a841b89d614 3087 )
AjK 0:0a841b89d614 3088 {
AjK 0:0a841b89d614 3089 FRESULT res;
AjK 0:0a841b89d614 3090 DIR dj;
AjK 0:0a841b89d614 3091 BYTE *dir;
AjK 0:0a841b89d614 3092 DEF_NAMEBUF;
AjK 0:0a841b89d614 3093
AjK 0:0a841b89d614 3094
AjK 0:0a841b89d614 3095 res = chk_mounted(&path, &dj.fs, 1);
AjK 0:0a841b89d614 3096 if (res == FR_OK) {
AjK 0:0a841b89d614 3097 INIT_BUF(dj);
AjK 0:0a841b89d614 3098 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 3099 FREE_BUF();
AjK 0:0a841b89d614 3100 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
AjK 0:0a841b89d614 3101 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3102 if (res == FR_OK) {
AjK 0:0a841b89d614 3103 dir = dj.dir;
AjK 0:0a841b89d614 3104 if (!dir) { /* Is it a root directory? */
AjK 0:0a841b89d614 3105 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3106 } else { /* File or sub directory */
AjK 0:0a841b89d614 3107 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
AjK 0:0a841b89d614 3108 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
AjK 0:0a841b89d614 3109 dj.fs->wflag = 1;
AjK 0:0a841b89d614 3110 res = sync(dj.fs);
AjK 0:0a841b89d614 3111 }
AjK 0:0a841b89d614 3112 }
AjK 0:0a841b89d614 3113 }
AjK 0:0a841b89d614 3114
AjK 0:0a841b89d614 3115 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 3116 }
AjK 0:0a841b89d614 3117
AjK 0:0a841b89d614 3118
AjK 0:0a841b89d614 3119
AjK 0:0a841b89d614 3120
AjK 0:0a841b89d614 3121 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3122 /* Change Timestamp */
AjK 0:0a841b89d614 3123 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3124
AjK 0:0a841b89d614 3125 FRESULT f_utime (
AjK 0:0a841b89d614 3126 const TCHAR *path, /* Pointer to the file/directory name */
AjK 0:0a841b89d614 3127 const FILINFO *fno /* Pointer to the time stamp to be set */
AjK 0:0a841b89d614 3128 )
AjK 0:0a841b89d614 3129 {
AjK 0:0a841b89d614 3130 FRESULT res;
AjK 0:0a841b89d614 3131 DIR dj;
AjK 0:0a841b89d614 3132 BYTE *dir;
AjK 0:0a841b89d614 3133 DEF_NAMEBUF;
AjK 0:0a841b89d614 3134
AjK 0:0a841b89d614 3135
AjK 0:0a841b89d614 3136 res = chk_mounted(&path, &dj.fs, 1);
AjK 0:0a841b89d614 3137 if (res == FR_OK) {
AjK 0:0a841b89d614 3138 INIT_BUF(dj);
AjK 0:0a841b89d614 3139 res = follow_path(&dj, path); /* Follow the file path */
AjK 0:0a841b89d614 3140 FREE_BUF();
AjK 0:0a841b89d614 3141 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
AjK 0:0a841b89d614 3142 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3143 if (res == FR_OK) {
AjK 0:0a841b89d614 3144 dir = dj.dir;
AjK 0:0a841b89d614 3145 if (!dir) { /* Root directory */
AjK 0:0a841b89d614 3146 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3147 } else { /* File or sub-directory */
AjK 0:0a841b89d614 3148 ST_WORD(dir+DIR_WrtTime, fno->ftime);
AjK 0:0a841b89d614 3149 ST_WORD(dir+DIR_WrtDate, fno->fdate);
AjK 0:0a841b89d614 3150 dj.fs->wflag = 1;
AjK 0:0a841b89d614 3151 res = sync(dj.fs);
AjK 0:0a841b89d614 3152 }
AjK 0:0a841b89d614 3153 }
AjK 0:0a841b89d614 3154 }
AjK 0:0a841b89d614 3155
AjK 0:0a841b89d614 3156 LEAVE_FF(dj.fs, res);
AjK 0:0a841b89d614 3157 }
AjK 0:0a841b89d614 3158
AjK 0:0a841b89d614 3159
AjK 0:0a841b89d614 3160
AjK 0:0a841b89d614 3161
AjK 0:0a841b89d614 3162 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3163 /* Rename File/Directory */
AjK 0:0a841b89d614 3164 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3165
AjK 0:0a841b89d614 3166 FRESULT f_rename (
AjK 0:0a841b89d614 3167 const TCHAR *path_old, /* Pointer to the old name */
AjK 0:0a841b89d614 3168 const TCHAR *path_new /* Pointer to the new name */
AjK 0:0a841b89d614 3169 )
AjK 0:0a841b89d614 3170 {
AjK 0:0a841b89d614 3171 FRESULT res;
AjK 0:0a841b89d614 3172 DIR djo, djn;
AjK 0:0a841b89d614 3173 BYTE buf[21], *dir;
AjK 0:0a841b89d614 3174 DWORD dw;
AjK 0:0a841b89d614 3175 DEF_NAMEBUF;
AjK 0:0a841b89d614 3176
AjK 0:0a841b89d614 3177
AjK 0:0a841b89d614 3178 res = chk_mounted(&path_old, &djo.fs, 1);
AjK 0:0a841b89d614 3179 if (res == FR_OK) {
AjK 0:0a841b89d614 3180 djn.fs = djo.fs;
AjK 0:0a841b89d614 3181 INIT_BUF(djo);
AjK 0:0a841b89d614 3182 res = follow_path(&djo, path_old); /* Check old object */
AjK 0:0a841b89d614 3183 if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
AjK 0:0a841b89d614 3184 res = FR_INVALID_NAME;
AjK 0:0a841b89d614 3185 #if _FS_SHARE
AjK 0:0a841b89d614 3186 if (res == FR_OK) res = chk_lock(&djo, 2);
AjK 0:0a841b89d614 3187 #endif
AjK 0:0a841b89d614 3188 if (res == FR_OK) { /* Old object is found */
AjK 0:0a841b89d614 3189 if (!djo.dir) { /* Is root dir? */
AjK 0:0a841b89d614 3190 res = FR_NO_FILE;
AjK 0:0a841b89d614 3191 } else {
AjK 0:0a841b89d614 3192 mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
AjK 0:0a841b89d614 3193 mem_cpy(&djn, &djo, sizeof(DIR)); /* Check new object */
AjK 0:0a841b89d614 3194 res = follow_path(&djn, path_new);
AjK 0:0a841b89d614 3195 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
AjK 0:0a841b89d614 3196 if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
AjK 0:0a841b89d614 3197 /* Start critical section that any interruption or error can cause cross-link */
AjK 0:0a841b89d614 3198 res = dir_register(&djn); /* Register the new entry */
AjK 0:0a841b89d614 3199 if (res == FR_OK) {
AjK 0:0a841b89d614 3200 dir = djn.dir; /* Copy object information except for name */
AjK 0:0a841b89d614 3201 mem_cpy(dir+13, buf+2, 19);
AjK 0:0a841b89d614 3202 dir[DIR_Attr] = buf[0] | AM_ARC;
AjK 0:0a841b89d614 3203 djo.fs->wflag = 1;
AjK 0:0a841b89d614 3204 if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */
AjK 0:0a841b89d614 3205 dw = clust2sect(djn.fs, LD_CLUST(dir));
AjK 0:0a841b89d614 3206 if (!dw) {
AjK 0:0a841b89d614 3207 res = FR_INT_ERR;
AjK 0:0a841b89d614 3208 } else {
AjK 0:0a841b89d614 3209 res = move_window(djn.fs, dw);
AjK 0:0a841b89d614 3210 dir = djn.fs->win+32; /* .. entry */
AjK 0:0a841b89d614 3211 if (res == FR_OK && dir[1] == '.') {
AjK 0:0a841b89d614 3212 dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
AjK 0:0a841b89d614 3213 ST_CLUST(dir, dw);
AjK 0:0a841b89d614 3214 djn.fs->wflag = 1;
AjK 0:0a841b89d614 3215 }
AjK 0:0a841b89d614 3216 }
AjK 0:0a841b89d614 3217 }
AjK 0:0a841b89d614 3218 if (res == FR_OK) {
AjK 0:0a841b89d614 3219 res = dir_remove(&djo); /* Remove old entry */
AjK 0:0a841b89d614 3220 if (res == FR_OK)
AjK 0:0a841b89d614 3221 res = sync(djo.fs);
AjK 0:0a841b89d614 3222 }
AjK 0:0a841b89d614 3223 }
AjK 0:0a841b89d614 3224 /* End critical section */
AjK 0:0a841b89d614 3225 }
AjK 0:0a841b89d614 3226 }
AjK 0:0a841b89d614 3227 }
AjK 0:0a841b89d614 3228 FREE_BUF();
AjK 0:0a841b89d614 3229 }
AjK 0:0a841b89d614 3230 LEAVE_FF(djo.fs, res);
AjK 0:0a841b89d614 3231 }
AjK 0:0a841b89d614 3232
AjK 0:0a841b89d614 3233 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 3234 #endif /* _FS_MINIMIZE == 0 */
AjK 0:0a841b89d614 3235 #endif /* _FS_MINIMIZE <= 1 */
AjK 0:0a841b89d614 3236 #endif /* _FS_MINIMIZE <= 2 */
AjK 0:0a841b89d614 3237
AjK 0:0a841b89d614 3238
AjK 0:0a841b89d614 3239
AjK 0:0a841b89d614 3240 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3241 /* Forward data to the stream directly (available on only tiny cfg) */
AjK 0:0a841b89d614 3242 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3243 #if _USE_FORWARD && _FS_TINY
AjK 0:0a841b89d614 3244
AjK 0:0a841b89d614 3245 FRESULT f_forward (
AjK 0:0a841b89d614 3246 FIL *fp, /* Pointer to the file object */
AjK 0:0a841b89d614 3247 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
AjK 0:0a841b89d614 3248 UINT btr, /* Number of bytes to forward */
AjK 0:0a841b89d614 3249 UINT *bf /* Pointer to number of bytes forwarded */
AjK 0:0a841b89d614 3250 )
AjK 0:0a841b89d614 3251 {
AjK 0:0a841b89d614 3252 FRESULT res;
AjK 0:0a841b89d614 3253 DWORD remain, clst, sect;
AjK 0:0a841b89d614 3254 UINT rcnt;
AjK 0:0a841b89d614 3255 BYTE csect;
AjK 0:0a841b89d614 3256
AjK 0:0a841b89d614 3257
AjK 0:0a841b89d614 3258 *bf = 0; /* Initialize byte counter */
AjK 0:0a841b89d614 3259
AjK 0:0a841b89d614 3260 res = validate(fp->fs, fp->id); /* Check validity of the object */
AjK 0:0a841b89d614 3261 if (res != FR_OK) LEAVE_FF(fp->fs, res);
AjK 0:0a841b89d614 3262 if (fp->flag & FA__ERROR) /* Check error flag */
AjK 0:0a841b89d614 3263 LEAVE_FF(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 3264 if (!(fp->flag & FA_READ)) /* Check access mode */
AjK 0:0a841b89d614 3265 LEAVE_FF(fp->fs, FR_DENIED);
AjK 0:0a841b89d614 3266
AjK 0:0a841b89d614 3267 remain = fp->fsize - fp->fptr;
AjK 0:0a841b89d614 3268 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
AjK 0:0a841b89d614 3269
AjK 0:0a841b89d614 3270 for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
AjK 0:0a841b89d614 3271 fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
AjK 0:0a841b89d614 3272 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
AjK 0:0a841b89d614 3273 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
AjK 0:0a841b89d614 3274 if (!csect) { /* On the cluster boundary? */
AjK 0:0a841b89d614 3275 clst = (fp->fptr == 0) ? /* On the top of the file? */
AjK 0:0a841b89d614 3276 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
AjK 0:0a841b89d614 3277 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 3278 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 3279 fp->curr_clust = clst; /* Update current cluster */
AjK 0:0a841b89d614 3280 }
AjK 0:0a841b89d614 3281 }
AjK 0:0a841b89d614 3282 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */
AjK 0:0a841b89d614 3283 if (!sect) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 3284 sect += csect;
AjK 0:0a841b89d614 3285 if (move_window(fp->fs, sect)) /* Move sector window */
AjK 0:0a841b89d614 3286 ABORT(fp->fs, FR_DISK_ERR);
AjK 0:0a841b89d614 3287 fp->dsect = sect;
AjK 0:0a841b89d614 3288 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
AjK 0:0a841b89d614 3289 if (rcnt > btr) rcnt = btr;
AjK 0:0a841b89d614 3290 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
AjK 0:0a841b89d614 3291 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
AjK 0:0a841b89d614 3292 }
AjK 0:0a841b89d614 3293
AjK 0:0a841b89d614 3294 LEAVE_FF(fp->fs, FR_OK);
AjK 0:0a841b89d614 3295 }
AjK 0:0a841b89d614 3296 #endif /* _USE_FORWARD */
AjK 0:0a841b89d614 3297
AjK 0:0a841b89d614 3298
AjK 0:0a841b89d614 3299
AjK 0:0a841b89d614 3300 #if _USE_MKFS && !_FS_READONLY
AjK 0:0a841b89d614 3301 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3302 /* Create File System on the Drive */
AjK 0:0a841b89d614 3303 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3304 #define N_ROOTDIR 512 /* Multiple of 32 */
AjK 0:0a841b89d614 3305 #define N_FATS 1 /* 1 or 2 */
AjK 0:0a841b89d614 3306
AjK 0:0a841b89d614 3307
AjK 0:0a841b89d614 3308 FRESULT f_mkfs (
AjK 0:0a841b89d614 3309 BYTE drv, /* Logical drive number */
AjK 0:0a841b89d614 3310 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
AjK 0:0a841b89d614 3311 UINT au /* Allocation unit size [bytes] */
AjK 0:0a841b89d614 3312 )
AjK 0:0a841b89d614 3313 {
AjK 0:0a841b89d614 3314 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
AjK 0:0a841b89d614 3315 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
AjK 0:0a841b89d614 3316 BYTE fmt, md, *tbl;
AjK 0:0a841b89d614 3317 DWORD n_clst, vs, n, wsect;
AjK 0:0a841b89d614 3318 UINT i;
AjK 0:0a841b89d614 3319 DWORD b_vol, b_fat, b_dir, b_data; /* Offset (LBA) */
AjK 0:0a841b89d614 3320 DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
AjK 0:0a841b89d614 3321 FATFS *fs;
AjK 0:0a841b89d614 3322 DSTATUS stat;
AjK 0:0a841b89d614 3323
AjK 0:0a841b89d614 3324
AjK 0:0a841b89d614 3325 /* Check mounted drive and clear work area */
AjK 0:0a841b89d614 3326 if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
AjK 0:0a841b89d614 3327 fs = FatFs[drv];
AjK 0:0a841b89d614 3328 if (!fs) return FR_NOT_ENABLED;
AjK 0:0a841b89d614 3329 fs->fs_type = 0;
AjK 0:0a841b89d614 3330 drv = LD2PD(drv);
AjK 0:0a841b89d614 3331
AjK 0:0a841b89d614 3332 /* Get disk statics */
AjK 0:0a841b89d614 3333 stat = disk_initialize(drv);
AjK 0:0a841b89d614 3334 if (stat & STA_NOINIT) return FR_NOT_READY;
AjK 0:0a841b89d614 3335 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
AjK 0:0a841b89d614 3336 #if _MAX_SS != 512 /* Get disk sector size */
AjK 0:0a841b89d614 3337 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK)
AjK 0:0a841b89d614 3338 return FR_DISK_ERR;
AjK 0:0a841b89d614 3339 #endif
AjK 0:0a841b89d614 3340 if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
AjK 0:0a841b89d614 3341 return FR_DISK_ERR;
AjK 0:0a841b89d614 3342 b_vol = (sfd) ? 0 : 63; /* Volume start sector */
AjK 0:0a841b89d614 3343 n_vol -= b_vol;
AjK 0:0a841b89d614 3344 if (au & (au - 1)) au = 0; /* Check validity of the allocation unit size */
AjK 0:0a841b89d614 3345 if (!au) { /* AU auto selection */
AjK 0:0a841b89d614 3346 vs = n_vol / (2000 / (SS(fs) / 512));
AjK 0:0a841b89d614 3347 for (i = 0; vs < vst[i]; i++) ;
AjK 0:0a841b89d614 3348 au = cst[i];
AjK 0:0a841b89d614 3349 }
AjK 0:0a841b89d614 3350 au /= SS(fs); /* Number of sectors per cluster */
AjK 0:0a841b89d614 3351 if (au == 0) au = 1;
AjK 0:0a841b89d614 3352 if (au > 128) au = 128;
AjK 0:0a841b89d614 3353
AjK 0:0a841b89d614 3354 /* Pre-compute number of clusters and FAT syb-type */
AjK 0:0a841b89d614 3355 n_clst = n_vol / au;
AjK 0:0a841b89d614 3356 fmt = FS_FAT12;
AjK 0:0a841b89d614 3357 if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
AjK 0:0a841b89d614 3358 if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
AjK 0:0a841b89d614 3359
AjK 0:0a841b89d614 3360 /* Determine offset and size of FAT structure */
AjK 0:0a841b89d614 3361 if (fmt == FS_FAT32) {
AjK 0:0a841b89d614 3362 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
AjK 0:0a841b89d614 3363 n_rsv = 32;
AjK 0:0a841b89d614 3364 n_dir = 0;
AjK 0:0a841b89d614 3365 } else {
AjK 0:0a841b89d614 3366 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
AjK 0:0a841b89d614 3367 n_fat = (n_fat + SS(fs) - 1) / SS(fs);
AjK 0:0a841b89d614 3368 n_rsv = 1;
AjK 0:0a841b89d614 3369 n_dir = N_ROOTDIR * 32UL / SS(fs);
AjK 0:0a841b89d614 3370 }
AjK 0:0a841b89d614 3371 b_fat = b_vol + n_rsv; /* FAT area start sector */
AjK 0:0a841b89d614 3372 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
AjK 0:0a841b89d614 3373 b_data = b_dir + n_dir; /* Data area start sector */
AjK 0:0a841b89d614 3374 if (n_vol < b_data + au) return FR_MKFS_ABORTED; /* Too small volume */
AjK 0:0a841b89d614 3375
AjK 0:0a841b89d614 3376 /* Align data start sector to erase block boundary (for flash memory media) */
AjK 0:0a841b89d614 3377 if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
AjK 0:0a841b89d614 3378 n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
AjK 0:0a841b89d614 3379 n = (n - b_data) / N_FATS;
AjK 0:0a841b89d614 3380 if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
AjK 0:0a841b89d614 3381 n_rsv += n;
AjK 0:0a841b89d614 3382 b_fat += n;
AjK 0:0a841b89d614 3383 } else { /* FAT12/16: Expand FAT size */
AjK 0:0a841b89d614 3384 n_fat += n;
AjK 0:0a841b89d614 3385 }
AjK 0:0a841b89d614 3386
AjK 0:0a841b89d614 3387 /* Determine number of cluster and final check of validity of the FAT sub-type */
AjK 0:0a841b89d614 3388 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
AjK 0:0a841b89d614 3389 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
AjK 0:0a841b89d614 3390 || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
AjK 0:0a841b89d614 3391 return FR_MKFS_ABORTED;
AjK 0:0a841b89d614 3392
AjK 0:0a841b89d614 3393 /* Create partition table if required */
AjK 0:0a841b89d614 3394 if (sfd) {
AjK 0:0a841b89d614 3395 md = 0xF0;
AjK 0:0a841b89d614 3396 } else {
AjK 0:0a841b89d614 3397 DWORD n_disk = b_vol + n_vol;
AjK 0:0a841b89d614 3398
AjK 0:0a841b89d614 3399 mem_set(fs->win, 0, SS(fs));
AjK 0:0a841b89d614 3400 tbl = fs->win+MBR_Table;
AjK 0:0a841b89d614 3401 ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */
AjK 0:0a841b89d614 3402 if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
AjK 0:0a841b89d614 3403 n_disk = n_disk / 63 / 255;
AjK 0:0a841b89d614 3404 tbl[7] = (BYTE)n_disk;
AjK 0:0a841b89d614 3405 tbl[6] = (BYTE)((n_disk >> 2) | 63);
AjK 0:0a841b89d614 3406 } else {
AjK 0:0a841b89d614 3407 ST_WORD(&tbl[6], 0xFFFF);
AjK 0:0a841b89d614 3408 }
AjK 0:0a841b89d614 3409 tbl[5] = 254;
AjK 0:0a841b89d614 3410 if (fmt != FS_FAT32) /* System ID */
AjK 0:0a841b89d614 3411 tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06;
AjK 0:0a841b89d614 3412 else
AjK 0:0a841b89d614 3413 tbl[4] = 0x0c;
AjK 0:0a841b89d614 3414 ST_DWORD(tbl+8, 63); /* Partition start in LBA */
AjK 0:0a841b89d614 3415 ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
AjK 0:0a841b89d614 3416 ST_WORD(tbl+64, 0xAA55); /* Signature */
AjK 0:0a841b89d614 3417 if (disk_write(drv, fs->win, 0, 1) != RES_OK)
AjK 0:0a841b89d614 3418 return FR_DISK_ERR;
AjK 0:0a841b89d614 3419 md = 0xF8;
AjK 0:0a841b89d614 3420 }
AjK 0:0a841b89d614 3421
AjK 0:0a841b89d614 3422 /* Create volume boot record */
AjK 0:0a841b89d614 3423 tbl = fs->win; /* Clear sector */
AjK 0:0a841b89d614 3424 mem_set(tbl, 0, SS(fs));
AjK 0:0a841b89d614 3425 mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot code, OEM name */
AjK 0:0a841b89d614 3426 i = SS(fs); /* Sector size */
AjK 0:0a841b89d614 3427 ST_WORD(tbl+BPB_BytsPerSec, i);
AjK 0:0a841b89d614 3428 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
AjK 0:0a841b89d614 3429 ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
AjK 0:0a841b89d614 3430 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
AjK 0:0a841b89d614 3431 i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
AjK 0:0a841b89d614 3432 ST_WORD(tbl+BPB_RootEntCnt, i);
AjK 0:0a841b89d614 3433 if (n_vol < 0x10000) { /* Number of total sectors */
AjK 0:0a841b89d614 3434 ST_WORD(tbl+BPB_TotSec16, n_vol);
AjK 0:0a841b89d614 3435 } else {
AjK 0:0a841b89d614 3436 ST_DWORD(tbl+BPB_TotSec32, n_vol);
AjK 0:0a841b89d614 3437 }
AjK 0:0a841b89d614 3438 tbl[BPB_Media] = md; /* Media descriptor */
AjK 0:0a841b89d614 3439 ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
AjK 0:0a841b89d614 3440 ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
AjK 0:0a841b89d614 3441 ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
AjK 0:0a841b89d614 3442 n = get_fattime(); /* Use current time as VSN */
AjK 0:0a841b89d614 3443 if (fmt == FS_FAT32) {
AjK 0:0a841b89d614 3444 ST_DWORD(tbl+BS_VolID32, n); /* VSN */
AjK 0:0a841b89d614 3445 ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
AjK 0:0a841b89d614 3446 ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
AjK 0:0a841b89d614 3447 ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
AjK 0:0a841b89d614 3448 ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
AjK 0:0a841b89d614 3449 tbl[BS_DrvNum32] = 0x80; /* Drive number */
AjK 0:0a841b89d614 3450 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
AjK 0:0a841b89d614 3451 mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
AjK 0:0a841b89d614 3452 } else {
AjK 0:0a841b89d614 3453 ST_DWORD(tbl+BS_VolID, n); /* VSN */
AjK 0:0a841b89d614 3454 ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
AjK 0:0a841b89d614 3455 tbl[BS_DrvNum] = 0x80; /* Drive number */
AjK 0:0a841b89d614 3456 tbl[BS_BootSig] = 0x29; /* Extended boot signature */
AjK 0:0a841b89d614 3457 mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
AjK 0:0a841b89d614 3458 }
AjK 0:0a841b89d614 3459 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
AjK 0:0a841b89d614 3460 if (disk_write(drv, tbl, b_vol, 1) != RES_OK)/* Write original (VBR) */
AjK 0:0a841b89d614 3461 return FR_DISK_ERR;
AjK 0:0a841b89d614 3462 if (fmt == FS_FAT32) /* Write backup (VBR+6) */
AjK 0:0a841b89d614 3463 disk_write(drv, tbl, b_vol + 6, 1);
AjK 0:0a841b89d614 3464
AjK 0:0a841b89d614 3465 /* Initialize FAT area */
AjK 0:0a841b89d614 3466 wsect = b_fat;
AjK 0:0a841b89d614 3467 for (i = 0; i < N_FATS; i++) {
AjK 0:0a841b89d614 3468 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
AjK 0:0a841b89d614 3469 n = md; /* Media descriptor byte */
AjK 0:0a841b89d614 3470 if (fmt != FS_FAT32) {
AjK 0:0a841b89d614 3471 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
AjK 0:0a841b89d614 3472 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
AjK 0:0a841b89d614 3473 } else {
AjK 0:0a841b89d614 3474 n |= 0xFFFFFF00;
AjK 0:0a841b89d614 3475 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
AjK 0:0a841b89d614 3476 ST_DWORD(tbl+4, 0xFFFFFFFF);
AjK 0:0a841b89d614 3477 ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
AjK 0:0a841b89d614 3478 }
AjK 0:0a841b89d614 3479 if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
AjK 0:0a841b89d614 3480 return FR_DISK_ERR;
AjK 0:0a841b89d614 3481 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
AjK 0:0a841b89d614 3482 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector write */
AjK 0:0a841b89d614 3483 if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
AjK 0:0a841b89d614 3484 return FR_DISK_ERR;
AjK 0:0a841b89d614 3485 }
AjK 0:0a841b89d614 3486 }
AjK 0:0a841b89d614 3487
AjK 0:0a841b89d614 3488 /* Initialize root directory */
AjK 0:0a841b89d614 3489 i = (fmt == FS_FAT32) ? au : n_dir;
AjK 0:0a841b89d614 3490 do {
AjK 0:0a841b89d614 3491 if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
AjK 0:0a841b89d614 3492 return FR_DISK_ERR;
AjK 0:0a841b89d614 3493 } while (--i);
AjK 0:0a841b89d614 3494
AjK 0:0a841b89d614 3495 #if _USE_ERASE /* Erase data area if needed */
AjK 0:0a841b89d614 3496 {
AjK 0:0a841b89d614 3497 DWORD eb[2];
AjK 0:0a841b89d614 3498
AjK 0:0a841b89d614 3499 eb[0] = wsect; eb[1] = wsect + n_clst * au - 1;
AjK 0:0a841b89d614 3500 disk_ioctl(drv, CTRL_ERASE_SECTOR, eb);
AjK 0:0a841b89d614 3501 }
AjK 0:0a841b89d614 3502 #endif
AjK 0:0a841b89d614 3503
AjK 0:0a841b89d614 3504 /* Create FSInfo if needed */
AjK 0:0a841b89d614 3505 if (fmt == FS_FAT32) {
AjK 0:0a841b89d614 3506 ST_WORD(tbl+BS_55AA, 0xAA55);
AjK 0:0a841b89d614 3507 ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
AjK 0:0a841b89d614 3508 ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
AjK 0:0a841b89d614 3509 ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
AjK 0:0a841b89d614 3510 ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
AjK 0:0a841b89d614 3511 disk_write(drv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */
AjK 0:0a841b89d614 3512 disk_write(drv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */
AjK 0:0a841b89d614 3513 }
AjK 0:0a841b89d614 3514
AjK 0:0a841b89d614 3515 return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR;
AjK 0:0a841b89d614 3516 }
AjK 0:0a841b89d614 3517
AjK 0:0a841b89d614 3518 #endif /* _USE_MKFS && !_FS_READONLY */
AjK 0:0a841b89d614 3519
AjK 0:0a841b89d614 3520
AjK 0:0a841b89d614 3521
AjK 0:0a841b89d614 3522
AjK 0:0a841b89d614 3523 #if _USE_STRFUNC
AjK 0:0a841b89d614 3524 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3525 /* Get a string from the file */
AjK 0:0a841b89d614 3526 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3527 TCHAR* f_gets (
AjK 0:0a841b89d614 3528 TCHAR* buff, /* Pointer to the string buffer to read */
AjK 0:0a841b89d614 3529 int len, /* Size of string buffer (characters) */
AjK 0:0a841b89d614 3530 FIL* fil /* Pointer to the file object */
AjK 0:0a841b89d614 3531 )
AjK 0:0a841b89d614 3532 {
AjK 0:0a841b89d614 3533 int n = 0;
AjK 0:0a841b89d614 3534 TCHAR c, *p = buff;
AjK 0:0a841b89d614 3535 BYTE s[2];
AjK 0:0a841b89d614 3536 UINT rc;
AjK 0:0a841b89d614 3537
AjK 0:0a841b89d614 3538
AjK 0:0a841b89d614 3539 while (n < len - 1) { /* Read bytes until buffer gets filled */
AjK 0:0a841b89d614 3540 f_read(fil, s, 1, &rc);
AjK 0:0a841b89d614 3541 if (rc != 1) break; /* Break on EOF or error */
AjK 0:0a841b89d614 3542 c = s[0];
AjK 0:0a841b89d614 3543 #if _LFN_UNICODE /* Read a character in UTF-8 encoding */
AjK 0:0a841b89d614 3544 if (c >= 0x80) {
AjK 0:0a841b89d614 3545 if (c < 0xC0) continue; /* Skip stray trailer */
AjK 0:0a841b89d614 3546 if (c < 0xE0) { /* Two-byte sequense */
AjK 0:0a841b89d614 3547 f_read(fil, s, 1, &rc);
AjK 0:0a841b89d614 3548 if (rc != 1) break;
AjK 0:0a841b89d614 3549 c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
AjK 0:0a841b89d614 3550 if (c < 0x80) c = '?';
AjK 0:0a841b89d614 3551 } else {
AjK 0:0a841b89d614 3552 if (c < 0xF0) { /* Three-byte sequense */
AjK 0:0a841b89d614 3553 f_read(fil, s, 2, &rc);
AjK 0:0a841b89d614 3554 if (rc != 2) break;
AjK 0:0a841b89d614 3555 c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
AjK 0:0a841b89d614 3556 if (c < 0x800) c = '?';
AjK 0:0a841b89d614 3557 } else { /* Reject four-byte sequense */
AjK 0:0a841b89d614 3558 c = '?';
AjK 0:0a841b89d614 3559 }
AjK 0:0a841b89d614 3560 }
AjK 0:0a841b89d614 3561 }
AjK 0:0a841b89d614 3562 #endif
AjK 0:0a841b89d614 3563 #if _USE_STRFUNC >= 2
AjK 0:0a841b89d614 3564 if (c == '\r') continue; /* Strip '\r' */
AjK 0:0a841b89d614 3565 #endif
AjK 0:0a841b89d614 3566 *p++ = c;
AjK 0:0a841b89d614 3567 n++;
AjK 0:0a841b89d614 3568 if (c == '\n') break; /* Break on EOL */
AjK 0:0a841b89d614 3569 }
AjK 0:0a841b89d614 3570 *p = 0;
AjK 0:0a841b89d614 3571 return n ? buff : 0; /* When no data read (eof or error), return with error. */
AjK 0:0a841b89d614 3572 }
AjK 0:0a841b89d614 3573
AjK 0:0a841b89d614 3574
AjK 0:0a841b89d614 3575
AjK 0:0a841b89d614 3576 #if !_FS_READONLY
AjK 0:0a841b89d614 3577 #include <stdarg.h>
AjK 0:0a841b89d614 3578 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3579 /* Put a character to the file */
AjK 0:0a841b89d614 3580 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3581 int f_putc (
AjK 0:0a841b89d614 3582 TCHAR c, /* A character to be output */
AjK 0:0a841b89d614 3583 FIL* fil /* Pointer to the file object */
AjK 0:0a841b89d614 3584 )
AjK 0:0a841b89d614 3585 {
AjK 0:0a841b89d614 3586 UINT bw, btw;
AjK 0:0a841b89d614 3587 BYTE s[3];
AjK 0:0a841b89d614 3588
AjK 0:0a841b89d614 3589
AjK 0:0a841b89d614 3590 #if _USE_STRFUNC >= 2
AjK 0:0a841b89d614 3591 if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
AjK 0:0a841b89d614 3592 #endif
AjK 0:0a841b89d614 3593
AjK 0:0a841b89d614 3594 #if _LFN_UNICODE /* Write the character in UTF-8 encoding */
AjK 0:0a841b89d614 3595 if (c < 0x80) { /* 7-bit */
AjK 0:0a841b89d614 3596 s[0] = (BYTE)c;
AjK 0:0a841b89d614 3597 btw = 1;
AjK 0:0a841b89d614 3598 } else {
AjK 0:0a841b89d614 3599 if (c < 0x800) { /* 11-bit */
AjK 0:0a841b89d614 3600 s[0] = (BYTE)(0xC0 | (c >> 6));
AjK 0:0a841b89d614 3601 s[1] = (BYTE)(0x80 | (c & 0x3F));
AjK 0:0a841b89d614 3602 btw = 2;
AjK 0:0a841b89d614 3603 } else { /* 16-bit */
AjK 0:0a841b89d614 3604 s[0] = (BYTE)(0xE0 | (c >> 12));
AjK 0:0a841b89d614 3605 s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
AjK 0:0a841b89d614 3606 s[2] = (BYTE)(0x80 | (c & 0x3F));
AjK 0:0a841b89d614 3607 btw = 3;
AjK 0:0a841b89d614 3608 }
AjK 0:0a841b89d614 3609 }
AjK 0:0a841b89d614 3610 #else /* Write the character without conversion */
AjK 0:0a841b89d614 3611 s[0] = (BYTE)c;
AjK 0:0a841b89d614 3612 btw = 1;
AjK 0:0a841b89d614 3613 #endif
AjK 0:0a841b89d614 3614 f_write(fil, s, btw, &bw); /* Write the char to the file */
AjK 0:0a841b89d614 3615 return (bw == btw) ? 1 : EOF; /* Return the result */
AjK 0:0a841b89d614 3616 }
AjK 0:0a841b89d614 3617
AjK 0:0a841b89d614 3618
AjK 0:0a841b89d614 3619
AjK 0:0a841b89d614 3620
AjK 0:0a841b89d614 3621 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3622 /* Put a string to the file */
AjK 0:0a841b89d614 3623 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3624 int f_puts (
AjK 0:0a841b89d614 3625 const TCHAR* str, /* Pointer to the string to be output */
AjK 0:0a841b89d614 3626 FIL* fil /* Pointer to the file object */
AjK 0:0a841b89d614 3627 )
AjK 0:0a841b89d614 3628 {
AjK 0:0a841b89d614 3629 int n;
AjK 0:0a841b89d614 3630
AjK 0:0a841b89d614 3631
AjK 0:0a841b89d614 3632 for (n = 0; *str; str++, n++) {
AjK 0:0a841b89d614 3633 if (f_putc(*str, fil) == EOF) return EOF;
AjK 0:0a841b89d614 3634 }
AjK 0:0a841b89d614 3635 return n;
AjK 0:0a841b89d614 3636 }
AjK 0:0a841b89d614 3637
AjK 0:0a841b89d614 3638
AjK 0:0a841b89d614 3639
AjK 0:0a841b89d614 3640
AjK 0:0a841b89d614 3641 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3642 /* Put a formatted string to the file */
AjK 0:0a841b89d614 3643 /*-----------------------------------------------------------------------*/
AjK 0:0a841b89d614 3644 int f_printf (
AjK 0:0a841b89d614 3645 FIL* fil, /* Pointer to the file object */
AjK 0:0a841b89d614 3646 const TCHAR* str, /* Pointer to the format string */
AjK 0:0a841b89d614 3647 ... /* Optional arguments... */
AjK 0:0a841b89d614 3648 )
AjK 0:0a841b89d614 3649 {
AjK 0:0a841b89d614 3650 va_list arp;
AjK 0:0a841b89d614 3651 BYTE f, r;
AjK 0:0a841b89d614 3652 UINT i, w;
AjK 0:0a841b89d614 3653 ULONG val;
AjK 0:0a841b89d614 3654 TCHAR c, d, s[16];
AjK 0:0a841b89d614 3655 int res, cc;
AjK 0:0a841b89d614 3656
AjK 0:0a841b89d614 3657
AjK 0:0a841b89d614 3658 va_start(arp, str);
AjK 0:0a841b89d614 3659
AjK 0:0a841b89d614 3660 for (cc = res = 0; cc != EOF; res += cc) {
AjK 0:0a841b89d614 3661 c = *str++;
AjK 0:0a841b89d614 3662 if (c == 0) break; /* End of string */
AjK 0:0a841b89d614 3663 if (c != '%') { /* Non escape character */
AjK 0:0a841b89d614 3664 cc = f_putc(c, fil);
AjK 0:0a841b89d614 3665 if (cc != EOF) cc = 1;
AjK 0:0a841b89d614 3666 continue;
AjK 0:0a841b89d614 3667 }
AjK 0:0a841b89d614 3668 w = f = 0;
AjK 0:0a841b89d614 3669 c = *str++;
AjK 0:0a841b89d614 3670 if (c == '0') { /* Flag: '0' padding */
AjK 0:0a841b89d614 3671 f = 1; c = *str++;
AjK 0:0a841b89d614 3672 }
AjK 0:0a841b89d614 3673 while (IsDigit(c)) { /* Precision */
AjK 0:0a841b89d614 3674 w = w * 10 + c - '0';
AjK 0:0a841b89d614 3675 c = *str++;
AjK 0:0a841b89d614 3676 }
AjK 0:0a841b89d614 3677 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
AjK 0:0a841b89d614 3678 f |= 2; c = *str++;
AjK 0:0a841b89d614 3679 }
AjK 0:0a841b89d614 3680 if (!c) break;
AjK 0:0a841b89d614 3681 d = c;
AjK 0:0a841b89d614 3682 if (IsLower(d)) d -= 0x20;
AjK 0:0a841b89d614 3683 switch (d) { /* Type is... */
AjK 0:0a841b89d614 3684 case 'S' : /* String */
AjK 0:0a841b89d614 3685 cc = f_puts(va_arg(arp, TCHAR*), fil); continue;
AjK 0:0a841b89d614 3686 case 'C' : /* Character */
AjK 0:0a841b89d614 3687 cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
AjK 0:0a841b89d614 3688 case 'B' : /* Binary */
AjK 0:0a841b89d614 3689 r = 2; break;
AjK 0:0a841b89d614 3690 case 'O' : /* Octal */
AjK 0:0a841b89d614 3691 r = 8; break;
AjK 0:0a841b89d614 3692 case 'D' : /* Signed decimal */
AjK 0:0a841b89d614 3693 case 'U' : /* Unsigned decimal */
AjK 0:0a841b89d614 3694 r = 10; break;
AjK 0:0a841b89d614 3695 case 'X' : /* Hexdecimal */
AjK 0:0a841b89d614 3696 r = 16; break;
AjK 0:0a841b89d614 3697 default: /* Unknown */
AjK 0:0a841b89d614 3698 cc = f_putc(c, fil); continue;
AjK 0:0a841b89d614 3699 }
AjK 0:0a841b89d614 3700
AjK 0:0a841b89d614 3701 /* Get an argument */
AjK 0:0a841b89d614 3702 val = (f & 2) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int));
AjK 0:0a841b89d614 3703 if (d == 'D' && (val & 0x80000000)) {
AjK 0:0a841b89d614 3704 val = 0 - val;
AjK 0:0a841b89d614 3705 f |= 4;
AjK 0:0a841b89d614 3706 }
AjK 0:0a841b89d614 3707 /* Put it in numeral string */
AjK 0:0a841b89d614 3708 i = 0;
AjK 0:0a841b89d614 3709 do {
AjK 0:0a841b89d614 3710 d = (TCHAR)(val % r); val /= r;
AjK 0:0a841b89d614 3711 if (d > 9) {
AjK 0:0a841b89d614 3712 d += 7;
AjK 0:0a841b89d614 3713 if (c == 'x') d += 0x20;
AjK 0:0a841b89d614 3714 }
AjK 0:0a841b89d614 3715 s[i++] = d + '0';
AjK 0:0a841b89d614 3716 } while (val && i < sizeof(s) / sizeof(s[0]));
AjK 0:0a841b89d614 3717 if (f & 4) s[i++] = '-';
AjK 0:0a841b89d614 3718 cc = 0;
AjK 0:0a841b89d614 3719 while (i < w-- && cc != EOF) {
AjK 0:0a841b89d614 3720 cc = f_putc((TCHAR)((f & 1) ? '0' : ' '), fil);
AjK 0:0a841b89d614 3721 res++;
AjK 0:0a841b89d614 3722 }
AjK 0:0a841b89d614 3723 do {
AjK 0:0a841b89d614 3724 cc = f_putc(s[--i], fil);
AjK 0:0a841b89d614 3725 res++;
AjK 0:0a841b89d614 3726 } while (i && cc != EOF);
AjK 0:0a841b89d614 3727 if (cc != EOF) cc = 0;
AjK 0:0a841b89d614 3728 }
AjK 0:0a841b89d614 3729
AjK 0:0a841b89d614 3730 va_end(arp);
AjK 0:0a841b89d614 3731 return (cc == EOF) ? cc : res;
AjK 0:0a841b89d614 3732 }
AjK 0:0a841b89d614 3733
AjK 0:0a841b89d614 3734 #endif /* !_FS_READONLY */
AjK 0:0a841b89d614 3735 #endif /* _USE_STRFUNC */