/** * Retrieves the current length of the specified open file. * * @param file The file to query. * @param out_len On success, the number of bytes in the file gets * written here. * * @return 0 on success; nonzero on failure. */ int nffs_file_len(struct nffs_file *file, uint32_t *out_len) { int rc; nffs_lock(); rc = nffs_inode_data_len(file->nf_inode_entry, out_len); nffs_unlock(); return rc; }
/** * Retrieves the current length of the specified open file. * * @param file The file to query. * @param out_len On success, the number of bytes in the file gets * written here. * * @return 0 on success; nonzero on failure. */ static int nffs_file_len(const struct fs_file *fs_file, uint32_t *out_len) { int rc; const struct nffs_file *file = (const struct nffs_file *)fs_file; nffs_lock(); rc = nffs_inode_data_len(file->nf_inode_entry, out_len); nffs_unlock(); return rc; }
/** * Positions a file's read and write pointer at the specified offset. The * offset is expressed as the number of bytes from the start of the file (i.e., * seeking to 0 places the pointer at the first byte in the file). * * @param file The file to reposition. * @param offset The offset from the start of the file to seek to. * * @return 0 on success; nonzero on failure. */ int nffs_file_seek(struct nffs_file *file, uint32_t offset) { uint32_t len; int rc; rc = nffs_inode_data_len(file->nf_inode_entry, &len); if (rc != 0) { return rc; } if (offset > len) { return FS_ERANGE; } file->nf_offset = offset; return 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; }