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