int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct nxffs_volume_s *volume; int ret; fvdbg("cmd: %d arg: %08lx\n", cmd, arg); /* Sanity checks */ DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); /* Recover the file system state from the open file */ volume = filep->f_inode->i_private; DEBUGASSERT(volume != NULL); /* Get exclusive access to the volume. Note that the volume exclsem * protects the open file list. */ ret = sem_wait(&volume->exclsem); if (ret != OK) { ret = -errno; fdbg("sem_wait failed: %d\n", ret); goto errout; } /* Only a reformat and optimize commands are supported */ if (cmd == FIOC_REFORMAT) { fvdbg("Reformat command\n"); /* We cannot reformat the volume if there are any open inodes */ if (volume->ofiles) { fdbg("Open files\n"); ret = -EBUSY; goto errout_with_semaphore; } /* Re-format the volume -- all is lost */ ret = nxffs_reformat(volume); } else if (cmd == FIOC_OPTIMIZE) { fvdbg("Optimize command\n"); /* Pack the volume */ ret = nxffs_pack(volume); } else { /* No other commands supported */ ret = -ENOTTY; } errout_with_semaphore: 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; }
static inline int nxffs_wralloc(FAR struct nxffs_volume_s *volume, FAR struct nxffs_wrfile_s *wrfile, size_t size) { bool packed; int ret; /* Allocate FLASH memory for the data block. * * Loop until the data block header is configured or until a failure * occurs. Note that nothing is written to FLASH. The data block header * is not written until either (1) the file is closed, or (2) the data * region is fully populated. */ packed = false; for (;;) { size_t mindata = MIN(NXFFS_MINDATA, size); /* File a valid location to position the data block. Start with * the first byte in the free FLASH region. */ ret = nxffs_hdrpos(volume, wrfile, mindata); if (ret == OK) { /* Find a region of memory in the block that is fully erased */ ret = nxffs_hdrerased(volume, wrfile, mindata); if (ret == OK) { /* Valid memory for the data block was found. Return success. */ return OK; } } /* 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); return -ENOSPC; } /* -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); return ret; } /* After packing the volume, froffset will be updated to point to the * new free flash region. Try again. */ nxffs_ioseek(volume, volume->froffset); packed = true; } /* Can't get here */ return OK; }