Only call ftruncate() once, when the output file descriptor is closed at the end, instead of after every lseek() - this corrects the file growth on XFS but has the side effect that writing to stdout in >> (append) mode truncates the file to the wrong size (#45).
This commit is contained in:
@@ -257,6 +257,31 @@ void pv_freecontents_calc(pvtransfercalc_t calc)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Truncate the output file descriptor to its current position, if it's a
|
||||
* valid fd, we're in sparse output mode, and no lseek() failed.
|
||||
*/
|
||||
static void pv_truncate_output(pvstate_t state)
|
||||
{
|
||||
off_t current_offset;
|
||||
|
||||
if (!state->control.sparse_output)
|
||||
return;
|
||||
if (state->transfer.output_not_seekable)
|
||||
return;
|
||||
if (state->control.output_fd < 0)
|
||||
return;
|
||||
|
||||
current_offset = lseek(state->control.output_fd, (off_t) 0, SEEK_CUR);
|
||||
if (current_offset == (off_t) - 1)
|
||||
return;
|
||||
|
||||
if (0 != ftruncate(state->control.output_fd, current_offset)) {
|
||||
debug("%s: %s", "output ftruncate() failed", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free a state structure, after which it can no longer be used.
|
||||
*/
|
||||
@@ -270,6 +295,7 @@ void pv_state_free(pvstate_t state)
|
||||
* still know the program name and output filename.
|
||||
*/
|
||||
if (state->control.output_fd >= 0) {
|
||||
pv_truncate_output(state);
|
||||
if (STDOUT_FILENO != state->control.output_fd) {
|
||||
if (close(state->control.output_fd) < 0) {
|
||||
pv_error("%s: %s",
|
||||
@@ -631,6 +657,7 @@ void pv_state_output_set(pvstate_t state, int fd, const char *name)
|
||||
* Close any previous output file first, so we can report any errors
|
||||
* before we store the new output filename.
|
||||
*/
|
||||
pv_truncate_output(state);
|
||||
if (state->control.output_fd >= 0 && state->control.output_fd != STDOUT_FILENO) {
|
||||
if (close(state->control.output_fd) < 0) {
|
||||
pv_error("%s: %s",
|
||||
|
||||
@@ -709,22 +709,6 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
if (output_offset == (off_t) - 1) {
|
||||
debug("%s: %s", "output lseek() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else if (0 != ftruncate(state->control.output_fd, output_offset)) {
|
||||
/* TODO: don't ftruncate() immediately. */
|
||||
/*
|
||||
* On XFS filesystems it looks like
|
||||
* this can actually make a sparse
|
||||
* file take up more space than a
|
||||
* regular file, though it's not
|
||||
* obvious yet whether the
|
||||
* ftruncate() is causing it or just
|
||||
* the lseek().
|
||||
*
|
||||
* Maybe just ftruncate() at the end
|
||||
* of the program.
|
||||
*/
|
||||
debug("%s: %s", "output ftruncate() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else {
|
||||
/* Seek successful - skip write. */
|
||||
nwritten = state->transfer.to_write;
|
||||
|
||||
Reference in New Issue
Block a user