/** * 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; }
/** * 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; }