# HG changeset patch # User asl # Date 1096962358 0 # Node ID 71a7aa4693878f5c5ef82dc95b18103676f50612 # Parent 5b91c0bea75ae9fd663058466daa5ea9c9a14221 Major update of fatfs. FAT32 support and changes to the node cache. diff --git a/packages/fs/fat/current/ChangeLog b/packages/fs/fat/current/ChangeLog --- a/packages/fs/fat/current/ChangeLog +++ b/packages/fs/fat/current/ChangeLog @@ -1,3 +1,39 @@ +2004-08-10 Savin Zlobec + + * src/fatfs.h: + * src/fatfs_supp.c: + Added FAT32 support. + +2004-07-13 Savin Zlobec + + * cdl/fatfs.cdl: + * src/fatfs.h: + * src/fatfs.c: + * src/fatfs_supp.c: + * src/fatfs_ncache.c: + Refactored the code and changed file node cache memory + allocation from malloc to custom pool based one. + +2004-07-05 Savin Zlobec + + * cdl/fatfs.cdl: + * src/fatfs.h: + * src/fatfs.c: + * src/fatfs_supp.c: + * src/fatfs_ncache.c: + Removed FAT table cache - it added little or no speed gain to + the fatfs. Implemented private data for fatfs file descriptors which + holds the current FAT cluster position, this greatly improves + read/write times for big files comparing to the old implementation. + * src/fatfs_tcache.c: Removed. + +2004-06-24 Savin Zlobec + + * src/fatfs.h: + * src/fatfs_supp.c: + Implemented fatfs_get_disk_usage function for + getting the number of total and free clusters. + 2004-01-19 Nick Garnett @@ -65,7 +101,7 @@ 2003-07-07 Savin Zlobec # Contributors: # Date: 2003-06-25 # @@ -63,8 +63,7 @@ cdl_package CYGPKG_FS_FAT { compile -library=libextras.a fatfs.c \ fatfs_supp.c \ - fatfs_ncache.c \ - fatfs_tcache.c + fatfs_ncache.c cdl_option CYGNUM_FS_FAT_NODE_HASH_TABLE_SIZE { display "Node hash table size" @@ -76,32 +75,16 @@ cdl_package CYGPKG_FS_FAT { as keys." } - cdl_option CYGNUM_FS_FAT_NODE_ALLOC_THRESHOLD { - display "Node allocation treshold" - flavor data - default_value 16 - legal_values 1 to 9999999999 - description "This option controls at which point the filesystem - starts reusing dead file nodes rather then allocating - memory for new nodes." - } - - cdl_option CYGNUM_FS_FAT_FAT_TABLE_CACHE_MEMSIZE { - display "FAT table cache memory size" + cdl_option CYGNUM_FS_FAT_NODE_POOL_SIZE { + display "Node pool size" flavor data - default_value 10240 + default_value { (CYGNUM_FILEIO_NFILE + 2) } legal_values 1 to 9999999999 - description "This option controls the amount of memory used - for the FAT table cache." - } - - cdl_option CYGNUM_FS_FAT_FAT_TABLE_CACHE_INCREMENT { - display "FAT table cache size increment" - flavor data - default_value 10 - legal_values 1 to 9999999999 - description "This option controls the amount of memory by which - the per-file FAT table cache will grow." + requires { CYGNUM_FS_FAT_NODE_POOL_SIZE >= (CYGNUM_FILEIO_NFILE+2) } + description "This option controls the size of the node pool used + for storing file nodes. This value should be set to + the maximum required number of simultaneously open + files plus the desired size of unused node cache." } cdl_option CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE { diff --git a/packages/fs/fat/current/src/fatfs.c b/packages/fs/fat/current/src/fatfs.c --- a/packages/fs/fat/current/src/fatfs.c +++ b/packages/fs/fat/current/src/fatfs.c @@ -8,8 +8,7 @@ //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2003 Savin Zlobec +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -41,7 +40,7 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): savin (based on ramfs.c) +// Author(s): Savin Zlobec (based on ramfs.c) // Original data: nickg // Date: 2003-06-29 // Purpose: FAT file system @@ -53,11 +52,10 @@ #include #include -#include #include #include -#include // base kernel types +#include #include // tracing macros #include // assertion macros @@ -71,7 +69,6 @@ #include #include -#include #include #include #include @@ -199,7 +196,7 @@ static cyg_fileops fatfs_dirops = // Parameters for a directory search. The fields of this structure are // updated as we follow a pathname through the directory tree. -struct fatfs_dirsearch_t +typedef struct fatfs_dirsearch_s { fatfs_disk_t *disk; // Disk info fatfs_node_t *dir; // Directory to search @@ -208,9 +205,20 @@ struct fatfs_dirsearch_t const char *name; // Last name fragment used int namelen; // Name fragment length cyg_bool last; // Last name in path? -}; +} fatfs_dirsearch_t; + +// ------------------------------------------------------------------------- +// FATFS file descriptor data -typedef struct fatfs_dirsearch_t fatfs_dirsearch_t; +typedef struct fatfs_fd_s +{ + fatfs_node_t *node; + fatfs_data_pos_t pos; +} fatfs_fd_t; + +static fatfs_fd_t fatfs_fds_base[CYGNUM_FILEIO_NFD]; +static fatfs_fd_t *fatfs_fds_pool[CYGNUM_FILEIO_NFD]; +static cyg_uint32 fatfs_fds_free_cnt; //========================================================================== @@ -232,16 +240,59 @@ print_disk_info(fatfs_disk_t *disk) #endif static void +init_fatfs_fds(void) +{ + static bool initialized = false; + + int i; + + if (initialized) + return; + + initialized = true; + + for (i = 0; i < CYGNUM_FILEIO_NFD; i++) + { + fatfs_fds_pool[i] = &fatfs_fds_base[i]; + } + fatfs_fds_free_cnt = i; +} + +static fatfs_fd_t * +alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node) +{ + fatfs_fd_t *fd = NULL; + + if (fatfs_fds_free_cnt > 0) + { + fd = fatfs_fds_pool[--fatfs_fds_free_cnt]; + + fd->node = node; + fatfs_initpos(disk, &node->dentry, &fd->pos); + } + + return fd; +} + +static void +free_fatfs_fd(fatfs_fd_t *fd) +{ + fatfs_fds_pool[fatfs_fds_free_cnt++] = fd; +} + +static void init_dirsearch(fatfs_dirsearch_t *ds, fatfs_disk_t *disk, fatfs_node_t *dir, const char *name) { - ds->disk = disk; + ds->disk = disk; + if (NULL == dir) ds->dir = disk->root; else ds->dir = dir; + ds->path = name; ds->node = ds->dir; ds->namelen = 0; @@ -251,67 +302,82 @@ init_dirsearch(fatfs_dirsearch_t *ds, static int find_direntry(fatfs_dirsearch_t *ds) { - int err; - cyg_uint32 pos = 0; - fatfs_node_t node_data; + fatfs_dir_entry_t dentry; + fatfs_data_pos_t pos; + int err; + + CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name); - CYG_TRACE1(TFS, "Finding dir entry '%s'", ds->name); - - ds->node = fatfs_node_find(ds->disk, ds->name, - ds->namelen, ds->dir->cluster); + // First check the cache + + ds->node = fatfs_node_find(ds->disk, + ds->name, + ds->namelen, + ds->dir->dentry.cluster); if (ds->node != NULL) { - CYG_TRACE1(TFS, "Found dir entry '%s' in cache", ds->name); + // Dir entry found in cache + + CYG_TRACE0(TFS, "dir entry found in cache"); + fatfs_node_touch(ds->disk, ds->node); return ENOERR; } - + + // Dir entry not in cache - search the current dir + + fatfs_initpos(ds->disk, &ds->dir->dentry, &pos); + while (true) - { - err = fatfs_get_dir_entry_node(ds->disk, ds->dir, &pos, &node_data); + { + // Read next dir entry + + err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry); if (err != ENOERR) return (err == EEOF ? ENOERR : err); - if ('\0' == node_data.filename[ds->namelen] && - 0 == strncasecmp(node_data.filename, ds->name, ds->namelen)) + // Compare filenames + + if ('\0' == dentry.filename[ds->namelen] && + 0 == strncasecmp(dentry.filename, ds->name, ds->namelen)) { - CYG_TRACE2(TFS, "Read dir entry '%s' at %d", - node_data.filename, pos); + // Dir entry found - allocate new node and return + + CYG_TRACE0(TFS, "dir entry found"); - ds->node = fatfs_node_alloc(ds->disk, &node_data); + ds->node = fatfs_node_alloc(ds->disk, &dentry); if (NULL == ds->node) - return ENOMEM; + return EMFILE; + return ENOERR; } - pos++; } } static int find_entry(fatfs_dirsearch_t *ds) { - int err; - const char *name = ds->path; - const char *n = name; - char namelen = 0; + const char *name = ds->path; + const char *n = name; + char namelen = 0; + int err; - // check that we really have a directory - if( !S_ISDIR(ds->dir->mode) ) + if( !S_ISDIR(ds->dir->dentry.mode) ) { - CYG_TRACE1(TFS, "Entry '%s' not dir", ds->dir->filename); + CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename); return ENOTDIR; } - // Isolate the next element of the path name. + // Isolate the next element of the path name while (*n != '\0' && *n != '/') n++, namelen++; - // If we terminated on a NUL, set last flag. + // If we terminated on a NUL, set last flag if (*n == '\0') ds->last = true; - // update name in dirsearch object + // Update name in dirsearch object ds->name = name; ds->namelen = namelen; @@ -319,7 +385,7 @@ find_entry(fatfs_dirsearch_t *ds) if (err != ENOERR) return err; - CYG_TRACE2(TFS, "Entry '%s' %s", name, (ds->node ? "found" : "not found")); + CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found")); if (ds->node != NULL) return ENOERR; @@ -332,14 +398,13 @@ fatfs_find(fatfs_dirsearch_t *ds) { int err; - CYG_TRACE1(TFS, "Find path='%s'", ds->path); + CYG_TRACE1(TFS, "find path='%s'", ds->path); // Short circuit empty paths if (*(ds->path) == '\0') return ENOERR; - // Iterate down directory tree until we find the object - // we want. + // Iterate down directory tree until we find the object we want for(;;) { err = find_entry(ds); @@ -349,18 +414,18 @@ fatfs_find(fatfs_dirsearch_t *ds) if (ds->last) { - CYG_TRACE0(TFS, "Entry found"); + CYG_TRACE0(TFS, "entry found"); return ENOERR; } - // Update dirsearch object to search next directory. - ds->dir = ds->node; + // Update dirsearch object to search next directory + ds->dir = ds->node; ds->path += ds->namelen; // Skip dirname separators if (*(ds->path) == '/') ds->path++; - CYG_TRACE1(TFS, "Find path to go='%s'", ds->path); + CYG_TRACE1(TFS, "find path to go='%s'", ds->path); } } @@ -375,14 +440,16 @@ fatfs_find(fatfs_dirsearch_t *ds) static int fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte) { - cyg_io_handle_t dev_h; - Cyg_ErrNo err; - fatfs_disk_t *disk; - fatfs_node_t root_data; + cyg_io_handle_t dev_h; + fatfs_disk_t *disk; + fatfs_dir_entry_t root_dentry; + Cyg_ErrNo err; - CYG_TRACE2(TFS, "Mount fste=%p mte=%p", fste, mte); + CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte); + + init_fatfs_fds(); - CYG_TRACE1(TFS, "Looking up disk device '%s'", mte->devname); + CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname); err = cyg_io_lookup(mte->devname, &dev_h); if (err != ENOERR) @@ -392,21 +459,11 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m if (NULL == disk) return ENOMEM; - CYG_TRACE0(TFS, "Initializing FAT table cache"); - - if (ENOERR != fatfs_tcache_create(disk, - CYGNUM_FS_FAT_FAT_TABLE_CACHE_MEMSIZE)) - { - free(disk); - return ENOMEM; - } - - CYG_TRACE0(TFS, "Initializing block cache"); + CYG_TRACE0(TFS, "initializing block cache"); disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE); if (NULL == disk->bcache_mem) { - fatfs_tcache_delete(disk); free(disk); return ENOMEM; } @@ -415,7 +472,6 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib); if (err != ENOERR) { - fatfs_tcache_delete(disk); free(disk->bcache_mem); free(disk); return err; @@ -423,12 +479,11 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m disk->dev_h = dev_h; - CYG_TRACE0(TFS, "Initializing disk"); + CYG_TRACE0(TFS, "initializing disk"); - err = fatfs_get_disk_info(disk); + err = fatfs_init(disk); if (err != ENOERR) { - fatfs_tcache_delete(disk); cyg_blib_delete(&disk->blib); free(disk->bcache_mem); free(disk); @@ -439,20 +494,22 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m print_disk_info(disk); #endif - CYG_TRACE0(TFS, "Initializing node cache"); + CYG_TRACE0(TFS, "initializing node cache"); fatfs_node_cache_init(disk); - CYG_TRACE0(TFS, "Initializing root node"); + CYG_TRACE0(TFS, "initializing root node"); - fatfs_get_root_node(disk, &root_data); - disk->root = fatfs_node_alloc(disk, &root_data); + fatfs_get_root_dir_entry(disk, &root_dentry); + + disk->root = fatfs_node_alloc(disk, &root_dentry); + fatfs_node_ref(disk, disk->root); mte->root = (cyg_dir)disk->root; mte->data = (CYG_ADDRWORD)disk; - CYG_TRACE0(TFS, "Disk mounted"); + CYG_TRACE0(TFS, "disk mounted"); return ENOERR; } @@ -465,10 +522,10 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m static int fatfs_umount(cyg_mtab_entry *mte) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_node_t *root = (fatfs_node_t *)mte->root; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_node_t *root = (fatfs_node_t *) mte->root; - CYG_TRACE3(TFS, "Umount mte=%p %d live nodes %d dead nodes", + CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes", mte, fatfs_get_live_node_count(disk), fatfs_get_dead_node_count(disk)); @@ -480,16 +537,15 @@ fatfs_umount(cyg_mtab_entry *mte) fatfs_node_unref(disk, root); fatfs_node_cache_flush(disk); - fatfs_tcache_delete(disk); // FIXME: cache delete can fail if cache can't be synced cyg_blib_delete(&disk->blib); free(disk->bcache_mem); free(disk); mte->root = CYG_DIR_NULL; - mte->data = (CYG_ADDRWORD)NULL; + mte->data = (CYG_ADDRWORD) NULL; - CYG_TRACE0(TFS, "Disk umounted"); + CYG_TRACE0(TFS, "disk umounted"); return ENOERR; } @@ -505,15 +561,16 @@ fatfs_open(cyg_mtab_entry *mte, int mode, cyg_file *file) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_node_t *node = NULL; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_node_t *node = NULL; + fatfs_fd_t *fd; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE5(TFS, "Open mte=%p dir=%p name='%s' mode=%d file=%p", + CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p", mte, dir, name, mode, file); - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); @@ -521,26 +578,29 @@ fatfs_open(cyg_mtab_entry *mte, { if (ds.last && (mode & O_CREAT)) { - fatfs_node_t node_data; + fatfs_dir_entry_t new_file_dentry; // No node there, if the O_CREAT bit is set then we must // create a new one. The dir and name fields of the dirsearch // object will have been updated so we know where to put it. - CYG_TRACE1(TFS, "Creating new file '%s'", name); + CYG_TRACE1(TFS, "creating new file '%s'", name); - err = fatfs_create_file(disk, ds.dir, ds.name, - ds.namelen, &node_data); + err = fatfs_create_file(disk, + &ds.dir->dentry, + ds.name, + ds.namelen, + &new_file_dentry); if (err != ENOERR) return err; - node = fatfs_node_alloc(disk, &node_data); + node = fatfs_node_alloc(disk, &new_file_dentry); if (NULL == node) - return ENOMEM; + return EMFILE; // Update directory times - ds.dir->atime = - ds.dir->mtime = cyg_timestamp(); + ds.dir->dentry.atime = + ds.dir->dentry.mtime = cyg_timestamp(); err = ENOERR; } @@ -548,7 +608,7 @@ fatfs_open(cyg_mtab_entry *mte, else if (err == ENOERR) { // The node exists. If the O_CREAT and O_EXCL bits are set, we - // must fail the open. + // must fail the open if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) err = EEXIST; @@ -558,28 +618,36 @@ fatfs_open(cyg_mtab_entry *mte, if (err == ENOERR && (mode & O_TRUNC)) { - // If the O_TRUNC bit is set we must clean out the file data. - CYG_TRACE0(TFS, "Truncating file"); - fatfs_trunc_file(disk, node); + // If the O_TRUNC bit is set we must clean out the file data + CYG_TRACE0(TFS, "truncating file"); + fatfs_trunc_file(disk, &node->dentry); } if (err != ENOERR) return err; - // Check that we actually have a file here - if (S_ISDIR(node->mode)) + if (S_ISDIR(node->dentry.mode)) return EISDIR; - // Make a reference to this file node + // Allocate file object private data and + // make a reference to this file node + + fd = alloc_fatfs_fd(disk, node); + if (NULL == fd) + return EMFILE; + fatfs_node_ref(disk, node); // Initialize the file object + if (mode & O_APPEND) + fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size); + file->f_flag |= mode & CYG_FILE_MODE_MASK; file->f_type = CYG_FILE_TYPE_FILE; file->f_ops = &fatfs_fileops; - file->f_offset = (mode & O_APPEND) ? node->size : 0; - file->f_data = (CYG_ADDRWORD)node; + file->f_offset = (mode & O_APPEND) ? node->dentry.size : 0; + file->f_data = (CYG_ADDRWORD) fd; file->f_xops = 0; return ENOERR; @@ -594,11 +662,11 @@ fatfs_unlink(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE3(TFS, "Unlink mte=%p dir=%p name='%s'", mte, dir, name); + CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name); init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); @@ -606,12 +674,11 @@ fatfs_unlink(cyg_mtab_entry *mte, if (err != ENOERR) return err; - + if (ds.node->refcnt > 0) return EBUSY; - // Delete node - err = fatfs_delete_file(disk, ds.node); + err = fatfs_delete_file(disk, &ds.node->dentry); if (err == ENOERR) fatfs_node_free(disk, ds.node); @@ -625,13 +692,13 @@ fatfs_unlink(cyg_mtab_entry *mte, static int fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE3(TFS, "Mkdir mte=%p dir=%p name='%s'", mte, dir, name); + CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name); - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); @@ -639,17 +706,20 @@ fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir { if (ds.last) { - fatfs_node_t node_data; + fatfs_dir_entry_t new_dir_dentry; // The entry does not exist, and it is the last element in - // the pathname, so we can create it here. + // the pathname, so we can create it here - err = fatfs_create_dir(disk, ds.dir, ds.name, - ds.namelen, &node_data); + err = fatfs_create_dir(disk, + &ds.dir->dentry, + ds.name, + ds.namelen, + &new_dir_dentry); if (err != ENOERR) return err; - fatfs_node_alloc(disk, &node_data); + fatfs_node_alloc(disk, &new_dir_dentry); return ENOERR; } @@ -669,27 +739,26 @@ fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir static int fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE3(TFS, "Rmdir mte=%p dir=%p name='%s'", mte, dir, name); + CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name); - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); if (err != ENOERR) return err; - // Check that this is actually a directory. - if (!S_ISDIR(ds.node->mode)) + if (!S_ISDIR(ds.node->dentry.mode)) return EPERM; if (ds.node->refcnt > 0) return EBUSY; - err = fatfs_delete_file(disk, ds.node); + err = fatfs_delete_file(disk, &ds.node->dentry); if (err == ENOERR) fatfs_node_free(disk, ds.node); @@ -707,11 +776,11 @@ fatfs_rename(cyg_mtab_entry *mte, cyg_dir dir2, const char *name2) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds1, ds2; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_dirsearch_t ds1, ds2; + int err; - CYG_TRACE5(TFS, "Rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", + CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", mte, dir1, name1, dir2, name2); init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1); @@ -720,44 +789,53 @@ fatfs_rename(cyg_mtab_entry *mte, if (err != ENOERR) return err; - // Protect the found nodes from being reused by the - // following search + // Protect the found nodes from being reused + // by the search for the ds2 dir/node pair fatfs_node_ref(disk, ds1.dir); fatfs_node_ref(disk, ds1.node); - init_dirsearch(&ds2, disk, (fatfs_node_t *)dir2, name2); + init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2); err = fatfs_find(&ds2); + // Check if the target name already exists if (err == ENOERR && ds2.last) { err = EEXIST; goto out; } + // Check if the target dir doesn't exist if (err == ENOENT && !ds2.last) goto out; + // Check if the target and the source are the same if (ds1.node == ds2.node) { err = ENOERR; goto out; } - err = fatfs_rename_file(disk, ds1.dir, ds1.node, ds2.dir, - ds2.name, ds2.namelen); + err = fatfs_rename_file(disk, + &ds1.dir->dentry, + &ds1.node->dentry, + &ds2.dir->dentry, + ds2.name, + ds2.namelen); + fatfs_node_rehash(disk, ds1.node); out: + // Unreference previousely protected nodes fatfs_node_unref(disk, ds1.dir); fatfs_node_unref(disk, ds1.node); if (err == ENOERR) { - ds1.dir->atime = - ds1.dir->mtime = - ds2.dir->atime = - ds2.dir->mtime = cyg_timestamp(); + ds1.dir->dentry.atime = + ds1.dir->dentry.mtime = + ds2.dir->dentry.atime = + ds2.dir->dentry.mtime = cyg_timestamp(); } return err; } @@ -774,7 +852,7 @@ fatfs_link(cyg_mtab_entry *mte, const char *name2, int type) { - CYG_TRACE6(TFS, "Link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d", + CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d", mte, dir1, name1, dir2, name2, type); // Linking not supported @@ -791,33 +869,39 @@ fatfs_opendir(cyg_mtab_entry *mte, const char *name, cyg_file *file) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_fd_t *fd; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE4(TFS, "Opendir mte=%p dir=%p name='%s' file=%p", + CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p", mte, dir, name, file); - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); - if (err != ENOERR) return err; - // Check it is really a directory. - if (!S_ISDIR(ds.node->mode)) + if (!S_ISDIR(ds.node->dentry.mode)) return ENOTDIR; - - // Make a reference to this dir node + + // Allocate file object private data and + // make a reference to this file node + + fd = alloc_fatfs_fd(disk, ds.node); + if (NULL == fd) + return EMFILE; + fatfs_node_ref(disk, ds.node); // Initialize the file object - file->f_type = CYG_FILE_TYPE_FILE; - file->f_ops = &fatfs_dirops; - file->f_data = (CYG_ADDRWORD)ds.node; - file->f_xops = 0; - file->f_offset = 0; + + file->f_type = CYG_FILE_TYPE_FILE; + file->f_ops = &fatfs_dirops; + file->f_data = (CYG_ADDRWORD) fd; + file->f_xops = 0; + file->f_offset = 0; return ENOERR; } @@ -832,33 +916,31 @@ fatfs_chdir(cyg_mtab_entry *mte, const char *name, cyg_dir *dir_out) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; - CYG_TRACE4(TFS, "Chdir mte=%p dir=%p dir_out=%p name=%d", + CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d", mte, dir, dir_out, name); if (dir_out != NULL) { - // This is a request to get a new directory pointer in - // *dir_out. + // This is a request to get a new directory pointer in *dir_out fatfs_dirsearch_t ds; - int err; + int err; - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); - if (err != ENOERR) return err; - // Check it is a directory - if (!S_ISDIR(ds.node->mode)) + if (!S_ISDIR(ds.node->dentry.mode)) return ENOTDIR; if (ds.node != disk->root) - fatfs_node_ref(disk, ds.node); - *dir_out = (cyg_dir)ds.node; + fatfs_node_ref(disk, ds.node); + + *dir_out = (cyg_dir) ds.node; } else { @@ -866,7 +948,7 @@ fatfs_chdir(cyg_mtab_entry *mte, // dir arguments are the current cdir setting and we should // forget this fact. - fatfs_node_t *node = (fatfs_node_t *)dir; + fatfs_node_t *node = (fatfs_node_t *) dir; if (node != disk->root) fatfs_node_unref(disk, node); @@ -885,31 +967,31 @@ fatfs_stat(cyg_mtab_entry *mte, const char *name, struct stat *buf) { - fatfs_disk_t *disk = (fatfs_disk_t *)mte->data; - fatfs_dirsearch_t ds; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) mte->data; + fatfs_dirsearch_t ds; + int err; - CYG_TRACE4(TFS, "Stat mte=%p dir=%p name='%s' buf=%p", + CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p", mte, dir, name, buf); - init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name); + init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); - if (err != ENOERR) return err; // Fill in the status - buf->st_mode = ds.node->mode; - buf->st_ino = (ino_t)ds.node->cluster; - buf->st_dev = 0; - buf->st_nlink = 1; - buf->st_uid = 0; - buf->st_gid = 0; - buf->st_size = ds.node->size; - buf->st_atime = ds.node->atime; - buf->st_mtime = ds.node->mtime; - buf->st_ctime = ds.node->ctime; + + buf->st_mode = ds.node->dentry.mode; + buf->st_ino = (ino_t) ds.node->dentry.cluster; + buf->st_dev = 0; + buf->st_nlink = 1; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = ds.node->dentry.size; + buf->st_atime = ds.node->dentry.atime; + buf->st_mtime = ds.node->dentry.mtime; + buf->st_ctime = ds.node->dentry.ctime; return ENOERR; } @@ -926,7 +1008,7 @@ fatfs_getinfo(cyg_mtab_entry *mte, void *buf, int len) { - CYG_TRACE6(TFS, "Getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d", + CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d", mte, dir, name, key, buf, len); return EINVAL; } @@ -943,7 +1025,7 @@ fatfs_setinfo(cyg_mtab_entry *mte, void *buf, int len) { - CYG_TRACE6(TFS, "Getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d", + CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d", mte, dir, name, key, buf, len); return EINVAL; } @@ -958,38 +1040,40 @@ fatfs_setinfo(cyg_mtab_entry *mte, static int fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) { - fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data; - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; - cyg_uint32 pos = fp->f_offset; - ssize_t resid = uio->uio_resid; - int i; + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + fatfs_node_t *node = fd->node; + cyg_uint32 pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + int i; - CYG_TRACE3(TFO, "Read fp=%p uio=%p pos=%d", fp, uio, pos); + CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos); // Loop over the io vectors until there are none left + for (i = 0; i < uio->uio_iovcnt; i++) { - cyg_iovec *iov = &uio->uio_iov[i]; - char *buf = (char *)iov->iov_base; - off_t len = iov->iov_len; + cyg_iovec *iov = &uio->uio_iov[i]; + char *buf = (char *) iov->iov_base; + off_t len = iov->iov_len; - // Loop over each vector filling it with data from the file. - while (len > 0 && pos < node->size) + // Loop over each vector filling it with data from the file + + while (len > 0 && pos < node->dentry.size) { cyg_uint32 l = len; - int err; + int err; // Adjust size to end of file if necessary - if (l > node->size-pos) - l = node->size-pos; + if (l > node->dentry.size-pos) + l = node->dentry.size-pos; - // Read data - err = fatfs_read_data(disk, node, buf, &l, pos); - + err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l); if (err != ENOERR) return err; // Update working vars + len -= l; buf += l; pos += l; @@ -997,11 +1081,12 @@ fatfs_fo_read(struct CYG_FILE_TAG *fp, s } } - // We successfully read some data, - // update the access time, file offset and transfer residue. - node->atime = cyg_timestamp(); - uio->uio_resid = resid; - fp->f_offset = (off_t)pos; + // We successfully read some data, update the access time, + // file offset and transfer residue + + node->dentry.atime = cyg_timestamp(); + uio->uio_resid = resid; + fp->f_offset = (off_t) pos; return ENOERR; } @@ -1013,49 +1098,53 @@ fatfs_fo_read(struct CYG_FILE_TAG *fp, s static int fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) { - fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data; - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; - cyg_uint32 pos = fp->f_offset; - ssize_t resid = uio->uio_resid; - int err = ENOERR; - int i; + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + fatfs_node_t *node = fd->node; + cyg_uint32 pos = fp->f_offset; + ssize_t resid = uio->uio_resid; + int err = ENOERR; + int i; - CYG_TRACE3(TFO, "Write fp=%p uio=%p pos=%d", fp, uio, pos); + CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos); // If the APPEND mode bit was supplied, force all writes to - // the end of the file. + // the end of the file if (fp->f_flag & CYG_FAPPEND) - pos = fp->f_offset = node->size; - - // Check that pos is within current file size, or at the very end. - if (pos < 0 || pos > node->size) + { + fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size); + pos = fp->f_offset = node->dentry.size; + } + + // Check that pos is within current file size, or at the very end + if (pos < 0 || pos > node->dentry.size) return EINVAL; - // Now loop over the iovecs until they are all done, or - // we get an error. + // Now loop over the iovecs until they are all done, or we get an error + for (i = 0; i < uio->uio_iovcnt; i++) { - cyg_iovec *iov = &uio->uio_iov[i]; - char *buf = (char *)iov->iov_base; - off_t len = iov->iov_len; + cyg_iovec *iov = &uio->uio_iov[i]; + char *buf = (char *) iov->iov_base; + off_t len = iov->iov_len; - // Loop over the vector writing it to the file until it has - // all been done. + // Loop over the vector writing it to the file + // until it has all been done + while (len > 0) { cyg_uint32 l = len; - // Write data - err = fatfs_write_data(disk, node, buf, &l, pos); + err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l); // Update working vars + len -= l; buf += l; pos += l; resid -= l; - // Stop writing if there is no more space in the file and - // indicate end of data. + // Stop writing if there is no more space in the file if (err == ENOSPC) break; @@ -1067,13 +1156,15 @@ fatfs_fo_write(struct CYG_FILE_TAG *fp, // We wrote some data successfully, update the modified and access // times of the node, increase its size appropriately, and update // the file offset and transfer residue. - node->mtime = - node->atime = cyg_timestamp(); - if (pos > node->size) - node->size = pos; + + node->dentry.mtime = + node->dentry.atime = cyg_timestamp(); + + if (pos > node->dentry.size) + node->dentry.size = pos; uio->uio_resid = resid; - fp->f_offset = (off_t)pos; + fp->f_offset = (off_t) pos; return err; } @@ -1085,39 +1176,45 @@ fatfs_fo_write(struct CYG_FILE_TAG *fp, static int fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence) { - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; - off_t pos = *apos; - - CYG_TRACE3(TFO, "Lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence); + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + off_t pos = *apos; + int err; + + CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence); switch (whence) { case SEEK_SET: - // Pos is already where we want to be. + // Pos is already where we want to be break; case SEEK_CUR: - // Add pos to current offset. + // Add pos to current offset pos += fp->f_offset; break; case SEEK_END: - // Add pos to file size. - pos += node->size; + // Add pos to file size + pos += fd->node->dentry.size; break; default: return EINVAL; } - // Check that pos is still within current file size, or at the - // very end. - if (pos < 0 || pos > node->size) + // Check that pos is still within current file size, + // or at the very end + if (pos < 0 || pos > fd->node->dentry.size) return EINVAL; - // All OK, set fp offset and return new position. - *apos = fp->f_offset = pos; + // All OK, set fp offset and return new position + + err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos); - CYG_TRACE2(TFO, "Lseek fp=%p new pos=%d", fp, *apos); + if (ENOERR == err) + *apos = fp->f_offset = pos; + + CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos); - return ENOERR; + return err; } // ------------------------------------------------------------------------- @@ -1127,7 +1224,7 @@ fatfs_fo_lseek(struct CYG_FILE_TAG *fp, static int fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data) { - CYG_TRACE3(TFO, "Ioctl fp=%p com=%x data=%x", fp, com, data); + CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data); return EINVAL; } @@ -1138,15 +1235,18 @@ fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, static int fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode) { - fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data; - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + fatfs_node_t *node = fd->node; + int err; - CYG_TRACE2(TFO, "Fsync fp=%p mode=%d", fp, mode); + CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode); - err = fatfs_write_file_attr(disk, node); + err = fatfs_write_dir_entry(disk, &node->dentry); + if (ENOERR == err) err = cyg_blib_sync(&disk->blib); + return err; } @@ -1157,16 +1257,23 @@ fatfs_fo_fsync(struct CYG_FILE_TAG *fp, static int fatfs_fo_close(struct CYG_FILE_TAG *fp) { - fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data; - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; - int err = ENOERR; + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + fatfs_node_t *node = fd->node; + int err = ENOERR; - CYG_TRACE1(TFO, "Close fp=%p", fp); + CYG_TRACE1(TFO, "close fp=%p", fp); + + // Write file attributes to disk, unreference + // the file node and free its private data if (node != disk->root) - err = fatfs_write_file_attr(disk, node); + err = fatfs_write_dir_entry(disk, &node->dentry); + fatfs_node_unref(disk, node); + free_fatfs_fd(fd); + return err; } @@ -1177,21 +1284,23 @@ fatfs_fo_close(struct CYG_FILE_TAG *fp) static int fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf) { - fatfs_node_t *node = (fatfs_node_t *)fp->f_data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + fatfs_node_t *node = fd->node; - CYG_TRACE2(TFO, "Fstat fp=%p buf=%p", fp, buf); + CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf); // Fill in the status - buf->st_mode = node->mode; - buf->st_ino = (ino_t)node->cluster; + + buf->st_mode = node->dentry.mode; + buf->st_ino = (ino_t) node->dentry.cluster; buf->st_dev = 0; buf->st_nlink = 1; buf->st_uid = 0; buf->st_gid = 0; - buf->st_size = node->size; - buf->st_atime = node->atime; - buf->st_mtime = node->mtime; - buf->st_ctime = node->ctime; + buf->st_size = node->dentry.size; + buf->st_atime = node->dentry.atime; + buf->st_mtime = node->dentry.mtime; + buf->st_ctime = node->dentry.ctime; return ENOERR; } @@ -1203,7 +1312,7 @@ fatfs_fo_fstat(struct CYG_FILE_TAG *fp, static int fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len) { - CYG_TRACE4(TFO, "Getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len); + CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len); return EINVAL; } @@ -1214,7 +1323,7 @@ fatfs_fo_getinfo(struct CYG_FILE_TAG *fp static int fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len) { - CYG_TRACE4(TFO, "Setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len); + CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len); return EINVAL; } @@ -1228,30 +1337,29 @@ fatfs_fo_setinfo(struct CYG_FILE_TAG *fp static int fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) { - fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data; - fatfs_node_t *dir = (fatfs_node_t *)fp->f_data; - struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base; - cyg_uint32 pos = fp->f_offset; - char *nbuf = ent->d_name; - off_t len = uio->uio_iov[0].iov_len; - fatfs_node_t node; - int err; + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base; + char *nbuf = ent->d_name; + off_t len = uio->uio_iov[0].iov_len; + fatfs_dir_entry_t dentry; + int err; - CYG_TRACE3(TFO, "Dirread fp=%p uio=%p pos=%d", fp, uio, pos); + CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset); if (len < sizeof(struct dirent)) return EINVAL; - err = fatfs_get_dir_entry_node(disk, dir, &pos, &node); + err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry); if (err != ENOERR) return (err == EEOF ? ENOERR : err); - strcpy(nbuf, node.filename); + strcpy(nbuf, dentry.filename); - dir->atime = cyg_timestamp(); - uio->uio_resid -= sizeof(struct dirent); - fp->f_offset = (off_t)(pos + 1); + fd->node->dentry.atime = cyg_timestamp(); + uio->uio_resid -= sizeof(struct dirent); + fp->f_offset++; return ENOERR; } @@ -1263,15 +1371,23 @@ fatfs_fo_dirread(struct CYG_FILE_TAG *fp static int fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence) { - CYG_TRACE2(TFO, "Dirlseek fp=%p whence=%d", fp, whence); + fatfs_disk_t *disk = (fatfs_disk_t *) fp->f_mte->data; + fatfs_fd_t *fd = (fatfs_fd_t *) fp->f_data; + int err; + + CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence); // Only allow SEEK_SET to zero if (whence != SEEK_SET || *pos != 0) return EINVAL; + + err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0); + + if (ENOERR == err) + *pos = fp->f_offset = 0; - *pos = fp->f_offset = 0; - return ENOERR; + return err; } // ------------------------------------------------------------------------- diff --git a/packages/fs/fat/current/src/fatfs.h b/packages/fs/fat/current/src/fatfs.h --- a/packages/fs/fat/current/src/fatfs.h +++ b/packages/fs/fat/current/src/fatfs.h @@ -10,7 +10,7 @@ //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2003 Savin Zlobec +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -40,7 +40,7 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): savin +// Author(s): Savin Zlobec // Date: 2003-06-29 // //####DESCRIPTIONEND#### @@ -48,9 +48,10 @@ //========================================================================== #include -#include + #include #include +#include #include #include @@ -63,15 +64,11 @@ #include #include -#include - // -------------------------------------------------------------------------- #define FATFS_HASH_TABLE_SIZE CYGNUM_FS_FAT_NODE_HASH_TABLE_SIZE -#define FATFS_NODE_ALLOC_THRESHOLD CYGNUM_FS_FAT_NODE_ALLOC_THRESHOLD - -#define FATFS_FAT_TABLE_CACHE_INCREMENT CYGNUM_FS_FAT_FAT_TABLE_CACHE_INCREMENT +#define FATFS_NODE_POOL_SIZE CYGNUM_FS_FAT_NODE_POOL_SIZE #ifdef CYGDBG_FS_FAT_NODE_CACHE_EXTRA_CHECKS # define FATFS_NODE_CACHE_EXTRA_CHECKS 1 @@ -82,12 +79,6 @@ // Node cache tracing support //#define FATFS_TRACE_NODE_CACHE 1 -// FAT table cache tracing support -//#define FATFS_TRACE_FAT_TABLE_CACHE 1 - -// FAT table operations tracing support -//#define FATFS_TRACE_FAT_TABLE 1 - // FAT dir entry operations tracing support //#define FATFS_TRACE_DIR_ENTRY 1 @@ -108,7 +99,8 @@ typedef enum fatfs_type_e { FATFS_FAT12 = 0, - FATFS_FAT16 + FATFS_FAT16, + FATFS_FAT32 } fatfs_type_t; typedef struct fatfs_data_pos_s @@ -120,32 +112,28 @@ typedef struct fatfs_data_pos_s cyg_uint32 cluster_pos; // Position inside cluster } fatfs_data_pos_t; -typedef struct fatfs_tcache_s +typedef struct fatfs_dir_entry_s { - cyg_uint32 *clusters; // Cached clusters array - cyg_uint32 size; // Number of cached clusters in array - cyg_uint32 max_size; // Size of array (allocated space) -} fatfs_tcache_t; + char filename[12+1]; // File name + mode_t mode; // Node type + size_t size; // Size of file in bytes + time_t ctime; // Creation timestamp + time_t atime; // Last access timestamp + time_t mtime; // Last write timestamp + cyg_uint8 priv_data; // Private data + cyg_uint32 cluster; // First cluster number + cyg_uint32 parent_cluster; // First cluster of parent dentry + fatfs_data_pos_t disk_pos; // Position of dir entry on disk +} fatfs_dir_entry_t; typedef struct fatfs_node_s { - char filename[12+1]; // File name - mode_t mode; // Node type - cyg_ucount32 refcnt; // Open file/current dir references - size_t size; // Size of file in bytes - time_t ctime; // Creation timestamp - time_t atime; // Last access timestamp - time_t mtime; // Last write timestamp - cyg_uint8 priv_data; // Private data - cyg_uint32 cluster; // First cluster number - cyg_uint32 parent_cluster; // First cluster of parent dentry - fatfs_data_pos_t dentry_pos; // Position of node's dir entry on disk + fatfs_dir_entry_t dentry; // Dir entry data + cyg_ucount32 refcnt; // Open file/current dir references - struct fatfs_node_s *list_prev; // Next node in list - struct fatfs_node_s *list_next; // Prev node in list - struct fatfs_node_s *hash_next; // Next node in hash - - fatfs_tcache_t tcache; // Node FAT table clusters cache + struct fatfs_node_s *list_prev; // Next node in list + struct fatfs_node_s *list_next; // Prev node in list + struct fatfs_node_s *hash_next; // Next node in hash } fatfs_node_t; typedef struct fatfs_hash_table_s @@ -164,84 +152,102 @@ typedef struct fatfs_node_list_s typedef struct fatfs_disk_s { - cyg_uint32 sector_size; // Sector size in bytes - cyg_uint32 sector_size_log2; // Sector size log2 - cyg_uint32 cluster_size; // Cluster size in bytes - cyg_uint32 cluster_size_log2; // Cluster size log2 - cyg_uint32 fat_tbl_pos; // Position of the first FAT table - cyg_uint32 fat_tbl_size; // FAT table size in bytes - cyg_uint32 fat_tbl_nents; // Number of entries in FAT table - cyg_uint32 fat_tbls_num; // Number of FAT tables - cyg_uint32 fat_root_dir_pos; // Position of the root dir - cyg_uint32 fat_root_dir_size; // Root dir size in bytes - cyg_uint32 fat_root_dir_nents; // Max number of entries in root dir - cyg_uint32 fat_data_pos; // Position of data area - fatfs_type_t fat_type; // Type of FAT - 12 or 16 + cyg_uint32 sector_size; // Sector size in bytes + cyg_uint32 sector_size_log2; // Sector size log2 + cyg_uint32 cluster_size; // Cluster size in bytes + cyg_uint32 cluster_size_log2; // Cluster size log2 + cyg_uint32 fat_tbl_pos; // Position of the first FAT table + cyg_uint32 fat_tbl_size; // FAT table size in bytes + cyg_uint32 fat_tbl_nents; // Number of entries in FAT table + cyg_uint32 fat_tbls_num; // Number of FAT tables + cyg_uint32 fat_root_dir_pos; // Position of the root dir + cyg_uint32 fat_root_dir_size; // Root dir size in bytes + cyg_uint32 fat_root_dir_nents; // Max number of entries in root dir + cyg_uint32 fat_root_dir_cluster; // Cluster number of root dir (FAT32) + cyg_uint32 fat_data_pos; // Position of data area + fatfs_type_t fat_type; // Type of FAT - 12, 16 or 32 - cyg_io_handle_t dev_h; // Disk device handle - fatfs_node_t *root; // Root dir node + cyg_io_handle_t dev_h; // Disk device handle + fatfs_node_t *root; // Root dir node - cyg_uint8 *tcache_mem; // FAT table cache memory base - cyg_handle_t tcache_mpool_h; // FAT table cache memory pool handle - cyg_mempool_var tcache_mpool; // FAT table cache memory pool struct + cyg_uint8 *bcache_mem; // Block cache memory base + cyg_blib_t blib; // Block cache and access library instance - cyg_uint8 *bcache_mem; // Block cache memory base - cyg_blib_t blib; // Block cache and access library instance - - fatfs_node_list_t live_nlist; // List of nodes with refcnt > 0 - fatfs_node_list_t dead_nlist; // List of nodes with refcnt == 0 - fatfs_hash_table_t node_hash; // Hash of nodes in live and dead lists + fatfs_node_t node_pool_base[FATFS_NODE_POOL_SIZE]; // Node pool base + fatfs_node_t *node_pool[FATFS_NODE_POOL_SIZE]; // Node pool + cyg_uint32 node_pool_free_cnt; // Node pool free cnt + + fatfs_node_list_t live_nlist; // List of nodes with refcnt > 0 + fatfs_node_list_t dead_nlist; // List of nodes with refcnt == 0 + fatfs_hash_table_t node_hash; // Hash of nodes in live and dead lists } fatfs_disk_t; // -------------------------------------------------------------------------- -int fatfs_get_disk_info(fatfs_disk_t *disk); +int fatfs_init(fatfs_disk_t *disk); + +void fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry); + +bool fatfs_is_root_dir_dentry(fatfs_dir_entry_t *dentry); -void fatfs_get_root_node(fatfs_disk_t *disk, fatfs_node_t *root); +int fatfs_get_disk_usage(fatfs_disk_t *disk, + cyg_uint32 *total_clusters, + cyg_uint32 *free_clusters); -bool fatfs_is_node_root_node(fatfs_node_t *node); +int fatfs_initpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos); -int fatfs_get_dir_entry_node(fatfs_disk_t *disk, - fatfs_node_t *dir, - cyg_uint32 *pos, - fatfs_node_t *node); +int fatfs_setpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + cyg_uint32 offset); -int fatfs_write_file_attr(fatfs_disk_t *disk, fatfs_node_t *node); +cyg_uint32 fatfs_getpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos); -int fatfs_delete_file(fatfs_disk_t *disk, fatfs_node_t *node); +int fatfs_read_dir_entry(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + fatfs_data_pos_t *pos, + fatfs_dir_entry_t *dentry); -int fatfs_create_file(fatfs_disk_t *disk, - fatfs_node_t *dir, - const char *name, - int namelen, - fatfs_node_t *node); +int fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry); + +int fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file); -int fatfs_create_dir(fatfs_disk_t *disk, - fatfs_node_t *dir, - const char *name, - int namelen, - fatfs_node_t *node); +int fatfs_create_file(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + const char *name, + int namelen, + fatfs_dir_entry_t *dentry); -int fatfs_trunc_file(fatfs_disk_t *disk, fatfs_node_t *node); +int fatfs_create_dir(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + const char *name, + int namelen, + fatfs_dir_entry_t *dentry); + +int fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file); -int fatfs_rename_file(fatfs_disk_t *disk, - fatfs_node_t *dir1, - fatfs_node_t *node, - fatfs_node_t *dir2, - const char *name, - int namelen); +int fatfs_rename_file(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir1, + fatfs_dir_entry_t *target, + fatfs_dir_entry_t *dir2, + const char *name, + int namelen); -int fatfs_read_data(fatfs_disk_t *disk, - fatfs_node_t *node, - void *data, - cyg_uint32 *len, - cyg_uint32 off); +int fatfs_read_data(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + void *data, + cyg_uint32 *len); -int fatfs_write_data(fatfs_disk_t *disk, - fatfs_node_t *node, - void *data, - cyg_uint32 *len, - cyg_uint32 off); +int fatfs_write_data(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + void *data, + cyg_uint32 *len); // -------------------------------------------------------------------------- @@ -249,7 +255,7 @@ void fatfs_node_cache_init(fatfs_disk_t void fatfs_node_cache_flush(fatfs_disk_t *disk); -fatfs_node_t *fatfs_node_alloc(fatfs_disk_t *disk, fatfs_node_t *node_data); +fatfs_node_t *fatfs_node_alloc(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry); void fatfs_node_ref(fatfs_disk_t *disk, fatfs_node_t *node); @@ -270,33 +276,6 @@ int fatfs_get_live_node_count(fatfs_dis int fatfs_get_dead_node_count(fatfs_disk_t *disk); -void fatfs_node_flush_dead_tcache(fatfs_disk_t *disk); - -// -------------------------------------------------------------------------- - -int fatfs_tcache_create(fatfs_disk_t *disk, cyg_uint32 mem_size); - -void fatfs_tcache_delete(fatfs_disk_t *disk); - -void fatfs_tcache_init(fatfs_disk_t *disk, fatfs_tcache_t *tcache); - -void fatfs_tcache_flush(fatfs_disk_t *disk, fatfs_tcache_t *tcache); - -bool fatfs_tcache_get(fatfs_disk_t *disk, - fatfs_tcache_t *tcache, - cyg_uint32 num, - cyg_uint32 *cluster); - -bool fatfs_tcache_get_last(fatfs_disk_t *disk, - fatfs_tcache_t *tcache, - cyg_uint32 *num, - cyg_uint32 *cluster); - -bool fatfs_tcache_set(fatfs_disk_t *disk, - fatfs_tcache_t *tcache, - cyg_uint32 num, - cyg_uint32 cluster); - // -------------------------------------------------------------------------- // Support routines // These enable the definition of local versions of certain routines diff --git a/packages/fs/fat/current/src/fatfs_ncache.c b/packages/fs/fat/current/src/fatfs_ncache.c --- a/packages/fs/fat/current/src/fatfs_ncache.c +++ b/packages/fs/fat/current/src/fatfs_ncache.c @@ -8,7 +8,7 @@ //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2003 Savin Zlobec +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -38,7 +38,7 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): savin +// Author(s): Savin Zlobec // Date: 2003-06-26 // //####DESCRIPTIONEND#### @@ -73,10 +73,8 @@ # define TNC 0 #endif -// This defines how many nodes should always be kept in -// dead list regardless of node allocation treshold - it -// should always be >= 2 or the file finding code may not -// work correctly! +// This defines how many nodes should always be kept in dead list - +// it should be >= 2 or the file finding code may not work correctly! #define DLIST_KEEP_NUM 2 //========================================================================== @@ -85,7 +83,7 @@ static void node_list_init(fatfs_node_list_t *list) { - list->size = 0; + list->size = 0; list->first = list->last = NULL; } @@ -267,10 +265,6 @@ node_lists_check(fatfs_disk_t* disk) { node_list_check(&disk->live_nlist, 1, 99999); node_list_check(&disk->dead_nlist, 0, 0); - - if ((disk->live_nlist.size + disk->dead_nlist.size) > - FATFS_NODE_ALLOC_THRESHOLD) - CYG_ASSERTC(disk->dead_nlist.size <= DLIST_KEEP_NUM); } #endif // USE_XCHECKS @@ -305,9 +299,10 @@ node_hash_add(fatfs_hash_table_t *tbl, f unsigned int hval; // Calculate hash of given node filename - hval = hash_fn(node->filename, strlen(node->filename)) % tbl->size; + hval = hash_fn(node->dentry.filename, + strlen(node->dentry.filename)) % tbl->size; - CYG_TRACE2(TNC, "name='%s' hval=%d", node->filename, hval); + CYG_TRACE2(TNC, "name='%s' hval=%d", node->dentry.filename, hval); if (tbl->nodes[hval] == NULL) { @@ -331,7 +326,7 @@ node_hash_add(fatfs_hash_table_t *tbl, f if (lnode == node) return false; - if (strcasecmp(lnode->filename, node->filename) > 0) + if (strcasecmp(lnode->dentry.filename, node->dentry.filename) > 0) { if (pnode != NULL) pnode->hash_next = node; // Insert in the middle @@ -359,7 +354,7 @@ node_hash_find(fatfs_hash_table_t *tbl, unsigned int namelen, unsigned int parent_cluster) { - unsigned int hval; + unsigned int hval; fatfs_node_t *node; // Calculate hash of name and get the first node in slot @@ -375,10 +370,10 @@ node_hash_find(fatfs_hash_table_t *tbl, // First compare the parent cluster number and // check filename length since it is faster than // comparing filenames - if (parent_cluster == node->parent_cluster && - '\0' == node->filename[namelen]) + if (parent_cluster == node->dentry.parent_cluster && + '\0' == node->dentry.filename[namelen]) { - int i = strncasecmp(node->filename, name, namelen); + int i = strncasecmp(node->dentry.filename, name, namelen); if (i == 0) return node; @@ -435,7 +430,8 @@ node_hash_remove(fatfs_hash_table_t *tbl fatfs_node_t *lnode, *pnode; // Calculate hash of name and get the first node in slot - hval = hash_fn(node->filename, strlen(node->filename)) % tbl->size; + hval = hash_fn(node->dentry.filename, + strlen(node->dentry.filename)) % tbl->size; lnode = tbl->nodes[hval]; // Now find the node in list and remove it @@ -480,9 +476,9 @@ node_hash_check(fatfs_hash_table_t *tbl) { if (pnode != NULL) { - int c = strcasecmp(pnode->filename, lnode->filename); + int c = strcasecmp(pnode->dentry.filename, lnode->dentry.filename); CYG_ASSERT(c <= 0, "hash table not sorted"); - CYG_ASSERT(pnode->parent_cluster != lnode->parent_cluster || + CYG_ASSERT(pnode->dentry.parent_cluster != lnode->dentry.parent_cluster || 0 != c, "duplicated node in hash table"); } n++; @@ -504,9 +500,9 @@ node_hash_not_found_check(fatfs_disk_t * node = node_list_get_head(&disk->live_nlist); while (NULL != node) { - if (node->parent_cluster == parent_cluster && - namelen == strlen(node->filename) && - 0 == strncasecmp(name, node->filename, namelen)) + if (node->dentry.parent_cluster == parent_cluster && + namelen == strlen(node->dentry.filename) && + 0 == strncasecmp(name, node->dentry.filename, namelen)) CYG_ASSERT(false, "node not found in hash, " "but exists in live list"); node = node_list_get_next(node); @@ -515,9 +511,9 @@ node_hash_not_found_check(fatfs_disk_t * node = node_list_get_head(&disk->dead_nlist); while (NULL != node) { - if (node->parent_cluster == parent_cluster && - namelen == strlen(node->filename) && - 0 == strncasecmp(name, node->filename, namelen)) + if (node->dentry.parent_cluster == parent_cluster && + namelen == strlen(node->dentry.filename) && + 0 == strncasecmp(name, node->dentry.filename, namelen)) CYG_ASSERT(false, "node not found in hash, " "but exists in dead list"); node = node_list_get_next(node); @@ -531,16 +527,16 @@ node_hash_found_check(fatfs_disk_t *disk unsigned int parent_cluster, fatfs_node_t* node) { - fatfs_node_t* n; + fatfs_node_t *n; n = node_list_get_head(&disk->live_nlist); while (NULL != n) { if (n == node) { - if (node->parent_cluster != parent_cluster || - namelen != strlen(node->filename) || - 0 != strncasecmp(name, node->filename, namelen)) + if (node->dentry.parent_cluster != parent_cluster || + namelen != strlen(node->dentry.filename) || + 0 != strncasecmp(name, node->dentry.filename, namelen)) CYG_ASSERT(false, "node_hash_find returned wrong node"); return; } @@ -552,9 +548,9 @@ node_hash_found_check(fatfs_disk_t *disk { if (n == node) { - if (node->parent_cluster != parent_cluster || - namelen != strlen(node->filename) || - 0 != strncasecmp(name, node->filename, namelen)) + if (node->dentry.parent_cluster != parent_cluster || + namelen != strlen(node->dentry.filename) || + 0 != strncasecmp(name, node->dentry.filename, namelen)) CYG_ASSERT(false, "node_hash_find returned wrong node"); return; } @@ -592,6 +588,37 @@ node_hash_found_check(fatfs_disk_t *disk #endif // not USE_XCHECKS //========================================================================== +// Node pool allocation functions + +static void +node_pool_init(fatfs_disk_t *disk) +{ + int i; + + for (i = 0; i < FATFS_NODE_POOL_SIZE; i++) + disk->node_pool[i] = &disk->node_pool_base[i]; + + disk->node_pool_free_cnt = i; +} + +static fatfs_node_t * +node_pool_alloc(fatfs_disk_t *disk) +{ + fatfs_node_t *node = NULL; + + if (disk->node_pool_free_cnt > 0) + node = disk->node_pool[--disk->node_pool_free_cnt]; + + return node; +} + +static void +node_pool_free(fatfs_disk_t *disk, fatfs_node_t *node) +{ + disk->node_pool[disk->node_pool_free_cnt++] = node; +} + +//========================================================================== //========================================================================== // Exported functions @@ -607,7 +634,8 @@ fatfs_node_cache_init(fatfs_disk_t *disk node_list_init(&disk->live_nlist); node_list_init(&disk->dead_nlist); node_hash_init(&disk->node_hash); - + node_pool_init(disk); + SANITY_CHECK(); } @@ -628,8 +656,7 @@ fatfs_node_cache_flush(fatfs_disk_t *dis node_list_remove(&disk->live_nlist, node); if (!node_hash_remove(&disk->node_hash, node)) CYG_ASSERT(false, "Node not in hash"); - fatfs_tcache_flush(disk, &node->tcache); - free(node); + node_pool_free(disk, node); node = next_node; } @@ -641,8 +668,7 @@ fatfs_node_cache_flush(fatfs_disk_t *dis node_list_remove(&disk->dead_nlist, node); if (!node_hash_remove(&disk->node_hash, node)) CYG_ASSERT(false, "Node not in hash"); - fatfs_tcache_flush(disk, &node->tcache); - free(node); + node_pool_free(disk, node); node = next_node; } @@ -654,62 +680,45 @@ fatfs_node_cache_flush(fatfs_disk_t *dis // Allocates a new node. fatfs_node_t* -fatfs_node_alloc(fatfs_disk_t *disk, fatfs_node_t *node_data) +fatfs_node_alloc(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry) { - int lsize, dsize; - fatfs_node_t *anode; + fatfs_node_t *node; CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node_data); + CYG_CHECK_DATA_PTRC(dentry); - lsize = node_list_get_size(&disk->live_nlist); - dsize = node_list_get_size(&disk->dead_nlist); - - CYG_TRACE2(TNC, "lsize=%d dsize=%d", lsize, dsize); - - // Allocate space for a new node if we haven't reached the - // allocation treshold or if we can't reuse dead nodes space - if (dsize > DLIST_KEEP_NUM && (lsize + dsize) >= - (FATFS_NODE_ALLOC_THRESHOLD - 1)) - anode = NULL; - else - anode = (fatfs_node_t *)malloc(sizeof(fatfs_node_t)); + node = node_pool_alloc(disk); - if (NULL == anode) + if (NULL == node) { - CYG_TRACE0(TNC, "getting node from dead list"); + CYG_TRACE2(TNC, "getting node from dead list (size=%d keep=%d)", + node_list_get_size(&disk->dead_nlist), DLIST_KEEP_NUM); - if (dsize <= DLIST_KEEP_NUM) + if (node_list_get_size(&disk->dead_nlist) <= DLIST_KEEP_NUM) return NULL; - anode = node_list_tail_get(&disk->dead_nlist); - if (NULL == anode) + node = node_list_tail_get(&disk->dead_nlist); + if (NULL == node) return NULL; - CYG_TRACE1(TNC, "recycling node='%s'", anode->filename); + CYG_TRACE1(TNC, "recycling node='%s'", node->dentry.filename); - // Flush FAT table cache - fatfs_tcache_flush(disk, &anode->tcache); - - node_list_remove(&disk->dead_nlist, anode); - if (!node_hash_remove(&disk->node_hash, anode)) - CYG_ASSERT(false, "Node not in hash"); + node_list_remove(&disk->dead_nlist, node); + if (!node_hash_remove(&disk->node_hash, node)) + CYG_ASSERT(false, "node not in hash"); } // Init new node - *anode = *node_data; - anode->refcnt = 0; + node->dentry = *dentry; + node->refcnt = 0; - // Init FAT table cache - fatfs_tcache_init(disk, &anode->tcache); - - node_list_head_add(&disk->dead_nlist, anode); - if (!node_hash_add(&disk->node_hash, anode)) - CYG_ASSERT(false, "Node already in hash"); + node_list_head_add(&disk->dead_nlist, node); + if (!node_hash_add(&disk->node_hash, node)) + CYG_ASSERT(false, "node already in hash"); SANITY_CHECK(); - return anode; + return node; } //-------------------------------------------------------------------------- @@ -722,7 +731,7 @@ fatfs_node_touch(fatfs_disk_t *disk, fat { CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(node); - CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt); + CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt); if (node->refcnt == 0) { @@ -749,14 +758,15 @@ fatfs_node_ref(fatfs_disk_t *disk, fatfs { CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(node); - CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt); + CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt); - // Increase node reference counter node->refcnt++; if (1 == node->refcnt) { - CYG_TRACE1(TNC, "node='%s' to live list", node->filename); // First reference - move node from dead to live list + + CYG_TRACE1(TNC, "node='%s' to live list", node->dentry.filename); + node_list_remove(&disk->dead_nlist, node); node_list_head_add(&disk->live_nlist, node); } @@ -770,41 +780,24 @@ fatfs_node_ref(fatfs_disk_t *disk, fatfs // If the reference goes from 1 to 0, than the node // is moved from live list to top of dead list. // (When reusing dead node it is always taken from the bottom of list) -// If we are over the allocation treshold the bottom node of -// dead list if freed. void fatfs_node_unref(fatfs_disk_t *disk, fatfs_node_t *node) { CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(node); - CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt); + CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt); CYG_ASSERT(node->refcnt > 0, "node->refcnt <= 0"); node->refcnt--; - if (node->refcnt == 0) + if (0 == node->refcnt) { // No more references - move node from live to dead list - CYG_TRACE1(TNC, "node='%s' to dead list", node->filename); + + CYG_TRACE1(TNC, "node='%s' to dead list", node->dentry.filename); + node_list_remove(&disk->live_nlist, node); node_list_head_add(&disk->dead_nlist, node); - - // Check the number of allocated nodes and free - // the last node in dead list if we are over - // the treshold and we have enough dead nodes - { - int lsize = node_list_get_size(&disk->live_nlist); - int dsize = node_list_get_size(&disk->dead_nlist); - - if (dsize > DLIST_KEEP_NUM && - (lsize + dsize) >= FATFS_NODE_ALLOC_THRESHOLD) - { - fatfs_node_t *n = node_list_get_tail(&disk->dead_nlist); - CYG_TRACE1(TNC, "freeing node='%s' - to satisfy " - "alloc treshold", n->filename); - fatfs_node_free(disk, n); - } - } } SANITY_CHECK(); @@ -820,18 +813,17 @@ fatfs_node_free(fatfs_disk_t *disk, fatf { CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(node); - CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt); + CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt); CYG_ASSERTC(node->refcnt == 0); CYG_ASSERTC(node != disk->root); - // Flush FAT table cache - fatfs_tcache_flush(disk, &node->tcache); + // Remove from dead list, from hash and free ptr - // Remove from dead list and from hash and free ptr node_list_remove(&disk->dead_nlist, node); if (!node_hash_remove(&disk->node_hash, node)) - CYG_ASSERT(false, "node not in hash"); - free(node); + CYG_ASSERT(false, "node not in hash"); + + node_pool_free(disk, node); SANITY_CHECK(); } @@ -847,10 +839,10 @@ fatfs_node_rehash(fatfs_disk_t *disk, fa CYG_CHECK_DATA_PTRC(node); if (!node_hash_remove_keyless(&disk->node_hash, node)) - CYG_ASSERT(false, "Node not in hash"); + CYG_ASSERT(false, "node not in hash"); if (!node_hash_add(&disk->node_hash, node)) - CYG_ASSERT(false, "Node already in hash"); + CYG_ASSERT(false, "node already in hash"); SANITY_CHECK(); } @@ -901,26 +893,5 @@ fatfs_get_dead_node_count(fatfs_disk_t * return node_list_get_size(&disk->dead_nlist); } -//-------------------------------------------------------------------------- -// fatfs_node_flush_dead_tcache() -// Flushes FAT table cache of dead nodes. - -void -fatfs_node_flush_dead_tcache(fatfs_disk_t *disk) -{ - fatfs_node_t *node; - - CYG_CHECK_DATA_PTRC(disk); - - node = node_list_get_tail(&disk->dead_nlist); - - while (NULL != node) - { - CYG_TRACE1(TNC, "node='%s'", node->filename); - fatfs_tcache_flush(disk, &node->tcache); - node = node_list_get_prev(node); - } -} - // ------------------------------------------------------------------------- // EOF fatfs_ncache.c diff --git a/packages/fs/fat/current/src/fatfs_supp.c b/packages/fs/fat/current/src/fatfs_supp.c --- a/packages/fs/fat/current/src/fatfs_supp.c +++ b/packages/fs/fat/current/src/fatfs_supp.c @@ -8,7 +8,7 @@ //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2003 Savin Zlobec +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -38,7 +38,7 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): savin +// Author(s): Savin Zlobec // Date: 2003-06-30 // //####DESCRIPTIONEND#### @@ -47,12 +47,14 @@ #include #include + #include #include #include #include #include #include + #include #include @@ -82,10 +84,10 @@ #define DENTRY_IS_ARCHIVE(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_ARCHIVE) #define DENTRY_IS_DELETED(_dentry_) \ - (0xE5 == (unsigned char)((_dentry_)->name[0])) + (0xE5 == (cyg_uint8)((_dentry_)->name[0])) #define DENTRY_IS_ZERO(_dentry_) \ - (0x00 == (unsigned char)((_dentry_)->name[0])) + (0x00 == (cyg_uint8)((_dentry_)->name[0])) // ------------------------------------------------------------------------- // FAT disk data access macros @@ -140,7 +142,7 @@ // ------------------------------------------------------------------------- // FAT table structures size -#define DENTRY_SIZE 0x20 // Dir entry size +#define DENTRY_SIZE 0x20 // Dir entry size // ------------------------------------------------------------------------- // Time & date defines @@ -150,12 +152,6 @@ // ------------------------------------------------------------------------- // Code tracing defines -#ifdef FATFS_TRACE_FAT_TABLE -# define TFT 1 -#else -# define TFT 0 -#endif - #ifdef FATFS_TRACE_DIR_ENTRY # define TDE 1 #else @@ -174,15 +170,6 @@ # define TDO 0 #endif -// ------------------------------------------------------------------------- -// FAT table entry type strings - -#if TFT -static const char *tentry_type_name[5] = { - "REGULAR", "FREE", "LAST", "RESERVED", "BAD" -}; -#endif - //========================================================================== // FAT structures @@ -195,7 +182,7 @@ typedef struct fat_boot_record_s // cyg_uint8 jump0; // + NOP char oem_name[8+1]; // 03h : OEM name cyg_uint16 bytes_per_sec; // 0Bh : cyg_bytes per sector - cyg_uint8 sec_per_clust; // 0Dh : Sectors per cluster + cyg_uint8 sec_per_clu; // 0Dh : Sectors per cluster cyg_uint16 res_sec_num; // 0Eh : Number of reserved sectors cyg_uint8 fat_tbls_num; // 10h : Number of copies of fat cyg_uint16 max_root_dents; // 11h : Maximum number of root dir entries @@ -206,36 +193,48 @@ typedef struct fat_boot_record_s cyg_uint16 heads_num; // 1Ah : Number of heads cyg_uint32 hsec_num; // 1Ch : Number of hidden sectors cyg_uint32 sec_num; // 20h : Number of sectors in partition - cyg_uint16 ldrv_num; // 24h : Logical drive number of partition - cyg_uint8 ext_sig; // 26h : Extended signature - cyg_uint32 ser_num; // 27h : Serial number of partition - char vol_name[11+1]; // 2Bh : Volume name of partition - char fat_name[8+1]; // 36h : FAT name -// unsigned char exe_code[448]; // 3Eh : Executable code - unsigned char exe_marker[2]; // 1FEh: Executable marker (55h AAh) + cyg_uint8 exe_marker[2]; // 1FEh: Executable marker (55h AAh) + +// FAT32 specific fields + + cyg_uint32 sec_per_fat_32; // 24h : Sectors per FAT + cyg_uint16 ext_flags; // 28h : Flags + cyg_uint16 fs_ver; // 2Ah : FS version + cyg_uint32 root_cluster; // 2Ch : Root dir cluster + cyg_uint16 fs_info_sec; // 30h : Sector number of FSINFO structure + cyg_uint16 bk_boot_sec; // 32h : Sector number of backup boot record +// cyg_uint8 reserved[12]; // 34h : Reserved + +// Fields with different locations on FAT12/16 and FAT32 + + cyg_uint8 drv_num; // 24h (40h) : Drive number of partition +// cyg_uint8 reserved1; // 25h (41h) : Reserved 1 + cyg_uint8 ext_sig; // 26h (42h) : Extended signature + cyg_uint32 ser_num; // 27h (43h) : Serial number of partition + char vol_name[11+1]; // 2Bh (47h) : Volume name of partition + char fat_name[8+1]; // 36h (52h) : FAT name + } fat_boot_record_t; // ------------------------------------------------------------------------- // FAT dir entry structure -typedef struct fat_dir_entry_s +typedef struct fat_raw_dir_entry_s { - char name[8+1]; // 00h : Name - char ext[3+1]; // 08h : Extension - cyg_uint8 attr; // 0Bh : Attribute - cyg_uint8 nt_reserved; // 0Ch : Win NT Reserved field - cyg_uint8 crt_sec_100; // 0Dh : Creation time ms stamp 0 - 199 - cyg_uint16 crt_time; // 0Eh : Creation time - cyg_uint16 crt_date; // 10h : Creation date - cyg_uint16 acc_date; // 12h : Last access date - cyg_uint16 cluster_HI; // 14h : Starting cluster HI WORD (FAT32) - cyg_uint16 wrt_time; // 16h : Time - cyg_uint16 wrt_date; // 18h : Date - cyg_uint16 cluster; // 1Ah : Starting cluster - cyg_uint32 size; // 1Ch : Size of the file - - fatfs_data_pos_t pos; // Positon on disk -} fat_dir_entry_t; + char name[8+1]; // 00h : Name + char ext[3+1]; // 08h : Extension + cyg_uint8 attr; // 0Bh : Attribute + cyg_uint8 nt_reserved; // 0Ch : Win NT Reserved field + cyg_uint8 crt_sec_100; // 0Dh : Creation time ms stamp 0 - 199 + cyg_uint16 crt_time; // 0Eh : Creation time + cyg_uint16 crt_date; // 10h : Creation date + cyg_uint16 acc_date; // 12h : Last access date + cyg_uint16 cluster_HI; // 14h : Starting cluster HI WORD (FAT32) + cyg_uint16 wrt_time; // 16h : Time + cyg_uint16 wrt_date; // 18h : Date + cyg_uint16 cluster; // 1Ah : Starting cluster + cyg_uint32 size; // 1Ch : Size of the file +} fat_raw_dir_entry_t; // ------------------------------------------------------------------------- // FAT cluster opts @@ -253,36 +252,111 @@ typedef enum cluster_opts_e // ------------------------------------------------------------------------- // get_val_log2() -// Gets the log2 of given value or returns 0 if value is -// not power of 2. +// Gets the log2 of given value or returns 0 if value is not a power of 2. static cyg_uint32 get_val_log2(cyg_uint32 val) { cyg_uint32 i, log2; - i = val; + i = val; log2 = 0; + while (0 == (i & 1)) { i >>= 1; log2++; } - if (i != 1) - return 0; - else - return log2; + + if (i != 1) return 0; + else return log2; +} + +// ------------------------------------------------------------------------- +// cluster_to_block_pos() +// Converts cluster position to blib block position. + +static void +cluster_to_block_pos(fatfs_disk_t *disk, + cyg_uint32 cluster, + cyg_uint32 cluster_pos, + cyg_uint32 *block, + cyg_uint32 *block_pos) +{ + cyg_uint32 block_size = cyg_blib_get_block_size(&disk->blib); + cyg_uint32 block_size_log2 = cyg_blib_get_block_size_log2(&disk->blib); + + *block = (cluster - 2) << (disk->cluster_size_log2 - block_size_log2); + + *block_pos = disk->fat_data_pos + cluster_pos; + + if (*block_pos > block_size) + { + *block += *block_pos >> block_size_log2; + *block_pos = *block_pos & (block_size - 1); + } +} + +// ------------------------------------------------------------------------- +// disk_write() +// Writes data to disk. + +static __inline__ int +disk_write(fatfs_disk_t *disk, + void *buf, + cyg_uint32 *len, + cyg_uint32 pos) +{ + return cyg_blib_write(&disk->blib, buf, len, 0, pos); } // ------------------------------------------------------------------------- -// get_data_disk_apos() -// Gets the absolute data position on disk from cluster number and -// position inside given cluster. - -static __inline__ cyg_uint32 -get_data_disk_apos(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 pos) +// disk_read() +// Reads data from disk. + +static __inline__ int +disk_read(fatfs_disk_t *disk, + void *buf, + cyg_uint32 *len, + cyg_uint32 pos) +{ + return cyg_blib_read(&disk->blib, buf, len, 0, pos); +} + +// ------------------------------------------------------------------------- +// disk_cluster_write() +// Writes data to disk at specified cluster position. + +static __inline__ int +disk_cluster_write(fatfs_disk_t *disk, + void *buf, + cyg_uint32 *len, + cyg_uint32 cluster, + cyg_uint32 cluster_pos) { - return (disk->fat_data_pos + disk->cluster_size * (cluster - 2) + pos); + cyg_uint32 block, block_pos; + + cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos); + + return cyg_blib_write(&disk->blib, buf, len, block, block_pos); +} + +// ------------------------------------------------------------------------- +// disk_cluster_read() +// Reads data from disk at specified cluster position. + +static __inline__ int +disk_cluster_read(fatfs_disk_t *disk, + void *buf, + cyg_uint32 *len, + cyg_uint32 cluster, + cyg_uint32 cluster_pos) +{ + cyg_uint32 block, block_pos; + + cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos); + + return cyg_blib_read(&disk->blib, buf, len, block, block_pos); } // ------------------------------------------------------------------------- @@ -330,8 +404,8 @@ date_unix2dos(cyg_uint32 unix_timestamp { cyg_uint32 jd; cyg_uint16 dtime, ddate; - int hour, min, sec; - int day, month, year; + int hour, min, sec; + int day, month, year; hour = (unix_timestamp / 3600) % 24; min = (unix_timestamp / 60) % 60; @@ -340,8 +414,8 @@ date_unix2dos(cyg_uint32 unix_timestamp jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24); jdays_to_gdate(jd, &day, &month, &year); - CYG_TRACE7(TDE, "ts=%d date=%d:%d:%d %d-%d-%d", - unix_timestamp, hour, min, sec, year, month, day); + CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d", + unix_timestamp, hour, min, sec, year, month, day); if (year < 1980) year = 1980; @@ -364,25 +438,26 @@ date_dos2unix(cyg_uint16 dos_time, cyg_uint16 dos_date, cyg_uint32 *unix_timestamp) { - int hour, min, sec; - int day, month, year; cyg_uint32 ts; + int hour, min, sec; + int day, month, year; - sec = (dos_time & ((1<<5)-1)) * 2; + sec = (dos_time & ((1<<5)-1)) * 2; dos_time >>= 5; - min = (dos_time & ((1<<6)-1)); + min = (dos_time & ((1<<6)-1)); dos_time >>= 6; - hour = dos_time; + hour = dos_time; - day = (dos_date & ((1<<5)-1)); + day = (dos_date & ((1<<5)-1)); dos_date >>= 5; - month = (dos_date & ((1<<4)-1)); + month = (dos_date & ((1<<4)-1)); dos_date >>= 4; - year = dos_date + 1980; + year = dos_date + 1980; gdate_to_jdays(day, month, year, &ts); + ts -= JD_1_JAN_1970; - ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600); + ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600); *unix_timestamp = ts; @@ -394,18 +469,19 @@ date_dos2unix(cyg_uint16 dos_time, //========================================================================== // FAT boot record functions +#if TDE + // ------------------------------------------------------------------------- // print_boot_record() // Prints FAT boot record. -#if TFT static void print_boot_record(fat_boot_record_t* fbr) { diag_printf("FAT: FBR jump code: 0x%02X\n", fbr->jump); diag_printf("FAT: FBR oem name: '%.8s'\n", fbr->oem_name); diag_printf("FAT: FBR bytes per sec: %u\n", fbr->bytes_per_sec); - diag_printf("FAT: FBR sec per cluster: %u\n", fbr->sec_per_clust); + diag_printf("FAT: FBR sec per cluster: %u\n", fbr->sec_per_clu); diag_printf("FAT: FBR reserved sec: %u\n", fbr->res_sec_num); diag_printf("FAT: FBR fat tbls num: %u\n", fbr->fat_tbls_num); diag_printf("FAT: FBR max root dents: %u\n", fbr->max_root_dents); @@ -416,7 +492,17 @@ print_boot_record(fat_boot_record_t* fbr diag_printf("FAT: FBR heads num: %u\n", fbr->heads_num); diag_printf("FAT: FBR hidden sec num: %u\n", fbr->hsec_num); diag_printf("FAT: FBR sec num: %u\n", fbr->sec_num); - diag_printf("FAT: FBR log drv num: %u\n", fbr->ldrv_num); + + if (0 == fbr->sec_per_fat) + { + diag_printf("FAT: FBR sec per fat32: %u\n", fbr->sec_per_fat_32); + diag_printf("FAT: FBR ext flags: 0x%04X\n", fbr->ext_flags); + diag_printf("FAT: FBR fs ver: %u\n", fbr->fs_ver); + diag_printf("FAT: FBR root cluster: %u\n", fbr->root_cluster); + diag_printf("FAT: FBR fs info sec: %u\n", fbr->fs_info_sec); + } + + diag_printf("FAT: FBR drv num: %u\n", fbr->drv_num); diag_printf("FAT: FBR ext sig: 0x%02X\n", fbr->ext_sig); diag_printf("FAT: FBR ser num: 0x%08X\n", fbr->ser_num); diag_printf("FAT: FBR vol name: '%.11s'\n", fbr->vol_name); @@ -424,7 +510,8 @@ print_boot_record(fat_boot_record_t* fbr diag_printf("FAT: FBR exe mark: 0x%02X 0x%02X\n", fbr->exe_marker[0], fbr->exe_marker[1]); } -#endif // TFT + +#endif // TDE // ------------------------------------------------------------------------- // read_boot_record() @@ -433,18 +520,18 @@ print_boot_record(fat_boot_record_t* fbr static int read_boot_record(fatfs_disk_t *disk, fat_boot_record_t *fbr) { - int len, err; - unsigned char data[0x3E]; + cyg_uint8 data[0x5A]; + int len, err; - len = 0x3E; - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, 0); + len = 0x5A; + err = disk_read(disk, (void*)data, &len, 0); if (err != ENOERR) return err; GET_WORD(data, fbr->jump, 0x00); GET_BYTES(data, fbr->oem_name, 8, 0x03); GET_WORD(data, fbr->bytes_per_sec, 0x0B); - GET_BYTE(data, fbr->sec_per_clust, 0x0D); + GET_BYTE(data, fbr->sec_per_clu, 0x0D); GET_WORD(data, fbr->res_sec_num, 0x0E); GET_BYTE(data, fbr->fat_tbls_num, 0x10); GET_WORD(data, fbr->max_root_dents, 0x11); @@ -455,15 +542,37 @@ read_boot_record(fatfs_disk_t *disk, fat GET_WORD(data, fbr->heads_num, 0x1A); GET_DWORD(data, fbr->hsec_num, 0x1C); GET_DWORD(data, fbr->sec_num, 0x20); - GET_WORD(data, fbr->ldrv_num, 0x24); - GET_BYTE(data, fbr->ext_sig, 0x26); - GET_DWORD(data, fbr->ser_num, 0x27); - GET_BYTES(data, fbr->vol_name, 11, 0x2B); - GET_BYTES(data, fbr->fat_name, 8, 0x36); - // Skip the exe code and read the end marker + // This is a quick check for FAT12/16 or FAT32 boot record. + // The sec_per_fat field must be 0 on FAT32, since this + // field plays a crucial role in detection of the FAT type + // (12,16,32) it is quite safe to make this assumption. + if (0 == fbr->sec_per_fat) + { + GET_DWORD(data, fbr->sec_per_fat_32, 0x24); + GET_WORD(data, fbr->ext_flags, 0x28); + GET_WORD(data, fbr->fs_ver, 0x2A); + GET_DWORD(data, fbr->root_cluster, 0x2C); + GET_WORD(data, fbr->fs_info_sec, 0x30); + GET_WORD(data, fbr->bk_boot_sec, 0x32); + GET_BYTE(data, fbr->drv_num, 0x40); + GET_BYTE(data, fbr->ext_sig, 0x42); + GET_DWORD(data, fbr->ser_num, 0x43); + GET_BYTES(data, fbr->vol_name, 11, 0x47); + GET_BYTES(data, fbr->fat_name, 8, 0x52); + } + else + { + GET_BYTE(data, fbr->drv_num, 0x24); + GET_BYTE(data, fbr->ext_sig, 0x26); + GET_DWORD(data, fbr->ser_num, 0x27); + GET_BYTES(data, fbr->vol_name, 11, 0x2B); + GET_BYTES(data, fbr->fat_name, 8, 0x36); + } + + // Read the end marker len = 0x02; - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, 0x1FE); + err = disk_read(disk, (void*)data, &len, 0x1FE); if (err != ENOERR) return err; @@ -473,8 +582,8 @@ read_boot_record(fatfs_disk_t *disk, fat fbr->oem_name[8] = '\0'; fbr->vol_name[11] = '\0'; fbr->fat_name[8] = '\0'; - -#if TFT + +#if TDE print_boot_record(fbr); #endif @@ -489,65 +598,61 @@ read_boot_record(fatfs_disk_t *disk, fat // Reads FAT table entry from disk. static int -read_tentry_fat12(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) -{ - unsigned char data[2]; - cyg_uint32 pos, num3; - cyg_uint16 e; - int len, err; - - num3 = num * 3; - pos = disk->fat_tbl_pos + (num3 >> 1); - len = 2; - - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos); - if (err != ENOERR) - return err; - - GET_WORD(data, e, 0x00); - - if (0 == (num3 & 1)) - *entry = e & 0x0FFF; - else - *entry = (e >> 4) & 0x0FFF; - - CYG_TRACE3(TFT, "tentry=%x num=%d at %d", *entry, num, pos); - - return ENOERR; -} - -static int -read_tentry_fat16(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) -{ - unsigned char data[2]; - cyg_uint32 pos; - cyg_uint16 e; - int len, err; - - pos = disk->fat_tbl_pos + (num << 1); - len = 2; - - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos); - if (err != ENOERR) - return err; - - GET_WORD(data, e, 0x00); - *entry = e; - - CYG_TRACE3(TFT, "tentry=%x num=%d at %d", *entry, num, pos); - - return ENOERR; -} - -static int read_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) { + cyg_uint8 data[4]; + cyg_uint32 pos, num3; + cyg_uint32 e; + int len, err; + switch (disk->fat_type) { - case FATFS_FAT12: return read_tentry_fat12(disk, num, entry); - case FATFS_FAT16: return read_tentry_fat16(disk, num, entry); - default: return EINVAL; + case FATFS_FAT12: + num3 = num * 3; + pos = disk->fat_tbl_pos + (num3 >> 1); + len = 2; + + err = disk_read(disk, (void*)data, &len, pos); + if (err != ENOERR) + return err; + + GET_WORD(data, e, 0x00); + + if (0 == (num3 & 1)) *entry = e & 0x0FFF; + else *entry = (e >> 4) & 0x0FFF; + + break; + + case FATFS_FAT16: + pos = disk->fat_tbl_pos + (num << 1); + len = 2; + + err = disk_read(disk, (void*)data, &len, pos); + if (err != ENOERR) + return err; + + GET_WORD(data, e, 0x00); + *entry = e; + + break; + + case FATFS_FAT32: + pos = disk->fat_tbl_pos + (num << 2); + len = 4; + + err = disk_read(disk, (void*)data, &len, pos); + if (err != ENOERR) + return err; + + GET_DWORD(data, e, 0x00); + *entry = e & 0x0FFFFFFF; + + break; + + default: + CYG_ASSERT(false, "Unknown FAT type"); } + return ENOERR; } // ------------------------------------------------------------------------- @@ -555,138 +660,127 @@ read_tentry(fatfs_disk_t *disk, cyg_uint // Writes FAT table entry to disk (to all copies of FAT). static int -write_tentry_fat12(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) +write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) { - unsigned char data[2]; - cyg_uint32 pos, num3; - cyg_uint16 e; - int i, len, err; + cyg_uint8 data[4]; + cyg_uint32 pos=0, num3; + cyg_uint32 e; + int i, len, err; - num3 = num * 3; - pos = disk->fat_tbl_pos + (num3 >> 1); - len = 2; + switch (disk->fat_type) + { + case FATFS_FAT12: + num3 = num * 3; + pos = disk->fat_tbl_pos + (num3 >> 1); + len = 2; - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos); - if (err != ENOERR) - return err; + err = disk_read(disk, (void*)data, &len, pos); + if (err != ENOERR) + return err; - GET_WORD(data, e, 0x00); + GET_WORD(data, e, 0x00); - if (0 == (num3 & 1)) - e = (e & 0xF000) | (*entry & 0x0FFF); - else - e = (e & 0x000F) | ((*entry & 0x0FFF) << 4); + if (0 == (num3 & 1)) e = (e & 0xF000) | (*entry & 0x0FFF); + else e = (e & 0x000F) | ((*entry & 0x0FFF) << 4); + + SET_WORD(data, e, 0x00); + + break; + + case FATFS_FAT16: + pos = disk->fat_tbl_pos + (num << 1); + len = 2; - SET_WORD(data, e, 0x00); + e = *entry; + SET_WORD(data, e, 0x00); + + break; + + case FATFS_FAT32: + pos = disk->fat_tbl_pos + (num << 2); + len = 4; + + err = disk_read(disk, (void*)data, &len, pos); + if (err != ENOERR) + return err; + GET_DWORD(data, e, 0x00); + + e = (e & 0xF0000000) | *entry; + + SET_DWORD(data, e, 0x00); + + break; + + default: + CYG_ASSERT(false, "Unknown FAT type"); + } + for (i = 0; i < disk->fat_tbls_num; i++) { - err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, pos); + err = disk_write(disk, (void*)data, &len, pos); if (err != ENOERR) return err; - CYG_TRACE4(TFT, "tentry=%x num=%d at %d tbl=%d", *entry, num, pos, i); - pos += disk->fat_tbl_size; } return ENOERR; } -static int -write_tentry_fat16(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) -{ - unsigned char data[2]; - cyg_uint32 pos; - cyg_uint16 e; - int i, len, err; - - pos = disk->fat_tbl_pos + (num << 1); - len = 2; - - e = *entry; - SET_WORD(data, e, 0x00); - - for (i = 0; i < disk->fat_tbls_num; i++) - { - err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, pos); - if (err != ENOERR) - return err; - - CYG_TRACE4(TFT, "tentry=%x num=%d at %d tbl=%d", *entry, num, pos, i); - - pos += disk->fat_tbl_size; - } - - return ENOERR; -} - -static int -write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry) -{ - switch (disk->fat_type) - { - case FATFS_FAT12: return write_tentry_fat12(disk, num, entry); - case FATFS_FAT16: return write_tentry_fat16(disk, num, entry); - default: return EINVAL; - } -} - // ------------------------------------------------------------------------- // get_tentry_type() // Gets the type of FAT table entry. static int -get_tentry_type_fat12(fatfs_disk_t *disk, cyg_uint32 entry) -{ - int type; - - if (entry < 0x0FF0) - { - if (0x0000 == entry) type = TENTRY_FREE; - else type = TENTRY_REGULAR; - } - else if (entry >= 0x0FF8) type = TENTRY_LAST; - else if (0x0FF7 == entry) type = TENTRY_BAD; - else type = TENTRY_RESERVED; - -#if TFT - CYG_TRACE2(TFT, "tentry=%04X type=%s", entry, tentry_type_name[type]); -#endif - - return type; -} - -static int -get_tentry_type_fat16(fatfs_disk_t *disk, cyg_uint32 entry) +get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry) { int type; - if (entry < 0xFFF0) - { - if (0x0000 == entry) type = TENTRY_FREE; - else type = TENTRY_REGULAR; - } - else if (entry >= 0xFFF8) type = TENTRY_LAST; - else if (0xFFF7 == entry) type = TENTRY_BAD; - else type = TENTRY_RESERVED; - -#if TFT - CYG_TRACE2(TFT, "tentry=%04X type=%s", entry, tentry_type_name[type]); -#endif - - return type; -} - -static int -get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry) -{ switch (disk->fat_type) { - case FATFS_FAT12: return get_tentry_type_fat12(disk, entry); - case FATFS_FAT16: return get_tentry_type_fat16(disk, entry); - default: return TENTRY_BAD; + case FATFS_FAT12: + if (entry < 0x0FF0) + { + if (0x0000 == entry) type = TENTRY_FREE; + else type = TENTRY_REGULAR; + } + else if (entry >= 0x0FF8) type = TENTRY_LAST; + else if (0x0FF7 == entry) type = TENTRY_BAD; + else type = TENTRY_RESERVED; + + break; + + case FATFS_FAT16: + if (entry < 0xFFF0) + { + if (0x0000 == entry) type = TENTRY_FREE; + else type = TENTRY_REGULAR; + } + else if (entry >= 0xFFF8) type = TENTRY_LAST; + else if (0xFFF7 == entry) type = TENTRY_BAD; + else type = TENTRY_RESERVED; + + break; + + case FATFS_FAT32: + + if (entry < 0x0FFFFFF0) + { + if (0x00000000 == entry) type = TENTRY_FREE; + else type = TENTRY_REGULAR; + } + else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST; + else if (0x0FFFFFF7 == entry) type = TENTRY_BAD; + else type = TENTRY_RESERVED; + + break; + + default: + CYG_ASSERT(false, "Unknown FAT type"); + type = TENTRY_BAD; // least likely to cause damage } + return type; } // ------------------------------------------------------------------------- @@ -694,40 +788,48 @@ get_tentry_type(fatfs_disk_t *disk, cyg_ // Sets the type of FAT table entry. static void -set_tentry_type_fat12(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type) -{ - switch (type) - { - case TENTRY_FREE: *entry = 0x0000; break; - case TENTRY_LAST: *entry = 0x0FF8; break; - case TENTRY_RESERVED: *entry = 0x0FF0; break; - case TENTRY_BAD: *entry = 0x0FF7; break; - default: - CYG_ASSERT(false, "Unknown tentry type"); - } -} - -static void -set_tentry_type_fat16(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type) -{ - switch (type) - { - case TENTRY_FREE: *entry = 0x0000; break; - case TENTRY_LAST: *entry = 0xFFF8; break; - case TENTRY_RESERVED: *entry = 0xFFF0; break; - case TENTRY_BAD: *entry = 0xFFF7; break; - default: - CYG_ASSERT(false, "Unknown tentry type"); - } -} - -static void set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type) { switch (disk->fat_type) { - case FATFS_FAT12: set_tentry_type_fat12(disk, entry, type); - case FATFS_FAT16: set_tentry_type_fat16(disk, entry, type); + case FATFS_FAT12: + switch (type) + { + case TENTRY_FREE: *entry = 0x0000; return; + case TENTRY_LAST: *entry = 0x0FF8; return; + case TENTRY_RESERVED: *entry = 0x0FF0; return; + case TENTRY_BAD: *entry = 0x0FF7; return; + default: + CYG_ASSERT(false, "Unknown tentry type"); + } + break; + + case FATFS_FAT16: + switch (type) + { + case TENTRY_FREE: *entry = 0x0000; return; + case TENTRY_LAST: *entry = 0xFFF8; return; + case TENTRY_RESERVED: *entry = 0xFFF0; return; + case TENTRY_BAD: *entry = 0xFFF7; return; + default: + CYG_ASSERT(false, "Unknown tentry type"); + } + break; + + case FATFS_FAT32: + switch (type) + { + case TENTRY_FREE: *entry = 0x00000000; return; + case TENTRY_LAST: *entry = 0x0FFFFFF8; return; + case TENTRY_RESERVED: *entry = 0x0FFFFFF0; return; + case TENTRY_BAD: *entry = 0x0FFFFFF7; return; + default: + CYG_ASSERT(false, "Unknown tentry type"); + } + break; + + default: + CYG_ASSERT(false, "Unknown FAT type"); } } @@ -757,38 +859,29 @@ set_tentry_next_cluster(fatfs_disk_t *di // FAT cluster functions // ------------------------------------------------------------------------- -// is_pos_inside_cluster() -// Checks if the given position is inside cluster size. - -static __inline__ bool -is_pos_inside_cluster(fatfs_disk_t *disk, cyg_uint32 pos) -{ - return (pos < disk->cluster_size); -} - -// ------------------------------------------------------------------------- // erase_cluster() -// Erases cluster (fills with 0x00). +// Erases cluster (fills with 0x00). static int erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster) { - unsigned char data[32]; - cyg_uint32 apos; - int err, len, i; + cyg_uint8 data[32]; + cyg_uint32 pos; + int err, len, i; + pos = 0; len = 32; memset((void*)data, 0x00, len); - apos = get_data_disk_apos(disk, cluster, 0); - CYG_TRACE1(TCL, "cluster=%d", cluster); + CYG_TRACE1(TCL, "erasing cluster=%d", cluster); for (i = 0; i < (disk->cluster_size >> 5); i++) { - err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, apos); + err = disk_cluster_write(disk, (void*)data, &len, cluster, pos); if (err != ENOERR) return err; - apos += len; + + pos += len; } return ENOERR; @@ -802,14 +895,9 @@ static int mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type) { cyg_uint32 tentry; - int err; set_tentry_type(disk, &tentry, type); - err = write_tentry(disk, cluster, &tentry); - - CYG_TRACE3(TCL, "cluster=%d type=%d tentry=%d", - cluster, type, tentry); - return err; + return write_tentry(disk, cluster, &tentry); } // ------------------------------------------------------------------------- @@ -820,45 +908,39 @@ static int link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2) { cyg_uint32 tentry; - int err; set_tentry_next_cluster(disk, &tentry, cluster2); - err = write_tentry(disk, cluster1, &tentry); - - CYG_TRACE3(TCL, "cluster1=%d cluster2=%d tentry=%d", - cluster1, cluster2, tentry); - return err; + return write_tentry(disk, cluster1, &tentry); } // ------------------------------------------------------------------------- // find_next_free_cluster() // Finds first free cluster starting from given cluster. // If none is available free_cluster is set to 0. -// If mark_as_last is set the found cluster is marked as LAST. +// If CO_MARK_LAST is set in opts the found cluster is marked as LAST. +// If CO_ERASE_NEW is set in opts the found cluster is erased. static int -find_next_free_cluster(fatfs_disk_t *disk, - cyg_uint32 start_cluster, - cyg_uint32 *free_cluster, - cluster_opts_t opts) +find_next_free_cluster(fatfs_disk_t *disk, + cyg_uint32 start_cluster, + cyg_uint32 *free_cluster, + cluster_opts_t opts) { cyg_uint32 c, tentry; - int err; + int err; - if (start_cluster < 2) - c = 2; - else - c = start_cluster + 1; + if (start_cluster < 2) c = 2; + else c = start_cluster + 1; *free_cluster = 0; - CYG_TRACE1(TCL, "c=%d", c); + CYG_TRACE1(TCL, "starting at cluster=%d", c); // Search from the starting cluster to the end of FAT and - // from start of FAT to the starting cluster + // from start of FAT to the starting cluster while (c != start_cluster) { - // End of FAT check + // Check for end of FAT if (c >= disk->fat_tbl_nents) { c = 2; @@ -872,21 +954,24 @@ find_next_free_cluster(fatfs_disk_t *di if (TENTRY_FREE == get_tentry_type(disk, tentry)) { - CYG_TRACE1(TCL, "free_cluster=%d", c); + CYG_TRACE1(TCL, "found free cluster=%d", c); + *free_cluster = c; + if (opts & CO_MARK_LAST) err = mark_cluster(disk, c, TENTRY_LAST); if ((err == ENOERR) && (opts & CO_ERASE_NEW)) err = erase_cluster(disk, c); + return err; } c++; } // No free clusters found + CYG_TRACE0(TCL, "!!! no free clusters found"); - // Return out of space return ENOSPC; } @@ -896,92 +981,59 @@ find_next_free_cluster(fatfs_disk_t *di // New cluster is marked as LAST. static int -find_and_append_cluster(fatfs_disk_t *disk, - cyg_uint32 cluster, - cyg_uint32 *new_cluster, - cluster_opts_t opts) +find_and_append_cluster(fatfs_disk_t *disk, + cyg_uint32 cluster, + cyg_uint32 *new_cluster, + cluster_opts_t opts) { cyg_uint32 free_cluster; - int err; + int err; - CYG_TRACE1(TCL, "cluster=%d", cluster); - err = find_next_free_cluster(disk, cluster, - &free_cluster, opts | CO_MARK_LAST); + &free_cluster, opts | CO_MARK_LAST); if (err != ENOERR) return err; - CYG_TRACE1(TCL, "free_cluster=%d", free_cluster); - - // Link clusters err = link_cluster(disk, cluster, free_cluster); if (err != ENOERR) return err; *new_cluster = free_cluster; - CYG_TRACE1(TCL, "new_cluster=%d", free_cluster); + CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d", + free_cluster, cluster); return ENOERR; } // ------------------------------------------------------------------------- // find_nth_cluster0() -// Finds nth cluster in chain (ie nth cluster of file). -// Searching from given position. +// Finds nth cluster in chain (ie nth cluster of file) searching +// from given position. The result is returned by the same position +// variable. static int find_nth_cluster0(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, - cyg_uint32 n, - fatfs_tcache_t *tcache) + fatfs_data_pos_t *pos, + cyg_uint32 n) { cyg_uint32 cluster, cluster_snum; - int err = ENOERR; + int err = ENOERR; - // Trivial case check - if (dpos->cluster_snum == n) + if (pos->cluster_snum == n) return ENOERR; - // First look in cache - if (NULL != tcache) - { - cyg_uint32 c, ln; - if (fatfs_tcache_get(disk, tcache, n, &c)) - { - // Cluster in cache - dpos->cluster = c; - dpos->cluster_snum = n; - CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d in cache", c, n); - return ENOERR; - } - else if (fatfs_tcache_get_last(disk, tcache, &ln, &c)) - { - // Cluster not in cache - get last - // in cache and search from there - dpos->cluster = c; - dpos->cluster_snum = ln; - CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d last in cache", c, ln); - } - else - { - // Empty cache - put first cluster in - fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster); - } - } + cluster = pos->cluster; + cluster_snum = pos->cluster_snum; - cluster = dpos->cluster; - cluster_snum = dpos->cluster_snum; - - CYG_TRACE4(TCL, "cluster=%d cluster_snum=%d n=%d n_to_search=%d", + CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d", cluster, cluster_snum, n, n-cluster_snum); // Adjust the number of clusters that should be // walked according to the given position n -= cluster_snum; - // Walk the cluster chain for n clusters or - // until last cluster + // Walk the cluster chain for n clusters or until last cluster while (n > 0) { cyg_uint32 tentry; @@ -995,8 +1047,7 @@ find_nth_cluster0(fatfs_disk_t *disk case TENTRY_REGULAR: break; case TENTRY_LAST: - // Oops early last cluster - CYG_TRACE1(TCL, "chain end n=%d", n); + CYG_TRACE1(TCL, "chain end at n=%d", n); err = EEOF; // File has less clusters than given n // this err should be caught by the // calling function @@ -1010,67 +1061,57 @@ find_nth_cluster0(fatfs_disk_t *disk } cluster = get_tentry_next_cluster(disk, tentry); cluster_snum++; - if (NULL != tcache) - fatfs_tcache_set(disk, tcache, cluster_snum, cluster); n--; } out: - dpos->cluster = cluster; - dpos->cluster_snum = cluster_snum; + pos->cluster = cluster; + pos->cluster_snum = cluster_snum; - CYG_TRACE2(TCL, "nth cluster=%d cluster_snum=%d", cluster, cluster_snum); + CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum); + return err; } // ------------------------------------------------------------------------- // find_nth_cluster() // Finds nth cluster in chain (ie nth cluster of file) searching -// from given position. If the chain ends one cluster before the -// given nth cluster and the CO_EXTEND is specifide, than the -// chain is extended by one cluster. +// from given position. The result is returned by the same position +// variable. If the chain ends one cluster before the given nth cluster +// and the CO_EXTEND is specified, than the chain is extended by one cluster. static int find_nth_cluster(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, + fatfs_data_pos_t *pos, cyg_uint32 n, - fatfs_tcache_t *tcache, cluster_opts_t opts) { int err; // Find nth cluster - err = find_nth_cluster0(disk, dpos, n, tcache); + err = find_nth_cluster0(disk, pos, n); // EEOF meens that the cluster chain ended early if ((err != EEOF) || !(opts & CO_EXTEND)) return err; - CYG_TRACE2(TCL, "cluster_snum=%d n=%d", dpos->cluster_snum, n); - // Check if one cluster short - if (dpos->cluster_snum == (n - 1)) + if (pos->cluster_snum == (n - 1)) { // Extend the chain for one cluster cyg_uint32 new_cluster; // Append new cluster to the end of chain - err = find_and_append_cluster(disk, dpos->cluster, - &new_cluster, opts); + err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts); if (err != ENOERR) return err; // Update position - dpos->cluster = new_cluster; - dpos->cluster_snum++; - dpos->cluster_pos = 0; + pos->cluster = new_cluster; + pos->cluster_snum += 1; + pos->cluster_pos = 0; - CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", - dpos->cluster, dpos->cluster_snum); - - // Update cache - if (NULL != tcache) - fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster); + CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster); } return err; @@ -1079,71 +1120,72 @@ find_nth_cluster(fatfs_disk_t *disk, // ------------------------------------------------------------------------- // get_next_cluster() // Gets next cluster in chain (ie next cluster of file). -// If CO_EXTEND is specified and the current cluster is last in +// If CO_EXTEND is specified and the current cluster is last in the // chain then the chain is extended by one cluster. static int get_next_cluster(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, - fatfs_tcache_t *tcache, + fatfs_data_pos_t *pos, cluster_opts_t opts) { int err; - CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", - dpos->cluster, dpos->cluster_snum); - - err = find_nth_cluster(disk, dpos, dpos->cluster_snum + 1, tcache, opts); - + err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts); if (err != ENOERR) return err; - // Update position - dpos->cluster_pos = 0; + // Reset inside cluster position + pos->cluster_pos = 0; - CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", - dpos->cluster, dpos->cluster_snum); - return ENOERR; } // ------------------------------------------------------------------------- -// get_data_position_from_off() -// Gets data position from given file offset. -// If CO_EXTEND is specified the file is extended if -// one cluster too short. - -static int -get_data_position_from_off(fatfs_disk_t *disk, - cyg_uint32 first_cluster, - cyg_uint32 offset, - fatfs_data_pos_t *dpos, - fatfs_tcache_t *tcache, - cluster_opts_t opts) +// get_position_from_off() +// Gets position from given offset. The search is started from the +// given position and the result is returned by the same variable. +// If CO_EXTEND is specified the file is extended if one cluster too short. + +static int +get_position_from_off(fatfs_disk_t *disk, + cyg_uint32 first_cluster, + cyg_uint32 offset, + fatfs_data_pos_t *pos, + cluster_opts_t opts) { - cyg_uint32 n; - int err; + fatfs_data_pos_t new_pos; + cyg_uint32 n; + int err; // Position inside the cluster - dpos->cluster_pos = offset & (disk->cluster_size - 1); + new_pos.cluster_pos = offset & (disk->cluster_size - 1); // Cluster seq number to be searched for n = offset >> disk->cluster_size_log2; - // Start searching from first cluster - dpos->cluster = first_cluster; - dpos->cluster_snum = 0; + if (n < pos->cluster_snum) + { + // Start searching from first cluster + new_pos.cluster = first_cluster; + new_pos.cluster_snum = 0; + } + else + { + // Start searching from the current position + new_pos.cluster = pos->cluster; + new_pos.cluster_snum = pos->cluster_snum; + } - CYG_TRACE4(TCL, "off=%d first_cluster=%d cluster_pos=%d n=%d\n", - offset, first_cluster, dpos->cluster_pos, n); - - err = find_nth_cluster(disk, dpos, n, tcache, opts); - + err = find_nth_cluster(disk, &new_pos, n, opts); + // Err could be EEOF wich means that the given // offset if out of given file (cluster chain) + if (ENOERR == err) + *pos = new_pos; + return err; -} +} // ------------------------------------------------------------------------- // free_cluster_chain() @@ -1153,10 +1195,10 @@ static int free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster) { cyg_uint32 c, next_c, tentry; - bool last; - int err; + bool last; + int err; - CYG_TRACE1(TCL, "start_cluster=%d", start_cluster); + CYG_TRACE1(TCL, "start cluster=%d", start_cluster); c = next_c = start_cluster; last = false; @@ -1192,7 +1234,7 @@ free_cluster_chain(fatfs_disk_t *disk, c c = next_c; } - CYG_TRACE1(TCL, "last_cluster=%d", c); + CYG_TRACE1(TCL, "last cluster=%d", c); return ENOERR; } @@ -1201,166 +1243,161 @@ free_cluster_chain(fatfs_disk_t *disk, c // FAT dir entry functions // ------------------------------------------------------------------------- -// print_dentry() +// print_raw_dentry() // Prints FAT directory entry. #if TDE static void -print_dentry(fat_dir_entry_t* fde) +print_raw_dentry(fat_raw_dir_entry_t* dentry) { - if (DENTRY_IS_DELETED(fde)) - diag_printf("FAT: FDE name: '?%.7s'\n", &fde->name[1]); + if (DENTRY_IS_DELETED(dentry)) + diag_printf("FAT: FDE name: '?%.7s'\n", &dentry->name[1]); else - diag_printf("FAT: FDE name: '%.8s'\n", fde->name); - diag_printf("FAT: FDE ext: '%.3s'\n", fde->ext); + diag_printf("FAT: FDE name: '%.8s'\n", dentry->name); + diag_printf("FAT: FDE ext: '%.3s'\n", dentry->ext); diag_printf("FAT: FDE attr: %c%c%c%c%c%c\n", - (DENTRY_IS_RDONLY(fde) ? 'R' : '-'), - (DENTRY_IS_HIDDEN(fde) ? 'H' : '-'), - (DENTRY_IS_SYSTEM(fde) ? 'S' : '-'), - (DENTRY_IS_VOLUME(fde) ? 'V' : '-'), - (DENTRY_IS_DIR(fde) ? 'D' : '-'), - (DENTRY_IS_ARCHIVE(fde) ? 'A' : '-')); - diag_printf("FAT: FDE crt time: %u\n", fde->crt_time); - diag_printf("FAT: FDE crt date: %u\n", fde->crt_date); - diag_printf("FAT: FDE acc date: %u\n", fde->acc_date); - diag_printf("FAT: FDE wrt time: %u\n", fde->wrt_time); - diag_printf("FAT: FDE wrt date: %u\n", fde->wrt_date); - diag_printf("FAT: FDE cluster: %u\n", fde->cluster); - diag_printf("FAT: FDE size: %u\n", fde->size); + (DENTRY_IS_RDONLY(dentry) ? 'R' : '-'), + (DENTRY_IS_HIDDEN(dentry) ? 'H' : '-'), + (DENTRY_IS_SYSTEM(dentry) ? 'S' : '-'), + (DENTRY_IS_VOLUME(dentry) ? 'V' : '-'), + (DENTRY_IS_DIR(dentry) ? 'D' : '-'), + (DENTRY_IS_ARCHIVE(dentry) ? 'A' : '-')); + diag_printf("FAT: FDE crt time: %u\n", dentry->crt_time); + diag_printf("FAT: FDE crt date: %u\n", dentry->crt_date); + diag_printf("FAT: FDE acc date: %u\n", dentry->acc_date); + diag_printf("FAT: FDE wrt time: %u\n", dentry->wrt_time); + diag_printf("FAT: FDE wrt date: %u\n", dentry->wrt_date); + diag_printf("FAT: FDE cluster: %u\n", dentry->cluster); + diag_printf("FAT: FDE size: %u\n", dentry->size); } #endif // TDE // ------------------------------------------------------------------------- -// read_dentry() -// Reads dir entry from disk. -// If cluster is 0 reads from root dir. +// read_raw_dentry() +// Reads dir entry from disk. static int -read_dentry(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, - fat_dir_entry_t *fde) +read_raw_dentry(fatfs_disk_t *disk, + fatfs_data_pos_t *pos, + fat_raw_dir_entry_t *dentry) { - unsigned char data[DENTRY_SIZE]; - cyg_uint32 apos; - int len, err; + cyg_uint8 data[DENTRY_SIZE]; + int len, err; + + CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d", + pos->cluster, pos->cluster_snum, pos->cluster_pos); - // Check if we are reading the root directory - if (0 == dpos->cluster) - apos = disk->fat_root_dir_pos + dpos->cluster_pos; + len = DENTRY_SIZE; + + // Check if we are reading the FAT12/16 root directory + if (0 == pos->cluster) + err = disk_read(disk, (void*)data, &len, + disk->fat_root_dir_pos + pos->cluster_pos); else - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); - - CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d", - dpos->cluster, dpos->cluster_pos, apos); - - len = DENTRY_SIZE; - err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, apos); + err = disk_cluster_read(disk, (void*)data, &len, + pos->cluster, pos->cluster_pos); if (err != ENOERR) return err; - GET_BYTES(data, fde->name, 8, 0x00); - GET_BYTES(data, fde->ext, 3, 0x08); - GET_BYTE(data, fde->attr, 0x0B); - GET_BYTE(data, fde->nt_reserved, 0x0C); - GET_BYTE(data, fde->crt_sec_100, 0x0D); - GET_WORD(data, fde->crt_time, 0x0E); - GET_WORD(data, fde->crt_date, 0x10); - GET_WORD(data, fde->acc_date, 0x12); - GET_WORD(data, fde->cluster_HI, 0x14); - GET_WORD(data, fde->wrt_time, 0x16); - GET_WORD(data, fde->wrt_date, 0x18); - GET_WORD(data, fde->cluster, 0x1A); - GET_DWORD(data, fde->size, 0x1C); + GET_BYTES(data, dentry->name, 8, 0x00); + GET_BYTES(data, dentry->ext, 3, 0x08); + GET_BYTE(data, dentry->attr, 0x0B); + GET_BYTE(data, dentry->nt_reserved, 0x0C); + GET_BYTE(data, dentry->crt_sec_100, 0x0D); + GET_WORD(data, dentry->crt_time, 0x0E); + GET_WORD(data, dentry->crt_date, 0x10); + GET_WORD(data, dentry->acc_date, 0x12); + GET_WORD(data, dentry->cluster_HI, 0x14); + GET_WORD(data, dentry->wrt_time, 0x16); + GET_WORD(data, dentry->wrt_date, 0x18); + GET_WORD(data, dentry->cluster, 0x1A); + GET_DWORD(data, dentry->size, 0x1C); // Zero terminate strings - fde->name[8] = '\0'; - fde->ext[3] = '\0'; + dentry->name[8] = '\0'; + dentry->ext[3] = '\0'; - // Store position - fde->pos = *dpos; - #if TDE - print_dentry(fde); + print_raw_dentry(dentry); #endif return ENOERR; } // ------------------------------------------------------------------------- -// write_dentry() -// Writes dir entry to disk. -// If cluster is 0 writes to root dir. +// write_raw_dentry() +// Writes raw dir entry to disk. static int -write_dentry(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, - fat_dir_entry_t *fde) +write_raw_dentry(fatfs_disk_t *disk, + fatfs_data_pos_t *pos, + fat_raw_dir_entry_t *dentry) { - unsigned char data[DENTRY_SIZE]; - cyg_uint32 apos; - int len, err; - - // Check if we are writting to the root directory - if (0 == dpos->cluster) - apos = disk->fat_root_dir_pos + dpos->cluster_pos; - else - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); + cyg_uint8 data[DENTRY_SIZE]; + int len, err; - CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d", - dpos->cluster, dpos->cluster_pos, apos); - - SET_BYTES(data, fde->name, 8, 0x00); - SET_BYTES(data, fde->ext, 3, 0x08); - SET_BYTE(data, fde->attr, 0x0B); - SET_BYTE(data, fde->nt_reserved, 0x0C); - SET_BYTE(data, fde->crt_sec_100, 0x0D); - SET_WORD(data, fde->crt_time, 0x0E); - SET_WORD(data, fde->crt_date, 0x10); - SET_WORD(data, fde->acc_date, 0x12); - SET_WORD(data, fde->cluster_HI, 0x14); - SET_WORD(data, fde->wrt_time, 0x16); - SET_WORD(data, fde->wrt_date, 0x18); - SET_WORD(data, fde->cluster, 0x1A); - SET_DWORD(data, fde->size, 0x1C); + CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d", + pos->cluster, pos->cluster_snum, pos->cluster_pos); + + SET_BYTES(data, dentry->name, 8, 0x00); + SET_BYTES(data, dentry->ext, 3, 0x08); + SET_BYTE(data, dentry->attr, 0x0B); + SET_BYTE(data, dentry->nt_reserved, 0x0C); + SET_BYTE(data, dentry->crt_sec_100, 0x0D); + SET_WORD(data, dentry->crt_time, 0x0E); + SET_WORD(data, dentry->crt_date, 0x10); + SET_WORD(data, dentry->acc_date, 0x12); + SET_WORD(data, dentry->cluster_HI, 0x14); + SET_WORD(data, dentry->wrt_time, 0x16); + SET_WORD(data, dentry->wrt_date, 0x18); + SET_WORD(data, dentry->cluster, 0x1A); + SET_DWORD(data, dentry->size, 0x1C); len = DENTRY_SIZE; - err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, apos); + + // Check if we are writting to the FAT12/16 root directory + if (0 == pos->cluster) + err = disk_write(disk, (void*)data, &len, + disk->fat_root_dir_pos + pos->cluster_pos); + else + err = disk_cluster_write(disk, (void*)data, &len, + pos->cluster, pos->cluster_pos); if (err != ENOERR) return err; #if TDE - print_dentry(fde); + print_raw_dentry(dentry); #endif return ENOERR; } // ------------------------------------------------------------------------- -// dentry_set_deleted() +// raw_dentry_set_deleted() // Sets the dentry filename first char to 0xE5 (ie deleted). static __inline__ void -dentry_set_deleted(fatfs_disk_t *disk, fat_dir_entry_t *dentry) +raw_dentry_set_deleted(fatfs_disk_t *disk, fat_raw_dir_entry_t *dentry) { dentry->name[0] = 0xE5; } // ------------------------------------------------------------------------- -// get_dentry_filename() +// get_raw_dentry_filename() // Gets the filename from given dir entry. static void -get_dentry_filename(fat_dir_entry_t *fde, char *name) +get_raw_dentry_filename(fat_raw_dir_entry_t *dentry, char *name) { - int i = 0; - char *cptr = fde->name; + int i = 0; + char *cptr = dentry->name; char *cname = name; while (*cptr != ' ' && i < 8) { *cname++ = *cptr++; i++; } - cptr = fde->ext; + cptr = dentry->ext; if (*cptr != ' ') { @@ -1372,34 +1409,36 @@ get_dentry_filename(fat_dir_entry_t *fde } *cname = '\0'; - CYG_TRACE3(TDE, "dos_name='%s' dos_ext='%s' filename='%s'", - fde->name, fde->ext, name); + CYG_TRACE3(TDE, "dos name='%s' dos ext='%s' filename='%s'", + dentry->name, dentry->ext, name); } // ------------------------------------------------------------------------- -// set_dentry_filename() -// Sets the filename to given dir entry. +// set_raw_dentry_filename() +// Sets the filename of given dir entry. static void -set_dentry_filename(fat_dir_entry_t *fde, const char *name, int namelen) +set_raw_dentry_filename(fat_raw_dir_entry_t *dentry, + const char *name, + int namelen) { - int i, nidx; + int i, nidx; const char *cname; - char *cptr; + char *cptr; // Special case check - if (name[0] == '.') + if ('.' == name[0]) { - if (name[1] == '\0') + if ('\0' == name[1]) { - strcpy(fde->name, ". "); - strcpy(fde->ext, " "); + strcpy(dentry->name, ". "); + strcpy(dentry->ext, " "); return; } - else if (name[1] == '.' && name[2] == '\0') + else if ('.' == name[1] && '\0' == name[2]) { - strcpy(fde->name, ".. "); - strcpy(fde->ext, " "); + strcpy(dentry->name, ".. "); + strcpy(dentry->ext, " "); return; } } @@ -1409,7 +1448,7 @@ set_dentry_filename(fat_dir_entry_t *fde nidx = 0; cname = name; - cptr = fde->name; + cptr = dentry->name; for (i = 0; i < 8; i++) { if (*cname != '.' && *cname != '\0' && nidx++ < namelen) @@ -1422,10 +1461,10 @@ set_dentry_filename(fat_dir_entry_t *fde while (*cname != '.' && *cname != '\0' && nidx++ < namelen) cname++; - if (*cname == '.' && nidx++ < namelen) + if ('.' == *cname && nidx++ < namelen) cname++; - cptr = fde->ext; + cptr = dentry->ext; for (i = 0; i < 3; i++) { if (*cname != '.' && *cname != '\0' && nidx++ < namelen) @@ -1435,66 +1474,46 @@ set_dentry_filename(fat_dir_entry_t *fde } *cptr = '\0'; - CYG_TRACE4(TDE, "filename='%s' namelen=%d dos_name='%s' dos_ext='%s'", - name, namelen, fde->name, fde->ext); + CYG_TRACE4(TDE, "filename='%s' namelen=%d dos name='%s' dos ext='%s'", + name, namelen, dentry->name, dentry->ext); } // ------------------------------------------------------------------------- -// get_next_dentry() +// read_next_raw_dentry() // Gets next dir entry searching from given position to the end. -// Position is expected in DENTRY_SIZE units. -// If EEOF is returned there are no more extries in given dir. +// If EEOF is returned there are no more entries in given dir. static int -get_next_dentry(fatfs_disk_t *disk, - fatfs_node_t *dir, - cyg_uint32 *pos, - fat_dir_entry_t *dentry) +read_next_raw_dentry(fatfs_disk_t *disk, + fatfs_data_pos_t *pos, + fat_raw_dir_entry_t *dentry) { - fatfs_data_pos_t dpos; - cyg_uint32 off; int err = ENOERR; - // Calculate dentry offset - off = *pos * DENTRY_SIZE; - - CYG_TRACE4(TDE, "pos=%d off=%d dir=%p cluster=%d", - off, *pos, dir, dir->cluster); - - // Root dir check - if (0 == dir->cluster) - { - dpos.cluster = 0; - dpos.cluster_snum = 0; - dpos.cluster_pos = off; - } - else - { - err = get_data_position_from_off(disk, dir->cluster, - off, &dpos, &dir->tcache, false); - if (err != ENOERR) - return err; - } - + // If we are reading the root dir on FAT32 we have + // to correct the position to the root dir cluster + if (FATFS_FAT32 == disk->fat_type && 0 == pos->cluster) + pos->cluster = disk->fat_root_dir_cluster; + while (true) { - // Root dir check - if (0 != dir->cluster) + // FAT12/16 root dir check + if (0 == pos->cluster) { - // Change cluster if needed - if (!is_pos_inside_cluster(disk, dpos.cluster_pos)) - err = get_next_cluster(disk, &dpos, &dir->tcache, CO_NONE); + if (pos->cluster_pos >= disk->fat_root_dir_nents) + err = EEOF; } else { - if (*pos >= disk->fat_root_dir_nents) - err = EEOF; + // Change cluster if needed + if (pos->cluster_pos >= disk->cluster_size) + err = get_next_cluster(disk, pos, CO_NONE); } if (err != ENOERR) break; - err = read_dentry(disk, &dpos, dentry); + err = read_raw_dentry(disk, pos, dentry); if (err != ENOERR) return err; @@ -1502,148 +1521,142 @@ get_next_dentry(fatfs_disk_t *disk, { // If we get a ZERO dir entry, we assume that // there are no more entries in current dir - CYG_TRACE0(TDE, "ZERO dentry"); + CYG_TRACE0(TDE, "end of dir"); err = EEOF; break; } else if (!DENTRY_IS_DELETED(dentry)) { // Dir entry found - CYG_TRACE3(TDE, "dentry_pos=%d cluster=%d pos=%d", - *pos, dpos.cluster, dpos.cluster_pos); + CYG_TRACE3(TDE, "found new dentry at cluster=%d snum=%d pos=%d", + pos->cluster, pos->cluster_snum, pos->cluster_pos); break; } - // Increment offset and position - dpos.cluster_pos += DENTRY_SIZE; - (*pos)++; + pos->cluster_pos += DENTRY_SIZE; } - if (EEOF == err) CYG_TRACE0(TDE, "end of dir"); - // EEOF could be returned if there are no more entries in this // dir - this should be cought by the calling function + return err; } // ------------------------------------------------------------------------- -// get_free_dentry() -// Gets free dir entry slot searching from given position. -// If an deleated entry is found, its clusters are freed and the -// entry is reused. -// The directory is extended if needed. +// get_free_raw_dentry() +// Gets free dir entry slot searching from given position extending the +// directory if needed. If an deleated entry is found it is reused. static int -get_free_dentry(fatfs_disk_t *disk, - fatfs_data_pos_t *dpos, - fatfs_tcache_t *tcache) +get_free_raw_dentry(fatfs_disk_t *disk, + fatfs_data_pos_t *pos) { - fat_dir_entry_t dentry; - fatfs_data_pos_t cdpos; - int err = ENOERR; + fat_raw_dir_entry_t raw_dentry; + fatfs_data_pos_t cpos; + int err = ENOERR; - CYG_TRACE3(TDE, "cluster=%d cluster_snum=%d cluster_pos=%d", - dpos->cluster, dpos->cluster_snum, dpos->cluster_pos); - cdpos = *dpos; + cpos = *pos; + // If we are reading the root dir on FAT32 we have + // to correct the position to the root dir cluster + if (FATFS_FAT32 == disk->fat_type && 0 == cpos.cluster) + cpos.cluster = disk->fat_root_dir_cluster; + + CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d", + pos->cluster, pos->cluster_snum, pos->cluster_pos); + while (true) { - // Root dir check - if (0 != cdpos.cluster) + // FAT12/16 root dir check + if (0 == cpos.cluster) { - // Change cluster if needed - if (!is_pos_inside_cluster(disk, cdpos.cluster_pos)) - err = get_next_cluster(disk, &cdpos, tcache, - CO_EXTEND | CO_ERASE_NEW); + if (cpos.cluster_pos >= disk->fat_root_dir_size) + err = ENOSPC; } else - { - if (cdpos.cluster_pos >= disk->fat_root_dir_size) - err = ENOSPC; + { + // Change cluster if needed + if (cpos.cluster_pos >= disk->cluster_size) + err = get_next_cluster(disk, &cpos, CO_EXTEND | CO_ERASE_NEW); } if (err != ENOERR) return err; - err = read_dentry(disk, &cdpos, &dentry); + err = read_raw_dentry(disk, &cpos, &raw_dentry); if (err != ENOERR) return err; - if (DENTRY_IS_DELETED(&dentry)) + if (DENTRY_IS_DELETED(&raw_dentry)) { - CYG_TRACE3(TDE, "deleted dentry at cluster=%d cluster_snum=%d " - "cluster_pos=%d", cdpos.cluster, cdpos.cluster_snum, - cdpos.cluster_pos); + CYG_TRACE3(TDE, "deleted dentry at cluster=%d snum=%d pos=%d", + cpos.cluster, cpos.cluster_snum, cpos.cluster_pos); - // Retrun found dentry position - *dpos = cdpos; + *pos = cpos; return ENOERR; } - else if (DENTRY_IS_ZERO(&dentry)) + else if (DENTRY_IS_ZERO(&raw_dentry)) { - CYG_TRACE3(TDE, "zero dentry at cluster=%d cluster_snum=%d " - "cluster_pos=%d", cdpos.cluster, cdpos.cluster_snum, - cdpos.cluster_pos); + CYG_TRACE3(TDE, "zero dentry at cluster=%d snum=%d pos=%d", + cpos.cluster, cpos.cluster_snum, cpos.cluster_pos); - // Retrun found dentry position - *dpos = cdpos; + *pos = cpos; return ENOERR; } - // Increment current position - cdpos.cluster_pos += DENTRY_SIZE; + cpos.cluster_pos += DENTRY_SIZE; } } // ------------------------------------------------------------------------- -// dentry_to_node() -// Converts FAT dir entry to node. +// raw_to_dentry() +// Converts raw FAT dir entry to dir entry. static void -dentry_to_node(fat_dir_entry_t *dentry, - fatfs_node_t *node) +raw_to_dentry(fat_raw_dir_entry_t *raw_dentry, + fatfs_data_pos_t *raw_dentry_pos, + fatfs_dir_entry_t *dentry) { - get_dentry_filename(dentry, node->filename); + get_raw_dentry_filename(raw_dentry, dentry->filename); - if (DENTRY_IS_DIR(dentry)) - node->mode = __stat_mode_DIR; + if (DENTRY_IS_DIR(raw_dentry)) + dentry->mode = __stat_mode_DIR; else - node->mode = __stat_mode_REG; + dentry->mode = __stat_mode_REG; - date_dos2unix(dentry->crt_time, dentry->crt_date, &node->ctime); - date_dos2unix(0, dentry->acc_date, &node->atime); - date_dos2unix(dentry->wrt_time, dentry->wrt_date, &node->mtime); + date_dos2unix(raw_dentry->crt_time, raw_dentry->crt_date, &dentry->ctime); + date_dos2unix(0, raw_dentry->acc_date, &dentry->atime); + date_dos2unix(raw_dentry->wrt_time, raw_dentry->wrt_date, &dentry->mtime); - node->size = dentry->size; - node->priv_data = dentry->nt_reserved; - node->cluster = dentry->cluster; - node->dentry_pos = dentry->pos; + dentry->size = raw_dentry->size; + dentry->priv_data = raw_dentry->nt_reserved; + dentry->cluster = raw_dentry->cluster | (raw_dentry->cluster_HI << 16); + dentry->disk_pos = *raw_dentry_pos; } // ------------------------------------------------------------------------- -// node_to_dentry() -// Converts node to FAT dir entry. +// dentry_to_raw() +// Converts dir entry to raw FAT dir entry. static void -node_to_dentry(fatfs_node_t *node, fat_dir_entry_t *dentry) +dentry_to_raw(fatfs_dir_entry_t *dentry, fat_raw_dir_entry_t *raw_dentry) { - set_dentry_filename(dentry, node->filename, 0); + set_raw_dentry_filename(raw_dentry, dentry->filename, 0); - if (node->mode == __stat_mode_DIR) - dentry->attr = DENTRY_ATTR_DIR; + if (__stat_mode_DIR == dentry->mode) + raw_dentry->attr = DENTRY_ATTR_DIR; else - dentry->attr = DENTRY_ATTR_ARCHIVE; + raw_dentry->attr = DENTRY_ATTR_ARCHIVE; - date_unix2dos(node->ctime, &dentry->crt_time, &dentry->crt_date); - date_unix2dos(node->atime, NULL, &dentry->acc_date); - date_unix2dos(node->mtime, &dentry->wrt_time, &dentry->wrt_date); + date_unix2dos(dentry->ctime, &raw_dentry->crt_time, &raw_dentry->crt_date); + date_unix2dos(dentry->atime, NULL, &raw_dentry->acc_date); + date_unix2dos(dentry->mtime, &raw_dentry->wrt_time, &raw_dentry->wrt_date); - dentry->crt_sec_100 = 0; //FIXME - dentry->size = node->size; - dentry->nt_reserved = node->priv_data; - dentry->cluster = node->cluster; - dentry->cluster_HI = 0; - dentry->pos = node->dentry_pos; + raw_dentry->crt_sec_100 = 0; //FIXME + raw_dentry->size = dentry->size; + raw_dentry->nt_reserved = dentry->priv_data; + raw_dentry->cluster = dentry->cluster & 0xFFFF; + raw_dentry->cluster_HI = dentry->cluster >> 16; } //========================================================================== @@ -1657,59 +1670,49 @@ static int read_data(fatfs_disk_t *disk, void *data, cyg_uint32 *len, - fatfs_data_pos_t *dpos, - fatfs_tcache_t *tcache) + fatfs_data_pos_t *pos) { - unsigned char *buf; - cyg_uint32 apos; - cyg_uint32 size; - int err; + cyg_uint8 *buf = (cyg_uint8 *) data; + cyg_uint32 size = *len; + int err = ENOERR; - // Initialize variables and get the absolute starting pos on disk - buf = (unsigned char *)data; - size = *len; - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); - err = ENOERR; - - CYG_TRACE5(TDO, "len=%d cluster=%d cluster_pos=%d " - "cluster_snum=%d apos=%d", *len, dpos->cluster, - dpos->cluster_pos, dpos->cluster_snum, apos); + CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d", + *len, pos->cluster, pos->cluster_snum, + pos->cluster_pos); while (size > 0) { cyg_uint32 csize; // Check if we are still inside current cluster - if (!is_pos_inside_cluster(disk, dpos->cluster_pos)) + if (pos->cluster_pos >= disk->cluster_size) { - // Get next cluster of file and adjust absolute disk position - err = get_next_cluster(disk, dpos, tcache, CO_NONE); + // Get next cluster of file + err = get_next_cluster(disk, pos, CO_NONE); if (err != ENOERR) goto out; - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); } // Adjust the data chunk size to be read to the cluster boundary - if (size > (disk->cluster_size - dpos->cluster_pos)) - csize = disk->cluster_size - dpos->cluster_pos; + if (size > (disk->cluster_size - pos->cluster_pos)) + csize = disk->cluster_size - pos->cluster_pos; else csize = size; - CYG_TRACE5(TDO, "-- len=%d cluster=%d cluster_pos=%d " - "cluster_snum=%d apos=%d", csize, dpos->cluster, - dpos->cluster_pos, dpos->cluster_snum, apos); + CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d", + csize, pos->cluster, pos->cluster_snum, + pos->cluster_pos); - // Read data chunk - err = cyg_blib_read(&disk->blib, (void*)buf, &csize, 0, apos); - + err = disk_cluster_read(disk, (void*)buf, &csize, + pos->cluster, pos->cluster_pos); if (err != ENOERR) goto out; // Adjust running variables - buf += csize; - dpos->cluster_pos += csize; - apos += csize; - size -= csize; + + buf += csize; + pos->cluster_pos += csize; + size -= csize; } out: @@ -1728,60 +1731,50 @@ static int write_data(fatfs_disk_t *disk, void *data, cyg_uint32 *len, - fatfs_data_pos_t *dpos, - fatfs_tcache_t *tcache) + fatfs_data_pos_t *pos) { - unsigned char *buf; - cyg_uint32 apos; - cyg_uint32 size; - int err; + cyg_uint8 *buf = (cyg_uint8 *) data; + cyg_uint32 size = *len; + int err = ENOERR; - // Initialize variables and get the absolute starting pos on disk - buf = (unsigned char *)data; - size = *len; - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); - err = ENOERR; - - CYG_TRACE5(TDO, "len=%d cluster=%d cluster_pos=%d " - "cluster_snum=%d apos=%d", *len, dpos->cluster, - dpos->cluster_pos, dpos->cluster_snum, apos); + CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d", + *len, pos->cluster, pos->cluster_snum, + pos->cluster_pos); while (size > 0) { cyg_uint32 csize; // Check if we are still inside current cluster - if (!is_pos_inside_cluster(disk, dpos->cluster_pos)) + if (pos->cluster_pos >= disk->cluster_size) { - // Get next cluster of file and adjust absolute disk position, - // if at the last cluster try to extend the cluster chain - err = get_next_cluster(disk, dpos, tcache, CO_EXTEND); + // Get next cluster of file, if at the last + // cluster try to extend the cluster chain + err = get_next_cluster(disk, pos, CO_EXTEND); if (err != ENOERR) goto out; - apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos); } // Adjust the data chunk size to be read to the cluster boundary - if (size > (disk->cluster_size - dpos->cluster_pos)) - csize = disk->cluster_size - dpos->cluster_pos; + if (size > (disk->cluster_size - pos->cluster_pos)) + csize = disk->cluster_size - pos->cluster_pos; else csize = size; - CYG_TRACE5(TDO, "-- len=%d cluster=%d cluster_pos=%d " - "cluster_snum=%d apos=%d", csize, dpos->cluster, - dpos->cluster_pos, dpos->cluster_snum, apos); + CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d", + csize, pos->cluster, pos->cluster_snum, + pos->cluster_pos); - // Write data chunk - err = cyg_blib_write(&disk->blib, (void*)buf, &csize, 0, apos); - + err = disk_cluster_write(disk, (void*)buf, &csize, + pos->cluster, pos->cluster_pos); if (err != ENOERR) goto out; // Adjust running variables - buf += csize; - dpos->cluster_pos += csize; - apos += csize; - size -= csize; + + buf += csize; + pos->cluster_pos += csize; + size -= csize; } out: @@ -1796,43 +1789,44 @@ out: // Misc functions // ------------------------------------------------------------------------- -// init_node() -// Initializes file attributes of a new node. +// init_dir_entry() +// Initializes attributes of a new dir entry. static void -init_node_fattr(fatfs_node_t *node, - const char *name, - int namelen, - mode_t mode, - cyg_uint32 parent_cluster, - fatfs_data_pos_t *dentry_pos) +init_dir_entry(fatfs_dir_entry_t *dentry, + const char *name, + int namelen, + mode_t mode, + cyg_uint32 parent_cluster, + cyg_uint32 first_cluster, + fatfs_data_pos_t *pos) { - if (namelen == 0) + if (0 == namelen) namelen = 12; - strncpy(node->filename, name, namelen); - node->filename[namelen] = '\0'; + strncpy(dentry->filename, name, namelen); + dentry->filename[namelen] = '\0'; - node->mode = mode; - node->ctime = - node->atime = - node->mtime = cyg_timestamp(); + dentry->mode = mode; + dentry->ctime = + dentry->atime = + dentry->mtime = cyg_timestamp(); - node->priv_data = 0; - node->size = 0; - node->cluster = 0; - node->parent_cluster = parent_cluster; - node->dentry_pos = *dentry_pos; + dentry->priv_data = 0; + dentry->size = 0; + dentry->cluster = first_cluster; + dentry->parent_cluster = parent_cluster; + dentry->disk_pos = *pos; } // ------------------------------------------------------------------------- -// is_node_root_node() -// Check if the given node is the root dir node +// is_root_dir_entry() +// Check if the given dir entry is the root dir entry. static __inline__ bool -is_node_root_node(fatfs_node_t *node) +is_root_dir_entry(fatfs_dir_entry_t *dentry) { - return (node->filename[0] == '\0' && node->cluster == 0); + return ('\0' == dentry->filename[0] && 0 == dentry->cluster); } //========================================================================== @@ -1840,16 +1834,16 @@ is_node_root_node(fatfs_node_t *node) // Exported functions // ------------------------------------------------------------------------- -// fatfs_get_disk_info() +// fatfs_init() // Gets disk info. int -fatfs_get_disk_info(fatfs_disk_t *disk) +fatfs_init(fatfs_disk_t *disk) { - int err; - cyg_uint32 sec_num, root_dir_sec_num; - cyg_uint32 data_sec_num, data_clu_num; + cyg_uint32 sec_num, sec_per_fat, root_dir_sec_num; + cyg_uint32 data_sec_num, data_clu_num; fat_boot_record_t boot_rec; + int err; CYG_CHECK_DATA_PTRC(disk); @@ -1863,11 +1857,27 @@ fatfs_get_disk_info(fatfs_disk_t *disk) 0xAA != boot_rec.exe_marker[1]) return EINVAL; + // Sector and cluster sizes + disk->sector_size = boot_rec.bytes_per_sec; + disk->sector_size_log2 = get_val_log2(disk->sector_size); + disk->cluster_size = boot_rec.bytes_per_sec * boot_rec.sec_per_clu; + disk->cluster_size_log2 = get_val_log2(disk->cluster_size); + + // Sector and cluster size should always be a power of 2 + if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2) + return EINVAL; + // Determine number of sectors if (boot_rec.sec_num_32 != 0) sec_num = boot_rec.sec_num_32; else sec_num = boot_rec.sec_num; + + // Determine number of sectors per fat + if (boot_rec.sec_per_fat != 0) + sec_per_fat = boot_rec.sec_per_fat; + else + sec_per_fat = boot_rec.sec_per_fat_32; // Number of sectors used by root directory root_dir_sec_num = ((boot_rec.max_root_dents * DENTRY_SIZE) + @@ -1875,167 +1885,252 @@ fatfs_get_disk_info(fatfs_disk_t *disk) // Number of data sectors data_sec_num = sec_num - (boot_rec.res_sec_num + - (boot_rec.fat_tbls_num * boot_rec.sec_per_fat) + root_dir_sec_num); + (boot_rec.fat_tbls_num * sec_per_fat) + root_dir_sec_num); // Number of data clusters - data_clu_num = data_sec_num / boot_rec.sec_per_clust; + data_clu_num = data_sec_num / boot_rec.sec_per_clu; + + // FAT table size and position + disk->fat_tbl_pos = boot_rec.bytes_per_sec * boot_rec.res_sec_num; + disk->fat_tbl_size = boot_rec.bytes_per_sec * sec_per_fat; + disk->fat_tbl_nents = data_clu_num + 2; + disk->fat_tbls_num = boot_rec.fat_tbls_num; // Determine the type of FAT based on number of data clusters - if (data_clu_num < 4085) - disk->fat_type = FATFS_FAT12; + if (data_clu_num < 4085) + disk->fat_type = FATFS_FAT12; else if (data_clu_num < 65525) - disk->fat_type = FATFS_FAT16; - else // FAT32 - return EINVAL; + disk->fat_type = FATFS_FAT16; + else + disk->fat_type = FATFS_FAT32; + + // Determine root dir and data positions + if (FATFS_FAT32 != disk->fat_type) + { + disk->fat_root_dir_pos = disk->fat_tbl_pos + + disk->fat_tbls_num * disk->fat_tbl_size; + disk->fat_root_dir_size = boot_rec.max_root_dents * DENTRY_SIZE; + disk->fat_root_dir_nents = boot_rec.max_root_dents; + disk->fat_root_dir_cluster = 0; + disk->fat_data_pos = disk->fat_root_dir_pos + + disk->fat_root_dir_size; + } + else + { + disk->fat_root_dir_pos = 0; + disk->fat_root_dir_size = 0; + disk->fat_root_dir_nents = 0; + disk->fat_root_dir_cluster = boot_rec.root_cluster; + disk->fat_data_pos = disk->fat_tbl_pos + + disk->fat_tbls_num * disk->fat_tbl_size; + } - // Sector and cluster sizes - disk->sector_size = boot_rec.bytes_per_sec; - disk->sector_size_log2 = get_val_log2(disk->sector_size); - disk->cluster_size = boot_rec.bytes_per_sec * boot_rec.sec_per_clust; - disk->cluster_size_log2 = get_val_log2(disk->cluster_size); + return ENOERR; +} + +// ------------------------------------------------------------------------- +// fatfs_get_root_dir_entry() +// Gets root dir entry. + +void +fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry) +{ + CYG_CHECK_DATA_PTRC(disk); + CYG_CHECK_DATA_PTRC(dentry); + + dentry->mode = __stat_mode_DIR; + dentry->size = disk->fat_root_dir_size; + dentry->ctime = 0; + dentry->atime = 0; + dentry->mtime = 0; + dentry->filename[0] = '\0'; + dentry->cluster = 0; + dentry->parent_cluster = 0; + + dentry->disk_pos.cluster = 0; + dentry->disk_pos.cluster_snum = 0; + dentry->disk_pos.cluster_pos = 0; +} + +// ------------------------------------------------------------------------- +// fatfs_get_disk_usage() +// Gets disk space. + +int +fatfs_get_disk_usage(fatfs_disk_t *disk, + cyg_uint32 *total_clusters, + cyg_uint32 *free_clusters) +{ + cyg_uint32 c, nfree, tentry; + int err; - // Sector and cluster size should always be a power of 2 - if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2) - return EINVAL; + nfree = 0; + for (c = 2; c < disk->fat_tbl_nents; c++) + { + err = read_tentry(disk, c, &tentry); + if (err != ENOERR) + return err; + + if (TENTRY_FREE == get_tentry_type(disk, tentry)) + nfree++; + } + + *total_clusters = disk->fat_tbl_nents - 2; + *free_clusters = nfree; + + return ENOERR; +} + + +// ------------------------------------------------------------------------- +// fatfs_read_dir_entry() +// Reads dir entry at given position. +// If there is no dir entry at given position the next closest is returned +// and the position is updated. If EEOF error is returned, then there are +// no more dir entries in given dir. + +int +fatfs_read_dir_entry(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + fatfs_data_pos_t *pos, + fatfs_dir_entry_t *dentry) +{ + fat_raw_dir_entry_t raw_dentry; + int err; - // FAT table and root dir sizes and position - disk->fat_tbl_pos = boot_rec.bytes_per_sec * boot_rec.res_sec_num; - disk->fat_tbl_size = boot_rec.bytes_per_sec * boot_rec.sec_per_fat; - disk->fat_tbl_nents = data_clu_num + 2; - disk->fat_tbls_num = boot_rec.fat_tbls_num; - disk->fat_root_dir_pos = disk->fat_tbl_pos + - disk->fat_tbls_num * disk->fat_tbl_size; - disk->fat_root_dir_size = boot_rec.max_root_dents * DENTRY_SIZE; - disk->fat_root_dir_nents = boot_rec.max_root_dents; - disk->fat_data_pos = disk->fat_root_dir_pos + disk->fat_root_dir_size; + CYG_CHECK_DATA_PTRC(disk); + CYG_CHECK_DATA_PTRC(dir); + CYG_CHECK_DATA_PTRC(pos); + CYG_CHECK_DATA_PTRC(dentry); + + err = read_next_raw_dentry(disk, pos, &raw_dentry); + if (err != ENOERR) + return err; + + raw_to_dentry(&raw_dentry, pos, dentry); + dentry->parent_cluster = dir->cluster; + + // Increment position for next call + pos->cluster_pos += DENTRY_SIZE; + + return ENOERR; +} + +// ------------------------------------------------------------------------- +// fatfs_initpos() +// Initializes position to the start of the given file. + +int +fatfs_initpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos) +{ + CYG_CHECK_DATA_PTRC(disk); + CYG_CHECK_DATA_PTRC(file); + CYG_CHECK_DATA_PTRC(pos); + + pos->cluster = file->cluster; + pos->cluster_snum = 0; + pos->cluster_pos = 0; return ENOERR; } // ------------------------------------------------------------------------- -// fatfs_get_root_node() -// Gets root dir node. +// fatfs_setpos() +// Sets the file position from offset. -void -fatfs_get_root_node(fatfs_disk_t *disk, fatfs_node_t *node) +int +fatfs_setpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + cyg_uint32 offset) { CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(file); + CYG_CHECK_DATA_PTRC(pos); - node->mode = __stat_mode_DIR; - node->size = disk->fat_root_dir_size; - node->ctime = 0; - node->atime = 0; - node->mtime = 0; - node->filename[0] = '\0'; - node->cluster = 0; - node->parent_cluster = 0; - - node->dentry_pos.cluster = 0; - node->dentry_pos.cluster_snum = 0; - node->dentry_pos.cluster_pos = 0; -} - -// ------------------------------------------------------------------------- -// fatfs_is_node_root_node() -// Check if the given node is root dir node. - -bool -fatfs_is_node_root_node(fatfs_node_t *node) -{ - return(is_node_root_node(node)); + return get_position_from_off(disk, file->cluster, offset, pos, CO_NONE); } // ------------------------------------------------------------------------- -// fatfs_get_dir_entry_node() -// Gets dir entry node at given position. -// If there is no dir entry at given position the next closest -// dir entry and its position are returned. -// If EEOF error is returned, then there are no more dir -// entries in given dir. +// fatfs_getpos() +// Gets the file offset from position. -int -fatfs_get_dir_entry_node(fatfs_disk_t *disk, - fatfs_node_t *dir, - cyg_uint32 *pos, - fatfs_node_t *node) +cyg_uint32 +fatfs_getpos(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos) { - fat_dir_entry_t dentry; - int err; - CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(dir); + CYG_CHECK_DATA_PTRC(file); CYG_CHECK_DATA_PTRC(pos); - CYG_CHECK_DATA_PTRC(node); - - err = get_next_dentry(disk, dir, pos, &dentry); - - if (err != ENOERR) - return err; - - dentry_to_node(&dentry, node); - node->parent_cluster = dir->cluster; - - return ENOERR; + + return (pos->cluster_snum << disk->cluster_size_log2) + pos->cluster_pos; } // ------------------------------------------------------------------------- -// fatfs_write_node() -// Writes node attributes to its dir entry (to disk). +// fatfs_write_dir_entry() +// Writes dir entry to disk. int -fatfs_write_file_attr(fatfs_disk_t *disk, fatfs_node_t *node) +fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry) { - fat_dir_entry_t dentry; - int err; + fat_raw_dir_entry_t raw_dentry; + int err; CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(dentry); - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + dentry_to_raw(dentry, &raw_dentry); + err = write_raw_dentry(disk, &dentry->disk_pos, &raw_dentry); return err; } // ------------------------------------------------------------------------- // fatfs_delete_file() -// Marks file dir entry as deleted. +// Marks dir entry as deleted and frees its cluster chain. int -fatfs_delete_file(fatfs_disk_t *disk, fatfs_node_t *node) +fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file) { - fat_dir_entry_t dentry; - int err; + fat_raw_dir_entry_t raw_dentry; + int err; CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(file); - // Can't delete root - if (is_node_root_node(node)) + if (is_root_dir_entry(file)) return EINVAL; - CYG_TRACE1(TDE, "filename='%s'", node->filename); + CYG_TRACE1(TDE, "filename='%s'", file->filename); - node_to_dentry(node, &dentry); + dentry_to_raw(file, &raw_dentry); // Check if we are about to delete a directory - if (DENTRY_IS_DIR(&dentry)) + if (DENTRY_IS_DIR(&raw_dentry)) { - fat_dir_entry_t cdentry; - cyg_uint32 pos = 0; - int i = 0; + fat_raw_dir_entry_t raw_cdentry; + fatfs_data_pos_t pos; + int i = 0; + + fatfs_initpos(disk, file, &pos); CYG_TRACE0(TDE, "got directory"); + // Count number of entries in this dir + while (true) { - err = get_next_dentry(disk, node, &pos, &cdentry); + err = read_next_raw_dentry(disk, &pos, &raw_cdentry); if (EEOF == err) break; else if (err != ENOERR) return err; - i++; pos++; + + pos.cluster_pos += DENTRY_SIZE; + i++; } CYG_TRACE1(TDE, "child count=%d", i); @@ -2045,9 +2140,9 @@ fatfs_delete_file(fatfs_disk_t *disk, fa } // Free file clusters - free_cluster_chain(disk, dentry.cluster); - dentry_set_deleted(disk, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + free_cluster_chain(disk, raw_dentry.cluster); + raw_dentry_set_deleted(disk, &raw_dentry); + err = write_raw_dentry(disk, &file->disk_pos, &raw_dentry); return err; } @@ -2056,38 +2151,40 @@ fatfs_delete_file(fatfs_disk_t *disk, fa // Creates a new file. int -fatfs_create_file(fatfs_disk_t *disk, - fatfs_node_t *dir, - const char *name, - int namelen, - fatfs_node_t *node) +fatfs_create_file(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + const char *name, + int namelen, + fatfs_dir_entry_t *dentry) { - fat_dir_entry_t dentry; - int err; + fatfs_data_pos_t pos; + int err; CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(dir); CYG_CHECK_DATA_PTRC(name); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(dentry); CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename); - dentry.pos.cluster = dir->cluster; - dentry.pos.cluster_snum = 0; - dentry.pos.cluster_pos = 0; + fatfs_initpos(disk, dir, &pos); // Get free dir entry in parent dir - err = get_free_dentry(disk, &dentry.pos, &dir->tcache); + err = get_free_raw_dentry(disk, &pos); if (err != ENOERR) return err; - // Set new file attributes - init_node_fattr(node, name, namelen, __stat_mode_REG, - dir->cluster, &dentry.pos); + // Create new file dir entry + + init_dir_entry(dentry, + name, + namelen, + __stat_mode_REG, + dir->cluster, + 0, + &pos); - // Write new dir dentry - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + err = fatfs_write_dir_entry(disk, dentry); if (err != ENOERR) return err; @@ -2099,78 +2196,84 @@ fatfs_create_file(fatfs_disk_t *disk, // Creates a new directory. int -fatfs_create_dir(fatfs_disk_t *disk, - fatfs_node_t *dir, - const char *name, - int namelen, - fatfs_node_t *node) +fatfs_create_dir(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir, + const char *name, + int namelen, + fatfs_dir_entry_t *dentry) { - fat_dir_entry_t dentry; - fatfs_node_t cnode; - cyg_uint32 free_cluster; - int err; + fatfs_dir_entry_t cdentry; + fatfs_data_pos_t pos; + cyg_uint32 free_cluster; + int err; CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(dir); CYG_CHECK_DATA_PTRC(name); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(dentry); CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename); // Get free cluster - err = find_next_free_cluster(disk, 0, &free_cluster, + err = find_next_free_cluster(disk, + 0, + &free_cluster, CO_MARK_LAST | CO_ERASE_NEW); if (err != ENOERR) return err; - dentry.pos.cluster = dir->cluster; - dentry.pos.cluster_snum = 0; - dentry.pos.cluster_pos = 0; + fatfs_initpos(disk, dir, &pos); // Get free dir entry in parent dir - err = get_free_dentry(disk, &dentry.pos, &dir->tcache); + err = get_free_raw_dentry(disk, &pos); if (err != ENOERR) return err; - // Set new dir attributes - init_node_fattr(node, name, namelen, __stat_mode_DIR, - dir->cluster, &dentry.pos); - node->cluster = free_cluster; + // Create new dir entry - // Write new dir dentry - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + init_dir_entry(dentry, + name, + namelen, + __stat_mode_DIR, + dir->cluster, + free_cluster, + &pos); + + err = fatfs_write_dir_entry(disk, dentry); if (err != ENOERR) return err; - // Starting position of new dir entries - dentry.pos.cluster = node->cluster; - dentry.pos.cluster_snum = 0; - dentry.pos.cluster_pos = 0; + // Create '.' and '..' dir entries + + fatfs_initpos(disk, dentry, &pos); CYG_TRACE0(TDE, "Creating '.' entry"); - // Set '.' dir attributes - init_node_fattr(&cnode, ".", 0, __stat_mode_DIR, - node->cluster, &dentry.pos); - cnode.cluster = node->cluster; - // Write '.' dentry - node_to_dentry(&cnode, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + init_dir_entry(&cdentry, + ".", + 0, + __stat_mode_DIR, + dentry->cluster, + dentry->cluster, + &pos); + + err = fatfs_write_dir_entry(disk, &cdentry); if (err != ENOERR) return err; - dentry.pos.cluster_pos += DENTRY_SIZE; + pos.cluster_pos += DENTRY_SIZE; CYG_TRACE0(TDE, "Creating '..' entry"); - // Set '..' dir attributes - init_node_fattr(&cnode, "..", 0, __stat_mode_DIR, - node->cluster, &dentry.pos); - cnode.cluster = dir->cluster; - // Write '..' dentry - node_to_dentry(&cnode, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); + init_dir_entry(&cdentry, + "..", + 0, + __stat_mode_DIR, + dentry->cluster, + dir->cluster, + &pos); + + err = fatfs_write_dir_entry(disk, &cdentry); if (err != ENOERR) return err; @@ -2182,45 +2285,33 @@ fatfs_create_dir(fatfs_disk_t *disk, // Truncates a file to zero length. int -fatfs_trunc_file(fatfs_disk_t *disk, fatfs_node_t *node) +fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file) { - fat_dir_entry_t dentry; int err; CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(file); - CYG_TRACE1(TDE, "file='%s'", node->filename); + CYG_TRACE1(TDE, "file='%s'", file->filename); - // Check for dir - if (S_ISDIR(node->mode)) + if (S_ISDIR(file->mode)) return EINVAL; - // Trivial case check - if (0 == node->size) + if (0 == file->size) return ENOERR; - // Free cluster chain - err = free_cluster_chain(disk, node->cluster); + err = free_cluster_chain(disk, file->cluster); if (err != ENOERR) return err; - // Flush tcache - fatfs_tcache_flush(disk, &node->tcache); - - // Update node attributes - node->cluster = 0; - node->size = 0; - node->mtime = - node->atime = cyg_timestamp(); + // Update file attributes - // Write dentry - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); - if (err != ENOERR) - return err; - - return ENOERR; + file->cluster = 0; + file->size = 0; + file->mtime = + file->atime = cyg_timestamp(); + + return fatfs_write_dir_entry(disk, file); } // ------------------------------------------------------------------------- @@ -2228,104 +2319,105 @@ fatfs_trunc_file(fatfs_disk_t *disk, fat // Renames a file. int -fatfs_rename_file(fatfs_disk_t *disk, - fatfs_node_t *dir1, - fatfs_node_t *node, - fatfs_node_t *dir2, - const char *name, - int namelen) +fatfs_rename_file(fatfs_disk_t *disk, + fatfs_dir_entry_t *dir1, + fatfs_dir_entry_t *target, + fatfs_dir_entry_t *dir2, + const char *name, + int namelen) { - fat_dir_entry_t dentry; - fatfs_data_pos_t dpos; - int err; + fat_raw_dir_entry_t raw_dentry; + fatfs_data_pos_t new_pos; + int err; CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(dir1); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(target); CYG_CHECK_DATA_PTRC(dir2); CYG_CHECK_DATA_PTRC(name); - // Can't rename root - if (is_node_root_node(node)) + if (is_root_dir_entry(target)) return EINVAL; - CYG_TRACE5(TDE, "dir1=%p '%s' to dir2=%p '%s' (%d)", - dir1, node->filename, dir2, name, namelen); - - strncpy(node->filename, name, namelen); - node->filename[namelen] = '\0'; + strncpy(target->filename, name, namelen); + target->filename[namelen] = '\0'; // Moving around in same dir + if (dir1 == dir2) { - CYG_TRACE0(TDE, "same dir"); - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dentry.pos, &dentry); - return err; + CYG_TRACE0(TDE, "same dir"); + return fatfs_write_dir_entry(disk, target); } CYG_TRACE0(TDE, "different dirs"); // Moveing around in different dirs - dpos.cluster = dir2->cluster; - dpos.cluster_snum = 0; - dpos.cluster_pos = 0; + fatfs_initpos(disk, dir2, &new_pos); CYG_TRACE0(TDE, "writting to new dir"); // Get free dir entry in target dir - err = get_free_dentry(disk, &dpos, &dir2->tcache); + + err = get_free_raw_dentry(disk, &new_pos); if (err != ENOERR) return err; - // Write node dentry to new location - node_to_dentry(node, &dentry); - err = write_dentry(disk, &dpos, &dentry); + // Write file dentry to new location + + dentry_to_raw(target, &raw_dentry); + err = write_raw_dentry(disk, &new_pos, &raw_dentry); if (err != ENOERR) return err; CYG_TRACE0(TDE, "deleting from old dir"); // Deleate dentry at old location - dentry_set_deleted(disk, &dentry); - dentry.size = 0; - dentry.cluster = 0; - err = write_dentry(disk, &dentry.pos, &dentry); + + raw_dentry_set_deleted(disk, &raw_dentry); + raw_dentry.size = 0; + raw_dentry.cluster = 0; + err = write_raw_dentry(disk, &target->disk_pos, &raw_dentry); if (err != ENOERR) return err; - // Set node new position and parent cluster - node->dentry_pos = dpos; - node->parent_cluster = dir2->cluster; + // Set file new position and parent cluster + + target->disk_pos = new_pos; + target->parent_cluster = dir2->cluster; // If we moved a directory, we also have to correct the '..' entry - if (__stat_mode_DIR == node->mode) + + if (__stat_mode_DIR == target->mode) { - fat_dir_entry_t cdentry; - cyg_uint32 pos = 0; - + fat_raw_dir_entry_t raw_cdentry; + fatfs_data_pos_t pos; + + fatfs_initpos(disk, target, &pos); + CYG_TRACE0(TDE, "moving directory - correcting '..' entry"); while (true) { - err = get_next_dentry(disk, node, &pos, &cdentry); + err = read_next_raw_dentry(disk, &pos, &raw_cdentry); if (EEOF == err) - return EIO; // This dir doesn't have the '..' entry, - // that means something is very wrong + return EINVAL; // This dir doesn't have the '..' entry, + // that means something is very wrong else if (err != ENOERR) return err; - if (0 == strncmp("..", cdentry.name, 2)) + if (0 == strncmp("..", raw_cdentry.name, 2)) { - cdentry.cluster = dir2->cluster; - err = write_dentry(disk, &cdentry.pos, &cdentry); + raw_cdentry.cluster = dir2->cluster; + err = write_raw_dentry(disk, &pos, &raw_cdentry); if (err != ENOERR) return err; break; } - pos++; + + pos.cluster_pos += DENTRY_SIZE; } } @@ -2337,27 +2429,19 @@ fatfs_rename_file(fatfs_disk_t *disk, // Reads data from disk. int -fatfs_read_data(fatfs_disk_t *disk, - fatfs_node_t *node, - void *data, - cyg_uint32 *len, - cyg_uint32 off) +fatfs_read_data(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + void *data, + cyg_uint32 *len) { - int err; - fatfs_data_pos_t dpos; - CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(file); CYG_CHECK_DATA_PTRC(data); CYG_CHECK_DATA_PTRC(len); - - err = get_data_position_from_off(disk, node->cluster, off, - &dpos, &node->tcache, CO_NONE); - if (err != ENOERR) - return err; + CYG_CHECK_DATA_PTRC(pos); - err = read_data(disk, data, len, &dpos, &node->tcache); - return err; + return read_data(disk, data, len, pos); } // ------------------------------------------------------------------------- @@ -2365,47 +2449,41 @@ fatfs_read_data(fatfs_disk_t *disk, // Writes data to disk. int -fatfs_write_data(fatfs_disk_t *disk, - fatfs_node_t *node, - void *data, - cyg_uint32 *len, - cyg_uint32 off) +fatfs_write_data(fatfs_disk_t *disk, + fatfs_dir_entry_t *file, + fatfs_data_pos_t *pos, + void *data, + cyg_uint32 *len) { int err; - fatfs_data_pos_t dpos; CYG_CHECK_DATA_PTRC(disk); - CYG_CHECK_DATA_PTRC(node); + CYG_CHECK_DATA_PTRC(file); CYG_CHECK_DATA_PTRC(data); CYG_CHECK_DATA_PTRC(len); + CYG_CHECK_DATA_PTRC(pos); // Check if this file has a zero size and no first cluster - if (0 == node->size && 0 == node->cluster) + + if (0 == file->size && 0 == file->cluster) { cyg_uint32 free_cluster; CYG_TRACE0(TDO, "new cluster for zero file"); - // Get free cluster + err = find_next_free_cluster(disk, 0, &free_cluster, CO_MARK_LAST); + if (err != ENOERR) { *len = 0; return err; } - node->cluster = free_cluster; + + file->cluster = free_cluster; + fatfs_initpos(disk, file, pos); } - err = get_data_position_from_off(disk, node->cluster, off, - &dpos, &node->tcache, - CO_MARK_LAST | CO_EXTEND); - if (err != ENOERR) - { - *len = 0; - return err; - } - - err = write_data(disk, data, len, &dpos, &node->tcache); - return err; + return write_data(disk, data, len, pos); } // -------------------------------------------------------------------------