/**
 * 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;
}
Beispiel #2
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_file_read(struct nffs_file *file, uint32_t len, void *out_data,
               uint32_t *out_len)
{
    uint32_t bytes_read;
    int rc;

    if (!nffs_ready()) {
        return FS_EUNINIT;
    }

    if (!(file->nf_access_flags & FS_ACCESS_READ)) {
        return FS_EACCESS;
    }

    rc = nffs_inode_read(file->nf_inode_entry, file->nf_offset, len, out_data,
                        &bytes_read);
    if (rc != 0) {
        return rc;
    }

    file->nf_offset += bytes_read;
    if (out_len != NULL) {
        *out_len = bytes_read;
    }

    return 0;
}
/**
 * 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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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;
}