First working draft of --sparse transfers, tests still needed (#45).
This commit is contained in:
@@ -221,6 +221,7 @@ extern void pv_state_error_skip_block_set(pvstate_t, off_t);
|
||||
extern void pv_state_stop_at_size_set(pvstate_t, bool);
|
||||
extern void pv_state_sync_after_write_set(pvstate_t, bool);
|
||||
extern void pv_state_direct_io_set(pvstate_t, bool);
|
||||
extern void pv_state_sparse_output_set(pvstate_t, bool);
|
||||
extern void pv_state_rate_limit_set(pvstate_t, off_t);
|
||||
extern void pv_state_target_buffer_size_set(pvstate_t, size_t);
|
||||
extern void pv_state_no_splice_set(pvstate_t, bool);
|
||||
|
||||
@@ -509,6 +509,7 @@ int main(int argc, char **argv)
|
||||
pv_state_error_skip_block_set(state, opts->error_skip_block);
|
||||
pv_state_sync_after_write_set(state, opts->sync_after_write);
|
||||
pv_state_direct_io_set(state, opts->direct_io);
|
||||
pv_state_sparse_output_set(state, opts->sparse_output);
|
||||
pv_state_discard_input_set(state, opts->discard_input);
|
||||
pv_state_rate_limit_set(state, opts->rate_limit);
|
||||
pv_state_target_buffer_size_set(state, opts->buffer_size);
|
||||
|
||||
@@ -131,6 +131,7 @@ void pv_reset_transfer(pvtransferstate_t transfer)
|
||||
transfer->line_positions_length = 0;
|
||||
transfer->line_positions_head = 0;
|
||||
transfer->last_output_position = 0;
|
||||
transfer->output_not_seekable = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,6 +495,11 @@ void pv_state_direct_io_set(pvstate_t state, bool val)
|
||||
state->control.direct_io_changed = true;
|
||||
}
|
||||
|
||||
void pv_state_sparse_output_set(pvstate_t state, bool val)
|
||||
{
|
||||
state->control.sparse_output = val;
|
||||
}
|
||||
|
||||
void pv_state_discard_input_set(pvstate_t state, bool val)
|
||||
{
|
||||
state->control.discard_input = val;
|
||||
|
||||
@@ -671,6 +671,62 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
nwritten = state->transfer.to_write;
|
||||
} else if (state->transfer.to_write > 0) {
|
||||
|
||||
/*
|
||||
* In sparse output mode, check whether all of the bytes to
|
||||
* be written are null, and if so, try to seek the output
|
||||
* instead of writing the null bytes.
|
||||
*/
|
||||
if (state->control.sparse_output && !state->transfer.output_not_seekable) {
|
||||
bool all_nulls = true;
|
||||
size_t write_check_position, write_end_position;
|
||||
write_check_position = state->transfer.write_position;
|
||||
write_end_position = write_check_position + (size_t) (state->transfer.to_write);
|
||||
while (all_nulls && write_check_position < write_end_position) {
|
||||
if ('\0' == state->transfer.transfer_buffer[write_check_position]) {
|
||||
write_check_position++;
|
||||
} else {
|
||||
all_nulls = false;
|
||||
}
|
||||
}
|
||||
if (all_nulls) {
|
||||
struct stat sb;
|
||||
|
||||
/*
|
||||
* Get the current size of the output file,
|
||||
* so we can attempt to enlarge it with
|
||||
* ftruncate() and then use lseek() to skip
|
||||
* to the new end of the file.
|
||||
*
|
||||
* If any step fails, mark the output not
|
||||
* seekable so we stop trying.
|
||||
*/
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
/*@+longintegral@ */
|
||||
/*
|
||||
* splint has trouble with off_t / __off_t, in the lseek() call.
|
||||
*/
|
||||
if (0 != fstat(state->control.output_fd, &sb)) {
|
||||
debug("%s: %s", "output fstat() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else if (0 !=
|
||||
ftruncate(state->control.output_fd,
|
||||
sb.st_size + (off_t) (state->transfer.to_write))) {
|
||||
debug("%s: %s", "output ftruncate() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else if (lseek(state->control.output_fd, (off_t) (state->transfer.to_write), SEEK_CUR)
|
||||
== (off_t) - 1) {
|
||||
debug("%s: %s", "output lseek() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else {
|
||||
/* Seek successful - skip write. */
|
||||
nwritten = state->transfer.to_write;
|
||||
goto pv__transfer_write_completed;
|
||||
}
|
||||
/*@-longintegral@ */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an interval timer or an alarm to interrupt the write
|
||||
* with a signal if the write takes too long, so we can
|
||||
@@ -733,6 +789,9 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
debug("%s", "cancelling alarm");
|
||||
(void) alarm(0);
|
||||
#endif /* HAVE_SETITIMER */
|
||||
|
||||
pv__transfer_write_completed:
|
||||
/* If lseek() worked for sparse output, it jumps down here. */
|
||||
}
|
||||
|
||||
if (nwritten > 0) {
|
||||
|
||||
Reference in New Issue
Block a user