1 //==========================================================================
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.
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.
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
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.
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.
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.
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####
43 // Author(s): Savin Zlobec <savin@elatec.si> (based on ramfs.c)
44 // Original data: nickg
46 // Purpose: FAT file system
47 // Description: This is a FAT filesystem for eCos.
49 //####DESCRIPTIONEND####
51 //==========================================================================
53 #include <pkgconf/system.h>
54 #include <pkgconf/hal.h>
55 #include <pkgconf/io_fileio.h>
56 #include <pkgconf/fs_fat.h>
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
63 #include <sys/types.h>
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>
80 //==========================================================================
81 // Tracing support defines
83 #ifdef FATFS_TRACE_FS_OP
89 #ifdef FATFS_TRACE_FILE_OP
95 //==========================================================================
96 // Forward definitions
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,
112 static int fatfs_chdir (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
114 static int fatfs_stat (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
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 );
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,
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 );
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);
139 //==========================================================================
140 // Filesystem table entries
142 // -------------------------------------------------------------------------
145 FSTAB_ENTRY(fatfs_fste, "fatfs", 0,
146 CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
161 // -------------------------------------------------------------------------
164 static cyg_fileops fatfs_fileops =
178 // -------------------------------------------------------------------------
179 // Directory file operations.
181 static cyg_fileops fatfs_dirops =
184 (cyg_fileop_write *)cyg_fileio_enosys,
186 (cyg_fileop_ioctl *)cyg_fileio_enosys,
188 (cyg_fileop_fsync *)cyg_fileio_enosys,
190 (cyg_fileop_fstat *)cyg_fileio_enosys,
191 (cyg_fileop_getinfo *)cyg_fileio_enosys,
192 (cyg_fileop_setinfo *)cyg_fileio_enosys
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.
200 typedef struct fatfs_dirsearch_s
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?
211 // -------------------------------------------------------------------------
212 // FATFS file descriptor data
214 typedef struct fatfs_fd_s
217 fatfs_data_pos_t pos;
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;
224 //==========================================================================
228 print_disk_info(fatfs_disk_t *disk)
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);
246 static bool initialized = false;
255 for (i = 0; i < CYGNUM_FILEIO_NFD; i++)
257 fatfs_fds_pool[i] = &fatfs_fds_base[i];
259 fatfs_fds_free_cnt = i;
263 alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node)
265 fatfs_fd_t *fd = NULL;
267 if (fatfs_fds_free_cnt > 0)
269 fd = fatfs_fds_pool[--fatfs_fds_free_cnt];
272 fatfs_initpos(disk, &node->dentry, &fd->pos);
279 free_fatfs_fd(fatfs_fd_t *fd)
281 fatfs_fds_pool[fatfs_fds_free_cnt++] = fd;
285 init_dirsearch(fatfs_dirsearch_t *ds,
293 ds->dir = disk->root;
304 find_direntry(fatfs_dirsearch_t *ds)
306 fatfs_dir_entry_t dentry;
307 fatfs_data_pos_t pos;
310 CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);
314 if (!strncmp(".", ds->name, ds->namelen))
322 ds->node = fatfs_node_find(ds->disk,
325 ds->dir->dentry.cluster);
327 if (ds->node != NULL)
329 // Dir entry found in cache
331 CYG_TRACE0(TFS, "dir entry found in cache");
333 fatfs_node_touch(ds->disk, ds->node);
337 // Dir entry not in cache - search the current dir
339 fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);
343 // Read next dir entry
345 err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
347 return (err == EEOF ? ENOERR : err);
351 if ('\0' == dentry.filename[ds->namelen] &&
352 0 == strncasecmp(dentry.filename, ds->name, ds->namelen))
354 // Dir entry found - allocate new node and return
356 CYG_TRACE0(TFS, "dir entry found");
358 if (0 == strncmp(ds->name, "..", ds->namelen))
360 fatfs_dir_entry_t _dentry;
361 fatfs_data_pos_t _pos;
363 if (0 == dentry.cluster)
365 ds->node = ds->disk->root;
369 fatfs_initpos(ds->disk, &dentry, &_pos);
372 err = fatfs_read_dir_entry(ds->disk, &dentry, &_pos, &_dentry);
375 if (0 == strcmp(".", _dentry.filename))
379 ds->node = fatfs_node_find(ds->disk,
381 strlen(_dentry.filename),
382 _dentry.parent_cluster);
384 if (NULL != ds->node)
385 fatfs_node_touch(ds->disk, ds->node);
387 ds->node = fatfs_node_alloc(ds->disk, &_dentry);
389 if (NULL == ds->node)
395 ds->node = fatfs_node_alloc(ds->disk, &dentry);
397 if (NULL == ds->node)
406 find_entry(fatfs_dirsearch_t *ds)
408 const char *name = ds->path;
409 const char *n = name;
413 if( !S_ISDIR(ds->dir->dentry.mode) )
415 CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
419 // Isolate the next element of the path name
420 while (*n != '\0' && *n != '/')
423 // If we terminated on a NUL, set last flag
427 // Update name in dirsearch object
429 ds->namelen = namelen;
431 err = find_direntry(ds);
435 CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
437 if (ds->node != NULL)
444 fatfs_find(fatfs_dirsearch_t *ds)
448 CYG_TRACE1(TFS, "find path='%s'", ds->path);
450 // Short circuit empty paths
451 if (*(ds->path) == '\0')
454 // Iterate down directory tree until we find the object we want
457 err = find_entry(ds);
464 CYG_TRACE0(TFS, "entry found");
468 // Update dirsearch object to search next directory
470 ds->path += ds->namelen;
472 // Skip dirname separators
473 if (*(ds->path) == '/') ds->path++;
475 CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
479 //==========================================================================
480 // Filesystem operations
482 // -------------------------------------------------------------------------
484 // Process a mount request. This mainly creates a root for the
488 fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
490 cyg_io_handle_t dev_h;
492 fatfs_dir_entry_t root_dentry;
495 CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
499 CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
501 err = cyg_io_lookup(mte->devname, &dev_h);
505 disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
509 CYG_TRACE0(TFS, "initializing block cache");
511 disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
512 if (NULL == disk->bcache_mem)
517 // FIXME: get block size from disk device
518 err = cyg_blib_io_create(dev_h, disk->bcache_mem,
519 CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
522 free(disk->bcache_mem);
529 CYG_TRACE0(TFS, "initializing disk");
531 err = fatfs_init(disk);
534 cyg_blib_delete(&disk->blib);
535 free(disk->bcache_mem);
541 print_disk_info(disk);
544 CYG_TRACE0(TFS, "initializing node cache");
546 fatfs_node_cache_init(disk);
548 CYG_TRACE0(TFS, "initializing root node");
550 fatfs_get_root_dir_entry(disk, &root_dentry);
552 disk->root = fatfs_node_alloc(disk, &root_dentry);
554 fatfs_node_ref(disk, disk->root);
556 mte->root = (cyg_dir)disk->root;
557 mte->data = (CYG_ADDRWORD)disk;
559 CYG_TRACE0(TFS, "disk mounted");
564 // -------------------------------------------------------------------------
566 // Unmount the filesystem. This will currently only succeed if the
567 // filesystem is empty.
570 fatfs_umount(cyg_mtab_entry *mte)
572 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
573 fatfs_node_t *root = (fatfs_node_t *) mte->root;
575 CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes",
576 mte, fatfs_get_live_node_count(disk),
577 fatfs_get_dead_node_count(disk));
579 if (root->refcnt > 1)
582 if (fatfs_get_live_node_count(disk) != 1)
585 fatfs_node_unref(disk, root);
586 fatfs_node_cache_flush(disk);
587 // FIXME: cache delete can fail if cache can't be synced
588 cyg_blib_delete(&disk->blib);
589 free(disk->bcache_mem);
592 mte->root = CYG_DIR_NULL;
593 mte->data = (CYG_ADDRWORD) NULL;
595 CYG_TRACE0(TFS, "disk umounted");
600 // -------------------------------------------------------------------------
602 // Open a file for reading or writing.
605 fatfs_open(cyg_mtab_entry *mte,
611 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
612 fatfs_node_t *node = NULL;
614 fatfs_dirsearch_t ds;
617 CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p",
618 mte, dir, name, mode, file);
620 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
622 err = fatfs_find(&ds);
626 if (ds.last && (mode & O_CREAT))
628 fatfs_dir_entry_t new_file_dentry;
630 // No node there, if the O_CREAT bit is set then we must
631 // create a new one. The dir and name fields of the dirsearch
632 // object will have been updated so we know where to put it.
634 CYG_TRACE1(TFS, "creating new file '%s'", name);
636 err = fatfs_create_file(disk,
644 node = fatfs_node_alloc(disk, &new_file_dentry);
648 // Update directory times
649 ds.dir->dentry.atime =
650 ds.dir->dentry.mtime = cyg_timestamp();
655 else if (err == ENOERR)
657 // The node exists. If the O_CREAT and O_EXCL bits are set, we
658 // must fail the open
660 if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
666 if (err == ENOERR && (mode & O_TRUNC))
668 // If the O_TRUNC bit is set we must clean out the file data
669 CYG_TRACE0(TFS, "truncating file");
670 fatfs_trunc_file(disk, &node->dentry);
676 if (S_ISDIR(node->dentry.mode))
679 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
680 // if the file is read only and is opened for writing
681 // fail with permission error
682 if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY))
684 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
686 // Allocate file object private data and
687 // make a reference to this file node
689 fd = alloc_fatfs_fd(disk, node);
693 fatfs_node_ref(disk, node);
695 // Initialize the file object
698 fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
700 file->f_flag |= mode & CYG_FILE_MODE_MASK;
701 file->f_type = CYG_FILE_TYPE_FILE;
702 file->f_ops = &fatfs_fileops;
703 file->f_offset = (mode & O_APPEND) ? node->dentry.size : 0;
704 file->f_data = (CYG_ADDRWORD) fd;
710 // -------------------------------------------------------------------------
712 // Remove a file link from its directory.
715 fatfs_unlink(cyg_mtab_entry *mte,
719 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
720 fatfs_dirsearch_t ds;
723 CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);
725 init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
727 err = fatfs_find(&ds);
732 if (ds.node->refcnt > 0)
735 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
736 // if the file is read only fail with permission error
737 if (S_FATFS_ISRDONLY(ds.node->dentry.attrib))
739 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
741 err = fatfs_delete_file(disk, &ds.node->dentry);
743 fatfs_node_free(disk, ds.node);
748 // -------------------------------------------------------------------------
750 // Create a new directory.
753 fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
755 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
756 fatfs_dirsearch_t ds;
759 CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);
761 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
763 err = fatfs_find(&ds);
769 fatfs_dir_entry_t new_dir_dentry;
771 // The entry does not exist, and it is the last element in
772 // the pathname, so we can create it here
774 err = fatfs_create_dir(disk,
782 fatfs_node_alloc(disk, &new_dir_dentry);
787 else if (err == ENOERR)
795 // -------------------------------------------------------------------------
797 // Remove a directory.
800 fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
802 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
803 fatfs_dirsearch_t ds;
807 CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);
809 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
811 err = fatfs_find(&ds);
816 if (!S_ISDIR(ds.node->dentry.mode))
819 if (ds.node->refcnt > 0)
822 err = fatfs_delete_file(disk, &ds.node->dentry);
825 node = fatfs_node_find( disk, ".", 1, ds.node->dentry.cluster );
827 fatfs_node_free(disk, node);
829 node = fatfs_node_find( disk, "..", 2, ds.node->dentry.cluster );
831 fatfs_node_free(disk, node);
833 fatfs_node_free(disk, ds.node);
838 // -------------------------------------------------------------------------
840 // Rename a file/dir.
843 fatfs_rename(cyg_mtab_entry *mte,
849 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
850 fatfs_dirsearch_t ds1, ds2;
853 CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'",
854 mte, dir1, name1, dir2, name2);
856 init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);
858 err = fatfs_find(&ds1);
862 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
863 // if the file is read only fail with permission error
864 if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib))
866 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
868 // Protect the found nodes from being reused
869 // by the search for the ds2 dir/node pair
870 fatfs_node_ref(disk, ds1.dir);
871 fatfs_node_ref(disk, ds1.node);
873 init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
875 err = fatfs_find(&ds2);
877 // Check if the target name already exists
878 if (err == ENOERR && ds2.last)
884 // Check if the target dir doesn't exist
885 if (err == ENOENT && !ds2.last)
888 // Check if the target and the source are the same
889 if (ds1.node == ds2.node)
895 err = fatfs_rename_file(disk,
902 fatfs_node_rehash(disk, ds1.node);
905 // Unreference previousely protected nodes
906 fatfs_node_unref(disk, ds1.dir);
907 fatfs_node_unref(disk, ds1.node);
911 ds1.dir->dentry.atime =
912 ds1.dir->dentry.mtime =
913 ds2.dir->dentry.atime =
914 ds2.dir->dentry.mtime = cyg_timestamp();
919 // -------------------------------------------------------------------------
921 // Make a new directory entry for a file.
924 fatfs_link(cyg_mtab_entry *mte,
931 CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
932 mte, dir1, name1, dir2, name2, type);
934 // Linking not supported
938 // -------------------------------------------------------------------------
940 // Open a directory for reading.
943 fatfs_opendir(cyg_mtab_entry *mte,
948 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
950 fatfs_dirsearch_t ds;
953 CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p",
954 mte, dir, name, file);
956 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
958 err = fatfs_find(&ds);
962 if (!S_ISDIR(ds.node->dentry.mode))
965 // Allocate file object private data and
966 // make a reference to this file node
968 fd = alloc_fatfs_fd(disk, ds.node);
972 fatfs_node_ref(disk, ds.node);
974 // Initialize the file object
976 file->f_type = CYG_FILE_TYPE_FILE;
977 file->f_ops = &fatfs_dirops;
978 file->f_data = (CYG_ADDRWORD) fd;
985 // -------------------------------------------------------------------------
987 // Change directory support.
990 fatfs_chdir(cyg_mtab_entry *mte,
995 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
997 CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d",
998 mte, dir, dir_out, name);
1000 if (dir_out != NULL)
1002 // This is a request to get a new directory pointer in *dir_out
1004 fatfs_dirsearch_t ds;
1007 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1009 err = fatfs_find(&ds);
1013 if (!S_ISDIR(ds.node->dentry.mode))
1016 if (ds.node != disk->root)
1017 fatfs_node_ref(disk, ds.node);
1019 *dir_out = (cyg_dir) ds.node;
1023 // If no output dir is required, this means that the mte and
1024 // dir arguments are the current cdir setting and we should
1025 // forget this fact.
1027 fatfs_node_t *node = (fatfs_node_t *) dir;
1029 if (node != disk->root)
1030 fatfs_node_unref(disk, node);
1036 // -------------------------------------------------------------------------
1038 // Get struct stat info for named object.
1041 fatfs_stat(cyg_mtab_entry *mte,
1046 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1047 fatfs_dirsearch_t ds;
1050 CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p",
1051 mte, dir, name, buf);
1053 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1055 err = fatfs_find(&ds);
1059 // Fill in the status
1061 buf->st_mode = ds.node->dentry.mode;
1062 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1063 if (!S_FATFS_ISRDONLY(ds.node->dentry.attrib))
1064 buf->st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
1065 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1066 buf->st_ino = (ino_t) ds.node->dentry.cluster;
1071 buf->st_size = ds.node->dentry.size;
1072 buf->st_atime = ds.node->dentry.atime;
1073 buf->st_mtime = ds.node->dentry.mtime;
1074 buf->st_ctime = ds.node->dentry.ctime;
1079 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1080 // -------------------------------------------------------------------------
1081 // fatfs_set_attrib()
1082 // Set FAT file system attributes for specified file
1085 fatfs_set_attrib(cyg_mtab_entry *mte,
1088 const cyg_fs_attrib_t new_attrib)
1090 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1091 fatfs_dirsearch_t ds;
1094 CYG_TRACE4(TFS, "set_attrib mte=%p dir=%p name='%s' buf=%x",
1095 mte, dir, name, new_attrib);
1097 // Verify new_mode is valid
1098 if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
1101 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1103 err = fatfs_find(&ds);
1107 // Change the "changeable" mode bits for the file.
1108 ds.node->dentry.attrib =
1109 (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;
1111 return fatfs_write_dir_entry(disk,&ds.node->dentry);
1114 // -------------------------------------------------------------------------
1115 // fatfs_get_attrib()
1116 // Set FAT file system attributes for specified file
1119 fatfs_get_attrib(cyg_mtab_entry *mte,
1122 cyg_fs_attrib_t * const file_attrib)
1124 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1125 fatfs_dirsearch_t ds;
1128 CYG_TRACE4(TFS, "get_attrib mte=%p dir=%p name='%s' buf=%x",
1129 mte, dir, name, file_attrib);
1131 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1133 err = fatfs_find(&ds);
1137 // Get the attribute field
1138 CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
1139 *file_attrib = ds.node->dentry.attrib;
1143 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1145 // -------------------------------------------------------------------------
1147 // Getinfo. Support for attrib
1150 fatfs_getinfo(cyg_mtab_entry *mte,
1159 CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1160 mte, dir, name, key, buf, len);
1163 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1164 case FS_INFO_ATTRIB:
1165 err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
1167 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1168 #if defined(CYGSEM_FILEIO_BLOCK_USAGE)
1169 case FS_INFO_BLOCK_USAGE: {
1170 cyg_uint32 total_clusters;
1171 cyg_uint32 free_clusters;
1172 struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
1173 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1175 err = fatfs_get_disk_usage(disk, &total_clusters, &free_clusters);
1178 usage->total_blocks = total_clusters;
1179 usage->free_blocks = free_clusters;
1180 usage->block_size = disk->cluster_size;
1191 // -------------------------------------------------------------------------
1193 // Setinfo. Support for fssync and attrib
1196 fatfs_setinfo(cyg_mtab_entry *mte,
1205 CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1206 mte, dir, name, key, buf, len);
1211 err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
1213 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1214 case FS_INFO_ATTRIB:
1215 err = fatfs_set_attrib(mte, dir, name, *(cyg_fs_attrib_t *)buf);
1217 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1225 //==========================================================================
1228 // -------------------------------------------------------------------------
1230 // Read data from the file.
1233 fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1235 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1236 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1237 fatfs_node_t *node = fd->node;
1238 cyg_uint32 pos = fp->f_offset;
1239 ssize_t resid = uio->uio_resid;
1242 CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);
1244 // Loop over the io vectors until there are none left
1246 for (i = 0; i < uio->uio_iovcnt; i++)
1248 cyg_iovec *iov = &uio->uio_iov[i];
1249 char *buf = (char *) iov->iov_base;
1250 off_t len = iov->iov_len;
1252 // Loop over each vector filling it with data from the file
1254 while (len > 0 && pos < node->dentry.size)
1259 // Adjust size to end of file if necessary
1260 if (l > node->dentry.size-pos)
1261 l = node->dentry.size-pos;
1263 err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
1267 // Update working vars
1276 // We successfully read some data, update the access time,
1277 // file offset and transfer residue
1279 node->dentry.atime = cyg_timestamp();
1280 uio->uio_resid = resid;
1281 fp->f_offset = (off_t) pos;
1286 // -------------------------------------------------------------------------
1288 // Write data to file.
1291 fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1293 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1294 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1295 fatfs_node_t *node = fd->node;
1296 cyg_uint32 pos = fp->f_offset;
1297 ssize_t resid = uio->uio_resid;
1301 CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
1303 // If the APPEND mode bit was supplied, force all writes to
1304 // the end of the file
1305 if (fp->f_flag & CYG_FAPPEND)
1307 fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
1308 pos = fp->f_offset = node->dentry.size;
1311 // Check that pos is within current file size, or at the very end
1312 if (pos < 0 || pos > node->dentry.size)
1315 // Now loop over the iovecs until they are all done, or we get an error
1317 for (i = 0; i < uio->uio_iovcnt; i++)
1319 cyg_iovec *iov = &uio->uio_iov[i];
1320 char *buf = (char *) iov->iov_base;
1321 off_t len = iov->iov_len;
1323 // Loop over the vector writing it to the file
1324 // until it has all been done
1330 err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);
1332 // Update working vars
1339 // Stop writing if there is no more space in the file
1348 // We wrote some data successfully, update the modified and access
1349 // times of the node, increase its size appropriately, and update
1350 // the file offset and transfer residue.
1352 node->dentry.mtime =
1353 node->dentry.atime = cyg_timestamp();
1355 if (pos > node->dentry.size)
1356 node->dentry.size = pos;
1358 uio->uio_resid = resid;
1359 fp->f_offset = (off_t) pos;
1364 // -------------------------------------------------------------------------
1366 // Seek to a new file position.
1369 fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
1371 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1372 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1376 CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
1381 // Pos is already where we want to be
1384 // Add pos to current offset
1385 pos += fp->f_offset;
1388 // Add pos to file size
1389 pos += fd->node->dentry.size;
1395 // Check that pos is still within current file size,
1396 // or at the very end
1397 if (pos < 0 || pos > fd->node->dentry.size)
1400 // All OK, set fp offset and return new position
1402 err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);
1405 *apos = fp->f_offset = pos;
1407 CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);
1412 // -------------------------------------------------------------------------
1414 // Handle ioctls. Currently none are defined.
1417 fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
1419 CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
1423 // -------------------------------------------------------------------------
1424 // fatfs_fo_fsync().
1425 // Force the file out to data storage.
1428 fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
1430 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1431 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1432 fatfs_node_t *node = fd->node;
1435 CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);
1437 err = fatfs_write_dir_entry(disk, &node->dentry);
1440 err = cyg_blib_sync(&disk->blib);
1445 // -------------------------------------------------------------------------
1450 fatfs_fo_close(struct CYG_FILE_TAG *fp)
1452 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1453 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1454 fatfs_node_t *node = fd->node;
1457 CYG_TRACE1(TFO, "close fp=%p", fp);
1459 // Write file attributes to disk, unreference
1460 // the file node and free its private data
1462 if (node != disk->root)
1463 err = fatfs_write_dir_entry(disk, &node->dentry);
1465 fatfs_node_unref(disk, node);
1472 // -------------------------------------------------------------------------
1477 fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
1479 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1480 fatfs_node_t *node = fd->node;
1482 CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);
1484 // Fill in the status
1486 buf->st_mode = node->dentry.mode;
1487 buf->st_ino = (ino_t) node->dentry.cluster;
1492 buf->st_size = node->dentry.size;
1493 buf->st_atime = node->dentry.atime;
1494 buf->st_mtime = node->dentry.mtime;
1495 buf->st_ctime = node->dentry.ctime;
1500 // -------------------------------------------------------------------------
1501 // fatfs_fo_getinfo()
1505 fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1507 CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1511 // -------------------------------------------------------------------------
1512 // fatfs_fo_setinfo()
1516 fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1518 CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1522 //==========================================================================
1523 // Directory operations
1525 // -------------------------------------------------------------------------
1526 // fatfs_fo_dirread()
1527 // Read a single directory entry from a file.
1530 fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1532 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1533 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1534 struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
1535 char *nbuf = ent->d_name;
1536 off_t len = uio->uio_iov[0].iov_len;
1537 fatfs_dir_entry_t dentry;
1540 CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);
1542 if (len < sizeof(struct dirent))
1545 err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry);
1548 return (err == EEOF ? ENOERR : err);
1550 strcpy(nbuf, dentry.filename);
1551 #ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
1552 ent->d_type = dentry.mode;
1554 fd->node->dentry.atime = cyg_timestamp();
1555 uio->uio_resid -= sizeof(struct dirent);
1561 // -------------------------------------------------------------------------
1562 // fatfs_fo_dirlseek()
1563 // Seek directory to start.
1566 fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
1568 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1569 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1572 CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);
1574 // Only allow SEEK_SET to zero
1576 if (whence != SEEK_SET || *pos != 0)
1579 err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);
1582 *pos = fp->f_offset = 0;
1587 // -------------------------------------------------------------------------