]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/fs/fat/v2_0/src/fatfs.c
Initial revision
[karo-tx-redboot.git] / packages / fs / fat / v2_0 / src / fatfs.c
1 //==========================================================================
2 //
3 //      fatfs.c
4 //
5 //      FAT file system
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           Savin Zlobec <savin@elatec.si> (based on ramfs.c)
44 // Original data:       nickg
45 // Date:                2003-06-29
46 // Purpose:             FAT file system
47 // Description:         This is a FAT filesystem for eCos. 
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <pkgconf/system.h>
54 #include <pkgconf/hal.h>
55 #include <pkgconf/io_fileio.h>
56 #include <pkgconf/fs_fat.h>
57
58 #include <cyg/infra/cyg_type.h>   
59 #include <cyg/infra/cyg_trac.h>        // tracing macros
60 #include <cyg/infra/cyg_ass.h>         // assertion macros
61
62 #include <unistd.h>
63 #include <sys/types.h>
64 #include <fcntl.h>
65 #include <sys/stat.h>
66 #include <errno.h>
67 #include <dirent.h>
68
69 #include <stdlib.h>
70 #include <string.h>
71
72 #include <cyg/infra/diag.h>
73 #include <cyg/fileio/fileio.h>
74 #include <cyg/io/io.h>
75 #include <blib/blib.h>
76 #include <cyg/fs/fatfs.h>
77
78 #include "fatfs.h"
79
80 //==========================================================================
81 // Tracing support defines 
82
83 #ifdef FATFS_TRACE_FS_OP
84 # define TFS 1
85 #else
86 # define TFS 0
87 #endif
88
89 #ifdef FATFS_TRACE_FILE_OP
90 # define TFO 1
91 #else
92 # define TFO 0
93 #endif
94
95 //==========================================================================
96 // Forward definitions
97
98 // Filesystem operations
99 static int fatfs_mount  (cyg_fstab_entry *fste, cyg_mtab_entry *mte);
100 static int fatfs_umount (cyg_mtab_entry *mte);
101 static int fatfs_open   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
102                          int mode, cyg_file *fte);
103 static int fatfs_unlink (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
104 static int fatfs_mkdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
105 static int fatfs_rmdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
106 static int fatfs_rename (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
107                          cyg_dir dir2, const char *name2 );
108 static int fatfs_link   (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
109                          cyg_dir dir2, const char *name2, int type );
110 static int fatfs_opendir(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
111                          cyg_file *fte );
112 static int fatfs_chdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
113                          cyg_dir *dir_out );
114 static int fatfs_stat   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
115                          struct stat *buf);
116 static int fatfs_getinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
117                          int key, void *buf, int len );
118 static int fatfs_setinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
119                          int key, void *buf, int len );
120
121 // File operations
122 static int fatfs_fo_read   (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
123 static int fatfs_fo_write  (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
124 static int fatfs_fo_lseek  (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
125 static int fatfs_fo_ioctl  (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
126                             CYG_ADDRWORD data);
127 static int fatfs_fo_fsync  (struct CYG_FILE_TAG *fp, int mode );        
128 static int fatfs_fo_close  (struct CYG_FILE_TAG *fp);
129 static int fatfs_fo_fstat  (struct CYG_FILE_TAG *fp, struct stat *buf );
130 static int fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, 
131                             void *buf, int len );
132 static int fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, 
133                             void *buf, int len );
134
135 // Directory operations
136 static int fatfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
137 static int fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence);
138
139 //==========================================================================
140 // Filesystem table entries
141
142 // -------------------------------------------------------------------------
143 // Fstab entry.
144
145 FSTAB_ENTRY(fatfs_fste, "fatfs", 0,
146             CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
147             fatfs_mount,
148             fatfs_umount,
149             fatfs_open,
150             fatfs_unlink,
151             fatfs_mkdir,
152             fatfs_rmdir,
153             fatfs_rename,
154             fatfs_link,
155             fatfs_opendir,
156             fatfs_chdir,
157             fatfs_stat,
158             fatfs_getinfo,
159             fatfs_setinfo);
160
161 // -------------------------------------------------------------------------
162 // File operations.
163
164 static cyg_fileops fatfs_fileops =
165 {
166     fatfs_fo_read,
167     fatfs_fo_write,
168     fatfs_fo_lseek,
169     fatfs_fo_ioctl,
170     cyg_fileio_seltrue,
171     fatfs_fo_fsync,
172     fatfs_fo_close,
173     fatfs_fo_fstat,
174     fatfs_fo_getinfo,
175     fatfs_fo_setinfo
176 };
177
178 // -------------------------------------------------------------------------
179 // Directory file operations.
180
181 static cyg_fileops fatfs_dirops =
182 {
183     fatfs_fo_dirread,
184     (cyg_fileop_write *)cyg_fileio_enosys,
185     fatfs_fo_dirlseek,
186     (cyg_fileop_ioctl *)cyg_fileio_enosys,
187     cyg_fileio_seltrue,
188     (cyg_fileop_fsync *)cyg_fileio_enosys,
189     fatfs_fo_close,
190     (cyg_fileop_fstat *)cyg_fileio_enosys,
191     (cyg_fileop_getinfo *)cyg_fileio_enosys,
192     (cyg_fileop_setinfo *)cyg_fileio_enosys
193 };
194
195 // -------------------------------------------------------------------------
196 // Directory search data
197 // Parameters for a directory search. The fields of this structure are
198 // updated as we follow a pathname through the directory tree.
199
200 typedef struct fatfs_dirsearch_s
201 {
202     fatfs_disk_t        *disk;     // Disk info 
203     fatfs_node_t        *dir;      // Directory to search
204     const char          *path;     // Path to follow
205     fatfs_node_t        *node;     // Node found
206     const char          *name;     // Last name fragment used
207     int                  namelen;  // Name fragment length
208     cyg_bool             last;     // Last name in path?
209 } fatfs_dirsearch_t;
210
211 // -------------------------------------------------------------------------
212 // FATFS file descriptor data
213
214 typedef struct fatfs_fd_s
215 {
216     fatfs_node_t      *node;
217     fatfs_data_pos_t   pos;
218 } fatfs_fd_t;
219
220 static fatfs_fd_t  fatfs_fds_base[CYGNUM_FILEIO_NFD];
221 static fatfs_fd_t *fatfs_fds_pool[CYGNUM_FILEIO_NFD];
222 static cyg_uint32  fatfs_fds_free_cnt;
223
224 //==========================================================================
225
226 #if TFS
227 static void 
228 print_disk_info(fatfs_disk_t *disk)
229 {
230     diag_printf("FAT: sector size:        %u\n", disk->sector_size);
231     diag_printf("FAT: cluster size:       %u\n", disk->cluster_size);
232     diag_printf("FAT: FAT table position: %u\n", disk->fat_tbl_pos);
233     diag_printf("FAT: FAT table num ent:  %u\n", disk->fat_tbl_nents);
234     diag_printf("FAT: FAT table size:     %u\n", disk->fat_tbl_size);
235     diag_printf("FAT: FAT tables num:     %u\n", disk->fat_tbls_num);
236     diag_printf("FAT: FAT root dir pos:   %u\n", disk->fat_root_dir_pos);
237     diag_printf("FAT: FAT root dir nents: %u\n", disk->fat_root_dir_nents);
238     diag_printf("FAT: FAT root dir size:  %u\n", disk->fat_root_dir_size);
239     diag_printf("FAT: FAT data position:  %u\n", disk->fat_data_pos);
240 }
241 #endif
242
243 static void
244 init_fatfs_fds(void)
245 {
246     static bool initialized = false;
247
248     int i;
249
250     if (initialized)
251         return;
252     
253     initialized = true;
254     
255     for (i = 0; i < CYGNUM_FILEIO_NFD; i++)
256     {
257         fatfs_fds_pool[i] = &fatfs_fds_base[i];    
258     }
259     fatfs_fds_free_cnt = i;
260 }
261
262 static fatfs_fd_t *
263 alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node)
264 {
265     fatfs_fd_t *fd = NULL;
266
267     if (fatfs_fds_free_cnt > 0)
268     {
269         fd = fatfs_fds_pool[--fatfs_fds_free_cnt];
270
271         fd->node = node;
272         fatfs_initpos(disk, &node->dentry, &fd->pos);
273     }
274     
275     return fd;
276 }
277
278 static void
279 free_fatfs_fd(fatfs_fd_t *fd)
280 {
281     fatfs_fds_pool[fatfs_fds_free_cnt++] = fd;
282 }
283
284 static void
285 init_dirsearch(fatfs_dirsearch_t *ds,
286                fatfs_disk_t      *disk, 
287                fatfs_node_t      *dir,
288                const char        *name)
289 {
290     ds->disk = disk;
291     
292     if (NULL == dir)
293         ds->dir = disk->root;
294     else
295         ds->dir = dir;
296     
297     ds->path    = name;
298     ds->node    = ds->dir;
299     ds->namelen = 0;
300     ds->last    = false;
301 }
302
303 static int
304 find_direntry(fatfs_dirsearch_t *ds)
305 {
306     fatfs_dir_entry_t  dentry;
307     fatfs_data_pos_t   pos;
308     int                err;
309
310     CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);
311
312     // First check the cache
313     
314     ds->node = fatfs_node_find(ds->disk, 
315                                ds->name, 
316                                ds->namelen, 
317                                ds->dir->dentry.cluster);
318
319     if (ds->node != NULL)
320     {
321         // Dir entry found in cache
322         
323         CYG_TRACE0(TFS, "dir entry found in cache");
324
325         fatfs_node_touch(ds->disk, ds->node);
326         return ENOERR;
327     }
328
329     // Dir entry not in cache - search the current dir
330
331     fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);
332
333     while (true)
334     {  
335         // Read next dir entry 
336         
337         err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
338         if (err != ENOERR)
339             return (err == EEOF ? ENOERR : err);
340
341         // Compare filenames
342         
343         if ('\0' == dentry.filename[ds->namelen] &&
344                0 == strncasecmp(dentry.filename, ds->name, ds->namelen))
345         {
346             // Dir entry found - allocate new node and return
347
348             CYG_TRACE0(TFS, "dir entry found");
349
350             ds->node = fatfs_node_alloc(ds->disk, &dentry);
351             if (NULL == ds->node)
352                 return EMFILE;
353
354             return ENOERR;
355         }
356     }
357 }
358
359 static int 
360 find_entry(fatfs_dirsearch_t *ds)
361 {
362     const char  *name     = ds->path;
363     const char  *n        = name;
364     char         namelen  = 0;
365     int          err;
366     
367     if( !S_ISDIR(ds->dir->dentry.mode) )
368     {
369         CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
370         return ENOTDIR;
371     }
372     
373     // Isolate the next element of the path name
374     while (*n != '\0' && *n != '/')
375         n++, namelen++;
376
377     // If we terminated on a NUL, set last flag
378     if (*n == '\0')
379         ds->last = true;
380
381     // Update name in dirsearch object
382     ds->name    = name;
383     ds->namelen = namelen;
384
385     err = find_direntry(ds);
386     if (err != ENOERR)
387         return err;
388
389     CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
390     
391     if (ds->node != NULL)
392        return ENOERR;
393     else
394        return ENOENT; 
395 }
396
397 static int
398 fatfs_find(fatfs_dirsearch_t *ds)
399 {
400     int err;
401
402     CYG_TRACE1(TFS, "find path='%s'", ds->path);
403     
404     // Short circuit empty paths
405     if (*(ds->path) == '\0')
406         return ENOERR;
407     
408     // Iterate down directory tree until we find the object we want
409     for(;;)
410     {
411         err = find_entry(ds);
412         
413         if (err != ENOERR)
414             return err;
415         
416         if (ds->last)
417         {
418             CYG_TRACE0(TFS, "entry found");
419             return ENOERR;
420         }
421
422         // Update dirsearch object to search next directory
423         ds->dir   = ds->node;
424         ds->path += ds->namelen;
425         
426         // Skip dirname separators
427         if (*(ds->path) == '/') ds->path++;
428         
429         CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
430     }
431 }
432
433 //==========================================================================
434 // Filesystem operations
435
436 // -------------------------------------------------------------------------
437 // fatfs_mount()
438 // Process a mount request. This mainly creates a root for the
439 // filesystem.
440
441 static int 
442 fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
443 {
444     cyg_io_handle_t     dev_h;
445     fatfs_disk_t       *disk;
446     fatfs_dir_entry_t   root_dentry;
447     Cyg_ErrNo           err;
448
449     CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
450
451     init_fatfs_fds();
452     
453     CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
454     
455     err = cyg_io_lookup(mte->devname, &dev_h);
456     if (err != ENOERR)
457         return err;
458
459     disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
460     if (NULL == disk)
461         return ENOMEM;
462         
463     CYG_TRACE0(TFS, "initializing block cache"); 
464
465     disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
466     if (NULL == disk->bcache_mem)
467     {
468         free(disk);
469         return ENOMEM;
470     }
471     // FIXME: get block size from disk device
472     err = cyg_blib_io_create(dev_h, disk->bcache_mem, 
473             CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
474     if (err != ENOERR)
475     {
476         free(disk->bcache_mem);
477         free(disk);
478         return err;
479     }
480     
481     disk->dev_h = dev_h;
482
483     CYG_TRACE0(TFS, "initializing disk");
484     
485     err = fatfs_init(disk);
486     if (err != ENOERR)
487     {
488         cyg_blib_delete(&disk->blib);
489         free(disk->bcache_mem);
490         free(disk);
491         return err;
492     }
493    
494 #if TFS    
495     print_disk_info(disk);
496 #endif
497
498     CYG_TRACE0(TFS, "initializing node cache");
499
500     fatfs_node_cache_init(disk);
501     
502     CYG_TRACE0(TFS, "initializing root node");
503     
504     fatfs_get_root_dir_entry(disk, &root_dentry);
505     
506     disk->root = fatfs_node_alloc(disk, &root_dentry);
507
508     fatfs_node_ref(disk, disk->root);
509     
510     mte->root = (cyg_dir)disk->root;
511     mte->data = (CYG_ADDRWORD)disk;
512
513     CYG_TRACE0(TFS, "disk mounted");
514
515     return ENOERR;
516 }
517
518 // -------------------------------------------------------------------------
519 // fatfs_umount()
520 // Unmount the filesystem. This will currently only succeed if the
521 // filesystem is empty.
522
523 static int
524 fatfs_umount(cyg_mtab_entry *mte)
525 {
526     fatfs_disk_t  *disk  = (fatfs_disk_t *) mte->data;
527     fatfs_node_t  *root  = (fatfs_node_t *) mte->root;
528
529     CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes", 
530                     mte, fatfs_get_live_node_count(disk), 
531                     fatfs_get_dead_node_count(disk));
532
533     if (root->refcnt > 1)
534         return EBUSY;
535     
536     if (fatfs_get_live_node_count(disk) != 1)
537         return EBUSY;
538
539     fatfs_node_unref(disk, root);
540     fatfs_node_cache_flush(disk);
541     // FIXME: cache delete can fail if cache can't be synced
542     cyg_blib_delete(&disk->blib); 
543     free(disk->bcache_mem);
544     free(disk);
545     
546     mte->root = CYG_DIR_NULL;
547     mte->data = (CYG_ADDRWORD) NULL;
548     
549     CYG_TRACE0(TFS, "disk umounted");
550     
551     return ENOERR;
552 }
553
554 // -------------------------------------------------------------------------
555 // fatfs_open()
556 // Open a file for reading or writing.
557
558 static int 
559 fatfs_open(cyg_mtab_entry *mte,
560            cyg_dir         dir, 
561            const char     *name,
562            int             mode,  
563            cyg_file       *file)
564 {
565     fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
566     fatfs_node_t       *node = NULL;
567     fatfs_fd_t         *fd;
568     fatfs_dirsearch_t   ds;
569     int                 err;
570
571     CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p", 
572                     mte, dir, name, mode, file);
573
574     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
575
576     err = fatfs_find(&ds);
577
578     if (err == ENOENT)
579     {
580         if (ds.last && (mode & O_CREAT))
581         {
582             fatfs_dir_entry_t new_file_dentry;
583             
584             // No node there, if the O_CREAT bit is set then we must
585             // create a new one. The dir and name fields of the dirsearch
586             // object will have been updated so we know where to put it.
587
588             CYG_TRACE1(TFS, "creating new file '%s'", name); 
589
590             err = fatfs_create_file(disk, 
591                                     &ds.dir->dentry, 
592                                     ds.name, 
593                                     ds.namelen, 
594                                     &new_file_dentry);
595             if (err != ENOERR)
596                 return err;
597
598             node = fatfs_node_alloc(disk, &new_file_dentry);
599             if (NULL == node)
600                 return EMFILE;
601            
602             // Update directory times
603             ds.dir->dentry.atime =
604             ds.dir->dentry.mtime = cyg_timestamp();
605             
606             err = ENOERR;
607         }
608     }
609     else if (err == ENOERR)
610     {
611         // The node exists. If the O_CREAT and O_EXCL bits are set, we
612         // must fail the open
613
614         if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
615             err = EEXIST;
616         else
617             node = ds.node;
618     }
619
620     if (err == ENOERR && (mode & O_TRUNC))
621     {
622         // If the O_TRUNC bit is set we must clean out the file data
623         CYG_TRACE0(TFS, "truncating file"); 
624         fatfs_trunc_file(disk, &node->dentry);
625     }
626
627     if (err != ENOERR)
628         return err;
629     
630     if (S_ISDIR(node->dentry.mode))
631         return EISDIR;
632
633 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
634     // if the file is read only and is opened for writing
635     // fail with permission error
636     if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY))
637         return EACCES;
638 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
639
640     // Allocate file object private data and
641     // make a reference to this file node
642
643     fd = alloc_fatfs_fd(disk, node);
644     if (NULL == fd)
645         return EMFILE;
646
647     fatfs_node_ref(disk, node);
648
649     // Initialize the file object
650
651     if (mode & O_APPEND)
652         fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);  
653     
654     file->f_flag   |= mode & CYG_FILE_MODE_MASK;
655     file->f_type    = CYG_FILE_TYPE_FILE;
656     file->f_ops     = &fatfs_fileops;
657     file->f_offset  = (mode & O_APPEND) ? node->dentry.size : 0;
658     file->f_data    = (CYG_ADDRWORD) fd;
659     file->f_xops    = 0;
660
661     return ENOERR;
662 }
663
664 // -------------------------------------------------------------------------
665 // fatfs_unlink()
666 // Remove a file link from its directory.
667
668 static int 
669 fatfs_unlink(cyg_mtab_entry *mte, 
670              cyg_dir         dir, 
671              const char     *name)
672 {
673     fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
674     fatfs_dirsearch_t   ds;
675     int                 err;
676
677     CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);
678
679     init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
680
681     err = fatfs_find(&ds);
682
683     if (err != ENOERR)
684         return err;
685
686     if (ds.node->refcnt > 0)
687         return EBUSY;
688     
689 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
690     // if the file is read only fail with permission error
691     if (S_FATFS_ISRDONLY(ds.node->dentry.attrib))
692         return EPERM;
693 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
694
695     err = fatfs_delete_file(disk, &ds.node->dentry);
696     if (err == ENOERR)
697         fatfs_node_free(disk, ds.node);
698     
699     return err;
700 }
701
702 // -------------------------------------------------------------------------
703 // fatfs_mkdir()
704 // Create a new directory.
705
706 static int
707 fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
708 {
709     fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
710     fatfs_dirsearch_t   ds;
711     int                 err;
712     
713     CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);
714
715     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
716
717     err = fatfs_find(&ds);
718
719     if (err == ENOENT)
720     {
721         if (ds.last)
722         {
723             fatfs_dir_entry_t new_dir_dentry;
724             
725             // The entry does not exist, and it is the last element in
726             // the pathname, so we can create it here
727
728             err = fatfs_create_dir(disk, 
729                                    &ds.dir->dentry, 
730                                    ds.name, 
731                                    ds.namelen, 
732                                    &new_dir_dentry);
733             if (err != ENOERR)
734                 return err;
735             
736             fatfs_node_alloc(disk, &new_dir_dentry);
737
738             return ENOERR;
739         }
740     } 
741     else if (err == ENOERR)
742     {
743         return EEXIST;
744     }
745     
746     return err;
747 }
748
749 // -------------------------------------------------------------------------
750 // fatfs_rmdir()
751 // Remove a directory.
752
753 static int 
754 fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
755 {
756     fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
757     fatfs_dirsearch_t  ds;
758     int                err;
759
760     CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);
761
762     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
763
764     err = fatfs_find(&ds);
765
766     if (err != ENOERR)
767         return err;
768   
769     if (!S_ISDIR(ds.node->dentry.mode))
770         return EPERM;
771  
772     if (ds.node->refcnt > 0)
773         return EBUSY;
774     
775     err = fatfs_delete_file(disk, &ds.node->dentry);
776     if (err == ENOERR)
777         fatfs_node_free(disk, ds.node);
778     
779     return err;
780 }
781
782 // -------------------------------------------------------------------------
783 // fatfs_rename()
784 // Rename a file/dir.
785
786 static int 
787 fatfs_rename(cyg_mtab_entry *mte, 
788              cyg_dir         dir1, 
789              const char     *name1,
790              cyg_dir         dir2, 
791              const char     *name2)
792 {
793     fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
794     fatfs_dirsearch_t   ds1, ds2;
795     int                 err;
796  
797     CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", 
798                     mte, dir1, name1, dir2, name2);
799
800     init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);
801
802     err = fatfs_find(&ds1);
803     if (err != ENOERR)
804         return err;
805
806 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
807     // if the file is read only fail with permission error
808     if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib))
809         return EPERM;
810 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
811
812     // Protect the found nodes from being reused 
813     // by the search for the ds2 dir/node pair 
814     fatfs_node_ref(disk, ds1.dir);
815     fatfs_node_ref(disk, ds1.node);
816     
817     init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
818    
819     err = fatfs_find(&ds2);
820
821     // Check if the target name already exists
822     if (err == ENOERR && ds2.last)
823     {
824         err = EEXIST;  
825         goto out;  
826     }
827     
828     // Check if the target dir doesn't exist
829     if (err == ENOENT && !ds2.last)
830         goto out;
831     
832     // Check if the target and the source are the same
833     if (ds1.node == ds2.node)
834     {
835         err = ENOERR;
836         goto out;
837     }
838     
839     err = fatfs_rename_file(disk, 
840                             &ds1.dir->dentry, 
841                             &ds1.node->dentry, 
842                             &ds2.dir->dentry, 
843                             ds2.name, 
844                             ds2.namelen);  
845
846     fatfs_node_rehash(disk, ds1.node);
847
848 out:
849     // Unreference previousely protected nodes
850     fatfs_node_unref(disk, ds1.dir);
851     fatfs_node_unref(disk, ds1.node);
852    
853     if (err == ENOERR)
854     {
855         ds1.dir->dentry.atime =
856         ds1.dir->dentry.mtime = 
857         ds2.dir->dentry.atime = 
858         ds2.dir->dentry.mtime = cyg_timestamp();    
859     } 
860     return err;
861 }
862
863 // -------------------------------------------------------------------------
864 // fatfs_link()
865 // Make a new directory entry for a file.
866
867 static int 
868 fatfs_link(cyg_mtab_entry *mte, 
869            cyg_dir         dir1, 
870            const char     *name1,
871            cyg_dir         dir2, 
872            const char     *name2, 
873            int             type)
874 {
875     CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
876                     mte, dir1, name1, dir2, name2, type);
877
878     // Linking not supported
879     return EINVAL;
880 }
881
882 // -------------------------------------------------------------------------
883 // fatfs_opendir()
884 // Open a directory for reading.
885
886 static int
887 fatfs_opendir(cyg_mtab_entry *mte,
888               cyg_dir         dir,
889               const char     *name,
890               cyg_file       *file)
891 {
892     fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
893     fatfs_fd_t         *fd;
894     fatfs_dirsearch_t   ds;
895     int                 err;
896
897     CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p", 
898                     mte, dir, name, file);
899
900     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
901
902     err = fatfs_find(&ds);
903     if (err != ENOERR)
904         return err;
905
906     if (!S_ISDIR(ds.node->dentry.mode)) 
907         return ENOTDIR;
908
909     // Allocate file object private data and
910     // make a reference to this file node
911
912     fd = alloc_fatfs_fd(disk, ds.node);
913     if (NULL == fd)
914         return EMFILE;
915     
916     fatfs_node_ref(disk, ds.node);
917     
918     // Initialize the file object
919
920     file->f_type    = CYG_FILE_TYPE_FILE;
921     file->f_ops     = &fatfs_dirops;
922     file->f_data    = (CYG_ADDRWORD) fd;
923     file->f_xops    = 0;
924     file->f_offset  = 0;
925
926     return ENOERR;
927 }
928
929 // -------------------------------------------------------------------------
930 // fatfs_chdir()
931 // Change directory support.
932
933 static int
934 fatfs_chdir(cyg_mtab_entry *mte,
935             cyg_dir         dir,
936             const char     *name,
937             cyg_dir        *dir_out)
938 {
939     fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
940
941     CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d", 
942                     mte, dir, dir_out, name);
943
944     if (dir_out != NULL)
945     {
946         // This is a request to get a new directory pointer in *dir_out
947         
948         fatfs_dirsearch_t ds;
949         int               err;
950
951         init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
952
953         err = fatfs_find(&ds);
954         if (err != ENOERR)
955             return err;
956
957         if (!S_ISDIR(ds.node->dentry.mode))
958             return ENOTDIR;
959
960         if (ds.node != disk->root)
961             fatfs_node_ref(disk, ds.node);
962         
963         *dir_out = (cyg_dir) ds.node;
964     }
965     else
966     {
967         // If no output dir is required, this means that the mte and
968         // dir arguments are the current cdir setting and we should
969         // forget this fact.
970
971         fatfs_node_t *node = (fatfs_node_t *) dir;
972
973         if (node != disk->root)
974             fatfs_node_unref(disk, node);
975     }
976
977     return ENOERR;
978 }
979
980 // -------------------------------------------------------------------------
981 // fatfs_stat()
982 // Get struct stat info for named object.
983
984 static int
985 fatfs_stat(cyg_mtab_entry *mte,
986            cyg_dir         dir,
987            const char     *name,
988            struct stat    *buf)
989 {
990     fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
991     fatfs_dirsearch_t  ds;
992     int                err;
993
994     CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p", 
995                     mte, dir, name, buf);
996
997     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
998
999     err = fatfs_find(&ds);
1000     if (err != ENOERR)
1001         return err;
1002
1003     // Fill in the status
1004     
1005     buf->st_mode   = ds.node->dentry.mode;
1006 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1007     if (!S_FATFS_ISRDONLY(ds.node->dentry.attrib))
1008         buf->st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
1009 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1010     buf->st_ino    = (ino_t) ds.node->dentry.cluster;
1011     buf->st_dev    = 0;
1012     buf->st_nlink  = 1;
1013     buf->st_uid    = 0;
1014     buf->st_gid    = 0;
1015     buf->st_size   = ds.node->dentry.size;
1016     buf->st_atime  = ds.node->dentry.atime;
1017     buf->st_mtime  = ds.node->dentry.mtime;
1018     buf->st_ctime  = ds.node->dentry.ctime;
1019
1020     return ENOERR;
1021 }
1022
1023 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1024 // -------------------------------------------------------------------------
1025 // fatfs_set_attrib()
1026 // Set FAT file system attributes for specified file
1027
1028 static int
1029 fatfs_set_attrib(cyg_mtab_entry        *mte,
1030                  cyg_dir                dir,
1031                  const char            *name,
1032                  const cyg_fs_attrib_t  new_attrib)
1033 {
1034     fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
1035     fatfs_dirsearch_t  ds;
1036     int                err;
1037
1038     CYG_TRACE4(TFS, "set_attrib mte=%p dir=%p name='%s' buf=%x", 
1039                     mte, dir, name, new_attrib);
1040
1041     // Verify new_mode is valid
1042     if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
1043         return EINVAL;
1044     
1045     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1046
1047     err = fatfs_find(&ds);
1048     if (err != ENOERR)
1049         return err;
1050
1051     // Change the "changeable" mode bits for the file.
1052     ds.node->dentry.attrib = 
1053       (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;
1054
1055     return fatfs_write_dir_entry(disk,&ds.node->dentry);
1056 }
1057
1058 // -------------------------------------------------------------------------
1059 // fatfs_get_attrib()
1060 // Set FAT file system attributes for specified file
1061
1062 static int
1063 fatfs_get_attrib(cyg_mtab_entry  *mte,
1064                  cyg_dir          dir,
1065                  const char      *name,
1066                  cyg_fs_attrib_t * const file_attrib)
1067 {
1068     fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
1069     fatfs_dirsearch_t  ds;
1070     int                err;
1071
1072     CYG_TRACE4(TFS, "get_attrib mte=%p dir=%p name='%s' buf=%x", 
1073                     mte, dir, name, file_attrib);
1074
1075     init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1076
1077     err = fatfs_find(&ds);
1078     if (err != ENOERR)
1079         return err;
1080
1081     // Get the attribute field
1082     CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
1083     *file_attrib = ds.node->dentry.attrib;
1084
1085     return ENOERR;
1086 }
1087 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1088
1089 // -------------------------------------------------------------------------
1090 // fatfs_getinfo()
1091 // Getinfo. Support for attrib
1092
1093 static int 
1094 fatfs_getinfo(cyg_mtab_entry *mte, 
1095               cyg_dir         dir, 
1096               const char     *name,
1097               int             key, 
1098               void           *buf, 
1099               int             len)
1100 {
1101     int err = EINVAL;
1102
1103     CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1104                     mte, dir, name, key, buf, len);
1105     switch( key )
1106     {
1107 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1108         case FS_INFO_ATTRIB:
1109             err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
1110             break;
1111 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1112         default:
1113             err = EINVAL;
1114             break;
1115     }
1116     return err;
1117 }
1118
1119 // -------------------------------------------------------------------------
1120 // fatfs_setinfo()
1121 // Setinfo. Support for fssync and attrib
1122
1123 static int 
1124 fatfs_setinfo(cyg_mtab_entry *mte, 
1125               cyg_dir         dir, 
1126               const char     *name,
1127               int             key, 
1128               void           *buf, 
1129               int             len)
1130 {
1131     int err = EINVAL;
1132
1133     CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1134                     mte, dir, name, key, buf, len);
1135
1136     switch( key )
1137     {
1138         case FS_INFO_SYNC:
1139             err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
1140             break;
1141 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1142         case FS_INFO_ATTRIB:
1143             err = fatfs_set_attrib(mte, dir, name, *(cyg_fs_attrib_t *)buf);
1144             break;
1145 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1146         default:
1147             err = EINVAL;
1148             break;
1149     }
1150     return err;
1151 }
1152
1153 //==========================================================================
1154 // File operations
1155
1156 // -------------------------------------------------------------------------
1157 // fatfs_fo_read()
1158 // Read data from the file.
1159
1160 static int 
1161 fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1162 {
1163     fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
1164     fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
1165     fatfs_node_t  *node   = fd->node;
1166     cyg_uint32     pos    = fp->f_offset;
1167     ssize_t        resid  = uio->uio_resid;
1168     int            i;
1169
1170     CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);
1171
1172     // Loop over the io vectors until there are none left
1173
1174     for (i = 0; i < uio->uio_iovcnt; i++)
1175     {
1176         cyg_iovec  *iov  = &uio->uio_iov[i];
1177         char       *buf  = (char *) iov->iov_base;
1178         off_t       len  = iov->iov_len;
1179
1180         // Loop over each vector filling it with data from the file
1181         
1182         while (len > 0 && pos < node->dentry.size)
1183         {
1184             cyg_uint32 l = len;
1185             int        err;
1186
1187             // Adjust size to end of file if necessary
1188             if (l > node->dentry.size-pos)
1189                 l = node->dentry.size-pos;
1190
1191             err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
1192             if (err != ENOERR)
1193                 return err;
1194
1195             // Update working vars
1196
1197             len   -= l;
1198             buf   += l;
1199             pos   += l;
1200             resid -= l;
1201         }
1202     }
1203
1204     // We successfully read some data, update the access time, 
1205     // file offset and transfer residue
1206
1207     node->dentry.atime = cyg_timestamp(); 
1208     uio->uio_resid     = resid;
1209     fp->f_offset       = (off_t) pos;
1210
1211     return ENOERR;
1212 }
1213
1214 // -------------------------------------------------------------------------
1215 // fatfs_fo_write()
1216 // Write data to file.
1217
1218 static int 
1219 fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1220 {
1221     fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
1222     fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
1223     fatfs_node_t  *node   = fd->node;
1224     cyg_uint32     pos    = fp->f_offset;
1225     ssize_t        resid  = uio->uio_resid;
1226     int            err    = ENOERR;
1227     int            i;
1228
1229     CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
1230     
1231     // If the APPEND mode bit was supplied, force all writes to
1232     // the end of the file
1233     if (fp->f_flag & CYG_FAPPEND)
1234     {
1235         fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
1236         pos = fp->f_offset = node->dentry.size;
1237     }
1238     
1239     // Check that pos is within current file size, or at the very end
1240     if (pos < 0 || pos > node->dentry.size)
1241         return EINVAL;
1242    
1243     // Now loop over the iovecs until they are all done, or we get an error
1244     
1245     for (i = 0; i < uio->uio_iovcnt; i++)
1246     {
1247         cyg_iovec  *iov  = &uio->uio_iov[i];
1248         char       *buf  = (char *) iov->iov_base;
1249         off_t       len  = iov->iov_len;
1250  
1251         // Loop over the vector writing it to the file 
1252         // until it has all been done
1253
1254         while (len > 0)
1255         {
1256             cyg_uint32 l = len;
1257
1258             err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);
1259
1260             // Update working vars
1261
1262             len   -= l;
1263             buf   += l;
1264             pos   += l;
1265             resid -= l;
1266
1267             // Stop writing if there is no more space in the file
1268             if (err == ENOSPC)
1269                 break;
1270             
1271             if (err != ENOERR)
1272                 return err;
1273         }
1274     }        
1275
1276     // We wrote some data successfully, update the modified and access
1277     // times of the node, increase its size appropriately, and update
1278     // the file offset and transfer residue.
1279
1280     node->dentry.mtime = 
1281     node->dentry.atime = cyg_timestamp();
1282
1283     if (pos > node->dentry.size)
1284         node->dentry.size = pos;
1285
1286     uio->uio_resid = resid;
1287     fp->f_offset   = (off_t) pos;
1288
1289     return err;
1290 }
1291
1292 // -------------------------------------------------------------------------
1293 // fatfs_fo_lseek()
1294 // Seek to a new file position.
1295
1296 static int 
1297 fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
1298 {
1299     fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1300     fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1301     off_t          pos   = *apos;
1302     int            err;
1303     
1304     CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
1305
1306     switch (whence)
1307     {
1308         case SEEK_SET:
1309             // Pos is already where we want to be
1310             break;
1311          case SEEK_CUR:
1312             // Add pos to current offset
1313             pos += fp->f_offset;
1314             break;
1315          case SEEK_END:
1316             // Add pos to file size
1317             pos += fd->node->dentry.size;
1318             break;
1319          default:
1320             return EINVAL;
1321     }
1322
1323     // Check that pos is still within current file size, 
1324     // or at the very end
1325     if (pos < 0 || pos > fd->node->dentry.size)
1326         return EINVAL;
1327   
1328     // All OK, set fp offset and return new position
1329     
1330     err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);
1331
1332     if (ENOERR == err)
1333         *apos = fp->f_offset = pos;
1334     
1335     CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);
1336
1337     return err;
1338 }
1339
1340 // -------------------------------------------------------------------------
1341 // fatfs_fo_ioctl()
1342 // Handle ioctls. Currently none are defined.
1343
1344 static int 
1345 fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
1346 {
1347     CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
1348     return EINVAL;
1349 }
1350
1351 // -------------------------------------------------------------------------
1352 // fatfs_fo_fsync().
1353 // Force the file out to data storage.
1354
1355 static int 
1356 fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
1357 {
1358     fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1359     fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1360     fatfs_node_t  *node  = fd->node;
1361     int            err;
1362     
1363     CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);
1364
1365     err = fatfs_write_dir_entry(disk, &node->dentry);
1366
1367     if (ENOERR == err)
1368         err = cyg_blib_sync(&disk->blib);
1369     
1370     return err;
1371 }
1372
1373 // -------------------------------------------------------------------------
1374 // fatfs_fo_close()
1375 // Close a file.
1376
1377 static int
1378 fatfs_fo_close(struct CYG_FILE_TAG *fp)
1379 {    
1380     fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1381     fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1382     fatfs_node_t  *node  = fd->node;
1383     int            err   = ENOERR;
1384
1385     CYG_TRACE1(TFO, "close fp=%p", fp);
1386
1387     // Write file attributes to disk, unreference 
1388     // the file node and free its private data
1389
1390     if (node != disk->root)
1391         err = fatfs_write_dir_entry(disk, &node->dentry);
1392
1393     fatfs_node_unref(disk, node);    
1394
1395     free_fatfs_fd(fd);
1396     
1397     return err;
1398 }
1399
1400 // -------------------------------------------------------------------------
1401 // fatfs_fo_fstat()
1402 // Get file status.
1403
1404 static int
1405 fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
1406 {
1407     fatfs_fd_t    *fd    = (fatfs_fd_t *) fp->f_data;
1408     fatfs_node_t  *node  = fd->node;
1409     
1410     CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);
1411
1412     // Fill in the status
1413
1414     buf->st_mode   = node->dentry.mode;
1415     buf->st_ino    = (ino_t) node->dentry.cluster;
1416     buf->st_dev    = 0;
1417     buf->st_nlink  = 1;
1418     buf->st_uid    = 0;
1419     buf->st_gid    = 0;
1420     buf->st_size   = node->dentry.size;
1421     buf->st_atime  = node->dentry.atime;
1422     buf->st_mtime  = node->dentry.mtime;
1423     buf->st_ctime  = node->dentry.ctime;
1424
1425     return ENOERR;
1426 }
1427
1428 // -------------------------------------------------------------------------
1429 // fatfs_fo_getinfo()
1430 // Get info.
1431
1432 static int
1433 fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1434 {
1435     CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1436     return EINVAL;
1437 }
1438
1439 // -------------------------------------------------------------------------
1440 // fatfs_fo_setinfo()
1441 // Set info.
1442
1443 static int
1444 fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1445 {
1446     CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1447     return EINVAL;
1448 }
1449
1450 //==========================================================================
1451 // Directory operations
1452
1453 // -------------------------------------------------------------------------
1454 // fatfs_fo_dirread()
1455 // Read a single directory entry from a file.
1456
1457 static int 
1458 fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1459 {
1460     fatfs_disk_t      *disk    = (fatfs_disk_t *)  fp->f_mte->data;
1461     fatfs_fd_t        *fd      = (fatfs_fd_t *)    fp->f_data;
1462     struct dirent     *ent     = (struct dirent *) uio->uio_iov[0].iov_base;
1463     char              *nbuf    = ent->d_name;
1464     off_t              len     = uio->uio_iov[0].iov_len;
1465     fatfs_dir_entry_t  dentry;
1466     int                err;
1467     
1468     CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);
1469
1470     if (len < sizeof(struct dirent))
1471         return EINVAL;
1472
1473     err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry);
1474
1475     if (err != ENOERR)
1476         return (err == EEOF ? ENOERR : err);
1477
1478     strcpy(nbuf, dentry.filename);
1479
1480     fd->node->dentry.atime  = cyg_timestamp();
1481     uio->uio_resid         -= sizeof(struct dirent);
1482     fp->f_offset++;
1483     
1484     return ENOERR;
1485 }
1486
1487 // -------------------------------------------------------------------------
1488 // fatfs_fo_dirlseek()
1489 // Seek directory to start.
1490
1491 static int 
1492 fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
1493 {
1494     fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1495     fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1496     int            err;
1497     
1498     CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);
1499
1500     // Only allow SEEK_SET to zero
1501     
1502     if (whence != SEEK_SET || *pos != 0)
1503         return EINVAL;
1504    
1505     err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);
1506
1507     if (ENOERR == err)
1508         *pos = fp->f_offset = 0;
1509     
1510     return err;
1511 }
1512
1513 // -------------------------------------------------------------------------
1514 // EOF fatfs.c