2 * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library 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 Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
22 #include <string.h> /* memset() */
29 * Type checking and casting macros
31 #define TYPE_VFS_DEVICE (vfs_device_get_type())
32 #define VFS_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice)
33 #define VFS_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice const)
34 #define VFS_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), vfs_device_get_type(), VfsDeviceClass)
35 #define IS_VFS_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), vfs_device_get_type ())
37 #define VFS_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), vfs_device_get_type(), VfsDeviceClass)
38 static GType vfs_device_get_type (void);
41 * Main object structure
50 char * file_lock_name;
52 char * volume_lock_name;
64 DeviceClass __parent__;
68 /* This regex will match all VfsDevice files in a directory. We use it
69 for cleanup and verification. Note that this regex does NOT match
71 #define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
73 /* The name of the volume lockfile. Should be the same as that
74 generated by lockfile_name(0). */
75 #define VOLUME_LOCKFILE_NAME "00000-lock"
77 #define VFS_DEVICE_MIN_BLOCK_SIZE (1)
78 #define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
79 #define VFS_DEVICE_DEFAULT_BLOCK_SIZE (DISK_BLOCK_BYTES)
80 #define VFS_DEVICE_LABEL_SIZE (32768)
82 /* This looks dangerous, but is actually modified by the umask. */
83 #define VFS_DEVICE_CREAT_MODE 0666
85 /* Possible (abstracted) results from a system I/O operation. */
88 RESULT_ERROR, /* Undefined error. */
89 RESULT_NO_DATA, /* End of File, while reading */
90 RESULT_NO_SPACE, /* Out of space. Sometimes we don't know if
91 it was this or I/O error, but this is the
92 preferred explanation. */
96 void vfs_device_register(void);
98 /* here are local prototypes */
99 static void vfs_device_init (VfsDevice * o);
100 static void vfs_device_class_init (VfsDeviceClass * c);
101 static void vfs_device_base_init (VfsDeviceClass * c);
102 static void vfs_device_finalize (GObject * o);
104 static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
105 char * label, char * timestamp);
106 static gboolean vfs_device_finish (Device * pself);
107 static void vfs_device_open_device (Device * pself, char * device_name,
108 char * device_type, char * device_node);
109 static gboolean vfs_device_start_file (Device * pself, dumpfile_t * ji);
110 static gboolean vfs_device_finish_file (Device * pself);
111 static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
112 static gboolean vfs_device_seek_block (Device * self, guint64 block);
113 static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
114 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node);
115 static DeviceStatusFlags vfs_device_read_label(Device * dself);
116 static gboolean vfs_device_write_block(Device * self, guint size, gpointer data);
117 static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
118 static IoResult vfs_device_robust_write(VfsDevice * self, char *buf,
120 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
123 /* Various helper functions. */
124 static void release_file(VfsDevice * self);
125 static gboolean check_is_dir(Device * d_self, const char * name);
126 static char* file_number_to_file_name(VfsDevice * self, guint file);
127 static gboolean file_number_to_file_name_functor(const char * filename,
129 static gboolean vfs_device_set_max_volume_usage_fn(Device *p_self,
130 DevicePropertyBase *base, GValue *val,
131 PropertySurety surety, PropertySource source);
132 gboolean vfs_device_get_free_space_fn(struct Device *p_self,
133 DevicePropertyBase *base, GValue *val,
134 PropertySurety *surety, PropertySource *source);
135 //static char* lockfile_name(VfsDevice * self, guint file);
136 static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
137 static void promote_volume_lock(VfsDevice * self);
138 static void demote_volume_lock(VfsDevice * self);
139 static void delete_vfs_files(VfsDevice * self);
140 static gboolean delete_vfs_files_functor(const char * filename,
142 static gboolean check_dir_empty_functor(const char * filename,
144 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
146 static int search_vfs_directory(VfsDevice *self, const char * regex,
147 SearchDirectoryFunctor functor, gpointer user_data);
148 static gint get_last_file_number(VfsDevice * self);
149 static gboolean get_last_file_number_functor(const char * filename,
151 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
152 static gboolean try_unlink(const char * file);
154 /* pointer to the classes of our parents */
155 static DeviceClass *parent_class = NULL;
157 void vfs_device_register(void) {
158 static const char * device_prefix_list[] = { "file", NULL };
159 register_device(vfs_device_factory, device_prefix_list);
163 vfs_device_get_type (void)
165 static GType type = 0;
167 if G_UNLIKELY(type == 0) {
168 static const GTypeInfo info = {
169 sizeof (VfsDeviceClass),
170 (GBaseInitFunc) vfs_device_base_init,
171 (GBaseFinalizeFunc) NULL,
172 (GClassInitFunc) vfs_device_class_init,
173 (GClassFinalizeFunc) NULL,
174 NULL /* class_data */,
177 (GInstanceInitFunc) vfs_device_init,
181 type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
182 &info, (GTypeFlags)0);
189 vfs_device_init (VfsDevice * self) {
190 Device * dself = DEVICE(self);
193 self->dir_name = self->file_name = NULL;
194 self->file_lock_name = self->volume_lock_name = NULL;
195 self->file_lock_fd = self->volume_lock_fd = self->open_file_fd = -1;
196 self->volume_bytes = 0;
197 self->volume_limit = 0;
199 /* Register Properties */
200 bzero(&response, sizeof(response));
202 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
203 g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
204 device_set_simple_property(dself, PROPERTY_CONCURRENCY,
205 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
206 g_value_unset(&response);
208 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
209 g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
210 device_set_simple_property(dself, PROPERTY_STREAMING,
211 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
212 g_value_unset(&response);
214 g_value_init(&response, G_TYPE_BOOLEAN);
215 g_value_set_boolean(&response, TRUE);
216 device_set_simple_property(dself, PROPERTY_APPENDABLE,
217 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
218 g_value_unset(&response);
220 g_value_init(&response, G_TYPE_BOOLEAN);
221 g_value_set_boolean(&response, TRUE);
222 device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
223 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
224 g_value_unset(&response);
226 g_value_init(&response, G_TYPE_BOOLEAN);
227 g_value_set_boolean(&response, FALSE);
228 device_set_simple_property(dself, PROPERTY_COMPRESSION,
229 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
230 g_value_unset(&response);
232 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
233 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
234 device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
235 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
236 g_value_unset(&response);
240 vfs_device_class_init (VfsDeviceClass * c)
242 GObjectClass *g_object_class = (GObjectClass*) c;
243 DeviceClass *device_class = (DeviceClass *)c;
245 parent_class = g_type_class_ref(TYPE_DEVICE);
247 device_class->open_device = vfs_device_open_device;
248 device_class->start = vfs_device_start;
249 device_class->start_file = vfs_device_start_file;
250 device_class->read_label = vfs_device_read_label;
251 device_class->write_block = vfs_device_write_block;
252 device_class->read_block = vfs_device_read_block;
253 device_class->finish_file = vfs_device_finish_file;
254 device_class->seek_file = vfs_device_seek_file;
255 device_class->seek_block = vfs_device_seek_block;
256 device_class->recycle_file = vfs_device_recycle_file;
257 device_class->finish = vfs_device_finish;
258 g_object_class->finalize = vfs_device_finalize;
262 vfs_device_base_init (VfsDeviceClass * c)
264 DeviceClass *device_class = (DeviceClass *)c;
266 device_class_register_property(device_class, PROPERTY_FREE_SPACE,
267 PROPERTY_ACCESS_GET_MASK,
268 vfs_device_get_free_space_fn,
271 device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
272 (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
273 (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
274 device_simple_property_get_fn,
275 vfs_device_set_max_volume_usage_fn);
277 device_class_register_property(device_class, PROPERTY_COMPRESSION,
278 PROPERTY_ACCESS_GET_MASK,
279 device_simple_property_get_fn,
284 vfs_device_set_max_volume_usage_fn(Device *p_self,
285 DevicePropertyBase *base, GValue *val,
286 PropertySurety surety, PropertySource source)
288 VfsDevice *self = VFS_DEVICE(p_self);
290 self->volume_limit = g_value_get_uint64(val);
292 return device_simple_property_set_fn(p_self, base, val, surety, source);
296 vfs_device_get_free_space_fn(struct Device *p_self,
297 DevicePropertyBase *base G_GNUC_UNUSED, GValue *val,
298 PropertySurety *surety, PropertySource *source)
300 VfsDevice *self = VFS_DEVICE(p_self);
302 struct fs_usage fsusage;
305 if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) {
306 if (fsusage.fsu_bavail_top_bit_set)
309 bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize;
310 if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024)
311 bytes_avail = (guint64)self->volume_limit * 1024;
313 qsize.accuracy = SIZE_ACCURACY_REAL;
314 qsize.bytes = bytes_avail;
316 *surety = PROPERTY_SURETY_GOOD;
318 g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno));
319 qsize.accuracy = SIZE_ACCURACY_UNKNOWN;
322 *surety = PROPERTY_SURETY_BAD;
325 g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
326 g_value_set_boxed(val, &qsize);
329 *source = PROPERTY_SOURCE_DETECTED;
334 /* Drops everything associated with the volume file: Its name and fd,
335 its lock, and its lock's name and fd. */
336 static void release_file(VfsDevice * self) {
338 robust_close(self->open_file_fd);
339 amfree(self->file_name);
341 if (self->file_lock_fd > 0) {
342 amfunlock(self->file_lock_fd, self->file_lock_name);
343 close(self->file_lock_fd);
344 amfree(self->file_lock_name);
346 self->file_lock_fd = self->open_file_fd = -1;
349 static void vfs_device_finalize(GObject * obj_self) {
350 VfsDevice *self = VFS_DEVICE (obj_self);
351 Device * d_self = (Device*)self;
353 if (d_self->access_mode != ACCESS_NULL) {
354 device_finish(d_self);
357 if(G_OBJECT_CLASS(parent_class)->finalize)
358 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
360 amfree(self->dir_name);
364 if (self->volume_lock_fd >= 0) {
365 amfunlock(self->volume_lock_fd, self->volume_lock_name);
366 close(self->volume_lock_fd);
369 amfree(self->volume_lock_name);
372 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) {
374 g_assert(0 == strcmp(device_type, "file"));
375 rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
376 device_open_device(rval, device_name, device_type, device_node);
380 static gboolean check_is_dir(Device * d_self, const char * name) {
381 struct stat dir_status;
383 if (stat(name, &dir_status) < 0) {
385 if (errno == EINTR) {
386 return check_is_dir(d_self, name);
389 device_set_error(d_self,
390 vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)),
391 DEVICE_STATUS_DEVICE_ERROR);
393 } else if (!S_ISDIR(dir_status.st_mode)) {
394 device_set_error(d_self,
395 vstrallocf(_("VFS Device path %s is not a directory"), name),
396 DEVICE_STATUS_DEVICE_ERROR);
409 /* A SearchDirectoryFunctor. */
410 static gboolean file_number_to_file_name_functor(const char * filename,
413 struct stat file_status;
414 fnfn_data *data = (fnfn_data*)datap;
416 result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
418 /* Just to be thorough, let's check that it's a real
420 if (0 != stat(result_tmp, &file_status)) {
421 g_warning(_("Cannot stat file %s (%s), ignoring it"), result_tmp, strerror(errno));
422 } else if (!S_ISREG(file_status.st_mode)) {
423 g_warning(_("%s is not a regular file, ignoring it"), result_tmp);
426 if (data->result == NULL) {
427 data->result = result_tmp;
435 /* This function finds the filename for a given file number. We search
436 * for a filesystem file matching the regex /^0*$device_file\./; if
437 * there is more than one such file we make a warning and take an
439 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
447 regex = g_strdup_printf("^0*%u\\.", device_file);
449 search_vfs_directory(self, regex,
450 file_number_to_file_name_functor, &data);
454 if (data.count == 0) {
455 g_assert(data.result == NULL);
457 } else if (data.count > 1) {
458 g_warning("Found multiple names for file number %d, choosing file %s",
459 device_file, data.result);
462 g_assert(data.result != NULL);
465 g_assert_not_reached();
468 /* This function returns the dynamically-allocated lockfile name for a
469 given file number. */
471 static char * lockfile_name(VfsDevice * self, guint number) {
472 return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
476 /* Does what you expect. If the lock already exists, it is released
477 * and regained, in case the mode is changing.
478 * The file field has several options:
479 * - file > 0: Open a lock on a real volume file.
480 * - file = 0: Open the volume lock as a volume file (for setup).
481 * - file < 0: Open the volume lock as a volume lock (persistantly).
483 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
484 G_GNUC_UNUSED int file,
485 G_GNUC_UNUSED gboolean exclusive) {
487 /* At the moment, file locking is horribly broken. */
493 Device *d_self = DEVICE(self);
495 if (self->volume_lock_name == NULL) {
496 self->volume_lock_name = lockfile_name(self, 0);
497 } else if (self->volume_lock_fd >= 0) {
498 amfunlock(self->volume_lock_fd, self->volume_lock_name);
499 close(self->volume_lock_fd);
501 name = self->volume_lock_name;
503 if (self->file_lock_fd >= 0 && self->file_lock_name != NULL) {
504 amfunlock(self->file_lock_fd, self->file_lock_name);
506 amfree(self->file_lock_name);
507 close(self->file_lock_fd);
508 name = self->file_lock_name = lockfile_name(self, file);
512 fd = robust_open(name, O_CREAT | O_WRONLY, VFS_DEVICE_CREAT_MODE);
515 device_set_error(d_self,
516 vstrallocf(_("Can't open lock file %s: %s"), name, strerror(errno)),
517 DEVICE_STATUS_DEVICE_ERROR);
528 self->volume_lock_fd = fd;
530 self->file_lock_fd = fd;
536 /* For now, does it the bad way. */
537 static void promote_volume_lock(VfsDevice * self) {
538 amfunlock(self->volume_lock_fd, self->volume_lock_name);
539 amflock(self->volume_lock_fd, self->volume_lock_name);
542 static void demote_volume_lock(VfsDevice * self) {
543 amfunlock(self->volume_lock_fd, self->volume_lock_name);
544 amroflock(self->volume_lock_fd, self->volume_lock_name);
547 /* A SearchDirectoryFunctor */
548 static gboolean update_volume_size_functor(const char * filename,
549 gpointer user_data) {
550 char * full_filename;
551 struct stat stat_buf;
552 VfsDevice * self = user_data;
554 full_filename = vstralloc(self->dir_name, "/", filename, NULL);
556 if (stat(full_filename, &stat_buf) < 0) {
557 /* Log it and keep going. */
558 g_warning(_("Couldn't stat file %s: %s"), full_filename, strerror(errno));
559 amfree(full_filename);
563 amfree(full_filename);
564 self->volume_bytes += stat_buf.st_size;
569 static void update_volume_size(VfsDevice * self) {
570 self->volume_bytes = 0;
571 search_vfs_directory(self, "^[0-9]+\\.",
572 update_volume_size_functor, self);
577 vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) {
579 self = VFS_DEVICE(pself);
581 pself->min_block_size = VFS_DEVICE_MIN_BLOCK_SIZE;
582 pself->max_block_size = VFS_DEVICE_MAX_BLOCK_SIZE;
583 pself->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
585 /* We don't have to free this ourselves; it will be freed by
586 * vfs_device_finalize whether we succeed here or not. */
587 self->dir_name = g_strconcat(device_node, "/data/", NULL);
589 if (parent_class->open_device) {
590 parent_class->open_device(pself, device_name, device_type, device_node);
594 /* A SearchDirectoryFunctor */
595 static gboolean delete_vfs_files_functor(const char * filename,
596 gpointer user_data) {
601 self = VFS_DEVICE(user_data);
602 d_self = DEVICE(self);
604 /* Skip the volume lock. */
605 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
608 path_name = vstralloc(self->dir_name, "/", filename, NULL);
609 if (unlink(path_name) != 0) {
610 g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno));
616 /* delete_vfs_files deletes all VfsDevice files in the directory except the
618 static void delete_vfs_files(VfsDevice * self) {
619 g_assert(self != NULL);
621 /* This function assumes that the volume is locked! */
622 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
623 delete_vfs_files_functor, self);
626 /* This is a functor suitable for search_directory. It simply prints a
627 warning. It also dodges the volume lockfile. */
628 static gboolean check_dir_empty_functor(const char * filename,
629 gpointer user_data) {
634 self = VFS_DEVICE(user_data);
635 d_self = DEVICE(self);
637 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
640 path_name = vstralloc(self->dir_name, "/", filename, NULL);
642 g_warning(_("Found spurious storage file %s"), path_name);
648 /* This function is used to write volume and dump headers. */
649 static gboolean write_amanda_header(VfsDevice * self,
650 const dumpfile_t * header) {
653 Device *d_self = DEVICE(self);
655 g_assert(header != NULL);
657 label_buffer = build_header(header, VFS_DEVICE_LABEL_SIZE);
658 if (strlen(label_buffer)+1 > VFS_DEVICE_LABEL_SIZE) {
659 amfree(label_buffer);
660 device_set_error(d_self,
661 stralloc(_("Amanda file header won't fit in a single block!")),
662 DEVICE_STATUS_DEVICE_ERROR);
666 result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
667 /* vfs_device_robust_write sets error status if necessary */
668 amfree(label_buffer);
669 return (result == RESULT_SUCCESS);
672 /* clear_and_label will erase the contents of the directory, and write
673 * this label in its place. This function assumes we already have a volume
674 * label write lock in place (e.g., promote_lock() has been called.) */
675 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
677 dumpfile_t * label_header;
678 Device *d_self = DEVICE(self);
682 /* Delete any extant data, except our volume lock. */
683 delete_vfs_files(self);
685 /* Print warnings about any remaining files. */
686 search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
687 check_dir_empty_functor, self);
689 self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
691 self->open_file_fd = robust_open(self->file_name,
692 O_CREAT | O_EXCL | O_WRONLY,
693 VFS_DEVICE_CREAT_MODE);
694 if (self->open_file_fd < 0) {
695 device_set_error(d_self,
696 vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)),
697 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
701 label_header = make_tapestart_header(DEVICE(self), label, timestamp);
702 if (!write_amanda_header(self, label_header)) {
703 /* write_amanda_header sets error status if necessary */
704 amfree(label_header);
707 amfree(label_header);
708 self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
712 /* Just like search_directory, but returns -1 in the event of an error */
714 search_vfs_directory(
717 SearchDirectoryFunctor functor,
720 Device *dself = DEVICE(self);
724 dir_handle = opendir(self->dir_name);
725 if (dir_handle == NULL) {
726 device_set_error(dself,
727 vstrallocf(_("Couldn't open device %s (directory %s) for reading: %s"),
728 dself->device_name, self->dir_name, strerror(errno)),
729 DEVICE_STATUS_DEVICE_ERROR);
733 /* TODO: is this the right moment to acquire a lock?? */
735 result = search_directory(dir_handle, regex, functor, user_data);
739 closedir(dir_handle);
743 static DeviceStatusFlags vfs_device_read_label(Device * dself) {
744 dumpfile_t * amanda_header;
747 self = VFS_DEVICE(dself);
748 g_assert(self != NULL);
750 if (!check_is_dir(dself, self->dir_name)) {
751 /* error message set by check_is_dir */
755 amfree(dself->volume_label);
756 amfree(dself->volume_time);
757 amfree(dself->volume_header);
759 if (device_in_error(self)) return dself->status;
761 amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0);
762 if (amanda_header == NULL) {
763 /* This means an error occured getting locks or opening the header
765 device_set_error(dself,
766 stralloc("Error loading device header -- unlabeled volume?"),
767 DEVICE_STATUS_DEVICE_ERROR
768 | DEVICE_STATUS_VOLUME_ERROR
769 | DEVICE_STATUS_VOLUME_UNLABELED);
770 return dself->status;
773 if (amanda_header->type != F_TAPESTART) {
774 /* This is an error, and should not happen. */
775 device_set_error(dself,
776 stralloc(_("Got a bad volume label")),
777 DEVICE_STATUS_VOLUME_ERROR);
778 amfree(amanda_header);
779 return dself->status;
782 dself->volume_label = g_strdup(amanda_header->name);
783 dself->volume_time = g_strdup(amanda_header->datestamp);
784 /* dself->volume_header is already set */
786 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
788 update_volume_size(self);
790 return dself->status;
793 static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) {
794 VfsDevice * self = VFS_DEVICE(pself);
797 if (device_in_error(self)) return FALSE;
799 g_assert(self->open_file_fd >= 0);
801 if (self->volume_limit > 0 &&
802 self->volume_bytes + size > self->volume_limit) {
804 pself->is_eof = TRUE;
805 device_set_error(pself,
806 stralloc(_("No space left on device")),
807 DEVICE_STATUS_VOLUME_ERROR);
811 result = vfs_device_robust_write(self, data, size);
812 if (result != RESULT_SUCCESS) {
813 /* vfs_device_robust_write set error status appropriately */
817 self->volume_bytes += size;
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);
848 pself->is_eof = TRUE;
849 pself->in_file = FALSE;
850 device_set_error(pself,
852 DEVICE_STATUS_SUCCESS);
855 device_set_error(pself,
856 vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
857 DEVICE_STATUS_DEVICE_ERROR);
861 g_assert_not_reached();
864 static gboolean vfs_device_start(Device * pself,
865 DeviceAccessMode mode, char * label,
868 self = VFS_DEVICE(pself);
870 if (!check_is_dir(pself, self->dir_name)) {
871 /* error message set by check_is_dir */
875 pself->in_file = FALSE;
877 if (mode == ACCESS_WRITE) {
878 promote_volume_lock(self);
879 if (!clear_and_prepare_label(self, label, timestamp)) {
880 /* clear_and_prepare_label sets error status if necessary */
881 demote_volume_lock(self);
885 pself->volume_label = newstralloc(pself->volume_label, label);
886 pself->volume_time = newstralloc(pself->volume_time, timestamp);
888 /* unset the VOLUME_UNLABELED flag, if it was set */
889 device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS);
891 demote_volume_lock(self);
892 pself->access_mode = mode;
894 if (pself->volume_label == NULL && device_read_label(pself) != DEVICE_STATUS_SUCCESS) {
895 /* device_read_label already set our error message */
898 pself->access_mode = mode;
908 vfs_device_finish (Device * pself) {
910 self = VFS_DEVICE(pself);
912 if (device_in_error(self)) return FALSE;
914 pself->access_mode = ACCESS_NULL;
923 /* A SearchDirectoryFunctor. */
924 static gboolean get_last_file_number_functor(const char * filename,
927 glfn_data * data = (glfn_data*)datap;
929 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
930 if (file > G_MAXINT) {
931 g_warning(_("Super-large device file %s found, ignoring"), filename);
934 /* This condition is needlessly complex due to sign issues. */
935 if (data->rval < 0 || ((guint)data->rval) < file) {
941 static gint get_last_file_number(VfsDevice * self) {
944 Device *d_self = DEVICE(self);
948 count = search_vfs_directory(self, "^[0-9]+\\.",
949 get_last_file_number_functor, &data);
952 /* Somebody deleted something important while we weren't looking. */
953 device_set_error(d_self,
954 stralloc(_("Error identifying VFS device contents!")),
955 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
958 g_assert(data.rval >= 0);
970 /* A SearchDirectoryFunctor. */
971 static gboolean get_next_file_number_functor(const char * filename,
974 gnfn_data * data = (gnfn_data*)datap;
976 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
977 if (file > G_MAXINT) {
978 g_warning(_("Super-large device file %s found, ignoring"), filename);
981 /* This condition is needlessly complex due to sign issues. */
982 if (file >= data->request &&
983 (data->best_found < 0 || file < (guint)data->best_found)) {
984 data->best_found = file;
989 /* Returns the file number equal to or greater than the given requested
991 static gint get_next_file_number(VfsDevice * self, guint request) {
994 Device *d_self = DEVICE(self);
996 data.request = request;
997 data.best_found = -1;
999 count = search_vfs_directory(self, "^[0-9]+\\.",
1000 get_next_file_number_functor, &data);
1003 /* Somebody deleted something important while we weren't looking. */
1004 device_set_error(d_self,
1005 stralloc(_("Error identifying VFS device contents!")),
1006 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1011 return data.best_found;
1014 /* Finds the file number, acquires a lock, and returns the new file name. */
1016 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
1018 char *base, *sanitary_base;
1022 fileno = 1 + get_last_file_number(self);
1026 if (open_lock(self, fileno, TRUE)) {
1033 /* record that we're at this filenum now */
1034 DEVICE(self)->file = fileno;
1036 base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
1038 sanitary_base = sanitise_filename(base);
1040 rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
1041 amfree(sanitary_base);
1046 vfs_device_start_file (Device * pself, dumpfile_t * ji) {
1048 self = VFS_DEVICE(pself);
1050 if (device_in_error(self)) return FALSE;
1052 /* set the blocksize in the header to 32k, since the VFS header is always
1053 * 32k regardless of the block_size setting */
1054 ji->blocksize = 32768;
1056 if (self->volume_limit > 0 &&
1057 self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) {
1058 device_set_error(pself,
1059 stralloc(_("No space left on device")),
1060 DEVICE_STATUS_DEVICE_ERROR);
1064 /* The basic idea here is thus:
1065 1) Try to get a lock on the next filenumber.
1066 2) If that fails, update our idea of "next filenumber" and try again.
1067 3) Then open the file itself.
1071 self->file_name = make_new_file_name(self, ji);
1072 if (self->file_name == NULL) {
1073 device_set_error(pself,
1074 stralloc(_("Could not create header filename")),
1075 DEVICE_STATUS_DEVICE_ERROR);
1079 self->open_file_fd = robust_open(self->file_name,
1080 O_CREAT | O_EXCL | O_RDWR,
1081 VFS_DEVICE_CREAT_MODE);
1082 if (self->open_file_fd < 0) {
1083 device_set_error(pself,
1084 vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)),
1085 DEVICE_STATUS_DEVICE_ERROR);
1091 if (!write_amanda_header(self, ji)) {
1092 /* write_amanda_header sets error status if necessary */
1097 /* handle some accounting business */
1098 self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1099 pself->in_file = TRUE;
1101 /* make_new_file_name set pself->file for us */
1107 vfs_device_finish_file (Device * pself) {
1109 self = VFS_DEVICE(pself);
1111 if (device_in_error(self)) return FALSE;
1115 pself->in_file = FALSE;
1119 /* This function is used for two purposes, rather than one. In
1120 * addition to its documented behavior, we also use it to open the
1121 * volume label for reading at startup. In that second case, we avoid
1122 * FdDevice-related side effects. */
1124 vfs_device_seek_file (Device * pself, guint requested_file) {
1128 char header_buffer[VFS_DEVICE_LABEL_SIZE];
1129 int header_buffer_size = sizeof(header_buffer);
1132 self = VFS_DEVICE(pself);
1134 if (device_in_error(self)) return NULL;
1136 pself->in_file = FALSE;
1137 pself->is_eof = FALSE;
1142 if (requested_file > 0) {
1143 file = get_next_file_number(self, requested_file);
1145 file = requested_file;
1149 /* Did they request one past the end? */
1150 char * tmp_file_name;
1151 tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1152 if (tmp_file_name != NULL) {
1153 free(tmp_file_name);
1154 pself->file = requested_file; /* other attributes are already correct */
1155 return make_tapeend_header();
1157 device_set_error(pself,
1158 stralloc(_("Attempt to read past tape-end file")),
1159 DEVICE_STATUS_SUCCESS);
1164 if (!open_lock(self, file, FALSE)) {
1165 device_set_error(pself,
1166 stralloc(_("could not acquire lock")),
1167 DEVICE_STATUS_DEVICE_ERROR);
1171 self->file_name = file_number_to_file_name(self, file);
1172 if (self->file_name == NULL) {
1173 device_set_error(pself,
1174 vstrallocf(_("File %d not found"), file),
1175 DEVICE_STATUS_VOLUME_ERROR);
1180 self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1181 if (self->open_file_fd < 0) {
1182 device_set_error(pself,
1183 vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1184 DEVICE_STATUS_DEVICE_ERROR);
1185 amfree(self->file_name);
1190 result = vfs_device_robust_read(self, header_buffer,
1191 &header_buffer_size);
1192 if (result != RESULT_SUCCESS) {
1193 device_set_error(pself,
1194 vstrallocf(_("Problem reading Amanda header: %s"), device_error(pself)),
1195 DEVICE_STATUS_VOLUME_ERROR);
1200 rval = g_new(dumpfile_t, 1);
1201 parse_file_header(header_buffer, rval, header_buffer_size);
1202 switch (rval->type) {
1204 case F_CONT_DUMPFILE:
1205 case F_SPLIT_DUMPFILE:
1209 /* file 0 should have a TAPESTART header; vfs_device_read_label
1211 if (requested_file == 0)
1216 device_set_error(pself,
1217 stralloc(_("Invalid amanda header while reading file header")),
1218 DEVICE_STATUS_VOLUME_ERROR);
1224 /* update our state */
1225 pself->in_file = TRUE;
1232 vfs_device_seek_block (Device * pself, guint64 block) {
1236 self = VFS_DEVICE(pself);
1238 g_assert(self->open_file_fd >= 0);
1239 g_assert(sizeof(off_t) >= sizeof(guint64));
1240 if (device_in_error(self)) return FALSE;
1242 /* Pretty simple. We figure out the blocksize and use that. */
1243 result = lseek(self->open_file_fd,
1244 (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1247 pself->block = block;
1249 if (result == (off_t)(-1)) {
1250 device_set_error(pself,
1251 vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1252 DEVICE_STATUS_DEVICE_ERROR);
1259 static gboolean try_unlink(const char * file) {
1260 if (unlink(file) < 0) {
1268 vfs_device_recycle_file (Device * pself, guint filenum) {
1270 struct stat file_status;
1273 self = VFS_DEVICE(pself);
1275 if (device_in_error(self)) return FALSE;
1278 * 1) Get a write lock on the file in question.
1279 * 2) Unlink the file in question.
1280 * 3) Unlink the lock.
1281 * 4) Release the lock.
1282 * FIXME: Is it OK to unlink the lockfile?
1285 self->file_name = file_number_to_file_name(self, filenum);
1286 if (self->file_name == NULL) {
1287 device_set_error(pself,
1288 vstrallocf(_("File %d not found"), filenum),
1289 DEVICE_STATUS_VOLUME_ERROR);
1293 if (!open_lock(self, filenum, FALSE)) {
1294 device_set_error(pself,
1295 stralloc(_("could not acquire lock")),
1296 DEVICE_STATUS_DEVICE_ERROR);
1300 if (0 != stat(self->file_name, &file_status)) {
1301 device_set_error(pself,
1302 vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1303 self->file_name, strerror(errno)),
1304 DEVICE_STATUS_VOLUME_ERROR);
1307 file_size = file_status.st_size;
1309 if (!try_unlink(self->file_name)) {
1310 device_set_error(pself,
1311 vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1312 DEVICE_STATUS_VOLUME_ERROR);
1317 if (!try_unlink(self->file_lock_name)) {
1318 device_set_error(pself,
1319 vstrallocf(_("Unlink of %s failed: %s"), self->file_lock_name, strerror(errno)),
1320 DEVICE_STATUS_VOLUME_ERROR);
1325 self->volume_bytes -= file_size;
1330 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1332 int fd = self->open_file_fd;
1333 Device *d_self = DEVICE(self);
1334 int want = *count, got = 0;
1336 while (got < want) {
1338 result = read(fd, buf + got, want - got);
1341 } else if (result == 0) {
1344 return RESULT_NO_DATA;
1347 return RESULT_SUCCESS;
1354 || errno == EWOULDBLOCK
1363 /* Error occured. */
1364 device_set_error(d_self,
1365 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1366 DEVICE_STATUS_VOLUME_ERROR);
1368 return RESULT_ERROR;
1373 return RESULT_SUCCESS;
1377 vfs_device_robust_write(VfsDevice * self, char *buf, int count) {
1378 int fd = self->open_file_fd;
1379 Device *d_self = DEVICE(self);
1382 while (rval < count) {
1384 result = write(fd, buf + rval, count - rval);
1393 || errno == EWOULDBLOCK
1409 /* We are definitely out of space. */
1410 device_set_error(d_self,
1411 vstrallocf(_("No space left on device: %s"), strerror(errno)),
1412 DEVICE_STATUS_VOLUME_ERROR);
1413 return RESULT_NO_SPACE;
1415 /* Error occured. Note that here we handle EIO as an error. */
1416 device_set_error(d_self,
1417 vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1418 DEVICE_STATUS_VOLUME_ERROR);
1419 return RESULT_ERROR;
1422 return RESULT_SUCCESS;