Example #1
0
/**
 * Creates a new empty file and writes it to the file system.  If a file with
 * the specified path already exists, the behavior is undefined.
 *
 * @param parent                The parent directory to insert the new file in.
 * @param filename              The name of the file to create.
 * @param filename_len          The length of the filename, in characters.
 * @param is_dir                1 if this is a directory; 0 if it is a normal
 *                                  file.
 * @param out_inode_entry       On success, this points to the inode
 *                                  corresponding to the new file.
 *
 * @return                      0 on success; nonzero on failure.
 */
int
nffs_file_new(struct nffs_inode_entry *parent, const char *filename,
              uint8_t filename_len, int is_dir,
              struct nffs_inode_entry **out_inode_entry)
{
    struct nffs_disk_inode disk_inode;
    struct nffs_inode_entry *inode_entry;
    uint32_t offset;
    uint8_t area_idx;
    int rc;

    inode_entry = nffs_inode_entry_alloc();
    if (inode_entry == NULL) {
        rc = FS_ENOMEM;
        goto err;
    }

    rc = nffs_misc_reserve_space(sizeof disk_inode + filename_len,
                                 &area_idx, &offset);
    if (rc != 0) {
        goto err;
    }

    memset(&disk_inode, 0xff, sizeof disk_inode);
    disk_inode.ndi_magic = NFFS_INODE_MAGIC;
    if (is_dir) {
        disk_inode.ndi_id = nffs_hash_next_dir_id++;
    } else {
        disk_inode.ndi_id = nffs_hash_next_file_id++;
    }
    disk_inode.ndi_seq = 0;
    if (parent == NULL) {
        disk_inode.ndi_parent_id = NFFS_ID_NONE;
    } else {
        disk_inode.ndi_parent_id = parent->nie_hash_entry.nhe_id;
    }
    disk_inode.ndi_filename_len = filename_len;
    nffs_crc_disk_inode_fill(&disk_inode, filename);

    rc = nffs_inode_write_disk(&disk_inode, filename, area_idx, offset);
    if (rc != 0) {
        goto err;
    }

    inode_entry->nie_hash_entry.nhe_id = disk_inode.ndi_id;
    inode_entry->nie_hash_entry.nhe_flash_loc =
        nffs_flash_loc(area_idx, offset);
    inode_entry->nie_refcnt = 1;

    if (parent != NULL) {
        rc = nffs_inode_add_child(parent, inode_entry);
        if (rc != 0) {
            goto err;
        }
    } else {
        assert(disk_inode.ndi_id == NFFS_ID_ROOT_DIR);
    }

    nffs_hash_insert(&inode_entry->nie_hash_entry);
    *out_inode_entry = inode_entry;

    return 0;

err:
    nffs_inode_entry_free(inode_entry);
    return rc;
}
Example #2
0
/**
 * Overwrites an existing data block.  The resulting block has the same ID as
 * the old one, but it supersedes it with a greater sequence number.
 *
 * @param entry                 The data block to overwrite.
 * @param left_copy_len         The number of bytes of existing data to retain
 *                                  before the new data begins.
 * @param new_data              The new data to write to the block.
 * @param new_data_len          The number of new bytes to write to the block.
 *                                  If this value plus left_copy_len is less
 *                                  than the existing block's data length,
 *                                  previous data at the end of the block is
 *                                  retained.
 *
 * @return                      0 on success; nonzero on failure.
 */
static int
nffs_write_over_block(struct nffs_hash_entry *entry, uint16_t left_copy_len,
                      const void *new_data, uint16_t new_data_len)
{
    struct nffs_disk_block disk_block;
    struct nffs_block block;
    uint32_t src_area_offset;
    uint32_t dst_area_offset;
    uint16_t right_copy_len;
    uint16_t block_off;
    uint8_t src_area_idx;
    uint8_t dst_area_idx;
    int rc;

    rc = nffs_block_from_hash_entry(&block, entry);
    if (rc != 0) {
        return rc;
    }

    assert(left_copy_len <= block.nb_data_len);

    /* Determine how much old data at the end of the block needs to be
     * retained.  If the new data doesn't extend to the end of the block, the
     * the rest of the block retains its old contents.
     */
    if (left_copy_len + new_data_len > block.nb_data_len) {
        right_copy_len = 0;
    } else {
        right_copy_len = block.nb_data_len - left_copy_len - new_data_len;
    }

    block.nb_seq++;
    block.nb_data_len = left_copy_len + new_data_len + right_copy_len;
    nffs_block_to_disk(&block, &disk_block);

    nffs_flash_loc_expand(entry->nhe_flash_loc,
                          &src_area_idx, &src_area_offset);

    rc = nffs_write_fill_crc16_overwrite(&disk_block,
                                         src_area_idx, src_area_offset,
                                         left_copy_len, right_copy_len,
                                         new_data, new_data_len);
    if (rc != 0) {
        return rc;
    }

    rc = nffs_misc_reserve_space(sizeof disk_block + disk_block.ndb_data_len,
                                 &dst_area_idx, &dst_area_offset);
    if (rc != 0) {
        return rc;
    }

    block_off = 0;

    /* Write the block header. */
    rc = nffs_flash_write(dst_area_idx, dst_area_offset + block_off,
                          &disk_block, sizeof disk_block);
    if (rc != 0) {
        return rc;
    }
    block_off += sizeof disk_block;

    /* Copy data from the start of the old block, in case the new data starts
     * at a non-zero offset.
     */
    if (left_copy_len > 0) {
        rc = nffs_flash_copy(src_area_idx, src_area_offset + block_off,
                             dst_area_idx, dst_area_offset + block_off,
                             left_copy_len);
        if (rc != 0) {
            return rc;
        }
        block_off += left_copy_len;
    }

    /* Write the new data into the data block.  This may extend the block's
     * length beyond its old value.
     */
    rc = nffs_flash_write(dst_area_idx, dst_area_offset + block_off,
                          new_data, new_data_len);
    if (rc != 0) {
        return rc;
    }
    block_off += new_data_len;

    /* Copy data from the end of the old block, in case the new data doesn't
     * extend to the end of the block.
     */
    if (right_copy_len > 0) {
        rc = nffs_flash_copy(src_area_idx, src_area_offset + block_off,
                             dst_area_idx, dst_area_offset + block_off,
                             right_copy_len);
        if (rc != 0) {
            return rc;
        }
        block_off += right_copy_len;
    }

    assert(block_off == sizeof disk_block + block.nb_data_len);

    entry->nhe_flash_loc = nffs_flash_loc(dst_area_idx, dst_area_offset);

    ASSERT_IF_TEST(nffs_crc_disk_block_validate(&disk_block, dst_area_idx,
                                                dst_area_offset) == 0);

    return 0;
}