producer_result_t device_read_producer(gpointer devicep, queue_buffer_t *buffer, size_t hint_size G_GNUC_UNUSED) { Device* device; device = (Device*) devicep; g_assert(IS_DEVICE(device)); buffer->offset = 0; for (;;) { int result, read_size; read_size = buffer->alloc_size; result = device_read_block(device, buffer->data, &read_size); if (result > 0) { buffer->data_size = read_size; return PRODUCER_MORE; } else if (result == 0) { /* unfortunately, the best "memory" we have of needing a larger * block size is the next time this buffer comes around, and even * this is incomplete as buffers may be resized periodically. So * we'll end up calling read_block with small buffers more often * than strictly necessary. */ buffer->data = realloc(buffer->data, read_size); buffer->alloc_size = read_size; } else if (device->is_eof) { return PRODUCER_FINISHED; } else { buffer->data_size = 0; return PRODUCER_ERROR; } } }
static gpointer pull_buffer_impl( XferElement *elt, size_t *size) { XferSourceDevice *self = (XferSourceDevice *)elt; gpointer buf = NULL; int result; int devsize; int max_block; /* indicate EOF on an cancel */ if (elt->cancelled) { *size = 0; return NULL; } /* get the device block size */ if (self->block_size == 0) { self->block_size = self->device->block_size; } do { buf = g_try_malloc(self->block_size); if (buf == NULL) { xfer_cancel_with_error(elt, _("%s: cannot allocate memory"), self->device->device_name); wait_until_xfer_cancelled(elt->xfer); return NULL; } devsize = (int)self->block_size; if (elt->size < 0) max_block = -1; else max_block = (elt->size+self->block_size-1)/self->block_size; result = device_read_block(self->device, buf, &devsize, max_block); *size = devsize; /* if the buffer was too small, loop around again */ if (result == 0) { g_assert(*size > self->block_size); self->block_size = devsize; amfree(buf); } } while (result == 0); if (result < 0) { amfree(buf); /* if we're not at EOF, it's an error */ if (!self->device->is_eof) { xfer_cancel_with_error(elt, _("error reading from %s: %s"), self->device->device_name, device_error_or_status(self->device)); wait_until_xfer_cancelled(elt->xfer); } *size = 0; return NULL; } return buf; }
static gpointer pull_buffer_impl( XferElement *elt, size_t *size) { XferSourceRecovery *self = XFER_SOURCE_RECOVERY(elt); gpointer buf = NULL; int result; int devsize; XMsg *msg; g_assert(elt->output_mech == XFER_MECH_PULL_BUFFER); g_mutex_lock(self->start_part_mutex); if (elt->size == 0) { if (elt->offset == 0 && elt->orig_size == 0) { self->paused = TRUE; } else { DBG(2, "xfer-source-recovery sending XMSG_CRC message"); DBG(2, "xfer-source-recovery CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(XFER_ELEMENT(self), XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); /* the device has signalled EOF (really end-of-part), so clean up instance * variables and report the EOP to the caller in the form of an xmsg */ DBG(2, "pull_buffer hit EOF; sending XMSG_SEGMENT_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_SEGMENT_DONE, 0); msg->size = self->part_size; if (self->part_timer) { msg->duration = g_timer_elapsed(self->part_timer, NULL); g_timer_destroy(self->part_timer); self->part_timer = NULL; } msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; self->paused = TRUE; device_clear_bytes_read(self->device); self->bytes_read += self->part_size; self->part_size = 0; self->block_size = 0; /* don't queue the XMSG_PART_DONE until we've adjusted all of our * instance variables appropriately */ xfer_queue_message(elt->xfer, msg); if (self->device->is_eof) { DBG(2, "pull_buffer hit EOF; sending XMSG_PART_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_PART_DONE, 0); msg->size = self->part_size; if (self->part_timer) { msg->duration = g_timer_elapsed(self->part_timer, NULL); g_timer_destroy(self->part_timer); self->part_timer = NULL; } msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; xfer_queue_message(elt->xfer, msg); } } } while (1) { /* make sure we have a device */ while (self->paused && !elt->cancelled) g_cond_wait(self->start_part_cond, self->start_part_mutex); /* indicate EOF on an cancel or when there are no more parts */ if (elt->cancelled) { goto error; } if (self->done) goto error; /* start the timer if this is the first pull_buffer of this part */ if (!self->part_timer) { DBG(2, "first pull_buffer of new part"); self->part_timer = g_timer_new(); } if (elt->size == 0) { result = -1; } else { /* loop until we read a full block, in case the blocks are larger * than expected */ if (self->block_size == 0) self->block_size = (size_t)self->device->block_size; do { int max_block; buf = g_malloc(self->block_size); if (buf == NULL) { xfer_cancel_with_error(elt, _("%s: cannot allocate memory"), self->device->device_name); g_mutex_unlock(self->start_part_mutex); wait_until_xfer_cancelled(elt->xfer); goto error_unlocked; } devsize = (int)self->block_size; if (elt->size < 0) max_block = -1; else max_block = (elt->size+self->block_size-1)/self->block_size; result = device_read_block(self->device, buf, &devsize, max_block); *size = devsize; if (result == 0) { g_assert(*size > self->block_size); self->block_size = devsize; amfree(buf); } } while (result == 0); if (result > 0 && (elt->offset || (elt->size > 0 && (long long unsigned)elt->size < *size))) { gpointer buf1 = g_malloc(self->block_size); if ((long long unsigned)elt->offset > *size) { g_debug("offset > *size"); } else if ((long long unsigned)elt->offset == *size) { g_debug("offset == *size"); } *size -= elt->offset; if (elt->size > 0 && (size_t)elt->size < *size) *size = elt->size; memmove(buf1, buf + elt->offset, *size); elt->offset = 0; g_free(buf); buf = buf1; } if (result > 0) elt->size -= *size; } /* if this block was successful, return it */ if (result > 0) { self->part_size += *size; break; } if (result < 0) { amfree(buf); /* if we're not at EOF, it's an error */ if (!self->device->is_eof && elt->size != 0) { xfer_cancel_with_error(elt, _("error reading from %s: %s"), self->device->device_name, device_error_or_status(self->device)); g_mutex_unlock(self->start_part_mutex); wait_until_xfer_cancelled(elt->xfer); goto error_unlocked; } DBG(2, "xfer-source-recovery sending XMSG_CRC message"); DBG(2, "xfer-source-recovery CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(XFER_ELEMENT(self), XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); /* the device has signalled EOF (really end-of-part), so clean up instance * variables and report the EOP to the caller in the form of an xmsg */ DBG(2, "pull_buffer hit EOF; sending XMSG_PART_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_PART_DONE, 0); msg->size = self->part_size; msg->duration = g_timer_elapsed(self->part_timer, NULL); msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; self->paused = TRUE; self->bytes_read += self->part_size; device_clear_bytes_read(self->device); self->part_size = 0; self->block_size = 0; if (self->part_timer) { g_timer_destroy(self->part_timer); self->part_timer = NULL; } /* don't queue the XMSG_PART_DONE until we've adjusted all of our * instance variables appropriately */ xfer_queue_message(elt->xfer, msg); if (elt->size == 0) { g_mutex_unlock(self->start_part_mutex); return NULL; } } } g_mutex_unlock(self->start_part_mutex); if (buf) { crc32_add(buf, *size, &elt->crc); } return buf; error: g_mutex_unlock(self->start_part_mutex); error_unlocked: *size = 0; return NULL; }