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

📄 taper-file-source.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 2006 Zmanda Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#define selfp (self->_priv)#include "taper-file-source.h"#include "fileheader.h"#include "holding.h"#define HOLDING_DISK_OPEN_FLAGS (O_NOCTTY | O_RDONLY)struct _TaperFileSourcePrivate {    /* How many bytes have we written from the current part? */    guint64 current_part_pos;    /* Information about the files at the start of this part. */    dumpfile_t part_start_chunk_header;    int part_start_chunk_fd;    /* Where is the start of this part with respect to the first chunk       of the part? */    guint64 part_start_chunk_offset;    /* These may be the same as their part_start_chunk_ counterparts. */    dumpfile_t current_chunk_header;    int current_chunk_fd;    /* Current position of current_chunk_fd. */    guint64 current_chunk_position;    /* Expected number of split parts. */    int predicted_splits;};/* here are local prototypes */static void taper_file_source_init (TaperFileSource * o);static void taper_file_source_class_init (TaperFileSourceClass * c);static ssize_t taper_file_source_read (TaperSource * pself, void * buf,                                            size_t count);static gboolean taper_file_source_seek_to_part_start (TaperSource * pself);static void taper_file_source_start_new_part (TaperSource * pself);static int taper_file_source_predict_parts(TaperSource * pself);static dumpfile_t * taper_file_source_get_first_header(TaperSource * pself);static gboolean first_time_setup(TaperFileSource * self);/* pointer to the class of our parent */static TaperSourceClass *parent_class = NULL;GType taper_file_source_get_type (void) {    static GType type = 0;        if G_UNLIKELY(type == 0) {        static const GTypeInfo info = {            sizeof (TaperFileSourceClass),            (GBaseInitFunc) NULL,            (GBaseFinalizeFunc) NULL,            (GClassInitFunc) taper_file_source_class_init,            (GClassFinalizeFunc) NULL,            NULL /* class_data */,            sizeof (TaperFileSource),            0 /* n_preallocs */,            (GInstanceInitFunc) taper_file_source_init,            NULL        };                type = g_type_register_static (TAPER_TYPE_SOURCE, "TaperFileSource",                                       &info, (GTypeFlags)0);    }        return type;}static voidtaper_file_source_finalize(GObject *obj_self){    TaperFileSource *self = TAPER_FILE_SOURCE (obj_self);    gpointer priv G_GNUC_UNUSED = self->_priv;    if(G_OBJECT_CLASS(parent_class)->finalize)        (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);    if(self->_priv->part_start_chunk_fd >= 0) {        close (self->_priv->part_start_chunk_fd);    }    if(self->_priv->current_chunk_fd >= 0) {        close (self->_priv->current_chunk_fd);    }}static void taper_file_source_init (TaperFileSource * o G_GNUC_UNUSED){    o->_priv = malloc(sizeof(TaperFileSourcePrivate));    o->_priv->part_start_chunk_fd = -1;    o->_priv->current_chunk_fd = -1;    o->_priv->predicted_splits = -1;    o->holding_disk_file = NULL;}static void  taper_file_source_class_init (TaperFileSourceClass * c) {    GObjectClass *g_object_class = (GObjectClass*) c;    TaperSourceClass *taper_source_class = (TaperSourceClass *)c;    parent_class = g_type_class_ref (TAPER_TYPE_SOURCE);    taper_source_class->read = taper_file_source_read;    taper_source_class->seek_to_part_start =        taper_file_source_seek_to_part_start;    taper_source_class->start_new_part = taper_file_source_start_new_part;    taper_source_class->get_first_header = taper_file_source_get_first_header;    taper_source_class->predict_parts = taper_file_source_predict_parts;    g_object_class->finalize = taper_file_source_finalize;}static void compute_splits(TaperFileSource * self) {    guint64 total_kb;    int predicted_splits;    TaperSource * pself = (TaperSource*)self;    if (selfp->predicted_splits > 0) {        return;    }    if (pself->max_part_size <= 0) {        selfp->predicted_splits = 1;        return;    }    total_kb = holding_file_size(self->holding_disk_file, TRUE);    if (total_kb <= 0) {        g_fprintf(stderr, "taper: %lld KB holding file makes no sense, not precalculating splits\n",		(long long)total_kb);        fflush(stderr);        selfp->predicted_splits = -1;        return;    }        g_fprintf(stderr, "taper: Total dump size should be %jukb, part size is %jukb\n",            (uintmax_t)total_kb, (uintmax_t)pself->max_part_size);    predicted_splits = (total_kb * 1024) / pself->max_part_size;    if (predicted_splits == 0 ||        (0 != ((total_kb * 1024) % pself->max_part_size))) {        predicted_splits ++;    }    selfp->predicted_splits = predicted_splits;}static int taper_file_source_predict_parts(TaperSource * pself) {    TaperFileSource * self = TAPER_FILE_SOURCE(pself);    g_return_val_if_fail(self != NULL, -1);    compute_splits(self);    return selfp->predicted_splits;}static dumpfile_t * taper_file_source_get_first_header(TaperSource * pself) {    TaperFileSource * self = TAPER_FILE_SOURCE(pself);    g_return_val_if_fail(self != NULL, NULL);    first_time_setup(self);    if (parent_class->get_first_header) {        return (parent_class->get_first_header)(pself);    } else {        return NULL;    }}/* Open a holding disk and parse the header. Returns TRUE if   everything went OK. Writes the fd into fd_pointer and the header   into header_pointer. Both must be non-NULL. */static gboolean open_holding_file(char * filename, int * fd_pointer,                                  dumpfile_t * header_pointer) {    int fd;    int read_result;    char * header_buffer;    g_return_val_if_fail(filename != NULL, FALSE);    g_return_val_if_fail(fd_pointer != NULL, FALSE);    g_return_val_if_fail(header_pointer != NULL, FALSE);    fd = robust_open(filename, O_NOCTTY | O_RDONLY, 0);    if (fd < 0) {        g_fprintf(stderr, "Could not open holding disk file %s: %s\n",                filename, strerror(errno));        return FALSE;    }    header_buffer = malloc(DISK_BLOCK_BYTES);    read_result = fullread(fd, header_buffer, DISK_BLOCK_BYTES);    if (read_result < DISK_BLOCK_BYTES) {        g_fprintf(stderr,                "Could not read header from holding disk file %s: %s\n",                filename, strerror(errno));        aclose(fd);        return FALSE;    }        parse_file_header(header_buffer, header_pointer, DISK_BLOCK_BYTES);    amfree(header_buffer);        if (!(header_pointer->type == F_DUMPFILE ||          header_pointer->type == F_CONT_DUMPFILE)) {        g_fprintf(stderr, "Got strange header from file %s.\n",                filename);        aclose(fd);        return FALSE;    }        *fd_pointer = fd;    return TRUE;}/* Copy fd and header information from first chunk fields to current   chunk. Returns FALSE if an error occurs (unlikely). */static gboolean copy_chunk_data(int * from_fd, int* to_fd,                                dumpfile_t * from_header,                                dumpfile_t * to_header) {    g_return_val_if_fail(from_fd != NULL, FALSE);    g_return_val_if_fail(to_fd != NULL, FALSE);    g_return_val_if_fail(from_header != NULL, FALSE);    g_return_val_if_fail(to_header != NULL, FALSE);    g_return_val_if_fail(*to_fd < 0, FALSE);        *to_fd = dup(*from_fd);    if (*to_fd < 0) {        g_fprintf(stderr, "dup(%d) failed!\n", *from_fd);        return FALSE;    }    memcpy(to_header, from_header, sizeof(*to_header));    return TRUE;}static gboolean first_time_setup(TaperFileSource * self) {    TaperSource * pself = (TaperSource*)self;    if (selfp->part_start_chunk_fd >= 0) {        return TRUE;    }    g_return_val_if_fail(self->holding_disk_file != NULL, FALSE);    if (!open_holding_file(self->holding_disk_file,                            &(selfp->part_start_chunk_fd),                           &(selfp->part_start_chunk_header))) {        return FALSE;    }    /* We are all set; just copy the "start chunk" datums into the       "current chunk" fields. */    if (!copy_chunk_data(&(selfp->part_start_chunk_fd),                         &(selfp->current_chunk_fd),                         &(selfp->part_start_chunk_header),                         &(selfp->current_chunk_header))) {        aclose(selfp->part_start_chunk_fd);        return FALSE;    }    pself->first_header = g_memdup(&(selfp->part_start_chunk_header),                                   sizeof(dumpfile_t));    /* Should not be necessary. You never know! */    selfp->current_part_pos = selfp->part_start_chunk_offset =        selfp->current_chunk_position = 0;    return TRUE;}static int retry_read(int fd, void * buf, size_t count) {    for (;;) {        int read_result = read(fd, buf, count);        if (read_result < 0 && (0#ifdef EAGAIN                                || errno == EAGAIN#endif#ifdef EWOULDBLOCK                                || errno == EWOULDBLOCK#endif#ifdef EINTR                                || errno == EINTR#endif                  )) {            /* Try again. */            continue;        } else {            if (read_result < 0) {                g_fprintf(stderr, "Error reading holding disk: %s\n",                        strerror(errno));            }            return read_result;        }    }}/* If another chunk is available, load it. Returns TRUE if there are   no more chunks or the next chunk is loaded, or FALSE if an error   occurs. */static gboolean get_next_chunk(TaperFileSource * self) {    char * cont_filename = NULL;    if (selfp->current_chunk_header.cont_filename[0] != '\0') {        cont_filename =            g_strdup(selfp->current_chunk_header.cont_filename);    } else {        /* No more data. */        aclose(selfp->current_chunk_fd);        bzero(&(selfp->current_chunk_header),              sizeof(selfp->current_chunk_header));        return TRUE;    }    /* More data. */    aclose(selfp->current_chunk_fd);    if (!open_holding_file(cont_filename,                           &(selfp->current_chunk_fd),                           &(selfp->current_chunk_header))) {        amfree(cont_filename);        bzero(&(selfp->current_chunk_header),              sizeof(selfp->current_chunk_header));        aclose(selfp->current_chunk_fd);        return FALSE;    }    amfree(cont_filename);    selfp->current_chunk_position = 0;    return TRUE;}static ssize_t taper_file_source_read (TaperSource * pself, void * buf, size_t count) {    TaperFileSource * self = (TaperFileSource*) pself;    int read_result;    g_return_val_if_fail (self != NULL, -1);    g_return_val_if_fail (TAPER_IS_FILE_SOURCE (self), -1);    g_return_val_if_fail (buf != NULL, -1);    g_return_val_if_fail (count > 0, -1);        if (!first_time_setup(self))        return -1;    if (pself->max_part_size > 0) {        count = MIN(count, pself->max_part_size - selfp->current_part_pos);    }    if (count <= 0) {        /* Was positive before. Thus we are at EOP. */        pself->end_of_part = TRUE;        return 0;    }    /* We don't use fullread, because we would rather return a partial     * read ASAP. */    read_result = retry_read(selfp->current_chunk_fd, buf, count);    if (read_result < 0) {        /* Nothing we can do. */        return read_result;    } else if (read_result == 0) {        if (!get_next_chunk(self)) {            return -1;         }        if (selfp->current_chunk_fd >= 0) {            /* Try again with the next chunk. */            return taper_file_source_read(pself, buf, count);        } else {            pself->end_of_data = TRUE;            return 0;        }    } else {        /* Success. */        selfp->current_part_pos += read_result;        selfp->current_chunk_position += read_result;        return read_result;    }}static gboolean taper_file_source_seek_to_part_start (TaperSource * pself) {    TaperFileSource * self = (TaperFileSource*)pself;    off_t lseek_result;    g_return_val_if_fail (self != NULL, FALSE);    g_return_val_if_fail (TAPER_IS_FILE_SOURCE (self), FALSE);    aclose(selfp->current_chunk_fd);    if (!copy_chunk_data(&(selfp->part_start_chunk_fd),                         &(selfp->current_chunk_fd),                         &(selfp->part_start_chunk_header),                         &(selfp->current_chunk_header))) {        return FALSE;    }    selfp->current_chunk_position = selfp->part_start_chunk_offset;    lseek_result = lseek(selfp->current_chunk_fd,                         DISK_BLOCK_BYTES + selfp->current_chunk_position,                         SEEK_SET);    if (lseek_result < 0) {        g_fprintf(stderr, "Could not seek holding disk file: %s\n",                strerror(errno));        return FALSE;    }    selfp->current_part_pos = 0;    if (parent_class->seek_to_part_start)        return parent_class->seek_to_part_start(pself);    else        return TRUE;}static void taper_file_source_start_new_part (TaperSource * pself) {    TaperFileSource * self = (TaperFileSource*)pself;    g_return_if_fail (self != NULL);    g_return_if_fail (TAPER_IS_FILE_SOURCE (self));    aclose(selfp->part_start_chunk_fd);    if (!copy_chunk_data(&(selfp->current_chunk_fd),                         &(selfp->part_start_chunk_fd),                         &(selfp->current_chunk_header),                         &(selfp->part_start_chunk_header))) {        /* We can't return FALSE. :-( Instead, we set things up so           they will fail on the next read(). */        aclose(selfp->current_chunk_fd);        aclose(selfp->part_start_chunk_fd);        return;    }    selfp->part_start_chunk_offset = selfp->current_chunk_position;    selfp->current_part_pos = 0;    if (parent_class->start_new_part)        parent_class->start_new_part(pself);}    

⌨️ 快捷键说明

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