2 * Copyright (c) 2005 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., 505 N Mathlida Ave, Suite 120
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 #include <string.h> /* memset() */
23 #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 /* Possible (abstracted) results from a system I/O operation. */
41 RESULT_ERROR, /* Undefined error. */
42 RESULT_NO_DATA, /* End of File, while reading */
43 RESULT_NO_SPACE, /* Out of space. Sometimes we don't know if
44 it was this or I/O error, but this is the
45 preferred explanation. */
49 /* here are local prototypes */
50 static void vfs_device_init (VfsDevice * o);
51 static void vfs_device_class_init (VfsDeviceClass * c);
52 static void vfs_device_finalize (GObject * o);
54 static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
55 char * label, char * timestamp);
56 static gboolean vfs_device_open_device (Device * pself,
58 static gboolean vfs_device_start_file (Device * pself, const dumpfile_t * ji);
59 static gboolean vfs_device_finish_file (Device * pself);
60 static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
61 static gboolean vfs_device_seek_block (Device * self, guint64 block);
62 static gboolean vfs_device_property_get (Device * pself, DevicePropertyId ID,
64 static gboolean vfs_device_property_set (Device * pself, DevicePropertyId ID,
66 static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
67 static Device * vfs_device_factory(char * device_type,
69 static ReadLabelStatusFlags vfs_device_read_label(Device * dself);
70 static gboolean vfs_device_write_block(Device * self, guint size,
71 gpointer data, gboolean last_block);
72 static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
73 static IoResult vfs_device_robust_write(VfsDevice * self, char *buf,
75 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
78 /* Various helper functions. */
79 static void release_file(VfsDevice * self);
80 static gboolean check_is_dir(const char * name, gboolean printmsg);
81 static char* file_number_to_file_name(VfsDevice * self, guint file);
82 static gboolean file_number_to_file_name_functor(const char * filename,
84 //static char* lockfile_name(VfsDevice * self, guint file);
85 static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
86 static void promote_volume_lock(VfsDevice * self);
87 static void demote_volume_lock(VfsDevice * self);
88 static gboolean delete_vfs_files(VfsDevice * self);
89 static gboolean delete_vfs_files_functor(const char * filename,
91 static gboolean check_dir_empty_functor(const char * filename,
93 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
95 static gint get_last_file_number(VfsDevice * self);
96 static gboolean get_last_file_number_functor(const char * filename,
98 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
99 static gboolean try_unlink(const char * file);
101 /* pointer to the classes of our parents */
102 static DeviceClass *parent_class = NULL;
104 void vfs_device_register(void) {
105 static const char * device_prefix_list[] = { "file", NULL };
106 register_device(vfs_device_factory, device_prefix_list);
110 vfs_device_get_type (void)
112 static GType type = 0;
114 if G_UNLIKELY(type == 0) {
115 static const GTypeInfo info = {
116 sizeof (VfsDeviceClass),
117 (GBaseInitFunc) NULL,
118 (GBaseFinalizeFunc) NULL,
119 (GClassInitFunc) vfs_device_class_init,
120 (GClassFinalizeFunc) NULL,
121 NULL /* class_data */,
124 (GInstanceInitFunc) vfs_device_init,
128 type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
129 &info, (GTypeFlags)0);
136 vfs_device_init (VfsDevice * self) {
141 self->dir_handle = NULL;
142 self->dir_name = self->file_name = NULL;
143 self->file_lock_name = self->volume_lock_name = NULL;
144 self->file_lock_fd = self->volume_lock_fd = self->open_file_fd = -1;
145 self->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
146 self->volume_bytes = 0;
147 self->volume_limit = 0;
149 /* Register Properties */
151 bzero(&response, sizeof(response));
152 prop.base = &device_property_concurrency;
153 prop.access = PROPERTY_ACCESS_GET_MASK;
154 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
155 g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
156 device_add_property(o, &prop, &response);
157 g_value_unset(&response);
159 prop.base = &device_property_streaming;
160 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
161 g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
162 device_add_property(o, &prop, &response);
163 g_value_unset(&response);
165 prop.base = &device_property_min_block_size;
166 g_value_init(&response, G_TYPE_UINT);
167 g_value_set_uint(&response, VFS_DEVICE_MIN_BLOCK_SIZE);
168 device_add_property(o, &prop, &response);
170 prop.base = &device_property_max_block_size;
171 g_value_set_uint(&response, VFS_DEVICE_MAX_BLOCK_SIZE);
172 device_add_property(o, &prop, &response);
173 g_value_unset(&response);
175 prop.base = &device_property_appendable;
176 g_value_init(&response, G_TYPE_BOOLEAN);
177 g_value_set_boolean(&response, TRUE);
178 device_add_property(o, &prop, &response);
180 prop.base = &device_property_partial_deletion;
181 device_add_property(o, &prop, &response);
182 g_value_unset(&response);
184 /* This one is handled by Device's get_property handler. */
185 prop.base = &device_property_canonical_name;
186 device_add_property(o, &prop, NULL);
188 prop.base = &device_property_medium_access_type;
189 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
190 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
191 device_add_property(o, &prop, &response);
192 g_value_unset(&response);
194 /* These are dynamic, handled in vfs_device_property_xxx */
195 prop.base = &device_property_block_size;
196 prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;
197 device_add_property(o, &prop, NULL);
199 prop.base = &device_property_max_volume_usage;
201 (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
202 (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE);
203 device_add_property(o, &prop, NULL);
207 vfs_device_class_init (VfsDeviceClass * c G_GNUC_UNUSED)
209 GObjectClass *g_object_class = (GObjectClass*) c;
210 DeviceClass *device_class = (DeviceClass *)c;
212 parent_class = g_type_class_ref(TYPE_DEVICE);
214 device_class->open_device = vfs_device_open_device;
215 device_class->start = vfs_device_start;
216 device_class->start_file = vfs_device_start_file;
217 device_class->read_label = vfs_device_read_label;
218 device_class->write_block = vfs_device_write_block;
219 device_class->read_block = vfs_device_read_block;
220 device_class->finish_file = vfs_device_finish_file;
221 device_class->seek_file = vfs_device_seek_file;
222 device_class->seek_block = vfs_device_seek_block;
223 device_class->property_get = vfs_device_property_get;
224 device_class->property_set = vfs_device_property_set;
225 device_class->recycle_file = vfs_device_recycle_file;
226 g_object_class->finalize = vfs_device_finalize;
229 /* Drops everything associated with the volume file: Its name and fd,
230 its lock, and its lock's name and fd. */
231 static void release_file(VfsDevice * self) {
233 robust_close(self->open_file_fd);
234 amfree(self->file_name);
236 if (self->file_lock_fd > 0) {
237 amfunlock(self->file_lock_fd, self->file_lock_name);
238 close(self->file_lock_fd);
239 amfree(self->file_lock_name);
241 self->file_lock_fd = self->open_file_fd = -1;
244 static void vfs_device_finalize(GObject * obj_self) {
245 VfsDevice *self = VFS_DEVICE (obj_self);
246 Device * d_self = (Device*)self;
248 if (d_self->access_mode != ACCESS_NULL) {
249 device_finish(d_self);
252 if(G_OBJECT_CLASS(parent_class)->finalize)
253 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
255 amfree(self->dir_name);
257 if(self->dir_handle) {
258 closedir (self->dir_handle);
259 self->dir_handle = NULL;
264 if (self->volume_lock_fd >= 0) {
265 amfunlock(self->volume_lock_fd, self->volume_lock_name);
266 close(self->volume_lock_fd);
269 amfree(self->volume_lock_name);
272 static Device * vfs_device_factory(char * device_type,
273 char * device_name) {
275 g_assert(0 == strcmp(device_type, "file"));
276 rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
277 if (!device_open_device(rval, device_name)) {
278 g_object_unref(rval);
285 static gboolean check_is_dir(const char * name, gboolean printmsg) {
286 struct stat dir_status;
288 if (stat(name, &dir_status) < 0) {
290 if (errno == EINTR) {
291 return check_is_dir(name, printmsg);
295 g_fprintf(stderr, "Error checking directory %s: %s\n",
296 name, strerror(errno));
299 } else if (!S_ISDIR(dir_status.st_mode)) {
301 g_fprintf(stderr, "VFS Device path %s is not a directory.\n",
316 /* A SearchDirectoryFunctor. */
317 static gboolean file_number_to_file_name_functor(const char * filename,
320 struct stat file_status;
321 fnfn_data *data = (fnfn_data*)datap;
323 result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
325 /* Just to be thorough, let's check that it's a real
327 if (0 != stat(result_tmp, &file_status)) {
328 g_fprintf(stderr, "Cannot stat file %s (%s), ignoring it.\n",
329 result_tmp, strerror(errno));
330 } else if (!S_ISREG(file_status.st_mode)) {
331 g_fprintf(stderr, "%s is not a regular file, ignoring it.\n",
335 if (data->result == NULL) {
336 data->result = result_tmp;
344 /* This function finds the filename for a given file number. We search
345 * for a filesystem file matching the regex /^0*$device_file\./; if
346 * there is more than one such file we make a warning and take an
348 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
352 g_return_val_if_fail(self != NULL, NULL);
357 regex = g_strdup_printf("^0*%u\\.", device_file);
359 search_directory(self->dir_handle, regex,
360 file_number_to_file_name_functor, &data);
364 if (data.count == 0) {
365 g_assert(data.result == NULL);
367 } else if (data.count > 1) {
369 "Found multiple names for file number %d, choosing file %s.\n",
370 device_file, data.result);
373 g_assert(data.result != NULL);
376 g_assert_not_reached();
379 /* This function returns the dynamically-allocated lockfile name for a
380 given file number. */
382 static char * lockfile_name(VfsDevice * self, guint number) {
383 return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
387 /* Does what you expect. If the lock already exists, it is released
388 * and regained, in case the mode is changing.
389 * The file field has several options:
390 * - file > 0: Open a lock on a real volume file.
391 * - file = 0: Open the volume lock as a volume file (for setup).
392 * - file < 0: Open the volume lock as a volume lock (persistantly).
394 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
395 G_GNUC_UNUSED int file,
396 G_GNUC_UNUSED gboolean exclusive) {
398 /* At the moment, file locking is horribly broken. */
405 if (self->volume_lock_name == NULL) {
406 self->volume_lock_name = lockfile_name(self, 0);
407 } else if (self->volume_lock_fd >= 0) {
408 amfunlock(self->volume_lock_fd, self->volume_lock_name);
409 close(self->volume_lock_fd);
411 name = self->volume_lock_name;
413 if (self->file_lock_fd >= 0 && self->file_lock_name != NULL) {
414 amfunlock(self->file_lock_fd, self->file_lock_name);
416 amfree(self->file_lock_name);
417 close(self->file_lock_fd);
418 name = self->file_lock_name = lockfile_name(self, file);
422 fd = robust_open(name, O_CREAT | O_WRONLY, VFS_DEVICE_CREAT_MODE);
425 g_fprintf(stderr, "Can't open lock file %s: %s\n",
426 name, strerror(errno));
437 self->volume_lock_fd = fd;
439 self->file_lock_fd = fd;
445 /* For now, does it the bad way. */
446 static void promote_volume_lock(VfsDevice * self) {
447 amfunlock(self->volume_lock_fd, self->volume_lock_name);
448 amflock(self->volume_lock_fd, self->volume_lock_name);
451 static void demote_volume_lock(VfsDevice * self) {
452 amfunlock(self->volume_lock_fd, self->volume_lock_name);
453 amroflock(self->volume_lock_fd, self->volume_lock_name);
456 /* A SearchDirectoryFunctor */
457 static gboolean update_volume_size_functor(const char * filename,
458 gpointer user_data) {
459 char * full_filename;
460 struct stat stat_buf;
461 VfsDevice * self = user_data;
462 g_return_val_if_fail(IS_VFS_DEVICE(self), FALSE);
464 full_filename = vstralloc(self->dir_name, "/", filename, NULL);
466 if (stat(full_filename, &stat_buf) < 0) {
467 /* Log it and keep going. */
468 g_fprintf(stderr, "Couldn't stat file %s: %s\n",
469 full_filename, strerror(errno));
470 amfree(full_filename);
474 amfree(full_filename);
475 self->volume_bytes += stat_buf.st_size;
480 static void update_volume_size(VfsDevice * self) {
481 self->volume_bytes = 0;
482 search_directory(self->dir_handle, "^[0-9]+\\.",
483 update_volume_size_functor, self);
488 vfs_device_open_device (Device * pself, char * device_name) {
492 self = VFS_DEVICE(pself);
493 g_return_val_if_fail (self != NULL, FALSE);
494 g_return_val_if_fail (device_name != NULL, FALSE);
496 /* We don't have to free this ourselves; it will be freed by
497 * vfs_device_finalize whether we succeed here or not. */
498 self->dir_name = g_strconcat(device_name, "/data/", NULL);
499 if (!check_is_dir(self->dir_name, TRUE)) {
503 /* Next open the directory itself. */
504 self->dir_handle = opendir(self->dir_name);
505 if (self->dir_handle == NULL) {
506 g_fprintf(stderr, "Couldn't open directory %s for reading: %s\n",
507 device_name, strerror(errno));
511 if (!open_lock(self, -1, FALSE))
514 /* Not an error if this fails. Note that we ignore the class hierarchy.
516 rval = vfs_device_seek_file(pself, 0);
519 if (parent_class->open_device) {
520 /* Will call vfs_device_read_label. */
521 return (parent_class->open_device)(pself, device_name);
527 /* A SearchDirectoryFunctor */
528 static gboolean delete_vfs_files_functor(const char * filename,
529 gpointer user_data) {
533 self = VFS_DEVICE(user_data);
534 g_return_val_if_fail(self != NULL, FALSE);
536 /* Skip the volume lock. */
537 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
540 path_name = vstralloc(self->dir_name, "/", filename, NULL);
541 if (unlink(path_name) != 0) {
542 g_fprintf(stderr, "Error unlinking %s: %s\n", path_name,
549 /* delete_vfs_files deletes all VfsDevice files in the directory except the
551 static gboolean delete_vfs_files(VfsDevice * self) {
552 g_assert(self != NULL);
553 g_assert(self->dir_handle != NULL);
555 /* This function assumes that the volume is locked! */
556 search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX,
557 delete_vfs_files_functor, self);
561 /* This is a functor suitable for search_directory. It simply prints a
562 warning. It also dodges the volume lockfile. */
563 static gboolean check_dir_empty_functor(const char * filename,
564 gpointer user_data) {
568 self = VFS_DEVICE(user_data);
569 g_return_val_if_fail(self != NULL, FALSE);
571 if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
574 path_name = vstralloc(self->dir_name, "/", filename, NULL);
576 g_fprintf(stderr, "Found spurious storage file %s\n", path_name);
582 /* This function is used to write volume and dump headers. */
583 static gboolean write_amanda_header(VfsDevice * self,
584 const dumpfile_t * header) {
588 g_return_val_if_fail(header != NULL, FALSE);
589 g_return_val_if_fail(self != NULL, FALSE);
590 label_buffer = build_header(header, VFS_DEVICE_LABEL_SIZE);
591 if (strlen(label_buffer)+1 > VFS_DEVICE_LABEL_SIZE) {
592 amfree(label_buffer);
593 g_fprintf(stderr, "Amanda header header won't fit on VFS device!\n");
597 result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
598 amfree(label_buffer);
599 return (result == RESULT_SUCCESS);
602 /* clear_and_label will erase the contents of the directory, and write
603 * this label in its place. This function assumes we already have a volume
604 * label write lock in place (e.g., promote_lock() has been called.) */
605 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
607 dumpfile_t * label_header;
611 /* Delete any extant data, except our volume lock. */
612 if (!delete_vfs_files(self)) {
616 /* Print warnings about any remaining files. */
617 search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX,
618 check_dir_empty_functor, self);
620 self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
622 self->open_file_fd = robust_open(self->file_name,
623 O_CREAT | O_EXCL | O_WRONLY,
624 VFS_DEVICE_CREAT_MODE);
625 if (self->open_file_fd < 0) {
626 g_fprintf(stderr, "Can't open file %s: %s\n", self->file_name,
631 label_header = make_tapestart_header(DEVICE(self), label, timestamp);
632 if (write_amanda_header(self, label_header)) {
633 amfree(label_header);
634 self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
637 amfree(label_header);
642 static ReadLabelStatusFlags vfs_device_read_label(Device * dself) {
643 dumpfile_t * amanda_header;
646 self = VFS_DEVICE(dself);
647 g_return_val_if_fail(self != NULL, ~READ_LABEL_STATUS_SUCCESS);
649 amanda_header = vfs_device_seek_file(dself, 0);
650 if (amanda_header == NULL) {
651 /* This means an error occured getting locks or opening the header
653 return (READ_LABEL_STATUS_DEVICE_ERROR |
654 READ_LABEL_STATUS_VOLUME_ERROR |
655 READ_LABEL_STATUS_VOLUME_UNLABELED);
658 if (amanda_header->type != F_TAPESTART) {
659 /* This is an error, and should not happen. */
660 g_fprintf(stderr, "Got a bad volume label\n");
661 amfree(amanda_header);
662 return READ_LABEL_STATUS_VOLUME_ERROR;
665 dself->volume_label = g_strdup(amanda_header->name);
666 dself->volume_time = g_strdup(amanda_header->datestamp);
667 amfree(amanda_header);
669 update_volume_size(self);
671 if (parent_class->read_label) {
672 return (parent_class->read_label)(dself);
674 return READ_LABEL_STATUS_SUCCESS;
678 static gboolean vfs_device_write_block(Device * pself, guint size,
679 gpointer data, gboolean last_block) {
680 VfsDevice * self = VFS_DEVICE(pself);
682 g_return_val_if_fail(self != NULL, FALSE);
683 g_return_val_if_fail(last_block || size >= (guint)self->block_size, FALSE);
684 g_return_val_if_fail(pself->in_file, FALSE);
685 g_assert(self->open_file_fd >= 0);
687 if (self->volume_limit > 0 &&
688 self->volume_bytes + size > self->volume_limit) {
690 pself->is_eof = TRUE;
694 result = vfs_device_robust_write(self, data, size);
695 if (result == RESULT_SUCCESS) {
696 self->volume_bytes += size;
697 if (parent_class->write_block) {
698 (parent_class->write_block)(pself, size, data, last_block);
707 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
712 self = VFS_DEVICE(pself);
713 g_return_val_if_fail (self != NULL, -1);
715 if (data == NULL || *size_req < self->block_size) {
716 /* Just a size query. */
717 *size_req = self->block_size;
721 size = self->block_size;
722 result = vfs_device_robust_read(self, data, &size);
728 pself->is_eof = TRUE;
734 g_assert_not_reached();
737 static gboolean vfs_device_start(Device * pself,
738 DeviceAccessMode mode, char * label,
741 self = VFS_DEVICE(pself);
742 g_return_val_if_fail(self != NULL, FALSE);
743 g_return_val_if_fail(parent_class->start != NULL, FALSE);
745 if (mode == ACCESS_WRITE) {
746 promote_volume_lock(self);
747 if (!clear_and_prepare_label(self, label, timestamp)) {
748 demote_volume_lock(self);
751 demote_volume_lock(self);
756 if (parent_class->start) {
757 return parent_class->start(pself, mode, label, timestamp);
768 /* A SearchDirectoryFunctor. */
769 static gboolean get_last_file_number_functor(const char * filename,
772 glfn_data * data = (glfn_data*)datap;
773 g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE);
774 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
775 if (file > G_MAXINT) {
776 g_fprintf(stderr, "Super-large device file %s found, ignoring.\n",
780 /* This condition is needlessly complex due to sign issues. */
781 if (data->rval < 0 || ((guint)data->rval) < file) {
787 static gint get_last_file_number(VfsDevice * self) {
793 count = search_directory(self->dir_handle, "^[0-9]+\\.",
794 get_last_file_number_functor, &data);
797 /* Somebody deleted something important while we weren't looking. */
798 g_fprintf(stderr, "Error identifying VFS device contents!\n");
801 g_assert(data.rval >= 0);
813 /* A SearchDirectoryFunctor. */
814 static gboolean get_next_file_number_functor(const char * filename,
817 gnfn_data * data = (gnfn_data*)datap;
818 g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE);
819 file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
820 if (file > G_MAXINT) {
821 g_fprintf(stderr, "Super-large device file %s found, ignoring.\n",
825 /* This condition is needlessly complex due to sign issues. */
826 if (file >= data->request &&
827 (data->best_found < 0 || file < (guint)data->best_found)) {
828 data->best_found = file;
833 /* Returns the file number equal to or greater than the given requested
835 static gint get_next_file_number(VfsDevice * self, guint request) {
839 data.request = request;
840 data.best_found = -1;
842 count = search_directory(self->dir_handle, "^[0-9]+\\.",
843 get_next_file_number_functor, &data);
846 /* Somebody deleted something important while we weren't looking. */
847 g_fprintf(stderr, "Error identifying VFS device contents!\n");
852 return data.best_found;
855 /* Finds the file number, acquires a lock, and returns the new file name. */
857 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
859 char *base, *sanitary_base;
863 fileno = 1 + get_last_file_number(self);
867 if (open_lock(self, fileno, TRUE)) {
874 base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
876 sanitary_base = sanitise_filename(base);
878 rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
879 amfree(sanitary_base);
884 vfs_device_start_file (Device * pself, const dumpfile_t * ji) {
887 self = VFS_DEVICE(pself);
888 g_return_val_if_fail (self != NULL, FALSE);
889 g_return_val_if_fail (ji != NULL, FALSE);
891 if (self->volume_limit > 0 &&
892 self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) {
897 /* The basic idea here is thus:
898 1) Try to get a lock on the next filenumber.
899 2) If that fails, update our idea of "next filenumber" and try again.
900 3) Then open the file itself.
904 self->file_name = make_new_file_name(self, ji);
905 if (self->file_name == NULL)
908 self->open_file_fd = robust_open(self->file_name,
909 O_CREAT | O_EXCL | O_RDWR,
910 VFS_DEVICE_CREAT_MODE);
911 if (self->open_file_fd < 0) {
912 g_fprintf(stderr, "Can't create file %s: %s\n", self->file_name,
919 if (!write_amanda_header(self, ji)) {
924 self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
926 if (parent_class->start_file) {
927 parent_class->start_file(pself, ji);
933 vfs_device_finish_file (Device * pself) {
935 self = VFS_DEVICE(pself);
936 g_return_val_if_fail(self != NULL, FALSE);
940 if (parent_class->finish_file) {
941 return parent_class->finish_file(pself);
945 g_assert_not_reached();
948 /* This function is used for two purposes, rather than one. In
949 * addition to its documented behavior, we also use it to open the
950 * volume label for reading at startup. In that second case, we avoid
951 * FdDevice-related side effects. */
953 vfs_device_seek_file (Device * pself, guint requested_file) {
957 char header_buffer[VFS_DEVICE_LABEL_SIZE];
958 int header_buffer_size = sizeof(header_buffer);
961 self = VFS_DEVICE(pself);
962 g_return_val_if_fail (self != NULL, NULL);
964 pself->in_file = FALSE;
968 if (requested_file > 0) {
969 file = get_next_file_number(self, requested_file);
971 file = requested_file;
975 /* Did they request one past the end? */
976 char * tmp_file_name;
977 tmp_file_name = file_number_to_file_name(self, requested_file - 1);
978 if (tmp_file_name != NULL) {
980 return make_tapeend_header();
986 if (!open_lock(self, file, FALSE)) {
990 self->file_name = file_number_to_file_name(self, file);
991 if (self->file_name == NULL) {
996 self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
997 if (self->open_file_fd <= 0) {
998 g_fprintf(stderr, "Couldn't open file %s: %s\n", self->file_name,
1000 amfree(self->file_name);
1005 result = vfs_device_robust_read(self, header_buffer,
1006 &header_buffer_size);
1007 if (result != RESULT_SUCCESS) {
1008 g_fprintf(stderr, "Problem reading Amanda header.\n");
1013 rval = malloc(sizeof(*rval));
1014 parse_file_header(header_buffer, rval, header_buffer_size);
1016 switch (rval->type) {
1018 case F_CONT_DUMPFILE:
1019 case F_SPLIT_DUMPFILE:
1021 if (parent_class->seek_file) {
1022 parent_class->seek_file(pself, file);
1030 } else if (file == 0) {
1039 vfs_device_seek_block (Device * pself, guint64 block) {
1043 self = VFS_DEVICE(pself);
1044 g_return_val_if_fail (self != NULL, FALSE);
1045 g_return_val_if_fail (self->open_file_fd >= 0, FALSE);
1046 g_assert(sizeof(off_t) >= sizeof(guint64));
1048 /* Pretty simple. We figure out the blocksize and use that. */
1049 result = lseek(self->open_file_fd,
1050 (block) * self->block_size + VFS_DEVICE_LABEL_SIZE,
1052 return (result != (off_t)(-1));
1056 vfs_device_property_get (Device * pself, DevicePropertyId ID, GValue * val) {
1058 self = VFS_DEVICE(pself);
1059 g_return_val_if_fail(self != NULL, FALSE);
1060 if (ID == PROPERTY_BLOCK_SIZE) {
1061 g_value_unset_init(val, G_TYPE_INT);
1062 g_value_set_int(val, self->block_size);
1064 } else if (ID == PROPERTY_MAX_VOLUME_USAGE) {
1065 g_value_unset_init(val, G_TYPE_UINT64);
1066 g_value_set_uint64(val, self->volume_limit);
1068 } else if (ID == PROPERTY_FREE_SPACE) {
1069 QualifiedSize qsize;
1070 struct fs_usage fsusage;
1071 guint64 bytes_avail;
1073 if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) {
1074 if (fsusage.fsu_bavail_top_bit_set)
1077 bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1078 if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024)
1079 bytes_avail = (guint64)self->volume_limit * 1024;
1081 qsize.accuracy = SIZE_ACCURACY_REAL;
1082 qsize.bytes = bytes_avail;
1084 g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno));
1085 qsize.accuracy = SIZE_ACCURACY_UNKNOWN;
1088 g_value_unset_init(val, QUALIFIED_SIZE_TYPE);
1089 g_value_set_boxed(val, &qsize);
1092 if (parent_class->property_get) {
1093 return parent_class->property_get(pself, ID, val);
1098 g_assert_not_reached();
1102 vfs_device_property_set (Device * pself, DevicePropertyId ID, GValue * val) {
1104 self = VFS_DEVICE(pself);
1105 g_return_val_if_fail(self != NULL, FALSE);
1106 if (ID == PROPERTY_BLOCK_SIZE) {
1107 int block_size = g_value_get_int(val);
1108 g_return_val_if_fail(block_size > 0, FALSE);
1109 self->block_size = block_size;
1111 } else if (ID == PROPERTY_MAX_VOLUME_USAGE) {
1112 self->volume_limit = g_value_get_uint64(val);
1115 if (parent_class->property_get) {
1116 return parent_class->property_get(pself, ID, val);
1121 g_assert_not_reached();
1124 static gboolean try_unlink(const char * file) {
1125 if (unlink(file) < 0) {
1126 g_fprintf(stderr, "Can't unlink file %s: %s\n", file, strerror(errno));
1134 vfs_device_recycle_file (Device * pself, guint filenum) {
1136 struct stat file_status;
1139 self = VFS_DEVICE(pself);
1140 g_return_val_if_fail(self != NULL, FALSE);
1141 g_return_val_if_fail(!(pself->in_file), FALSE);
1144 * 1) Get a write lock on the file in question.
1145 * 2) Unlink the file in question.
1146 * 3) Unlink the lock.
1147 * 4) Release the lock.
1148 * FIXME: Is it OK to unlink the lockfile?
1151 self->file_name = file_number_to_file_name(self, filenum);
1153 if (self->file_name == NULL)
1156 if (!open_lock(self, filenum, TRUE))
1159 if (0 != stat(self->file_name, &file_status)) {
1160 fprintf(stderr, "Cannot stat file %s (%s), so not removing.\n",
1161 self->file_name, strerror(errno));
1164 file_size = file_status.st_size;
1166 if (!try_unlink(self->file_name) ||
1167 !try_unlink(self->file_lock_name)) {
1172 self->volume_bytes -= file_size;
1177 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1179 int fd = self->open_file_fd;
1180 int want = *count, got = 0;
1182 while (got < want) {
1184 result = read(fd, buf + got, want - got);
1187 } else if (result == 0) {
1190 return RESULT_NO_DATA;
1193 return RESULT_SUCCESS;
1200 || errno == EWOULDBLOCK
1209 /* Error occured. */
1210 g_fprintf(stderr, "Error reading fd %d: %s\n", fd, strerror(errno));
1217 return RESULT_SUCCESS;
1221 vfs_device_robust_write(VfsDevice * self, char *buf, int count) {
1222 int fd = self->open_file_fd;
1225 while (rval < count) {
1227 result = write(fd, buf + rval, count - rval);
1236 || errno == EWOULDBLOCK
1252 /* We are definitely out of space. */
1253 return RESULT_NO_SPACE;
1255 /* Error occured. Note that here we handle EIO as an error. */
1256 g_fprintf(stderr, "Error writing device fd %d: %s\n",
1257 fd, strerror(errno));
1259 return RESULT_ERROR;
1262 return RESULT_SUCCESS;