00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 #include "ff.h"
00080 #include "diskio.h"
00081
00082
00083
00084
00085
00086
00087
00088 #if _FATFS != 0x007E
00089 #error Wrong include file (ff.h).
00090 #endif
00091
00092 #if _FS_REENTRANT
00093 #if _USE_LFN == 1
00094 #error Static LFN work area must not be used in re-entrant configuration.
00095 #endif
00096 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
00097 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
00098
00099 #else
00100 #define ENTER_FF(fs)
00101 #define LEAVE_FF(fs, res) return res
00102
00103 #endif
00104
00105 #define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
00106
00107 #ifndef NULL
00108 #define NULL 0
00109 #endif
00110
00111
00112 #define NS 11
00113 #define NS_LOSS 0x01
00114 #define NS_LFN 0x02
00115 #define NS_LAST 0x04
00116 #define NS_BODY 0x08
00117 #define NS_EXT 0x10
00118 #define NS_DOT 0x20
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 #if _DRIVES < 1 || _DRIVES > 9
00130 #error Number of drives must be 1-9.
00131 #endif
00132 static
00133 FATFS *FatFs[_DRIVES];
00134
00135 static
00136 WORD Fsid;
00137
00138 #if _FS_RPATH
00139 static
00140 BYTE Drive;
00141 #endif
00142
00143
00144 #if _USE_LFN == 1
00145 static
00146 WCHAR LfnBuf[_MAX_LFN + 1];
00147 #define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR *lp = LfnBuf
00148 #define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
00149
00150 #elif _USE_LFN > 1
00151 #define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR lbuf[_MAX_LFN + 1], *lp = lbuf
00152 #define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
00153
00154 #else
00155 #define NAMEBUF(sp,lp) BYTE sp[12]
00156 #define INITBUF(dj,sp,lp) dj.fn = sp
00157
00158 #endif
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 static
00176 void mem_cpy (void* dst, const void* src, int cnt) {
00177 char *d = (char*)dst;
00178 const char *s = (const char *)src;
00179 while (cnt--) *d++ = *s++;
00180 }
00181
00182
00183 static
00184 void mem_set (void* dst, int val, int cnt) {
00185 char *d = (char*)dst;
00186 while (cnt--) *d++ = (char)val;
00187 }
00188
00189
00190 static
00191 int mem_cmp (const void* dst, const void* src, int cnt) {
00192 const char *d = (const char *)dst, *s = (const char *)src;
00193 int r = 0;
00194 while (cnt-- && (r = *d++ - *s++) == 0) ;
00195 return r;
00196 }
00197
00198
00199 static
00200 int chk_chr (const char* str, int chr) {
00201 while (*str && *str != chr) str++;
00202 return *str;
00203 }
00204
00205
00206
00207
00208
00209
00210 #if _FS_REENTRANT
00211
00212 static
00213 BOOL lock_fs (
00214 FATFS *fs
00215 )
00216 {
00217 return ff_req_grant(fs->sobj);
00218 }
00219
00220
00221 static
00222 void unlock_fs (
00223 FATFS *fs,
00224 FRESULT res
00225 )
00226 {
00227 if (res != FR_NOT_ENABLED &&
00228 res != FR_INVALID_DRIVE &&
00229 res != FR_INVALID_OBJECT &&
00230 res != FR_TIMEOUT) {
00231 ff_rel_grant(fs->sobj);
00232 }
00233 }
00234 #endif
00235
00236
00237
00238
00239
00240
00241
00242 static
00243 FRESULT move_window (
00244 FATFS *fs,
00245 DWORD sector
00246 )
00247 {
00248 DWORD wsect;
00249
00250
00251 wsect = fs->winsect;
00252 if (wsect != sector) {
00253 #if !_FS_READONLY
00254 if (fs->wflag) {
00255 if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
00256 return FR_DISK_ERR;
00257 fs->wflag = 0;
00258 if (wsect < (fs->fatbase + fs->sects_fat)) {
00259 BYTE nf;
00260 for (nf = fs->n_fats; nf > 1; nf--) {
00261 wsect += fs->sects_fat;
00262 disk_write(fs->drive, fs->win, wsect, 1);
00263 }
00264 }
00265 }
00266 #endif
00267 if (sector) {
00268 if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
00269 return FR_DISK_ERR;
00270 fs->winsect = sector;
00271 }
00272 }
00273
00274 return FR_OK;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283 #if !_FS_READONLY
00284 static
00285 FRESULT sync (
00286 FATFS *fs
00287 )
00288 {
00289 FRESULT res;
00290
00291
00292 res = move_window(fs, 0);
00293 if (res == FR_OK) {
00294
00295 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
00296 fs->winsect = 0;
00297 mem_set(fs->win, 0, 512);
00298 ST_WORD(fs->win+BS_55AA, 0xAA55);
00299 ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
00300 ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
00301 ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
00302 ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
00303 disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
00304 fs->fsi_flag = 0;
00305 }
00306
00307 if (disk_ioctl(fs->drive, CTRL_SYNC, (void*)NULL) != RES_OK)
00308 res = FR_DISK_ERR;
00309 }
00310
00311 return res;
00312 }
00313 #endif
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 DWORD get_fat (
00324 FATFS *fs,
00325 DWORD clst
00326 )
00327 {
00328 UINT wc, bc;
00329 DWORD fsect;
00330
00331
00332 if (clst < 2 || clst >= fs->max_clust)
00333 return 1;
00334
00335 fsect = fs->fatbase;
00336 switch (fs->fs_type) {
00337 case FS_FAT12 :
00338 bc = clst; bc += bc / 2;
00339 if (move_window(fs, fsect + (bc / SS(fs)))) break;
00340 wc = fs->win[bc & (SS(fs) - 1)]; bc++;
00341 if (move_window(fs, fsect + (bc / SS(fs)))) break;
00342 wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
00343 return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
00344
00345 case FS_FAT16 :
00346 if (move_window(fs, fsect + (clst / (SS(fs) / 2)))) break;
00347 return LD_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)]);
00348
00349 case FS_FAT32 :
00350 if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break;
00351 return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
00352 }
00353
00354 return 0xFFFFFFFF;
00355 }
00356
00357
00358
00359
00360
00361
00362
00363 #if !_FS_READONLY
00364
00365 FRESULT put_fat (
00366 FATFS *fs,
00367 DWORD clst,
00368 DWORD val
00369 )
00370 {
00371 UINT bc;
00372 BYTE *p;
00373 DWORD fsect;
00374 FRESULT res;
00375
00376
00377 if (clst < 2 || clst >= fs->max_clust) {
00378 res = FR_INT_ERR;
00379
00380 } else {
00381 fsect = fs->fatbase;
00382 switch (fs->fs_type) {
00383 case FS_FAT12 :
00384 bc = clst; bc += bc / 2;
00385 res = move_window(fs, fsect + (bc / SS(fs)));
00386 if (res != FR_OK) break;
00387 p = &fs->win[bc & (SS(fs) - 1)];
00388 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
00389 bc++;
00390 fs->wflag = 1;
00391 res = move_window(fs, fsect + (bc / SS(fs)));
00392 if (res != FR_OK) break;
00393 p = &fs->win[bc & (SS(fs) - 1)];
00394 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
00395 break;
00396
00397 case FS_FAT16 :
00398 res = move_window(fs, fsect + (clst / (SS(fs) / 2)));
00399 if (res != FR_OK) break;
00400 ST_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)], (WORD)val);
00401 break;
00402
00403 case FS_FAT32 :
00404 res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
00405 if (res != FR_OK) break;
00406 ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
00407 break;
00408
00409 default :
00410 res = FR_INT_ERR;
00411 }
00412 fs->wflag = 1;
00413 }
00414
00415 return res;
00416 }
00417 #endif
00418
00419
00420
00421
00422
00423
00424
00425 #if !_FS_READONLY
00426 static
00427 FRESULT remove_chain (
00428 FATFS *fs,
00429 DWORD clst
00430 )
00431 {
00432 FRESULT res;
00433 DWORD nxt;
00434
00435
00436 if (clst < 2 || clst >= fs->max_clust) {
00437 res = FR_INT_ERR;
00438
00439 } else {
00440 res = FR_OK;
00441 while (clst < fs->max_clust) {
00442 nxt = get_fat(fs, clst);
00443 if (nxt == 0) break;
00444 if (nxt == 1) { res = FR_INT_ERR; break; }
00445 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
00446 res = put_fat(fs, clst, 0);
00447 if (res != FR_OK) break;
00448 if (fs->free_clust != 0xFFFFFFFF) {
00449 fs->free_clust++;
00450 fs->fsi_flag = 1;
00451 }
00452 clst = nxt;
00453 }
00454 }
00455
00456 return res;
00457 }
00458 #endif
00459
00460
00461
00462
00463
00464
00465
00466 #if !_FS_READONLY
00467 static
00468 DWORD create_chain (
00469 FATFS *fs,
00470 DWORD clst
00471 )
00472 {
00473 DWORD cs, ncl, scl, mcl;
00474
00475
00476 mcl = fs->max_clust;
00477 if (clst == 0) {
00478 scl = fs->last_clust;
00479 if (scl == 0 || scl >= mcl) scl = 1;
00480 }
00481 else {
00482 cs = get_fat(fs, clst);
00483 if (cs < 2) return 1;
00484 if (cs < mcl) return cs;
00485 scl = clst;
00486 }
00487
00488 ncl = scl;
00489 for (;;) {
00490 ncl++;
00491 if (ncl >= mcl) {
00492 ncl = 2;
00493 if (ncl > scl) return 0;
00494 }
00495 cs = get_fat(fs, ncl);
00496 if (cs == 0) break;
00497 if (cs == 0xFFFFFFFF || cs == 1)
00498 return cs;
00499 if (ncl == scl) return 0;
00500 }
00501
00502 if (put_fat(fs, ncl, 0x0FFFFFFF))
00503 return 0xFFFFFFFF;
00504 if (clst != 0) {
00505 if (put_fat(fs, clst, ncl))
00506 return 0xFFFFFFFF;
00507 }
00508
00509 fs->last_clust = ncl;
00510 if (fs->free_clust != 0xFFFFFFFF) {
00511 fs->free_clust--;
00512 fs->fsi_flag = 1;
00513 }
00514
00515 return ncl;
00516 }
00517 #endif
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 DWORD clust2sect (
00528 FATFS *fs,
00529 DWORD clst
00530 )
00531 {
00532 clst -= 2;
00533 if (clst >= (fs->max_clust - 2)) return 0;
00534 return clst * fs->csize + fs->database;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 static
00545 FRESULT dir_seek (
00546 DIR *dj,
00547 WORD idx
00548 )
00549 {
00550 DWORD clst;
00551 WORD ic;
00552
00553
00554 dj->index = idx;
00555 clst = dj->sclust;
00556 if (clst == 1 || clst >= dj->fs->max_clust)
00557 return FR_INT_ERR;
00558 if (!clst && dj->fs->fs_type == FS_FAT32)
00559 clst = dj->fs->dirbase;
00560
00561 if (clst == 0) {
00562 dj->clust = clst;
00563 if (idx >= dj->fs->n_rootdir)
00564 return FR_INT_ERR;
00565 dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32);
00566 }
00567 else {
00568 ic = SS(dj->fs) / 32 * dj->fs->csize;
00569 while (idx >= ic) {
00570 clst = get_fat(dj->fs, clst);
00571 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
00572 if (clst < 2 || clst >= dj->fs->max_clust)
00573 return FR_INT_ERR;
00574 idx -= ic;
00575 }
00576 dj->clust = clst;
00577 dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32);
00578 }
00579
00580 dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32;
00581
00582 return FR_OK;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592 static
00593 FRESULT dir_next (
00594 DIR *dj,
00595 BOOL streach
00596 )
00597 {
00598 DWORD clst;
00599 WORD i;
00600
00601
00602 i = dj->index + 1;
00603 if (!i || !dj->sect)
00604 return FR_NO_FILE;
00605
00606 if (!(i % (SS(dj->fs) / 32))) {
00607 dj->sect++;
00608
00609 if (dj->clust == 0) {
00610 if (i >= dj->fs->n_rootdir)
00611 return FR_NO_FILE;
00612 }
00613 else {
00614 if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) {
00615 clst = get_fat(dj->fs, dj->clust);
00616 if (clst <= 1) return FR_INT_ERR;
00617 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
00618 if (clst >= dj->fs->max_clust) {
00619 #if !_FS_READONLY
00620 BYTE c;
00621 if (!streach) return FR_NO_FILE;
00622 clst = create_chain(dj->fs, dj->clust);
00623 if (clst == 0) return FR_DENIED;
00624 if (clst == 1) return FR_INT_ERR;
00625 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
00626
00627 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
00628 mem_set(dj->fs->win, 0, SS(dj->fs));
00629 dj->fs->winsect = clust2sect(dj->fs, clst);
00630 for (c = 0; c < dj->fs->csize; c++) {
00631 dj->fs->wflag = 1;
00632 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
00633 dj->fs->winsect++;
00634 }
00635 dj->fs->winsect -= c;
00636 #else
00637 return FR_NO_FILE;
00638 #endif
00639 }
00640 dj->clust = clst;
00641 dj->sect = clust2sect(dj->fs, clst);
00642 }
00643 }
00644 }
00645
00646 dj->index = i;
00647 dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
00648
00649 return FR_OK;
00650 }
00651
00652
00653
00654
00655
00656
00657
00658 #if _USE_LFN
00659 static
00660 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};
00661
00662
00663 static
00664 BOOL cmp_lfn (
00665 WCHAR *lfnbuf,
00666 BYTE *dir
00667 )
00668 {
00669 int i, s;
00670 WCHAR wc, uc;
00671
00672
00673 i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13;
00674 s = 0; wc = 1;
00675 do {
00676 uc = LD_WORD(dir+LfnOfs[s]);
00677 if (wc) {
00678 wc = ff_wtoupper(uc);
00679 if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]))
00680 return FALSE;
00681 } else {
00682 if (uc != 0xFFFF) return FALSE;
00683 }
00684 } while (++s < 13);
00685
00686 if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i])
00687 return FALSE;
00688
00689 return TRUE;
00690 }
00691
00692
00693
00694 static
00695 BOOL pick_lfn (
00696 WCHAR *lfnbuf,
00697 BYTE *dir
00698 )
00699 {
00700 int i, s;
00701 WCHAR wc, uc;
00702
00703
00704 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;
00705
00706 s = 0; wc = 1;
00707 do {
00708 uc = LD_WORD(dir+LfnOfs[s]);
00709 if (wc) {
00710 if (i >= _MAX_LFN) return FALSE;
00711 lfnbuf[i++] = wc = uc;
00712 } else {
00713 if (uc != 0xFFFF) return FALSE;
00714 }
00715 } while (++s < 13);
00716
00717 if (dir[LDIR_Ord] & 0x40) {
00718 if (i >= _MAX_LFN) return FALSE;
00719 lfnbuf[i] = 0;
00720 }
00721
00722 return TRUE;
00723 }
00724
00725
00726 #if !_FS_READONLY
00727 static
00728 void fit_lfn (
00729 const WCHAR *lfnbuf,
00730 BYTE *dir,
00731 BYTE ord,
00732 BYTE sum
00733 )
00734 {
00735 int i, s;
00736 WCHAR wc;
00737
00738
00739 dir[LDIR_Chksum] = sum;
00740 dir[LDIR_Attr] = AM_LFN;
00741 dir[LDIR_Type] = 0;
00742 ST_WORD(dir+LDIR_FstClusLO, 0);
00743
00744 i = (ord - 1) * 13;
00745 s = wc = 0;
00746 do {
00747 if (wc != 0xFFFF) wc = lfnbuf[i++];
00748 ST_WORD(dir+LfnOfs[s], wc);
00749 if (!wc) wc = 0xFFFF;
00750 } while (++s < 13);
00751 if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40;
00752 dir[LDIR_Ord] = ord;
00753 }
00754
00755 #endif
00756 #endif
00757
00758
00759
00760
00761
00762
00763 #if _USE_LFN
00764 void gen_numname (
00765 BYTE *dst,
00766 const BYTE *src,
00767 const WCHAR *lfn,
00768 WORD num
00769 )
00770 {
00771 char ns[8];
00772 int i, j;
00773
00774
00775 mem_cpy(dst, src, 11);
00776
00777 if (num > 5) {
00778 do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
00779 }
00780
00781
00782 i = 7;
00783 do {
00784 ns[i--] = (num % 10) + '0';
00785 num /= 10;
00786 } while (num);
00787 ns[i] = '~';
00788
00789
00790 for (j = 0; j < i && dst[j] != ' '; j++) {
00791 if (IsDBCS1(dst[j])) {
00792 if (j == i - 1) break;
00793 j++;
00794 }
00795 }
00796 do {
00797 dst[j++] = (i < 8) ? ns[i++] : ' ';
00798 } while (j < 8);
00799 }
00800 #endif
00801
00802
00803
00804
00805
00806
00807
00808 #if _USE_LFN
00809 static
00810 BYTE sum_sfn (
00811 const BYTE *dir
00812 )
00813 {
00814 BYTE sum = 0;
00815 int n = 11;
00816
00817 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
00818 return sum;
00819 }
00820 #endif
00821
00822
00823
00824
00825
00826
00827
00828
00829 static
00830 FRESULT dir_find (
00831 DIR *dj
00832 )
00833 {
00834 FRESULT res;
00835 BYTE c, *dir;
00836 #if _USE_LFN
00837 BYTE a, ord, sum;
00838 #endif
00839
00840 res = dir_seek(dj, 0);
00841 if (res != FR_OK) return res;
00842
00843 #if _USE_LFN
00844 ord = sum = 0xFF;
00845 #endif
00846 do {
00847 res = move_window(dj->fs, dj->sect);
00848 if (res != FR_OK) break;
00849 dir = dj->dir;
00850 c = dir[DIR_Name];
00851 if (c == 0) { res = FR_NO_FILE; break; }
00852 #if _USE_LFN
00853 a = dir[DIR_Attr] & AM_MASK;
00854 if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) {
00855 ord = 0xFF;
00856 } else {
00857 if (a == AM_LFN) {
00858 if (dj->lfn) {
00859 if (c & 0x40) {
00860 sum = dir[LDIR_Chksum];
00861 c &= 0xBF; ord = c;
00862 dj->lfn_idx = dj->index;
00863 }
00864
00865 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
00866 }
00867 } else {
00868 if (!ord && sum == sum_sfn(dir)) break;
00869 ord = 0xFF; dj->lfn_idx = 0xFFFF;
00870 if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break;
00871 }
00872 }
00873 #else
00874 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11))
00875 break;
00876 #endif
00877 res = dir_next(dj, FALSE);
00878 } while (res == FR_OK);
00879
00880 return res;
00881 }
00882
00883
00884
00885
00886
00887
00888
00889 #if _FS_MINIMIZE <= 1
00890 static
00891 FRESULT dir_read (
00892 DIR *dj
00893 )
00894 {
00895 FRESULT res;
00896 BYTE c, *dir;
00897 #if _USE_LFN
00898 BYTE a, ord = 0xFF, sum = 0xFF;
00899 #endif
00900
00901 res = FR_NO_FILE;
00902 while (dj->sect) {
00903 res = move_window(dj->fs, dj->sect);
00904 if (res != FR_OK) break;
00905 dir = dj->dir;
00906 c = dir[DIR_Name];
00907 if (c == 0) { res = FR_NO_FILE; break; }
00908 #if _USE_LFN
00909 a = dir[DIR_Attr] & AM_MASK;
00910 if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) {
00911 ord = 0xFF;
00912 } else {
00913 if (a == AM_LFN) {
00914 if (c & 0x40) {
00915 sum = dir[LDIR_Chksum];
00916 c &= 0xBF; ord = c;
00917 dj->lfn_idx = dj->index;
00918 }
00919
00920 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
00921 } else {
00922 if (ord || sum != sum_sfn(dir))
00923 dj->lfn_idx = 0xFFFF;
00924 break;
00925 }
00926 }
00927 #else
00928 if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))
00929 break;
00930 #endif
00931 res = dir_next(dj, FALSE);
00932 if (res != FR_OK) break;
00933 }
00934
00935 if (res != FR_OK) dj->sect = 0;
00936
00937 return res;
00938 }
00939 #endif
00940
00941
00942
00943
00944
00945
00946 #if !_FS_READONLY
00947 static
00948 FRESULT dir_register (
00949 DIR *dj
00950 )
00951 {
00952 FRESULT res;
00953 BYTE c, *dir;
00954 #if _USE_LFN
00955 WORD n, ne, is;
00956 BYTE sn[12], *fn, sum;
00957 WCHAR *lfn;
00958
00959
00960 fn = dj->fn; lfn = dj->lfn;
00961 mem_cpy(sn, fn, 12);
00962
00963 if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME;
00964
00965 if (sn[NS] & NS_LOSS) {
00966 fn[NS] = 0; dj->lfn = NULL;
00967 for (n = 1; n < 100; n++) {
00968 gen_numname(fn, sn, lfn, n);
00969 res = dir_find(dj);
00970 if (res != FR_OK) break;
00971 }
00972 if (n == 100) return FR_DENIED;
00973 if (res != FR_NO_FILE) return res;
00974 fn[NS] = sn[NS]; dj->lfn = lfn;
00975 }
00976
00977 if (sn[NS] & NS_LFN) {
00978 for (ne = 0; lfn[ne]; ne++) ;
00979 ne = (ne + 25) / 13;
00980 } else {
00981 ne = 1;
00982 }
00983
00984
00985 res = dir_seek(dj, 0);
00986 if (res != FR_OK) return res;
00987 n = is = 0;
00988 do {
00989 res = move_window(dj->fs, dj->sect);
00990 if (res != FR_OK) break;
00991 c = *dj->dir;
00992 if (c == 0xE5 || c == 0) {
00993 if (n == 0) is = dj->index;
00994 if (++n == ne) break;
00995 } else {
00996 n = 0;
00997 }
00998 res = dir_next(dj, TRUE);
00999 } while (res == FR_OK);
01000
01001 if (res == FR_OK && ne > 1) {
01002 res = dir_seek(dj, is);
01003 if (res == FR_OK) {
01004 sum = sum_sfn(dj->fn);
01005 ne--;
01006 do {
01007 res = move_window(dj->fs, dj->sect);
01008 if (res != FR_OK) break;
01009 fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
01010 dj->fs->wflag = 1;
01011 res = dir_next(dj, FALSE);
01012 } while (res == FR_OK && --ne);
01013 }
01014 }
01015
01016 #else
01017 res = dir_seek(dj, 0);
01018 if (res == FR_OK) {
01019 do {
01020 res = move_window(dj->fs, dj->sect);
01021 if (res != FR_OK) break;
01022 c = *dj->dir;
01023 if (c == 0xE5 || c == 0) break;
01024 res = dir_next(dj, TRUE);
01025 } while (res == FR_OK);
01026 }
01027 #endif
01028
01029 if (res == FR_OK) {
01030 res = move_window(dj->fs, dj->sect);
01031 if (res == FR_OK) {
01032 dir = dj->dir;
01033 mem_set(dir, 0, 32);
01034 mem_cpy(dir, dj->fn, 11);
01035 dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);
01036 dj->fs->wflag = 1;
01037 }
01038 }
01039
01040 return res;
01041 }
01042 #endif
01043
01044
01045
01046
01047
01048
01049
01050 #if !_FS_READONLY && !_FS_MINIMIZE
01051 static
01052 FRESULT dir_remove (
01053 DIR *dj
01054 )
01055 {
01056 FRESULT res;
01057 #if _USE_LFN
01058 WORD i;
01059
01060 i = dj->index;
01061 res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));
01062 if (res == FR_OK) {
01063 do {
01064 res = move_window(dj->fs, dj->sect);
01065 if (res != FR_OK) break;
01066 *dj->dir = 0xE5;
01067 dj->fs->wflag = 1;
01068 if (dj->index >= i) break;
01069 res = dir_next(dj, FALSE);
01070 } while (res == FR_OK);
01071 if (res == FR_NO_FILE) res = FR_INT_ERR;
01072 }
01073
01074 #else
01075 res = dir_seek(dj, dj->index);
01076 if (res == FR_OK) {
01077 res = move_window(dj->fs, dj->sect);
01078 if (res == FR_OK) {
01079 *dj->dir = 0xE5;
01080 dj->fs->wflag = 1;
01081 }
01082 }
01083 #endif
01084
01085 return res;
01086 }
01087 #endif
01088
01089
01090
01091
01092
01093
01094
01095
01096 static
01097 FRESULT create_name (
01098 DIR *dj,
01099 const XCHAR **path
01100 )
01101 {
01102 #ifdef _EXCVT
01103 static const BYTE cvt[] = _EXCVT;
01104 #endif
01105
01106 #if _USE_LFN
01107 BYTE b, cf;
01108 WCHAR w, *lfn;
01109 int i, ni, si, di;
01110 const XCHAR *p;
01111
01112
01113 si = di = 0;
01114 p = *path;
01115 lfn = dj->lfn;
01116 for (;;) {
01117 w = p[si++];
01118 if (w < ' ' || w == '/' || w == '\\') break;
01119 if (di >= _MAX_LFN)
01120 return FR_INVALID_NAME;
01121 #if !_LFN_UNICODE
01122 w &= 0xFF;
01123 if (IsDBCS1(w)) {
01124 b = p[si++];
01125 if (!IsDBCS2(b))
01126 return FR_INVALID_NAME;
01127 w = (w << 8) + b;
01128 }
01129 w = ff_convert(w, 1);
01130 if (!w) return FR_INVALID_NAME;
01131 #endif
01132 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w))
01133 return FR_INVALID_NAME;
01134 lfn[di++] = w;
01135 }
01136 *path = &p[si];
01137 cf = (w < ' ') ? NS_LAST : 0;
01138 #if _FS_RPATH
01139 if ((di == 1 && lfn[di - 1] == '.') ||
01140 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
01141 lfn[di] = 0;
01142 for (i = 0; i < 11; i++)
01143 dj->fn[i] = (i < di) ? '.' : ' ';
01144 dj->fn[i] = cf | NS_DOT;
01145 return FR_OK;
01146 }
01147 #endif
01148 while (di) {
01149 w = lfn[di - 1];
01150 if (w != ' ' && w != '.') break;
01151 di--;
01152 }
01153 if (!di) return FR_INVALID_NAME;
01154
01155 lfn[di] = 0;
01156
01157
01158 mem_set(dj->fn, ' ', 11);
01159 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;
01160 if (si) cf |= NS_LOSS | NS_LFN;
01161 while (di && lfn[di - 1] != '.') di--;
01162
01163 b = i = 0; ni = 8;
01164 for (;;) {
01165 w = lfn[si++];
01166 if (!w) break;
01167 if (w == ' ' || (w == '.' && si != di)) {
01168 cf |= NS_LOSS | NS_LFN; continue;
01169 }
01170
01171 if (i >= ni || si == di) {
01172 if (ni == 11) {
01173 cf |= NS_LOSS | NS_LFN; break;
01174 }
01175 if (si != di) cf |= NS_LOSS | NS_LFN;
01176 if (si > di) break;
01177 si = di; i = 8; ni = 11;
01178 b <<= 2; continue;
01179 }
01180
01181 if (w >= 0x80) {
01182 #ifdef _EXCVT
01183 w = ff_convert(w, 0);
01184 if (w) w = cvt[w - 0x80];
01185 #else
01186 w = ff_convert(ff_wtoupper(w), 0);
01187 #endif
01188 cf |= NS_LFN;
01189 }
01190
01191 if (_DF1S && w >= 0x100) {
01192 if (i >= ni - 1) {
01193 cf |= NS_LOSS | NS_LFN; i = ni; continue;
01194 }
01195 dj->fn[i++] = (BYTE)(w >> 8);
01196 } else {
01197 if (!w || chk_chr("+,;[=]", w)) {
01198 w = '_'; cf |= NS_LOSS | NS_LFN;
01199 } else {
01200 if (IsUpper(w)) {
01201 b |= 2;
01202 } else {
01203 if (IsLower(w)) {
01204 b |= 1; w -= 0x20;
01205 }
01206 }
01207 }
01208 }
01209 dj->fn[i++] = (BYTE)w;
01210 }
01211
01212 if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05;
01213
01214 if (ni == 8) b <<= 2;
01215 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03)
01216 cf |= NS_LFN;
01217 if (!(cf & NS_LFN)) {
01218 if ((b & 0x03) == 0x01) cf |= NS_EXT;
01219 if ((b & 0x0C) == 0x04) cf |= NS_BODY;
01220 }
01221
01222 dj->fn[NS] = cf;
01223
01224 return FR_OK;
01225
01226
01227 #else
01228 BYTE b, c, d, *sfn;
01229 int ni, si, i;
01230 const char *p;
01231
01232
01233 sfn = dj->fn;
01234 mem_set(sfn, ' ', 11);
01235 si = i = b = 0; ni = 8;
01236 p = *path;
01237 #if _FS_RPATH
01238 if (p[si] == '.') {
01239 for (;;) {
01240 c = p[si++];
01241 if (c != '.' || si >= 3) break;
01242 sfn[i++] = c;
01243 }
01244 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
01245 *path = &p[si];
01246 sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;
01247 return FR_OK;
01248 }
01249 #endif
01250 for (;;) {
01251 c = p[si++];
01252 if (c <= ' ' || c == '/' || c == '\\') break;
01253 if (c == '.' || i >= ni) {
01254 if (ni != 8 || c != '.') return FR_INVALID_NAME;
01255 i = 8; ni = 11;
01256 b <<= 2; continue;
01257 }
01258 if (c >= 0x80) {
01259 #ifdef _EXCVT
01260 c = cvt[c - 0x80];
01261 #else
01262 b |= 3;
01263 #if !_DF1S
01264 return FR_INVALID_NAME;
01265 #endif
01266 #endif
01267 }
01268 if (IsDBCS1(c)) {
01269 d = p[si++];
01270 if (!IsDBCS2(d) || i >= ni - 1)
01271 return FR_INVALID_NAME;
01272 sfn[i++] = c;
01273 sfn[i++] = d;
01274 } else {
01275 if (chk_chr(" \"*+,[=]|\x7F", c))
01276 return FR_INVALID_NAME;
01277 if (IsUpper(c)) {
01278 b |= 2;
01279 } else {
01280 if (IsLower(c)) {
01281 b |= 1; c -= 0x20;
01282 }
01283 }
01284 sfn[i++] = c;
01285 }
01286 }
01287 *path = &p[si];
01288 c = (c <= ' ') ? NS_LAST : 0;
01289
01290 if (!i) return FR_INVALID_NAME;
01291 if (sfn[0] == 0xE5) sfn[0] = 0x05;
01292
01293 if (ni == 8) b <<= 2;
01294 if ((b & 0x03) == 0x01) c |= NS_EXT;
01295 if ((b & 0x0C) == 0x04) c |= NS_BODY;
01296
01297 sfn[NS] = c;
01298
01299 return FR_OK;
01300 #endif
01301 }
01302
01303
01304
01305
01306
01307
01308
01309 #if _FS_MINIMIZE <= 1
01310 static
01311 void get_fileinfo (
01312 DIR *dj,
01313 FILINFO *fno
01314 )
01315 {
01316 int i;
01317 BYTE c, nt, *dir;
01318 char *p;
01319
01320
01321 p = fno->fname;
01322 if (dj->sect) {
01323 dir = dj->dir;
01324 nt = dir[DIR_NTres];
01325 for (i = 0; i < 8; i++) {
01326 c = dir[i];
01327 if (c == ' ') break;
01328 if (c == 0x05) c = 0xE5;
01329 if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
01330 *p++ = c;
01331 }
01332 if (dir[8] != ' ') {
01333 *p++ = '.';
01334 for (i = 8; i < 11; i++) {
01335 c = dir[i];
01336 if (c == ' ') break;
01337 if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
01338 *p++ = c;
01339 }
01340 }
01341 fno->fattrib = dir[DIR_Attr];
01342 fno->fsize = LD_DWORD(dir+DIR_FileSize);
01343 fno->fdate = LD_WORD(dir+DIR_WrtDate);
01344 fno->ftime = LD_WORD(dir+DIR_WrtTime);
01345 }
01346 *p = 0;
01347
01348 #if _USE_LFN
01349 if (fno->lfname) {
01350 XCHAR *tp = fno->lfname;
01351 WCHAR w, *lfn;
01352
01353 i = 0;
01354 if (dj->sect && dj->lfn_idx != 0xFFFF) {
01355 lfn = dj->lfn;
01356 while ((w = *lfn++) != 0) {
01357 #if !_LFN_UNICODE
01358 w = ff_convert(w, 0);
01359 if (!w) { i = 0; break; }
01360 if (_DF1S && w >= 0x100)
01361 tp[i++] = (XCHAR)(w >> 8);
01362 #endif
01363 if (i >= fno->lfsize - 1) { i = 0; break; }
01364 tp[i++] = (XCHAR)w;
01365 }
01366 }
01367 tp[i] = 0;
01368 }
01369 #endif
01370 }
01371 #endif
01372
01373
01374
01375
01376
01377
01378
01379
01380 static
01381 FRESULT follow_path (
01382 DIR *dj,
01383 const XCHAR *path
01384 )
01385 {
01386 FRESULT res;
01387 BYTE *dir, last;
01388
01389
01390 while (!_USE_LFN && *path == ' ') path++;
01391 #if _FS_RPATH
01392 if (*path == '/' || *path == '\\') {
01393 path++; dj->sclust = 0;
01394 } else {
01395 dj->sclust = dj->fs->cdir;
01396 }
01397 #else
01398 if (*path == '/' || *path == '\\')
01399 path++;
01400 dj->sclust = 0;
01401 #endif
01402
01403 if ((UINT)*path < ' ') {
01404 res = dir_seek(dj, 0);
01405 dj->dir = NULL;
01406
01407 } else {
01408 for (;;) {
01409 res = create_name(dj, &path);
01410 if (res != FR_OK) break;
01411 res = dir_find(dj);
01412 last = *(dj->fn+NS) & NS_LAST;
01413 if (res != FR_OK) {
01414 if (res == FR_NO_FILE && !last)
01415 res = FR_NO_PATH;
01416 break;
01417 }
01418 if (last) break;
01419 dir = dj->dir;
01420 if (!(dir[DIR_Attr] & AM_DIR)) {
01421 res = FR_NO_PATH; break;
01422 }
01423 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
01424 }
01425 }
01426
01427 return res;
01428 }
01429
01430
01431
01432
01433
01434
01435
01436
01437 static
01438 BYTE check_fs (
01439 FATFS *fs,
01440 DWORD sect
01441 )
01442 {
01443 if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK)
01444 return 3;
01445 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)
01446 return 2;
01447
01448 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
01449 return 0;
01450 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
01451 return 0;
01452
01453 return 1;
01454 }
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464 FRESULT chk_mounted (
01465 const XCHAR **path,
01466 FATFS **rfs,
01467 BYTE chk_wp
01468 )
01469 {
01470 BYTE fmt, *tbl;
01471 UINT vol;
01472 DSTATUS stat;
01473 DWORD bsect, fsize, tsect, mclst;
01474 const XCHAR *p = *path;
01475 FATFS *fs;
01476
01477
01478 vol = p[0] - '0';
01479 if (vol <= 9 && p[1] == ':') {
01480 p += 2; *path = p;
01481 } else {
01482 #if _FS_RPATH
01483 vol = Drive;
01484 #else
01485 vol = 0;
01486 #endif
01487 }
01488
01489
01490 if (vol >= _DRIVES)
01491 return FR_INVALID_DRIVE;
01492 *rfs = fs = FatFs[vol];
01493 if (!fs) return FR_NOT_ENABLED;
01494
01495 ENTER_FF(fs);
01496
01497 if (fs->fs_type) {
01498 stat = disk_status(fs->drive);
01499 if (!(stat & STA_NOINIT)) {
01500 #if !_FS_READONLY
01501 if (chk_wp && (stat & STA_PROTECT))
01502 return FR_WRITE_PROTECTED;
01503 #endif
01504 return FR_OK;
01505 }
01506 }
01507
01508
01509
01510 fs->fs_type = 0;
01511 fs->drive = (BYTE)LD2PD(vol);
01512 stat = disk_initialize(fs->drive);
01513 if (stat & STA_NOINIT)
01514 return FR_NOT_READY;
01515 #if _MAX_SS != 512
01516 if (disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
01517 return FR_NO_FILESYSTEM;
01518 #endif
01519 #if !_FS_READONLY
01520 if (chk_wp && (stat & STA_PROTECT))
01521 return FR_WRITE_PROTECTED;
01522 #endif
01523
01524 fmt = check_fs(fs, bsect = 0);
01525 if (fmt == 1) {
01526
01527 tbl = &fs->win[MBR_Table + LD2PT(vol) * 16];
01528 if (tbl[4]) {
01529 bsect = LD_DWORD(&tbl[8]);
01530 fmt = check_fs(fs, bsect);
01531 }
01532 }
01533 if (fmt == 3) return FR_DISK_ERR;
01534 if (fmt || LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))
01535 return FR_NO_FILESYSTEM;
01536
01537
01538 fsize = LD_WORD(fs->win+BPB_FATSz16);
01539 if (!fsize) fsize = LD_DWORD(fs->win+BPB_FATSz32);
01540 fs->sects_fat = fsize;
01541 fs->n_fats = fs->win[BPB_NumFATs];
01542 fsize *= fs->n_fats;
01543 fs->fatbase = bsect + LD_WORD(fs->win+BPB_RsvdSecCnt);
01544 fs->csize = fs->win[BPB_SecPerClus];
01545 fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);
01546 tsect = LD_WORD(fs->win+BPB_TotSec16);
01547 if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
01548 fs->max_clust = mclst = (tsect
01549 - LD_WORD(fs->win+BPB_RsvdSecCnt) - fsize - fs->n_rootdir / (SS(fs)/32)
01550 ) / fs->csize + 2;
01551
01552 fmt = FS_FAT12;
01553 if (mclst >= 0xFF7) fmt = FS_FAT16;
01554 if (mclst >= 0xFFF7) fmt = FS_FAT32;
01555
01556 if (fmt == FS_FAT32)
01557 fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);
01558 else
01559 fs->dirbase = fs->fatbase + fsize;
01560 fs->database = fs->fatbase + fsize + fs->n_rootdir / (SS(fs)/32);
01561
01562 #if !_FS_READONLY
01563
01564 fs->free_clust = 0xFFFFFFFF;
01565 fs->wflag = 0;
01566
01567 if (fmt == FS_FAT32) {
01568 fs->fsi_flag = 0;
01569 fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
01570 if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
01571 LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
01572 LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
01573 LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
01574 fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
01575 fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
01576 }
01577 }
01578 #endif
01579 fs->fs_type = fmt;
01580 fs->winsect = 0;
01581 #if _FS_RPATH
01582 fs->cdir = 0;
01583 #endif
01584 fs->id = ++Fsid;
01585
01586 return FR_OK;
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596 static
01597 FRESULT validate (
01598 FATFS *fs,
01599 WORD id
01600 )
01601 {
01602 if (!fs || !fs->fs_type || fs->id != id)
01603 return FR_INVALID_OBJECT;
01604
01605 ENTER_FF(fs);
01606
01607 if (disk_status(fs->drive) & STA_NOINIT)
01608 return FR_NOT_READY;
01609
01610 return FR_OK;
01611 }
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628 FRESULT f_mount (
01629 BYTE vol,
01630 FATFS *fs
01631 )
01632 {
01633 FATFS *rfs;
01634
01635
01636 if (vol >= _DRIVES)
01637 return FR_INVALID_DRIVE;
01638 rfs = FatFs[vol];
01639
01640 if (rfs) {
01641 #if _FS_REENTRANT
01642 if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
01643 #endif
01644 rfs->fs_type = 0;
01645 }
01646
01647 if (fs) {
01648 fs->fs_type = 0;
01649 #if _FS_REENTRANT
01650 if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
01651 #endif
01652 }
01653 FatFs[vol] = fs;
01654
01655 return FR_OK;
01656 }
01657
01658
01659
01660
01661
01662
01663
01664
01665 FRESULT f_open (
01666 FIL *fp,
01667 const XCHAR *path,
01668 BYTE mode
01669 )
01670 {
01671 FRESULT res;
01672 DIR dj;
01673 NAMEBUF(sfn, lfn);
01674 BYTE *dir;
01675
01676
01677 fp->fs = NULL;
01678 #if !_FS_READONLY
01679 mode &= (FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW);
01680 res = chk_mounted(&path, &dj.fs, (BYTE)(mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)));
01681 #else
01682 mode &= FA_READ;
01683 res = chk_mounted(&path, &dj.fs, 0);
01684 #endif
01685 if (res != FR_OK) LEAVE_FF(dj.fs, res);
01686 INITBUF(dj, sfn, lfn);
01687 res = follow_path(&dj, path);
01688
01689 #if !_FS_READONLY
01690
01691 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
01692 DWORD ps, cl;
01693
01694 if (res != FR_OK) {
01695 if (res == FR_NO_FILE)
01696 res = dir_register(&dj);
01697 if (res != FR_OK) LEAVE_FF(dj.fs, res);
01698 mode |= FA_CREATE_ALWAYS;
01699 dir = dj.dir;
01700 }
01701 else {
01702 if (mode & FA_CREATE_NEW)
01703 LEAVE_FF(dj.fs, FR_EXIST);
01704 dir = dj.dir;
01705 if (!dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR)))
01706 LEAVE_FF(dj.fs, FR_DENIED);
01707 if (mode & FA_CREATE_ALWAYS) {
01708 cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
01709 ST_WORD(dir+DIR_FstClusHI, 0);
01710 ST_WORD(dir+DIR_FstClusLO, 0);
01711 ST_DWORD(dir+DIR_FileSize, 0);
01712 dj.fs->wflag = 1;
01713 ps = dj.fs->winsect;
01714 if (cl) {
01715 res = remove_chain(dj.fs, cl);
01716 if (res) LEAVE_FF(dj.fs, res);
01717 dj.fs->last_clust = cl - 1;
01718 }
01719 res = move_window(dj.fs, ps);
01720 if (res != FR_OK) LEAVE_FF(dj.fs, res);
01721 }
01722 }
01723 if (mode & FA_CREATE_ALWAYS) {
01724 dir[DIR_Attr] = 0;
01725 ps = get_fattime();
01726 ST_DWORD(dir+DIR_CrtTime, ps);
01727 dj.fs->wflag = 1;
01728 mode |= FA__WRITTEN;
01729 }
01730 }
01731
01732 else {
01733 #endif
01734 if (res != FR_OK) LEAVE_FF(dj.fs, res);
01735 dir = dj.dir;
01736 if (!dir || (dir[DIR_Attr] & AM_DIR))
01737 LEAVE_FF(dj.fs, FR_NO_FILE);
01738 #if !_FS_READONLY
01739 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO))
01740 LEAVE_FF(dj.fs, FR_DENIED);
01741 }
01742 fp->dir_sect = dj.fs->winsect;
01743 fp->dir_ptr = dj.dir;
01744 #endif
01745 fp->flag = mode;
01746 fp->org_clust =
01747 ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
01748 fp->fsize = LD_DWORD(dir+DIR_FileSize);
01749 fp->fptr = 0; fp->csect = 255;
01750 fp->dsect = 0;
01751 fp->fs = dj.fs; fp->id = dj.fs->id;
01752
01753 LEAVE_FF(dj.fs, FR_OK);
01754 }
01755
01756
01757
01758
01759
01760
01761
01762
01763 FRESULT f_read (
01764 FIL *fp,
01765 void *buff,
01766 UINT btr,
01767 UINT *br
01768 )
01769 {
01770 FRESULT res;
01771 DWORD clst, sect, remain;
01772 UINT rcnt, cc;
01773 BYTE *rbuff = buff;
01774
01775
01776 *br = 0;
01777
01778 res = validate(fp->fs, fp->id);
01779 if (res != FR_OK) LEAVE_FF(fp->fs, res);
01780 if (fp->flag & FA__ERROR)
01781 LEAVE_FF(fp->fs, FR_INT_ERR);
01782 if (!(fp->flag & FA_READ))
01783 LEAVE_FF(fp->fs, FR_DENIED);
01784 remain = fp->fsize - fp->fptr;
01785 if (btr > remain) btr = (UINT)remain;
01786
01787 for ( ; btr;
01788 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
01789 if ((fp->fptr % SS(fp->fs)) == 0) {
01790 if (fp->csect >= fp->fs->csize) {
01791 clst = (fp->fptr == 0) ?
01792 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
01793 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
01794 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
01795 fp->curr_clust = clst;
01796 fp->csect = 0;
01797 }
01798 sect = clust2sect(fp->fs, fp->curr_clust);
01799 if (!sect) ABORT(fp->fs, FR_INT_ERR);
01800 sect += fp->csect;
01801 cc = btr / SS(fp->fs);
01802 if (cc) {
01803 if (fp->csect + cc > fp->fs->csize)
01804 cc = fp->fs->csize - fp->csect;
01805 if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
01806 ABORT(fp->fs, FR_DISK_ERR);
01807 #if !_FS_READONLY && _FS_MINIMIZE <= 2
01808 #if _FS_TINY
01809 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
01810 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
01811 #else
01812 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
01813 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
01814 #endif
01815 #endif
01816 fp->csect += (BYTE)cc;
01817 rcnt = SS(fp->fs) * cc;
01818 continue;
01819 }
01820 #if !_FS_TINY
01821 #if !_FS_READONLY
01822 if (fp->flag & FA__DIRTY) {
01823 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
01824 ABORT(fp->fs, FR_DISK_ERR);
01825 fp->flag &= ~FA__DIRTY;
01826 }
01827 #endif
01828 if (fp->dsect != sect) {
01829 if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
01830 ABORT(fp->fs, FR_DISK_ERR);
01831 }
01832 #endif
01833 fp->dsect = sect;
01834 fp->csect++;
01835 }
01836 rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));
01837 if (rcnt > btr) rcnt = btr;
01838 #if _FS_TINY
01839 if (move_window(fp->fs, fp->dsect))
01840 ABORT(fp->fs, FR_DISK_ERR);
01841 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);
01842 #else
01843 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);
01844 #endif
01845 }
01846
01847 LEAVE_FF(fp->fs, FR_OK);
01848 }
01849
01850
01851
01852
01853 #if !_FS_READONLY
01854
01855
01856
01857
01858 FRESULT f_write (
01859 FIL *fp,
01860 const void *buff,
01861 UINT btw,
01862 UINT *bw
01863 )
01864 {
01865 FRESULT res;
01866 DWORD clst, sect;
01867 UINT wcnt, cc;
01868 const BYTE *wbuff = buff;
01869
01870
01871 *bw = 0;
01872
01873 res = validate(fp->fs, fp->id);
01874 if (res != FR_OK) LEAVE_FF(fp->fs, res);
01875 if (fp->flag & FA__ERROR)
01876 LEAVE_FF(fp->fs, FR_INT_ERR);
01877 if (!(fp->flag & FA_WRITE))
01878 LEAVE_FF(fp->fs, FR_DENIED);
01879 if (fp->fsize + btw < fp->fsize) btw = 0;
01880
01881 for ( ; btw;
01882 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
01883 if ((fp->fptr % SS(fp->fs)) == 0) {
01884 if (fp->csect >= fp->fs->csize) {
01885 if (fp->fptr == 0) {
01886 clst = fp->org_clust;
01887 if (clst == 0)
01888 fp->org_clust = clst = create_chain(fp->fs, 0);
01889 } else {
01890 clst = create_chain(fp->fs, fp->curr_clust);
01891 }
01892 if (clst == 0) break;
01893 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
01894 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
01895 fp->curr_clust = clst;
01896 fp->csect = 0;
01897 }
01898 #if _FS_TINY
01899 if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))
01900 ABORT(fp->fs, FR_DISK_ERR);
01901 #else
01902 if (fp->flag & FA__DIRTY) {
01903 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
01904 ABORT(fp->fs, FR_DISK_ERR);
01905 fp->flag &= ~FA__DIRTY;
01906 }
01907 #endif
01908 sect = clust2sect(fp->fs, fp->curr_clust);
01909 if (!sect) ABORT(fp->fs, FR_INT_ERR);
01910 sect += fp->csect;
01911 cc = btw / SS(fp->fs);
01912 if (cc) {
01913 if (fp->csect + cc > fp->fs->csize)
01914 cc = fp->fs->csize - fp->csect;
01915 if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
01916 ABORT(fp->fs, FR_DISK_ERR);
01917 #if _FS_TINY
01918 if (fp->fs->winsect - sect < cc) {
01919 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
01920 fp->fs->wflag = 0;
01921 }
01922 #else
01923 if (fp->dsect - sect < cc) {
01924 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
01925 fp->flag &= ~FA__DIRTY;
01926 }
01927 #endif
01928 fp->csect += (BYTE)cc;
01929 wcnt = SS(fp->fs) * cc;
01930 continue;
01931 }
01932 #if _FS_TINY
01933 if (fp->fptr >= fp->fsize) {
01934 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
01935 fp->fs->winsect = sect;
01936 }
01937 #else
01938 if (fp->dsect != sect) {
01939 if (fp->fptr < fp->fsize &&
01940 disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
01941 ABORT(fp->fs, FR_DISK_ERR);
01942 }
01943 #endif
01944 fp->dsect = sect;
01945 fp->csect++;
01946 }
01947 wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));
01948 if (wcnt > btw) wcnt = btw;
01949 #if _FS_TINY
01950 if (move_window(fp->fs, fp->dsect))
01951 ABORT(fp->fs, FR_DISK_ERR);
01952 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);
01953 fp->fs->wflag = 1;
01954 #else
01955 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);
01956 fp->flag |= FA__DIRTY;
01957 #endif
01958 }
01959
01960 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;
01961 fp->flag |= FA__WRITTEN;
01962
01963 LEAVE_FF(fp->fs, FR_OK);
01964 }
01965
01966
01967
01968
01969
01970
01971
01972
01973 FRESULT f_sync (
01974 FIL *fp
01975 )
01976 {
01977 FRESULT res;
01978 DWORD tim;
01979 BYTE *dir;
01980
01981
01982 res = validate(fp->fs, fp->id);
01983 if (res == FR_OK) {
01984 if (fp->flag & FA__WRITTEN) {
01985 #if !_FS_TINY
01986 if (fp->flag & FA__DIRTY) {
01987 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
01988 LEAVE_FF(fp->fs, FR_DISK_ERR);
01989 fp->flag &= ~FA__DIRTY;
01990 }
01991 #endif
01992
01993 res = move_window(fp->fs, fp->dir_sect);
01994 if (res == FR_OK) {
01995 dir = fp->dir_ptr;
01996 dir[DIR_Attr] |= AM_ARC;
01997 ST_DWORD(dir+DIR_FileSize, fp->fsize);
01998 ST_WORD(dir+DIR_FstClusLO, fp->org_clust);
01999 ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
02000 tim = get_fattime();
02001 ST_DWORD(dir+DIR_WrtTime, tim);
02002 fp->flag &= ~FA__WRITTEN;
02003 fp->fs->wflag = 1;
02004 res = sync(fp->fs);
02005 }
02006 }
02007 }
02008
02009 LEAVE_FF(fp->fs, res);
02010 }
02011
02012 #endif
02013
02014
02015
02016
02017
02018
02019
02020
02021 FRESULT f_close (
02022 FIL *fp
02023 )
02024 {
02025 FRESULT res;
02026
02027
02028 #if _FS_READONLY
02029 res = validate(fp->fs, fp->id);
02030 if (res == FR_OK) fp->fs = NULL;
02031 LEAVE_FF(fp->fs, res);
02032 #else
02033 res = f_sync(fp);
02034 if (res == FR_OK) fp->fs = NULL;
02035 return res;
02036 #endif
02037 }
02038
02039
02040
02041
02042
02043
02044
02045
02046 #if _FS_RPATH
02047
02048 FRESULT f_chdrive (
02049 BYTE drv
02050 )
02051 {
02052 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
02053
02054 Drive = drv;
02055
02056 return FR_OK;
02057 }
02058
02059
02060
02061
02062 FRESULT f_chdir (
02063 const XCHAR *path
02064 )
02065 {
02066 FRESULT res;
02067 DIR dj;
02068 NAMEBUF(sfn, lfn);
02069 BYTE *dir;
02070
02071
02072 res = chk_mounted(&path, &dj.fs, 0);
02073 if (res == FR_OK) {
02074 INITBUF(dj, sfn, lfn);
02075 res = follow_path(&dj, path);
02076 if (res == FR_OK) {
02077 dir = dj.dir;
02078 if (!dir) {
02079 dj.fs->cdir = 0;
02080 } else {
02081 if (dir[DIR_Attr] & AM_DIR)
02082 dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
02083 else
02084 res = FR_NO_PATH;
02085 }
02086 }
02087 if (res == FR_NO_FILE) res = FR_NO_PATH;
02088 }
02089
02090 LEAVE_FF(dj.fs, res);
02091 }
02092
02093 #endif
02094
02095
02096
02097 #if _FS_MINIMIZE <= 2
02098
02099
02100
02101
02102 FRESULT f_lseek (
02103 FIL *fp,
02104 DWORD ofs
02105 )
02106 {
02107 FRESULT res;
02108 DWORD clst, bcs, nsect, ifptr;
02109
02110
02111 res = validate(fp->fs, fp->id);
02112 if (res != FR_OK) LEAVE_FF(fp->fs, res);
02113 if (fp->flag & FA__ERROR)
02114 LEAVE_FF(fp->fs, FR_INT_ERR);
02115 if (ofs > fp->fsize
02116 #if !_FS_READONLY
02117 && !(fp->flag & FA_WRITE)
02118 #endif
02119 ) ofs = fp->fsize;
02120
02121 ifptr = fp->fptr;
02122 fp->fptr = nsect = 0; fp->csect = 255;
02123 if (ofs > 0) {
02124 bcs = (DWORD)fp->fs->csize * SS(fp->fs);
02125 if (ifptr > 0 &&
02126 (ofs - 1) / bcs >= (ifptr - 1) / bcs) {
02127 fp->fptr = (ifptr - 1) & ~(bcs - 1);
02128 ofs -= fp->fptr;
02129 clst = fp->curr_clust;
02130 } else {
02131 clst = fp->org_clust;
02132 #if !_FS_READONLY
02133 if (clst == 0) {
02134 clst = create_chain(fp->fs, 0);
02135 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
02136 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
02137 fp->org_clust = clst;
02138 }
02139 #endif
02140 fp->curr_clust = clst;
02141 }
02142 if (clst != 0) {
02143 while (ofs > bcs) {
02144 #if !_FS_READONLY
02145 if (fp->flag & FA_WRITE) {
02146 clst = create_chain(fp->fs, clst);
02147 if (clst == 0) {
02148 ofs = bcs; break;
02149 }
02150 } else
02151 #endif
02152 clst = get_fat(fp->fs, clst);
02153 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
02154 if (clst <= 1 || clst >= fp->fs->max_clust) ABORT(fp->fs, FR_INT_ERR);
02155 fp->curr_clust = clst;
02156 fp->fptr += bcs;
02157 ofs -= bcs;
02158 }
02159 fp->fptr += ofs;
02160 fp->csect = (BYTE)(ofs / SS(fp->fs));
02161 if (ofs % SS(fp->fs)) {
02162 nsect = clust2sect(fp->fs, clst);
02163 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
02164 nsect += fp->csect;
02165 fp->csect++;
02166 }
02167 }
02168 }
02169 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
02170 #if !_FS_TINY
02171 #if !_FS_READONLY
02172 if (fp->flag & FA__DIRTY) {
02173 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
02174 ABORT(fp->fs, FR_DISK_ERR);
02175 fp->flag &= ~FA__DIRTY;
02176 }
02177 #endif
02178 if (disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK)
02179 ABORT(fp->fs, FR_DISK_ERR);
02180 #endif
02181 fp->dsect = nsect;
02182 }
02183 #if !_FS_READONLY
02184 if (fp->fptr > fp->fsize) {
02185 fp->fsize = fp->fptr;
02186 fp->flag |= FA__WRITTEN;
02187 }
02188 #endif
02189
02190 LEAVE_FF(fp->fs, res);
02191 }
02192
02193
02194
02195
02196 #if _FS_MINIMIZE <= 1
02197
02198
02199
02200
02201 FRESULT f_opendir (
02202 DIR *dj,
02203 const XCHAR *path
02204 )
02205 {
02206 FRESULT res;
02207 NAMEBUF(sfn, lfn);
02208 BYTE *dir;
02209
02210
02211 res = chk_mounted(&path, &dj->fs, 0);
02212 if (res == FR_OK) {
02213 INITBUF((*dj), sfn, lfn);
02214 res = follow_path(dj, path);
02215 if (res == FR_OK) {
02216 dir = dj->dir;
02217 if (dir) {
02218 if (dir[DIR_Attr] & AM_DIR) {
02219 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
02220 } else {
02221 res = FR_NO_PATH;
02222 }
02223 }
02224 if (res == FR_OK) {
02225 dj->id = dj->fs->id;
02226 res = dir_seek(dj, 0);
02227 }
02228 }
02229 if (res == FR_NO_FILE) res = FR_NO_PATH;
02230 }
02231
02232 LEAVE_FF(dj->fs, res);
02233 }
02234
02235
02236
02237
02238
02239
02240
02241
02242 FRESULT f_readdir (
02243 DIR *dj,
02244 FILINFO *fno
02245 )
02246 {
02247 FRESULT res;
02248 NAMEBUF(sfn, lfn);
02249
02250
02251 res = validate(dj->fs, dj->id);
02252 if (res == FR_OK) {
02253 INITBUF((*dj), sfn, lfn);
02254 if (!fno) {
02255 res = dir_seek(dj, 0);
02256 } else {
02257 res = dir_read(dj);
02258 if (res == FR_NO_FILE) {
02259 dj->sect = 0;
02260 res = FR_OK;
02261 }
02262 if (res == FR_OK) {
02263 get_fileinfo(dj, fno);
02264 res = dir_next(dj, FALSE);
02265 if (res == FR_NO_FILE) {
02266 dj->sect = 0;
02267 res = FR_OK;
02268 }
02269 }
02270 }
02271 }
02272
02273 LEAVE_FF(dj->fs, res);
02274 }
02275
02276
02277
02278 #if _FS_MINIMIZE == 0
02279
02280
02281
02282
02283 FRESULT f_stat (
02284 const XCHAR *path,
02285 FILINFO *fno
02286 )
02287 {
02288 FRESULT res;
02289 DIR dj;
02290 NAMEBUF(sfn, lfn);
02291
02292
02293 res = chk_mounted(&path, &dj.fs, 0);
02294 if (res == FR_OK) {
02295 INITBUF(dj, sfn, lfn);
02296 res = follow_path(&dj, path);
02297 if (res == FR_OK) {
02298 if (dj.dir)
02299 get_fileinfo(&dj, fno);
02300 else
02301 res = FR_INVALID_NAME;
02302 }
02303 }
02304
02305 LEAVE_FF(dj.fs, res);
02306 }
02307
02308
02309
02310 #if !_FS_READONLY
02311
02312
02313
02314
02315 FRESULT f_getfree (
02316 const XCHAR *path,
02317 DWORD *nclst,
02318 FATFS **fatfs
02319 )
02320 {
02321 FRESULT res;
02322 DWORD n, clst, sect, stat;
02323 UINT i;
02324 BYTE fat, *p;
02325
02326
02327
02328 res = chk_mounted(&path, fatfs, 0);
02329 if (res != FR_OK) LEAVE_FF(*fatfs, res);
02330
02331
02332 if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
02333 *nclst = (*fatfs)->free_clust;
02334 LEAVE_FF(*fatfs, FR_OK);
02335 }
02336
02337
02338 fat = (*fatfs)->fs_type;
02339 n = 0;
02340 if (fat == FS_FAT12) {
02341 clst = 2;
02342 do {
02343 stat = get_fat(*fatfs, clst);
02344 if (stat == 0xFFFFFFFF) LEAVE_FF(*fatfs, FR_DISK_ERR);
02345 if (stat == 1) LEAVE_FF(*fatfs, FR_INT_ERR);
02346 if (stat == 0) n++;
02347 } while (++clst < (*fatfs)->max_clust);
02348 } else {
02349 clst = (*fatfs)->max_clust;
02350 sect = (*fatfs)->fatbase;
02351 i = 0; p = 0;
02352 do {
02353 if (!i) {
02354 res = move_window(*fatfs, sect++);
02355 if (res != FR_OK)
02356 LEAVE_FF(*fatfs, res);
02357 p = (*fatfs)->win;
02358 i = SS(*fatfs);
02359 }
02360 if (fat == FS_FAT16) {
02361 if (LD_WORD(p) == 0) n++;
02362 p += 2; i -= 2;
02363 } else {
02364 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
02365 p += 4; i -= 4;
02366 }
02367 } while (--clst);
02368 }
02369 (*fatfs)->free_clust = n;
02370 if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
02371 *nclst = n;
02372
02373 LEAVE_FF(*fatfs, FR_OK);
02374 }
02375
02376
02377
02378
02379
02380
02381
02382
02383 FRESULT f_truncate (
02384 FIL *fp
02385 )
02386 {
02387 FRESULT res;
02388 DWORD ncl;
02389
02390
02391 res = validate(fp->fs, fp->id);
02392 if (res != FR_OK) LEAVE_FF(fp->fs, res);
02393 if (fp->flag & FA__ERROR)
02394 LEAVE_FF(fp->fs, FR_INT_ERR);
02395 if (!(fp->flag & FA_WRITE))
02396 LEAVE_FF(fp->fs, FR_DENIED);
02397
02398 if (fp->fsize > fp->fptr) {
02399 fp->fsize = fp->fptr;
02400 fp->flag |= FA__WRITTEN;
02401 if (fp->fptr == 0) {
02402 res = remove_chain(fp->fs, fp->org_clust);
02403 fp->org_clust = 0;
02404 } else {
02405 ncl = get_fat(fp->fs, fp->curr_clust);
02406 res = FR_OK;
02407 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
02408 if (ncl == 1) res = FR_INT_ERR;
02409 if (res == FR_OK && ncl < fp->fs->max_clust) {
02410 res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
02411 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
02412 }
02413 }
02414 }
02415 if (res != FR_OK) fp->flag |= FA__ERROR;
02416
02417 LEAVE_FF(fp->fs, res);
02418 }
02419
02420
02421
02422
02423
02424
02425
02426
02427 FRESULT f_unlink (
02428 const XCHAR *path
02429 )
02430 {
02431 FRESULT res;
02432 DIR dj, sdj;
02433 NAMEBUF(sfn, lfn);
02434 BYTE *dir;
02435 DWORD dclst;
02436
02437
02438 res = chk_mounted(&path, &dj.fs, 1);
02439 if (res != FR_OK) LEAVE_FF(dj.fs, res);
02440
02441 INITBUF(dj, sfn, lfn);
02442 res = follow_path(&dj, path);
02443 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
02444 res = FR_INVALID_NAME;
02445 if (res != FR_OK) LEAVE_FF(dj.fs, res);
02446
02447 dir = dj.dir;
02448 if (!dir)
02449 LEAVE_FF(dj.fs, FR_INVALID_NAME);
02450 if (dir[DIR_Attr] & AM_RDO)
02451 LEAVE_FF(dj.fs, FR_DENIED);
02452 dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
02453
02454 if (dir[DIR_Attr] & AM_DIR) {
02455 if (dclst < 2) LEAVE_FF(dj.fs, FR_INT_ERR);
02456 mem_cpy(&sdj, &dj, sizeof(DIR));
02457 sdj.sclust = dclst;
02458 res = dir_seek(&sdj, 2);
02459 if (res != FR_OK) LEAVE_FF(dj.fs, res);
02460 res = dir_read(&sdj);
02461 if (res == FR_OK) res = FR_DENIED;
02462 if (res != FR_NO_FILE) LEAVE_FF(dj.fs, res);
02463 }
02464
02465 res = dir_remove(&dj);
02466 if (res == FR_OK) {
02467 if (dclst)
02468 res = remove_chain(dj.fs, dclst);
02469 if (res == FR_OK) res = sync(dj.fs);
02470 }
02471
02472 LEAVE_FF(dj.fs, res);
02473 }
02474
02475
02476
02477
02478
02479
02480
02481
02482 FRESULT f_mkdir (
02483 const XCHAR *path
02484 )
02485 {
02486 FRESULT res;
02487 DIR dj;
02488 NAMEBUF(sfn, lfn);
02489 BYTE *dir, n;
02490 DWORD dsect, dclst, pclst, tim;
02491
02492
02493 res = chk_mounted(&path, &dj.fs, 1);
02494 if (res != FR_OK) LEAVE_FF(dj.fs, res);
02495
02496 INITBUF(dj, sfn, lfn);
02497 res = follow_path(&dj, path);
02498 if (res == FR_OK) res = FR_EXIST;
02499 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
02500 res = FR_INVALID_NAME;
02501 if (res != FR_NO_FILE)
02502 LEAVE_FF(dj.fs, res);
02503
02504 dclst = create_chain(dj.fs, 0);
02505 res = FR_OK;
02506 if (dclst == 0) res = FR_DENIED;
02507 if (dclst == 1) res = FR_INT_ERR;
02508 if (dclst == 0xFFFFFFFF) res = FR_DISK_ERR;
02509 if (res == FR_OK)
02510 res = move_window(dj.fs, 0);
02511 if (res != FR_OK) LEAVE_FF(dj.fs, res);
02512 dsect = clust2sect(dj.fs, dclst);
02513
02514 dir = dj.fs->win;
02515 mem_set(dir, 0, SS(dj.fs));
02516 mem_set(dir+DIR_Name, ' ', 8+3);
02517 dir[DIR_Name] = '.';
02518 dir[DIR_Attr] = AM_DIR;
02519 tim = get_fattime();
02520 ST_DWORD(dir+DIR_WrtTime, tim);
02521 ST_WORD(dir+DIR_FstClusLO, dclst);
02522 ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
02523 mem_cpy(dir+32, dir, 32);
02524 dir[33] = '.';
02525 pclst = dj.sclust;
02526 if (dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase)
02527 pclst = 0;
02528 ST_WORD(dir+32+DIR_FstClusLO, pclst);
02529 ST_WORD(dir+32+DIR_FstClusHI, pclst >> 16);
02530 for (n = 0; n < dj.fs->csize; n++) {
02531 dj.fs->winsect = dsect++;
02532 dj.fs->wflag = 1;
02533 res = move_window(dj.fs, 0);
02534 if (res) LEAVE_FF(dj.fs, res);
02535 mem_set(dir, 0, SS(dj.fs));
02536 }
02537
02538 res = dir_register(&dj);
02539 if (res != FR_OK) {
02540 remove_chain(dj.fs, dclst);
02541 } else {
02542 dir = dj.dir;
02543 dir[DIR_Attr] = AM_DIR;
02544 ST_DWORD(dir+DIR_WrtTime, tim);
02545 ST_WORD(dir+DIR_FstClusLO, dclst);
02546 ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
02547 dj.fs->wflag = 1;
02548 res = sync(dj.fs);
02549 }
02550
02551 LEAVE_FF(dj.fs, res);
02552 }
02553
02554
02555
02556
02557
02558
02559
02560
02561 FRESULT f_chmod (
02562 const XCHAR *path,
02563 BYTE value,
02564 BYTE mask
02565 )
02566 {
02567 FRESULT res;
02568 DIR dj;
02569 NAMEBUF(sfn, lfn);
02570 BYTE *dir;
02571
02572
02573 res = chk_mounted(&path, &dj.fs, 1);
02574 if (res == FR_OK) {
02575 INITBUF(dj, sfn, lfn);
02576 res = follow_path(&dj, path);
02577 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
02578 res = FR_INVALID_NAME;
02579 if (res == FR_OK) {
02580 dir = dj.dir;
02581 if (!dir) {
02582 res = FR_INVALID_NAME;
02583 } else {
02584 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;
02585 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask);
02586 dj.fs->wflag = 1;
02587 res = sync(dj.fs);
02588 }
02589 }
02590 }
02591
02592 LEAVE_FF(dj.fs, res);
02593 }
02594
02595
02596
02597
02598
02599
02600
02601
02602 FRESULT f_utime (
02603 const XCHAR *path,
02604 const FILINFO *fno
02605 )
02606 {
02607 FRESULT res;
02608 DIR dj;
02609 NAMEBUF(sfn, lfn);
02610 BYTE *dir;
02611
02612
02613 res = chk_mounted(&path, &dj.fs, 1);
02614 if (res == FR_OK) {
02615 INITBUF(dj, sfn, lfn);
02616 res = follow_path(&dj, path);
02617 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
02618 res = FR_INVALID_NAME;
02619 if (res == FR_OK) {
02620 dir = dj.dir;
02621 if (!dir) {
02622 res = FR_INVALID_NAME;
02623 } else {
02624 ST_WORD(dir+DIR_WrtTime, fno->ftime);
02625 ST_WORD(dir+DIR_WrtDate, fno->fdate);
02626 dj.fs->wflag = 1;
02627 res = sync(dj.fs);
02628 }
02629 }
02630 }
02631
02632 LEAVE_FF(dj.fs, res);
02633 }
02634
02635
02636
02637
02638
02639
02640
02641
02642 FRESULT f_rename (
02643 const XCHAR *path_old,
02644 const XCHAR *path_new
02645 )
02646 {
02647 FRESULT res;
02648 DIR dj_old, dj_new;
02649 NAMEBUF(sfn, lfn);
02650 BYTE buf[21], *dir;
02651 DWORD dw;
02652
02653
02654 INITBUF(dj_old, sfn, lfn);
02655 res = chk_mounted(&path_old, &dj_old.fs, 1);
02656 if (res == FR_OK) {
02657 dj_new.fs = dj_old.fs;
02658 res = follow_path(&dj_old, path_old);
02659 if (_FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT))
02660 res = FR_INVALID_NAME;
02661 }
02662 if (res != FR_OK) LEAVE_FF(dj_old.fs, res);
02663
02664 if (!dj_old.dir) LEAVE_FF(dj_old.fs, FR_NO_FILE);
02665 mem_cpy(buf, dj_old.dir+DIR_Attr, 21);
02666
02667 mem_cpy(&dj_new, &dj_old, sizeof(DIR));
02668 res = follow_path(&dj_new, path_new);
02669 if (res == FR_OK) res = FR_EXIST;
02670 if (res == FR_NO_FILE) {
02671 res = dir_register(&dj_new);
02672 if (res == FR_OK) {
02673 dir = dj_new.dir;
02674 mem_cpy(dir+13, buf+2, 19);
02675 dir[DIR_Attr] = buf[0] | AM_ARC;
02676 dj_old.fs->wflag = 1;
02677 if (dir[DIR_Attr] & AM_DIR) {
02678 dw = clust2sect(dj_new.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
02679 if (!dw) {
02680 res = FR_INT_ERR;
02681 } else {
02682 res = move_window(dj_new.fs, dw);
02683 dir = dj_new.fs->win+32;
02684 if (res == FR_OK && dir[1] == '.') {
02685 dw = (dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase) ? 0 : dj_new.sclust;
02686 ST_WORD(dir+DIR_FstClusLO, dw);
02687 ST_WORD(dir+DIR_FstClusHI, dw >> 16);
02688 dj_new.fs->wflag = 1;
02689 }
02690 }
02691 }
02692 if (res == FR_OK) {
02693 res = dir_remove(&dj_old);
02694 if (res == FR_OK)
02695 res = sync(dj_old.fs);
02696 }
02697 }
02698 }
02699
02700 LEAVE_FF(dj_old.fs, res);
02701 }
02702
02703 #endif
02704 #endif
02705 #endif
02706 #endif
02707
02708
02709
02710
02711
02712
02713 #if _USE_FORWARD && _FS_TINY
02714
02715 FRESULT f_forward (
02716 FIL *fp,
02717 UINT (*func)(const BYTE*,UINT),
02718 UINT btr,
02719 UINT *bf
02720 )
02721 {
02722 FRESULT res;
02723 DWORD remain, clst, sect;
02724 UINT rcnt;
02725
02726
02727 *bf = 0;
02728
02729 res = validate(fp->fs, fp->id);
02730 if (res != FR_OK) LEAVE_FF(fp->fs, res);
02731 if (fp->flag & FA__ERROR)
02732 LEAVE_FF(fp->fs, FR_INT_ERR);
02733 if (!(fp->flag & FA_READ))
02734 LEAVE_FF(fp->fs, FR_DENIED);
02735
02736 remain = fp->fsize - fp->fptr;
02737 if (btr > remain) btr = (UINT)remain;
02738
02739 for ( ; btr && (*func)(NULL, 0);
02740 fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
02741 if ((fp->fptr % SS(fp->fs)) == 0) {
02742 if (fp->csect >= fp->fs->csize) {
02743 clst = (fp->fptr == 0) ?
02744 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
02745 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
02746 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
02747 fp->curr_clust = clst;
02748 fp->csect = 0;
02749 }
02750 fp->csect++;
02751 }
02752 sect = clust2sect(fp->fs, fp->curr_clust);
02753 if (!sect) ABORT(fp->fs, FR_INT_ERR);
02754 sect += fp->csect - 1;
02755 if (move_window(fp->fs, sect))
02756 ABORT(fp->fs, FR_DISK_ERR);
02757 fp->dsect = sect;
02758 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs));
02759 if (rcnt > btr) rcnt = btr;
02760 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
02761 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
02762 }
02763
02764 LEAVE_FF(fp->fs, FR_OK);
02765 }
02766 #endif
02767
02768
02769
02770 #if _USE_MKFS && !_FS_READONLY
02771
02772
02773
02774 #define N_ROOTDIR 512
02775 #define N_FATS 1
02776 #define MAX_SECTOR 131072000UL
02777 #define MIN_SECTOR 2000UL
02778
02779
02780 FRESULT f_mkfs (
02781 BYTE drv,
02782 BYTE partition,
02783 WORD allocsize
02784 )
02785 {
02786 static const DWORD sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000, 0 };
02787 static const WORD cstbl[] = { 32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512 };
02788 BYTE fmt, m, *tbl;
02789 DWORD b_part, b_fat, b_dir, b_data;
02790 DWORD n_part, n_rsv, n_fat, n_dir;
02791 DWORD n_clst, d, n;
02792 WORD as;
02793 FATFS *fs;
02794 DSTATUS stat;
02795
02796
02797
02798 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
02799 if (partition >= 2) return FR_MKFS_ABORTED;
02800
02801
02802 fs = FatFs[drv];
02803 if (!fs) return FR_NOT_ENABLED;
02804 fs->fs_type = 0;
02805 drv = LD2PD(drv);
02806
02807
02808 stat = disk_initialize(drv);
02809 if (stat & STA_NOINIT) return FR_NOT_READY;
02810 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
02811 #if _MAX_SS != 512
02812 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
02813 || SS(fs) > _MAX_SS)
02814 return FR_MKFS_ABORTED;
02815 #endif
02816 if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
02817 return FR_MKFS_ABORTED;
02818 if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
02819 b_part = (!partition) ? 63 : 0;
02820 n_part -= b_part;
02821 for (d = 512; d <= 32768U && d != allocsize; d <<= 1) ;
02822 if (d != allocsize) allocsize = 0;
02823 if (!allocsize) {
02824 d = n_part;
02825 for (as = SS(fs); as > 512U; as >>= 1) d >>= 1;
02826 for (n = 0; d < sstbl[n]; n++) ;
02827 allocsize = cstbl[n];
02828 }
02829 if (allocsize < SS(fs)) allocsize = SS(fs);
02830
02831 allocsize /= SS(fs);
02832
02833
02834 n_clst = n_part / allocsize;
02835 fmt = FS_FAT12;
02836 if (n_clst >= 0xFF5) fmt = FS_FAT16;
02837 if (n_clst >= 0xFFF5) fmt = FS_FAT32;
02838
02839
02840 switch (fmt) {
02841 case FS_FAT12:
02842 n_fat = ((n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
02843 n_rsv = 1 + partition;
02844 n_dir = N_ROOTDIR * 32 / SS(fs);
02845 break;
02846 case FS_FAT16:
02847 n_fat = ((n_clst * 2) + 4 + SS(fs) - 1) / SS(fs);
02848 n_rsv = 1 + partition;
02849 n_dir = N_ROOTDIR * 32 / SS(fs);
02850 break;
02851 default:
02852 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
02853 n_rsv = 33 - partition;
02854 n_dir = 0;
02855 }
02856 b_fat = b_part + n_rsv;
02857 b_dir = b_fat + n_fat * N_FATS;
02858 b_data = b_dir + n_dir;
02859
02860
02861 if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
02862 n = (b_data + n - 1) & ~(n - 1);
02863 n_fat += (n - b_data) / N_FATS;
02864
02865
02866
02867 n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
02868 if ( (fmt == FS_FAT16 && n_clst < 0xFF5)
02869 || (fmt == FS_FAT32 && n_clst < 0xFFF5))
02870 return FR_MKFS_ABORTED;
02871
02872
02873 if (!partition) {
02874 DWORD n_disk = b_part + n_part;
02875
02876 mem_set(fs->win, 0, SS(fs));
02877 tbl = fs->win+MBR_Table;
02878 ST_DWORD(tbl, 0x00010180);
02879 if (n_disk < 63UL * 255 * 1024) {
02880 n_disk = n_disk / 63 / 255;
02881 tbl[7] = (BYTE)n_disk;
02882 tbl[6] = (BYTE)((n_disk >> 2) | 63);
02883 } else {
02884 ST_WORD(&tbl[6], 0xFFFF);
02885 }
02886 tbl[5] = 254;
02887 if (fmt != FS_FAT32)
02888 tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
02889 else
02890 tbl[4] = 0x0c;
02891 ST_DWORD(tbl+8, 63);
02892 ST_DWORD(tbl+12, n_part);
02893 ST_WORD(tbl+64, 0xAA55);
02894 if (disk_write(drv, fs->win, 0, 1) != RES_OK)
02895 return FR_DISK_ERR;
02896 partition = 0xF8;
02897 } else {
02898 partition = 0xF0;
02899 }
02900
02901
02902 tbl = fs->win;
02903 mem_set(tbl, 0, SS(fs));
02904 ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB);
02905 ST_WORD(tbl+BPB_BytsPerSec, SS(fs));
02906 tbl[BPB_SecPerClus] = (BYTE)allocsize;
02907 ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);
02908 tbl[BPB_NumFATs] = N_FATS;
02909 ST_WORD(tbl+BPB_RootEntCnt, SS(fs) / 32 * n_dir);
02910 if (n_part < 0x10000) {
02911 ST_WORD(tbl+BPB_TotSec16, n_part);
02912 } else {
02913 ST_DWORD(tbl+BPB_TotSec32, n_part);
02914 }
02915 tbl[BPB_Media] = partition;
02916 ST_WORD(tbl+BPB_SecPerTrk, 63);
02917 ST_WORD(tbl+BPB_NumHeads, 255);
02918 ST_DWORD(tbl+BPB_HiddSec, b_part);
02919 n = get_fattime();
02920 if (fmt != FS_FAT32) {
02921 ST_DWORD(tbl+BS_VolID, n);
02922 ST_WORD(tbl+BPB_FATSz16, n_fat);
02923 tbl[BS_DrvNum] = 0x80;
02924 tbl[BS_BootSig] = 0x29;
02925 mem_cpy(tbl+BS_VolLab, "NO NAME FAT ", 19);
02926 } else {
02927 ST_DWORD(tbl+BS_VolID32, n);
02928 ST_DWORD(tbl+BPB_FATSz32, n_fat);
02929 ST_DWORD(tbl+BPB_RootClus, 2);
02930 ST_WORD(tbl+BPB_FSInfo, 1);
02931 ST_WORD(tbl+BPB_BkBootSec, 6);
02932 tbl[BS_DrvNum32] = 0x80;
02933 tbl[BS_BootSig32] = 0x29;
02934 mem_cpy(tbl+BS_VolLab32, "NO NAME FAT32 ", 19);
02935 }
02936 ST_WORD(tbl+BS_55AA, 0xAA55);
02937 if (SS(fs) > 512U) {
02938 ST_WORD(tbl+SS(fs)-2, 0xAA55);
02939 }
02940 if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
02941 return FR_DISK_ERR;
02942 if (fmt == FS_FAT32)
02943 disk_write(drv, tbl, b_part+6, 1);
02944
02945
02946 for (m = 0; m < N_FATS; m++) {
02947 mem_set(tbl, 0, SS(fs));
02948 if (fmt != FS_FAT32) {
02949 n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
02950 n |= partition;
02951 ST_DWORD(tbl, n);
02952 } else {
02953 ST_DWORD(tbl+0, 0xFFFFFFF8);
02954 ST_DWORD(tbl+4, 0xFFFFFFFF);
02955 ST_DWORD(tbl+8, 0x0FFFFFFF);
02956 }
02957 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
02958 return FR_DISK_ERR;
02959 mem_set(tbl, 0, SS(fs));
02960 for (n = 1; n < n_fat; n++) {
02961 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
02962 return FR_DISK_ERR;
02963 }
02964 }
02965
02966
02967 m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
02968 do {
02969 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
02970 return FR_DISK_ERR;
02971 } while (--m);
02972
02973
02974 if (fmt == FS_FAT32) {
02975 ST_WORD(tbl+BS_55AA, 0xAA55);
02976 ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
02977 ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
02978 ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
02979 ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
02980 disk_write(drv, tbl, b_part+1, 1);
02981 disk_write(drv, tbl, b_part+7, 1);
02982 }
02983
02984 return (disk_ioctl(drv, CTRL_SYNC, (void*)NULL) == RES_OK) ? FR_OK : FR_DISK_ERR;
02985 }
02986
02987 #endif
02988
02989
02990
02991
02992 #if _USE_STRFUNC
02993
02994
02995
02996 char* f_gets (
02997 char* buff,
02998 int len,
02999 FIL* fil
03000 )
03001 {
03002 int i = 0;
03003 char *p = buff;
03004 UINT rc;
03005
03006
03007 while (i < len - 1) {
03008 f_read(fil, p, 1, &rc);
03009 if (rc != 1) break;
03010 #if _USE_STRFUNC >= 2
03011 if (*p == '\r') continue;
03012 #endif
03013 i++;
03014 if (*p++ == '\n') break;
03015 }
03016 *p = 0;
03017 return i ? buff : NULL;
03018 }
03019
03020
03021
03022 #if !_FS_READONLY
03023 #include <stdarg.h>
03024
03025
03026
03027 int f_putc (
03028 int chr,
03029 FIL* fil
03030 )
03031 {
03032 UINT bw;
03033 char c;
03034
03035
03036 #if _USE_STRFUNC >= 2
03037 if (chr == '\n') f_putc ('\r', fil);
03038 #endif
03039 if (!fil) {
03040
03041 return chr;
03042 }
03043 c = (char)chr;
03044 f_write(fil, &c, 1, &bw);
03045 return bw ? chr : EOF;
03046 }
03047
03048
03049
03050
03051
03052
03053
03054 int f_puts (
03055 const char* str,
03056 FIL* fil
03057 )
03058 {
03059 int n;
03060
03061
03062 for (n = 0; *str; str++, n++) {
03063 if (f_putc(*str, fil) == EOF) return EOF;
03064 }
03065 return n;
03066 }
03067
03068
03069
03070
03071
03072
03073
03074 int f_printf (
03075 FIL* fil,
03076 const char* str,
03077 ...
03078 )
03079 {
03080 va_list arp;
03081 UCHAR c, f, r;
03082 ULONG val;
03083 char s[16];
03084 int i, w, res, cc;
03085
03086
03087 va_start(arp, str);
03088
03089 for (cc = res = 0; cc != EOF; res += cc) {
03090 c = *str++;
03091 if (c == 0) break;
03092 if (c != '%') {
03093 cc = f_putc(c, fil);
03094 if (cc != EOF) cc = 1;
03095 continue;
03096 }
03097 w = f = 0;
03098 c = *str++;
03099 if (c == '0') {
03100 f = 1; c = *str++;
03101 }
03102 while (c >= '0' && c <= '9') {
03103 w = w * 10 + (c - '0');
03104 c = *str++;
03105 }
03106 if (c == 'l') {
03107 f |= 2; c = *str++;
03108 }
03109 if (c == 's') {
03110 cc = f_puts(va_arg(arp, char*), fil);
03111 continue;
03112 }
03113 if (c == 'c') {
03114 cc = f_putc(va_arg(arp, int), fil);
03115 if (cc != EOF) cc = 1;
03116 continue;
03117 }
03118 r = 0;
03119 if (c == 'd') r = 10;
03120 if (c == 'u') r = 10;
03121 if (c == 'X') r = 16;
03122 if (r == 0) break;
03123 if (f & 2) {
03124 val = (ULONG)va_arg(arp, long);
03125 } else {
03126 val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
03127 }
03128
03129 if (c == 'd') {
03130 if (val & 0x80000000) {
03131 val = 0 - val;
03132 f |= 4;
03133 }
03134 }
03135 i = sizeof(s) - 1; s[i] = 0;
03136 do {
03137 c = (UCHAR)(val % r + '0');
03138 if (c > '9') c += 7;
03139 s[--i] = c;
03140 val /= r;
03141 } while (i && val);
03142 if (i && (f & 4)) s[--i] = '-';
03143 w = sizeof(s) - 1 - w;
03144 while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
03145 cc = f_puts(&s[i], fil);
03146 }
03147
03148 va_end(arp);
03149 return (cc == EOF) ? cc : res;
03150 }
03151
03152 #endif
03153 #endif