예제 #1
0
파일: nffs.c 프로젝트: tecbea/larva
/**
 * 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;
}
예제 #2
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;
}