/**
 * Opens a file at the specified path.  The result of opening a nonexistent
 * file depends on the access flags specified.  All intermediate directories
 * must already exist.
 *
 * The mode strings passed to fopen() map to nffs_open()'s access flags as
 * follows:
 *   "r"  -  FS_ACCESS_READ
 *   "r+" -  FS_ACCESS_READ | FS_ACCESS_WRITE
 *   "w"  -  FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE
 *   "w+" -  FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE
 *   "a"  -  FS_ACCESS_WRITE | FS_ACCESS_APPEND
 *   "a+" -  FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_APPEND
 *
 * @param path              The path of the file to open.
 * @param access_flags      Flags controlling file access; see above table.
 * @param out_file          On success, a pointer to the newly-created file
 *                              handle gets written here.
 *
 * @return                  0 on success; nonzero on failure.
 */
static int
nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file)
{
    int rc;
    struct nffs_file *out_file;

    nffs_lock();

    if (!nffs_ready()) {
        rc = FS_EUNINIT;
        goto done;
    }

    rc = nffs_file_open(&out_file, path, access_flags);
    if (rc != 0) {
        goto done;
    }
    *out_fs_file = (struct fs_file *)out_file;
done:
    nffs_unlock();
    if (rc != 0) {
        *out_fs_file = NULL;
    }
    return rc;
}
Exemple #2
0
/**
 * Searches for a valid nffs file system among the specified areas.  This
 * function succeeds if a file system is detected among any subset of the
 * supplied areas.  If the area set does not contain a valid file system,
 * a new one can be created via a separate call to nffs_format().
 *
 * @param area_descs        The area set to search.  This array must be
 *                              terminated with a 0-length area.
 *
 * @return                  0 on success;
 *                          NFFS_ECORRUPT if no valid file system was detected;
 *                          other nonzero on error.
 */
int
nffs_detect(const struct nffs_area_desc *area_descs)
{
    int rc;

    nffs_lock();
    rc = nffs_restore_full(area_descs);
    nffs_unlock();

    return rc;
}
Exemple #3
0
/**
 * Retrieves the current read and write position of the specified open file.
 *
 * @param file              The file to query.
 *
 * @return                  The file offset, in bytes.
 */
uint32_t
nffs_getpos(const struct nffs_file *file)
{
    uint32_t offset;

    nffs_lock();
    offset = file->nf_offset;
    nffs_unlock();

    return offset;
}
Exemple #4
0
/**
 * Positions a file's read and write pointer at the specified offset.  The
 * offset is expressed as the number of bytes from the start of the file (i.e.,
 * seeking to offset 0 places the pointer at the first byte in the file).
 *
 * @param file              The file to reposition.
 * @param offset            The 0-based file offset to seek to.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_seek(struct nffs_file *file, uint32_t offset)
{
    int rc;

    nffs_lock();
    rc = nffs_file_seek(file, offset);
    nffs_unlock();

    return rc;
}
Exemple #5
0
/**
 * Erases all the specified areas and initializes them with a clean nffs
 * file system.
 *
 * @param area_descs        The set of areas to format.
 *
 * @return                  0 on success;
 *                          nonzero on failure.
 */
int
nffs_format(const struct nffs_area_desc *area_descs)
{
    int rc;

    nffs_lock();
    rc = nffs_format_full(area_descs);
    nffs_unlock();

    return rc;
}
Exemple #6
0
/**
 * Retrieves the current length of the specified open file.
 *
 * @param file              The file to query.
 * @param out_len           On success, the number of bytes in the file gets
 *                              written here.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_file_len(struct nffs_file *file, uint32_t *out_len)
{
    int rc;

    nffs_lock();
    rc = nffs_inode_data_len(file->nf_inode_entry, out_len);
    nffs_unlock();

    return rc;
}
/**
 * Retrieves the current length of the specified open file.
 *
 * @param file              The file to query.
 * @param out_len           On success, the number of bytes in the file gets
 *                              written here.
 *
 * @return                  0 on success; nonzero on failure.
 */
