/* * Copyright (c) 2012 Sean Bartell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup bithenge * @{ */ /** * @file * Access files as blobs. * @todo Provide more information about the file. */ #include #include #include #include #include #include #include "common.h" #include #include typedef struct { bithenge_blob_t base; int fd; aoff64_t size; // needed by file_read() bool needs_close; } file_blob_t; static inline file_blob_t *blob_as_file(bithenge_blob_t *base) { return (file_blob_t *)base; } static inline bithenge_blob_t *file_as_blob(file_blob_t *blob) { return &blob->base; } static errno_t file_size(bithenge_blob_t *base, aoff64_t *size) { file_blob_t *blob = blob_as_file(base); *size = blob->size; return EOK; } static errno_t file_read(bithenge_blob_t *base, aoff64_t offset, char *buffer, aoff64_t *size) { file_blob_t *blob = blob_as_file(base); if (offset > blob->size) return ELIMIT; size_t amount_read; errno_t rc = vfs_read(blob->fd, &offset, buffer, *size, &amount_read); if (rc != EOK) return errno; *size += amount_read; return EOK; } static void file_destroy(bithenge_blob_t *base) { file_blob_t *blob = blob_as_file(base); vfs_put(blob->fd); free(blob); } static const bithenge_random_access_blob_ops_t file_ops = { .size = file_size, .read = file_read, .destroy = file_destroy, }; static errno_t new_file_blob(bithenge_node_t **out, int fd, bool needs_close) { assert(out); vfs_stat_t stat; errno_t rc = vfs_stat(fd, &stat); if (rc != EOK) { if (needs_close) vfs_put(fd); return rc; } // Create blob file_blob_t *blob = malloc(sizeof(*blob)); if (!blob) { if (needs_close) vfs_put(fd); return ENOMEM; } rc = bithenge_init_random_access_blob(file_as_blob(blob), &file_ops); if (rc != EOK) { free(blob); if (needs_close) vfs_put(fd); return rc; } blob->fd = fd; #ifdef __HELENOS__ blob->size = stat.size; #else blob->size = stat.st_size; #endif blob->needs_close = needs_close; *out = bithenge_blob_as_node(file_as_blob(blob)); return EOK; } /** Create a blob for a file. The blob must be freed with @a * bithenge_node_t::bithenge_node_destroy after it is used. * @param[out] out Stores the created blob. * @param filename The name of the file. * @return EOK on success or an error code from errno.h. */ errno_t bithenge_new_file_blob(bithenge_node_t **out, const char *filename) { assert(filename); int fd; errno_t rc = vfs_lookup_open(filename, WALK_REGULAR, MODE_READ, &fd); if (rc != EOK) return rc; return new_file_blob(out, fd, true); } /** Create a blob for a file descriptor. The blob must be freed with @a * bithenge_node_t::bithenge_node_destroy after it is used. * @param[out] out Stores the created blob. * @param fd The file descriptor. * @return EOK on success or an error code from errno.h. */ errno_t bithenge_new_file_blob_from_fd(bithenge_node_t **out, int fd) { return new_file_blob(out, fd, false); } /** Create a blob for a file pointer. The blob must be freed with @a * bithenge_node_t::bithenge_node_destroy after it is used. * @param[out] out Stores the created blob. * @param file The file pointer. * @return EOK on success or an error code from errno.h. */ errno_t bithenge_new_file_blob_from_file(bithenge_node_t **out, FILE *file) { int fd = fileno(file); if (fd < 0) return errno; return new_file_blob(out, fd, false); } /** @} */