static int fatfs_find(fatfs_dirsearch_t *ds) { int err; 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 for(;;) { err = find_entry(ds); if (err != ENOERR) return err; if (ds->last) { CYG_TRACE0(TFS, "entry found"); return ENOERR; } // 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); } }
externC cyg_uint32 hal_arch_default_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data) { CYG_TRACE1(true, "Interrupt: %d", vector); CYG_FAIL("Spurious Interrupt!!!"); return 0; }
void fatfs_node_ref(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->dentry.filename, node->refcnt); node->refcnt++; if (1 == node->refcnt) { // 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); } SANITY_CHECK(); }
fatfs_node_t* fatfs_node_alloc(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry) { fatfs_node_t *node; CYG_CHECK_DATA_PTRC(disk); CYG_CHECK_DATA_PTRC(dentry); node = node_pool_alloc(disk); if (NULL == node) { CYG_TRACE2(TNC, "getting node from dead list (size=%d keep=%d)", node_list_get_size(&disk->dead_nlist), DLIST_KEEP_NUM); if (node_list_get_size(&disk->dead_nlist) <= DLIST_KEEP_NUM) return NULL; node = node_list_tail_get(&disk->dead_nlist); if (NULL == node) return NULL; CYG_TRACE1(TNC, "recycling node='%s'", node->dentry.filename); 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 node->dentry = *dentry; node->refcnt = 0; 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 node; }
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->dentry.filename, node->refcnt); CYG_ASSERT(node->refcnt > 0, "node->refcnt <= 0"); node->refcnt--; if (0 == node->refcnt) { // No more references - move node from live to dead list 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); } SANITY_CHECK(); }
externC cyg_uint32 hal_default_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data) { CYG_TRACE1(true, "Interrupt: %d", vector); #ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS #ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT #ifdef CYGDBG_HAL_CTRLC_ISR // then see if it is an incoming character interrupt and break // into the stub ROM if the char is a ^C. if ( CYGDBG_HAL_CTRLC_ISR( vector, data ) ) return 1; // interrupt handled #endif #endif #endif diag_printf("Spurious Interrupt!!! - vector: %d, data: %x\n", vector, data); CYG_FAIL("Spurious Interrupt!!!"); return 0; }
static int fatfs_fo_close(struct CYG_FILE_TAG *fp) { 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); // Write file attributes to disk, unreference // the file node and free its private data if (node != disk->root) err = fatfs_write_dir_entry(disk, &node->dentry); fatfs_node_unref(disk, node); free_fatfs_fd(fd); return err; }
static int find_entry(fatfs_dirsearch_t *ds) { const char *name = ds->path; const char *n = name; char namelen = 0; int err; if( !S_ISDIR(ds->dir->dentry.mode) ) { CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename); return ENOTDIR; } // Isolate the next element of the path name while (*n != '\0' && *n != '/') n++, namelen++; // If we terminated on a NUL, set last flag if (*n == '\0') ds->last = true; // Update name in dirsearch object ds->name = name; ds->namelen = namelen; err = find_direntry(ds); if (err != ENOERR) return err; CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found")); if (ds->node != NULL) return ENOERR; else return ENOENT; }
static int fatfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name, int mode, cyg_file *file) { 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", mte, dir, name, mode, file); init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name); err = fatfs_find(&ds); if (err == ENOENT) { if (ds.last && (mode & O_CREAT)) { 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); 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, &new_file_dentry); if (NULL == node) return EMFILE; // Update directory times ds.dir->dentry.atime = ds.dir->dentry.mtime = cyg_timestamp(); err = ENOERR; } } else if (err == ENOERR) { // The node exists. If the O_CREAT and O_EXCL bits are set, we // must fail the open if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) err = EEXIST; else node = ds.node; } 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->dentry); } if (err != ENOERR) return err; if (S_ISDIR(node->dentry.mode)) return EISDIR; #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES // if the file is read only and is opened for writing // fail with permission error if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY)) return EACCES; #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES // 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->dentry.size : 0; file->f_data = (CYG_ADDRWORD) fd; file->f_xops = 0; return ENOERR; }
static int fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte) { 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); init_fatfs_fds(); CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname); err = cyg_io_lookup(mte->devname, &dev_h); if (err != ENOERR) return err; disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t)); if (NULL == disk) return ENOMEM; CYG_TRACE0(TFS, "initializing block cache"); disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE); if (NULL == disk->bcache_mem) { free(disk); return ENOMEM; } // FIXME: get block size from disk device err = cyg_blib_io_create(dev_h, disk->bcache_mem, CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib); if (err != ENOERR) { free(disk->bcache_mem); free(disk); return err; } disk->dev_h = dev_h; CYG_TRACE0(TFS, "initializing disk"); err = fatfs_init(disk); if (err != ENOERR) { cyg_blib_delete(&disk->blib); free(disk->bcache_mem); free(disk); return err; } #if TFS print_disk_info(disk); #endif CYG_TRACE0(TFS, "initializing node cache"); fatfs_node_cache_init(disk); CYG_TRACE0(TFS, "initializing root node"); 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"); return ENOERR; }
static int find_direntry(fatfs_dirsearch_t *ds) { fatfs_dir_entry_t dentry; fatfs_data_pos_t pos; int err; CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name); // Check for '.' if (!strncmp(".", ds->name, ds->namelen)) { ds->node = ds->dir; return ENOERR; } // Check the cache ds->node = fatfs_node_find(ds->disk, ds->name, ds->namelen, ds->dir->dentry.cluster); if (ds->node != NULL) { // 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) { // Read next dir entry err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry); if (err != ENOERR) return (err == EEOF ? ENOERR : err); // Compare filenames if ('\0' == dentry.filename[ds->namelen] && 0 == strncasecmp(dentry.filename, ds->name, ds->namelen)) { // Dir entry found - allocate new node and return CYG_TRACE0(TFS, "dir entry found"); if (0 == strncmp(ds->name, "..", ds->namelen)) { fatfs_dir_entry_t _dentry; fatfs_data_pos_t _pos; if (0 == dentry.cluster) { ds->node = ds->disk->root; return ENOERR; } fatfs_initpos(ds->disk, &dentry, &_pos); while (true) { err = fatfs_read_dir_entry(ds->disk, &dentry, &_pos, &_dentry); if (err != ENOERR) return err; if (0 == strcmp(".", _dentry.filename)) break; } ds->node = fatfs_node_find(ds->disk, _dentry.filename, strlen(_dentry.filename), _dentry.parent_cluster); if (NULL != ds->node) fatfs_node_touch(ds->disk, ds->node); else ds->node = fatfs_node_alloc(ds->disk, &_dentry); if (NULL == ds->node) return EMFILE; return ENOERR; } else ds->node = fatfs_node_alloc(ds->disk, &dentry); if (NULL == ds->node) return EMFILE; return ENOERR; } } }