/* Calf Box, an open source musical instrument. Copyright (C) 2010-2011 Krzysztof Foltman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "blob.h" #include "tarfile.h" #include #include #include #include #include #include #include struct cbox_blob *cbox_blob_new(size_t size) { struct cbox_blob *p = malloc(sizeof(struct cbox_blob)); if (!p) return NULL; p->data = size ? malloc(size) : NULL; p->size = size; return p; } struct cbox_blob *cbox_blob_new_copy_data(const void *data, size_t size) { struct cbox_blob *p = cbox_blob_new(size); if (!p) return NULL; memcpy(p, data, size); return p; } struct cbox_blob *cbox_blob_new_acquire_data(void *data, size_t size) { struct cbox_blob *p = malloc(sizeof(struct cbox_blob)); if (!p) return NULL; p->data = data; p->size = size; return p; } static struct cbox_blob *read_from_fd(const char *context_name, const char *pathname, int fd, size_t size, GError **error) { struct cbox_blob *blob = cbox_blob_new(size + 1); if (!blob) { g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot allocate memory for file '%s'", context_name, pathname); return NULL; } uint8_t *data = blob->data; size_t nread = 0; do { size_t chunk = size - nread; if (chunk > 131072) chunk = 131072; size_t nv = read(fd, data + nread, chunk); if (nv == (size_t)-1) { if (errno == EINTR) continue; g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot read '%s': %s", context_name, pathname, strerror(errno)); cbox_blob_destroy(blob); return NULL; } nread += nv; } while(nread < size); // Make sure that the content is 0-padded but still has the original size // (without extra zero byte) data[nread] = '\0'; blob->size = nread; return blob; } struct cbox_blob *cbox_blob_new_from_file(const char *context_name, struct cbox_tarfile *tarfile, const char *path, const char *name, size_t max_size, GError **error) { gchar *fullpath = g_build_filename(path, name, NULL); struct cbox_blob *blob = NULL; if (tarfile) { struct cbox_taritem *item = cbox_tarfile_get_item_by_name(tarfile, fullpath, TRUE); if (item) { int fd = cbox_tarfile_openitem(tarfile, item); if (fd >= 0) { blob = read_from_fd(context_name, fullpath, fd, item->size, error); cbox_tarfile_closeitem(tarfile, item, fd); } } } else { int fd = open(fullpath, O_RDONLY | O_LARGEFILE); if (fd >= 0) { uint64_t size = lseek64(fd, 0, SEEK_END); if (size <= max_size) blob = read_from_fd(context_name, fullpath, fd, size, error); else g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: file '%s' too large (%llu while max size is %u)", context_name, fullpath, (unsigned long long)size, (unsigned)max_size); close(fd); } else g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot open '%s': %s", context_name, fullpath, strerror(errno)); } g_free(fullpath); return blob; } void cbox_blob_destroy(struct cbox_blob *blob) { free(blob->data); free(blob); }