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