2 * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
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.
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
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
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
22 #include <string.h> /* memset() */
27 #include "vfs-device.h"
29 /* This regex will match all VfsDevice files in a directory. We use it
30 for cleanup and verification. Note that this regex does NOT match
32 #define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
34 /* The name of the volume lockfile. Should be the same as that
35 generated by lockfile_name(0). */
36 #define VOLUME_LOCKFILE_NAME "00000-lock"
38 #define VFS_DEVICE_MIN_BLOCK_SIZE (1)
39 #define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
40 #define VFS_DEVICE_DEFAULT_BLOCK_SIZE (DISK_BLOCK_BYTES)
41 #define VFS_DEVICE_LABEL_SIZE (32768)
43 /* This looks dangerous, but is actually modified by the umask. */
44 #define VFS_DEVICE_CREAT_MODE 0666
46 /* Possible (abstracted) results from a system I/O operation. */
49 RESULT_ERROR, /* Undefined error. */
50 RESULT_NO_DATA, /* End of File, while reading */
51 RESULT_NO_SPACE, /* Out of space. Sometimes we don't know if
52 it was this or I/O error, but this is the
53 preferred explanation. */
57 void vfs_device_register(void);
59 /* here are local prototypes */
60 static void vfs_device_init (VfsDevice * o);
61 static void vfs_device_class_init (VfsDeviceClass * c);
62 static void vfs_device_base_init (VfsDeviceClass * c);
63 static void vfs_device_finalize (GObject * o);
65 static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
66 char * label, char * timestamp);
67 static gboolean vfs_device_finish (Device * pself);
68 static void vfs_device_open_device (Device * pself, char * device_name,
69 char * device_type, char * device_node);
70 static gboolean vfs_device_start_file (Device * pself, dumpfile_t * ji);
71 static gboolean vfs_device_finish_file (Device * dself);
72 static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
73 static gboolean vfs_device_seek_block (Device * self, guint64 block);
74 static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
75 static gboolean vfs_device_erase (Device * pself);
76 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node);
77 static DeviceStatusFlags vfs_device_read_label(Device * dself);
78 static gboolean vfs_device_write_block(Device * self, guint size, gpointer data);
79 static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
80 static IoResult vfs_device_robust_write(VfsDevice * self, char *buf,
82 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
85 /* Various helper functions. */
86 static void release_file(VfsDevice * self);
87 static gboolean check_is_dir(VfsDevice * self, const char * name);
88 static char * file_number_to_file_name(VfsDevice * self, guint file);
89 static gboolean file_number_to_file_name_functor(const char * filename,
91 static gboolean vfs_device_set_max_volume_usage_fn(Device *p_self,
92 DevicePropertyBase *base, GValue *val,
93 PropertySurety surety, PropertySource source);
94 gboolean vfs_device_get_free_space_fn(struct Device *p_self,
95 DevicePropertyBase *base, GValue *val,
96 PropertySurety *surety, PropertySource *source);
97 //static char* lockfile_name(VfsDevice * self, guint file);
98 static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
99 static void promote_volume_lock(VfsDevice * self);
100 static void demote_volume_lock(VfsDevice * self);
101 static gboolean delete_vfs_files_functor(const char * filename,
103 static gboolean check_dir_empty_functor(const char * filename,
105 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
107 static int search_vfs_directory(VfsDevice *self, const char * regex,
108 SearchDirectoryFunctor functor, gpointer user_data);
109 static gint get_last_file_number(VfsDevice * self);
110 static gboolean get_last_file_number_functor(const char * filename,
112 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
113 static gboolean try_unlink(const char * file);
115 /* pointer to the classes of our parents */
116 static DeviceClass *parent_class = NULL;
118 void vfs_device_register(void) {
119 static const char * device_prefix_list[] = { "file", NULL };
120 register_device(vfs_device_factory, device_prefix_list);
124 vfs_device_get_type (void)
126 static GType type = 0;
128 if G_UNLIKELY(type == 0) {
129 static const GTypeInfo info = {
130 sizeof (VfsDeviceClass),
131 (GBaseInitFunc) vfs_device_base_init,
132 (GBaseFinalizeFunc) NULL,
133 (GClassInitFunc) vfs_device_class_init,
134 (GClassFinalizeFunc) NULL,
135 NULL /* class_data */,
138 (GInstanceInitFunc) vfs_device_init,
142 type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
143 &info, (GTypeFlags)0);
150 vfs_device_init (VfsDevice * self) {
151 Device * dself = DEVICE(self);
154 self->dir_name = self->file_name = NULL;
155 self->open_file_fd = -1;
156 self->volume_bytes = 0;
157 self->volume_limit = 0;
159 /* Register Properties */
160 bzero(&response, sizeof(response));
162 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
163 g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
164 device_set_simple_property(dself, PROPERTY_CONCURRENCY,
165 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
166 g_value_unset(&response);
168 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
169 g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
170 device_set_simple_property(dself, PROPERTY_STREAMING,
171 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
172 g_value_unset(&response);
174 g_value_init(&response, G_TYPE_BOOLEAN);
175 g_value_set_boolean(&response, TRUE);
176 device_set_simple_property(dself, PROPERTY_APPENDABLE,
177 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
178 g_value_unset(&response);
180 g_value_init(&response, G_TYPE_BOOLEAN);
181 g_value_set_boolean(&response, TRUE);
182 device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
183 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
184 g_value_unset(&response);
186 g_value_init(&response, G_TYPE_BOOLEAN);
187 g_value_set_boolean(&response, TRUE);
188 device_set_simple_property(dself, PROPERTY_FULL_DELETION,
189 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
190 g_value_unset(&response);
192 g_value_init(&response, G_TYPE_BOOLEAN);
193 g_value_set_boolean(&response, FALSE);
194 device_set_simple_property(dself, PROPERTY_COMPRESSION,
195 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
196 g_value_unset(&response);
198 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
199 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
200 device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
201 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
202 g_value_unset(&response);
206 vfs_device_class_init (VfsDeviceClass * c)
208 GObjectClass *g_object_class = (GObjectClass*) c;
209 DeviceClass *device_class = DEVICE_CLASS(c);
211 parent_class = g_type_class_ref(TYPE_DEVICE);
213 device_class->open_device = vfs_device_open_device;
214 device_class->start = vfs_device_start;
215 device_class->start_file = vfs_device_start_file;
216 device_class->read_label = vfs_device_read_label;
217 device_class->write_block = vfs_device_write_block;
218 device_class->read_block = vfs_device_read_block;
219 device_class->finish_file = vfs_device_finish_file;
220 device_class->seek_file = vfs_device_seek_file;
221 device_class->seek_block = vfs_device_seek_block;
222 device_class->recycle_file = vfs_device_recycle_file;
223 device_class->erase = vfs_device_erase;
224 device_class->finish = vfs_device_finish;
226 g_object_class->finalize = vfs_device_finalize;
230 vfs_device_base_init (VfsDeviceClass * c)
232 DeviceClass *device_class = (DeviceClass *)c;
234 device_class_register_property(device_class, PROPERTY_FREE_SPACE,
235 PROPERTY_ACCESS_GET_MASK,
236 vfs_device_get_free_space_fn,
239 device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
240 (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
241 (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
242 device_simple_property_get_fn,
243 vfs_device_set_max_volume_usage_fn);
245 device_class_register_property(device_class, PROPERTY_COMPRESSION,
246 PROPERTY_ACCESS_GET_MASK,
247 device_simple_property_get_fn,
252 vfs_device_set_max_volume_usage_fn(Device *p_self,
253 DevicePropertyBase *base, GValue *val,
254 PropertySurety surety, PropertySource source)
256 VfsDevice *self = VFS_DEVICE(p_self);
258 self->volume_limit = g_value_get_uint64(val);
260 return device_simple_property_set_fn(p_self, base, val, surety, source);
264 vfs_device_get_free_space_fn(struct Device *dself,
265 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
266 PropertySurety *surety, PropertySource *source)
268 VfsDevice *self = VFS_DEVICE(dself);
270 struct fs_usage fsusage;
273 if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) {
274 if (fsusage.fsu_bavail_top_bit_set)
277 bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize;
278 if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024)
279 bytes_avail = (guint64)self->volume_limit * 1024;
281 qsize.accuracy = SIZE_ACCURACY_REAL;
282 qsize.bytes = bytes_avail;
284 *surety = PROPERTY_SURETY_GOOD;
286 g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno));
287 qsize.accuracy = SIZE_ACCURACY_UNKNOWN;
290 *surety = PROPERTY_SURETY_BAD;
293 g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
294 g_value_set_boxed(val, &qsize);
297 *source = PROPERTY_SOURCE_DETECTED;
302 /* Drops everything associated with the volume file: Its name and fd. */
303 void release_file(VfsDevice * self) {
305 if (self->open_file_fd != -1)
306 robust_close(self->open_file_fd);
307 amfree(self->file_name);
309 self->open_file_fd = -1;
312 static void vfs_device_finalize(GObject * obj_self) {
313 VfsDevice *self = VFS_DEVICE (obj_self);
314 Device * d_self = (Device*)self;
316 if (d_self->access_mode != ACCESS_NULL) {
317 device_finish(d_self);
320 if(G_OBJECT_CLASS(parent_class)->finalize)
321 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
323 amfree(self->dir_name);
328 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) {
330 g_assert(0 == strcmp(device_type, "file"));
331 rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
332 device_open_device(rval, device_name, device_type, device_node);
336 static gboolean check_is_dir(VfsDevice * self, const char * name) {
337 Device *dself = DEVICE(self);
338 struct stat dir_status;
340 if (stat(name, &dir_status) < 0) {
342 if (errno == EINTR) {
343 return check_is_dir(self, name);
346 device_set_error(dself,
347 vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)),
348 DEVICE_STATUS_DEVICE_ERROR);
350 } else if (!S_ISDIR(dir_status.st_mode)) {
351 device_set_error(dself,
352 vstrallocf(_("VFS Device path %s is not a directory"), name),
353 DEVICE_STATUS_DEVICE_ERROR);
366 /* A SearchDirectoryFunctor. */
367 static gboolean file_number_to_file_name_functor(const char * filename,
370 struct stat file_status;
371 fnfn_data *data = (fnfn_data*)datap;
373 result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
375 /* Just to be thorough, let's check that it's a real
377 if (0 != stat(result_tmp, &file_status)) {
378 g_warning(_("Cannot stat file %s (%s), ignoring it"), result_tmp, strerror(errno));
379 } else if (!S_ISREG(file_status.st_mode)) {
380 g_warning(_("%s is not a regular file, ignoring it"), result_tmp);
383 if (data->result == NULL) {
384 data->result = result_tmp;
392 /* This function finds the filename for a given file number. We search
393 * for a filesystem file matching the regex /^0*$device_file\./; if
394 * there is more than one such file we make a warning and take an
396 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
404 regex = g_strdup_printf("^0*%u\\.", device_file);
406 search_vfs_directory(self, regex,
407 file_number_to_file_name_functor, &data);
411 if (data.count == 0) {
412 g_assert(data.result == NULL);
414 } else if (data.count > 1) {
415 g_warning("Found multiple names for file number %d, choosing file %s",
416 device_file, data.result);
419 g_assert(data.result != NULL);
422 g_assert_not_reached();
425 /* This function returns the dynamically-allocated lockfile name for a
426 given file number. */
428 static char * lockfile_name(VfsDevice * self, guint number) {
429 return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
433 /* Does what you expect. If the lock already exists, it is released
434 * and regained, in case the mode is changing.
435 * The file field has several options:
436 * - file > 0: Open a lock on a real volume file.
437 * - file = 0: Open the volume lock as a volume file (for setup).
438 * - file < 0: Open the volume lock as a volume lock (persistantly).
440 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
441 G_GNUC_UNUSED int file,
442 G_GNUC_UNUSED gboolean exclusive) {
444 /* At the moment, file locking is horribly broken. */
448 /* For now, does it the bad way. */
449 static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
452 static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
455 /* A SearchDirectoryFunctor */
456 static gboolean update_volume_size_functor(const char * filename,
457 gpointer user_data) {
458 char * full_filename;
459 struct stat stat_buf;
460 VfsDevice * self = VFS_DEVICE(user_data);
462 full_filename = vstralloc(self->dir_name, "/", filename, NULL);
464 if (stat(full_filename, &stat_buf) < 0) {
465 /* Log it and keep going. */
466 g_warning(_("Couldn't stat file %s: %s"), full_filename, strerror(errno));
467 amfree(full_filename);
471 amfree(full_filename);
472 self->volume_bytes += stat_buf.st_size;
477 static void update_volume_size(VfsDevice * self) {
479 self->volume_bytes = 0;
480 search_vfs_directory(self, "^[0-9]+\\.",
481 update_volume_size_functor, self);
486 vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) {
488 self = VFS_DEVICE(pself);
490 pself->min_block_size = VFS_DEVICE_MIN_BLOCK_SIZE;
491 pself->max_block_size = VFS_DEVICE_MAX_BLOCK_SIZE;
492 pself->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
494 /* We don't have to free this ourselves; it will be freed by
495 * vfs_device_finalize whether we succeed here or not. */
496 self->dir_name = g_strconcat(device_node, "/data/", NULL);
498 if (parent_class->open_device) {
499 parent_class->open_device(pself, device_name, device_type, device_node);
503 /* A SearchDirectoryFunctor */
504 static gboolean delete_vfs_files_functor(const char * filename,
505 gpointer user_data) {
510 self = VFS_DEVICE(user_data);
511 d_self = DEVICE(self);
513 /* Skip the volume lock. */
514 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
517 path_name = vstralloc(self->dir_name, "/", filename, NULL);
518 if (unlink(path_name) != 0) {
519 g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno));
525 /* delete_vfs_files deletes all VfsDevice files in the directory except the
527 void delete_vfs_files(VfsDevice * self) {
528 g_assert(self != NULL);
530 /* This function assumes that the volume is locked! */
531 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
532 delete_vfs_files_functor, self);
535 /* This is a functor suitable for search_directory. It simply prints a
536 warning. It also dodges the volume lockfile. */
537 static gboolean check_dir_empty_functor(const char * filename,
538 gpointer user_data) {
539 VfsDevice * self = VFS_DEVICE(user_data);
542 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
545 path_name = vstralloc(self->dir_name, "/", filename, NULL);
547 g_warning(_("Found spurious storage file %s"), path_name);
553 /* This function is used to write volume and dump headers. */
554 static gboolean write_amanda_header(VfsDevice * self,
555 const dumpfile_t * header) {
558 Device *d_self = DEVICE(self);
560 g_assert(header != NULL);
562 label_buffer = device_build_amanda_header(d_self, header, NULL);
564 amfree(label_buffer);
565 device_set_error(d_self,
566 stralloc(_("Amanda file header won't fit in a single block!")),
567 DEVICE_STATUS_DEVICE_ERROR);
571 result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
572 /* vfs_device_robust_write sets error status if necessary */
573 amfree(label_buffer);
574 return (result == RESULT_SUCCESS);
577 /* clear_and_label will erase the contents of the directory, and write
578 * this label in its place. This function assumes we already have a volume
579 * label write lock in place (e.g., promote_lock() has been called.) */
580 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
582 dumpfile_t * label_header;
583 Device *d_self = DEVICE(self);
587 /* Delete any extant data, except our volume lock. */
588 delete_vfs_files(self);
590 /* Print warnings about any remaining files. */
591 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
592 check_dir_empty_functor, self);
594 self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
596 self->open_file_fd = robust_open(self->file_name,
597 O_CREAT | O_EXCL | O_WRONLY,
598 VFS_DEVICE_CREAT_MODE);
599 if (self->open_file_fd < 0) {
600 device_set_error(d_self,
601 vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)),
602 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
606 label_header = make_tapestart_header(DEVICE(self), label, timestamp);
607 if (!write_amanda_header(self, label_header)) {
608 /* write_amanda_header sets error status if necessary */
609 dumpfile_free(label_header);
612 dumpfile_free(d_self->volume_header);
613 d_self->volume_header = label_header;
614 self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
618 /* Just like search_directory, but returns -1 in the event of an error */
620 search_vfs_directory(
623 SearchDirectoryFunctor functor,
626 Device *dself = DEVICE(self);
630 dir_handle = opendir(self->dir_name);
631 if (dir_handle == NULL) {
632 device_set_error(dself,
633 vstrallocf(_("Couldn't open device %s (directory %s) for reading: %s"),
634 dself->device_name, self->dir_name, strerror(errno)),
635 DEVICE_STATUS_DEVICE_ERROR);
639 /* TODO: is this the right moment to acquire a lock?? */
641 result = search_directory(dir_handle, regex, functor, user_data);
645 closedir(dir_handle);
649 static DeviceStatusFlags vfs_device_read_label(Device * dself) {
650 VfsDevice * self = VFS_DEVICE(dself);
651 dumpfile_t * amanda_header;
653 g_assert(self != NULL);
655 if (!check_is_dir(self, self->dir_name)) {
656 /* error message set by check_is_dir */
657 return dself->status;
660 amfree(dself->volume_label);
661 amfree(dself->volume_time);
662 dumpfile_free(dself->volume_header);
663 dself->volume_header = NULL;
665 if (device_in_error(dself)) return dself->status;
667 amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0);
669 if (amanda_header == NULL) {
670 /* This means an error occured getting locks or opening the header
672 device_set_error(dself,
673 stralloc("Error loading device header -- unlabeled volume?"),
674 DEVICE_STATUS_DEVICE_ERROR
675 | DEVICE_STATUS_VOLUME_ERROR
676 | DEVICE_STATUS_VOLUME_UNLABELED);
677 return dself->status;
680 /* close the fd we just opened */
681 vfs_device_finish_file(dself);
683 if (amanda_header->type != F_TAPESTART) {
684 /* This is an error, and should not happen. */
685 device_set_error(dself,
686 stralloc(_("Got a bad volume label")),
687 DEVICE_STATUS_VOLUME_ERROR);
688 amfree(amanda_header);
689 return dself->status;
692 dself->volume_label = g_strdup(amanda_header->name);
693 dself->volume_time = g_strdup(amanda_header->datestamp);
694 /* self->volume_header is already set */
696 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
698 update_volume_size(self);
700 return dself->status;
703 static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) {
704 VfsDevice * self = VFS_DEVICE(pself);
707 if (device_in_error(self)) return FALSE;
709 g_assert(self->open_file_fd >= 0);
711 if (self->volume_limit > 0 &&
712 self->volume_bytes + size > self->volume_limit) {
714 pself->is_eom = TRUE;
715 device_set_error(pself,
716 stralloc(_("No space left on device")),
717 DEVICE_STATUS_VOLUME_ERROR);
721 result = vfs_device_robust_write(self, data, size);
722 if (result != RESULT_SUCCESS) {
723 /* vfs_device_robust_write set error status appropriately */
727 self->volume_bytes += size;
734 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
739 self = VFS_DEVICE(pself);
741 if (device_in_error(self)) return -1;
743 if (data == NULL || (gsize)*size_req < pself->block_size) {
744 /* Just a size query. */
745 g_assert(pself->block_size < INT_MAX);
746 *size_req = (int)pself->block_size;
750 size = pself->block_size;
751 result = vfs_device_robust_read(self, data, &size);
758 pself->is_eof = TRUE;
759 pself->in_file = FALSE;
760 device_set_error(pself,
762 DEVICE_STATUS_SUCCESS);
765 device_set_error(pself,
766 vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
767 DEVICE_STATUS_DEVICE_ERROR);
771 g_assert_not_reached();
775 vfs_device_start(Device * dself,
776 DeviceAccessMode mode, char * label,
778 VfsDevice * self = VFS_DEVICE(dself);
780 if (!check_is_dir(self, self->dir_name)) {
781 /* error message set by check_is_dir */
785 dself->in_file = FALSE;
787 if (mode == ACCESS_WRITE) {
788 promote_volume_lock(self);
789 if (!clear_and_prepare_label(self, label, timestamp)) {
790 /* clear_and_prepare_label sets error status if necessary */
791 demote_volume_lock(self);
795 dself->volume_label = newstralloc(dself->volume_label, label);
796 dself->volume_time = newstralloc(dself->volume_time, timestamp);
798 /* unset the VOLUME_UNLABELED flag, if it was set */
799 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
801 demote_volume_lock(self);
802 dself->access_mode = mode;
804 if (dself->volume_label == NULL && device_read_label(dself) != DEVICE_STATUS_SUCCESS) {
805 /* device_read_label already set our error message */
808 dself->access_mode = mode;
818 vfs_device_finish (Device * pself) {
820 self = VFS_DEVICE(pself);
824 if (device_in_error(self)) return FALSE;
826 pself->access_mode = ACCESS_NULL;
827 pself->in_file = FALSE;
836 /* A SearchDirectoryFunctor. */
837 static gboolean get_last_file_number_functor(const char * filename,
840 glfn_data * data = (glfn_data*)datap;
842 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
843 if (file > G_MAXINT) {
844 g_warning(_("Super-large device file %s found, ignoring"), filename);
847 /* This condition is needlessly complex due to sign issues. */
848 if (data->rval < 0 || ((guint)data->rval) < file) {
855 get_last_file_number(VfsDevice * self) {
858 Device *d_self = DEVICE(self);
862 count = search_vfs_directory(self, "^[0-9]+\\.",
863 get_last_file_number_functor, &data);
866 /* Somebody deleted something important while we weren't looking. */
867 device_set_error(d_self,
868 stralloc(_("Error identifying VFS device contents!")),
869 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
872 g_assert(data.rval >= 0);
884 /* A SearchDirectoryFunctor. */
885 static gboolean get_next_file_number_functor(const char * filename,
888 gnfn_data * data = (gnfn_data*)datap;
890 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
891 if (file > G_MAXINT) {
892 g_warning(_("Super-large device file %s found, ignoring"), filename);
895 /* This condition is needlessly complex due to sign issues. */
896 if (file >= data->request &&
897 (data->best_found < 0 || file < (guint)data->best_found)) {
898 data->best_found = file;
903 /* Returns the file number equal to or greater than the given requested
906 get_next_file_number(VfsDevice * self, guint request) {
909 Device *d_self = DEVICE(self);
911 data.request = request;
912 data.best_found = -1;
914 count = search_vfs_directory(self, "^[0-9]+\\.",
915 get_next_file_number_functor, &data);
918 /* Somebody deleted something important while we weren't looking. */
919 device_set_error(d_self,
920 stralloc(_("Error identifying VFS device contents!")),
921 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
926 return data.best_found;
929 /* Finds the file number, acquires a lock, and returns the new file name. */
931 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
933 char *base, *sanitary_base;
937 fileno = 1 + get_last_file_number(self);
941 if (open_lock(self, fileno, TRUE)) {
948 /* record that we're at this filenum now */
949 DEVICE(self)->file = fileno;
951 base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
953 sanitary_base = sanitise_filename(base);
955 rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
956 amfree(sanitary_base);
961 vfs_device_start_file (Device * dself, dumpfile_t * ji) {
962 VfsDevice * self = VFS_DEVICE(dself);
964 dself->is_eom = FALSE;
966 if (device_in_error(self)) return FALSE;
968 /* set the blocksize in the header to 32k, since the VFS header is always
969 * 32k regardless of the block_size setting */
970 ji->blocksize = 32768;
972 if (self->volume_limit > 0 &&
973 self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) {
974 dself->is_eom = TRUE;
975 device_set_error(dself,
976 stralloc(_("No space left on device")),
977 DEVICE_STATUS_DEVICE_ERROR);
981 /* The basic idea here is thus:
982 1) Try to get a lock on the next filenumber.
983 2) If that fails, update our idea of "next filenumber" and try again.
984 3) Then open the file itself.
988 self->file_name = make_new_file_name(self, ji);
989 if (self->file_name == NULL) {
990 device_set_error(dself,
991 stralloc(_("Could not create header filename")),
992 DEVICE_STATUS_DEVICE_ERROR);
996 self->open_file_fd = robust_open(self->file_name,
997 O_CREAT | O_EXCL | O_RDWR,
998 VFS_DEVICE_CREAT_MODE);
999 if (self->open_file_fd < 0) {
1000 device_set_error(dself,
1001 vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)),
1002 DEVICE_STATUS_DEVICE_ERROR);
1008 if (!write_amanda_header(self, ji)) {
1009 /* write_amanda_header sets error status if necessary */
1014 /* handle some accounting business */
1015 self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1016 dself->in_file = TRUE;
1018 /* make_new_file_name set pself->file for us */
1024 vfs_device_finish_file(Device * dself) {
1025 VfsDevice * self = VFS_DEVICE(dself);
1027 if (device_in_error(self)) return FALSE;
1031 dself->in_file = FALSE;
1039 /* This function is used for two purposes, rather than one. In
1040 * addition to its documented behavior, we also use it to open the
1041 * volume label for reading at startup. In that second case, we avoid
1042 * FdDevice-related side effects. */
1044 vfs_device_seek_file (Device * dself, guint requested_file) {
1045 VfsDevice *self = VFS_DEVICE(dself);
1048 char header_buffer[VFS_DEVICE_LABEL_SIZE];
1049 int header_buffer_size = sizeof(header_buffer);
1052 if (device_in_error(self)) return NULL;
1054 dself->in_file = FALSE;
1055 dself->is_eof = FALSE;
1060 if (requested_file > 0) {
1061 file = get_next_file_number(self, requested_file);
1063 file = requested_file;
1067 /* Did they request one past the end? */
1068 char * tmp_file_name;
1069 tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1070 if (tmp_file_name != NULL) {
1071 free(tmp_file_name);
1072 dself->file = requested_file; /* other attributes are already correct */
1073 return make_tapeend_header();
1075 device_set_error(dself,
1076 stralloc(_("Attempt to read past tape-end file")),
1077 DEVICE_STATUS_SUCCESS);
1082 if (!open_lock(self, file, FALSE)) {
1083 device_set_error(dself,
1084 stralloc(_("could not acquire lock")),
1085 DEVICE_STATUS_DEVICE_ERROR);
1089 self->file_name = file_number_to_file_name(self, file);
1090 if (self->file_name == NULL) {
1091 device_set_error(dself,
1092 vstrallocf(_("File %d not found"), file),
1093 DEVICE_STATUS_VOLUME_ERROR);
1098 self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1099 if (self->open_file_fd < 0) {
1100 device_set_error(dself,
1101 vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1102 DEVICE_STATUS_DEVICE_ERROR);
1103 amfree(self->file_name);
1108 result = vfs_device_robust_read(self, header_buffer,
1109 &header_buffer_size);
1110 if (result != RESULT_SUCCESS) {
1111 device_set_error(dself,
1112 vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1113 DEVICE_STATUS_VOLUME_ERROR);
1118 rval = g_new(dumpfile_t, 1);
1119 parse_file_header(header_buffer, rval, header_buffer_size);
1120 switch (rval->type) {
1122 case F_CONT_DUMPFILE:
1123 case F_SPLIT_DUMPFILE:
1127 /* file 0 should have a TAPESTART header; vfs_device_read_label
1129 if (requested_file == 0)
1134 device_set_error(dself,
1135 stralloc(_("Invalid amanda header while reading file header")),
1136 DEVICE_STATUS_VOLUME_ERROR);
1142 /* update our state */
1143 dself->in_file = TRUE;
1150 vfs_device_seek_block (Device * pself, guint64 block) {
1154 self = VFS_DEVICE(pself);
1156 g_assert(self->open_file_fd >= 0);
1157 g_assert(sizeof(off_t) >= sizeof(guint64));
1158 if (device_in_error(self)) return FALSE;
1160 /* Pretty simple. We figure out the blocksize and use that. */
1161 result = lseek(self->open_file_fd,
1162 (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1165 pself->block = block;
1167 if (result == (off_t)(-1)) {
1168 device_set_error(pself,
1169 vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1170 DEVICE_STATUS_DEVICE_ERROR);
1177 static gboolean try_unlink(const char * file) {
1178 if (unlink(file) < 0) {
1186 vfs_device_recycle_file (Device * dself, guint filenum) {
1187 VfsDevice * self = VFS_DEVICE(dself);
1188 struct stat file_status;
1191 if (device_in_error(self)) return FALSE;
1194 * 1) Get a write lock on the file in question.
1195 * 2) Unlink the file in question.
1196 * 3) Unlink the lock.
1197 * 4) Release the lock.
1198 * FIXME: Is it OK to unlink the lockfile?
1201 self->file_name = file_number_to_file_name(self, filenum);
1202 if (self->file_name == NULL) {
1203 device_set_error(dself,
1204 vstrallocf(_("File %d not found"), filenum),
1205 DEVICE_STATUS_VOLUME_ERROR);
1209 if (!open_lock(self, filenum, FALSE)) {
1210 device_set_error(dself,
1211 stralloc(_("could not acquire lock")),
1212 DEVICE_STATUS_DEVICE_ERROR);
1216 if (0 != stat(self->file_name, &file_status)) {
1217 device_set_error(dself,
1218 vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1219 self->file_name, strerror(errno)),
1220 DEVICE_STATUS_VOLUME_ERROR);
1223 file_size = file_status.st_size;
1225 if (!try_unlink(self->file_name)) {
1226 device_set_error(dself,
1227 vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1228 DEVICE_STATUS_VOLUME_ERROR);
1233 self->volume_bytes -= file_size;
1239 vfs_device_erase (Device * dself) {
1240 VfsDevice *self = VFS_DEVICE(dself);
1242 if (!open_lock(self, 0, true))
1245 delete_vfs_files(self);
1252 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1254 int fd = self->open_file_fd;
1255 Device *d_self = DEVICE(self);
1256 int want = *count, got = 0;
1258 while (got < want) {
1260 result = read(fd, buf + got, want - got);
1263 } else if (result == 0) {
1266 return RESULT_NO_DATA;
1269 return RESULT_SUCCESS;
1276 || errno == EWOULDBLOCK
1285 /* Error occured. */
1286 device_set_error(d_self,
1287 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1288 DEVICE_STATUS_VOLUME_ERROR);
1290 return RESULT_ERROR;
1295 return RESULT_SUCCESS;
1299 vfs_device_robust_write(VfsDevice * self, char *buf, int count) {
1300 int fd = self->open_file_fd;
1301 Device *d_self = DEVICE(self);
1304 while (rval < count) {
1306 result = write(fd, buf + rval, count - rval);
1315 || errno == EWOULDBLOCK
1331 /* We are definitely out of space. */
1332 device_set_error(d_self,
1333 vstrallocf(_("No space left on device: %s"), strerror(errno)),
1334 DEVICE_STATUS_VOLUME_ERROR);
1335 return RESULT_NO_SPACE;
1337 /* Error occured. Note that here we handle EIO as an error. */
1338 device_set_error(d_self,
1339 vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1340 DEVICE_STATUS_VOLUME_ERROR);
1341 return RESULT_ERROR;
1344 return RESULT_SUCCESS;