⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfs-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2005 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  * published by the Free Software Foundation. *  * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public * License for more details. *  * You should have received a copy of the GNU Lesser General Public License * 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 */#include <string.h> /* memset() */#include "vfs-device.h"#include "fsusage.h"#include "amanda.h"#include "util.h"#include <regex.h>/* 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. */#define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"/* The name of the volume lockfile. Should be the same as that   generated by lockfile_name(0). */#define VOLUME_LOCKFILE_NAME "00000-lock"/* Possible (abstracted) results from a system I/O operation. */typedef enum {    RESULT_SUCCESS,    RESULT_ERROR,        /* Undefined error. */    RESULT_NO_DATA,      /* End of File, while reading */    RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if                            it was this or I/O error, but this is the                            preferred explanation. */    RESULT_MAX} IoResult;/* here are local prototypes */static void vfs_device_init (VfsDevice * o);static void vfs_device_class_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_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 int vfs_device_read_block(Device * self, gpointer data, int * size_req);static IoResult vfs_device_robust_write(VfsDevice * self,  char *buf,                                              int count);static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,                                             int *count);/* Various helper functions. */static void release_file(VfsDevice * self);static gboolean check_is_dir(const char * name, gboolean printmsg);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 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 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 gint get_last_file_number(VfsDevice * self);static gboolean get_last_file_number_functor(const char * filename,                                             gpointer datap);static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);static gboolean try_unlink(const char * file);/* pointer to the classes of our parents */static DeviceClass *parent_class = NULL;void vfs_device_register(void) {    static const char * device_prefix_list[] = { "file", NULL };    register_device(vfs_device_factory, device_prefix_list);}GTypevfs_device_get_type (void){    static GType type = 0;    if G_UNLIKELY(type == 0) {        static const GTypeInfo info = {            sizeof (VfsDeviceClass),            (GBaseInitFunc) NULL,            (GBaseFinalizeFunc) NULL,            (GClassInitFunc) vfs_device_class_init,            (GClassFinalizeFunc) NULL,            NULL /* class_data */,            sizeof (VfsDevice),            0 /* n_preallocs */,            (GInstanceInitFunc) vfs_device_init,            NULL        };        type = g_type_register_static (TYPE_DEVICE, "VfsDevice",                                       &info, (GTypeFlags)0);    }        return type;}static void vfs_device_init (VfsDevice * self) {    Device * o;    DeviceProperty prop;    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->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);    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);    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_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);    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);    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);    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){    GObjectClass *g_object_class = (GObjectClass*) c;    DeviceClass *device_class = (DeviceClass *)c;    parent_class = g_type_class_ref(TYPE_DEVICE);    device_class->open_device = vfs_device_open_device;    device_class->start = vfs_device_start;    device_class->start_file = vfs_device_start_file;    device_class->read_label = vfs_device_read_label;    device_class->write_block = vfs_device_write_block;    device_class->read_block = vfs_device_read_block;    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;    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 release_file(VfsDevice * self) {    /* Doesn't hurt. */    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;}static void vfs_device_finalize(GObject * obj_self) {    VfsDevice *self = VFS_DEVICE (obj_self);    Device * d_self = (Device*)self;    if (d_self->access_mode != ACCESS_NULL) {        device_finish(d_self);    }    if(G_OBJECT_CLASS(parent_class)->finalize)        (* G_OBJECT_CLASS(parent_class)->finalize)(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) {    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;    }}static gboolean check_is_dir(const char * name, gboolean printmsg) {    struct stat dir_status;        if (stat(name, &dir_status) < 0) {#ifdef EINTR        if (errno == EINTR) {            return check_is_dir(name, printmsg);        }#endif /* EINTR */        if (printmsg) {            g_fprintf(stderr, "Error checking directory %s: %s\n",                    name, strerror(errno));        }        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);        }        return FALSE;    } else {        return TRUE;    }}typedef struct {    VfsDevice * self;    int count;    char * result;} fnfn_data;/* A SearchDirectoryFunctor. */static gboolean file_number_to_file_name_functor(const char * filename,                                                 gpointer datap) {    char * result_tmp;    struct stat file_status;    fnfn_data *data = (fnfn_data*)datap;        result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);            /* 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));    } else if (!S_ISREG(file_status.st_mode)) {        g_fprintf(stderr, "%s is not a regular file, ignoring it.\n",                result_tmp);    } else {        data->count ++;        if (data->result == NULL) {            data->result = result_tmp;            result_tmp = NULL;        }    }    amfree(result_tmp);    return TRUE;}/* This function finds the filename for a given file number. We search * for a filesystem file matching the regex /^0*$device_file\./; if * there is more than one such file we make a warning and take an * arbitrary one. */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);    amfree(regex);    if (data.count == 0) {        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",                device_file, data.result);        return data.result;    } else {        g_assert(data.result != NULL);        return data.result;    }    g_assert_not_reached();}/* This function returns the dynamically-allocated lockfile name for a   given file number. *//*static char * lockfile_name(VfsDevice * self, guint number) {    return g_strdup_printf("%s/%05d-lock", self->dir_name, number);}*//* Does what you expect. If the lock already exists, it is released * and regained, in case the mode is changing. * The file field has several options: * - file > 0: Open a lock on a real volume file. * - file = 0: Open the volume lock as a volume file (for setup). * - file < 0: Open the volume lock as a volume lock (persistantly). */static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,			  G_GNUC_UNUSED int file,			  G_GNUC_UNUSED gboolean exclusive) {    /* 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -