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);
312 // First check the cache
314 ds->node = fatfs_node_find(ds->disk,
317 ds->dir->dentry.cluster);
319 if (ds->node != NULL)
321 // Dir entry found in cache
323 CYG_TRACE0(TFS, "dir entry found in cache");
325 fatfs_node_touch(ds->disk, ds->node);
329 // Dir entry not in cache - search the current dir
331 fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);
335 // Read next dir entry
337 err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
339 return (err == EEOF ? ENOERR : err);
343 if ('\0' == dentry.filename[ds->namelen] &&
344 0 == strncasecmp(dentry.filename, ds->name, ds->namelen))
346 // Dir entry found - allocate new node and return
348 CYG_TRACE0(TFS, "dir entry found");
350 ds->node = fatfs_node_alloc(ds->disk, &dentry);
351 if (NULL == ds->node)
360 find_entry(fatfs_dirsearch_t *ds)
362 const char *name = ds->path;
363 const char *n = name;
367 if( !S_ISDIR(ds->dir->dentry.mode) )
369 CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
373 // Isolate the next element of the path name
374 while (*n != '\0' && *n != '/')
377 // If we terminated on a NUL, set last flag
381 // Update name in dirsearch object
383 ds->namelen = namelen;
385 err = find_direntry(ds);
389 CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
391 if (ds->node != NULL)
398 fatfs_find(fatfs_dirsearch_t *ds)
402 CYG_TRACE1(TFS, "find path='%s'", ds->path);
404 // Short circuit empty paths
405 if (*(ds->path) == '\0')
408 // Iterate down directory tree until we find the object we want
411 err = find_entry(ds);
418 CYG_TRACE0(TFS, "entry found");
422 // Update dirsearch object to search next directory
424 ds->path += ds->namelen;
426 // Skip dirname separators
427 if (*(ds->path) == '/') ds->path++;
429 CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
433 //==========================================================================
434 // Filesystem operations
436 // -------------------------------------------------------------------------
438 // Process a mount request. This mainly creates a root for the
442 fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
444 cyg_io_handle_t dev_h;
446 fatfs_dir_entry_t root_dentry;
449 CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
453 CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
455 err = cyg_io_lookup(mte->devname, &dev_h);
459 disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
463 CYG_TRACE0(TFS, "initializing block cache");
465 disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
466 if (NULL == disk->bcache_mem)
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);
476 free(disk->bcache_mem);
483 CYG_TRACE0(TFS, "initializing disk");
485 err = fatfs_init(disk);
488 cyg_blib_delete(&disk->blib);
489 free(disk->bcache_mem);
495 print_disk_info(disk);
498 CYG_TRACE0(TFS, "initializing node cache");
500 fatfs_node_cache_init(disk);
502 CYG_TRACE0(TFS, "initializing root node");
504 fatfs_get_root_dir_entry(disk, &root_dentry);
506 disk->root = fatfs_node_alloc(disk, &root_dentry);
508 fatfs_node_ref(disk, disk->root);
510 mte->root = (cyg_dir)disk->root;
511 mte->data = (CYG_ADDRWORD)disk;
513 CYG_TRACE0(TFS, "disk mounted");
518 // -------------------------------------------------------------------------
520 // Unmount the filesystem. This will currently only succeed if the
521 // filesystem is empty.
524 fatfs_umount(cyg_mtab_entry *mte)
526 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
527 fatfs_node_t *root = (fatfs_node_t *) mte->root;
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));
533 if (root->refcnt > 1)
536 if (fatfs_get_live_node_count(disk) != 1)
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);
546 mte->root = CYG_DIR_NULL;
547 mte->data = (CYG_ADDRWORD) NULL;
549 CYG_TRACE0(TFS, "disk umounted");
554 // -------------------------------------------------------------------------
556 // Open a file for reading or writing.
559 fatfs_open(cyg_mtab_entry *mte,
565 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
566 fatfs_node_t *node = NULL;
568 fatfs_dirsearch_t ds;
571 CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p",
572 mte, dir, name, mode, file);
574 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
576 err = fatfs_find(&ds);
580 if (ds.last && (mode & O_CREAT))
582 fatfs_dir_entry_t new_file_dentry;
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.
588 CYG_TRACE1(TFS, "creating new file '%s'", name);
590 err = fatfs_create_file(disk,
598 node = fatfs_node_alloc(disk, &new_file_dentry);
602 // Update directory times
603 ds.dir->dentry.atime =
604 ds.dir->dentry.mtime = cyg_timestamp();
609 else if (err == ENOERR)
611 // The node exists. If the O_CREAT and O_EXCL bits are set, we
612 // must fail the open
614 if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
620 if (err == ENOERR && (mode & O_TRUNC))
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);
630 if (S_ISDIR(node->dentry.mode))
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))
638 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
640 // Allocate file object private data and
641 // make a reference to this file node
643 fd = alloc_fatfs_fd(disk, node);
647 fatfs_node_ref(disk, node);
649 // Initialize the file object
652 fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
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;
664 // -------------------------------------------------------------------------
666 // Remove a file link from its directory.
669 fatfs_unlink(cyg_mtab_entry *mte,
673 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
674 fatfs_dirsearch_t ds;
677 CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);
679 init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
681 err = fatfs_find(&ds);
686 if (ds.node->refcnt > 0)
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))
693 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
695 err = fatfs_delete_file(disk, &ds.node->dentry);
697 fatfs_node_free(disk, ds.node);
702 // -------------------------------------------------------------------------
704 // Create a new directory.
707 fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
709 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
710 fatfs_dirsearch_t ds;
713 CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);
715 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
717 err = fatfs_find(&ds);
723 fatfs_dir_entry_t new_dir_dentry;
725 // The entry does not exist, and it is the last element in
726 // the pathname, so we can create it here
728 err = fatfs_create_dir(disk,
736 fatfs_node_alloc(disk, &new_dir_dentry);
741 else if (err == ENOERR)
749 // -------------------------------------------------------------------------
751 // Remove a directory.
754 fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
756 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
757 fatfs_dirsearch_t ds;
760 CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);
762 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
764 err = fatfs_find(&ds);
769 if (!S_ISDIR(ds.node->dentry.mode))
772 if (ds.node->refcnt > 0)
775 err = fatfs_delete_file(disk, &ds.node->dentry);
777 fatfs_node_free(disk, ds.node);
782 // -------------------------------------------------------------------------
784 // Rename a file/dir.
787 fatfs_rename(cyg_mtab_entry *mte,
793 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
794 fatfs_dirsearch_t ds1, ds2;
797 CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'",
798 mte, dir1, name1, dir2, name2);
800 init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);
802 err = fatfs_find(&ds1);
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))
810 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
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);
817 init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
819 err = fatfs_find(&ds2);
821 // Check if the target name already exists
822 if (err == ENOERR && ds2.last)
828 // Check if the target dir doesn't exist
829 if (err == ENOENT && !ds2.last)
832 // Check if the target and the source are the same
833 if (ds1.node == ds2.node)
839 err = fatfs_rename_file(disk,
846 fatfs_node_rehash(disk, ds1.node);
849 // Unreference previousely protected nodes
850 fatfs_node_unref(disk, ds1.dir);
851 fatfs_node_unref(disk, ds1.node);
855 ds1.dir->dentry.atime =
856 ds1.dir->dentry.mtime =
857 ds2.dir->dentry.atime =
858 ds2.dir->dentry.mtime = cyg_timestamp();
863 // -------------------------------------------------------------------------
865 // Make a new directory entry for a file.
868 fatfs_link(cyg_mtab_entry *mte,
875 CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
876 mte, dir1, name1, dir2, name2, type);
878 // Linking not supported
882 // -------------------------------------------------------------------------
884 // Open a directory for reading.
887 fatfs_opendir(cyg_mtab_entry *mte,
892 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
894 fatfs_dirsearch_t ds;
897 CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p",
898 mte, dir, name, file);
900 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
902 err = fatfs_find(&ds);
906 if (!S_ISDIR(ds.node->dentry.mode))
909 // Allocate file object private data and
910 // make a reference to this file node
912 fd = alloc_fatfs_fd(disk, ds.node);
916 fatfs_node_ref(disk, ds.node);
918 // Initialize the file object
920 file->f_type = CYG_FILE_TYPE_FILE;
921 file->f_ops = &fatfs_dirops;
922 file->f_data = (CYG_ADDRWORD) fd;
929 // -------------------------------------------------------------------------
931 // Change directory support.
934 fatfs_chdir(cyg_mtab_entry *mte,
939 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
941 CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d",
942 mte, dir, dir_out, name);
946 // This is a request to get a new directory pointer in *dir_out
948 fatfs_dirsearch_t ds;
951 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
953 err = fatfs_find(&ds);
957 if (!S_ISDIR(ds.node->dentry.mode))
960 if (ds.node != disk->root)
961 fatfs_node_ref(disk, ds.node);
963 *dir_out = (cyg_dir) ds.node;
967 // If no output dir is required, this means that the mte and
968 // dir arguments are the current cdir setting and we should
971 fatfs_node_t *node = (fatfs_node_t *) dir;
973 if (node != disk->root)
974 fatfs_node_unref(disk, node);
980 // -------------------------------------------------------------------------
982 // Get struct stat info for named object.
985 fatfs_stat(cyg_mtab_entry *mte,
990 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
991 fatfs_dirsearch_t ds;
994 CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p",
995 mte, dir, name, buf);
997 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
999 err = fatfs_find(&ds);
1003 // Fill in the status
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;
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;
1023 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1024 // -------------------------------------------------------------------------
1025 // fatfs_set_attrib()
1026 // Set FAT file system attributes for specified file
1029 fatfs_set_attrib(cyg_mtab_entry *mte,
1032 const cyg_fs_attrib_t new_attrib)
1034 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1035 fatfs_dirsearch_t ds;
1038 CYG_TRACE4(TFS, "set_attrib mte=%p dir=%p name='%s' buf=%x",
1039 mte, dir, name, new_attrib);
1041 // Verify new_mode is valid
1042 if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
1045 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1047 err = fatfs_find(&ds);
1051 // Change the "changeable" mode bits for the file.
1052 ds.node->dentry.attrib =
1053 (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;
1055 return fatfs_write_dir_entry(disk,&ds.node->dentry);
1058 // -------------------------------------------------------------------------
1059 // fatfs_get_attrib()
1060 // Set FAT file system attributes for specified file
1063 fatfs_get_attrib(cyg_mtab_entry *mte,
1066 cyg_fs_attrib_t * const file_attrib)
1068 fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
1069 fatfs_dirsearch_t ds;
1072 CYG_TRACE4(TFS, "get_attrib mte=%p dir=%p name='%s' buf=%x",
1073 mte, dir, name, file_attrib);
1075 init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1077 err = fatfs_find(&ds);
1081 // Get the attribute field
1082 CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
1083 *file_attrib = ds.node->dentry.attrib;
1087 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1089 // -------------------------------------------------------------------------
1091 // Getinfo. Support for attrib
1094 fatfs_getinfo(cyg_mtab_entry *mte,
1103 CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1104 mte, dir, name, key, buf, len);
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);
1111 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1119 // -------------------------------------------------------------------------
1121 // Setinfo. Support for fssync and attrib
1124 fatfs_setinfo(cyg_mtab_entry *mte,
1133 CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1134 mte, dir, name, key, buf, len);
1139 err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
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);
1145 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1153 //==========================================================================
1156 // -------------------------------------------------------------------------
1158 // Read data from the file.
1161 fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
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;
1170 CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);
1172 // Loop over the io vectors until there are none left
1174 for (i = 0; i < uio->uio_iovcnt; i++)
1176 cyg_iovec *iov = &uio->uio_iov[i];
1177 char *buf = (char *) iov->iov_base;
1178 off_t len = iov->iov_len;
1180 // Loop over each vector filling it with data from the file
1182 while (len > 0 && pos < node->dentry.size)
1187 // Adjust size to end of file if necessary
1188 if (l > node->dentry.size-pos)
1189 l = node->dentry.size-pos;
1191 err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
1195 // Update working vars
1204 // We successfully read some data, update the access time,
1205 // file offset and transfer residue
1207 node->dentry.atime = cyg_timestamp();
1208 uio->uio_resid = resid;
1209 fp->f_offset = (off_t) pos;
1214 // -------------------------------------------------------------------------
1216 // Write data to file.
1219 fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
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;
1229 CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
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)
1235 fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
1236 pos = fp->f_offset = node->dentry.size;
1239 // Check that pos is within current file size, or at the very end
1240 if (pos < 0 || pos > node->dentry.size)
1243 // Now loop over the iovecs until they are all done, or we get an error
1245 for (i = 0; i < uio->uio_iovcnt; i++)
1247 cyg_iovec *iov = &uio->uio_iov[i];
1248 char *buf = (char *) iov->iov_base;
1249 off_t len = iov->iov_len;
1251 // Loop over the vector writing it to the file
1252 // until it has all been done
1258 err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);
1260 // Update working vars
1267 // Stop writing if there is no more space in the file
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.
1280 node->dentry.mtime =
1281 node->dentry.atime = cyg_timestamp();
1283 if (pos > node->dentry.size)
1284 node->dentry.size = pos;
1286 uio->uio_resid = resid;
1287 fp->f_offset = (off_t) pos;
1292 // -------------------------------------------------------------------------
1294 // Seek to a new file position.
1297 fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
1299 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1300 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1304 CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
1309 // Pos is already where we want to be
1312 // Add pos to current offset
1313 pos += fp->f_offset;
1316 // Add pos to file size
1317 pos += fd->node->dentry.size;
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)
1328 // All OK, set fp offset and return new position
1330 err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);
1333 *apos = fp->f_offset = pos;
1335 CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);
1340 // -------------------------------------------------------------------------
1342 // Handle ioctls. Currently none are defined.
1345 fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
1347 CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
1351 // -------------------------------------------------------------------------
1352 // fatfs_fo_fsync().
1353 // Force the file out to data storage.
1356 fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
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;
1363 CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);
1365 err = fatfs_write_dir_entry(disk, &node->dentry);
1368 err = cyg_blib_sync(&disk->blib);
1373 // -------------------------------------------------------------------------
1378 fatfs_fo_close(struct CYG_FILE_TAG *fp)
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;
1385 CYG_TRACE1(TFO, "close fp=%p", fp);
1387 // Write file attributes to disk, unreference
1388 // the file node and free its private data
1390 if (node != disk->root)
1391 err = fatfs_write_dir_entry(disk, &node->dentry);
1393 fatfs_node_unref(disk, node);
1400 // -------------------------------------------------------------------------
1405 fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
1407 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1408 fatfs_node_t *node = fd->node;
1410 CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);
1412 // Fill in the status
1414 buf->st_mode = node->dentry.mode;
1415 buf->st_ino = (ino_t) node->dentry.cluster;
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;
1428 // -------------------------------------------------------------------------
1429 // fatfs_fo_getinfo()
1433 fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1435 CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1439 // -------------------------------------------------------------------------
1440 // fatfs_fo_setinfo()
1444 fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1446 CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1450 //==========================================================================
1451 // Directory operations
1453 // -------------------------------------------------------------------------
1454 // fatfs_fo_dirread()
1455 // Read a single directory entry from a file.
1458 fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
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;
1468 CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);
1470 if (len < sizeof(struct dirent))
1473 err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry);
1476 return (err == EEOF ? ENOERR : err);
1478 strcpy(nbuf, dentry.filename);
1480 fd->node->dentry.atime = cyg_timestamp();
1481 uio->uio_resid -= sizeof(struct dirent);
1487 // -------------------------------------------------------------------------
1488 // fatfs_fo_dirlseek()
1489 // Seek directory to start.
1492 fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
1494 fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data;
1495 fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data;
1498 CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);
1500 // Only allow SEEK_SET to zero
1502 if (whence != SEEK_SET || *pos != 0)
1505 err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);
1508 *pos = fp->f_offset = 0;
1513 // -------------------------------------------------------------------------