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

📄 tape-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
            self->bsf_after_eom = feature_request_flags;            return TRUE;        } else {            return FALSE;        }    } else if (id == PROPERTY_BSF_AFTER_EOM) {        /* You can only set this if EOM is enabled. */        if (self->bsf | FEATURE_STATUS_DISABLED)            return FALSE;        else            return try_set_feature(d_self->access_mode,                                   feature_request_flags,                                   &(self->bsf_after_eom));    } else if (id == PROPERTY_FINAL_FILEMARKS) {        guint request = g_value_get_uint(val);        if (request == 1 || request == 2) {            self->final_filemarks = request;            return TRUE;        } else {            return FALSE;        }    } else {        /* Chain up */        if (parent_class->property_set) {            return (parent_class->property_set)(d_self, id, val);        } else {            return FALSE;        }    }    g_assert_not_reached();}static gboolean tape_device_finish (Device * d_self) {    TapeDevice * self;    self = TAPE_DEVICE(d_self);    g_return_val_if_fail(self != NULL, FALSE);    /* Polish off this file, if relevant. */    if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {        if (!device_finish_file(d_self))            return FALSE;    }    /* Write an extra filemark, if needed. The OS will give us one for       sure. */    if (self->final_filemarks > 1 &&        IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {        if (!tape_weof(self->fd, 1)) {            g_fprintf(stderr, "Error writing final filemark: %s\n",                    strerror(errno));            return FALSE;        }    }    /* Rewind. */    if (!tape_rewind(self->fd)) {        g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));        return FALSE;    }    d_self->access_mode = ACCESS_NULL;    if (parent_class->finish) {        return (parent_class->finish)(d_self);    } else {        return TRUE;    }}/* Works just like read(), except for the following: * 1) Retries on EINTR & friends. * 2) Stores count in parameter, not return value. * 3) Provides explicit return result. */static IoResulttape_device_robust_read (TapeDevice * self, void * buf, int * count) {    Device * d_self;    int result;    d_self = (Device*)self;    g_return_val_if_fail(self != NULL, RESULT_ERROR);    g_return_val_if_fail(*count >= 0, RESULT_ERROR);    /* Callers should ensure this. */    g_assert((guint)(*count) <= self->read_block_size);    for (;;) {        result = read(self->fd, buf, *count);        if (result > 0) {            /* Success. By definition, we read a full block. */            *count = result;            return RESULT_SUCCESS;        } else if (result == 0) {            return RESULT_NO_DATA;        } else {            if (0#ifdef EAGAIN                || errno == EAGAIN#endif#ifdef EWOULDBLOCK                || errno == EWOULDBLOCK#endif#ifdef EINTR                || errno == EINTR#endif                ) {                /* Interrupted system call */                continue;            } else if ((self->fixed_block_size == 0) &&                       (0#ifdef ENOMEM                        || errno == ENOMEM /* bad user-space buffer */#endif#ifdef EOVERFLOW                        || errno == EOVERFLOW /* bad kernel-space buffer */#endif#ifdef EINVAL                        || errno == EINVAL /* ??? */#endif                        )) {                /* Buffer too small. */                return RESULT_SMALL_BUFFER;            } else {                g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",                        *count, d_self->device_name, strerror(errno));                return RESULT_ERROR;            }        }    }    g_assert_not_reached();}/* Kernel workaround: If needed, poke the kernel so it doesn't fail.   at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS   is not defined. */static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,                           int count G_GNUC_UNUSED) {#ifdef NEED_RESETOFS    int result;    self->private->write_count += count;    if (self->private->write_count < RESETOFS_THRESHOLD) {        return;    }    result = lseek(self->fd, 0, SEEK_SET);    if (result < 0) {        g_fprintf(stderr,                "Warning: lseek() failed during kernel 2GB workaround.\n");    }#endif}static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count) {    Device * d_self;    int result;    g_return_val_if_fail(self != NULL, RESULT_ERROR);    d_self = (Device*)self;        check_resetofs(self, count);    for (;;) {        result = write(self->fd, buf, count);        if (result == count) {            /* Success. */            self->private->write_count ++;            return RESULT_SUCCESS;        } else if (result >= 0) {            /* write() returned a short count. This should not happen. */            g_fprintf(stderr,                  "Mysterious short write on tape device: Tried %d, got %d.\n",                    count, result);            return RESULT_ERROR;        } else if (0#ifdef EAGAIN                   || errno == EAGAIN#endif#ifdef EWOULDBLOCK                   || errno == EWOULDBLOCK#endif#ifdef EINTR                   || errno == EINTR#endif                   ) {                /* Interrupted system call */            continue;        } else if (0#ifdef ENOSPC                   || errno == ENOSPC#endif#ifdef EIO                   || errno == EIO#endif                   ) {            /* Probably EOT. Print a message if we got EIO. */#ifdef EIO            if (errno == EIO) {                g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",                        d_self->device_name);            }#endif            return RESULT_NO_SPACE;        } else {            /* WTF */            g_fprintf(stderr,     "Kernel gave unexpected write() result of \"%s\" on device %s.\n",                    strerror(errno), d_self->device_name);            return RESULT_ERROR;        }    }    g_assert_not_reached();}/* Reads some number of tape blocks into the bit-bucket. If the count   is negative, then we read the rest of the entire file. Returns the   number of blocks read, or -1 if an error occured. If we encounter   EOF (as opposed to some other error) we return the number of blocks   actually read. */static int drain_tape_blocks(TapeDevice * self, int count) {    char * buffer;    int buffer_size;    int i;    buffer_size = self->read_block_size;    buffer = malloc(sizeof(buffer_size));    for (i = 0; i < count || count < 0;) {        int result;        result = read(self->fd, buffer, buffer_size);        if (result > 0) {            i ++;            continue;        } else if (result == 0) {            free(buffer);            return i;        } else {            /* First check for interrupted system call. */            if (0#ifdef EAGAIN                || errno == EAGAIN#endif#ifdef EWOULDBLOCK                || errno == EWOULDBLOCK#endif#ifdef EINTR                || errno == EINTR#endif                ) {                /* Interrupted system call */                continue;            } else if (0#ifdef ENOSPC                       || errno == ENOSPC /* bad user-space buffer */#endif#ifdef EOVERFLOW                       || errno == EOVERFLOW /* bad kernel-space buffer */#endif#ifdef EINVAL                       || errno == EINVAL /* ??? */#endif                       ) {                /* The buffer may not be big enough. But the OS is not                   100% clear. We double the buffer and try again, but                   in no case allow a buffer bigger than 32 MB. */                buffer_size *= 2;                if (buffer_size > 32*1024*1024) {                    free(buffer);                    return -1;                } else {                    buffer = realloc(buffer, buffer_size);                    continue;                }            }        }    }        return count;}/* FIXME: Make sure that there are no cycles in reimplementation   dependencies. */static gboolean tape_device_fsf (TapeDevice * self, guint count) {    g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);        if (self->fsf & FEATURE_STATUS_ENABLED) {        return tape_fsf(self->fd, count);    } else {        guint i;        for (i = 0; i < count; i ++) {            if (drain_tape_blocks(self, -1) < 0)                return FALSE;        }        return TRUE;    }}/* Seek back over count + 1 filemarks to the start of the given file. */static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file) {    g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);    if (self->bsf & FEATURE_STATUS_ENABLED) {        /* The BSF operation is not very smart; it includes the           filemark of the present file as part of the count, and seeks           to the wrong (BOT) side of the filemark. We compensate for           this by seeking one filemark too many, then FSFing back over           it.           If this procedure fails for some reason, we can still try           the backup plan. */        if (tape_bsf(self->fd, count + 1) &&            tape_device_fsf(self, 1))            return TRUE;    } /* Fall through to backup plan. */    /* We rewind the tape, then seek forward the given number of       files. */    if (!tape_rewind(self->fd))        return FALSE;    return tape_device_fsf(self, file);}static gboolean tape_device_fsr (TapeDevice * self, guint count) {    g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);    if (self->fsr & FEATURE_STATUS_ENABLED) {        return tape_fsr(self->fd, count);    } else {        int result = drain_tape_blocks(self, count);        return result > 0 && (int)count == result;    }}/* Seek back the given number of blocks to block number block within * the current file, numbered file. */static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {    g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);        g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);    if (self->bsr & FEATURE_STATUS_ENABLED) {        return tape_bsr(self->fd, count);    } else {        /* We BSF, then FSR. */        if (!tape_device_bsf(self, 0, file))            return FALSE;                return tape_device_fsr(self, block);    }    g_assert_not_reached();}/* Go to the right place to write more data, and update the file   number if possible. */static gboolean tape_device_eod (TapeDevice * self) {    Device * d_self;    g_return_val_if_fail (self != NULL, (gboolean )0);    g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);    d_self = (Device*)self;    if (self->eom & FEATURE_STATUS_ENABLED) {        int result;        result = tape_eod(self->fd);         if (result == TAPE_OP_ERROR) {            return FALSE;        } else if (result == TAPE_POSITION_UNKNOWN) {            d_self->file = -1;        } else {            /* We drop by 1 because Device will increment the first               time the user does start_file. */            d_self->file = result - 1;        }        return TRUE;    } else {        int count = 0;        if (!tape_rewind(self->fd))            return FALSE;                for (;;) {            /* We alternately read a block and FSF. If the read is               successful, then we are not there yet and should FSF               again. */            int result;            result = drain_tape_blocks(self, 1);            if (result == 1) {                /* More data, FSF. */                tape_device_fsf(self, 1);                count ++;            } else if (result == 0) {                /* Finished. */                d_self->file = count;                return TRUE;            } else {                return FALSE;            }        }    }}Device *tape_device_factory (char * device_type, char * device_name) {    Device * rval;    g_assert(0 == strcmp(device_type, "tape"));    rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));    if (!device_open_device(rval, device_name)) {        g_object_unref(rval);        return NULL;    } else {        return rval;    }}

⌨️ 快捷键说明

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