示例#1
0
/**
 * Performs a file open operation.
 *
 * @param out_file          On success, a pointer to the newly-created file
 *                              handle gets written here.
 * @param path              The path of the file to open.
 * @param access_flags      Flags controlling file access; see nffs_open() for
 *                              details.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
nffs_file_open(struct nffs_file **out_file, const char *path,
               uint8_t access_flags)
{
    struct nffs_path_parser parser;
    struct nffs_inode_entry *parent;
    struct nffs_inode_entry *inode;
    struct nffs_file *file;
    int rc;

    file = NULL;

    /* Reject invalid access flag combinations. */
    if (!(access_flags & (FS_ACCESS_READ | FS_ACCESS_WRITE))) {
        rc = FS_EINVAL;
        goto err;
    }
    if (access_flags & (FS_ACCESS_APPEND | FS_ACCESS_TRUNCATE) &&
        !(access_flags & FS_ACCESS_WRITE)) {

        rc = FS_EINVAL;
        goto err;
    }
    if (access_flags & FS_ACCESS_APPEND &&
        access_flags & FS_ACCESS_TRUNCATE) {

        rc = FS_EINVAL;
        goto err;
    }

    file = nffs_file_alloc();
    if (file == NULL) {
        rc = FS_ENOMEM;
        goto err;
    }

    nffs_path_parser_new(&parser, path);
    rc = nffs_path_find(&parser, &inode, &parent);
    if (rc == FS_ENOENT && parser.npp_token_type == NFFS_PATH_TOKEN_LEAF) {
        /* The path is valid, but the file does not exist.  This is an error
         * for read-only opens.
         */
        if (!(access_flags & FS_ACCESS_WRITE)) {
            goto err;
        }

        /* Make sure the parent directory exists. */
        if (parent == NULL) {
            goto err;
        }

        /* Create a new file at the specified path. */
        rc = nffs_file_new(parent, parser.npp_token, parser.npp_token_len, 0,
                           &file->nf_inode_entry);
        if (rc != 0) {
            goto err;
        }
    } else if (rc == 0) {
        /* The file already exists. */

        /* Reject an attempt to open a directory. */
        if (nffs_hash_id_is_dir(inode->nie_hash_entry.nhe_id)) {
            rc = FS_EINVAL;
            goto err;
        }

        if (access_flags & FS_ACCESS_TRUNCATE) {
            /* The user is truncating the file.  Unlink the old file and create
             * a new one in its place.
             */
            nffs_path_unlink(path);
            rc = nffs_file_new(parent, parser.npp_token, parser.npp_token_len,
                               0, &file->nf_inode_entry);
            if (rc != 0) {
                goto err;
            }
        } else {
            /* The user is not truncating the file.  Point the file handle to
             * the existing inode.
             */
            file->nf_inode_entry = inode;
        }
    } else {
        /* Invalid path. */
        goto err;
    }

    if (access_flags & FS_ACCESS_APPEND) {
        rc = nffs_inode_data_len(file->nf_inode_entry, &file->nf_offset);
        if (rc != 0) {
            goto err;
        }
    } else {
        file->nf_offset = 0;
    }
    file->nf_inode_entry->nie_refcnt++;
    file->nf_access_flags = access_flags;

    *out_file = file;

    return 0;

err:
    nffs_file_free(file);
    return rc;
}
/**
 * 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_full(const struct nffs_area_desc *area_descs)
{
    int rc;
    int i;

    /* Start from a clean state. */
    nffs_misc_reset();

    /* Select largest area to be the initial scratch area. */
    nffs_scratch_area_idx = 0;
    for (i = 1; area_descs[i].nad_length != 0; i++) {
        if (i >= NFFS_MAX_AREAS) {
            rc = FS_EINVAL;
            goto err;
        }

        if (area_descs[i].nad_length >
            area_descs[nffs_scratch_area_idx].nad_length) {

            nffs_scratch_area_idx = i;
        }
    }

    rc = nffs_misc_set_num_areas(i);
    if (rc != 0) {
        goto err;
    }

    for (i = 0; i < nffs_num_areas; i++) {
        nffs_areas[i].na_offset = area_descs[i].nad_offset;
        nffs_areas[i].na_length = area_descs[i].nad_length;
        nffs_areas[i].na_flash_id = area_descs[i].nad_flash_id;
        nffs_areas[i].na_cur = 0;
        nffs_areas[i].na_gc_seq = 0;

        if (i == nffs_scratch_area_idx) {
            nffs_areas[i].na_id = NFFS_AREA_ID_NONE;
        } else {
            nffs_areas[i].na_id = i;
        }

        rc = nffs_format_area(i, i == nffs_scratch_area_idx);
        if (rc != 0) {
            goto err;
        }
    }

    rc = nffs_misc_validate_scratch();
    if (rc != 0) {
        goto err;
    }

    /* Create root directory. */
    rc = nffs_file_new(NULL, "", 0, 1, &nffs_root_dir);
    if (rc != 0) {
        goto err;
    }

    /* Create "lost+found" directory. */
    rc = nffs_misc_create_lost_found_dir();
    if (rc != 0) {
        goto err;
    }

    rc = nffs_misc_validate_root_dir();
    if (rc != 0) {
        goto err;
    }

    rc = nffs_misc_set_max_block_data_len(0);
    if (rc != 0) {
        goto err;
    }

    return 0;

err:
    nffs_misc_reset();
    return rc;
}