diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 181 |
1 files changed, 86 insertions, 95 deletions
@@ -1,4 +1,4 @@ /* util.c - Several utility routines for cpio. - Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010 Free - Software Foundation, Inc. + Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010, + 2011 Free Software Foundation, Inc. @@ -102,3 +102,3 @@ tape_empty_output_buffer (int out_des) -static int sparse_write (int fildes, char *buf, unsigned int nbyte); +static ssize_t sparse_write (int fildes, char *buf, size_t nbyte, bool flush); @@ -115,5 +115,5 @@ static int sparse_write (int fildes, char *buf, unsigned int nbyte); void -disk_empty_output_buffer (int out_des) +disk_empty_output_buffer (int out_des, bool flush) { - int bytes_written; + ssize_t bytes_written; @@ -138,3 +138,3 @@ disk_empty_output_buffer (int out_des) if (sparse_flag) - bytes_written = sparse_write (out_des, output_buffer, output_size); + bytes_written = sparse_write (out_des, output_buffer, output_size, flush); else @@ -144,3 +144,6 @@ disk_empty_output_buffer (int out_des) { - error (1, errno, _("write error")); + if (bytes_written == -1) + error (1, errno, _("write error")); + else + error (1, 0, _("write error: partial write")); } @@ -277,3 +280,3 @@ disk_buffered_write (char *in_buf, int out_des, off_t num_bytes) if (space_left == 0) - disk_empty_output_buffer (out_des); + disk_empty_output_buffer (out_des, false); else @@ -1113,103 +1116,91 @@ buf_all_zeros (char *buf, int bufsize) -int delayed_seek_count = 0; +/* Write NBYTE bytes from BUF to file descriptor FILDES, trying to + create holes instead of writing blockfuls of zeros. + + Return the number of bytes written (including bytes in zero + regions) on success, -1 on error. -/* Write NBYTE bytes from BUF to remote tape connection FILDES. - Return the number of bytes written on success, -1 on error. */ + If FLUSH is set, make sure the trailing zero region is flushed + on disk. +*/ -static int -sparse_write (int fildes, char *buf, unsigned int nbyte) +static ssize_t +sparse_write (int fildes, char *buf, size_t nbytes, bool flush) { - int complete_block_count; - int leftover_bytes_count; - int seek_count; - int write_count; - char *cur_write_start; - int lseek_rc; - int write_rc; - int i; - enum { begin, in_zeros, not_in_zeros } state; - - complete_block_count = nbyte / DISKBLOCKSIZE; - leftover_bytes_count = nbyte % DISKBLOCKSIZE; - - if (delayed_seek_count != 0) - state = in_zeros; - else - state = begin; + size_t nwritten = 0; + ssize_t n; + char *start_ptr = buf; - seek_count = delayed_seek_count; + static off_t delayed_seek_count = 0; + off_t seek_count = 0; - for (i = 0; i < complete_block_count; ++i) + enum { begin, in_zeros, not_in_zeros } state = + delayed_seek_count ? in_zeros : begin; + + while (nbytes) { - switch (state) + size_t rest = nbytes; + + if (rest < DISKBLOCKSIZE) + /* Force write */ + state = not_in_zeros; + else { - case begin : - if (buf_all_zeros (buf, DISKBLOCKSIZE)) - { - seek_count = DISKBLOCKSIZE; - state = in_zeros; - } - else - { - cur_write_start = buf; - write_count = DISKBLOCKSIZE; - state = not_in_zeros; - } - buf += DISKBLOCKSIZE; - break; - - case in_zeros : - if (buf_all_zeros (buf, DISKBLOCKSIZE)) - { - seek_count += DISKBLOCKSIZE; - } - else - { - lseek (fildes, seek_count, SEEK_CUR); - cur_write_start = buf; - write_count = DISKBLOCKSIZE; - state = not_in_zeros; - } - buf += DISKBLOCKSIZE; - break; - - case not_in_zeros : - if (buf_all_zeros (buf, DISKBLOCKSIZE)) - { - write_rc = write (fildes, cur_write_start, write_count); - seek_count = DISKBLOCKSIZE; - state = in_zeros; - } - else - { - write_count += DISKBLOCKSIZE; - } - buf += DISKBLOCKSIZE; - break; + if (buf_all_zeros (buf, rest)) + { + if (state == not_in_zeros) + { + ssize_t bytes = buf - start_ptr + rest; + + n = write (fildes, start_ptr, bytes); + if (n == -1) + return -1; + nwritten += n; + if (n < bytes) + return nwritten + seek_count; + start_ptr = NULL; + } + else + seek_count += rest; + state = in_zeros; + } + else + { + seek_count += delayed_seek_count; + if (lseek (fildes, seek_count, SEEK_CUR) == -1) + return -1; + delayed_seek_count = seek_count = 0; + state = not_in_zeros; + start_ptr = buf; + } } + buf += rest; + nbytes -= rest; } - switch (state) + if (state != in_zeros) { - case begin : - case in_zeros : - delayed_seek_count = seek_count; - break; - - case not_in_zeros : - write_rc = write (fildes, cur_write_start, write_count); - delayed_seek_count = 0; - break; + seek_count += delayed_seek_count; + if (seek_count && lseek (fildes, seek_count, SEEK_CUR) == -1) + return -1; + delayed_seek_count = seek_count = 0; + + n = write (fildes, start_ptr, buf - start_ptr); + if (n == -1) + return n; + nwritten += n; } + delayed_seek_count += seek_count; - if (leftover_bytes_count != 0) + if (flush && delayed_seek_count) { - if (delayed_seek_count != 0) - { - lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR); - delayed_seek_count = 0; - } - write_rc = write (fildes, buf, leftover_bytes_count); - } - return nbyte; + if (lseek (fildes, delayed_seek_count - 1, SEEK_CUR) == -1) + return -1; + n = write (fildes, "", 1); + if (n != 1) + return n; + delayed_seek_count = 0; + } + + return nwritten + seek_count; } |