X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=device-src%2Fvfs-device.c;h=ce536b83e244ed5872aa67e34bb9b2e849d34bb7;hb=c489fc6ad53e4658722b7f63fb40edc6f53c57a9;hp=b197dcc1d91f7919a93297d17b2c737b4154b714;hpb=94a044f90357edefa6f4ae9f0b1d5885b0e34aee;p=debian%2Famanda diff --git a/device-src/vfs-device.c b/device-src/vfs-device.c index b197dcc..ce536b8 100644 --- a/device-src/vfs-device.c +++ b/device-src/vfs-device.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved. + * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 as @@ -14,18 +14,53 @@ * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120 - * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com + * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300 + * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com */ +#include "amanda.h" #include /* memset() */ - -#include "vfs-device.h" #include "fsusage.h" -#include "amanda.h" #include "util.h" +#include "device.h" #include +/* + * Type checking and casting macros + */ +#define TYPE_VFS_DEVICE (vfs_device_get_type()) +#define VFS_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice) +#define VFS_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), vfs_device_get_type(), VfsDevice const) +#define VFS_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), vfs_device_get_type(), VfsDeviceClass) +#define IS_VFS_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), vfs_device_get_type ()) + +#define VFS_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), vfs_device_get_type(), VfsDeviceClass) +static GType vfs_device_get_type (void); + +/* + * Main object structure + */ +typedef struct { + Device __parent__; + + /*< private >*/ + char * dir_name; + char * file_name; + int open_file_fd; + + /* Properties */ + guint64 volume_bytes; + guint64 volume_limit; +} VfsDevice; + +/* + * Class definition + */ +typedef struct { + DeviceClass __parent__; +} VfsDeviceClass; + + /* This regex will match all VfsDevice files in a directory. We use it for cleanup and verification. Note that this regex does NOT match the volume label. */ @@ -35,6 +70,14 @@ generated by lockfile_name(0). */ #define VOLUME_LOCKFILE_NAME "00000-lock" +#define VFS_DEVICE_MIN_BLOCK_SIZE (1) +#define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX) +#define VFS_DEVICE_DEFAULT_BLOCK_SIZE (DISK_BLOCK_BYTES) +#define VFS_DEVICE_LABEL_SIZE (32768) + +/* This looks dangerous, but is actually modified by the umask. */ +#define VFS_DEVICE_CREAT_MODE 0666 + /* Possible (abstracted) results from a system I/O operation. */ typedef enum { RESULT_SUCCESS, @@ -46,29 +89,27 @@ typedef enum { RESULT_MAX } IoResult; +void vfs_device_register(void); + /* here are local prototypes */ static void vfs_device_init (VfsDevice * o); static void vfs_device_class_init (VfsDeviceClass * c); +static void vfs_device_base_init (VfsDeviceClass * c); static void vfs_device_finalize (GObject * o); static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode, char * label, char * timestamp); -static gboolean vfs_device_open_device (Device * pself, - char * device_name); -static gboolean vfs_device_start_file (Device * pself, const dumpfile_t * ji); +static gboolean vfs_device_finish (Device * pself); +static void vfs_device_open_device (Device * pself, char * device_name, + char * device_type, char * device_node); +static gboolean vfs_device_start_file (Device * pself, dumpfile_t * ji); static gboolean vfs_device_finish_file (Device * pself); static dumpfile_t * vfs_device_seek_file (Device * self, guint file); static gboolean vfs_device_seek_block (Device * self, guint64 block); -static gboolean vfs_device_property_get (Device * pself, DevicePropertyId ID, - GValue * val); -static gboolean vfs_device_property_set (Device * pself, DevicePropertyId ID, - GValue * val); static gboolean vfs_device_recycle_file (Device * pself, guint filenum); -static Device * vfs_device_factory(char * device_type, - char * device_name); -static ReadLabelStatusFlags vfs_device_read_label(Device * dself); -static gboolean vfs_device_write_block(Device * self, guint size, - gpointer data, gboolean last_block); +static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node); +static DeviceStatusFlags vfs_device_read_label(Device * dself); +static gboolean vfs_device_write_block(Device * self, guint size, gpointer data); static int vfs_device_read_block(Device * self, gpointer data, int * size_req); static IoResult vfs_device_robust_write(VfsDevice * self, char *buf, int count); @@ -77,21 +118,29 @@ static IoResult vfs_device_robust_read(VfsDevice * self, char *buf, /* Various helper functions. */ static void release_file(VfsDevice * self); -static gboolean check_is_dir(const char * name, gboolean printmsg); +static gboolean check_is_dir(Device * d_self, const char * name); static char* file_number_to_file_name(VfsDevice * self, guint file); static gboolean file_number_to_file_name_functor(const char * filename, gpointer datap); +static gboolean vfs_device_set_max_volume_usage_fn(Device *p_self, + DevicePropertyBase *base, GValue *val, + PropertySurety surety, PropertySource source); +gboolean vfs_device_get_free_space_fn(struct Device *p_self, + DevicePropertyBase *base, GValue *val, + PropertySurety *surety, PropertySource *source); //static char* lockfile_name(VfsDevice * self, guint file); static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive); static void promote_volume_lock(VfsDevice * self); static void demote_volume_lock(VfsDevice * self); -static gboolean delete_vfs_files(VfsDevice * self); +static void delete_vfs_files(VfsDevice * self); static gboolean delete_vfs_files_functor(const char * filename, gpointer self); static gboolean check_dir_empty_functor(const char * filename, gpointer self); static gboolean clear_and_prepare_label(VfsDevice * self, char * label, char * timestamp); +static int search_vfs_directory(VfsDevice *self, const char * regex, + SearchDirectoryFunctor functor, gpointer user_data); static gint get_last_file_number(VfsDevice * self); static gboolean get_last_file_number_functor(const char * filename, gpointer datap); @@ -106,7 +155,7 @@ void vfs_device_register(void) { register_device(vfs_device_factory, device_prefix_list); } -GType +static GType vfs_device_get_type (void) { static GType type = 0; @@ -114,7 +163,7 @@ vfs_device_get_type (void) if G_UNLIKELY(type == 0) { static const GTypeInfo info = { sizeof (VfsDeviceClass), - (GBaseInitFunc) NULL, + (GBaseInitFunc) vfs_device_base_init, (GBaseFinalizeFunc) NULL, (GClassInitFunc) vfs_device_class_init, (GClassFinalizeFunc) NULL, @@ -134,77 +183,56 @@ vfs_device_get_type (void) static void vfs_device_init (VfsDevice * self) { - Device * o; - DeviceProperty prop; + Device * dself = DEVICE(self); GValue response; - self->dir_handle = NULL; self->dir_name = self->file_name = NULL; - self->file_lock_name = self->volume_lock_name = NULL; - self->file_lock_fd = self->volume_lock_fd = self->open_file_fd = -1; - self->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE; - self->volume_bytes = 0; + self->open_file_fd = -1; + self->volume_bytes = 0; self->volume_limit = 0; /* Register Properties */ - o = DEVICE(self); bzero(&response, sizeof(response)); - prop.base = &device_property_concurrency; - prop.access = PROPERTY_ACCESS_GET_MASK; + g_value_init(&response, CONCURRENCY_PARADIGM_TYPE); g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS); - device_add_property(o, &prop, &response); + device_set_simple_property(dself, PROPERTY_CONCURRENCY, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); g_value_unset(&response); - prop.base = &device_property_streaming; g_value_init(&response, STREAMING_REQUIREMENT_TYPE); g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE); - device_add_property(o, &prop, &response); + device_set_simple_property(dself, PROPERTY_STREAMING, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); g_value_unset(&response); - prop.base = &device_property_min_block_size; - g_value_init(&response, G_TYPE_UINT); - g_value_set_uint(&response, VFS_DEVICE_MIN_BLOCK_SIZE); - device_add_property(o, &prop, &response); - - prop.base = &device_property_max_block_size; - g_value_set_uint(&response, VFS_DEVICE_MAX_BLOCK_SIZE); - device_add_property(o, &prop, &response); + g_value_init(&response, G_TYPE_BOOLEAN); + g_value_set_boolean(&response, TRUE); + device_set_simple_property(dself, PROPERTY_APPENDABLE, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); g_value_unset(&response); - prop.base = &device_property_appendable; g_value_init(&response, G_TYPE_BOOLEAN); g_value_set_boolean(&response, TRUE); - device_add_property(o, &prop, &response); - - prop.base = &device_property_partial_deletion; - device_add_property(o, &prop, &response); + device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); g_value_unset(&response); - /* This one is handled by Device's get_property handler. */ - prop.base = &device_property_canonical_name; - device_add_property(o, &prop, NULL); + g_value_init(&response, G_TYPE_BOOLEAN); + g_value_set_boolean(&response, FALSE); + device_set_simple_property(dself, PROPERTY_COMPRESSION, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); + g_value_unset(&response); - prop.base = &device_property_medium_access_type; g_value_init(&response, MEDIA_ACCESS_MODE_TYPE); g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE); - device_add_property(o, &prop, &response); + device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE, + &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED); g_value_unset(&response); - - /* These are dynamic, handled in vfs_device_property_xxx */ - prop.base = &device_property_block_size; - prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START; - device_add_property(o, &prop, NULL); - - prop.base = &device_property_max_volume_usage; - prop.access = - (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) & - (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE); - device_add_property(o, &prop, NULL); } static void -vfs_device_class_init (VfsDeviceClass * c G_GNUC_UNUSED) +vfs_device_class_init (VfsDeviceClass * c) { GObjectClass *g_object_class = (GObjectClass*) c; DeviceClass *device_class = (DeviceClass *)c; @@ -220,25 +248,92 @@ vfs_device_class_init (VfsDeviceClass * c G_GNUC_UNUSED) device_class->finish_file = vfs_device_finish_file; device_class->seek_file = vfs_device_seek_file; device_class->seek_block = vfs_device_seek_block; - device_class->property_get = vfs_device_property_get; - device_class->property_set = vfs_device_property_set; device_class->recycle_file = vfs_device_recycle_file; + device_class->finish = vfs_device_finish; g_object_class->finalize = vfs_device_finalize; } -/* Drops everything associated with the volume file: Its name and fd, - its lock, and its lock's name and fd. */ +static void +vfs_device_base_init (VfsDeviceClass * c) +{ + DeviceClass *device_class = (DeviceClass *)c; + + device_class_register_property(device_class, PROPERTY_FREE_SPACE, + PROPERTY_ACCESS_GET_MASK, + vfs_device_get_free_space_fn, + NULL); + + device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE, + (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) & + (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE), + device_simple_property_get_fn, + vfs_device_set_max_volume_usage_fn); + + device_class_register_property(device_class, PROPERTY_COMPRESSION, + PROPERTY_ACCESS_GET_MASK, + device_simple_property_get_fn, + NULL); +} + +gboolean +vfs_device_set_max_volume_usage_fn(Device *p_self, + DevicePropertyBase *base, GValue *val, + PropertySurety surety, PropertySource source) +{ + VfsDevice *self = VFS_DEVICE(p_self); + + self->volume_limit = g_value_get_uint64(val); + + return device_simple_property_set_fn(p_self, base, val, surety, source); +} + +gboolean +vfs_device_get_free_space_fn(struct Device *p_self, + DevicePropertyBase *base G_GNUC_UNUSED, GValue *val, + PropertySurety *surety, PropertySource *source) +{ + VfsDevice *self = VFS_DEVICE(p_self); + QualifiedSize qsize; + struct fs_usage fsusage; + guint64 bytes_avail; + + if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) { + if (fsusage.fsu_bavail_top_bit_set) + bytes_avail = 0; + else + bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize; + if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024) + bytes_avail = (guint64)self->volume_limit * 1024; + + qsize.accuracy = SIZE_ACCURACY_REAL; + qsize.bytes = bytes_avail; + if (surety) + *surety = PROPERTY_SURETY_GOOD; + } else { + g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno)); + qsize.accuracy = SIZE_ACCURACY_UNKNOWN; + qsize.bytes = 0; + if (surety) + *surety = PROPERTY_SURETY_BAD; + } + + g_value_unset_init(val, QUALIFIED_SIZE_TYPE); + g_value_set_boxed(val, &qsize); + + if (source) + *source = PROPERTY_SOURCE_DETECTED; + + return TRUE; +} + +/* Drops everything associated with the volume file: Its name and fd. */ static void release_file(VfsDevice * self) { /* Doesn't hurt. */ - robust_close(self->open_file_fd); + if (self->open_file_fd != -1) + robust_close(self->open_file_fd); amfree(self->file_name); - if (self->file_lock_fd > 0) { - amfunlock(self->file_lock_fd, self->file_lock_name); - close(self->file_lock_fd); - amfree(self->file_lock_name); - } - self->file_lock_fd = self->open_file_fd = -1; + self->open_file_fd = -1; } static void vfs_device_finalize(GObject * obj_self) { @@ -254,53 +349,34 @@ static void vfs_device_finalize(GObject * obj_self) { amfree(self->dir_name); - if(self->dir_handle) { - closedir (self->dir_handle); - self->dir_handle = NULL; - } - release_file(self); - - if (self->volume_lock_fd >= 0) { - amfunlock(self->volume_lock_fd, self->volume_lock_name); - close(self->volume_lock_fd); - } - - amfree(self->volume_lock_name); } -static Device * vfs_device_factory(char * device_type, - char * device_name) { +static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) { Device * rval; g_assert(0 == strcmp(device_type, "file")); rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL)); - if (!device_open_device(rval, device_name)) { - g_object_unref(rval); - return NULL; - } else { - return rval; - } + device_open_device(rval, device_name, device_type, device_node); + return rval; } -static gboolean check_is_dir(const char * name, gboolean printmsg) { +static gboolean check_is_dir(Device * d_self, const char * name) { struct stat dir_status; if (stat(name, &dir_status) < 0) { #ifdef EINTR if (errno == EINTR) { - return check_is_dir(name, printmsg); + return check_is_dir(d_self, name); } #endif /* EINTR */ - if (printmsg) { - g_fprintf(stderr, "Error checking directory %s: %s\n", - name, strerror(errno)); - } + device_set_error(d_self, + vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; } else if (!S_ISDIR(dir_status.st_mode)) { - if (printmsg) { - g_fprintf(stderr, "VFS Device path %s is not a directory.\n", - name); - } + device_set_error(d_self, + vstrallocf(_("VFS Device path %s is not a directory"), name), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; } else { return TRUE; @@ -325,11 +401,9 @@ static gboolean file_number_to_file_name_functor(const char * filename, /* Just to be thorough, let's check that it's a real file. */ if (0 != stat(result_tmp, &file_status)) { - g_fprintf(stderr, "Cannot stat file %s (%s), ignoring it.\n", - result_tmp, strerror(errno)); + g_warning(_("Cannot stat file %s (%s), ignoring it"), result_tmp, strerror(errno)); } else if (!S_ISREG(file_status.st_mode)) { - g_fprintf(stderr, "%s is not a regular file, ignoring it.\n", - result_tmp); + g_warning(_("%s is not a regular file, ignoring it"), result_tmp); } else { data->count ++; if (data->result == NULL) { @@ -349,15 +423,14 @@ static char * file_number_to_file_name(VfsDevice * self, guint device_file) { char * regex; fnfn_data data; - g_return_val_if_fail(self != NULL, NULL); data.self = self; data.count = 0; data.result = NULL; regex = g_strdup_printf("^0*%u\\.", device_file); - search_directory(self->dir_handle, regex, - file_number_to_file_name_functor, &data); + search_vfs_directory(self, regex, + file_number_to_file_name_functor, &data); amfree(regex); @@ -365,8 +438,7 @@ static char * file_number_to_file_name(VfsDevice * self, guint device_file) { g_assert(data.result == NULL); return NULL; } else if (data.count > 1) { - g_fprintf(stderr, - "Found multiple names for file number %d, choosing file %s.\n", + g_warning("Found multiple names for file number %d, choosing file %s", device_file, data.result); return data.result; } else { @@ -397,60 +469,13 @@ static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self, /* At the moment, file locking is horribly broken. */ return TRUE; - -/* - int fd; - char * name; - if (file < 0) { - if (self->volume_lock_name == NULL) { - self->volume_lock_name = lockfile_name(self, 0); - } else if (self->volume_lock_fd >= 0) { - amfunlock(self->volume_lock_fd, self->volume_lock_name); - close(self->volume_lock_fd); - } - name = self->volume_lock_name; - } else { - if (self->file_lock_fd >= 0 && self->file_lock_name != NULL) { - amfunlock(self->file_lock_fd, self->file_lock_name); - } - amfree(self->file_lock_name); - close(self->file_lock_fd); - name = self->file_lock_name = lockfile_name(self, file); - } - - - fd = robust_open(name, O_CREAT | O_WRONLY, VFS_DEVICE_CREAT_MODE); - - if (fd < 0) { - g_fprintf(stderr, "Can't open lock file %s: %s\n", - name, strerror(errno)); - return FALSE; - } - - if (exclusive) { - amflock(fd, name); - } else { - amroflock(fd, name); - } - - if (file < 0) { - self->volume_lock_fd = fd; - } else { - self->file_lock_fd = fd; - } - return TRUE; -*/ } /* For now, does it the bad way. */ -static void promote_volume_lock(VfsDevice * self) { - amfunlock(self->volume_lock_fd, self->volume_lock_name); - amflock(self->volume_lock_fd, self->volume_lock_name); +static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) { } -static void demote_volume_lock(VfsDevice * self) { - amfunlock(self->volume_lock_fd, self->volume_lock_name); - amroflock(self->volume_lock_fd, self->volume_lock_name); +static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) { } /* A SearchDirectoryFunctor */ @@ -459,14 +484,12 @@ static gboolean update_volume_size_functor(const char * filename, char * full_filename; struct stat stat_buf; VfsDevice * self = user_data; - g_return_val_if_fail(IS_VFS_DEVICE(self), FALSE); - + full_filename = vstralloc(self->dir_name, "/", filename, NULL); if (stat(full_filename, &stat_buf) < 0) { /* Log it and keep going. */ - g_fprintf(stderr, "Couldn't stat file %s: %s\n", - full_filename, strerror(errno)); + g_warning(_("Couldn't stat file %s: %s"), full_filename, strerror(errno)); amfree(full_filename); return TRUE; } @@ -479,48 +502,26 @@ static gboolean update_volume_size_functor(const char * filename, static void update_volume_size(VfsDevice * self) { self->volume_bytes = 0; - search_directory(self->dir_handle, "^[0-9]+\\.", - update_volume_size_functor, self); + search_vfs_directory(self, "^[0-9]+\\.", + update_volume_size_functor, self); } -static gboolean -vfs_device_open_device (Device * pself, char * device_name) { +static void +vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) { VfsDevice * self; - dumpfile_t * rval; - self = VFS_DEVICE(pself); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (device_name != NULL, FALSE); + + pself->min_block_size = VFS_DEVICE_MIN_BLOCK_SIZE; + pself->max_block_size = VFS_DEVICE_MAX_BLOCK_SIZE; + pself->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE; /* We don't have to free this ourselves; it will be freed by * vfs_device_finalize whether we succeed here or not. */ - self->dir_name = g_strconcat(device_name, "/data/", NULL); - if (!check_is_dir(self->dir_name, TRUE)) { - return FALSE; - } - - /* Next open the directory itself. */ - self->dir_handle = opendir(self->dir_name); - if (self->dir_handle == NULL) { - g_fprintf(stderr, "Couldn't open directory %s for reading: %s\n", - device_name, strerror(errno)); - return FALSE; - } - - if (!open_lock(self, -1, FALSE)) - return FALSE; - - /* Not an error if this fails. Note that we ignore the class hierarchy. - */ - rval = vfs_device_seek_file(pself, 0); - amfree(rval); + self->dir_name = g_strconcat(device_node, "/data/", NULL); if (parent_class->open_device) { - /* Will call vfs_device_read_label. */ - return (parent_class->open_device)(pself, device_name); - } else { - return TRUE; + parent_class->open_device(pself, device_name, device_type, device_node); } } @@ -528,10 +529,11 @@ vfs_device_open_device (Device * pself, char * device_name) { static gboolean delete_vfs_files_functor(const char * filename, gpointer user_data) { VfsDevice * self; + Device * d_self; char * path_name; self = VFS_DEVICE(user_data); - g_return_val_if_fail(self != NULL, FALSE); + d_self = DEVICE(self); /* Skip the volume lock. */ if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0) @@ -539,8 +541,7 @@ static gboolean delete_vfs_files_functor(const char * filename, path_name = vstralloc(self->dir_name, "/", filename, NULL); if (unlink(path_name) != 0) { - g_fprintf(stderr, "Error unlinking %s: %s\n", path_name, - strerror(errno)); + g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno)); } amfree(path_name); return TRUE; @@ -548,14 +549,12 @@ static gboolean delete_vfs_files_functor(const char * filename, /* delete_vfs_files deletes all VfsDevice files in the directory except the volume lockfile. */ -static gboolean delete_vfs_files(VfsDevice * self) { +static void delete_vfs_files(VfsDevice * self) { g_assert(self != NULL); - g_assert(self->dir_handle != NULL); /* This function assumes that the volume is locked! */ - search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX, - delete_vfs_files_functor, self); - return TRUE; + search_vfs_directory(self, VFS_DEVICE_FILE_REGEX, + delete_vfs_files_functor, self); } /* This is a functor suitable for search_directory. It simply prints a @@ -564,16 +563,17 @@ static gboolean check_dir_empty_functor(const char * filename, gpointer user_data) { VfsDevice * self; char * path_name; + Device *d_self; self = VFS_DEVICE(user_data); - g_return_val_if_fail(self != NULL, FALSE); + d_self = DEVICE(self); if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0) return TRUE; path_name = vstralloc(self->dir_name, "/", filename, NULL); - g_fprintf(stderr, "Found spurious storage file %s\n", path_name); + g_warning(_("Found spurious storage file %s"), path_name); amfree(path_name); return TRUE; @@ -584,17 +584,21 @@ static gboolean write_amanda_header(VfsDevice * self, const dumpfile_t * header) { char * label_buffer; IoResult result; - - g_return_val_if_fail(header != NULL, FALSE); - g_return_val_if_fail(self != NULL, FALSE); + Device *d_self = DEVICE(self); + + g_assert(header != NULL); + label_buffer = build_header(header, VFS_DEVICE_LABEL_SIZE); if (strlen(label_buffer)+1 > VFS_DEVICE_LABEL_SIZE) { amfree(label_buffer); - g_fprintf(stderr, "Amanda header header won't fit on VFS device!\n"); + device_set_error(d_self, + stralloc(_("Amanda file header won't fit in a single block!")), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; } result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE); + /* vfs_device_robust_write sets error status if necessary */ amfree(label_buffer); return (result == RESULT_SUCCESS); } @@ -605,17 +609,16 @@ static gboolean write_amanda_header(VfsDevice * self, static gboolean clear_and_prepare_label(VfsDevice * self, char * label, char * timestamp) { dumpfile_t * label_header; + Device *d_self = DEVICE(self); release_file(self); /* Delete any extant data, except our volume lock. */ - if (!delete_vfs_files(self)) { - return FALSE; - } + delete_vfs_files(self); /* Print warnings about any remaining files. */ - search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX, - check_dir_empty_functor, self); + search_vfs_directory(self, VFS_DEVICE_FILE_REGEX, + check_dir_empty_functor, self); self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label); @@ -623,84 +626,132 @@ static gboolean clear_and_prepare_label(VfsDevice * self, char * label, O_CREAT | O_EXCL | O_WRONLY, VFS_DEVICE_CREAT_MODE); if (self->open_file_fd < 0) { - g_fprintf(stderr, "Can't open file %s: %s\n", self->file_name, - strerror(errno)); + device_set_error(d_self, + vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR); return FALSE; } label_header = make_tapestart_header(DEVICE(self), label, timestamp); - if (write_amanda_header(self, label_header)) { - amfree(label_header); - self->volume_bytes = VFS_DEVICE_LABEL_SIZE; - return TRUE; - } else { + if (!write_amanda_header(self, label_header)) { + /* write_amanda_header sets error status if necessary */ amfree(label_header); return FALSE; } + amfree(label_header); + self->volume_bytes = VFS_DEVICE_LABEL_SIZE; + return TRUE; } -static ReadLabelStatusFlags vfs_device_read_label(Device * dself) { +/* Just like search_directory, but returns -1 in the event of an error */ +static int +search_vfs_directory( + VfsDevice *self, + const char * regex, + SearchDirectoryFunctor functor, + gpointer user_data) +{ + Device *dself = DEVICE(self); + DIR *dir_handle; + int result = -1; + + dir_handle = opendir(self->dir_name); + if (dir_handle == NULL) { + device_set_error(dself, + vstrallocf(_("Couldn't open device %s (directory %s) for reading: %s"), + dself->device_name, self->dir_name, strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); + goto error; + } + + /* TODO: is this the right moment to acquire a lock?? */ + + result = search_directory(dir_handle, regex, functor, user_data); + +error: + if (dir_handle) + closedir(dir_handle); + return result; +} + +static DeviceStatusFlags vfs_device_read_label(Device * dself) { dumpfile_t * amanda_header; VfsDevice * self; self = VFS_DEVICE(dself); - g_return_val_if_fail(self != NULL, ~READ_LABEL_STATUS_SUCCESS); + g_assert(self != NULL); + + if (!check_is_dir(dself, self->dir_name)) { + /* error message set by check_is_dir */ + return dself->status; + } - amanda_header = vfs_device_seek_file(dself, 0); + amfree(dself->volume_label); + amfree(dself->volume_time); + amfree(dself->volume_header); + + if (device_in_error(self)) return dself->status; + + amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0); if (amanda_header == NULL) { /* This means an error occured getting locks or opening the header * file. */ - return (READ_LABEL_STATUS_DEVICE_ERROR | - READ_LABEL_STATUS_VOLUME_ERROR | - READ_LABEL_STATUS_VOLUME_UNLABELED); + device_set_error(dself, + stralloc("Error loading device header -- unlabeled volume?"), + DEVICE_STATUS_DEVICE_ERROR + | DEVICE_STATUS_VOLUME_ERROR + | DEVICE_STATUS_VOLUME_UNLABELED); + return dself->status; } if (amanda_header->type != F_TAPESTART) { /* This is an error, and should not happen. */ - g_fprintf(stderr, "Got a bad volume label\n"); + device_set_error(dself, + stralloc(_("Got a bad volume label")), + DEVICE_STATUS_VOLUME_ERROR); amfree(amanda_header); - return READ_LABEL_STATUS_VOLUME_ERROR; + return dself->status; } dself->volume_label = g_strdup(amanda_header->name); dself->volume_time = g_strdup(amanda_header->datestamp); - amfree(amanda_header); + /* dself->volume_header is already set */ + + device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS); update_volume_size(self); - if (parent_class->read_label) { - return (parent_class->read_label)(dself); - } else { - return READ_LABEL_STATUS_SUCCESS; - } + return dself->status; } -static gboolean vfs_device_write_block(Device * pself, guint size, - gpointer data, gboolean last_block) { +static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) { VfsDevice * self = VFS_DEVICE(pself); IoResult result; - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(last_block || size >= (guint)self->block_size, FALSE); - g_return_val_if_fail(pself->in_file, FALSE); + + if (device_in_error(self)) return FALSE; + g_assert(self->open_file_fd >= 0); if (self->volume_limit > 0 && self->volume_bytes + size > self->volume_limit) { /* Simulate EOF. */ pself->is_eof = TRUE; + device_set_error(pself, + stralloc(_("No space left on device")), + DEVICE_STATUS_VOLUME_ERROR); return FALSE; } result = vfs_device_robust_write(self, data, size); - if (result == RESULT_SUCCESS) { - self->volume_bytes += size; - if (parent_class->write_block) { - (parent_class->write_block)(pself, size, data, last_block); - } - return TRUE; - } else { + if (result != RESULT_SUCCESS) { + /* vfs_device_robust_write set error status appropriately */ return FALSE; } + + self->volume_bytes += size; + pself->block ++; + + return TRUE; } static int @@ -710,24 +761,34 @@ vfs_device_read_block(Device * pself, gpointer data, int * size_req) { IoResult result; self = VFS_DEVICE(pself); - g_return_val_if_fail (self != NULL, -1); - if (data == NULL || *size_req < self->block_size) { + if (device_in_error(self)) return -1; + + if (data == NULL || (gsize)*size_req < pself->block_size) { /* Just a size query. */ - *size_req = self->block_size; + g_assert(pself->block_size < INT_MAX); + *size_req = (int)pself->block_size; return 0; } - size = self->block_size; + size = pself->block_size; result = vfs_device_robust_read(self, data, &size); switch (result) { case RESULT_SUCCESS: *size_req = size; + pself->block++; return size; case RESULT_NO_DATA: pself->is_eof = TRUE; - /* FALLTHROUGH */ + pself->in_file = FALSE; + device_set_error(pself, + stralloc(_("EOF")), + DEVICE_STATUS_SUCCESS); + return -1; default: + device_set_error(pself, + vstrallocf(_("Error reading from data file: %s"), strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); return -1; } @@ -739,25 +800,53 @@ static gboolean vfs_device_start(Device * pself, char * timestamp) { VfsDevice * self; self = VFS_DEVICE(pself); - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(parent_class->start != NULL, FALSE); - + + if (!check_is_dir(pself, self->dir_name)) { + /* error message set by check_is_dir */ + return FALSE; + } + + pself->in_file = FALSE; + if (mode == ACCESS_WRITE) { promote_volume_lock(self); if (!clear_and_prepare_label(self, label, timestamp)) { + /* clear_and_prepare_label sets error status if necessary */ demote_volume_lock(self); return FALSE; } + + pself->volume_label = newstralloc(pself->volume_label, label); + pself->volume_time = newstralloc(pself->volume_time, timestamp); + + /* unset the VOLUME_UNLABELED flag, if it was set */ + device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS); + demote_volume_lock(self); + pself->access_mode = mode; + } else { + if (pself->volume_label == NULL && device_read_label(pself) != DEVICE_STATUS_SUCCESS) { + /* device_read_label already set our error message */ + return FALSE; + } else { + pself->access_mode = mode; + } } release_file(self); - if (parent_class->start) { - return parent_class->start(pself, mode, label, timestamp); - } else { - return TRUE; - } + return TRUE; +} + +static gboolean +vfs_device_finish (Device * pself) { + VfsDevice * self; + self = VFS_DEVICE(pself); + + if (device_in_error(self)) return FALSE; + + pself->access_mode = ACCESS_NULL; + return TRUE; } typedef struct { @@ -770,11 +859,10 @@ static gboolean get_last_file_number_functor(const char * filename, gpointer datap) { guint64 file; glfn_data * data = (glfn_data*)datap; - g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE); + file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */ if (file > G_MAXINT) { - g_fprintf(stderr, "Super-large device file %s found, ignoring.\n", - filename); + g_warning(_("Super-large device file %s found, ignoring"), filename); return TRUE; } /* This condition is needlessly complex due to sign issues. */ @@ -787,15 +875,18 @@ static gboolean get_last_file_number_functor(const char * filename, static gint get_last_file_number(VfsDevice * self) { glfn_data data; int count; + Device *d_self = DEVICE(self); data.self = self; data.rval = -1; - count = search_directory(self->dir_handle, "^[0-9]+\\.", - get_last_file_number_functor, &data); + count = search_vfs_directory(self, "^[0-9]+\\.", + get_last_file_number_functor, &data); if (count <= 0) { /* Somebody deleted something important while we weren't looking. */ - g_fprintf(stderr, "Error identifying VFS device contents!\n"); + device_set_error(d_self, + stralloc(_("Error identifying VFS device contents!")), + DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR); return -1; } else { g_assert(data.rval >= 0); @@ -815,11 +906,10 @@ static gboolean get_next_file_number_functor(const char * filename, gpointer datap) { guint file; gnfn_data * data = (gnfn_data*)datap; - g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE); + file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */ if (file > G_MAXINT) { - g_fprintf(stderr, "Super-large device file %s found, ignoring.\n", - filename); + g_warning(_("Super-large device file %s found, ignoring"), filename); return TRUE; } /* This condition is needlessly complex due to sign issues. */ @@ -835,16 +925,19 @@ static gboolean get_next_file_number_functor(const char * filename, static gint get_next_file_number(VfsDevice * self, guint request) { gnfn_data data; int count; + Device *d_self = DEVICE(self); data.self = self; data.request = request; data.best_found = -1; - count = search_directory(self->dir_handle, "^[0-9]+\\.", - get_next_file_number_functor, &data); + count = search_vfs_directory(self, "^[0-9]+\\.", + get_next_file_number_functor, &data); if (count <= 0) { /* Somebody deleted something important while we weren't looking. */ - g_fprintf(stderr, "Error identifying VFS device contents!\n"); + device_set_error(d_self, + stralloc(_("Error identifying VFS device contents!")), + DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR); return -1; } @@ -871,6 +964,9 @@ char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) { } } + /* record that we're at this filenum now */ + DEVICE(self)->file = fileno; + base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk, ji->dumplevel); sanitary_base = sanitise_filename(base); @@ -881,16 +977,21 @@ char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) { } static gboolean -vfs_device_start_file (Device * pself, const dumpfile_t * ji) { +vfs_device_start_file (Device * pself, dumpfile_t * ji) { VfsDevice * self; - self = VFS_DEVICE(pself); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (ji != NULL, FALSE); + + if (device_in_error(self)) return FALSE; + + /* set the blocksize in the header to 32k, since the VFS header is always + * 32k regardless of the block_size setting */ + ji->blocksize = 32768; if (self->volume_limit > 0 && self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) { - /* No more room. */ + device_set_error(pself, + stralloc(_("No space left on device")), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; } @@ -902,30 +1003,37 @@ vfs_device_start_file (Device * pself, const dumpfile_t * ji) { 5) Chain up. */ self->file_name = make_new_file_name(self, ji); - if (self->file_name == NULL) + if (self->file_name == NULL) { + device_set_error(pself, + stralloc(_("Could not create header filename")), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; + } self->open_file_fd = robust_open(self->file_name, O_CREAT | O_EXCL | O_RDWR, VFS_DEVICE_CREAT_MODE); if (self->open_file_fd < 0) { - g_fprintf(stderr, "Can't create file %s: %s\n", self->file_name, - strerror(errno)); + device_set_error(pself, + vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); release_file(self); return FALSE; } if (!write_amanda_header(self, ji)) { + /* write_amanda_header sets error status if necessary */ release_file(self); return FALSE; } + /* handle some accounting business */ self->volume_bytes += VFS_DEVICE_LABEL_SIZE; + pself->in_file = TRUE; + pself->block = 0; + /* make_new_file_name set pself->file for us */ - if (parent_class->start_file) { - parent_class->start_file(pself, ji); - } return TRUE; } @@ -933,16 +1041,13 @@ static gboolean vfs_device_finish_file (Device * pself) { VfsDevice * self; self = VFS_DEVICE(pself); - g_return_val_if_fail(self != NULL, FALSE); + + if (device_in_error(self)) return FALSE; release_file(self); - - if (parent_class->finish_file) { - return parent_class->finish_file(pself); - } else { - return TRUE; - } - g_assert_not_reached(); + + pself->in_file = FALSE; + return TRUE; } /* This function is used for two purposes, rather than one. In @@ -959,9 +1064,12 @@ vfs_device_seek_file (Device * pself, guint requested_file) { IoResult result; self = VFS_DEVICE(pself); - g_return_val_if_fail (self != NULL, NULL); + + if (device_in_error(self)) return NULL; pself->in_file = FALSE; + pself->is_eof = FALSE; + pself->block = 0; release_file(self); @@ -977,26 +1085,37 @@ vfs_device_seek_file (Device * pself, guint requested_file) { tmp_file_name = file_number_to_file_name(self, requested_file - 1); if (tmp_file_name != NULL) { free(tmp_file_name); + pself->file = requested_file; /* other attributes are already correct */ return make_tapeend_header(); } else { + device_set_error(pself, + stralloc(_("Attempt to read past tape-end file")), + DEVICE_STATUS_SUCCESS); return NULL; } } if (!open_lock(self, file, FALSE)) { + device_set_error(pself, + stralloc(_("could not acquire lock")), + DEVICE_STATUS_DEVICE_ERROR); return NULL; } self->file_name = file_number_to_file_name(self, file); if (self->file_name == NULL) { + device_set_error(pself, + vstrallocf(_("File %d not found"), file), + DEVICE_STATUS_VOLUME_ERROR); release_file(self); return NULL; } self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0); - if (self->open_file_fd <= 0) { - g_fprintf(stderr, "Couldn't open file %s: %s\n", self->file_name, - strerror(errno)); + if (self->open_file_fd < 0) { + device_set_error(pself, + vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); amfree(self->file_name); release_file(self); return NULL; @@ -1005,34 +1124,42 @@ vfs_device_seek_file (Device * pself, guint requested_file) { result = vfs_device_robust_read(self, header_buffer, &header_buffer_size); if (result != RESULT_SUCCESS) { - g_fprintf(stderr, "Problem reading Amanda header.\n"); + device_set_error(pself, + vstrallocf(_("Problem reading Amanda header: %s"), device_error(pself)), + DEVICE_STATUS_VOLUME_ERROR); release_file(self); return NULL; } - rval = malloc(sizeof(*rval)); + rval = g_new(dumpfile_t, 1); parse_file_header(header_buffer, rval, header_buffer_size); - if (file > 0) { - switch (rval->type) { + switch (rval->type) { case F_DUMPFILE: case F_CONT_DUMPFILE: case F_SPLIT_DUMPFILE: - /* Chain up. */ - if (parent_class->seek_file) { - parent_class->seek_file(pself, file); - } - return rval; + break; + + case F_TAPESTART: + /* file 0 should have a TAPESTART header; vfs_device_read_label + * uses this */ + if (requested_file == 0) + break; + /* FALLTHROUGH */ + default: + device_set_error(pself, + stralloc(_("Invalid amanda header while reading file header")), + DEVICE_STATUS_VOLUME_ERROR); amfree(rval); release_file(self); return NULL; - } - } else if (file == 0) { - return rval; - } else { - amfree(rval); - return NULL; } + + /* update our state */ + pself->in_file = TRUE; + pself->file = file; + + return rval; } static gboolean @@ -1041,89 +1168,30 @@ vfs_device_seek_block (Device * pself, guint64 block) { off_t result; self = VFS_DEVICE(pself); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (self->open_file_fd >= 0, FALSE); + + g_assert(self->open_file_fd >= 0); g_assert(sizeof(off_t) >= sizeof(guint64)); + if (device_in_error(self)) return FALSE; /* Pretty simple. We figure out the blocksize and use that. */ result = lseek(self->open_file_fd, - (block) * self->block_size + VFS_DEVICE_LABEL_SIZE, + (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE, SEEK_SET); - return (result != (off_t)(-1)); -} -static gboolean -vfs_device_property_get (Device * pself, DevicePropertyId ID, GValue * val) { - VfsDevice * self; - self = VFS_DEVICE(pself); - g_return_val_if_fail(self != NULL, FALSE); - if (ID == PROPERTY_BLOCK_SIZE) { - g_value_unset_init(val, G_TYPE_INT); - g_value_set_int(val, self->block_size); - return TRUE; - } else if (ID == PROPERTY_MAX_VOLUME_USAGE) { - g_value_unset_init(val, G_TYPE_UINT64); - g_value_set_uint64(val, self->volume_limit); - return TRUE; - } else if (ID == PROPERTY_FREE_SPACE) { - QualifiedSize qsize; - struct fs_usage fsusage; - guint64 bytes_avail; - - if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) { - if (fsusage.fsu_bavail_top_bit_set) - bytes_avail = 0; - else - bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize; - if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024) - bytes_avail = (guint64)self->volume_limit * 1024; - - qsize.accuracy = SIZE_ACCURACY_REAL; - qsize.bytes = bytes_avail; - } else { - g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno)); - qsize.accuracy = SIZE_ACCURACY_UNKNOWN; - qsize.bytes = 0; - } - g_value_unset_init(val, QUALIFIED_SIZE_TYPE); - g_value_set_boxed(val, &qsize); - return TRUE; - } else { - if (parent_class->property_get) { - return parent_class->property_get(pself, ID, val); - } else { - return FALSE; - } - } - g_assert_not_reached(); -} + pself->block = block; -static gboolean -vfs_device_property_set (Device * pself, DevicePropertyId ID, GValue * val) { - VfsDevice * self; - self = VFS_DEVICE(pself); - g_return_val_if_fail(self != NULL, FALSE); - if (ID == PROPERTY_BLOCK_SIZE) { - int block_size = g_value_get_int(val); - g_return_val_if_fail(block_size > 0, FALSE); - self->block_size = block_size; - return TRUE; - } else if (ID == PROPERTY_MAX_VOLUME_USAGE) { - self->volume_limit = g_value_get_uint64(val); - return TRUE; - } else { - if (parent_class->property_get) { - return parent_class->property_get(pself, ID, val); - } else { - return FALSE; - } + if (result == (off_t)(-1)) { + device_set_error(pself, + vstrallocf(_("Error seeking within file: %s"), strerror(errno)), + DEVICE_STATUS_DEVICE_ERROR); + return FALSE; } - g_assert_not_reached(); + + return TRUE; } static gboolean try_unlink(const char * file) { if (unlink(file) < 0) { - g_fprintf(stderr, "Can't unlink file %s: %s\n", file, strerror(errno)); return FALSE; } else { return TRUE; @@ -1137,8 +1205,8 @@ vfs_device_recycle_file (Device * pself, guint filenum) { off_t file_size; self = VFS_DEVICE(pself); - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(!(pself->in_file), FALSE); + + if (device_in_error(self)) return FALSE; /* Game Plan: * 1) Get a write lock on the file in question. @@ -1149,22 +1217,33 @@ vfs_device_recycle_file (Device * pself, guint filenum) { */ self->file_name = file_number_to_file_name(self, filenum); - - if (self->file_name == NULL) + if (self->file_name == NULL) { + device_set_error(pself, + vstrallocf(_("File %d not found"), filenum), + DEVICE_STATUS_VOLUME_ERROR); return FALSE; + } - if (!open_lock(self, filenum, TRUE)) + if (!open_lock(self, filenum, FALSE)) { + device_set_error(pself, + stralloc(_("could not acquire lock")), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; + } if (0 != stat(self->file_name, &file_status)) { - fprintf(stderr, "Cannot stat file %s (%s), so not removing.\n", - self->file_name, strerror(errno)); + device_set_error(pself, + vstrallocf(_("Cannot stat file %s (%s), so not removing"), + self->file_name, strerror(errno)), + DEVICE_STATUS_VOLUME_ERROR); return FALSE; } file_size = file_status.st_size; - if (!try_unlink(self->file_name) || - !try_unlink(self->file_lock_name)) { + if (!try_unlink(self->file_name)) { + device_set_error(pself, + vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)), + DEVICE_STATUS_VOLUME_ERROR); release_file(self); return FALSE; } @@ -1177,6 +1256,7 @@ vfs_device_recycle_file (Device * pself, guint filenum) { static IoResult vfs_device_robust_read(VfsDevice * self, char *buf, int *count) { int fd = self->open_file_fd; + Device *d_self = DEVICE(self); int want = *count, got = 0; while (got < want) { @@ -1207,9 +1287,11 @@ static IoResult vfs_device_robust_read(VfsDevice * self, char *buf, continue; } else { /* Error occured. */ - g_fprintf(stderr, "Error reading fd %d: %s\n", fd, strerror(errno)); + device_set_error(d_self, + vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)), + DEVICE_STATUS_VOLUME_ERROR); *count = got; - return -1; + return RESULT_ERROR; } } @@ -1220,6 +1302,7 @@ static IoResult vfs_device_robust_read(VfsDevice * self, char *buf, static IoResult vfs_device_robust_write(VfsDevice * self, char *buf, int count) { int fd = self->open_file_fd; + Device *d_self = DEVICE(self); int rval = 0; while (rval < count) { @@ -1250,12 +1333,15 @@ vfs_device_robust_write(VfsDevice * self, char *buf, int count) { #endif ) { /* We are definitely out of space. */ + device_set_error(d_self, + vstrallocf(_("No space left on device: %s"), strerror(errno)), + DEVICE_STATUS_VOLUME_ERROR); return RESULT_NO_SPACE; } else { /* Error occured. Note that here we handle EIO as an error. */ - g_fprintf(stderr, "Error writing device fd %d: %s\n", - fd, strerror(errno)); - + device_set_error(d_self, + vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)), + DEVICE_STATUS_VOLUME_ERROR); return RESULT_ERROR; } }