1 /*----------------------------------------------------------------------------/ 
   2 /  Petit FatFs - FAT file system module  R0.01a                (C)ChaN, 2009 
   3 /-----------------------------------------------------------------------------/ 
   4 / Petit FatFs module is an open source software to implement FAT file system to 
   5 / small embedded systems. This is a free software and is opened for education, 
   6 / research and commercial developments under license policy of following trems. 
   8 /  Copyright (C) 2009, ChaN, all right reserved. 
  10 / * The Petit FatFs module is a free software and there is NO WARRANTY. 
  11 / * No restriction on use. You can use, modify and redistribute it for 
  12 /   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. 
  13 / * Redistributions of source code must retain the above copyright notice. 
  15 /-----------------------------------------------------------------------------/ 
  16 / Jun 15,'09 R0.01a  Branched from FatFs R0.07b 
  17 /----------------------------------------------------------------------------*/ 
  19 #include "pff.h"                /* Petit FatFs configurations and declarations */ 
  20 #include "diskio.h"             /* Declarations of low level disk I/O functions */ 
  23 /*-------------------------------------------------------------------------- 
  27 ---------------------------------------------------------------------------*/ 
  30 FATFS 
*FatFs
;   /* Pointer to the file system object (logical drive) */ 
  33 /*-------------------------------------------------------------------------- 
  37 ---------------------------------------------------------------------------*/ 
  40 /*-----------------------------------------------------------------------*/ 
  41 /* String functions                                                      */ 
  42 /*-----------------------------------------------------------------------*/ 
  46 void mem_set (void* dst
, int val
, int cnt
) { 
  48         while (cnt
--) *d
++ = (char)val
; 
  51 /* Compare memory to memory */ 
  53 int mem_cmp (const void* dst
, const void* src
, int cnt
) { 
  54         const char *d 
= (const char *)dst
, *s 
= (const char *)src
; 
  56         while (cnt
-- && (r 
= *d
++ - *s
++) == 0) ; 
  60 /* Check if chr is contained in the string */ 
  62 int chk_chr (const char* str
, int chr
) { 
  63         while (*str 
&& *str 
!= chr
) str
++; 
  69 /*-----------------------------------------------------------------------*/ 
  70 /* FAT access - Read value of a FAT entry                                */ 
  71 /*-----------------------------------------------------------------------*/ 
  74 CLUST 
get_fat ( /* 1:IO error, Else:Cluster status */ 
  75         CLUST clst      
/* Cluster# to get the link information */ 
  83         if (clst 
< 2 || clst 
>= fs
->max_clust
)  /* Range check */ 
  86         switch (fs
->fs_type
) { 
  88                 bc 
= (WORD
)clst
; bc 
+= bc 
/ 2; 
  89                 ofs 
= bc 
% 512; bc 
/= 512; 
  91                         if (disk_readp(buf
, fs
->fatbase 
+ bc
, ofs
, 2)) break; 
  93                         if (disk_readp(buf
, fs
->fatbase 
+ bc
, 511, 1)) break; 
  94                         if (disk_readp(buf
+1, fs
->fatbase 
+ bc 
+ 1, 0, 1)) break; 
  97                 return (clst 
& 1) ? 
(wc 
>> 4) : (wc 
& 0xFFF); 
 100                 if (disk_readp(buf
, fs
->fatbase 
+ clst 
/ 256, (WORD
)(((WORD
)clst 
% 256) * 2), 2)) break; 
 104                 if (disk_readp(buf
, fs
->fatbase 
+ clst 
/ 128, (WORD
)(((WORD
)clst 
% 128) * 4), 4)) break; 
 105                 return LD_DWORD(buf
) & 0x0FFFFFFF; 
 109         return 1;       /* An error occured at the disk I/O layer */ 
 115 /*-----------------------------------------------------------------------*/ 
 116 /* Get sector# from cluster#                                             */ 
 117 /*-----------------------------------------------------------------------*/ 
 120 DWORD 
clust2sect (      /* !=0: Sector number, 0: Failed - invalid cluster# */ 
 121         CLUST clst              
/* Cluster# to be converted */ 
 128         if (clst 
>= (fs
->max_clust 
- 2)) return 0;              /* Invalid cluster# */ 
 129         return (DWORD
)clst 
* fs
->csize 
+ fs
->database
; 
 135 /*-----------------------------------------------------------------------*/ 
 136 /* Directory handling - Rewind directory index                           */ 
 137 /*-----------------------------------------------------------------------*/ 
 141         DIR *dj                 
/* Pointer to directory object */ 
 150         if (clst 
== 1 || clst 
>= fs
->max_clust
) /* Check start cluster range */ 
 153         if (!clst 
&& fs
->fs_type 
== FS_FAT32
)   /* Replace cluster# 0 with root cluster# if in FAT32 */ 
 156         dj
->clust 
= clst
;                                               /* Current cluster */ 
 157         dj
->sect 
= clst ? 
clust2sect(clst
) : fs
->dirbase
;       /* Current sector */ 
 159         return FR_OK
;   /* Seek succeeded */ 
 165 /*-----------------------------------------------------------------------*/ 
 166 /* Directory handling - Move directory index next                        */ 
 167 /*-----------------------------------------------------------------------*/ 
 170 FRESULT 
dir_next (      /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */ 
 171         DIR *dj                 
/* Pointer to directory object */ 
 180         if (!i 
|| !dj
->sect
)    /* Report EOT when index has reached 65535 */ 
 183         if (!(i 
& (16-1))) {    /* Sector changed? */ 
 184                 dj
->sect
++;                     /* Next sector */ 
 186                 if (dj
->clust 
== 0) {   /* Static table */ 
 187                         if (i 
>= fs
->n_rootdir
) /* Report EOT when end of table */ 
 190                 else {                                  /* Dynamic table */ 
 191                         if (((i 
/ 16) & (fs
->csize
-1)) == 0) {  /* Cluster changed? */ 
 192                                 clst 
= get_fat(dj
->clust
);              /* Get next cluster */ 
 193                                 if (clst 
<= 1) return FR_DISK_ERR
; 
 194                                 if (clst 
>= fs
->max_clust
)              /* When it reached end of dynamic table */ 
 195                                         return FR_NO_FILE
;                      /* Report EOT */ 
 196                                 dj
->clust 
= clst
;                               /* Initialize data for new cluster */ 
 197                                 dj
->sect 
= clust2sect(clst
); 
 210 /*-----------------------------------------------------------------------*/ 
 211 /* Directory handling - Find an object in the directory                  */ 
 212 /*-----------------------------------------------------------------------*/ 
 216         DIR *dj                 
/* Pointer to the directory object linked to the file name */ 
 223         res 
= dir_rewind(dj
);                   /* Rewind directory object */ 
 224         if (res 
!= FR_OK
) return res
; 
 228                 res 
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index 
% 16) * 32), 32)      /* Read an entry */ 
 229                         ? FR_DISK_ERR 
: FR_OK
; 
 230                 if (res 
!= FR_OK
) break; 
 231                 c 
= dir
[DIR_Name
];      /* First character */ 
 232                 if (c 
== 0) { res 
= FR_NO_FILE
; break; }        /* Reached to end of table */ 
 233                 if (!(dir
[DIR_Attr
] & AM_VOL
) && !mem_cmp(dir
, dj
->fn
, 11)) /* Is it a valid entry? */ 
 235                 res 
= dir_next(dj
);                                                     /* Next entry */ 
 236         } while (res 
== FR_OK
); 
 244 /*-----------------------------------------------------------------------*/ 
 245 /* Read an object from the directory                                     */ 
 246 /*-----------------------------------------------------------------------*/ 
 250         DIR *dj                 
/* Pointer to the directory object to store read object name */ 
 260                 res 
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index 
% 16) * 32), 32)      /* Read an entry */ 
 261                         ? FR_DISK_ERR 
: FR_OK
; 
 262                 if (res 
!= FR_OK
) break; 
 264                 if (c 
== 0) { res 
= FR_NO_FILE
; break; }        /* Reached to end of table */ 
 265                 a 
= dir
[DIR_Attr
] & AM_MASK
; 
 266                 if (c 
!= 0xE5 && c 
!= '.' && !(a 
& AM_VOL
))     /* Is it a valid entry? */ 
 268                 res 
= dir_next(dj
);                             /* Next entry */ 
 269                 if (res 
!= FR_OK
) break; 
 272         if (res 
!= FR_OK
) dj
->sect 
= 0; 
 280 /*-----------------------------------------------------------------------*/ 
 281 /* Pick a segment and create the object name in directory form           */ 
 282 /*-----------------------------------------------------------------------*/ 
 286 FRESULT 
create_name ( 
 287         DIR *dj
,                        /* Pointer to the directory object */ 
 288         const char **path       
/* Pointer to pointer to the segment in the path string */ 
 291         BYTE c
, ni
, si
, i
, *sfn
; 
 294         /* Create file name in directory form */ 
 296         mem_set(sfn
, ' ', 11); 
 301                 if (c 
< ' ' || c 
== '/') break; /* Break on end of segment */ 
 302                 if (c 
== '.' || i 
>= ni
) { 
 303                         if (ni 
!= 8 || c 
!= '.') return FR_INVALID_NAME
; 
 307                 if (c 
>= 0x7F || chk_chr(" +,;[=\\]\"*:<>\?|", c
))      /* Reject unallowable chrs for SFN */ 
 308                         return FR_INVALID_NAME
; 
 309                 if (c 
>='a' && c 
<= 'z') c 
-= 0x20; 
 312         if (!i
) return FR_INVALID_NAME
;         /* Reject null string */ 
 313         *path 
= &p
[si
];                                         /* Rerurn pointer to the next segment */ 
 315         sfn
[11] = (c 
< ' ') ? 
1 : 0;            /* Set last segment flag if end of path */ 
 323 /*-----------------------------------------------------------------------*/ 
 324 /* Get file information from directory entry                             */ 
 325 /*-----------------------------------------------------------------------*/ 
 328 void get_fileinfo (             /* No return code */ 
 329         DIR *dj
,                        /* Pointer to the directory object */ 
 330         FILINFO 
*fno            
/* Pointer to store the file information */ 
 340                 for (i 
= 0; i 
< 8; i
++) {       /* Copy file name body */ 
 343                         if (c 
== 0x05) c 
= 0xE5; 
 346                 if (dir
[8] != ' ') {            /* Copy file name extension */ 
 348                         for (i 
= 8; i 
< 11; i
++) { 
 354                 fno
->fattrib 
= dir
[DIR_Attr
];                           /* Attribute */ 
 355                 fno
->fsize 
= LD_DWORD(dir
+DIR_FileSize
);        /* Size */ 
 356                 fno
->fdate 
= LD_WORD(dir
+DIR_WrtDate
);          /* Date */ 
 357                 fno
->ftime 
= LD_WORD(dir
+DIR_WrtTime
);          /* Time */ 
 361 #endif /* _USE_DIR */ 
 365 /*-----------------------------------------------------------------------*/ 
 366 /* Follow a file path                                                    */ 
 367 /*-----------------------------------------------------------------------*/ 
 370 FRESULT 
follow_path (   /* FR_OK(0): successful, !=0: error code */ 
 371         DIR *dj
,                        /* Directory object to return last directory and found object */ 
 372         const char *path        
/* Full-path string to find a file or directory */ 
 379         if (*path 
== '/') path
++;                       /* Strip heading separator */ 
 380         dj
->sclust 
= 0;                                         /* Set start directory (always root dir) */ 
 382         if ((BYTE
)*path 
< ' ') {                        /* Null path means the root directory */ 
 383                 res 
= dir_rewind(dj
); 
 386         } else {                                                        /* Follow path */ 
 388                         res 
= create_name(dj
, &path
);   /* Get a segment */ 
 389                         if (res 
!= FR_OK
) break; 
 390                         res 
= dir_find(dj
);                             /* Find it */ 
 391                         if (res 
!= FR_OK
) {                             /* Could not find the object */ 
 392                                 if (res 
== FR_NO_FILE 
&& !*(dj
->fn
+11)) 
 396                         if (*(dj
->fn
+11)) break;                /* Last segment match. Function completed. */ 
 397                         dir 
= FatFs
->buf
;                               /* There is next segment. Follow the sub directory */ 
 398                         if (!(dir
[DIR_Attr
] & AM_DIR
)) { /* Cannot follow because it is a file */ 
 399                                 res 
= FR_NO_PATH
; break; 
 403                                 ((DWORD
)LD_WORD(dir
+DIR_FstClusHI
) << 16) |  
 405                                 LD_WORD(dir
+DIR_FstClusLO
); 
 415 /*-----------------------------------------------------------------------*/ 
 416 /* Check a sector if it is an FAT boot record                            */ 
 417 /*-----------------------------------------------------------------------*/ 
 420 BYTE 
check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */ 
 421         BYTE 
*buf
,      /* Working buffer */ 
 422         DWORD sect      
/* Sector# (lba) to check if it is an FAT boot record or not */ 
 425         if (disk_readp(buf
, sect
, 510, 2))              /* Read the boot sector */ 
 427         if (LD_WORD(buf
) != 0xAA55)                             /* Check record signature */ 
 430         if (!disk_readp(buf
, sect
, BS_FilSysType
, 2) && LD_WORD(buf
) == 0x4146) /* Check FAT12/16 */ 
 433         if (!disk_readp(buf
, sect
, BS_FilSysType32
, 2) && LD_WORD(buf
) == 0x4146)       /* Check FAT32 */ 
 442 /*-------------------------------------------------------------------------- 
 446 --------------------------------------------------------------------------*/ 
 450 /*-----------------------------------------------------------------------*/ 
 451 /* Mount/Unmount a Locical Drive                                         */ 
 452 /*-----------------------------------------------------------------------*/ 
 455         FATFS 
*fs               
/* Pointer to new file system object (NULL: Unmount) */ 
 459         DWORD bsect
, fsize
, tsect
, mclst
; 
 463         if (!fs
) return FR_OK
;                          /* Unregister fs object */ 
 465         if (disk_initialize() & STA_NOINIT
)     /* Check if the drive is ready or not */ 
 468         /* Search FAT partition on the drive */ 
 470         fmt 
= check_fs(buf
, bsect
);                     /* Check sector 0 as an SFD format */ 
 471         if (fmt 
== 1) {                                         /* Not an FAT boot record, it may be FDISK format */ 
 472                 /* Check a partition listed in top of the partition table */ 
 473                 if (disk_readp(buf
, bsect
, MBR_Table
, 16)) {    /* 1st partition entry */ 
 476                         if (buf
[4]) {                                   /* Is the partition existing? */ 
 477                                 bsect 
= LD_DWORD(&buf
[8]);      /* Partition offset in LBA */ 
 478                                 fmt 
= check_fs(buf
, bsect
);     /* Check the partition */ 
 482         if (fmt 
== 3) return FR_DISK_ERR
; 
 483         if (fmt
) return FR_NO_FILESYSTEM
;       /* No valid FAT patition is found */ 
 485         /* Initialize the file system object */ 
 486         if (disk_readp(buf
, bsect
, 13, sizeof(buf
))) return FR_DISK_ERR
; 
 488         fsize 
= LD_WORD(buf
+BPB_FATSz16
-13);                            /* Number of sectors per FAT */ 
 489         if (!fsize
) fsize 
= LD_DWORD(buf
+BPB_FATSz32
-13); 
 491         fsize 
*= buf
[BPB_NumFATs
-13];                                           /* Number of sectors in FAT area */ 
 492         fs
->fatbase 
= bsect 
+ LD_WORD(buf
+BPB_RsvdSecCnt
-13); /* FAT start sector (lba) */ 
 493         fs
->csize 
= buf
[BPB_SecPerClus
-13];                                     /* Number of sectors per cluster */ 
 494         fs
->n_rootdir 
= LD_WORD(buf
+BPB_RootEntCnt
-13);         /* Nmuber of root directory entries */ 
 495         tsect 
= LD_WORD(buf
+BPB_TotSec16
-13);                           /* Number of sectors on the file system */ 
 496         if (!tsect
) tsect 
= LD_DWORD(buf
+BPB_TotSec32
-13); 
 497         mclst 
= (tsect                                          
/* Last cluster# + 1 */ 
 498                 - LD_WORD(buf
+BPB_RsvdSecCnt
-13) - fsize 
- fs
->n_rootdir 
/ 16 
 500         fs
->max_clust 
= (CLUST
)mclst
; 
 502         fmt 
= FS_FAT12
;                                                 /* Determine the FAT sub type */ 
 503         if (mclst 
>= 0xFF7) fmt 
= FS_FAT16
;             /* Number of clusters >= 0xFF5 */ 
 504         if (mclst 
>= 0xFFF7)                                    /* Number of clusters >= 0xFFF5 */ 
 508                 return FR_NO_FILESYSTEM
; 
 511         fs
->fs_type 
= fmt
;              /* FAT sub-type */ 
 514                 fs
->dirbase 
= LD_DWORD(buf
+(BPB_RootClus
-13));  /* Root directory start cluster */ 
 517                 fs
->dirbase 
= fs
->fatbase 
+ fsize
;                              /* Root directory start sector (lba) */ 
 518         fs
->database 
= fs
->fatbase 
+ fsize 
+ fs
->n_rootdir 
/ 16;        /* Data start sector (lba) */ 
 529 /*-----------------------------------------------------------------------*/ 
 530 /* Open or Create a File                                                 */ 
 531 /*-----------------------------------------------------------------------*/ 
 534         const char *path        
/* Pointer to the file name */ 
 539         BYTE sp
[12], dir
[32]; 
 543         if (!fs
)                                                /* Check file system */ 
 544                 return FR_NOT_ENABLED
; 
 549         res 
= follow_path(&dj
, path
);   /* Follow the file path */ 
 550         if (res 
!= FR_OK
) return res
;   /* Follow failed */ 
 551         if (!dir
[0] || (dir
[DIR_Attr
] & AM_DIR
))        /* It is a directory */ 
 554         fs
->org_clust 
=                                         /* File start cluster */ 
 556                 ((DWORD
)LD_WORD(dir
+DIR_FstClusHI
) << 16) | 
 558                 LD_WORD(dir
+DIR_FstClusLO
); 
 559         fs
->fsize 
= LD_DWORD(dir
+DIR_FileSize
); /* File size */ 
 560         fs
->fptr 
= 0;                                           /* File pointer */ 
 569 /*-----------------------------------------------------------------------*/ 
 571 /*-----------------------------------------------------------------------*/ 
 574         void* dest
,             /* Pointer to the destination object */ 
 575         WORD btr
,               /* Number of bytes to read (bit15:destination) */ 
 576         WORD
* br                
/* Pointer to number of bytes read */ 
 588         if (!fs
) return FR_NOT_ENABLED
;         /* Check file system */ 
 589         if (!(fs
->flag 
& FA_READ
)) 
 590                         return FR_INVALID_OBJECT
; 
 592         remain 
= fs
->fsize 
- fs
->fptr
; 
 593         if (btr 
> remain
) btr 
= (UINT
)remain
;                   /* Truncate btr by remaining bytes */ 
 595         for ( ;  btr
;                                                                   /* Repeat until all data transferred */ 
 596                 rbuff 
+= rcnt
, fs
->fptr 
+= rcnt
, *br 
+= rcnt
, btr 
-= rcnt
) { 
 597                 if ((fs
->fptr 
% 512) == 0) {                            /* On the sector boundary? */ 
 598                         if ((fs
->fptr 
/ 512 % fs
->csize
) == 0) {        /* On the cluster boundary? */ 
 599                                 clst 
= (fs
->fptr 
== 0) ?                        
/* On the top of the file? */ 
 600                                         fs
->org_clust 
: get_fat(fs
->curr_clust
); 
 602                                         fs
->flag 
= 0; return FR_DISK_ERR
; 
 604                                 fs
->curr_clust 
= clst
;                          /* Update current cluster */ 
 605                                 fs
->csect 
= 0;                                          /* Reset sector offset in the cluster */ 
 607                         sect 
= clust2sect(fs
->curr_clust
);              /* Get current sector */ 
 609                                 fs
->flag 
= 0; return FR_DISK_ERR
; 
 613                         fs
->csect
++;                                                    /* Next sector address in the cluster */ 
 615                 rcnt 
= 512 - ((WORD
)fs
->fptr 
% 512);            /* Get partial sector data from sector buffer */ 
 616                 if (rcnt 
> btr
) rcnt 
= btr
; 
 617                 if (fs
->flag 
& FA_STREAM
) { 
 618                         dr 
= disk_readp(dest
, fs
->dsect
, (WORD
)(fs
->fptr 
% 512), (WORD
)(rcnt 
| 0x8000)); 
 620                         dr 
= disk_readp(rbuff
, fs
->dsect
, (WORD
)(fs
->fptr 
% 512), rcnt
); 
 624                         return (dr 
== RES_STRERR
) ? FR_STREAM_ERR 
: FR_DISK_ERR
; 
 635 /*-----------------------------------------------------------------------*/ 
 636 /* Seek File R/W Pointer                                                 */ 
 637 /*-----------------------------------------------------------------------*/ 
 640         DWORD ofs               
/* File pointer from top of file */ 
 644         DWORD bcs
, nsect
, ifptr
; 
 648         if (!fs
) return FR_NOT_ENABLED
;         /* Check file system */ 
 649         if (!(fs
->flag 
& FA_READ
)) 
 650                         return FR_INVALID_OBJECT
; 
 652         if (ofs 
> fs
->fsize
) ofs 
= fs
->fsize
;   /* Clip offset with the file size */ 
 656                 bcs 
= (DWORD
)fs
->csize 
* 512;   /* Cluster size (byte) */ 
 658                         (ofs 
- 1) / bcs 
>= (ifptr 
- 1) / bcs
) { /* When seek to same or following cluster, */ 
 659                         fs
->fptr 
= (ifptr 
- 1) & ~(bcs 
- 1);    /* start from the current cluster */ 
 661                         clst 
= fs
->curr_clust
; 
 662                 } else {                                                        /* When seek to back cluster, */ 
 663                         clst 
= fs
->org_clust
;                   /* start from the first cluster */ 
 664                         fs
->curr_clust 
= clst
; 
 666                 while (ofs 
> bcs
) {                             /* Cluster following loop */ 
 667                                 clst 
= get_fat(clst
);   /* Follow cluster chain if not in write mode */ 
 668                         if (clst 
<= 1 || clst 
>= fs
->max_clust
) { 
 669                                 fs
->flag 
= 0; return FR_DISK_ERR
; 
 671                         fs
->curr_clust 
= clst
; 
 676                 fs
->csect 
= (BYTE
)(ofs 
/ 512) + 1;      /* Sector offset in the cluster */ 
 677                 nsect 
= clust2sect(clst
);       /* Current sector */ 
 679                         fs
->flag 
= 0; return FR_DISK_ERR
; 
 681                 fs
->dsect 
= nsect 
+ fs
->csect 
- 1; 
 690 /*-----------------------------------------------------------------------*/ 
 691 /* Create a Directroy Object                                             */ 
 692 /*-----------------------------------------------------------------------*/ 
 695         DIR *dj
,                        /* Pointer to directory object to create */ 
 696         const char *path        
/* Pointer to the directory path */ 
 700         BYTE sp
[12], dir
[32]; 
 704         if (!fs
) {                              /* Check file system */ 
 705                 res 
= FR_NOT_ENABLED
; 
 709                 res 
= follow_path(dj
, path
);                    /* Follow the path to the directory */ 
 710                 if (res 
== FR_OK
) {                                             /* Follow completed */ 
 711                         if (dir
[0]) {                                           /* It is not the root dir */ 
 712                                 if (dir
[DIR_Attr
] & AM_DIR
) {   /* The object is a directory */ 
 715                                         ((DWORD
)LD_WORD(dir
+DIR_FstClusHI
) << 16) | 
 717                                         LD_WORD(dir
+DIR_FstClusLO
); 
 718                                 } else {                                                /* The object is not a directory */ 
 723                                 res 
= dir_rewind(dj
);                   /* Rewind dir */ 
 726                 if (res 
== FR_NO_FILE
) res 
= FR_NO_PATH
; 
 735 /*-----------------------------------------------------------------------*/ 
 736 /* Read Directory Entry in Sequense                                      */ 
 737 /*-----------------------------------------------------------------------*/ 
 740         DIR *dj
,                        /* Pointer to the open directory object */ 
 741         FILINFO 
*fno            
/* Pointer to file information to return */ 
 745         BYTE sp
[12], dir
[32]; 
 749         if (!fs
) {                              /* Check file system */ 
 750                 res 
= FR_NOT_ENABLED
; 
 755                         res 
= dir_rewind(dj
); 
 758                         if (res 
== FR_NO_FILE
) { 
 762                         if (res 
== FR_OK
) {                             /* A valid entry is found */ 
 763                                 get_fileinfo(dj
, fno
);          /* Get the object information */ 
 764                                 res 
= dir_next(dj
);                     /* Increment index for next */ 
 765                                 if (res 
== FR_NO_FILE
) {