static int
nffs_file_len(const struct fs_file *fs_file, uint32_t *out_len)
{
    int rc;
    const struct nffs_file *file = (const struct nffs_file *)fs_file;

    nffs_lock();
    rc = nffs_inode_data_len(file->nf_inode_entry, out_len);
    nffs_unlock();

    return rc;
}
Exemple #8
0
/**
 * Reads data from the specified file.  If more data is requested than remains
 * in the file, all available data is retrieved.  Note: this type of short read
 * results in a success return code.
 *
 * @param file              The file to read from.
 * @param len               The number of bytes to attempt to read.
 * @param out_data          The destination buffer to read into.
 * @param out_len           On success, the number of bytes actually read gets
 *                              written here.  Pass null if you don't care.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_read(struct nffs_file *file, uint32_t len, void *out_data,
          uint32_t *out_len)
{
    int rc;

    nffs_lock();
    rc = nffs_file_read(file, len, out_data, out_len);
    nffs_unlock();

    return rc;
}
/**
 * Positions a file's read and write pointer at the specified offset.  The
 * offset is expressed as the number of bytes from the start of the file (i.e.,
 * seeking to offset 0 places the pointer at the first byte in the file).
 *
 * @param file              The file to reposition.
 * @param offset            The 0-based file offset to seek to.
 *
 * @return                  0 on success; nonzero on failure.
 */
static int
nffs_seek(struct fs_file *fs_file, uint32_t offset)
{
    int rc;
    struct nffs_file *file = (struct nffs_file *)fs_file;

    nffs_lock();
    rc = nffs_file_seek(file, offset);
    nffs_unlock();

    return rc;
}
/**
 * Closes the specified directory handle.
 *
 * @param dir                   The directory to close.
 *
 * @return                      0 on success; nonzero on failure.
 */
static int
nffs_closedir(struct fs_dir *fs_dir)
{
    int rc;
    struct nffs_dir *dir = (struct nffs_dir *)fs_dir;

    nffs_lock();
    rc = nffs_dir_close(dir);
    nffs_unlock();

    return rc;
}
/**
 * Reads the next entry in an open directory.
 *
 * @param dir                   The directory handle to read from.
 * @param out_dirent            On success, points to the next child entry in
 *                                  the specified directory.
 *
 * @return                      0 on success;
 *                              FS_ENOENT if there are no more entries in the
 *                                  parent directory;
 *                              other nonzero on error.
 */
static int
nffs_readdir(struct fs_dir *fs_dir, struct fs_dirent **out_fs_dirent)
{
    int rc;
    struct nffs_dir *dir = (struct nffs_dir *)fs_dir;
    struct nffs_dirent **out_dirent = (struct nffs_dirent **)out_fs_dirent;

    nffs_lock();
    rc = nffs_dir_read(dir, out_dirent);
    nffs_unlock();

    return rc;
}
Exemple #12
0
/**
 * Closes the specified file and invalidates the file handle.  If the file has
 * already been unlinked, and this is the last open handle to the file, this
 * operation causes the file to be deleted from disk.
 *
 * @param file              The file handle to close.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_close(struct nffs_file *file)
{
    int rc;

    if (file == NULL) {
        return 0;
    }

    nffs_lock();
    rc = nffs_file_close(file);
    nffs_unlock();

    return rc;
}
/**
 * Tells you whether the specified directory entry is a sub-directory or a
 * regular file.
 *
 * @param dirent                The directory entry to query.
 *
 * @return                      1: The entry is a directory;
 *                              0: The entry is a regular file.
 */
static int
nffs_dirent_is_dir(const struct fs_dirent *fs_dirent)
{
    uint32_t id;
    const struct nffs_dirent *dirent = (const struct nffs_dirent *)fs_dirent;

    nffs_lock();

    assert(dirent != NULL && dirent->nde_inode_entry != NULL);
    id = dirent->nde_inode_entry->nie_hash_entry.nhe_id;

    nffs_unlock();

    return nffs_hash_id_is_dir(id);
}
/**
 * Retrieves the filename of the specified directory entry.  The retrieved
 * filename is always null-terminated.  To ensure enough space to hold the full
 * filename plus a null-termintor, a destination buffer of size
 * (NFFS_FILENAME_MAX_LEN + 1) should be used.
 *
 * @param dirent                The directory entry to query.
 * @param max_len               The size of the "out_name" character buffer.
 * @param out_name              On success, the entry's filename is written
 *                                  here; always null-terminated.
 * @param out_name_len          On success, contains the actual length of the
 *                                  filename, NOT including the
 *                                  null-terminator.
 *
 * @return                      0 on success; nonzero on failure.
 */
