2 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
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.
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
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
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
23 #include <string.h> /* memset() */
28 #include "vfs-device.h"
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
33 #define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
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"
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)
44 /* Allow comfortable room for another block and a header before PEOM */
45 #define EOM_EARLY_WARNING_ZONE_BLOCKS 4
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
52 /* This looks dangerous, but is actually modified by the umask. */
53 #define VFS_DEVICE_CREAT_MODE 0666
55 /* Possible (abstracted) results from a system I/O operation. */
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. */
66 void vfs_device_register(void);
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);
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,
91 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
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,
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,
121 static gboolean check_dir_empty_functor(const char * filename,
123 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
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,
130 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
131 static gboolean try_unlink(const char * file);
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
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);
141 /* pointer to the classes of our parents */
142 static DeviceClass *parent_class = NULL;
144 /* device-specific properties */
145 DevicePropertyBase device_property_monitor_free_space;
146 #define PROPERTY_MONITOR_FREE_SPACE (device_property_monitor_free_space.ID)
148 void vfs_device_register(void) {
149 static const char * device_prefix_list[] = { "file", NULL };
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?");
155 register_device(vfs_device_factory, device_prefix_list);
159 vfs_device_get_type (void)
161 static GType type = 0;
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 */,
173 (GInstanceInitFunc) vfs_device_init,
177 type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
178 &info, (GTypeFlags)0);
185 vfs_device_init (VfsDevice * self) {
186 Device * dself = DEVICE(self);
189 self->dir_name = self->file_name = NULL;
190 self->open_file_fd = -1;
191 self->volume_bytes = 0;
192 self->volume_limit = 0;
194 self->enforce_volume_limit = TRUE;
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;
201 /* Register Properties */
202 bzero(&response, sizeof(response));
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);
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);
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);
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);
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);
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);
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);
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);
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);
260 vfs_device_class_init (VfsDeviceClass * c)
262 GObjectClass *g_object_class = (GObjectClass*) c;
263 DeviceClass *device_class = DEVICE_CLASS(c);
265 parent_class = g_type_class_ref(TYPE_DEVICE);
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;
280 g_object_class->finalize = vfs_device_finalize;
284 vfs_device_base_init (VfsDeviceClass * c)
286 DeviceClass *device_class = (DeviceClass *)c;
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);
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);
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);
305 device_class_register_property(device_class, PROPERTY_COMPRESSION,
306 PROPERTY_ACCESS_GET_MASK,
307 device_simple_property_get_fn,
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);
318 vfs_device_set_max_volume_usage_fn(Device *p_self,
319 DevicePropertyBase *base, GValue *val,
320 PropertySurety surety, PropertySource source)
322 VfsDevice *self = VFS_DEVICE(p_self);
324 self->volume_limit = g_value_get_uint64(val);
326 return device_simple_property_set_fn(p_self, base, val, surety, source);
330 vfs_device_set_enforce_max_volume_usage_fn(Device *p_self,
331 DevicePropertyBase *base, GValue *val,
332 PropertySurety surety, PropertySource source)
334 VfsDevice *self = VFS_DEVICE(p_self);
336 self->enforce_volume_limit = g_value_get_boolean(val);
338 return device_simple_property_set_fn(p_self, base, val, surety, source);
342 property_get_monitor_free_space_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
343 GValue *val, PropertySurety *surety, PropertySource *source)
345 VfsDevice *self = VFS_DEVICE(p_self);
347 g_value_unset_init(val, G_TYPE_BOOLEAN);
348 g_value_set_boolean(val, self->monitor_free_space);
351 *surety = PROPERTY_SURETY_GOOD;
354 *source = PROPERTY_SOURCE_DEFAULT;
361 property_set_monitor_free_space_fn(Device *p_self,
362 DevicePropertyBase *base, GValue *val,
363 PropertySurety surety, PropertySource source)
365 VfsDevice *self = VFS_DEVICE(p_self);
367 self->monitor_free_space = g_value_get_boolean(val);
369 return device_simple_property_set_fn(p_self, base, val, surety, source);
373 property_set_leom_fn(Device *p_self,
374 DevicePropertyBase *base, GValue *val,
375 PropertySurety surety, PropertySource source)
377 VfsDevice *self = VFS_DEVICE(p_self);
379 self->leom = g_value_get_boolean(val);
381 return device_simple_property_set_fn(p_self, base, val, surety, source);
384 /* Drops everything associated with the volume file: Its name and fd. */
385 void release_file(VfsDevice * self) {
387 if (self->open_file_fd != -1)
388 robust_close(self->open_file_fd);
389 amfree(self->file_name);
391 self->open_file_fd = -1;
394 static void vfs_device_finalize(GObject * obj_self) {
395 VfsDevice *self = VFS_DEVICE (obj_self);
396 Device * d_self = (Device*)self;
398 if (d_self->access_mode != ACCESS_NULL) {
399 device_finish(d_self);
402 if(G_OBJECT_CLASS(parent_class)->finalize)
403 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
405 amfree(self->dir_name);
410 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) {
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);
418 static gboolean check_is_dir(VfsDevice * self, const char * name) {
419 Device *dself = DEVICE(self);
420 struct stat dir_status;
422 if (stat(name, &dir_status) < 0) {
424 if (errno == EINTR) {
425 return check_is_dir(self, name);
428 device_set_error(dself,
429 vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)),
430 DEVICE_STATUS_DEVICE_ERROR);
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);
448 /* A SearchDirectoryFunctor. */
449 static gboolean file_number_to_file_name_functor(const char * filename,
452 struct stat file_status;
453 fnfn_data *data = (fnfn_data*)datap;
455 result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
457 /* Just to be thorough, let's check that it's a real
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);
465 if (data->result == NULL) {
466 data->result = result_tmp;
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
478 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
486 regex = g_strdup_printf("^0*%u\\.", device_file);
488 search_vfs_directory(self, regex,
489 file_number_to_file_name_functor, &data);
493 if (data.count == 0) {
494 g_assert(data.result == 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);
501 g_assert(data.result != NULL);
504 g_assert_not_reached();
507 /* This function returns the dynamically-allocated lockfile name for a
508 given file number. */
510 static char * lockfile_name(VfsDevice * self, guint number) {
511 return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
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).
522 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
523 G_GNUC_UNUSED int file,
524 G_GNUC_UNUSED gboolean exclusive) {
526 /* At the moment, file locking is horribly broken. */
530 /* For now, does it the bad way. */
531 static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
534 static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
537 /* A SearchDirectoryFunctor */
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);
544 full_filename = vstralloc(self->dir_name, "/", filename, NULL);
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);
553 amfree(full_filename);
554 self->volume_bytes += stat_buf.st_size;
559 static void update_volume_size(VfsDevice * self) {
561 self->volume_bytes = 0;
562 search_vfs_directory(self, "^[0-9]+\\.",
563 update_volume_size_functor, self);
568 vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) {
570 self = VFS_DEVICE(pself);
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;
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);
580 if (parent_class->open_device) {
581 parent_class->open_device(pself, device_name, device_type, device_node);
585 /* A SearchDirectoryFunctor */
586 static gboolean delete_vfs_files_functor(const char * filename,
587 gpointer user_data) {
591 self = VFS_DEVICE(user_data);
593 /* Skip the volume lock. */
594 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
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));
605 /* delete_vfs_files deletes all VfsDevice files in the directory except the
607 void delete_vfs_files(VfsDevice * self) {
608 g_assert(self != NULL);
610 /* This function assumes that the volume is locked! */
611 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
612 delete_vfs_files_functor, self);
615 /* This is a functor suitable for search_directory. It simply prints a
616 warning. It also dodges the volume lockfile. */
617 static gboolean check_dir_empty_functor(const char * filename,
618 gpointer user_data) {
619 VfsDevice * self = VFS_DEVICE(user_data);
622 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
625 path_name = vstralloc(self->dir_name, "/", filename, NULL);
627 g_warning(_("Found spurious storage file %s"), path_name);
633 /* This function is used to write volume and dump headers. */
634 static gboolean write_amanda_header(VfsDevice * self,
635 const dumpfile_t * header) {
638 Device *d_self = DEVICE(self);
640 g_assert(header != NULL);
642 label_buffer = device_build_amanda_header(d_self, header, NULL);
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);
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);
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.) */
660 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
662 dumpfile_t * label_header;
663 Device *d_self = DEVICE(self);
667 /* Delete any extant data, except our volume lock. */
668 delete_vfs_files(self);
670 /* Print warnings about any remaining files. */
671 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
672 check_dir_empty_functor, self);
674 self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
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);
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);
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;
699 /* Just like search_directory, but returns -1 in the event of an error */
701 search_vfs_directory(
704 SearchDirectoryFunctor functor,
707 Device *dself = DEVICE(self);
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);
720 /* TODO: is this the right moment to acquire a lock?? */
722 result = search_directory(dir_handle, regex, functor, user_data);
726 closedir(dir_handle);
730 static DeviceStatusFlags vfs_device_read_label(Device * dself) {
731 VfsDevice * self = VFS_DEVICE(dself);
732 dumpfile_t * amanda_header;
734 g_assert(self != NULL);
736 if (!check_is_dir(self, self->dir_name)) {
737 /* error message set by check_is_dir */
738 return dself->status;
741 amfree(dself->volume_label);
742 amfree(dself->volume_time);
743 dumpfile_free(dself->volume_header);
744 dself->volume_header = NULL;
746 if (device_in_error(dself)) return dself->status;
748 amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0);
750 if (amanda_header == NULL) {
751 /* This means an error occured getting locks or opening the header
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;
761 /* close the fd we just opened */
762 vfs_device_finish_file(dself);
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;
774 /* self->volume_header is already set */
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);
782 update_volume_size(self);
784 return dself->status;
787 static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) {
788 VfsDevice * self = VFS_DEVICE(pself);
791 if (device_in_error(self)) return FALSE;
793 g_assert(self->open_file_fd >= 0);
795 if (check_at_leom(self, size))
796 pself->is_eom = TRUE;
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);
807 result = vfs_device_robust_write(self, data, size);
808 if (result != RESULT_SUCCESS) {
809 /* vfs_device_robust_write set error status appropriately */
813 self->volume_bytes += size;
814 self->checked_bytes_used += size;
816 g_mutex_lock(pself->device_mutex);
817 pself->bytes_written += size;
818 g_mutex_unlock(pself->device_mutex);
824 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
829 self = VFS_DEVICE(pself);
831 if (device_in_error(self)) return -1;
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;
840 size = pself->block_size;
841 result = vfs_device_robust_read(self, data, &size);
845 g_mutex_lock(pself->device_mutex);
846 pself->bytes_read += size;
847 g_mutex_unlock(pself->device_mutex);
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,
857 DEVICE_STATUS_SUCCESS);
860 device_set_error(pself,
861 vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
862 DEVICE_STATUS_DEVICE_ERROR);
866 g_assert_not_reached();
870 vfs_device_start(Device * dself,
871 DeviceAccessMode mode, char * label,
873 VfsDevice * self = VFS_DEVICE(dself);
875 if (!check_is_dir(self, self->dir_name)) {
876 /* error message set by check_is_dir */
880 g_mutex_lock(dself->device_mutex);
881 dself->in_file = FALSE;
882 g_mutex_unlock(dself->device_mutex);
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);
892 dself->volume_label = newstralloc(dself->volume_label, label);
893 dself->volume_time = newstralloc(dself->volume_time, timestamp);
895 /* unset the VOLUME_UNLABELED flag, if it was set */
896 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
898 demote_volume_lock(self);
899 dself->access_mode = mode;
901 if (dself->volume_label == NULL && device_read_label(dself) != DEVICE_STATUS_SUCCESS) {
902 /* device_read_label already set our error message */
905 dself->access_mode = mode;
915 vfs_device_finish (Device * pself) {
917 self = VFS_DEVICE(pself);
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);
926 if (device_in_error(self)) return FALSE;
936 /* A SearchDirectoryFunctor. */
937 static gboolean get_last_file_number_functor(const char * filename,
940 glfn_data * data = (glfn_data*)datap;
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);
947 /* This condition is needlessly complex due to sign issues. */
948 if (data->rval < 0 || ((guint)data->rval) < file) {
955 get_last_file_number(VfsDevice * self) {
958 Device *d_self = DEVICE(self);
962 count = search_vfs_directory(self, "^[0-9]+\\.",
963 get_last_file_number_functor, &data);
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);
972 g_assert(data.rval >= 0);
984 /* A SearchDirectoryFunctor. */
985 static gboolean get_next_file_number_functor(const char * filename,
988 gnfn_data * data = (gnfn_data*)datap;
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);
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;
1003 /* Returns the file number equal to or greater than the given requested
1006 get_next_file_number(VfsDevice * self, guint request) {
1009 Device *d_self = DEVICE(self);
1011 data.request = request;
1012 data.best_found = -1;
1014 count = search_vfs_directory(self, "^[0-9]+\\.",
1015 get_next_file_number_functor, &data);
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);
1026 return data.best_found;
1029 /* Finds the file number, acquires a lock, and returns the new file name. */
1031 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
1033 char *base, *sanitary_base;
1037 fileno = 1 + get_last_file_number(self);
1041 if (open_lock(self, fileno, TRUE)) {
1048 /* record that we're at this filenum now */
1049 DEVICE(self)->file = fileno;
1051 base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
1053 sanitary_base = sanitise_filename(base);
1055 rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
1056 amfree(sanitary_base);
1061 vfs_device_start_file (Device * dself, dumpfile_t * ji) {
1062 VfsDevice * self = VFS_DEVICE(dself);
1064 dself->is_eom = FALSE;
1066 if (device_in_error(self)) return FALSE;
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;
1072 if (check_at_leom(self, VFS_DEVICE_LABEL_SIZE))
1073 dself->is_eom = TRUE;
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);
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.
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);
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);
1111 if (!write_amanda_header(self, ji)) {
1112 /* write_amanda_header sets error status if necessary */
1117 /* handle some accounting business */
1118 self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1119 self->checked_bytes_used += VFS_DEVICE_LABEL_SIZE;
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 */
1131 vfs_device_finish_file(Device * dself) {
1132 VfsDevice * self = VFS_DEVICE(dself);
1134 if (device_in_error(self)) return FALSE;
1138 g_mutex_lock(dself->device_mutex);
1139 dself->in_file = FALSE;
1140 g_mutex_unlock(dself->device_mutex);
1145 /* This function is used for two purposes, rather than one. In
1146 * addition to its documented behavior, we also use it to open the
1147 * volume label for reading at startup. In that second case, we avoid
1148 * FdDevice-related side effects. */
1150 vfs_device_seek_file (Device * dself, guint requested_file) {
1151 VfsDevice *self = VFS_DEVICE(dself);
1154 char header_buffer[VFS_DEVICE_LABEL_SIZE];
1155 int header_buffer_size = sizeof(header_buffer);
1158 if (device_in_error(self)) return NULL;
1160 dself->is_eof = FALSE;
1162 g_mutex_lock(dself->device_mutex);
1163 dself->in_file = FALSE;
1164 dself->bytes_read = 0;
1165 g_mutex_unlock(dself->device_mutex);
1169 if (requested_file > 0) {
1170 file = get_next_file_number(self, requested_file);
1172 file = requested_file;
1176 /* Did they request one past the end? */
1177 char * tmp_file_name;
1178 tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1179 if (tmp_file_name != NULL) {
1180 free(tmp_file_name);
1181 dself->file = requested_file; /* other attributes are already correct */
1182 return make_tapeend_header();
1184 device_set_error(dself,
1185 stralloc(_("Attempt to read past tape-end file")),
1186 DEVICE_STATUS_SUCCESS);
1191 if (!open_lock(self, file, FALSE)) {
1192 device_set_error(dself,
1193 stralloc(_("could not acquire lock")),
1194 DEVICE_STATUS_DEVICE_ERROR);
1198 self->file_name = file_number_to_file_name(self, file);
1199 if (self->file_name == NULL) {
1200 device_set_error(dself,
1201 vstrallocf(_("File %d not found"), file),
1202 file == 0 ? DEVICE_STATUS_VOLUME_UNLABELED
1203 : DEVICE_STATUS_VOLUME_ERROR);
1205 rval = g_new(dumpfile_t, 1);
1210 self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1211 if (self->open_file_fd < 0) {
1212 device_set_error(dself,
1213 vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1214 DEVICE_STATUS_DEVICE_ERROR);
1215 amfree(self->file_name);
1220 result = vfs_device_robust_read(self, header_buffer,
1221 &header_buffer_size);
1222 if (result != RESULT_SUCCESS) {
1223 device_set_error(dself,
1224 vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1225 DEVICE_STATUS_VOLUME_ERROR);
1230 rval = g_new(dumpfile_t, 1);
1231 parse_file_header(header_buffer, rval, header_buffer_size);
1232 switch (rval->type) {
1234 case F_CONT_DUMPFILE:
1235 case F_SPLIT_DUMPFILE:
1239 /* file 0 should have a TAPESTART header; vfs_device_read_label
1241 if (requested_file == 0)
1246 device_set_error(dself,
1247 stralloc(_("Invalid amanda header while reading file header")),
1248 DEVICE_STATUS_VOLUME_ERROR);
1254 /* update our state */
1255 if (requested_file == 0) {
1256 dself->header_block_size = header_buffer_size;
1258 g_mutex_lock(dself->device_mutex);
1259 dself->in_file = TRUE;
1260 g_mutex_unlock(dself->device_mutex);
1267 vfs_device_seek_block (Device * pself, guint64 block) {
1271 self = VFS_DEVICE(pself);
1273 g_assert(self->open_file_fd >= 0);
1274 g_assert(sizeof(off_t) >= sizeof(guint64));
1275 if (device_in_error(self)) return FALSE;
1277 /* Pretty simple. We figure out the blocksize and use that. */
1278 result = lseek(self->open_file_fd,
1279 (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1282 pself->block = block;
1284 if (result == (off_t)(-1)) {
1285 device_set_error(pself,
1286 vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1287 DEVICE_STATUS_DEVICE_ERROR);
1294 static gboolean try_unlink(const char * file) {
1295 if (unlink(file) < 0) {
1303 check_at_leom(VfsDevice *self, guint64 size)
1305 gboolean recheck = FALSE;
1306 guint64 est_avail_now;
1307 struct fs_usage fsusage;
1308 guint64 block_size = DEVICE(self)->block_size;
1309 guint64 eom_warning_buffer = EOM_EARLY_WARNING_ZONE_BLOCKS * block_size;
1311 if (!self->leom || !self->monitor_free_space)
1314 /* handle VOLUME_LIMIT */
1315 if (self->enforce_volume_limit && self->volume_limit &&
1316 self->volume_bytes + size + eom_warning_buffer > self->volume_limit) {
1320 /* handle actual filesystem available space, using some heuristics to avoid polling this
1323 if (self->checked_fs_free_bytes >= self->checked_bytes_used + size)
1324 est_avail_now = self->checked_fs_free_bytes - self->checked_bytes_used - size;
1326 /* is it time to check again? */
1327 if (est_avail_now <= block_size * MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS) {
1329 } else if (self->checked_bytes_used > MONITOR_FREE_SPACE_EVERY_KB * 1024) {
1331 } else if (self->checked_fs_free_time + MONITOR_FREE_SPACE_EVERY_SECONDS <= time(NULL)) {
1338 if (get_fs_usage(self->dir_name, NULL, &fsusage) < 0 || fsusage.fsu_bavail_top_bit_set) {
1339 g_warning("Filesystem cannot provide free space: %s; setting MONITOR_FREE_SPACE false",
1340 fsusage.fsu_bavail_top_bit_set? "no result" : strerror(errno));
1341 self->monitor_free_space = FALSE;
1345 self->checked_fs_free_bytes = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1346 self->checked_bytes_used = 0;
1347 self->checked_fs_free_time = time(NULL);
1349 if (self->checked_fs_free_bytes - size <= eom_warning_buffer) {
1350 g_debug("%s: at LEOM", DEVICE(self)->device_name);
1358 check_at_peom(VfsDevice *self, guint64 size)
1360 if (self->enforce_volume_limit && (self->volume_limit > 0)) {
1361 guint64 newtotal = self->volume_bytes + size;
1362 if (newtotal > self->volume_limit) {
1371 vfs_device_recycle_file (Device * dself, guint filenum) {
1372 VfsDevice * self = VFS_DEVICE(dself);
1373 struct stat file_status;
1376 if (device_in_error(self)) return FALSE;
1379 * 1) Get a write lock on the file in question.
1380 * 2) Unlink the file in question.
1381 * 3) Unlink the lock.
1382 * 4) Release the lock.
1383 * FIXME: Is it OK to unlink the lockfile?
1386 self->file_name = file_number_to_file_name(self, filenum);
1387 if (self->file_name == NULL) {
1388 device_set_error(dself,
1389 vstrallocf(_("File %d not found"), filenum),
1390 DEVICE_STATUS_VOLUME_ERROR);
1394 if (!open_lock(self, filenum, FALSE)) {
1395 device_set_error(dself,
1396 stralloc(_("could not acquire lock")),
1397 DEVICE_STATUS_DEVICE_ERROR);
1401 if (0 != stat(self->file_name, &file_status)) {
1402 device_set_error(dself,
1403 vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1404 self->file_name, strerror(errno)),
1405 DEVICE_STATUS_VOLUME_ERROR);
1408 file_size = file_status.st_size;
1410 if (!try_unlink(self->file_name)) {
1411 device_set_error(dself,
1412 vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1413 DEVICE_STATUS_VOLUME_ERROR);
1418 self->volume_bytes -= file_size;
1424 vfs_device_erase (Device * dself) {
1425 VfsDevice *self = VFS_DEVICE(dself);
1427 if (!open_lock(self, 0, TRUE))
1430 delete_vfs_files(self);
1434 dumpfile_free(dself->volume_header);
1435 dself->volume_header = NULL;
1436 device_set_error(dself, g_strdup("Unlabeled volume"),
1437 DEVICE_STATUS_VOLUME_UNLABELED);
1442 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1444 int fd = self->open_file_fd;
1445 Device *d_self = DEVICE(self);
1446 int want = *count, got = 0;
1448 while (got < want) {
1450 result = read(fd, buf + got, want - got);
1453 } else if (result == 0) {
1456 return RESULT_NO_DATA;
1459 return RESULT_SUCCESS;
1466 || errno == EWOULDBLOCK
1475 /* Error occured. */
1476 device_set_error(d_self,
1477 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1478 DEVICE_STATUS_VOLUME_ERROR);
1480 return RESULT_ERROR;
1485 return RESULT_SUCCESS;
1489 vfs_device_robust_write(VfsDevice * self, char *buf, int count) {
1490 int fd = self->open_file_fd;
1491 Device *d_self = DEVICE(self);
1494 while (rval < count) {
1496 result = write(fd, buf + rval, count - rval);
1505 || errno == EWOULDBLOCK
1521 /* We are definitely out of space. */
1522 device_set_error(d_self,
1523 vstrallocf(_("No space left on device: %s"), strerror(errno)),
1524 DEVICE_STATUS_VOLUME_ERROR);
1525 return RESULT_NO_SPACE;
1527 /* Error occured. Note that here we handle EIO as an error. */
1528 device_set_error(d_self,
1529 vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1530 DEVICE_STATUS_VOLUME_ERROR);
1531 return RESULT_ERROR;
1534 return RESULT_SUCCESS;
1537 /* TODO: add prop */