Imported Upstream version 3.3.3
[debian/amanda] / xfer-src / dest-buffer.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  *
19  * Contact information: Zmanda Inc., 465 N Mathlida Ave, Suite 300
20  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21  */
22
23 #include "amanda.h"
24 #include "amxfer.h"
25
26 /*
27  * Class declaration
28  *
29  * This declaration is entirely private; nothing but xfer_dest_buffer() references
30  * it directly.
31  */
32
33 GType xfer_dest_buffer_get_type(void);
34 #define XFER_DEST_BUFFER_TYPE (xfer_dest_buffer_get_type())
35 #define XFER_DEST_BUFFER(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), xfer_dest_buffer_get_type(), XferDestBuffer)
36 #define XFER_DEST_BUFFER_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), xfer_dest_buffer_get_type(), XferDestBuffer const)
37 #define XFER_DEST_BUFFER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), xfer_dest_buffer_get_type(), XferDestBufferClass)
38 #define IS_XFER_DEST_BUFFER(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), xfer_dest_buffer_get_type ())
39 #define XFER_DEST_BUFFER_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), xfer_dest_buffer_get_type(), XferDestBufferClass)
40
41 static GObjectClass *parent_class = NULL;
42
43 /*
44  * Main object structure
45  */
46
47 typedef struct XferDestBuffer {
48     XferElement __parent__;
49
50     gsize max_size;
51
52     gpointer buf;
53     gsize len;
54     gsize allocated;
55 } XferDestBuffer;
56
57 /*
58  * Class definition
59  */
60
61 typedef struct {
62     XferElementClass __parent__;
63
64     void (*get)(XferDestBuffer *self, gpointer *buf, gsize *size);
65 } XferDestBufferClass;
66
67 /*
68  * Implementation
69  */
70
71 static void
72 get_impl(
73     XferDestBuffer *self,
74     gpointer *buf,
75     gsize *size)
76 {
77     if (size)
78         *size = self->len;
79
80     if (buf)
81         *buf = self->buf;
82 }
83
84 static void
85 push_buffer_impl(
86     XferElement *elt,
87     gpointer buf,
88     size_t len)
89 {
90     XferDestBuffer *self = (XferDestBuffer *)elt;
91
92     if (!buf)
93         return;
94
95     /* make sure this isn't too much data */
96     if (self->max_size && self->len + len > self->max_size) {
97         xfer_cancel_with_error(elt,
98             _("illegal attempt to transfer more than %zd bytes"), self->max_size);
99         wait_until_xfer_cancelled(elt->xfer);
100         amfree(buf);
101         return;
102     }
103
104     /* expand the buffer if necessary */
105     if (self->len + len > self->allocated) {
106         gsize new_size = self->allocated * 2;
107         if (new_size < self->len+len)
108             new_size = self->len+len;
109         if (self->max_size && new_size > self->max_size)
110             new_size = self->max_size;
111
112         self->buf = g_realloc(self->buf, new_size);
113         self->allocated = new_size;
114     }
115
116     g_memmove(((guint8 *)self->buf)+self->len, buf, len);
117     self->len += len;
118
119     amfree(buf);
120 }
121
122 static void
123 finalize_impl(
124     GObject * obj_self)
125 {
126     XferDestBuffer *self = XFER_DEST_BUFFER(obj_self);
127
128     if (self->buf)
129         g_free(self->buf);
130     self->buf = NULL;
131
132     /* chain up */
133     G_OBJECT_CLASS(parent_class)->finalize(obj_self);
134 }
135
136 static void
137 class_init(
138     XferDestBufferClass * selfc)
139 {
140     XferElementClass *klass = XFER_ELEMENT_CLASS(selfc);
141     GObjectClass *goc = G_OBJECT_CLASS(selfc);
142     static xfer_element_mech_pair_t mech_pairs[] = {
143         { XFER_MECH_PUSH_BUFFER, XFER_MECH_NONE, XFER_NROPS(0), XFER_NTHREADS(0) },
144         { XFER_MECH_NONE, XFER_MECH_NONE, XFER_NROPS(0), XFER_NTHREADS(0) },
145     };
146
147     selfc->get = get_impl;
148     klass->push_buffer = push_buffer_impl;
149     goc->finalize = finalize_impl;
150
151     klass->perl_class = "Amanda::Xfer::Dest::Buffer";
152     klass->mech_pairs = mech_pairs;
153
154     parent_class = g_type_class_peek_parent(selfc);
155 }
156
157 GType
158 xfer_dest_buffer_get_type (void)
159 {
160     static GType type = 0;
161
162     if G_UNLIKELY(type == 0) {
163         static const GTypeInfo info = {
164             sizeof (XferDestBufferClass),
165             (GBaseInitFunc) NULL,
166             (GBaseFinalizeFunc) NULL,
167             (GClassInitFunc) class_init,
168             (GClassFinalizeFunc) NULL,
169             NULL /* class_data */,
170             sizeof (XferDestBuffer),
171             0 /* n_preallocs */,
172             (GInstanceInitFunc) NULL,
173             NULL
174         };
175
176         type = g_type_register_static (XFER_ELEMENT_TYPE, "XferDestBuffer", &info, 0);
177     }
178
179     return type;
180 }
181
182 void
183 xfer_dest_buffer_get(
184     XferElement *elt,
185     gpointer *buf,
186     gsize *size)
187 {
188     XferDestBufferClass *klass;
189     g_assert(IS_XFER_DEST_BUFFER(elt));
190
191     klass = XFER_DEST_BUFFER_GET_CLASS(elt);
192     klass->get(XFER_DEST_BUFFER(elt), buf, size);
193 }
194
195 /* create an element of this class; prototype is in xfer-element.h */
196 XferElement *
197 xfer_dest_buffer(
198     gsize max_size)
199 {
200     XferDestBuffer *self = (XferDestBuffer *)g_object_new(XFER_DEST_BUFFER_TYPE, NULL);
201     XferElement *elt = XFER_ELEMENT(self);
202
203     self->max_size = max_size;
204
205     return elt;
206 }