f0d3205a9a9b54f7f1f4216ddf2ab90044682b63
[debian/amanda] / server-src / taper-source.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2006 Zmanda Inc.
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.1 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 Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #define selfp (self->_priv)
21
22 #include "taper-source.h"
23 #include "taper-file-source.h"
24 #include "taper-port-source.h"
25 #include "taper-disk-port-source.h"
26 #include "taper-mem-port-source.h"
27
28 /* here are local prototypes */
29 static void taper_source_init (TaperSource * o);
30 static void taper_source_class_init (TaperSourceClass * c);
31 static void default_taper_source_start_new_part(TaperSource * self);
32 static gboolean default_taper_source_is_partial(TaperSource * self);
33 static gboolean default_taper_source_seek_to_part_start(TaperSource * self);
34 static gboolean default_taper_source_get_end_of_data(TaperSource * self);
35 static gboolean default_taper_source_get_end_of_part(TaperSource * self);
36 static dumpfile_t * default_taper_source_get_first_header(TaperSource * self);
37
38 /* pointer to the class of our parent */
39 static GObjectClass *parent_class = NULL;
40
41 GType
42 taper_source_get_type (void)
43 {
44     static GType type = 0;
45     
46     if G_UNLIKELY(type == 0) {
47         static const GTypeInfo info = {
48             sizeof (TaperSourceClass),
49             (GBaseInitFunc) NULL,
50             (GBaseFinalizeFunc) NULL,
51             (GClassInitFunc) taper_source_class_init,
52             (GClassFinalizeFunc) NULL,
53             NULL /* class_data */,
54             sizeof (TaperSource),
55             0 /* n_preallocs */,
56             (GInstanceInitFunc) taper_source_init,
57             NULL
58         };
59         
60         type = g_type_register_static (G_TYPE_OBJECT, "TaperSource", &info,
61                                        (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
62     }
63     
64     return type;
65 }
66
67 static void taper_source_finalize(GObject * obj_self) {
68     TaperSource * self = TAPER_SOURCE(obj_self);
69     
70     if (G_OBJECT_CLASS(parent_class)->finalize)
71         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
72
73     if (self->first_header)
74         amfree(self->first_header);
75
76     if (self->driver_handle)
77         amfree(self->driver_handle);
78 }
79
80 static void 
81 taper_source_init (TaperSource * o) {
82     o->end_of_data = FALSE;
83     o->end_of_part = FALSE;
84     o->max_part_size = G_MAXUINT64;
85     o->first_header = NULL;
86 }
87
88 static void 
89 taper_source_class_init (TaperSourceClass * c) {
90     GObjectClass *g_object_class = (GObjectClass*) c;
91
92     parent_class = g_type_class_ref (G_TYPE_OBJECT);
93
94     c->read = NULL;
95     c->seek_to_part_start = default_taper_source_seek_to_part_start;
96     c->start_new_part = default_taper_source_start_new_part;
97     c->is_partial = default_taper_source_is_partial;
98     c->get_end_of_data = default_taper_source_get_end_of_data;
99     c->get_end_of_part = default_taper_source_get_end_of_part;
100     c->get_first_header = default_taper_source_get_first_header;
101     c->predict_parts = NULL;
102
103     g_object_class->finalize = taper_source_finalize;
104 }
105
106 TaperSource * taper_source_new(char * handle,
107                                cmd_t mode, char * holding_disk_file,
108                                int socket_fd,
109                                char * split_disk_buffer,
110                                guint64 splitsize,
111                                guint64 fallback_splitsize) {
112     TaperSource * source_rval;
113     g_return_val_if_fail(mode == FILE_WRITE || mode == PORT_WRITE, NULL);
114     if (mode == FILE_WRITE) {
115         TaperFileSource * file_rval;
116         g_return_val_if_fail(holding_disk_file != NULL, NULL);
117         g_return_val_if_fail(holding_disk_file[0] != '\0', NULL);
118
119         /* Return a TaperFileSource. */
120         
121         source_rval = (TaperSource*)
122             g_object_new(TAPER_TYPE_FILE_SOURCE, NULL);
123         file_rval = (TaperFileSource*) source_rval;
124
125         if (file_rval == NULL)
126             return NULL;
127
128         file_rval->holding_disk_file = g_strdup(holding_disk_file);
129         source_rval->max_part_size = splitsize;
130     } else {
131         TaperPortSource * port_rval;
132         g_return_val_if_fail(socket_fd >= 0, NULL);
133
134         if (split_disk_buffer != NULL) {
135             TaperDiskPortSource * disk_rval;
136             g_return_val_if_fail(split_disk_buffer[0] != '\0', NULL);
137             g_return_val_if_fail(splitsize > 0, NULL);
138             
139             /* Return a TaperDiskPortSource. */
140             source_rval = (TaperSource*)
141                 g_object_new(TAPER_TYPE_DISK_PORT_SOURCE, NULL);
142             disk_rval = (TaperDiskPortSource*) source_rval;
143             port_rval = (TaperPortSource*) source_rval;
144
145             if (disk_rval == NULL)
146                 return NULL;
147
148             disk_rval->buffer_dir_name = g_strdup(split_disk_buffer);
149             disk_rval->fallback_buffer_size = fallback_splitsize;
150             source_rval->max_part_size = splitsize;
151         } else {
152             if (splitsize != 0) {
153                 TaperMemPortSource * mem_rval;
154                 /* Return a TaperMemPortSource. */
155                 if (fallback_splitsize == 0)
156                     fallback_splitsize = splitsize;
157                 source_rval = (TaperSource*)
158                     g_object_new(TAPER_TYPE_MEM_PORT_SOURCE, NULL);
159                 mem_rval = (TaperMemPortSource*) source_rval;
160                 port_rval = (TaperPortSource*) source_rval;
161
162                 if (mem_rval == NULL)
163                     return NULL;
164                 
165                 source_rval->max_part_size = fallback_splitsize;
166             } else {
167                 /* Return a TaperPortSource. */
168                 source_rval = (TaperSource*)
169                     g_object_new(TAPER_TYPE_PORT_SOURCE, NULL);
170                 port_rval = (TaperPortSource*) source_rval;
171
172                 if (source_rval == NULL)
173                     return NULL;
174             } 
175         }
176         
177         port_rval->socket_fd = socket_fd;
178     }
179
180     /* If we got here, we have a return value. */
181     source_rval->driver_handle = strdup(handle);
182     return source_rval;
183 }
184
185 /* Default implementations of virtual functions. */
186 static void
187 default_taper_source_start_new_part(TaperSource * self) {
188     self->end_of_part = FALSE;
189 }
190
191 static gboolean
192 default_taper_source_seek_to_part_start(TaperSource * self) {
193     self->end_of_data = self->end_of_part = FALSE;
194
195     return TRUE;
196 }
197
198 static gboolean
199 default_taper_source_is_partial(TaperSource * self) {
200     return self->first_header->is_partial;
201 }
202
203 static gboolean default_taper_source_get_end_of_data(TaperSource * self) {
204     return self->end_of_data;
205 }
206 static gboolean default_taper_source_get_end_of_part(TaperSource * self) {
207     return self->end_of_part;
208 }
209 static dumpfile_t* default_taper_source_get_first_header(TaperSource * self) {
210     if (self->first_header == NULL)
211         return NULL;
212     return dumpfile_copy(self->first_header);
213 }
214
215 /* The rest of these functions are vtable dispatch stubs. */
216
217 ssize_t 
218 taper_source_read (TaperSource * self, void * buf, size_t count)
219 {
220     TaperSourceClass *klass;
221     g_return_val_if_fail (self != NULL, (ssize_t )-1);
222     g_return_val_if_fail (TAPER_IS_SOURCE (self), (ssize_t )-1);
223     g_return_val_if_fail (buf != NULL, (ssize_t )-1);
224     g_return_val_if_fail (count > 0, (ssize_t )-1);
225
226     if (self->end_of_data || self->end_of_part) {
227         return 0;
228     }
229
230     klass = TAPER_SOURCE_GET_CLASS(self);
231     
232     if(klass->read)
233         return (*klass->read)(self,buf,count);
234     else
235         return (ssize_t )(-1);
236 }
237
238 gboolean 
239 taper_source_get_end_of_data (TaperSource * self)
240 {
241     TaperSourceClass *klass;
242     g_return_val_if_fail (self != NULL, TRUE);
243     g_return_val_if_fail (TAPER_IS_SOURCE (self), TRUE);
244
245     klass = TAPER_SOURCE_GET_CLASS(self);
246     
247     g_return_val_if_fail(klass->get_end_of_data != NULL, TRUE);
248
249     return (*klass->get_end_of_data)(self);
250 }
251
252 gboolean 
253 taper_source_get_end_of_part (TaperSource * self)
254 {
255     TaperSourceClass *klass;
256     g_return_val_if_fail (self != NULL, TRUE);
257     g_return_val_if_fail (TAPER_IS_SOURCE (self), TRUE);
258
259     klass = TAPER_SOURCE_GET_CLASS(self);
260     
261     g_return_val_if_fail(klass->get_end_of_part != NULL, TRUE);
262
263     return (*klass->get_end_of_part)(self);
264 }
265
266 dumpfile_t *
267 taper_source_get_first_header (TaperSource * self)
268 {
269     TaperSourceClass *klass;
270     g_return_val_if_fail (self != NULL, NULL);
271     g_return_val_if_fail (TAPER_IS_SOURCE (self), NULL);
272
273     klass = TAPER_SOURCE_GET_CLASS(self);
274     
275     g_return_val_if_fail(klass->get_first_header != NULL, NULL);
276
277     return (*klass->get_first_header)(self);
278 }
279
280 int taper_source_predict_parts(TaperSource * self) {
281     TaperSourceClass *klass;
282     g_return_val_if_fail (self != NULL, -1);
283     g_return_val_if_fail (TAPER_IS_SOURCE (self), -1);
284
285     klass = TAPER_SOURCE_GET_CLASS(self);
286     
287     if (klass->predict_parts != NULL) {
288         return (*klass->predict_parts)(self);
289     } else {
290         return -1;
291     }
292 }
293
294 gboolean 
295 taper_source_seek_to_part_start (TaperSource * self)
296 {
297     TaperSourceClass *klass;
298     g_return_val_if_fail (self != NULL, (gboolean )0);
299     g_return_val_if_fail (TAPER_IS_SOURCE (self), (gboolean )0);
300     klass = TAPER_SOURCE_GET_CLASS(self);
301     
302     if(klass->seek_to_part_start)
303         return (*klass->seek_to_part_start)(self);
304     else
305         return (gboolean )(0);
306 }
307
308 void 
309 taper_source_start_new_part (TaperSource * self)
310 {
311     TaperSourceClass *klass;
312     g_return_if_fail (self != NULL);
313     g_return_if_fail (TAPER_IS_SOURCE (self));
314     klass = TAPER_SOURCE_GET_CLASS(self);
315     
316     if(klass->start_new_part)
317         (*klass->start_new_part)(self);
318 }
319
320 gboolean
321 taper_source_is_partial (TaperSource * self)
322 {
323     TaperSourceClass *klass;
324     g_return_val_if_fail (self != NULL, FALSE);
325     g_return_val_if_fail (TAPER_IS_SOURCE (self), FALSE);
326     g_return_val_if_fail (taper_source_get_end_of_data(self), FALSE);
327     klass = TAPER_SOURCE_GET_CLASS(self);
328     
329     if(klass->is_partial)
330         return (*klass->is_partial)(self);
331     else
332         return FALSE;
333 }
334
335 producer_result_t taper_source_producer(gpointer data,
336                                         queue_buffer_t * buffer,
337                                         int hint_size) {
338     TaperSource * source;
339     int result;
340
341     source = data;
342     g_assert(TAPER_IS_SOURCE(source));
343
344     buffer->offset = 0;
345     if (buffer->data == NULL) {
346         buffer->data = malloc(hint_size);
347         /* This allocation is more likely than most to fail. */
348         g_return_val_if_fail(buffer->data != NULL, PRODUCER_ERROR);
349         buffer->alloc_size = hint_size;
350     }
351
352     result = taper_source_read(source, buffer->data, buffer->alloc_size);
353     if (result > 0) {
354         buffer->data_size = result;
355         return PRODUCER_MORE;
356     } else if (result == 0) {
357         /* EOF or EOC? We are done here either way. */
358         return PRODUCER_FINISHED;
359     } else {
360         return PRODUCER_ERROR;
361     }
362
363     g_assert_not_reached();
364 }
365