1 /*
2 * Copyright (C) 2007 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22 #define __GDA_INTERNAL__
23 #include "dir-blob-op.h"
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <glib/gstdio.h>
29
30 struct _GdaDirBlobOpPrivate {
31 gchar *complete_filename;
32 };
33
34 static void gda_dir_blob_op_class_init (GdaDirBlobOpClass *klass);
35 static void gda_dir_blob_op_init (GdaDirBlobOp *blob,
36 GdaDirBlobOpClass *klass);
37 static void gda_dir_blob_op_finalize (GObject *object);
38
39 static glong gda_dir_blob_op_get_length (GdaBlobOp *op);
40 static glong gda_dir_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
41 static glong gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset);
42
43 static GObjectClass *parent_class = NULL;
44
45 /*
46 * Object init and finalize
47 */
48 GType
_gda_dir_blob_op_get_type(void)49 _gda_dir_blob_op_get_type (void)
50 {
51 static GType type = 0;
52
53 if (G_UNLIKELY (type == 0)) {
54 static GMutex registering;
55 static const GTypeInfo info = {
56 sizeof (GdaDirBlobOpClass),
57 (GBaseInitFunc) NULL,
58 (GBaseFinalizeFunc) NULL,
59 (GClassInitFunc) gda_dir_blob_op_class_init,
60 NULL,
61 NULL,
62 sizeof (GdaDirBlobOp),
63 0,
64 (GInstanceInitFunc) gda_dir_blob_op_init,
65 0
66 };
67 g_mutex_lock (®istering);
68 if (type == 0)
69 type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaDirBlobOp", &info, 0);
70 g_mutex_unlock (®istering);
71 }
72 return type;
73 }
74
75 static void
gda_dir_blob_op_init(GdaDirBlobOp * op,G_GNUC_UNUSED GdaDirBlobOpClass * klass)76 gda_dir_blob_op_init (GdaDirBlobOp *op,
77 G_GNUC_UNUSED GdaDirBlobOpClass *klass)
78 {
79 g_return_if_fail (GDA_IS_DIR_BLOB_OP (op));
80
81 op->priv = g_new0 (GdaDirBlobOpPrivate, 1);
82 op->priv->complete_filename = NULL;
83 }
84
85 static void
gda_dir_blob_op_class_init(GdaDirBlobOpClass * klass)86 gda_dir_blob_op_class_init (GdaDirBlobOpClass *klass)
87 {
88 GObjectClass *object_class = G_OBJECT_CLASS (klass);
89 GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
90
91 parent_class = g_type_class_peek_parent (klass);
92
93 object_class->finalize = gda_dir_blob_op_finalize;
94 blob_class->get_length = gda_dir_blob_op_get_length;
95 blob_class->read = gda_dir_blob_op_read;
96 blob_class->write = gda_dir_blob_op_write;
97 }
98
99
100 static void
gda_dir_blob_op_finalize(GObject * object)101 gda_dir_blob_op_finalize (GObject * object)
102 {
103 GdaDirBlobOp *pgop = (GdaDirBlobOp *) object;
104
105 g_return_if_fail (GDA_IS_DIR_BLOB_OP (pgop));
106
107 g_free (pgop->priv->complete_filename);
108 g_free (pgop->priv);
109 pgop->priv = NULL;
110
111 parent_class->finalize (object);
112 }
113
114 /**
115 * _gda_dir_blob_op_new
116 */
117 GdaBlobOp *
_gda_dir_blob_op_new(const gchar * complete_filename)118 _gda_dir_blob_op_new (const gchar *complete_filename)
119 {
120 GdaDirBlobOp *pgop;
121
122 g_return_val_if_fail (complete_filename, NULL);
123
124 pgop = g_object_new (GDA_TYPE_DIR_BLOB_OP, NULL);
125 pgop->priv->complete_filename = g_strdup (complete_filename);
126
127 return GDA_BLOB_OP (pgop);
128 }
129
130 /**
131 * _gda_dir_blob_set_filename
132 */
133 void
_gda_dir_blob_set_filename(GdaDirBlobOp * blob,const gchar * complete_filename)134 _gda_dir_blob_set_filename (GdaDirBlobOp *blob, const gchar *complete_filename)
135 {
136 g_return_if_fail (GDA_IS_DIR_BLOB_OP (blob));
137 g_return_if_fail (blob->priv);
138 g_return_if_fail (complete_filename);
139
140 g_free (blob->priv->complete_filename);
141 blob->priv->complete_filename = g_strdup (complete_filename);
142 }
143
144 /**
145 * _gda_dir_blob_get_filename
146 */
147 const gchar *
_gda_dir_blob_get_filename(GdaDirBlobOp * blob)148 _gda_dir_blob_get_filename (GdaDirBlobOp *blob)
149 {
150 g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (blob), NULL);
151 g_return_val_if_fail (blob->priv, NULL);
152
153 return blob->priv->complete_filename;
154 }
155
156 /*
157 * Virtual functions
158 */
159 static glong
gda_dir_blob_op_get_length(GdaBlobOp * op)160 gda_dir_blob_op_get_length (GdaBlobOp *op)
161 {
162 GdaDirBlobOp *dirop;
163 struct stat filestat;
164
165 g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
166 dirop = GDA_DIR_BLOB_OP (op);
167 g_return_val_if_fail (dirop->priv, -1);
168
169 if (! g_stat (dirop->priv->complete_filename, &filestat))
170 return filestat.st_size;
171 else
172 return -1;
173 }
174
175 static glong
gda_dir_blob_op_read(GdaBlobOp * op,GdaBlob * blob,glong offset,glong size)176 gda_dir_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
177 {
178 GdaDirBlobOp *dirop;
179 GdaBinary *bin;
180 FILE *file;
181 size_t nread;
182
183 g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
184 dirop = GDA_DIR_BLOB_OP (op);
185 g_return_val_if_fail (dirop->priv, -1);
186 if (offset >= G_MAXINT)
187 return -1;
188 g_return_val_if_fail (blob, -1);
189
190 /* open file */
191 file = fopen (dirop->priv->complete_filename, "rb"); /* Flawfinder: ignore */
192 if (!file)
193 return -1;
194
195 /* go to offset */
196 if (fseek (file, offset, SEEK_SET) != 0) {
197 fclose (file);
198 return -1;
199 }
200
201 bin = (GdaBinary *) blob;
202 if (bin->data) {
203 g_free (bin->data);
204 bin->data = NULL;
205 }
206 bin->data = g_new0 (guchar, size);
207 nread = fread ((char *) (bin->data), 1, size, file);
208 bin->binary_length = nread;
209 fclose (file);
210
211 return nread;
212 }
213
214 static glong
gda_dir_blob_op_write(GdaBlobOp * op,GdaBlob * blob,glong offset)215 gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
216 {
217 GdaDirBlobOp *dirop;
218 GdaBinary *bin;
219 FILE *file;
220 glong nbwritten;
221
222 g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
223 dirop = GDA_DIR_BLOB_OP (op);
224 g_return_val_if_fail (dirop->priv, -1);
225 if (offset >= G_MAXINT)
226 return -1;
227 g_return_val_if_fail (blob, -1);
228
229 /* open file */
230 file = fopen (dirop->priv->complete_filename, "w+b"); /* Flawfinder: ignore */
231 if (!file)
232 return -1;
233
234 /* go to offset */
235 if (offset > 0) {
236 if (fseek (file, offset, SEEK_SET) != 0) {
237 fclose (file);
238 return -1;
239 }
240 }
241
242 if (blob->op && (blob->op != op)) {
243 /* use data through blob->op */
244 #define buf_size 16384
245 gint nread = 0;
246 GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
247 gda_blob_set_op (tmpblob, blob->op);
248
249 nbwritten = 0;
250
251 for (nread = gda_blob_op_read (tmpblob->op, tmpblob, 0, buf_size);
252 nread > 0;
253 nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
254 GdaBinary *bin = (GdaBinary *) tmpblob;
255 glong tmp_written;
256 tmp_written = fwrite ((char *) (bin->data), sizeof (guchar), bin->binary_length, file);
257 if (tmp_written < bin->binary_length) {
258 /* error writing stream */
259 fclose (file);
260 gda_blob_free ((gpointer) tmpblob);
261 return -1;
262 }
263 nbwritten += tmp_written;
264 if (nread < buf_size)
265 /* nothing more to read */
266 break;
267 }
268 fclose (file);
269 gda_blob_free ((gpointer) tmpblob);
270 }
271 else {
272 bin = (GdaBinary *) blob;
273 nbwritten = fwrite ((char *) (bin->data), 1, bin->binary_length, file);
274 fclose (file);
275 }
276
277 return (nbwritten >= 0) ? nbwritten : -1;
278 }
279