static int
nffs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len,
                 char *out_name, uint8_t *out_name_len)
{
    int rc;
    struct nffs_dirent *dirent = (struct nffs_dirent *)fs_dirent;

    nffs_lock();

    assert(dirent != NULL && dirent->nde_inode_entry != NULL);
    rc = nffs_inode_read_filename(dirent->nde_inode_entry, max_len, out_name,
                                  out_name_len);

    nffs_unlock();

    return rc;
}
/**
 * Opens the directory at the specified path.  The directory's contents can be
 * read with subsequent calls to nffs_readdir().  When you are done with the
 * directory handle, close it with nffs_closedir().
 *
 * Unlinking files from the directory while it is open may result in
 * unpredictable behavior.  New files can be created inside the directory.
 *
 * @param path                  The directory to open.
 * @param out_dir               On success, points to the directory handle.
 *
 * @return                      0 on success;
 *                              FS_ENOENT if the specified directory does not
 *                                  exist;
 *                              other nonzero on error.
 */
static int
nffs_opendir(const char *path, struct fs_dir **out_fs_dir)
{
    int rc;
    struct nffs_dir **out_dir = (struct nffs_dir **)out_fs_dir;

    nffs_lock();

    if (!nffs_ready()) {
        rc = FS_EUNINIT;
        goto done;
    }

    rc = nffs_dir_open(path, out_dir);

done:
    nffs_unlock();
    return rc;
}
Exemple #16
0
/**
 * Creates the directory represented by the specified path.  All intermediate
 * directories must already exist.  The specified path must start with a '/'
 * character.
 *
 * @param path                  The directory to create.
 *
 * @return                      0 on success;
 *                              nonzero on failure.
 */
int
nffs_mkdir(const char *path)
{
    int rc;

    nffs_lock();

    if (!nffs_ready()) {
        rc = NFFS_EUNINIT;
        goto done;
    }

    rc = nffs_path_new_dir(path, NULL);
    if (rc != 0) {
        goto done;
    }

done:
    nffs_unlock();
    return rc;
}
Exemple #17
0
/**
 * Performs a rename and / or move of the specified source path to the
 * specified destination.  The source path can refer to either a file or a
 * directory.  All intermediate directories in the destination path must
 * already exist.  If the source path refers to a file, the destination path
 * must contain a full filename path, rather than just the new parent
 * directory.  If an object already exists at the specified destination path,
 * this function causes it to be unlinked prior to the rename (i.e., the
 * destination gets clobbered).
 *
 * @param from              The source path.
 * @param to                The destination path.
 *
 * @return                  0 on success;
 *                          nonzero on failure.
 */
int
nffs_rename(const char *from, const char *to)
{
    int rc;

    nffs_lock();

    if (!nffs_ready()) {
        rc = NFFS_EUNINIT;
        goto done;
    }

    rc = nffs_path_rename(from, to);
    if (rc != 0) {
        goto done;
    }

    rc = 0;

done:
    nffs_unlock();
    return rc;
}
Exemple #18
0
/**
 * Unlinks the file or directory at the specified path.  If the path refers to
 * a directory, all the directory's descendants are recursively unlinked.  Any
 * open file handles refering to an unlinked file remain valid, and can be
 * read from and written to.
 *
 * @path                    The path of the file or directory to unlink.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_unlink(const char *path)
{
    int rc;

    nffs_lock();

    if (!nffs_ready()) {
        rc = NFFS_EUNINIT;
        goto done;
    }

    rc = nffs_path_unlink(path);
    if (rc != 0) {
        goto done;
    }

    rc = 0;

done:
    nffs_unlock();
    return rc;
}
Exemple #19
0
/**
 * Writes the supplied data to the current offset of the specified file handle.
 *
 * @param file              The file to write to.
 * @param data              The data to write.
 * @param len               The number of bytes to write.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_write(struct nffs_file *file, const void *data, int len)
{
    int rc;

    nffs_lock();

    if (!nffs_ready()) {
        rc = NFFS_EUNINIT;
        goto done;
    }

    rc = nffs_write_to_file(file, data, len);
    if (rc != 0) {
        goto done;
    }

    rc = 0;

done:
    nffs_unlock();
    return rc;
}