Imported Upstream version 2.6.1p2
[debian/amanda] / server-src / taper-mem-port-source.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2005-2008 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-mem-port-source.h"
23
24 struct _TaperMemPortSourcePrivate {
25     /* Actual size of this buffer is given by max_part_size in TaperSource. */
26     char * retry_buffer;
27     guint64 buffer_offset; /* Bytes read from buffer. */
28     guint64 buffer_len;    /* Bytes written to buffer. */
29     gboolean retry_mode;
30 };
31 /* here are local prototypes */
32 static void taper_mem_port_source_init (TaperMemPortSource * o);
33 static void taper_mem_port_source_class_init (TaperMemPortSourceClass * c);
34 static ssize_t taper_mem_port_source_read (TaperSource * pself, void * buf,
35                                            size_t count);
36 static gboolean taper_mem_port_source_seek_to_part_start (TaperSource * pself);
37 static void taper_mem_port_source_start_new_part (TaperSource * pself);
38 static int taper_mem_port_source_predict_parts(TaperSource * pself);
39
40 /* pointer to the class of our parent */
41 static TaperSourceClass * source_parent_class = NULL;
42 static TaperPortSourceClass *parent_class = NULL;
43
44 GType
45 taper_mem_port_source_get_type (void)
46 {
47     static GType type = 0;
48     
49     if G_UNLIKELY(type == 0) {
50         static const GTypeInfo info = {
51             sizeof (TaperMemPortSourceClass),
52             (GBaseInitFunc) NULL,
53             (GBaseFinalizeFunc) NULL,
54             (GClassInitFunc) taper_mem_port_source_class_init,
55             (GClassFinalizeFunc) NULL,
56             NULL /* class_data */,
57             sizeof (TaperMemPortSource),
58             0 /* n_preallocs */,
59             (GInstanceInitFunc) taper_mem_port_source_init,
60             NULL
61         };
62         
63         type = g_type_register_static (TAPER_TYPE_PORT_SOURCE,
64                                        "TaperMemPortSource", &info,
65                                        (GTypeFlags)0);
66     }
67     
68     return type;
69 }
70
71 static void
72 taper_mem_port_source_finalize(GObject *obj_self) {
73     TaperMemPortSource *self = TAPER_MEM_PORT_SOURCE (obj_self);
74     if(G_OBJECT_CLASS(parent_class)->finalize)
75         (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
76     amfree (self->_priv->retry_buffer);
77     amfree (self->_priv);
78 }
79
80 static void 
81 taper_mem_port_source_init (TaperMemPortSource * o) {
82     o->_priv = malloc(sizeof(TaperMemPortSourcePrivate));
83     o->_priv->retry_buffer = NULL;
84     o->_priv->retry_mode = FALSE;
85     o->_priv->buffer_offset = o->_priv->buffer_len = 0;
86 }
87
88 static void 
89 taper_mem_port_source_class_init (TaperMemPortSourceClass * c) {
90     GObjectClass *g_object_class = (GObjectClass*) c;
91     TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
92     
93     parent_class = g_type_class_ref (TAPER_TYPE_PORT_SOURCE);
94     source_parent_class = (TaperSourceClass*)parent_class;
95     
96     taper_source_class->read = taper_mem_port_source_read;
97     taper_source_class->seek_to_part_start =
98         taper_mem_port_source_seek_to_part_start;
99     taper_source_class->start_new_part = taper_mem_port_source_start_new_part;
100     taper_source_class->predict_parts = taper_mem_port_source_predict_parts;
101
102     g_object_class->finalize = taper_mem_port_source_finalize;
103 }
104
105 static int taper_mem_port_source_predict_parts(TaperSource * pself) {
106     TaperMemPortSource * self = TAPER_MEM_PORT_SOURCE(pself);
107     g_return_val_if_fail(self != NULL, -1);
108
109     return -1;
110 }
111
112 /* Allocate buffer space, if it hasn't been done yet. */
113 static gboolean
114 setup_retry_buffer(TaperMemPortSource * self) {
115     TaperSource *pself = TAPER_SOURCE(self);
116     guint64 alloc_size;
117     if (selfp->retry_buffer != NULL)
118         return TRUE;
119
120     alloc_size = pself->max_part_size;
121     if (alloc_size > SIZE_MAX) {
122         g_fprintf(stderr, "Fallback split size of %lld is greater that system maximum of %lld.\n",
123                 (long long)alloc_size, (long long)SIZE_MAX);
124         alloc_size = SIZE_MAX;
125     }
126     
127     if (alloc_size < DISK_BLOCK_BYTES * 10) {
128         g_fprintf(stderr, "Fallback split size of %ju is smaller than 10 blocks (%u bytes).\n",
129                   (uintmax_t)alloc_size, DISK_BLOCK_BYTES * 10);
130         alloc_size = DISK_BLOCK_BYTES * 10;
131     }
132     
133     pself->max_part_size = alloc_size;
134     selfp->retry_buffer = malloc(alloc_size);
135
136     if (selfp->retry_buffer == NULL) {
137         pself->errmsg = g_strdup_printf(_("Can't allocate %ju bytes of memory for split buffer"),
138                                         (uintmax_t)pself->max_part_size);
139         return FALSE;
140     }
141
142     return TRUE;
143 }
144
145 static ssize_t 
146 taper_mem_port_source_read (TaperSource * pself, void * buf, size_t count) {
147     TaperMemPortSource * self = (TaperMemPortSource*)pself;
148     g_return_val_if_fail (self != NULL, -1);
149     g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), -1);
150     g_return_val_if_fail (buf != NULL, -1);
151     g_return_val_if_fail (count > 0, -1);
152     
153     if (selfp->retry_mode) {
154         g_assert(selfp->retry_buffer != NULL && selfp->buffer_len > 0);
155         count = MIN(count, selfp->buffer_len - selfp->buffer_offset);
156
157         if (count == 0) {
158             /* It was not before. */
159             pself->end_of_part = TRUE;
160             return 0;
161         }
162
163         memcpy(buf, selfp->retry_buffer + selfp->buffer_offset, count);
164         selfp->buffer_offset += count;
165
166         /* cancel retry mode if we're at the end of the retry buffer */
167         if (selfp->buffer_offset == selfp->buffer_len) {
168             selfp->retry_mode = 0;
169         }
170
171         return count;
172     } else {
173         int read_result;
174         if (selfp->retry_buffer == NULL) {
175             if (!setup_retry_buffer(self))
176                 return -1;
177         }
178
179         count = MIN(count, pself->max_part_size - selfp->buffer_len);
180         if (count == 0) /* it was nonzero before */ {
181             pself->end_of_part = TRUE;
182             return 0;
183         }
184         
185         read_result = source_parent_class->read(pself, buf, count);
186         /* TaperPortSource handles EOF and other goodness. */
187         if (read_result <= 0) {
188             return read_result;
189         }
190
191         /* All's well in the world. */
192         memcpy(selfp->retry_buffer + selfp->buffer_len,
193                buf, read_result);
194         selfp->buffer_len += read_result;
195
196         return read_result;
197     }
198
199     g_assert_not_reached();
200 }
201
202 static gboolean 
203 taper_mem_port_source_seek_to_part_start (TaperSource * pself) {
204     TaperMemPortSource * self = (TaperMemPortSource*)pself;
205     g_return_val_if_fail (self != NULL, FALSE);
206     g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), FALSE);
207     g_return_val_if_fail (selfp->buffer_len > 0, FALSE);
208
209     selfp->retry_mode = TRUE;
210     selfp->buffer_offset = 0;
211
212     if (source_parent_class->seek_to_part_start)
213         return source_parent_class->seek_to_part_start(pself);
214     else
215         return TRUE;
216 }
217
218 static void 
219 taper_mem_port_source_start_new_part (TaperSource * pself) {
220     TaperMemPortSource * self = (TaperMemPortSource*)pself;
221     g_return_if_fail (self != NULL);
222     g_return_if_fail (TAPER_IS_MEM_PORT_SOURCE (self));
223
224     selfp->buffer_offset = selfp->buffer_len = 0;
225     selfp->retry_mode = FALSE;
226
227     if (source_parent_class->start_new_part)
228         source_parent_class->start_new_part(pself);
229 }