Merge pull request #1 from atsampson/master
[calfbox.git] / blob.c
blobe8d65f6d3e54570606957b0bf3407b320b7a69e5
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "blob.h"
20 #include "tarfile.h"
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <glib.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
29 struct cbox_blob *cbox_blob_new(size_t size)
31 struct cbox_blob *p = malloc(sizeof(struct cbox_blob));
32 if (!p)
33 return NULL;
34 p->data = size ? malloc(size) : NULL;
35 p->size = size;
36 return p;
39 struct cbox_blob *cbox_blob_new_copy_data(const void *data, size_t size)
41 struct cbox_blob *p = cbox_blob_new(size);
42 if (!p)
43 return NULL;
44 memcpy(p, data, size);
45 return p;
48 struct cbox_blob *cbox_blob_new_acquire_data(void *data, size_t size)
50 struct cbox_blob *p = malloc(sizeof(struct cbox_blob));
51 if (!p)
52 return NULL;
53 p->data = data;
54 p->size = size;
55 return p;
58 static struct cbox_blob *read_from_fd(const char *context_name, const char *pathname, int fd, size_t size, GError **error)
60 struct cbox_blob *blob = cbox_blob_new(size + 1);
61 if (!blob)
63 g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot allocate memory for file '%s'", context_name, pathname);
64 return NULL;
66 uint8_t *data = blob->data;
67 size_t nread = 0;
68 do {
69 size_t chunk = size - nread;
70 if (chunk > 131072)
71 chunk = 131072;
72 size_t nv = read(fd, data + nread, chunk);
73 if (nv == (size_t)-1)
75 if (errno == EINTR)
76 continue;
77 g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot read '%s': %s", context_name, pathname, strerror(errno));
78 cbox_blob_destroy(blob);
79 return NULL;
81 nread += nv;
82 } while(nread < size);
83 // Make sure that the content is 0-padded but still has the original size
84 // (without extra zero byte)
85 data[nread] = '\0';
86 blob->size = nread;
87 return blob;
90 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)
92 gchar *fullpath = g_build_filename(path, name, NULL);
93 struct cbox_blob *blob = NULL;
94 if (tarfile)
96 struct cbox_taritem *item = cbox_tarfile_get_item_by_name(tarfile, fullpath, TRUE);
97 if (item)
99 int fd = cbox_tarfile_openitem(tarfile, item);
100 if (fd >= 0)
102 blob = read_from_fd(context_name, fullpath, fd, item->size, error);
103 cbox_tarfile_closeitem(tarfile, item, fd);
107 else
109 int fd = open(fullpath, O_RDONLY | O_LARGEFILE);
110 if (fd >= 0)
112 uint64_t size = lseek64(fd, 0, SEEK_END);
113 if (size <= max_size)
114 blob = read_from_fd(context_name, fullpath, fd, size, error);
115 else
116 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);
117 close(fd);
119 else
120 g_set_error(error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s: cannot open '%s': %s", context_name, fullpath, strerror(errno));
122 g_free(fullpath);
123 return blob;
126 void cbox_blob_destroy(struct cbox_blob *blob)
128 free(blob->data);
129 free(blob);