1 /*
2 * Copyright (c) 2007-2013 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 <string.h> /* memset() */
24 #include "fsusage.h"
25 #include "util.h"
26 #include <regex.h>
27
28 #include "vfs-device.h"
29
30 /* This regex will match all VfsDevice files in a directory. We use it
31 for cleanup and verification. Note that this regex does NOT match
32 the volume label. */
33 #define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
34
35 /* The name of the volume lockfile. Should be the same as that
36 generated by lockfile_name(0). */
37 #define VOLUME_LOCKFILE_NAME "00000-lock"
38
39 #define VFS_DEVICE_MIN_BLOCK_SIZE (1)
40 #define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
41 #define VFS_DEVICE_DEFAULT_BLOCK_SIZE (DISK_BLOCK_BYTES)
42 #define VFS_DEVICE_LABEL_SIZE (32768)
43
44 /* Allow comfortable room for another block and a header before PEOM */
45 #define EOM_EARLY_WARNING_ZONE_BLOCKS 4
46
47 /* Constants for free-space monitoring */
48 #define MONITOR_FREE_SPACE_EVERY_SECONDS 5
49 #define MONITOR_FREE_SPACE_EVERY_KB 102400
50 #define MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS 128
51
52 /* This looks dangerous, but is actually modified by the umask. */
53 #define VFS_DEVICE_CREAT_MODE 0666
54
55 /* Possible (abstracted) results from a system I/O operation. */
56 typedef enum {
57 RESULT_SUCCESS,
58 RESULT_ERROR, /* Undefined error. */
59 RESULT_NO_DATA, /* End of File, while reading */
60 RESULT_NO_SPACE, /* Out of space. Sometimes we don't know if
61 it was this or I/O error, but this is the
62 preferred explanation. */
63 RESULT_MAX
64 } IoResult;
65
66 void vfs_device_register(void);
67
68 /* here are local prototypes */
69 static void vfs_device_init (VfsDevice * o);
70 static void vfs_device_class_init (VfsDeviceClass * c);
71 static void vfs_device_base_init (VfsDeviceClass * c);
72 static void vfs_device_finalize (GObject * o);
73
74 static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
75 char * label, char * timestamp);
76 static gboolean vfs_device_finish (Device * pself);
77 static void vfs_device_open_device (Device * pself, char * device_name,
78 char * device_type, char * device_node);
79 static gboolean vfs_device_start_file (Device * pself, dumpfile_t * ji);
80 static gboolean vfs_device_finish_file (Device * dself);
81 static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
82 static gboolean vfs_device_seek_block (Device * self, guint64 block);
83 static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
84 static gboolean vfs_device_erase (Device * pself);
85 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node);
86 static DeviceStatusFlags vfs_device_read_label(Device * dself);
87 static gboolean vfs_device_write_block(Device * self, guint size, gpointer data);
88 static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
89 static IoResult vfs_device_robust_write(VfsDevice * self, char *buf,
90 int count);
91 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
92 int *count);
93
94 /* Various helper functions. */
95 static void release_file(VfsDevice * self);
96 static gboolean check_is_dir(VfsDevice * self, const char * name);
97 static char * file_number_to_file_name(VfsDevice * self, guint file);
98 static gboolean file_number_to_file_name_functor(const char * filename,
99 gpointer datap);
100 static gboolean vfs_device_set_max_volume_usage_fn(Device *p_self,
101 DevicePropertyBase *base, GValue *val,
102 PropertySurety surety, PropertySource source);
103 static gboolean vfs_device_set_enforce_max_volume_usage_fn(Device *p_self,
104 DevicePropertyBase *base, GValue *val,
105 PropertySurety surety, PropertySource source);
106 static gboolean property_get_monitor_free_space_fn(Device *p_self,
107 DevicePropertyBase *base, GValue *val,
108 PropertySurety *surety, PropertySource *source);
109 static gboolean property_set_monitor_free_space_fn(Device *p_self,
110 DevicePropertyBase *base, GValue *val,
111 PropertySurety surety, PropertySource source);
112 static gboolean property_set_leom_fn(Device *p_self,
113 DevicePropertyBase *base, GValue *val,
114 PropertySurety surety, PropertySource source);
115 //static char* lockfile_name(VfsDevice * self, guint file);
116 static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
117 static void promote_volume_lock(VfsDevice * self);
118 static void demote_volume_lock(VfsDevice * self);
119 static gboolean delete_vfs_files_functor(const char * filename,
120 gpointer self);
121 static gboolean check_dir_empty_functor(const char * filename,
122 gpointer self);
123 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
124 char * timestamp);
125 static int search_vfs_directory(VfsDevice *self, const char * regex,
126 SearchDirectoryFunctor functor, gpointer user_data);
127 static gint get_last_file_number(VfsDevice * self);
128 static gboolean get_last_file_number_functor(const char * filename,
129 gpointer datap);
130 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
131 static gboolean try_unlink(const char * file);
132
133 /* return TRUE if the device is going to hit ENOSPC "soon" - this is used to
134 * detect LEOM as represented by actually running out of space on the
135 * underlying filesystem. Size is the size of the buffer that is about to
136 * be written. */
137 static gboolean check_at_leom(VfsDevice *self, guint64 size);
138 /* Similar, but for PEOM */
139 static gboolean check_at_peom(VfsDevice *self, guint64 size);
140
141 /* pointer to the classes of our parents */
142 static DeviceClass *parent_class = NULL;
143
144 /* device-specific properties */
145 DevicePropertyBase device_property_monitor_free_space;
146 #define PROPERTY_MONITOR_FREE_SPACE (device_property_monitor_free_space.ID)
147
vfs_device_register(void)148 void vfs_device_register(void) {
149 static const char * device_prefix_list[] = { "file", NULL };
150
151 device_property_fill_and_register(&device_property_monitor_free_space,
152 G_TYPE_BOOLEAN, "monitor_free_space",
153 "Should VFS device monitor the filesystem's available free space?");
154
155 register_device(vfs_device_factory, device_prefix_list);
156 }
157
158 GType
vfs_device_get_type(void)159 vfs_device_get_type (void)
160 {
161 static GType type = 0;
162
163 if G_UNLIKELY(type == 0) {
164 static const GTypeInfo info = {
165 sizeof (VfsDeviceClass),
166 (GBaseInitFunc) vfs_device_base_init,
167 (GBaseFinalizeFunc) NULL,
168 (GClassInitFunc) vfs_device_class_init,
169 (GClassFinalizeFunc) NULL,
170 NULL /* class_data */,
171 sizeof (VfsDevice),
172 0 /* n_preallocs */,
173 (GInstanceInitFunc) vfs_device_init,
174 NULL
175 };
176
177 type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
178 &info, (GTypeFlags)0);
179 }
180
181 return type;
182 }
183
184 static void
vfs_device_init(VfsDevice * self)185 vfs_device_init (VfsDevice * self) {
186 Device * dself = DEVICE(self);
187 GValue response;
188
189 self->dir_name = self->file_name = NULL;
190 self->open_file_fd = -1;
191 self->volume_bytes = 0;
192 self->volume_limit = 0;
193 self->leom = TRUE;
194 self->enforce_volume_limit = TRUE;
195
196 self->monitor_free_space = TRUE;
197 self->checked_fs_free_bytes = G_MAXUINT64;
198 self->checked_fs_free_time = 0;
199 self->checked_fs_free_bytes = G_MAXUINT64;
200
201 /* Register Properties */
202 bzero(&response, sizeof(response));
203
204 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
205 g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
206 device_set_simple_property(dself, PROPERTY_CONCURRENCY,
207 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
208 g_value_unset(&response);
209
210 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
211 g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
212 device_set_simple_property(dself, PROPERTY_STREAMING,
213 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
214 g_value_unset(&response);
215
216 g_value_init(&response, G_TYPE_BOOLEAN);
217 g_value_set_boolean(&response, TRUE);
218 device_set_simple_property(dself, PROPERTY_APPENDABLE,
219 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
220 g_value_unset(&response);
221
222 g_value_init(&response, G_TYPE_BOOLEAN);
223 g_value_set_boolean(&response, TRUE);
224 device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
225 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
226 g_value_unset(&response);
227
228 g_value_init(&response, G_TYPE_BOOLEAN);
229 g_value_set_boolean(&response, TRUE);
230 device_set_simple_property(dself, PROPERTY_FULL_DELETION,
231 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
232 g_value_unset(&response);
233
234 g_value_init(&response, G_TYPE_BOOLEAN);
235 g_value_set_boolean(&response, TRUE);
236 device_set_simple_property(dself, PROPERTY_LEOM,
237 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
238 g_value_unset(&response);
239
240 g_value_init(&response, G_TYPE_BOOLEAN);
241 g_value_set_boolean(&response, TRUE);
242 device_set_simple_property(dself, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
243 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
244 g_value_unset(&response);
245
246 g_value_init(&response, G_TYPE_BOOLEAN);
247 g_value_set_boolean(&response, FALSE);
248 device_set_simple_property(dself, PROPERTY_COMPRESSION,
249 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
250 g_value_unset(&response);
251
252 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
253 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
254 device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
255 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
256 g_value_unset(&response);
257 }
258
259 static void
vfs_device_class_init(VfsDeviceClass * c)260 vfs_device_class_init (VfsDeviceClass * c)
261 {
262 GObjectClass *g_object_class = (GObjectClass*) c;
263 DeviceClass *device_class = DEVICE_CLASS(c);
264
265 parent_class = g_type_class_ref(TYPE_DEVICE);
266
267 device_class->open_device = vfs_device_open_device;
268 device_class->start = vfs_device_start;
269 device_class->start_file = vfs_device_start_file;
270 device_class->read_label = vfs_device_read_label;
271 device_class->write_block = vfs_device_write_block;
272 device_class->read_block = vfs_device_read_block;
273 device_class->finish_file = vfs_device_finish_file;
274 device_class->seek_file = vfs_device_seek_file;
275 device_class->seek_block = vfs_device_seek_block;
276 device_class->recycle_file = vfs_device_recycle_file;
277 device_class->erase = vfs_device_erase;
278 device_class->finish = vfs_device_finish;
279
280 g_object_class->finalize = vfs_device_finalize;
281 }
282
283 static void
vfs_device_base_init(VfsDeviceClass * c)284 vfs_device_base_init (VfsDeviceClass * c)
285 {
286 DeviceClass *device_class = (DeviceClass *)c;
287
288 device_class_register_property(device_class, PROPERTY_MONITOR_FREE_SPACE,
289 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK,
290 property_get_monitor_free_space_fn,
291 property_set_monitor_free_space_fn);
292
293 device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
294 (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
295 (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
296 device_simple_property_get_fn,
297 vfs_device_set_max_volume_usage_fn);
298
299 device_class_register_property(device_class, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
300 (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
301 (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
302 device_simple_property_get_fn,
303 vfs_device_set_enforce_max_volume_usage_fn);
304
305 device_class_register_property(device_class, PROPERTY_COMPRESSION,
306 PROPERTY_ACCESS_GET_MASK,
307 device_simple_property_get_fn,
308 NULL);
309
310 /* add the ability to set LEOM to FALSE, for testing purposes */
311 device_class_register_property(device_class, PROPERTY_LEOM,
312 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
313 device_simple_property_get_fn,
314 property_set_leom_fn);
315 }
316
317 static gboolean
vfs_device_set_max_volume_usage_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)318 vfs_device_set_max_volume_usage_fn(Device *p_self,
319 DevicePropertyBase *base, GValue *val,
320 PropertySurety surety, PropertySource source)
321 {
322 VfsDevice *self = VFS_DEVICE(p_self);
323
324 self->volume_limit = g_value_get_uint64(val);
325
326 return device_simple_property_set_fn(p_self, base, val, surety, source);
327 }
328
329 static gboolean
vfs_device_set_enforce_max_volume_usage_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)330 vfs_device_set_enforce_max_volume_usage_fn(Device *p_self,
331 DevicePropertyBase *base, GValue *val,
332 PropertySurety surety, PropertySource source)
333 {
334 VfsDevice *self = VFS_DEVICE(p_self);
335
336 self->enforce_volume_limit = g_value_get_boolean(val);
337
338 return device_simple_property_set_fn(p_self, base, val, surety, source);
339 }
340
341 static gboolean
property_get_monitor_free_space_fn(Device * p_self,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)342 property_get_monitor_free_space_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
343 GValue *val, PropertySurety *surety, PropertySource *source)
344 {
345 VfsDevice *self = VFS_DEVICE(p_self);
346
347 g_value_unset_init(val, G_TYPE_BOOLEAN);
348 g_value_set_boolean(val, self->monitor_free_space);
349
350 if (surety)
351 *surety = PROPERTY_SURETY_GOOD;
352
353 if (source)
354 *source = PROPERTY_SOURCE_DEFAULT;
355
356 return TRUE;
357 }
358
359
360 static gboolean
property_set_monitor_free_space_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)361 property_set_monitor_free_space_fn(Device *p_self,
362 DevicePropertyBase *base, GValue *val,
363 PropertySurety surety, PropertySource source)
364 {
365 VfsDevice *self = VFS_DEVICE(p_self);
366
367 self->monitor_free_space = g_value_get_boolean(val);
368
369 return device_simple_property_set_fn(p_self, base, val, surety, source);
370 }
371
372 static gboolean
property_set_leom_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)373 property_set_leom_fn(Device *p_self,
374 DevicePropertyBase *base, GValue *val,
375 PropertySurety surety, PropertySource source)
376 {
377 VfsDevice *self = VFS_DEVICE(p_self);
378
379 self->leom = g_value_get_boolean(val);
380
381 return device_simple_property_set_fn(p_self, base, val, surety, source);
382 }
383
384 /* Drops everything associated with the volume file: Its name and fd. */
release_file(VfsDevice * self)385 void release_file(VfsDevice * self) {
386 /* Doesn't hurt. */
387 if (self->open_file_fd != -1)
388 robust_close(self->open_file_fd);
389 amfree(self->file_name);
390
391 self->open_file_fd = -1;
392 }
393
vfs_device_finalize(GObject * obj_self)394 static void vfs_device_finalize(GObject * obj_self) {
395 VfsDevice *self = VFS_DEVICE (obj_self);
396 Device * d_self = (Device*)self;
397
398 if (d_self->access_mode != ACCESS_NULL) {
399 device_finish(d_self);
400 }
401
402 if(G_OBJECT_CLASS(parent_class)->finalize)
403 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
404
405 amfree(self->dir_name);
406
407 release_file(self);
408 }
409
vfs_device_factory(char * device_name,char * device_type,char * device_node)410 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) {
411 Device * rval;
412 g_assert(0 == strcmp(device_type, "file"));
413 rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
414 device_open_device(rval, device_name, device_type, device_node);
415 return rval;
416 }
417
check_is_dir(VfsDevice * self,const char * name)418 static gboolean check_is_dir(VfsDevice * self, const char * name) {
419 Device *dself = DEVICE(self);
420 struct stat dir_status;
421
422 if (stat(name, &dir_status) < 0) {
423 #ifdef EINTR
424 if (errno == EINTR) {
425 return check_is_dir(self, name);
426 }
427 #endif /* EINTR */
428 device_set_error(dself,
429 vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)),
430 DEVICE_STATUS_DEVICE_ERROR);
431 return FALSE;
432 } else if (!S_ISDIR(dir_status.st_mode)) {
433 device_set_error(dself,
434 vstrallocf(_("VFS Device path %s is not a directory"), name),
435 DEVICE_STATUS_DEVICE_ERROR);
436 return FALSE;
437 } else {
438 return TRUE;
439 }
440 }
441
442 typedef struct {
443 VfsDevice * self;
444 int count;
445 char * result;
446 } fnfn_data;
447
448 /* A SearchDirectoryFunctor. */
file_number_to_file_name_functor(const char * filename,gpointer datap)449 static gboolean file_number_to_file_name_functor(const char * filename,
450 gpointer datap) {
451 char * result_tmp;
452 struct stat file_status;
453 fnfn_data *data = (fnfn_data*)datap;
454
455 result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
456
457 /* Just to be thorough, let's check that it's a real
458 file. */
459 if (0 != stat(result_tmp, &file_status)) {
460 g_warning(_("Cannot stat file %s (%s), ignoring it"), result_tmp, strerror(errno));
461 } else if (!S_ISREG(file_status.st_mode)) {
462 g_warning(_("%s is not a regular file, ignoring it"), result_tmp);
463 } else {
464 data->count ++;
465 if (data->result == NULL) {
466 data->result = result_tmp;
467 result_tmp = NULL;
468 }
469 }
470 amfree(result_tmp);
471 return TRUE;
472 }
473
474 /* This function finds the filename for a given file number. We search
475 * for a filesystem file matching the regex /^0*$device_file\./; if
476 * there is more than one such file we make a warning and take an
477 * arbitrary one. */
file_number_to_file_name(VfsDevice * self,guint device_file)478 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
479 char * regex;
480 fnfn_data data;
481
482 data.self = self;
483 data.count = 0;
484 data.result = NULL;
485
486 regex = g_strdup_printf("^0*%u\\.", device_file);
487
488 search_vfs_directory(self, regex,
489 file_number_to_file_name_functor, &data);
490
491 amfree(regex);
492
493 if (data.count == 0) {
494 g_assert(data.result == NULL);
495 return NULL;
496 } else if (data.count > 1) {
497 g_warning("Found multiple names for file number %d, choosing file %s",
498 device_file, data.result);
499 return data.result;
500 } else {
501 g_assert(data.result != NULL);
502 return data.result;
503 }
504 g_assert_not_reached();
505 }
506
507 /* This function returns the dynamically-allocated lockfile name for a
508 given file number. */
509 /*
510 static char * lockfile_name(VfsDevice * self, guint number) {
511 return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
512 }
513 */
514
515 /* Does what you expect. If the lock already exists, it is released
516 * and regained, in case the mode is changing.
517 * The file field has several options:
518 * - file > 0: Open a lock on a real volume file.
519 * - file = 0: Open the volume lock as a volume file (for setup).
520 * - file < 0: Open the volume lock as a volume lock (persistantly).
521 */
open_lock(G_GNUC_UNUSED VfsDevice * self,G_GNUC_UNUSED int file,G_GNUC_UNUSED gboolean exclusive)522 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
523 G_GNUC_UNUSED int file,
524 G_GNUC_UNUSED gboolean exclusive) {
525
526 /* At the moment, file locking is horribly broken. */
527 return TRUE;
528 }
529
530 /* For now, does it the bad way. */
promote_volume_lock(VfsDevice * self G_GNUC_UNUSED)531 static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
532 }
533
demote_volume_lock(VfsDevice * self G_GNUC_UNUSED)534 static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
535 }
536
537 /* A SearchDirectoryFunctor */
update_volume_size_functor(const char * filename,gpointer user_data)538 static gboolean update_volume_size_functor(const char * filename,
539 gpointer user_data) {
540 char * full_filename;
541 struct stat stat_buf;
542 VfsDevice * self = VFS_DEVICE(user_data);
543
544 full_filename = vstralloc(self->dir_name, "/", filename, NULL);
545
546 if (stat(full_filename, &stat_buf) < 0) {
547 /* Log it and keep going. */
548 g_warning(_("Couldn't stat file %s: %s"), full_filename, strerror(errno));
549 amfree(full_filename);
550 return TRUE;
551 }
552
553 amfree(full_filename);
554 self->volume_bytes += stat_buf.st_size;
555
556 return TRUE;
557 }
558
update_volume_size(VfsDevice * self)559 static void update_volume_size(VfsDevice * self) {
560
561 self->volume_bytes = 0;
562 search_vfs_directory(self, "^[0-9]+\\.",
563 update_volume_size_functor, self);
564
565 }
566
567 static void
vfs_device_open_device(Device * pself,char * device_name,char * device_type,char * device_node)568 vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) {
569 VfsDevice * self;
570 self = VFS_DEVICE(pself);
571
572 pself->min_block_size = VFS_DEVICE_MIN_BLOCK_SIZE;
573 pself->max_block_size = VFS_DEVICE_MAX_BLOCK_SIZE;
574 pself->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
575
576 /* We don't have to free this ourselves; it will be freed by
577 * vfs_device_finalize whether we succeed here or not. */
578 self->dir_name = g_strconcat(device_node, "/data/", NULL);
579
580 if (parent_class->open_device) {
581 parent_class->open_device(pself, device_name, device_type, device_node);
582 }
583 }
584
585 /* A SearchDirectoryFunctor */
delete_vfs_files_functor(const char * filename,gpointer user_data)586 static gboolean delete_vfs_files_functor(const char * filename,
587 gpointer user_data) {
588 VfsDevice * self;
589 char * path_name;
590
591 self = VFS_DEVICE(user_data);
592
593 /* Skip the volume lock. */
594 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
595 return TRUE;
596
597 path_name = vstralloc(self->dir_name, "/", filename, NULL);
598 if (unlink(path_name) != 0) {
599 g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno));
600 }
601 amfree(path_name);
602 return TRUE;
603 }
604
605 /* delete_vfs_files deletes all VfsDevice files in the directory except the
606 volume lockfile. */
delete_vfs_files(VfsDevice * self)607 void delete_vfs_files(VfsDevice * self) {
608 g_assert(self != NULL);
609
610 /* This function assumes that the volume is locked! */
611 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
612 delete_vfs_files_functor, self);
613 }
614
615 /* This is a functor suitable for search_directory. It simply prints a
616 warning. It also dodges the volume lockfile. */
check_dir_empty_functor(const char * filename,gpointer user_data)617 static gboolean check_dir_empty_functor(const char * filename,
618 gpointer user_data) {
619 VfsDevice * self = VFS_DEVICE(user_data);
620 char * path_name;
621
622 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
623 return TRUE;
624
625 path_name = vstralloc(self->dir_name, "/", filename, NULL);
626
627 g_warning(_("Found spurious storage file %s"), path_name);
628
629 amfree(path_name);
630 return TRUE;
631 }
632
633 /* This function is used to write volume and dump headers. */
write_amanda_header(VfsDevice * self,const dumpfile_t * header)634 static gboolean write_amanda_header(VfsDevice * self,
635 const dumpfile_t * header) {
636 char * label_buffer;
637 IoResult result;
638 Device *d_self = DEVICE(self);
639
640 g_assert(header != NULL);
641
642 label_buffer = device_build_amanda_header(d_self, header, NULL);
643 if (!label_buffer) {
644 amfree(label_buffer);
645 device_set_error(d_self,
646 stralloc(_("Amanda file header won't fit in a single block!")),
647 DEVICE_STATUS_DEVICE_ERROR);
648 return FALSE;
649 }
650
651 result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
652 /* vfs_device_robust_write sets error status if necessary */
653 amfree(label_buffer);
654 return (result == RESULT_SUCCESS);
655 }
656
657 /* clear_and_label will erase the contents of the directory, and write
658 * this label in its place. This function assumes we already have a volume
659 * label write lock in place (e.g., promote_lock() has been called.) */
clear_and_prepare_label(VfsDevice * self,char * label,char * timestamp)660 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
661 char * timestamp) {
662 dumpfile_t * label_header;
663 Device *d_self = DEVICE(self);
664
665 release_file(self);
666
667 /* Delete any extant data, except our volume lock. */
668 delete_vfs_files(self);
669
670 /* Print warnings about any remaining files. */
671 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
672 check_dir_empty_functor, self);
673
674 self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
675
676 self->open_file_fd = robust_open(self->file_name,
677 O_CREAT | O_EXCL | O_WRONLY,
678 VFS_DEVICE_CREAT_MODE);
679 if (self->open_file_fd < 0) {
680 device_set_error(d_self,
681 vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)),
682 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
683 return FALSE;
684 }
685
686 label_header = make_tapestart_header(DEVICE(self), label, timestamp);
687 if (!write_amanda_header(self, label_header)) {
688 /* write_amanda_header sets error status if necessary */
689 dumpfile_free(label_header);
690 return FALSE;
691 }
692 dumpfile_free(d_self->volume_header);
693 d_self->header_block_size = VFS_DEVICE_LABEL_SIZE;
694 d_self->volume_header = label_header;
695 self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
696 return TRUE;
697 }
698
699 /* Just like search_directory, but returns -1 in the event of an error */
700 static int
search_vfs_directory(VfsDevice * self,const char * regex,SearchDirectoryFunctor functor,gpointer user_data)701 search_vfs_directory(
702 VfsDevice *self,
703 const char * regex,
704 SearchDirectoryFunctor functor,
705 gpointer user_data)
706 {
707 Device *dself = DEVICE(self);
708 DIR *dir_handle;
709 int result = -1;
710
711 dir_handle = opendir(self->dir_name);
712 if (dir_handle == NULL) {
713 device_set_error(dself,
714 vstrallocf(_("Couldn't open device %s (directory %s) for reading: %s"),
715 dself->device_name, self->dir_name, strerror(errno)),
716 DEVICE_STATUS_DEVICE_ERROR);
717 goto error;
718 }
719
720 /* TODO: is this the right moment to acquire a lock?? */
721
722 result = search_directory(dir_handle, regex, functor, user_data);
723
724 error:
725 if (dir_handle)
726 closedir(dir_handle);
727 return result;
728 }
729
vfs_device_read_label(Device * dself)730 static DeviceStatusFlags vfs_device_read_label(Device * dself) {
731 VfsDevice * self = VFS_DEVICE(dself);
732 dumpfile_t * amanda_header;
733
734 g_assert(self != NULL);
735
736 if (!check_is_dir(self, self->dir_name)) {
737 /* error message set by check_is_dir */
738 return dself->status;
739 }
740
741 amfree(dself->volume_label);
742 amfree(dself->volume_time);
743 dumpfile_free(dself->volume_header);
744 dself->volume_header = NULL;
745
746 if (device_in_error(dself)) return dself->status;
747
748 amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0);
749 release_file(self);
750 if (amanda_header == NULL) {
751 /* This means an error occured getting locks or opening the header
752 * file. */
753 device_set_error(dself,
754 stralloc("Error loading device header -- unlabeled volume?"),
755 DEVICE_STATUS_DEVICE_ERROR
756 | DEVICE_STATUS_VOLUME_ERROR
757 | DEVICE_STATUS_VOLUME_UNLABELED);
758 return dself->status;
759 }
760
761 /* close the fd we just opened */
762 vfs_device_finish_file(dself);
763
764 if (amanda_header->type != F_TAPESTART &&
765 amanda_header->type != F_EMPTY) {
766 /* This is an error, and should not happen. */
767 device_set_error(dself,
768 stralloc(_("Got a bad volume label")),
769 DEVICE_STATUS_VOLUME_ERROR);
770 amfree(amanda_header);
771 return dself->status;
772 }
773
774 /* self->volume_header is already set */
775
776 if (amanda_header->type == F_TAPESTART) {
777 dself->volume_label = g_strdup(amanda_header->name);
778 dself->volume_time = g_strdup(amanda_header->datestamp);
779 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
780 }
781
782 update_volume_size(self);
783
784 return dself->status;
785 }
786
vfs_device_write_block(Device * pself,guint size,gpointer data)787 static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) {
788 VfsDevice * self = VFS_DEVICE(pself);
789 IoResult result;
790
791 if (device_in_error(self)) return FALSE;
792
793 g_assert(self->open_file_fd >= 0);
794
795 if (check_at_leom(self, size))
796 pself->is_eom = TRUE;
797
798 if (check_at_peom(self, size)) {
799 /* check_at_peom() only checks against MAX_VOLUME_USAGE limit */
800 pself->is_eom = TRUE;
801 device_set_error(pself,
802 stralloc(_("No space left on device: more than MAX_VOLUME_USAGE bytes written")),
803 DEVICE_STATUS_VOLUME_ERROR);
804 return FALSE;
805 }
806
807 result = vfs_device_robust_write(self, data, size);
808 if (result != RESULT_SUCCESS) {
809 /* vfs_device_robust_write set error status appropriately */
810 return FALSE;
811 }
812
813 self->volume_bytes += size;
814 self->checked_bytes_used += size;
815 pself->block ++;
816 g_mutex_lock(pself->device_mutex);
817 pself->bytes_written += size;
818 g_mutex_unlock(pself->device_mutex);
819
820 return TRUE;
821 }
822
823 static int
vfs_device_read_block(Device * pself,gpointer data,int * size_req)824 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
825 VfsDevice * self;
826 int size;
827 IoResult result;
828
829 self = VFS_DEVICE(pself);
830
831 if (device_in_error(self)) return -1;
832
833 if (data == NULL || (gsize)*size_req < pself->block_size) {
834 /* Just a size query. */
835 g_assert(pself->block_size < INT_MAX);
836 *size_req = (int)pself->block_size;
837 return 0;
838 }
839
840 size = pself->block_size;
841 result = vfs_device_robust_read(self, data, &size);
842 switch (result) {
843 case RESULT_SUCCESS:
844 *size_req = size;
845 g_mutex_lock(pself->device_mutex);
846 pself->bytes_read += size;
847 g_mutex_unlock(pself->device_mutex);
848 pself->block++;
849 return size;
850 case RESULT_NO_DATA:
851 pself->is_eof = TRUE;
852 g_mutex_lock(pself->device_mutex);
853 pself->in_file = FALSE;
854 g_mutex_unlock(pself->device_mutex);
855 device_set_error(pself,
856 stralloc(_("EOF")),
857 DEVICE_STATUS_SUCCESS);
858 return -1;
859 default:
860 device_set_error(pself,
861 vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
862 DEVICE_STATUS_DEVICE_ERROR);
863 return -1;
864 }
865
866 g_assert_not_reached();
867 }
868
869 static gboolean
vfs_device_start(Device * dself,DeviceAccessMode mode,char * label,char * timestamp)870 vfs_device_start(Device * dself,
871 DeviceAccessMode mode, char * label,
872 char * timestamp) {
873 VfsDevice * self = VFS_DEVICE(dself);
874
875 if (!check_is_dir(self, self->dir_name)) {
876 /* error message set by check_is_dir */
877 return FALSE;
878 }
879
880 g_mutex_lock(dself->device_mutex);
881 dself->in_file = FALSE;
882 g_mutex_unlock(dself->device_mutex);
883
884 if (mode == ACCESS_WRITE) {
885 promote_volume_lock(self);
886 if (!clear_and_prepare_label(self, label, timestamp)) {
887 /* clear_and_prepare_label sets error status if necessary */
888 demote_volume_lock(self);
889 return FALSE;
890 }
891
892 dself->volume_label = newstralloc(dself->volume_label, label);
893 dself->volume_time = newstralloc(dself->volume_time, timestamp);
894
895 /* unset the VOLUME_UNLABELED flag, if it was set */
896 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
897
898 demote_volume_lock(self);
899 dself->access_mode = mode;
900 } else {
901 if (dself->volume_label == NULL && device_read_label(dself) != DEVICE_STATUS_SUCCESS) {
902 /* device_read_label already set our error message */
903 return FALSE;
904 } else {
905 dself->access_mode = mode;
906 }
907 }
908
909 release_file(self);
910
911 return TRUE;
912 }
913
914 static gboolean
vfs_device_finish(Device * pself)915 vfs_device_finish (Device * pself) {
916 VfsDevice * self;
917 self = VFS_DEVICE(pself);
918
919 release_file(self);
920
921 pself->access_mode = ACCESS_NULL;
922 g_mutex_lock(pself->device_mutex);
923 pself->in_file = FALSE;
924 g_mutex_unlock(pself->device_mutex);
925
926 if (device_in_error(self)) return FALSE;
927
928 return TRUE;
929 }
930
931 typedef struct {
932 VfsDevice * self;
933 int rval;
934 } glfn_data;
935
936 /* A SearchDirectoryFunctor. */
get_last_file_number_functor(const char * filename,gpointer datap)937 static gboolean get_last_file_number_functor(const char * filename,
938 gpointer datap) {
939 guint64 file;
940 glfn_data * data = (glfn_data*)datap;
941
942 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
943 if (file > G_MAXINT) {
944 g_warning(_("Super-large device file %s found, ignoring"), filename);
945 return TRUE;
946 }
947 /* This condition is needlessly complex due to sign issues. */
948 if (data->rval < 0 || ((guint)data->rval) < file) {
949 data->rval = file;
950 }
951 return TRUE;
952 }
953
954 static gint
get_last_file_number(VfsDevice * self)955 get_last_file_number(VfsDevice * self) {
956 glfn_data data;
957 int count;
958 Device *d_self = DEVICE(self);
959 data.self = self;
960 data.rval = -1;
961
962 count = search_vfs_directory(self, "^[0-9]+\\.",
963 get_last_file_number_functor, &data);
964
965 if (count <= 0) {
966 /* Somebody deleted something important while we weren't looking. */
967 device_set_error(d_self,
968 stralloc(_("Error identifying VFS device contents!")),
969 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
970 return -1;
971 } else {
972 g_assert(data.rval >= 0);
973 }
974
975 return data.rval;
976 }
977
978 typedef struct {
979 VfsDevice * self;
980 guint request;
981 int best_found;
982 } gnfn_data;
983
984 /* A SearchDirectoryFunctor. */
get_next_file_number_functor(const char * filename,gpointer datap)985 static gboolean get_next_file_number_functor(const char * filename,
986 gpointer datap) {
987 guint file;
988 gnfn_data * data = (gnfn_data*)datap;
989
990 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
991 if (file > G_MAXINT) {
992 g_warning(_("Super-large device file %s found, ignoring"), filename);
993 return TRUE;
994 }
995 /* This condition is needlessly complex due to sign issues. */
996 if (file >= data->request &&
997 (data->best_found < 0 || file < (guint)data->best_found)) {
998 data->best_found = file;
999 }
1000 return TRUE;
1001 }
1002
1003 /* Returns the file number equal to or greater than the given requested
1004 * file number. */
1005 static gint
get_next_file_number(VfsDevice * self,guint request)1006 get_next_file_number(VfsDevice * self, guint request) {
1007 gnfn_data data;
1008 int count;
1009 Device *d_self = DEVICE(self);
1010 data.self = self;
1011 data.request = request;
1012 data.best_found = -1;
1013
1014 count = search_vfs_directory(self, "^[0-9]+\\.",
1015 get_next_file_number_functor, &data);
1016
1017 if (count <= 0) {
1018 /* Somebody deleted something important while we weren't looking. */
1019 device_set_error(d_self,
1020 stralloc(_("Error identifying VFS device contents!")),
1021 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1022 return -1;
1023 }
1024
1025 /* Could be -1. */
1026 return data.best_found;
1027 }
1028
1029 /* Finds the file number, acquires a lock, and returns the new file name. */
1030 static
make_new_file_name(VfsDevice * self,const dumpfile_t * ji)1031 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
1032 char * rval;
1033 char *base, *sanitary_base;
1034 int fileno;
1035
1036 for (;;) {
1037 fileno = 1 + get_last_file_number(self);
1038 if (fileno <= 0)
1039 return NULL;
1040
1041 if (open_lock(self, fileno, TRUE)) {
1042 break;
1043 } else {
1044 continue;
1045 }
1046 }
1047
1048 /* record that we're at this filenum now */
1049 DEVICE(self)->file = fileno;
1050
1051 base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
1052 ji->dumplevel);
1053 sanitary_base = sanitise_filename(base);
1054 amfree(base);
1055 rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
1056 amfree(sanitary_base);
1057 return rval;
1058 }
1059
1060 static gboolean
vfs_device_start_file(Device * dself,dumpfile_t * ji)1061 vfs_device_start_file (Device * dself, dumpfile_t * ji) {
1062 VfsDevice * self = VFS_DEVICE(dself);
1063
1064 dself->is_eom = FALSE;
1065
1066 if (device_in_error(self)) return FALSE;
1067
1068 /* set the blocksize in the header to 32k, since the VFS header is always
1069 * 32k regardless of the block_size setting */
1070 ji->blocksize = 32768;
1071
1072 if (check_at_leom(self, VFS_DEVICE_LABEL_SIZE))
1073 dself->is_eom = TRUE;
1074
1075 if (check_at_peom(self, VFS_DEVICE_LABEL_SIZE)) {
1076 /* check_at_peom() only checks against MAX_VOLUME_USAGE limit */
1077 dself->is_eom = TRUE;
1078 device_set_error(dself,
1079 stralloc(_("No space left on device: more than MAX_VOLUME_USAGE bytes written")),
1080 DEVICE_STATUS_DEVICE_ERROR);
1081 return FALSE;
1082 }
1083
1084 /* The basic idea here is thus:
1085 1) Try to get a lock on the next filenumber.
1086 2) If that fails, update our idea of "next filenumber" and try again.
1087 3) Then open the file itself.
1088 4) Write the label.
1089 5) Chain up. */
1090
1091 self->file_name = make_new_file_name(self, ji);
1092 if (self->file_name == NULL) {
1093 device_set_error(dself,
1094 stralloc(_("Could not create header filename")),
1095 DEVICE_STATUS_DEVICE_ERROR);
1096 return FALSE;
1097 }
1098
1099 self->open_file_fd = robust_open(self->file_name,
1100 O_CREAT | O_EXCL | O_RDWR,
1101 VFS_DEVICE_CREAT_MODE);
1102 if (self->open_file_fd < 0) {
1103 device_set_error(dself,
1104 vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)),
1105 DEVICE_STATUS_DEVICE_ERROR);
1106 release_file(self);
1107 return FALSE;
1108 }
1109
1110
1111 if (!write_amanda_header(self, ji)) {
1112 /* write_amanda_header sets error status if necessary */
1113 release_file(self);
1114 return FALSE;
1115 }
1116
1117 /* handle some accounting business */
1118 self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1119 self->checked_bytes_used += VFS_DEVICE_LABEL_SIZE;
1120 dself->block = 0;
1121 g_mutex_lock(dself->device_mutex);
1122 dself->in_file = TRUE;
1123 dself->bytes_written = 0;
1124 g_mutex_unlock(dself->device_mutex);
1125 /* make_new_file_name set pself->file for us */
1126
1127 return TRUE;
1128 }
1129
1130 static gboolean
vfs_device_finish_file(Device * dself)1131 vfs_device_finish_file(Device * dself) {
1132 VfsDevice * self = VFS_DEVICE(dself);
1133
1134 if (!dself->in_file)
1135 return TRUE;
1136
1137 g_mutex_lock(dself->device_mutex);
1138 dself->in_file = FALSE;
1139 g_mutex_unlock(dself->device_mutex);
1140
1141 release_file(self);
1142
1143 if (device_in_error(self)) return FALSE;
1144
1145 return TRUE;
1146 }
1147
1148 /* This function is used for two purposes, rather than one. In
1149 * addition to its documented behavior, we also use it to open the
1150 * volume label for reading at startup. In that second case, we avoid
1151 * FdDevice-related side effects. */
1152 static dumpfile_t *
vfs_device_seek_file(Device * dself,guint requested_file)1153 vfs_device_seek_file (Device * dself, guint requested_file) {
1154 VfsDevice *self = VFS_DEVICE(dself);
1155 int file;
1156 dumpfile_t * rval;
1157 char header_buffer[VFS_DEVICE_LABEL_SIZE];
1158 int header_buffer_size = sizeof(header_buffer);
1159 IoResult result;
1160
1161 if (device_in_error(self)) return NULL;
1162
1163 dself->is_eof = FALSE;
1164 dself->block = 0;
1165 g_mutex_lock(dself->device_mutex);
1166 dself->in_file = FALSE;
1167 dself->bytes_read = 0;
1168 g_mutex_unlock(dself->device_mutex);
1169
1170 release_file(self);
1171
1172 if (requested_file > 0) {
1173 file = get_next_file_number(self, requested_file);
1174 } else {
1175 file = requested_file;
1176 }
1177
1178 if (file < 0) {
1179 /* Did they request one past the end? */
1180 char * tmp_file_name;
1181 tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1182 if (tmp_file_name != NULL) {
1183 free(tmp_file_name);
1184 dself->file = requested_file; /* other attributes are already correct */
1185 return make_tapeend_header();
1186 } else {
1187 device_set_error(dself,
1188 stralloc(_("Attempt to read past tape-end file")),
1189 DEVICE_STATUS_SUCCESS);
1190 return NULL;
1191 }
1192 }
1193
1194 if (!open_lock(self, file, FALSE)) {
1195 device_set_error(dself,
1196 stralloc(_("could not acquire lock")),
1197 DEVICE_STATUS_DEVICE_ERROR);
1198 return NULL;
1199 }
1200
1201 self->file_name = file_number_to_file_name(self, file);
1202 if (self->file_name == NULL) {
1203 device_set_error(dself,
1204 vstrallocf(_("File %d not found"), file),
1205 file == 0 ? DEVICE_STATUS_VOLUME_UNLABELED
1206 : DEVICE_STATUS_VOLUME_ERROR);
1207 release_file(self);
1208 rval = g_new(dumpfile_t, 1);
1209 fh_init(rval);
1210 return rval;
1211 }
1212
1213 self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1214 if (self->open_file_fd < 0) {
1215 device_set_error(dself,
1216 vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1217 DEVICE_STATUS_DEVICE_ERROR);
1218 amfree(self->file_name);
1219 release_file(self);
1220 return NULL;
1221 }
1222
1223 result = vfs_device_robust_read(self, header_buffer,
1224 &header_buffer_size);
1225 if (result != RESULT_SUCCESS) {
1226 device_set_error(dself,
1227 vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1228 DEVICE_STATUS_VOLUME_ERROR);
1229 release_file(self);
1230 return NULL;
1231 }
1232
1233 rval = g_new(dumpfile_t, 1);
1234 parse_file_header(header_buffer, rval, header_buffer_size);
1235 switch (rval->type) {
1236 case F_DUMPFILE:
1237 case F_CONT_DUMPFILE:
1238 case F_SPLIT_DUMPFILE:
1239 break;
1240
1241 case F_TAPESTART:
1242 /* file 0 should have a TAPESTART header; vfs_device_read_label
1243 * uses this */
1244 if (requested_file == 0)
1245 break;
1246 /* FALLTHROUGH */
1247
1248 default:
1249 device_set_error(dself,
1250 stralloc(_("Invalid amanda header while reading file header")),
1251 DEVICE_STATUS_VOLUME_ERROR);
1252 amfree(rval);
1253 release_file(self);
1254 return NULL;
1255 }
1256
1257 /* update our state */
1258 if (requested_file == 0) {
1259 dself->header_block_size = header_buffer_size;
1260 }
1261 g_mutex_lock(dself->device_mutex);
1262 dself->in_file = TRUE;
1263 g_mutex_unlock(dself->device_mutex);
1264 dself->file = file;
1265
1266 return rval;
1267 }
1268
1269 static gboolean
vfs_device_seek_block(Device * pself,guint64 block)1270 vfs_device_seek_block (Device * pself, guint64 block) {
1271 VfsDevice * self;
1272 off_t result;
1273
1274 self = VFS_DEVICE(pself);
1275
1276 g_assert(self->open_file_fd >= 0);
1277 g_assert(sizeof(off_t) >= sizeof(guint64));
1278 if (device_in_error(self)) return FALSE;
1279
1280 /* Pretty simple. We figure out the blocksize and use that. */
1281 result = lseek(self->open_file_fd,
1282 (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1283 SEEK_SET);
1284
1285 pself->block = block;
1286
1287 if (result == (off_t)(-1)) {
1288 device_set_error(pself,
1289 vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1290 DEVICE_STATUS_DEVICE_ERROR);
1291 return FALSE;
1292 }
1293
1294 return TRUE;
1295 }
1296
try_unlink(const char * file)1297 static gboolean try_unlink(const char * file) {
1298 if (unlink(file) < 0) {
1299 return FALSE;
1300 } else {
1301 return TRUE;
1302 }
1303 }
1304
1305 static gboolean
check_at_leom(VfsDevice * self,guint64 size)1306 check_at_leom(VfsDevice *self, guint64 size)
1307 {
1308 gboolean recheck = FALSE;
1309 guint64 est_avail_now;
1310 struct fs_usage fsusage;
1311 guint64 block_size = DEVICE(self)->block_size;
1312 guint64 eom_warning_buffer = EOM_EARLY_WARNING_ZONE_BLOCKS * block_size;
1313
1314 if (!self->leom || !self->monitor_free_space)
1315 return FALSE;
1316
1317 /* handle VOLUME_LIMIT */
1318 if (self->enforce_volume_limit && self->volume_limit &&
1319 self->volume_bytes + size + eom_warning_buffer > self->volume_limit) {
1320 return TRUE;
1321 }
1322
1323 /* handle actual filesystem available space, using some heuristics to avoid polling this
1324 * too frequently */
1325 est_avail_now = 0;
1326 if (self->checked_fs_free_bytes >= self->checked_bytes_used + size)
1327 est_avail_now = self->checked_fs_free_bytes - self->checked_bytes_used - size;
1328
1329 /* is it time to check again? */
1330 if (est_avail_now <= block_size * MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS) {
1331 recheck = TRUE;
1332 } else if (self->checked_bytes_used > MONITOR_FREE_SPACE_EVERY_KB * 1024) {
1333 recheck = TRUE;
1334 } else if (self->checked_fs_free_time + MONITOR_FREE_SPACE_EVERY_SECONDS <= time(NULL)) {
1335 recheck = TRUE;
1336 }
1337
1338 if (!recheck)
1339 return FALSE;
1340
1341 if (get_fs_usage(self->dir_name, NULL, &fsusage) < 0 || fsusage.fsu_bavail_top_bit_set) {
1342 g_warning("Filesystem cannot provide free space: %s; setting MONITOR_FREE_SPACE false",
1343 fsusage.fsu_bavail_top_bit_set? "no result" : strerror(errno));
1344 self->monitor_free_space = FALSE;
1345 return FALSE;
1346 }
1347
1348 self->checked_fs_free_bytes = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1349 self->checked_bytes_used = 0;
1350 self->checked_fs_free_time = time(NULL);
1351
1352 if (self->checked_fs_free_bytes - size <= eom_warning_buffer) {
1353 g_debug("%s: at LEOM", DEVICE(self)->device_name);
1354 return TRUE;
1355 }
1356
1357 return FALSE;
1358 }
1359
1360 static gboolean
check_at_peom(VfsDevice * self,guint64 size)1361 check_at_peom(VfsDevice *self, guint64 size)
1362 {
1363 if (self->enforce_volume_limit && (self->volume_limit > 0)) {
1364 guint64 newtotal = self->volume_bytes + size;
1365 if (newtotal > self->volume_limit) {
1366 return TRUE;
1367 }
1368 }
1369
1370 return FALSE;
1371 }
1372
1373 static gboolean
vfs_device_recycle_file(Device * dself,guint filenum)1374 vfs_device_recycle_file (Device * dself, guint filenum) {
1375 VfsDevice * self = VFS_DEVICE(dself);
1376 struct stat file_status;
1377 off_t file_size;
1378
1379 if (device_in_error(self)) return FALSE;
1380
1381 /* Game Plan:
1382 * 1) Get a write lock on the file in question.
1383 * 2) Unlink the file in question.
1384 * 3) Unlink the lock.
1385 * 4) Release the lock.
1386 * FIXME: Is it OK to unlink the lockfile?
1387 */
1388
1389 self->file_name = file_number_to_file_name(self, filenum);
1390 if (self->file_name == NULL) {
1391 device_set_error(dself,
1392 vstrallocf(_("File %d not found"), filenum),
1393 DEVICE_STATUS_VOLUME_ERROR);
1394 return FALSE;
1395 }
1396
1397 if (!open_lock(self, filenum, FALSE)) {
1398 device_set_error(dself,
1399 stralloc(_("could not acquire lock")),
1400 DEVICE_STATUS_DEVICE_ERROR);
1401 return FALSE;
1402 }
1403
1404 if (0 != stat(self->file_name, &file_status)) {
1405 device_set_error(dself,
1406 vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1407 self->file_name, strerror(errno)),
1408 DEVICE_STATUS_VOLUME_ERROR);
1409 return FALSE;
1410 }
1411 file_size = file_status.st_size;
1412
1413 if (!try_unlink(self->file_name)) {
1414 device_set_error(dself,
1415 vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1416 DEVICE_STATUS_VOLUME_ERROR);
1417 release_file(self);
1418 return FALSE;
1419 }
1420
1421 self->volume_bytes -= file_size;
1422 release_file(self);
1423 return TRUE;
1424 }
1425
1426 static gboolean
vfs_device_erase(Device * dself)1427 vfs_device_erase (Device * dself) {
1428 VfsDevice *self = VFS_DEVICE(dself);
1429
1430 if (!open_lock(self, 0, TRUE))
1431 return FALSE;
1432
1433 delete_vfs_files(self);
1434
1435 release_file(self);
1436
1437 dumpfile_free(dself->volume_header);
1438 dself->volume_header = NULL;
1439 device_set_error(dself, g_strdup("Unlabeled volume"),
1440 DEVICE_STATUS_VOLUME_UNLABELED);
1441
1442 return TRUE;
1443 }
1444
vfs_device_robust_read(VfsDevice * self,char * buf,int * count)1445 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1446 int *count) {
1447 int fd = self->open_file_fd;
1448 Device *d_self = DEVICE(self);
1449 int want = *count, got = 0;
1450
1451 while (got < want) {
1452 int result;
1453 result = read(fd, buf + got, want - got);
1454 if (result > 0) {
1455 got += result;
1456 } else if (result == 0) {
1457 /* end of file */
1458 if (got == 0) {
1459 return RESULT_NO_DATA;
1460 } else {
1461 *count = got;
1462 return RESULT_SUCCESS;
1463 }
1464 } else if (0
1465 #ifdef EAGAIN
1466 || errno == EAGAIN
1467 #endif
1468 #ifdef EWOULDBLOCK
1469 || errno == EWOULDBLOCK
1470 #endif
1471 #ifdef EINTR
1472 || errno == EINTR
1473 #endif
1474 ) {
1475 /* Try again. */
1476 continue;
1477 } else {
1478 /* Error occured. */
1479 device_set_error(d_self,
1480 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1481 DEVICE_STATUS_VOLUME_ERROR);
1482 *count = got;
1483 return RESULT_ERROR;
1484 }
1485 }
1486
1487 *count = got;
1488 return RESULT_SUCCESS;
1489 }
1490
1491 static IoResult
vfs_device_robust_write(VfsDevice * self,char * buf,int count)1492 vfs_device_robust_write(VfsDevice * self, char *buf, int count) {
1493 int fd = self->open_file_fd;
1494 Device *d_self = DEVICE(self);
1495 int rval = 0;
1496
1497 while (rval < count) {
1498 int result;
1499 result = write(fd, buf + rval, count - rval);
1500 if (result > 0) {
1501 rval += result;
1502 continue;
1503 } else if (0
1504 #ifdef EAGAIN
1505 || errno == EAGAIN
1506 #endif
1507 #ifdef EWOULDBLOCK
1508 || errno == EWOULDBLOCK
1509 #endif
1510 #ifdef EINTR
1511 || errno == EINTR
1512 #endif
1513 ) {
1514 /* Try again. */
1515 continue;
1516 } else if (0
1517 #ifdef EFBIG
1518 || errno == EFBIG
1519 #endif
1520 #ifdef ENOSPC
1521 || errno == ENOSPC
1522 #endif
1523 ) {
1524 /* We are definitely out of space. */
1525 device_set_error(d_self,
1526 vstrallocf(_("No space left on device: %s"), strerror(errno)),
1527 DEVICE_STATUS_VOLUME_ERROR);
1528 return RESULT_NO_SPACE;
1529 } else {
1530 /* Error occured. Note that here we handle EIO as an error. */
1531 device_set_error(d_self,
1532 vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1533 DEVICE_STATUS_VOLUME_ERROR);
1534 return RESULT_ERROR;
1535 }
1536 }
1537 return RESULT_SUCCESS;
1538 }
1539
1540 /* TODO: add prop */
1541