Imported Upstream version 3.3.3
[debian/amanda] / device-src / null-device.c
1 /*
2  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 #include "amanda.h"
23 #include "device.h"
24
25 #define NULL_DEVICE_MIN_BLOCK_SIZE (1)
26 #define NULL_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
27 #define NULL_DEVICE_DEFAULT_BLOCK_SIZE DISK_BLOCK_BYTES
28
29 /*
30  * Type checking and casting macros
31  */
32 #define TYPE_NULL_DEVICE        (null_device_get_type())
33 #define NULL_DEVICE(obj)        G_TYPE_CHECK_INSTANCE_CAST((obj), null_device_get_type(), NullDevice)
34 #define NULL_DEVICE_CONST(obj)  G_TYPE_CHECK_INSTANCE_CAST((obj), null_device_get_type(), NullDevice const)
35 #define NULL_DEVICE_CLASS(klass)        G_TYPE_CHECK_CLASS_CAST((klass), null_device_get_type(), NullDeviceClass)
36 #define IS_NULL_DEVICE(obj)     G_TYPE_CHECK_INSTANCE_TYPE((obj), null_device_get_type ())
37 #define NULL_DEVICE_GET_CLASS(obj)      G_TYPE_INSTANCE_GET_CLASS((obj), null_device_get_type(), NullDeviceClass)
38 static GType null_device_get_type (void);
39
40 /*
41  * Main object structure
42  */
43 typedef struct _NullDevice NullDevice;
44 struct _NullDevice {
45         Device __parent__;
46 };
47
48 /*
49  * Class definition
50  */
51 typedef struct _NullDeviceClass NullDeviceClass;
52 struct _NullDeviceClass {
53     DeviceClass __parent__;
54 };
55
56 void null_device_register(void);
57
58 /* here are local prototypes */
59 static void null_device_init (NullDevice * o);
60 static void null_device_class_init (NullDeviceClass * c);
61 static void null_device_base_init (NullDeviceClass * c);
62 static DeviceStatusFlags null_device_read_label(Device * dself);
63 static void null_device_open_device(Device * self, char *device_name,
64                                     char * device_type, char * device_node);
65 static gboolean null_device_start (Device * self, DeviceAccessMode mode,
66                                    char * label, char * timestamp);
67 static gboolean null_device_finish (Device * pself);
68 static gboolean null_device_start_file(Device * self, dumpfile_t * jobInfo);
69 static gboolean null_device_write_block (Device * self, guint size, gpointer data);
70 static gboolean null_device_finish_file(Device * self);
71 static Device* null_device_factory(char * device_name, char * device_type, char * device_node);
72
73 /* pointer to the class of our parent */
74 static DeviceClass *parent_class = NULL;
75
76 void null_device_register(void) {
77     static const char * device_prefix_list[] = { "null", NULL };
78     register_device(null_device_factory, device_prefix_list);
79 }
80
81 static GType
82 null_device_get_type (void)
83 {
84     static GType type = 0;
85
86     if G_UNLIKELY(type == 0) {
87         static const GTypeInfo info = {
88             sizeof (NullDeviceClass),
89             (GBaseInitFunc) null_device_base_init,
90             (GBaseFinalizeFunc) NULL,
91             (GClassInitFunc) null_device_class_init,
92             (GClassFinalizeFunc) NULL,
93             NULL /* class_data */,
94             sizeof (NullDevice),
95             0 /* n_preallocs */,
96             (GInstanceInitFunc) null_device_init,
97             NULL
98         };
99
100         type = g_type_register_static (TYPE_DEVICE, "NullDevice", &info,
101                                        (GTypeFlags)0);
102     }
103
104     return type;
105 }
106
107 static void
108 null_device_init (NullDevice * self)
109 {
110     Device * dself;
111     GValue response;
112
113     dself = (Device*)(self);
114     bzero(&response, sizeof(response));
115
116     /* Register properties */
117     g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
118     g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
119     device_set_simple_property(dself, PROPERTY_CONCURRENCY,
120             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
121     g_value_unset(&response);
122
123     g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
124     g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
125     device_set_simple_property(dself, PROPERTY_STREAMING,
126             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
127     g_value_unset(&response);
128
129     g_value_init(&response, G_TYPE_BOOLEAN);
130     g_value_set_boolean(&response, FALSE);
131     device_set_simple_property(dself, PROPERTY_APPENDABLE,
132             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
133     g_value_unset(&response);
134
135     g_value_init(&response, G_TYPE_BOOLEAN);
136     g_value_set_boolean(&response, FALSE);
137     device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
138             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
139     g_value_unset(&response);
140
141     g_value_init(&response, G_TYPE_BOOLEAN);
142     g_value_set_boolean(&response, FALSE);
143     device_set_simple_property(dself, PROPERTY_FULL_DELETION,
144             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
145     g_value_unset(&response);
146
147     g_value_init(&response, G_TYPE_BOOLEAN);
148     g_value_set_boolean(&response, FALSE);
149     device_set_simple_property(dself, PROPERTY_LEOM,
150             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
151     g_value_unset(&response);
152
153     /* this device's canonical name is always "null:", regardless of
154      * the name the user supplies; note that we install the simple
155      * getter in null_device_class_init. */
156     g_value_init(&response, G_TYPE_STRING);
157     g_value_set_static_string(&response, "null:");
158     device_set_simple_property(dself, PROPERTY_CANONICAL_NAME,
159             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
160     g_value_unset(&response);
161
162     g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
163     g_value_set_enum(&response, MEDIA_ACCESS_MODE_WRITE_ONLY);
164     device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
165             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
166     g_value_unset(&response);
167 }
168
169 static void
170 null_device_class_init (NullDeviceClass * c)
171 {
172     DeviceClass *device_class = (DeviceClass *)c;
173
174     parent_class = g_type_class_ref (TYPE_DEVICE);
175
176     device_class->read_label = null_device_read_label;
177     device_class->open_device = null_device_open_device;
178     device_class->start = null_device_start;
179     device_class->finish = null_device_finish;
180     device_class->start_file = null_device_start_file;
181     device_class->write_block = null_device_write_block;
182     device_class->finish_file = null_device_finish_file;
183 }
184
185 static void
186 null_device_base_init (NullDeviceClass * c)
187 {
188     DeviceClass *device_class = (DeviceClass *)c;
189
190     /* Our canonical name is simpler than most devices' */
191     device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
192             PROPERTY_ACCESS_GET_MASK,
193             device_simple_property_get_fn,
194             device_simple_property_set_fn);
195 }
196
197
198 static Device* null_device_factory(char * device_name, char * device_type, char * device_node) {
199     Device * device;
200     g_assert(0 == strcmp(device_type, "null"));
201     device = DEVICE(g_object_new(TYPE_NULL_DEVICE, NULL));
202     device_open_device(device, device_name, device_type, device_node);
203     return device;
204 }
205
206 /* Begin virtual function overrides */
207
208 static DeviceStatusFlags
209 null_device_read_label(Device * dself) {
210     if (device_in_error(dself)) return FALSE;
211
212     device_set_error(dself,
213         stralloc(_("Can't open NULL device for reading or appending.")),
214         DEVICE_STATUS_VOLUME_UNLABELED | DEVICE_STATUS_VOLUME_ERROR);
215     return FALSE;
216 }
217
218 static void
219 null_device_open_device(Device * pself, char *device_name,
220                         char * device_type, char * device_node)
221 {
222     pself->min_block_size = NULL_DEVICE_MIN_BLOCK_SIZE;
223     pself->max_block_size = NULL_DEVICE_MAX_BLOCK_SIZE;
224     pself->block_size = NULL_DEVICE_DEFAULT_BLOCK_SIZE;
225
226     if (parent_class->open_device) {
227         parent_class->open_device(pself, device_name, device_type, device_node);
228     }
229 }
230
231 static gboolean
232 null_device_start (Device * pself, DeviceAccessMode mode,
233                    char * label, char * timestamp) {
234     NullDevice * self;
235     self = NULL_DEVICE(pself);
236
237     if (device_in_error(self)) return FALSE;
238
239     pself->access_mode = mode;
240     g_mutex_lock(pself->device_mutex);
241     pself->in_file = FALSE;
242     g_mutex_unlock(pself->device_mutex);
243
244     if (mode == ACCESS_WRITE) {
245         pself->volume_label = newstralloc(pself->volume_label, label);
246         pself->volume_time = newstralloc(pself->volume_time, timestamp);
247         pself->header_block_size = 32768;
248         return TRUE;
249     } else {
250         device_set_error(pself,
251             stralloc(_("Can't open NULL device for reading or appending.")),
252             DEVICE_STATUS_VOLUME_UNLABELED | DEVICE_STATUS_VOLUME_ERROR);
253         return FALSE;
254     }
255 }
256
257 /* This default implementation does very little. */
258 static gboolean
259 null_device_finish (Device * pself) {
260     pself->access_mode = ACCESS_NULL;
261
262     if (device_in_error(pself)) return FALSE;
263
264     return TRUE;
265 }
266
267 static gboolean
268 null_device_start_file(Device * d_self,
269                     dumpfile_t * jobInfo G_GNUC_UNUSED)
270 {
271     g_mutex_lock(d_self->device_mutex);
272     d_self->in_file = TRUE;
273     g_mutex_unlock(d_self->device_mutex);
274     d_self->is_eom = FALSE;
275     d_self->block = 0;
276     if (d_self->file <= 0)
277         d_self->file = 1;
278     else
279         d_self->file ++;
280
281     return TRUE;
282 }
283
284 static gboolean
285 null_device_write_block (Device * pself, guint size G_GNUC_UNUSED,
286             gpointer data G_GNUC_UNUSED) {
287     NullDevice * self;
288     self = NULL_DEVICE(pself);
289
290     if (device_in_error(self)) return FALSE;
291
292     pself->block++;
293
294     return TRUE;
295 }
296
297 static gboolean
298 null_device_finish_file(Device * pself) {
299     if (device_in_error(pself)) return FALSE;
300
301     g_mutex_lock(pself->device_mutex);
302     pself->in_file = FALSE;
303     g_mutex_unlock(pself->device_mutex);
304     return TRUE;
305 }