int nxffs_updateinode(FAR struct nxffs_volume_s *volume, FAR struct nxffs_entry_s *entry) { FAR struct nxffs_ofile_s *ofile; /* Find the open inode structure matching this name */ ofile = nxffs_findofile(volume, entry->name); if (ofile) { /* Yes.. the file is open. Update the FLASH offsets to inode headers */ ofile->entry.hoffset = entry->hoffset; ofile->entry.noffset = entry->noffset; ofile->entry.doffset = entry->doffset; } return OK; }
static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume, FAR const char *name, FAR struct nxffs_ofile_s **ppofile) { FAR struct nxffs_ofile_s *ofile; int ret; /* Get exclusive access to the volume. Note that the volume exclsem * protects the open file list. */ ret = sem_wait(&volume->exclsem); if (ret != OK) { fdbg("ERROR: sem_wait failed: %d\n", ret); ret = -get_errno(); goto errout; } /* Check if the file has already been opened (for reading) */ ofile = nxffs_findofile(volume, name); if (ofile) { /* The file is already open. * Limitation: Files cannot be open both for reading and writing. */ if ((ofile->oflags & O_WROK) != 0) { fdbg("ERROR: File is open for writing\n"); ret = -ENOSYS; goto errout_with_exclsem; } /* Just increment the reference count on the ofile */ ofile->crefs++; fvdbg("crefs: %d\n", ofile->crefs); } /* The file has not yet been opened. * Limitation: The file must exist. We do not support creation of files * read-only. */ else { /* Not already open.. create a new open structure */ ofile = (FAR struct nxffs_ofile_s *)kmm_zalloc(sizeof(struct nxffs_ofile_s)); if (!ofile) { fdbg("ERROR: ofile allocation failed\n"); ret = -ENOMEM; goto errout_with_exclsem; } /* Initialize the open file state structure */ ofile->crefs = 1; ofile->oflags = O_RDOK; /* Find the file on this volume associated with this file name */ ret = nxffs_findinode(volume, name, &ofile->entry); if (ret != OK) { fvdbg("Inode '%s' not found: %d\n", name, -ret); goto errout_with_ofile; } /* Add the open file structure to the head of the list of open files */ ofile->flink = volume->ofiles; volume->ofiles = ofile; } /* Return the open file state structure */ *ppofile = ofile; sem_post(&volume->exclsem); return OK; errout_with_ofile: kmm_free(ofile); errout_with_exclsem: sem_post(&volume->exclsem); errout: return ret; }
static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume, FAR const char *name, mode_t oflags, FAR struct nxffs_ofile_s **ppofile) { FAR struct nxffs_wrfile_s *wrfile; FAR struct nxffs_entry_s entry; bool packed; bool truncate = false; int namlen; int ret; /* Limitation: Only a single writer is permitted. Writing may involve * extension of the file system in FLASH. Since files are contiguous * in FLASH, only a single file may be extending the FLASH region. */ ret = sem_wait(&volume->wrsem); if (ret != OK) { fdbg("ERROR: sem_wait failed: %d\n", ret); ret = -get_errno(); goto errout; } /* Get exclusive access to the volume. Note that the volume exclsem * protects the open file list. Note that exclsem is ALWAYS taken * after wrsem to avoid deadlocks. */ ret = sem_wait(&volume->exclsem); if (ret != OK) { fdbg("ERROR: sem_wait failed: %d\n", ret); ret = -get_errno(); goto errout_with_wrsem; } /* Check if the file exists */ ret = nxffs_findinode(volume, name, &entry); if (ret == OK) { FAR struct nxffs_ofile_s *ofile; /* It exists. Release the entry. */ nxffs_freeentry(&entry); /* Is the file already open for reading? */ ofile = nxffs_findofile(volume, name); if (ofile) { /* The file is already open. * Limitation: Files cannot be open both for reading and writing. */ fdbg("ERROR: File is open for reading\n"); ret = -ENOSYS; goto errout_with_exclsem; } /* It would be an error if we are asked to create the file * exclusively. */ else if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { fdbg("ERROR: File exists, can't create O_EXCL\n"); ret = -EEXIST; goto errout_with_exclsem; } /* Were we asked to truncate the file? NOTE: Don't truncate the * file if we were not also asked to created it. See below... * we will not re-create the file unless O_CREAT is also specified. */ else if ((oflags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC)) { /* Just schedule the removal the file and fall through to re-create it. * Note that the old file of the same name will not actually be removed * until the new file is successfully written. */ truncate = true; } /* The file exists and we were not asked to truncate (and recreate) it. * Limitation: Cannot write to existing files. */ else { fdbg("ERROR: File %s exists and we were not asked to truncate it\n"); ret = -ENOSYS; goto errout_with_exclsem; } } /* Okay, the file is not open and does not exists (maybe because we deleted * it). Now, make sure that we were asked to created it. */ if ((oflags & O_CREAT) == 0) { fdbg("ERROR: Not asked to create the file\n"); ret = -ENOENT; goto errout_with_exclsem; } /* Make sure that the length of the file name will fit in a uint8_t */ namlen = strlen(name); if (namlen > CONFIG_NXFFS_MAXNAMLEN) { fdbg("ERROR: Name is too long: %d\n", namlen); ret = -EINVAL; goto errout_with_exclsem; } /* Yes.. Create a new structure that will describe the state of this open * file. NOTE that a special variant of the open file structure is used * that includes additional information to support the write operation. */ #ifdef CONFIG_NXFFS_PREALLOCATED wrfile = &g_wrfile; memset(wrfile, 0, sizeof(struct nxffs_wrfile_s)); #else wrfile = (FAR struct nxffs_wrfile_s *)kmm_zalloc(sizeof(struct nxffs_wrfile_s)); if (!wrfile) { ret = -ENOMEM; goto errout_with_exclsem; } #endif /* Initialize the open file state structure */ wrfile->ofile.crefs = 1; wrfile->ofile.oflags = oflags; wrfile->ofile.entry.utc = time(NULL); wrfile->truncate = truncate; /* Save a copy of the inode name. */ wrfile->ofile.entry.name = strdup(name); if (!wrfile->ofile.entry.name) { ret = -ENOMEM; goto errout_with_ofile; } /* Allocate FLASH memory for the file and set up for the write. * * Loop until the inode header is configured or until a failure occurs. * Note that nothing is written to FLASH. The inode header is not * written until the file is closed. */ packed = false; for (;;) { /* File a valid location to position the inode header. Start with the * first byte in the free FLASH region. */ ret = nxffs_hdrpos(volume, wrfile); if (ret == OK) { /* Find a region of memory in the block that is fully erased */ ret = nxffs_hdrerased(volume, wrfile); if (ret == OK) { /* Valid memory for the inode header was found. Break out of * the loop. */ break; } } /* If no valid memory is found searching to the end of the volume, * then -ENOSPC will be returned. Other errors are not handled. */ if (ret != -ENOSPC || packed) { fdbg("ERROR: Failed to find inode header memory: %d\n", -ret); goto errout_with_name; } /* -ENOSPC is a special case.. It means that the volume is full. * Try to pack the volume in order to free up some space. */ ret = nxffs_pack(volume); if (ret < 0) { fdbg("ERROR: Failed to pack the volume: %d\n", -ret); goto errout_with_name; } /* After packing the volume, froffset will be updated to point to the * new free flash region. Try again. */ packed = true; } /* Loop until the inode name is configured or until a failure occurs. * Note that nothing is written to FLASH. */ for (;;) { /* File a valid location to position the inode name. Start with the * first byte in the free FLASH region. */ ret = nxffs_nampos(volume, wrfile, namlen); if (ret == OK) { /* Find a region of memory in the block that is fully erased */ ret = nxffs_namerased(volume, wrfile, namlen); if (ret == OK) { /* Valid memory for the inode header was found. Write the * inode name to this location. */ ret = nxffs_wrname(volume, &wrfile->ofile.entry, namlen); if (ret < 0) { fdbg("ERROR: Failed to write the inode name: %d\n", -ret); goto errout_with_name; } /* Then just break out of the loop reporting success. Note * that the alllocated inode name string is retained; it * will be needed later to calculate the inode CRC. */ break; } } /* If no valid memory is found searching to the end of the volume, * then -ENOSPC will be returned. Other errors are not handled. */ if (ret != -ENOSPC || packed) { fdbg("ERROR: Failed to find inode name memory: %d\n", -ret); goto errout_with_name; } /* -ENOSPC is a special case.. It means that the volume is full. * Try to pack the volume in order to free up some space. */ ret = nxffs_pack(volume); if (ret < 0) { fdbg("ERROR: Failed to pack the volume: %d\n", -ret); goto errout_with_name; } /* After packing the volume, froffset will be updated to point to the * new free flash region. Try again. */ packed = true; } /* Add the open file structure to the head of the list of open files */ wrfile->ofile.flink = volume->ofiles; volume->ofiles = &wrfile->ofile; /* Indicate that the volume is open for writing and return the open file * instance. Releasing exclsem allows other readers while the write is * in progress. But wrsem is still held for this open file, preventing * any further writers until this inode is closed.s */ *ppofile = &wrfile->ofile; sem_post(&volume->exclsem); return OK; errout_with_name: kmm_free(wrfile->ofile.entry.name); errout_with_ofile: #ifndef CONFIG_NXFFS_PREALLOCATED kmm_free(wrfile); #endif errout_with_exclsem: sem_post(&volume->exclsem); errout_with_wrsem: sem_post(&volume->wrsem); errout: return ret; }
int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name) { FAR struct nxffs_ofile_s *ofile; FAR struct nxffs_inode_s *inode; struct nxffs_entry_s entry; int ret; /* Check if the file is open */ ofile = nxffs_findofile(volume, name); if (ofile) { /* We can't remove the inode if it is open */ fdbg("Inode '%s' is open\n", name); ret = -EBUSY; goto errout; } /* Find the NXFFS inode */ ret = nxffs_findinode(volume, name, &entry); if (ret < 0) { fdbg("Inode '%s' not found\n", name); goto errout; } /* Set the position to the FLASH offset of the file header (nxffs_findinode * should have left the block in the cache). */ nxffs_ioseek(volume, entry.hoffset); /* Make sure that the block is in the cache */ ret = nxffs_rdcache(volume, volume->ioblock); if (ret < 0) { fdbg("Failed to read data into cache: %d\n", ret); goto errout_with_entry; } /* Change the file status... it is no longer valid */ inode = (FAR struct nxffs_inode_s *)&volume->cache[volume->iooffset]; inode->state = INODE_STATE_DELETED; /* Then write the cached block back to FLASH */ ret = nxffs_wrcache(volume); if (ret < 0) { fdbg("Failed to read data into cache: %d\n", ret); } errout_with_entry: nxffs_freeentry(&entry); errout: return ret; }