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

📄 vfs-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 demote_volume_lock(VfsDevice * self) {    amfunlock(self->volume_lock_fd, self->volume_lock_name);    amroflock(self->volume_lock_fd, self->volume_lock_name);}/* A SearchDirectoryFunctor */static gboolean update_volume_size_functor(const char * filename,                                           gpointer user_data) {    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));        amfree(full_filename);        return TRUE;    }    amfree(full_filename);    self->volume_bytes += stat_buf.st_size;    return TRUE;}static void update_volume_size(VfsDevice * self) {    self->volume_bytes = 0;    search_directory(self->dir_handle, "^[0-9]+\\.",                     update_volume_size_functor, self);}static gboolean vfs_device_open_device (Device * pself, char * device_name) {    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);    /* 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);    if (parent_class->open_device) {        /* Will call vfs_device_read_label. */        return (parent_class->open_device)(pself, device_name);    } else {        return TRUE;    }}/* A SearchDirectoryFunctor */static gboolean delete_vfs_files_functor(const char * filename,                                         gpointer user_data) {    VfsDevice * self;    char * path_name;    self = VFS_DEVICE(user_data);    g_return_val_if_fail(self != NULL, FALSE);    /* Skip the volume lock. */    if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)        return TRUE;    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));    }    amfree(path_name);    return TRUE;}/* delete_vfs_files deletes all VfsDevice files in the directory except the   volume lockfile. */static gboolean 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;}/* This is a functor suitable for search_directory. It simply prints a   warning. It also dodges the volume lockfile. */static gboolean check_dir_empty_functor(const char * filename,                                        gpointer user_data) {    VfsDevice * self;    char * path_name;    self = VFS_DEVICE(user_data);    g_return_val_if_fail(self != NULL, FALSE);    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);    amfree(path_name);    return TRUE;}/* This function is used to write volume and dump headers. */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);    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");        return FALSE;    }    result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);    amfree(label_buffer);    return (result == RESULT_SUCCESS);}/* clear_and_label will erase the contents of the directory, and write * this label in its place. This function assumes we already have a volume * label write lock in place (e.g., promote_lock() has been called.) */static gboolean clear_and_prepare_label(VfsDevice * self, char * label,                                        char * timestamp) {    dumpfile_t * label_header;    release_file(self);    /* Delete any extant data, except our volume lock. */    if (!delete_vfs_files(self)) {        return FALSE;    }    /* Print warnings about any remaining files. */    search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX,                     check_dir_empty_functor, self);    self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);    self->open_file_fd = robust_open(self->file_name,                                     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));        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 {        amfree(label_header);        return FALSE;    }}static ReadLabelStatusFlags 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);    amanda_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);    }    if (amanda_header->type != F_TAPESTART) {        /* This is an error, and should not happen. */        g_fprintf(stderr, "Got a bad volume label\n");        amfree(amanda_header);        return READ_LABEL_STATUS_VOLUME_ERROR;    }    dself->volume_label = g_strdup(amanda_header->name);    dself->volume_time = g_strdup(amanda_header->datestamp);    amfree(amanda_header);    update_volume_size(self);    if (parent_class->read_label) {        return (parent_class->read_label)(dself);    } else {        return READ_LABEL_STATUS_SUCCESS;    }}static gboolean vfs_device_write_block(Device * pself, guint size,                                       gpointer data, gboolean last_block) {    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);    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;        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 {        return FALSE;    }}static intvfs_device_read_block(Device * pself, gpointer data, int * size_req) {    VfsDevice * self;    int size;    IoResult result;        self = VFS_DEVICE(pself);    g_return_val_if_fail (self != NULL, -1);    if (data == NULL || *size_req < self->block_size) {        /* Just a size query. */        *size_req = self->block_size;        return 0;    }    size = self->block_size;    result = vfs_device_robust_read(self, data, &size);    switch (result) {    case RESULT_SUCCESS:        *size_req = size;        return size;    case RESULT_NO_DATA:        pself->is_eof = TRUE;        /* FALLTHROUGH */    default:        return -1;    }    g_assert_not_reached();}static gboolean	vfs_device_start(Device * pself,                                 DeviceAccessMode mode, char * label,                                 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 (mode == ACCESS_WRITE) {        promote_volume_lock(self);        if (!clear_and_prepare_label(self, label, timestamp)) {            demote_volume_lock(self);            return FALSE;        }        demote_volume_lock(self);    }    release_file(self);     if (parent_class->start) {        return parent_class->start(pself, mode, label, timestamp);    } else {        return TRUE;    }}typedef struct {    VfsDevice * self;    int rval;} glfn_data;/* A SearchDirectoryFunctor. */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);        return TRUE;    }    /* This condition is needlessly complex due to sign issues. */    if (data->rval < 0 || ((guint)data->rval) < file) {        data->rval = file;    }    return TRUE;}static gint get_last_file_number(VfsDevice * self) {    glfn_data data;    int count;    data.self = self;    data.rval = -1;        count = search_directory(self->dir_handle, "^[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");        return -1;    } else {        g_assert(data.rval >= 0);    }        return data.rval;}typedef struct {    VfsDevice * self;    guint request;    int best_found;} gnfn_data;/* A SearchDirectoryFunctor. */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);        return TRUE;    }    /* This condition is needlessly complex due to sign issues. */    if (file >= data->request &&        (data->best_found < 0 || file < (guint)data->best_found)) {        data->best_found = file;    }    return TRUE;}/* Returns the file number equal to or greater than the given requested * file number. */static gint get_next_file_number(VfsDevice * self, guint request) {    gnfn_data data;    int count;    data.self = self;    data.request = request;    data.best_found = -1;        count = search_directory(self->dir_handle, "^[0-9]+\\.",                             get_next_file_number_functor, &data);

⌨️ 快捷键说明

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