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 #include <string.h>
00058 #include "ff.h"
00059 #include "diskio.h"
00060 #include "fattime.h"
00061
00062
00063
00064
00065
00066
00067
00068 static
00069 FATFS *FatFs[_DRIVES];
00070 static
00071 WORD fsid;
00072
00073
00074
00075
00076
00077
00078
00079 static
00080 BOOL move_window (
00081 FATFS *fs,
00082 DWORD sector
00083 )
00084 {
00085 DWORD wsect;
00086
00087
00088 wsect = fs->winsect;
00089 if (wsect != sector) {
00090 #if !_FS_READONLY
00091 BYTE n;
00092 if (fs->winflag) {
00093 if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
00094 return FALSE;
00095 fs->winflag = 0;
00096 if (wsect < (fs->fatbase + fs->sects_fat)) {
00097 for (n = fs->n_fats; n >= 2; n--) {
00098 wsect += fs->sects_fat;
00099 disk_write(fs->drive, fs->win, wsect, 1);
00100 }
00101 }
00102 }
00103 #endif
00104 if (sector) {
00105 if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
00106 return FALSE;
00107 fs->winsect = sector;
00108 }
00109 }
00110 return TRUE;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120 #if !_FS_READONLY
00121 static
00122 FRESULT sync (
00123 FATFS *fs
00124 )
00125 {
00126 fs->winflag = 1;
00127 if (!move_window(fs, 0)) return FR_RW_ERROR;
00128 #if _USE_FSINFO
00129
00130 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
00131 fs->winsect = 0;
00132 memset(fs->win, 0, 512);
00133 ST_WORD(&fs->win[BS_55AA], 0xAA55);
00134 ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252);
00135 ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272);
00136 ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust);
00137 ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust);
00138 disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
00139 fs->fsi_flag = 0;
00140 }
00141 #endif
00142
00143 if (disk_ioctl(fs->drive, CTRL_SYNC, NULL) != RES_OK)
00144 return FR_RW_ERROR;
00145 return FR_OK;
00146 }
00147 #endif
00148
00149
00150
00151
00152
00153
00154
00155
00156 static
00157 DWORD get_cluster (
00158 FATFS *fs,
00159 DWORD clust
00160 )
00161 {
00162 WORD wc, bc;
00163 DWORD fatsect;
00164
00165
00166 if (clust >= 2 && clust < fs->max_clust) {
00167 fatsect = fs->fatbase;
00168 switch (fs->fs_type) {
00169 case FS_FAT12 :
00170 bc = (WORD)clust * 3 / 2;
00171 if (!move_window(fs, fatsect + (bc / SS(fs)))) break;
00172 wc = fs->win[bc & (SS(fs) - 1)]; bc++;
00173 if (!move_window(fs, fatsect + (bc / SS(fs)))) break;
00174 wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
00175 return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);
00176
00177 case FS_FAT16 :
00178 if (!move_window(fs, fatsect + (clust / (SS(fs) / 2)))) break;
00179 return LD_WORD(&fs->win[((WORD)clust * 2) & (SS(fs) - 1)]);
00180
00181 case FS_FAT32 :
00182 if (!move_window(fs, fatsect + (clust / (SS(fs) / 4)))) break;
00183 return LD_DWORD(&fs->win[((WORD)clust * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
00184 }
00185 }
00186
00187 return 1;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197 #if !_FS_READONLY
00198 static
00199 BOOL put_cluster (
00200 FATFS *fs,
00201 DWORD clust,
00202 DWORD val
00203 )
00204 {
00205 WORD bc;
00206 BYTE *p;
00207 DWORD fatsect;
00208
00209
00210 fatsect = fs->fatbase;
00211 switch (fs->fs_type) {
00212 case FS_FAT12 :
00213 bc = (WORD)clust * 3 / 2;
00214 if (!move_window(fs, fatsect + (bc / SS(fs)))) return FALSE;
00215 p = &fs->win[bc & (SS(fs) - 1)];
00216 *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
00217 bc++;
00218 fs->winflag = 1;
00219 if (!move_window(fs, fatsect + (bc / SS(fs)))) return FALSE;
00220 p = &fs->win[bc & (SS(fs) - 1)];
00221 *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
00222 break;
00223
00224 case FS_FAT16 :
00225 if (!move_window(fs, fatsect + (clust / (SS(fs) / 2)))) return FALSE;
00226 ST_WORD(&fs->win[((WORD)clust * 2) & (SS(fs) - 1)], (WORD)val);
00227 break;
00228
00229 case FS_FAT32 :
00230 if (!move_window(fs, fatsect + (clust / (SS(fs) / 4)))) return FALSE;
00231 ST_DWORD(&fs->win[((WORD)clust * 4) & (SS(fs) - 1)], val);
00232 break;
00233
00234 default :
00235 return FALSE;
00236 }
00237 fs->winflag = 1;
00238 return TRUE;
00239 }
00240 #endif
00241
00242
00243
00244
00245
00246
00247
00248
00249 #if !_FS_READONLY
00250 static
00251 BOOL remove_chain (
00252 FATFS *fs,
00253 DWORD clust
00254 )
00255 {
00256 DWORD nxt;
00257
00258
00259 while (clust >= 2 && clust < fs->max_clust) {
00260 nxt = get_cluster(fs, clust);
00261 if (nxt == 1) return FALSE;
00262 if (!put_cluster(fs, clust, 0)) return FALSE;
00263 if (fs->free_clust != 0xFFFFFFFF) {
00264 fs->free_clust++;
00265 #if _USE_FSINFO
00266 fs->fsi_flag = 1;
00267 #endif
00268 }
00269 clust = nxt;
00270 }
00271 return TRUE;
00272 }
00273 #endif
00274
00275
00276
00277
00278
00279
00280
00281
00282 #if !_FS_READONLY
00283 static
00284 DWORD create_chain (
00285 FATFS *fs,
00286 DWORD clust
00287 )
00288 {
00289 DWORD cstat, ncl, scl, mcl = fs->max_clust;
00290
00291
00292 if (clust == 0) {
00293 scl = fs->last_clust;
00294 if (scl == 0 || scl >= mcl) scl = 1;
00295 }
00296 else {
00297 cstat = get_cluster(fs, clust);
00298 if (cstat < 2) return 1;
00299 if (cstat < mcl) return cstat;
00300 scl = clust;
00301 }
00302
00303 ncl = scl;
00304 for (;;) {
00305 ncl++;
00306 if (ncl >= mcl) {
00307 ncl = 2;
00308 if (ncl > scl) return 0;
00309 }
00310 cstat = get_cluster(fs, ncl);
00311 if (cstat == 0) break;
00312 if (cstat == 1) return 1;
00313 if (ncl == scl) return 0;
00314 }
00315
00316 if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1;
00317 if (clust != 0 && !put_cluster(fs, clust, ncl)) return 1;
00318
00319 fs->last_clust = ncl;
00320 if (fs->free_clust != 0xFFFFFFFF) {
00321 fs->free_clust--;
00322 #if _USE_FSINFO
00323 fs->fsi_flag = 1;
00324 #endif
00325 }
00326
00327 return ncl;
00328 }
00329 #endif
00330
00331
00332
00333
00334
00335
00336
00337
00338 static
00339 DWORD clust2sect (
00340 FATFS *fs,
00341 DWORD clust
00342 )
00343 {
00344 clust -= 2;
00345 if (clust >= (fs->max_clust - 2)) return 0;
00346 return clust * fs->csize + fs->database;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356 static
00357 BOOL next_dir_entry (
00358 DIR *dj
00359 )
00360 {
00361 DWORD clust;
00362 WORD idx;
00363
00364
00365 idx = dj->index + 1;
00366 if ((idx & ((SS(dj->fs) - 1) / 32)) == 0) {
00367 dj->sect++;
00368 if (dj->clust == 0) {
00369 if (idx >= dj->fs->n_rootdir) return FALSE;
00370 } else {
00371 if (((idx / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) {
00372 clust = get_cluster(dj->fs, dj->clust);
00373 if (clust < 2 || clust >= dj->fs->max_clust)
00374 return FALSE;
00375 dj->clust = clust;
00376 dj->sect = clust2sect(dj->fs, clust);
00377 }
00378 }
00379 }
00380 dj->index = idx;
00381 return TRUE;
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391 #if _FS_MINIMIZE <= 1
00392 static
00393 void get_fileinfo (
00394 FILINFO *finfo,
00395 const BYTE *dir
00396 )
00397 {
00398 BYTE n, c, a;
00399 char *p;
00400
00401
00402 p = &finfo->fname[0];
00403 a = _USE_NTFLAG ? dir[DIR_NTres] : 0;
00404 for (n = 0; n < 8; n++) {
00405 c = dir[n];
00406 if (c == ' ') break;
00407 if (c == 0x05) c = 0xE5;
00408 if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20;
00409 *p++ = c;
00410 }
00411 if (dir[8] != ' ') {
00412 *p++ = '.';
00413 for (n = 8; n < 11; n++) {
00414 c = dir[n];
00415 if (c == ' ') break;
00416 if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20;
00417 *p++ = c;
00418 }
00419 }
00420 *p = '\0';
00421
00422 finfo->fattrib = dir[DIR_Attr];
00423 finfo->fsize = LD_DWORD(&dir[DIR_FileSize]);
00424 finfo->fdate = LD_WORD(&dir[DIR_WrtDate]);
00425 finfo->ftime = LD_WORD(&dir[DIR_WrtTime]);
00426 }
00427 #endif
00428
00429
00430
00431
00432
00433
00434
00435
00436 static
00437 char make_dirfile (
00438 const char **path,
00439 char *dirname
00440 )
00441 {
00442 BYTE n, t, c, a, b;
00443
00444
00445 memset(dirname, ' ', 8+3);
00446 a = 0; b = 0x18;
00447 n = 0; t = 8;
00448 for (;;) {
00449 c = *(*path)++;
00450 if (c == '\0' || c == '/') {
00451 if (n == 0) break;
00452 dirname[11] = _USE_NTFLAG ? (a & b) : 0;
00453 return c;
00454 }
00455 if (c <= ' ' || c == 0x7F) break;
00456 if (c == '.') {
00457 if (!(a & 1) && n >= 1 && n <= 8) {
00458 n = 8; t = 11; continue;
00459 }
00460 break;
00461 }
00462 if (_USE_SJIS &&
00463 ((c >= 0x81 && c <= 0x9F) ||
00464 (c >= 0xE0 && c <= 0xFC))) {
00465 if (n == 0 && c == 0xE5)
00466 c = 0x05;
00467 a ^= 0x01; goto md_l2;
00468 }
00469 if (c == '"') break;
00470 if (c <= ')') goto md_l1;
00471 if (c <= ',') break;
00472 if (c <= '9') goto md_l1;
00473 if (c <= '?') break;
00474 if (!(a & 1)) {
00475 if (c == '|') break;
00476 if (c >= '[' && c <= ']') break;
00477 if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
00478 (t == 8) ? (b &= 0xF7) : (b &= 0xEF);
00479 if (c >= 'a' && c <= 'z') {
00480 c -= 0x20;
00481 if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
00482 }
00483 }
00484 md_l1:
00485 a &= 0xFE;
00486 md_l2:
00487 if (n >= t) break;
00488 dirname[n++] = c;
00489 }
00490 return 1;
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500 static
00501 FRESULT trace_path (
00502 DIR *dj,
00503 char *fn,
00504 const char *path,
00505 BYTE **dir
00506 )
00507 {
00508 DWORD clust;
00509 char ds;
00510 BYTE *dptr = NULL;
00511 FATFS *fs = dj->fs;
00512
00513
00514
00515 clust = fs->dirbase;
00516 if (fs->fs_type == FS_FAT32) {
00517 dj->clust = dj->sclust = clust;
00518 dj->sect = clust2sect(fs, clust);
00519 } else {
00520 dj->clust = dj->sclust = 0;
00521 dj->sect = clust;
00522 }
00523 dj->index = 0;
00524
00525 if (*path == '\0') {
00526 *dir = NULL; return FR_OK;
00527 }
00528
00529 for (;;) {
00530 ds = make_dirfile(&path, fn);
00531 if (ds == 1) return FR_INVALID_NAME;
00532 for (;;) {
00533 if (!move_window(fs, dj->sect)) return FR_RW_ERROR;
00534 dptr = &fs->win[(dj->index & ((SS(fs) - 1) / 32)) * 32];
00535 if (dptr[DIR_Name] == 0)
00536 return !ds ? FR_NO_FILE : FR_NO_PATH;
00537 if (dptr[DIR_Name] != 0xE5
00538 && !(dptr[DIR_Attr] & AM_VOL)
00539 && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break;
00540 if (!next_dir_entry(dj))
00541 return !ds ? FR_NO_FILE : FR_NO_PATH;
00542 }
00543 if (!ds) { *dir = dptr; return FR_OK; }
00544 if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH;
00545 clust = ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | LD_WORD(&dptr[DIR_FstClusLO]);
00546 dj->clust = dj->sclust = clust;
00547 dj->sect = clust2sect(fs, clust);
00548 dj->index = 2;
00549 }
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 #if !_FS_READONLY
00560 static
00561 FRESULT reserve_direntry (
00562 DIR *dj,
00563 BYTE **dir
00564 )
00565 {
00566 DWORD clust, sector;
00567 BYTE c, n, *dptr;
00568 FATFS *fs = dj->fs;
00569
00570
00571
00572 clust = dj->sclust;
00573 if (clust != 0) {
00574 dj->clust = clust;
00575 dj->sect = clust2sect(fs, clust);
00576 } else {
00577 dj->sect = fs->dirbase;
00578 }
00579 dj->index = 0;
00580
00581 do {
00582 if (!move_window(fs, dj->sect)) return FR_RW_ERROR;
00583 dptr = &fs->win[(dj->index & ((SS(dj->fs) - 1) / 32)) * 32];
00584 c = dptr[DIR_Name];
00585 if (c == 0 || c == 0xE5) {
00586 *dir = dptr; return FR_OK;
00587 }
00588 } while (next_dir_entry(dj));
00589
00590
00591
00592 if (clust == 0 || !(clust = create_chain(fs, dj->clust))) return FR_DENIED;
00593 if (clust == 1 || !move_window(fs, 0)) return FR_RW_ERROR;
00594
00595
00596 fs->winsect = sector = clust2sect(fs, clust);
00597 memset(fs->win, 0, SS(fs));
00598 for (n = fs->csize; n; n--) {
00599 if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK)
00600 return FR_RW_ERROR;
00601 sector++;
00602 }
00603 fs->winflag = 1;
00604 *dir = fs->win;
00605
00606 return FR_OK;
00607 }
00608 #endif
00609
00610
00611
00612
00613
00614
00615
00616
00617 static
00618 BYTE check_fs (
00619 FATFS *fs,
00620 DWORD sect
00621 )
00622 {
00623 if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK)
00624 return 2;
00625 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)
00626 return 2;
00627
00628 if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3))
00629 return 0;
00630 if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
00631 return 0;
00632
00633 return 1;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643 static
00644 FRESULT auto_mount (
00645 const char **path,
00646 FATFS **rfs,
00647 BYTE chk_wp
00648 )
00649 {
00650 BYTE drv, fmt, *tbl;
00651 DSTATUS stat;
00652 DWORD bootsect, fatsize, totalsect, maxclust;
00653 const char *p = *path;
00654 FATFS *fs;
00655
00656
00657
00658 while (*p == ' ') p++;
00659 drv = p[0] - '0';
00660 if (drv <= 9 && p[1] == ':')
00661 p += 2;
00662 else
00663 drv = 0;
00664 if (*p == '/') p++;
00665 *path = p;
00666
00667
00668 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
00669 *rfs = fs = FatFs[drv];
00670 if (!fs) return FR_NOT_ENABLED;
00671
00672 if (fs->fs_type) {
00673 stat = disk_status(fs->drive);
00674 if (!(stat & STA_NOINIT)) {
00675 #if !_FS_READONLY
00676 if (chk_wp && (stat & STA_PROTECT))
00677 return FR_WRITE_PROTECTED;
00678 #endif
00679 return FR_OK;
00680 }
00681 }
00682
00683
00684
00685 memset(fs, 0, sizeof(FATFS));
00686 fs->drive = LD2PD(drv);
00687 stat = disk_initialize(fs->drive);
00688 if (stat & STA_NOINIT)
00689 return FR_NOT_READY;
00690 #if S_MAX_SIZ > 512
00691 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > S_MAX_SIZ)
00692 return FR_NO_FILESYSTEM;
00693 #endif
00694 #if !_FS_READONLY
00695 if (chk_wp && (stat & STA_PROTECT))
00696 return FR_WRITE_PROTECTED;
00697 #endif
00698
00699 fmt = check_fs(fs, bootsect = 0);
00700 if (fmt == 1) {
00701
00702 tbl = &fs->win[MBR_Table + LD2PT(drv) * 16];
00703 if (tbl[4]) {
00704 bootsect = LD_DWORD(&tbl[8]);
00705 fmt = check_fs(fs, bootsect);
00706 }
00707 }
00708 if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != SS(fs))
00709 return FR_NO_FILESYSTEM;
00710
00711
00712 fatsize = LD_WORD(&fs->win[BPB_FATSz16]);
00713 if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]);
00714 fs->sects_fat = fatsize;
00715 fs->n_fats = fs->win[BPB_NumFATs];
00716 fatsize *= fs->n_fats;
00717 fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]);
00718 fs->csize = fs->win[BPB_SecPerClus];
00719 fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);
00720 totalsect = LD_WORD(&fs->win[BPB_TotSec16]);
00721 if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]);
00722 fs->max_clust = maxclust = (totalsect
00723 - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (SS(fs)/32)
00724 ) / fs->csize + 2;
00725
00726 fmt = FS_FAT12;
00727 if (maxclust >= 0xFF7) fmt = FS_FAT16;
00728 if (maxclust >= 0xFFF7) fmt = FS_FAT32;
00729
00730 if (fmt == FS_FAT32)
00731 fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);
00732 else
00733 fs->dirbase = fs->fatbase + fatsize;
00734 fs->database = fs->fatbase + fatsize + fs->n_rootdir / (SS(fs)/32);
00735
00736 #if !_FS_READONLY
00737
00738 fs->free_clust = 0xFFFFFFFF;
00739 #if _USE_FSINFO
00740
00741 if (fmt == FS_FAT32) {
00742 fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
00743 if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
00744 LD_WORD(&fs->win[BS_55AA]) == 0xAA55 &&
00745 LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 &&
00746 LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) {
00747 fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]);
00748 fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]);
00749 }
00750 }
00751 #endif
00752 #endif
00753
00754 fs->fs_type = fmt;
00755 fs->id = ++fsid;
00756 return FR_OK;
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766 static
00767 FRESULT validate (
00768 const FATFS *fs,
00769 WORD id
00770 )
00771 {
00772 if (!fs || !fs->fs_type || fs->id != id)
00773 return FR_INVALID_OBJECT;
00774 if (disk_status(fs->drive) & STA_NOINIT)
00775 return FR_NOT_READY;
00776
00777 return FR_OK;
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795 FRESULT f_mount (
00796 BYTE drv,
00797 FATFS *fs
00798 )
00799 {
00800 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
00801
00802 if (FatFs[drv]) FatFs[drv]->fs_type = 0;
00803
00804 FatFs[drv] = fs;
00805 if (fs) fs->fs_type = 0;
00806
00807 return FR_OK;
00808 }
00809
00810
00811
00812
00813
00814
00815
00816
00817 FRESULT f_open (
00818 FIL *fp,
00819 const char *path,
00820 BYTE mode
00821 )
00822 {
00823 FRESULT res;
00824 DIR dj;
00825 BYTE *dir;
00826 char fn[8+3+1];
00827
00828
00829 fp->fs = NULL;
00830 #if !_FS_READONLY
00831 mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
00832 res = auto_mount(&path, &dj.fs, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
00833 #else
00834 mode &= FA_READ;
00835 res = auto_mount(&path, &dj.fs, 0);
00836 #endif
00837 if (res != FR_OK) return res;
00838 res = trace_path(&dj, fn, path, &dir);
00839
00840 #if !_FS_READONLY
00841
00842 if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
00843 DWORD ps, rs;
00844 if (res != FR_OK) {
00845 if (res != FR_NO_FILE) return res;
00846 res = reserve_direntry(&dj, &dir);
00847 if (res != FR_OK) return res;
00848 memset(dir, 0, 32);
00849 memcpy(&dir[DIR_Name], fn, 8+3);
00850 dir[DIR_NTres] = fn[11];
00851 mode |= FA_CREATE_ALWAYS;
00852 }
00853 else {
00854 if (mode & FA_CREATE_NEW)
00855 return FR_EXIST;
00856 if (!dir || (dir[DIR_Attr] & (AM_RDO|AM_DIR)))
00857 return FR_DENIED;
00858 if (mode & FA_CREATE_ALWAYS) {
00859 rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
00860 ST_WORD(&dir[DIR_FstClusHI], 0);
00861 ST_WORD(&dir[DIR_FstClusLO], 0);
00862 ST_DWORD(&dir[DIR_FileSize], 0);
00863 dj.fs->winflag = 1;
00864 ps = dj.fs->winsect;
00865 if (!remove_chain(dj.fs, rs) || !move_window(dj.fs, ps))
00866 return FR_RW_ERROR;
00867 dj.fs->last_clust = rs - 1;
00868 }
00869 }
00870 if (mode & FA_CREATE_ALWAYS) {
00871 dir[DIR_Attr] = 0;
00872 ps = get_fattime();
00873 ST_DWORD(&dir[DIR_CrtTime], ps);
00874 dj.fs->winflag = 1;
00875 mode |= FA__WRITTEN;
00876 }
00877 }
00878
00879 else {
00880 #endif
00881 if (res != FR_OK) return res;
00882 if (!dir || (dir[DIR_Attr] & AM_DIR))
00883 return FR_NO_FILE;
00884 #if !_FS_READONLY
00885 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO))
00886 return FR_DENIED;
00887 }
00888 fp->dir_sect = dj.fs->winsect;
00889 fp->dir_ptr = dir;
00890 #endif
00891 fp->flag = mode;
00892 fp->org_clust =
00893 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
00894 fp->fsize = LD_DWORD(&dir[DIR_FileSize]);
00895 fp->fptr = 0; fp->csect = 255;
00896 fp->curr_sect = 0;
00897 fp->fs = dj.fs; fp->id = dj.fs->id;
00898
00899 return FR_OK;
00900 }
00901
00902
00903
00904
00905
00906
00907
00908
00909 FRESULT f_read (
00910 FIL *fp,
00911 void *buff,
00912 UINT btr,
00913 UINT *br
00914 )
00915 {
00916 FRESULT res;
00917 DWORD clust, sect, remain;
00918 UINT rcnt, cc;
00919 BYTE *rbuff = buff;
00920
00921
00922 *br = 0;
00923 res = validate(fp->fs, fp->id);
00924 if (res != FR_OK) return res;
00925 if (fp->flag & FA__ERROR) return FR_RW_ERROR;
00926 if (!(fp->flag & FA_READ)) return FR_DENIED;
00927 remain = fp->fsize - fp->fptr;
00928 if (btr > remain) btr = (UINT)remain;
00929
00930 for ( ; btr;
00931 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
00932 if ((fp->fptr % SS(fp->fs)) == 0) {
00933 if (fp->csect >= fp->fs->csize) {
00934 clust = (fp->fptr == 0) ?
00935 fp->org_clust : get_cluster(fp->fs, fp->curr_clust);
00936 if (clust < 2 || clust >= fp->fs->max_clust) goto fr_error;
00937 fp->curr_clust = clust;
00938 fp->csect = 0;
00939 }
00940 sect = clust2sect(fp->fs, fp->curr_clust) + fp->csect;
00941 cc = btr / SS(fp->fs);
00942 if (cc) {
00943 if (fp->csect + cc > fp->fs->csize)
00944 cc = fp->fs->csize - fp->csect;
00945 if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
00946 goto fr_error;
00947 fp->csect += (BYTE)cc;
00948 rcnt = SS(fp->fs) * cc;
00949 continue;
00950 }
00951 if (sect != fp->curr_sect) {
00952 #if !_FS_READONLY
00953 if (fp->flag & FA__DIRTY) {
00954 if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
00955 goto fr_error;
00956 fp->flag &= (BYTE)~FA__DIRTY;
00957 }
00958 #endif
00959 if (disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK)
00960 goto fr_error;
00961 fp->curr_sect = sect;
00962 }
00963 fp->csect++;
00964 }
00965 rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));
00966 if (rcnt > btr) rcnt = btr;
00967 memcpy(rbuff, &fp->buffer[fp->fptr % SS(fp->fs)], rcnt);
00968 }
00969
00970 return FR_OK;
00971
00972 fr_error:
00973 fp->flag |= FA__ERROR;
00974 return FR_RW_ERROR;
00975 }
00976
00977
00978
00979
00980 #if !_FS_READONLY
00981
00982
00983
00984
00985 FRESULT f_write (
00986 FIL *fp,
00987 const void *buff,
00988 UINT btw,
00989 UINT *bw
00990 )
00991 {
00992 FRESULT res;
00993 DWORD clust, sect;
00994 UINT wcnt, cc;
00995 const BYTE *wbuff = buff;
00996
00997
00998 *bw = 0;
00999 res = validate(fp->fs, fp->id);
01000 if (res != FR_OK) return res;
01001 if (fp->flag & FA__ERROR) return FR_RW_ERROR;
01002 if (!(fp->flag & FA_WRITE)) return FR_DENIED;
01003 if (fp->fsize + btw < fp->fsize) return FR_OK;
01004
01005 for ( ; btw;
01006 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
01007 if ((fp->fptr % SS(fp->fs)) == 0) {
01008 if (fp->csect >= fp->fs->csize) {
01009 if (fp->fptr == 0) {
01010 clust = fp->org_clust;
01011 if (clust == 0)
01012 fp->org_clust = clust = create_chain(fp->fs, 0);
01013 } else {
01014 clust = create_chain(fp->fs, fp->curr_clust);
01015 }
01016 if (clust == 0) break;
01017 if (clust == 1 || clust >= fp->fs->max_clust) goto fw_error;
01018 fp->curr_clust = clust;
01019 fp->csect = 0;
01020 }
01021 sect = clust2sect(fp->fs, fp->curr_clust) + fp->csect;
01022 cc = btw / SS(fp->fs);
01023 if (cc) {
01024 if (fp->csect + cc > fp->fs->csize)
01025 cc = fp->fs->csize - fp->csect;
01026 if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
01027 goto fw_error;
01028 fp->csect += (BYTE)cc;
01029 wcnt = SS(fp->fs) * cc;
01030 continue;
01031 }
01032 if (sect != fp->curr_sect) {
01033 if (fp->flag & FA__DIRTY) {
01034 if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
01035 goto fw_error;
01036 fp->flag &= (BYTE)~FA__DIRTY;
01037 }
01038 if (fp->fptr < fp->fsize &&
01039 disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK)
01040 goto fw_error;
01041 fp->curr_sect = sect;
01042 }
01043 fp->csect++;
01044 }
01045 wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));
01046 if (wcnt > btw) wcnt = btw;
01047 memcpy(&fp->buffer[fp->fptr % SS(fp->fs)], wbuff, wcnt);
01048 fp->flag |= FA__DIRTY;
01049 }
01050
01051 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;
01052 fp->flag |= FA__WRITTEN;
01053 return FR_OK;
01054
01055 fw_error:
01056 fp->flag |= FA__ERROR;
01057 return FR_RW_ERROR;
01058 }
01059
01060
01061
01062
01063
01064
01065
01066
01067 FRESULT f_sync (
01068 FIL *fp
01069 )
01070 {
01071 FRESULT res;
01072 DWORD tim;
01073 BYTE *dir;
01074
01075
01076 res = validate(fp->fs, fp->id);
01077 if (res == FR_OK) {
01078 if (fp->flag & FA__WRITTEN) {
01079
01080 if (fp->flag & FA__DIRTY) {
01081 if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
01082 return FR_RW_ERROR;
01083 fp->flag &= (BYTE)~FA__DIRTY;
01084 }
01085
01086 if (!move_window(fp->fs, fp->dir_sect))
01087 return FR_RW_ERROR;
01088 dir = fp->dir_ptr;
01089 dir[DIR_Attr] |= AM_ARC;
01090 ST_DWORD(&dir[DIR_FileSize], fp->fsize);
01091 ST_WORD(&dir[DIR_FstClusLO], fp->org_clust);
01092 ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16);
01093 tim = get_fattime();
01094 ST_DWORD(&dir[DIR_WrtTime], tim);
01095 fp->flag &= (BYTE)~FA__WRITTEN;
01096 res = sync(fp->fs);
01097 }
01098 }
01099 return res;
01100 }
01101
01102 #endif
01103
01104
01105
01106
01107
01108
01109
01110
01111 FRESULT f_close (
01112 FIL *fp
01113 )
01114 {
01115 FRESULT res;
01116
01117
01118 #if !_FS_READONLY
01119 res = f_sync(fp);
01120 #else
01121 res = validate(fp->fs, fp->id);
01122 #endif
01123 if (res == FR_OK) fp->fs = NULL;
01124 return res;
01125 }
01126
01127
01128
01129
01130 #if _FS_MINIMIZE <= 2
01131
01132
01133
01134
01135 FRESULT f_lseek (
01136 FIL *fp,
01137 DWORD ofs
01138 )
01139 {
01140 FRESULT res;
01141 DWORD clust, csize, nsect, ifptr;
01142
01143
01144 res = validate(fp->fs, fp->id);
01145 if (res != FR_OK) return res;
01146 if (fp->flag & FA__ERROR) return FR_RW_ERROR;
01147 if (ofs > fp->fsize
01148 #if !_FS_READONLY
01149 && !(fp->flag & FA_WRITE)
01150 #endif
01151 ) ofs = fp->fsize;
01152
01153 ifptr = fp->fptr;
01154 fp->fptr = 0; fp->csect = 255;
01155 nsect = 0;
01156 if (ofs > 0) {
01157 csize = (DWORD)fp->fs->csize * SS(fp->fs);
01158 if (ifptr > 0 &&
01159 (ofs - 1) / csize >= (ifptr - 1) / csize) {
01160 fp->fptr = (ifptr - 1) & ~(csize - 1);
01161 ofs -= fp->fptr;
01162 clust = fp->curr_clust;
01163 } else {
01164 clust = fp->org_clust;
01165 #if !_FS_READONLY
01166 if (clust == 0) {
01167 clust = create_chain(fp->fs, 0);
01168 if (clust == 1) goto fk_error;
01169 fp->org_clust = clust;
01170 }
01171 #endif
01172 fp->curr_clust = clust;
01173 }
01174 if (clust != 0) {
01175 while (ofs > csize) {
01176 #if !_FS_READONLY
01177 if (fp->flag & FA_WRITE) {
01178 clust = create_chain(fp->fs, clust);
01179 if (clust == 0) {
01180 ofs = csize; break;
01181 }
01182 } else
01183 #endif
01184 clust = get_cluster(fp->fs, clust);
01185 if (clust < 2 || clust >= fp->fs->max_clust) goto fk_error;
01186 fp->curr_clust = clust;
01187 fp->fptr += csize;
01188 ofs -= csize;
01189 }
01190 fp->fptr += ofs;
01191 fp->csect = (BYTE)(ofs / SS(fp->fs));
01192 if (ofs & (SS(fp->fs) - 1)) {
01193 nsect = clust2sect(fp->fs, clust) + fp->csect;
01194 fp->csect++;
01195 }
01196 }
01197 }
01198 if (nsect && nsect != fp->curr_sect) {
01199 #if !_FS_READONLY
01200 if (fp->flag & FA__DIRTY) {
01201 if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
01202 goto fk_error;
01203 fp->flag &= (BYTE)~FA__DIRTY;
01204 }
01205 #endif
01206 if (disk_read(fp->fs->drive, fp->buffer, nsect, 1) != RES_OK)
01207 goto fk_error;
01208 fp->curr_sect = nsect;
01209 }
01210
01211 #if !_FS_READONLY
01212 if (fp->fptr > fp->fsize) {
01213 fp->fsize = fp->fptr;
01214 fp->flag |= FA__WRITTEN;
01215 }
01216 #endif
01217
01218 return FR_OK;
01219
01220 fk_error:
01221 fp->flag |= FA__ERROR;
01222 return FR_RW_ERROR;
01223 }
01224
01225
01226
01227
01228 #if _FS_MINIMIZE <= 1
01229
01230
01231
01232
01233 FRESULT f_opendir (
01234 DIR *dj,
01235 const char *path
01236 )
01237 {
01238 FRESULT res;
01239 BYTE *dir;
01240 char fn[8+3+1];
01241
01242
01243 res = auto_mount(&path, &dj->fs, 0);
01244 if (res == FR_OK) {
01245 res = trace_path(dj, fn, path, &dir);
01246 if (res == FR_OK) {
01247 if (dir) {
01248 if (dir[DIR_Attr] & AM_DIR) {
01249 dj->clust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
01250 dj->sect = clust2sect(dj->fs, dj->clust);
01251 dj->index = 2;
01252 } else {
01253 res = FR_NO_FILE;
01254 }
01255 }
01256 dj->id = dj->fs->id;
01257 }
01258 }
01259
01260 return res;
01261 }
01262
01263
01264
01265
01266
01267
01268
01269
01270 FRESULT f_readdir (
01271 DIR *dj,
01272 FILINFO *finfo
01273 )
01274 {
01275 BYTE *dir, c, res;
01276
01277
01278 res = validate(dj->fs, dj->id);
01279 if (res != FR_OK) return res;
01280
01281 finfo->fname[0] = 0;
01282 while (dj->sect) {
01283 if (!move_window(dj->fs, dj->sect))
01284 return FR_RW_ERROR;
01285 dir = &dj->fs->win[(dj->index & ((SS(dj->fs) - 1) >> 5)) * 32];
01286 c = dir[DIR_Name];
01287 if (c == 0) break;
01288 if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL))
01289 get_fileinfo(finfo, dir);
01290 if (!next_dir_entry(dj)) dj->sect = 0;
01291 if (finfo->fname[0]) break;
01292 }
01293
01294 return FR_OK;
01295 }
01296
01297
01298
01299
01300 #if _FS_MINIMIZE == 0
01301
01302
01303
01304
01305 FRESULT f_stat (
01306 const char *path,
01307 FILINFO *finfo
01308 )
01309 {
01310 FRESULT res;
01311 DIR dj;
01312 BYTE *dir;
01313 char fn[8+3+1];
01314
01315
01316 res = auto_mount(&path, &dj.fs, 0);
01317 if (res == FR_OK) {
01318 res = trace_path(&dj, fn, path, &dir);
01319 if (res == FR_OK) {
01320 if (dir)
01321 get_fileinfo(finfo, dir);
01322 else
01323 res = FR_INVALID_NAME;
01324 }
01325 }
01326
01327 return res;
01328 }
01329
01330
01331
01332 #if !_FS_READONLY
01333
01334
01335
01336
01337 FRESULT f_truncate (
01338 FIL *fp
01339 )
01340 {
01341 FRESULT res;
01342 DWORD ncl;
01343
01344
01345 res = validate(fp->fs, fp->id);
01346 if (res != FR_OK) return res;
01347 if (fp->flag & FA__ERROR) return FR_RW_ERROR;
01348 if (!(fp->flag & FA_WRITE)) return FR_DENIED;
01349
01350 if (fp->fsize > fp->fptr) {
01351 fp->fsize = fp->fptr;
01352 fp->flag |= FA__WRITTEN;
01353 if (fp->fptr == 0) {
01354 if (!remove_chain(fp->fs, fp->org_clust)) goto ft_error;
01355 fp->org_clust = 0;
01356 } else {
01357 ncl = get_cluster(fp->fs, fp->curr_clust);
01358 if (ncl < 2) goto ft_error;
01359 if (ncl < fp->fs->max_clust) {
01360 if (!put_cluster(fp->fs, fp->curr_clust, 0x0FFFFFFF)) goto ft_error;
01361 if (!remove_chain(fp->fs, ncl)) goto ft_error;
01362 }
01363 }
01364 }
01365
01366 return FR_OK;
01367
01368 ft_error:
01369 fp->flag |= FA__ERROR;
01370 return FR_RW_ERROR;
01371 }
01372
01373
01374
01375
01376
01377
01378
01379
01380 FRESULT f_getfree (
01381 const char *drv,
01382 DWORD *nclust,
01383 FATFS **fatfs
01384 )
01385 {
01386 FRESULT res;
01387 DWORD n, clust, sect;
01388 BYTE fat, f, *p;
01389
01390
01391
01392 res = auto_mount(&drv, fatfs, 0);
01393 if (res != FR_OK) return res;
01394
01395
01396 if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
01397 *nclust = (*fatfs)->free_clust;
01398 return FR_OK;
01399 }
01400
01401
01402 fat = (*fatfs)->fs_type;
01403 n = 0;
01404 if (fat == FS_FAT12) {
01405 clust = 2;
01406 do {
01407 if ((WORD)get_cluster(*fatfs, clust) == 0) n++;
01408 } while (++clust < (*fatfs)->max_clust);
01409 } else {
01410 clust = (*fatfs)->max_clust;
01411 sect = (*fatfs)->fatbase;
01412 f = 0; p = 0;
01413 do {
01414 if (!f) {
01415 if (!move_window(*fatfs, sect++)) return FR_RW_ERROR;
01416 p = (*fatfs)->win;
01417 }
01418 if (fat == FS_FAT16) {
01419 if (LD_WORD(p) == 0) n++;
01420 p += 2; f += 1;
01421 } else {
01422 if (LD_DWORD(p) == 0) n++;
01423 p += 4; f += 2;
01424 }
01425 } while (--clust);
01426 }
01427 (*fatfs)->free_clust = n;
01428 #if _USE_FSINFO
01429 if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
01430 #endif
01431
01432 *nclust = n;
01433 return FR_OK;
01434 }
01435
01436
01437
01438
01439
01440
01441
01442
01443 FRESULT f_unlink (
01444 const char *path
01445 )
01446 {
01447 FRESULT res;
01448 DIR dj;
01449 BYTE *dir, *sdir;
01450 DWORD dclust, dsect;
01451 char fn[8+3+1];
01452
01453
01454 res = auto_mount(&path, &dj.fs, 1);
01455 if (res != FR_OK) return res;
01456 res = trace_path(&dj, fn, path, &dir);
01457 if (res != FR_OK) return res;
01458 if (!dir) return FR_INVALID_NAME;
01459 if (dir[DIR_Attr] & AM_RDO) return FR_DENIED;
01460 dsect = dj.fs->winsect;
01461 dclust = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
01462
01463 if (dir[DIR_Attr] & AM_DIR) {
01464 dj.clust = dclust;
01465 dj.sect = clust2sect(dj.fs, dclust);
01466 dj.index = 2;
01467 do {
01468 if (!move_window(dj.fs, dj.sect)) return FR_RW_ERROR;
01469 sdir = &dj.fs->win[(dj.index & ((SS(dj.fs) - 1) >> 5)) * 32];
01470 if (sdir[DIR_Name] == 0) break;
01471 if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL))
01472 return FR_DENIED;
01473 } while (next_dir_entry(&dj));
01474 }
01475
01476 if (!move_window(dj.fs, dsect)) return FR_RW_ERROR;
01477 dir[DIR_Name] = 0xE5;
01478 dj.fs->winflag = 1;
01479 if (!remove_chain(dj.fs, dclust)) return FR_RW_ERROR;
01480
01481 return sync(dj.fs);
01482 }
01483
01484
01485
01486
01487
01488
01489
01490
01491 FRESULT f_mkdir (
01492 const char *path
01493 )
01494 {
01495 FRESULT res;
01496 DIR dj;
01497 BYTE *dir, *fw, n;
01498 char fn[8+3+1];
01499 DWORD sect, dsect, dclust, pclust, tim;
01500
01501
01502 res = auto_mount(&path, &dj.fs, 1);
01503 if (res != FR_OK) return res;
01504 res = trace_path(&dj, fn, path, &dir);
01505 if (res == FR_OK) return FR_EXIST;
01506 if (res != FR_NO_FILE) return res;
01507
01508 res = reserve_direntry(&dj, &dir);
01509 if (res != FR_OK) return res;
01510 sect = dj.fs->winsect;
01511 dclust = create_chain(dj.fs, 0);
01512 if (dclust == 1) return FR_RW_ERROR;
01513 dsect = clust2sect(dj.fs, dclust);
01514 if (!dsect) return FR_DENIED;
01515 if (!move_window(dj.fs, dsect)) return FR_RW_ERROR;
01516
01517 fw = dj.fs->win;
01518 memset(fw, 0, SS(dj.fs));
01519 for (n = 1; n < dj.fs->csize; n++) {
01520 if (disk_write(dj.fs->drive, fw, ++dsect, 1) != RES_OK)
01521 return FR_RW_ERROR;
01522 }
01523 memset(&fw[DIR_Name], ' ', 8+3);
01524 fw[DIR_Name] = '.';
01525 fw[DIR_Attr] = AM_DIR;
01526 tim = get_fattime();
01527 ST_DWORD(&fw[DIR_WrtTime], tim);
01528 memcpy(&fw[32], &fw[0], 32); fw[33] = '.';
01529 ST_WORD(&fw[ DIR_FstClusLO], dclust);
01530 ST_WORD(&fw[ DIR_FstClusHI], dclust >> 16);
01531 pclust = dj.sclust;
01532 if (dj.fs->fs_type == FS_FAT32 && pclust == dj.fs->dirbase) pclust = 0;
01533 ST_WORD(&fw[32+DIR_FstClusLO], pclust);
01534 ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16);
01535 dj.fs->winflag = 1;
01536
01537 if (!move_window(dj.fs, sect)) return FR_RW_ERROR;
01538 memset(&dir[0], 0, 32);
01539 memcpy(&dir[DIR_Name], fn, 8+3);
01540 dir[DIR_NTres] = fn[11];
01541 dir[DIR_Attr] = AM_DIR;
01542 ST_DWORD(&dir[DIR_WrtTime], tim);
01543 ST_WORD(&dir[DIR_FstClusLO], dclust);
01544 ST_WORD(&dir[DIR_FstClusHI], dclust >> 16);
01545
01546 return sync(dj.fs);
01547 }
01548
01549
01550
01551
01552
01553
01554
01555
01556 FRESULT f_chmod (
01557 const char *path,
01558 BYTE value,
01559 BYTE mask
01560 )
01561 {
01562 FRESULT res;
01563 DIR dj;
01564 BYTE *dir;
01565 char fn[8+3+1];
01566
01567
01568 res = auto_mount(&path, &dj.fs, 1);
01569 if (res == FR_OK) {
01570 res = trace_path(&dj, fn, path, &dir);
01571 if (res == FR_OK) {
01572 if (!dir) {
01573 res = FR_INVALID_NAME;
01574 } else {
01575 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;
01576 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask);
01577 res = sync(dj.fs);
01578 }
01579 }
01580 }
01581 return res;
01582 }
01583
01584
01585
01586
01587
01588
01589
01590
01591 FRESULT f_utime (
01592 const char *path,
01593 const FILINFO *finfo
01594 )
01595 {
01596 FRESULT res;
01597 DIR dj;
01598 BYTE *dir;
01599 char fn[8+3+1];
01600
01601
01602 res = auto_mount(&path, &dj.fs, 1);
01603 if (res == FR_OK) {
01604 res = trace_path(&dj, fn, path, &dir);
01605 if (res == FR_OK) {
01606 if (!dir) {
01607 res = FR_INVALID_NAME;
01608 } else {
01609 ST_WORD(&dir[DIR_WrtTime], finfo->ftime);
01610 ST_WORD(&dir[DIR_WrtDate], finfo->fdate);
01611 res = sync(dj.fs);
01612 }
01613 }
01614 }
01615 return res;
01616 }
01617
01618
01619
01620
01621
01622
01623
01624
01625 FRESULT f_rename (
01626 const char *path_old,
01627 const char *path_new
01628 )
01629 {
01630 FRESULT res;
01631 DIR dj;
01632 DWORD sect_old;
01633 BYTE *dir_old, *dir_new, direntry[32-11];
01634 char fn[8+3+1];
01635
01636
01637 res = auto_mount(&path_old, &dj.fs, 1);
01638 if (res != FR_OK) return res;
01639
01640 res = trace_path(&dj, fn, path_old, &dir_old);
01641 if (res != FR_OK) return res;
01642 if (!dir_old) return FR_NO_FILE;
01643 sect_old = dj.fs->winsect;
01644 memcpy(direntry, &dir_old[DIR_Attr], 32-11);
01645
01646 res = trace_path(&dj, fn, path_new, &dir_new);
01647 if (res == FR_OK) return FR_EXIST;
01648 if (res != FR_NO_FILE) return res;
01649 res = reserve_direntry(&dj, &dir_new);
01650 if (res != FR_OK) return res;
01651
01652 memcpy(&dir_new[DIR_Attr], direntry, 32-11);
01653 memcpy(&dir_new[DIR_Name], fn, 8+3);
01654 dir_new[DIR_NTres] = fn[11];
01655 dj.fs->winflag = 1;
01656
01657 if (!move_window(dj.fs, sect_old)) return FR_RW_ERROR;
01658 dir_old[DIR_Name] = 0xE5;
01659
01660 return sync(dj.fs);
01661 }
01662
01663 #endif
01664 #endif
01665 #endif
01666 #endif
01667
01668
01669
01670 #if _USE_MKFS && !_FS_READONLY
01671
01672
01673
01674 #define N_ROOTDIR 512
01675 #define N_FATS 1
01676 #define MAX_SECTOR 64000000UL
01677 #define MIN_SECTOR 2000UL
01678
01679
01680
01681 FRESULT f_mkfs (
01682 BYTE drv,
01683 BYTE partition,
01684 WORD allocsize
01685 )
01686 {
01687 BYTE fmt, m, *tbl;
01688 DWORD b_part, b_fat, b_dir, b_data;
01689 DWORD n_part, n_rsv, n_fat, n_dir;
01690 DWORD n_clust, n;
01691 FATFS *fs;
01692 DSTATUS stat;
01693
01694
01695
01696 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
01697 if (partition >= 2) return FR_MKFS_ABORTED;
01698 for (n = 512; n <= 32768U && n != allocsize; n <<= 1);
01699 if (n != allocsize) return FR_MKFS_ABORTED;
01700
01701
01702 fs = FatFs[drv];
01703 if (!fs) return FR_NOT_ENABLED;
01704 fs->fs_type = 0;
01705 drv = LD2PD(drv);
01706
01707
01708 stat = disk_initialize(drv);
01709 if (stat & STA_NOINIT) return FR_NOT_READY;
01710 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
01711 if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
01712 return FR_MKFS_ABORTED;
01713 if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
01714 b_part = (!partition) ? 63 : 0;
01715 n_part -= b_part;
01716 #if S_MAX_SIZ > 512
01717 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
01718 || SS(fs) > S_MAX_SIZ
01719 || SS(fs) > allocsize)
01720 return FR_MKFS_ABORTED;
01721 #endif
01722 allocsize /= SS(fs);
01723
01724
01725 n_clust = n_part / allocsize;
01726 fmt = FS_FAT12;
01727 if (n_clust >= 0xFF5) fmt = FS_FAT16;
01728 if (n_clust >= 0xFFF5) fmt = FS_FAT32;
01729
01730
01731 switch (fmt) {
01732 case FS_FAT12:
01733 n_fat = ((n_clust * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
01734 n_rsv = 1 + partition;
01735 n_dir = N_ROOTDIR * 32 / SS(fs);
01736 break;
01737 case FS_FAT16:
01738 n_fat = ((n_clust * 2) + 4 + SS(fs) - 1) / SS(fs);
01739 n_rsv = 1 + partition;
01740 n_dir = N_ROOTDIR * 32 / SS(fs);
01741 break;
01742 default:
01743 n_fat = ((n_clust * 4) + 8 + SS(fs) - 1) / SS(fs);
01744 n_rsv = 33 - partition;
01745 n_dir = 0;
01746 }
01747 b_fat = b_part + n_rsv;
01748 b_dir = b_fat + n_fat * N_FATS;
01749 b_data = b_dir + n_dir;
01750
01751
01752 if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
01753 n = (b_data + n - 1) & ~(n - 1);
01754 n_fat += (n - b_data) / N_FATS;
01755
01756
01757
01758 n_clust = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
01759 if ( (fmt == FS_FAT16 && n_clust < 0xFF5)
01760 || (fmt == FS_FAT32 && n_clust < 0xFFF5))
01761 return FR_MKFS_ABORTED;
01762
01763
01764 if (!partition) {
01765 DWORD n_disk = b_part + n_part;
01766
01767 tbl = &fs->win[MBR_Table];
01768 ST_DWORD(&tbl[0], 0x00010180);
01769 if (n_disk < 63UL * 255 * 1024) {
01770 n_disk = n_disk / 63 / 255;
01771 tbl[7] = (BYTE)n_disk;
01772 tbl[6] = (BYTE)((n_disk >> 2) | 63);
01773 } else {
01774 ST_WORD(&tbl[6], 0xFFFF);
01775 }
01776 tbl[5] = 254;
01777 if (fmt != FS_FAT32)
01778 tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
01779 else
01780 tbl[4] = 0x0c;
01781 ST_DWORD(&tbl[8], 63);
01782 ST_DWORD(&tbl[12], n_part);
01783 ST_WORD(&tbl[64], 0xAA55);
01784 if (disk_write(drv, fs->win, 0, 1) != RES_OK)
01785 return FR_RW_ERROR;
01786 }
01787
01788
01789 tbl = fs->win;
01790 memset(tbl, 0, SS(fs));
01791 ST_DWORD(&tbl[BS_jmpBoot], 0x90FEEB);
01792 ST_WORD(&tbl[BPB_BytsPerSec], SS(fs));
01793 tbl[BPB_SecPerClus] = (BYTE)allocsize;
01794 ST_WORD(&tbl[BPB_RsvdSecCnt], n_rsv);
01795 tbl[BPB_NumFATs] = N_FATS;
01796 ST_WORD(&tbl[BPB_RootEntCnt], SS(fs) / 32 * n_dir);
01797 if (n_part < 0x10000) {
01798 ST_WORD(&tbl[BPB_TotSec16], n_part);
01799 } else {
01800 ST_DWORD(&tbl[BPB_TotSec32], n_part);
01801 }
01802 tbl[BPB_Media] = 0xF8;
01803 ST_WORD(&tbl[BPB_SecPerTrk], 63);
01804 ST_WORD(&tbl[BPB_NumHeads], 255);
01805 ST_DWORD(&tbl[BPB_HiddSec], b_part);
01806 n = get_fattime();
01807 if (fmt != FS_FAT32) {
01808 ST_DWORD(&tbl[BS_VolID], n);
01809 ST_WORD(&tbl[BPB_FATSz16], n_fat);
01810 tbl[BS_DrvNum] = 0x80;
01811 tbl[BS_BootSig] = 0x29;
01812 memcpy(&tbl[BS_VolLab], "NO NAME FAT ", 19);
01813 } else {
01814 ST_DWORD(&tbl[BS_VolID32], n);
01815 ST_DWORD(&tbl[BPB_FATSz32], n_fat);
01816 ST_DWORD(&tbl[BPB_RootClus], 2);
01817 ST_WORD(&tbl[BPB_FSInfo], 1);
01818 ST_WORD(&tbl[BPB_BkBootSec], 6);
01819 tbl[BS_DrvNum32] = 0x80;
01820 tbl[BS_BootSig32] = 0x29;
01821 memcpy(&tbl[BS_VolLab32], "NO NAME FAT32 ", 19);
01822 }
01823 ST_WORD(&tbl[BS_55AA], 0xAA55);
01824 if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
01825 return FR_RW_ERROR;
01826 if (fmt == FS_FAT32)
01827 disk_write(drv, tbl, b_part+6, 1);
01828
01829
01830 for (m = 0; m < N_FATS; m++) {
01831 memset(tbl, 0, SS(fs));
01832 if (fmt != FS_FAT32) {
01833 n = (fmt == FS_FAT12) ? 0x00FFFFF8 : 0xFFFFFFF8;
01834 ST_DWORD(&tbl[0], n);
01835 } else {
01836 ST_DWORD(&tbl[0], 0xFFFFFFF8);
01837 ST_DWORD(&tbl[4], 0xFFFFFFFF);
01838 ST_DWORD(&tbl[8], 0x0FFFFFFF);
01839 }
01840 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
01841 return FR_RW_ERROR;
01842 memset(tbl, 0, SS(fs));
01843 for (n = 1; n < n_fat; n++) {
01844 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
01845 return FR_RW_ERROR;
01846 }
01847 }
01848
01849
01850 m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
01851 do {
01852 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
01853 return FR_RW_ERROR;
01854 } while (--m);
01855
01856
01857 if (fmt == FS_FAT32) {
01858 ST_WORD(&tbl[BS_55AA], 0xAA55);
01859 ST_DWORD(&tbl[FSI_LeadSig], 0x41615252);
01860 ST_DWORD(&tbl[FSI_StrucSig], 0x61417272);
01861 ST_DWORD(&tbl[FSI_Free_Count], n_clust - 1);
01862 ST_DWORD(&tbl[FSI_Nxt_Free], 0xFFFFFFFF);
01863 disk_write(drv, tbl, b_part+1, 1);
01864 disk_write(drv, tbl, b_part+7, 1);
01865 }
01866
01867 return (disk_ioctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR;
01868 }
01869
01870 #endif
01871
01872
01873
01874
01875 #if _USE_STRFUNC >= 1
01876
01877
01878
01879 char* fgets (
01880 char* buff,
01881 int len,
01882 FIL* fil
01883 )
01884 {
01885 int i = 0;
01886 char *p = buff;
01887 UINT rc;
01888
01889
01890 while (i < len - 1) {
01891 f_read(fil, p, 1, &rc);
01892 if (rc != 1) break;
01893 #if _USE_STRFUNC >= 2
01894 if (*p == '\r') continue;
01895 #endif
01896 i++;
01897 if (*p++ == '\n') break;
01898 }
01899 *p = 0;
01900 return i ? buff : 0;
01901 }
01902
01903
01904
01905 #if !_FS_READONLY
01906 #include <stdarg.h>
01907
01908
01909
01910 int fputc (
01911 int chr,
01912 FIL* fil
01913 )
01914 {
01915 UINT bw;
01916 char c;
01917
01918
01919 #if _USE_STRFUNC >= 2
01920 if (chr == '\n') fputc ('\r', fil);
01921 #endif
01922 if (!fil) {
01923
01924 return chr;
01925 }
01926 c = (char)chr;
01927 f_write(fil, &c, 1, &bw);
01928 return bw ? chr : EOF;
01929 }
01930
01931
01932
01933
01934
01935
01936
01937 int fputs (
01938 const char* str,
01939 FIL* fil
01940 )
01941 {
01942 int n;
01943
01944
01945 for (n = 0; *str; str++, n++) {
01946 if (fputc(*str, fil) == EOF) return EOF;
01947 }
01948 return n;
01949 }
01950
01951
01952
01953
01954
01955
01956
01957 int fprintf (
01958 FIL* fil,
01959 const char* str,
01960 ...
01961 )
01962 {
01963 va_list arp;
01964 UCHAR c, f, r;
01965 ULONG val;
01966 char s[16];
01967 int i, w, res, cc;
01968
01969
01970 va_start(arp, str);
01971
01972 for (cc = res = 0; cc != EOF; res += cc) {
01973 c = *str++;
01974 if (c == 0) break;
01975 if (c != '%') {
01976 cc = fputc(c, fil);
01977 if (cc != EOF) cc = 1;
01978 continue;
01979 }
01980 w = f = 0;
01981 c = *str++;
01982 if (c == '0') {
01983 f = 1; c = *str++;
01984 }
01985 while (c >= '0' && c <= '9') {
01986 w = w * 10 + (c - '0');
01987 c = *str++;
01988 }
01989 if (c == 'l') {
01990 f |= 2; c = *str++;
01991 }
01992 if (c == 's') {
01993 cc = fputs(va_arg(arp, char*), fil);
01994 continue;
01995 }
01996 if (c == 'c') {
01997 cc = fputc(va_arg(arp, char), fil);
01998 if (cc != EOF) cc = 1;
01999 continue;
02000 }
02001 r = 0;
02002 if (c == 'd') r = 10;
02003 if (c == 'u') r = 10;
02004 if (c == 'X') r = 16;
02005 if (r == 0) break;
02006 if (f & 2) {
02007 val = (ULONG)va_arg(arp, long);
02008 } else {
02009 val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
02010 }
02011
02012 if (c == 'd') {
02013 if (val >= 0x80000000) {
02014 val = 0 - val;
02015 f |= 4;
02016 }
02017 }
02018 i = sizeof(s) - 1; s[i] = 0;
02019 do {
02020 c = (UCHAR)(val % r + '0');
02021 if (c > '9') c += 7;
02022 s[--i] = c;
02023 val /= r;
02024 } while (i && val);
02025 if (i && (f & 4)) s[--i] = '-';
02026 w = sizeof(s) - 1 - w;
02027 while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
02028 cc = fputs(&s[i], fil);
02029 }
02030
02031 va_end(arp);
02032 return (cc == EOF) ? cc : res;
02033 }
02034
02035 #endif
02036 #endif