aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-09-19 00:37:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-09-19 03:14:47 +0300
commit1f6b4122815eb16dca584faac123ef46da2d538f (patch)
tree9934c37a74ed0f4ac5248eac345b971a6882d8fb
parenta279052b65a53d228f0d2cd188114f4cf398cc82 (diff)
downloadcpio-1f6b4122815eb16dca584faac123ef46da2d538f.tar.gz
cpio-1f6b4122815eb16dca584faac123ef46da2d538f.tar.bz2
Fix error handling in disk_empty_output_buffer and sparse_write
* src/extern.h (delayed_seek_count): Remove. (disk_empty_output_buffer): Change signature. * src/util.c (disk_empty_output_buffer): Take two arguments. Correctly handle partial writes (errno is not meaningful). (delayed_seek_count): Remove variable. (sparse_write): Change return type and signature. Rewrite. Return number actual number of bytes written or -1 on error. Check returns from lseek and write. * src/copyin.c (copyin_regular_file): Call disk_empty_output_buffer with flush=true before closing the file. * src/copypass.c (process_copy_pass): Likewise.
-rw-r--r--src/copyin.c12
-rw-r--r--src/copypass.c13
-rw-r--r--src/extern.h3
-rw-r--r--src/util.c181
4 files changed, 90 insertions, 119 deletions
diff --git a/src/copyin.c b/src/copyin.c
index 22e33dc..3ab5dac 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -515,13 +515,13 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
swapping_bytes = true;
else
error (0, 0, _("cannot swap bytes of %s: odd number of bytes"),
file_hdr->c_name);
}
copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize);
- disk_empty_output_buffer (out_file_des);
+ disk_empty_output_buffer (out_file_des, true);
if (to_stdout_option)
{
if (archive_format == arf_crcascii)
{
if (crc != file_hdr->c_chksum)
@@ -529,22 +529,12 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
file_hdr->c_name, crc, file_hdr->c_chksum);
}
tape_skip_padding (in_file_des, file_hdr->c_filesize);
return;
}
- /* Debian hack to fix a bug in the --sparse option.
- This bug has been reported to
- "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
- if (delayed_seek_count > 0)
- {
- lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
- write (out_file_des, "", 1);
- delayed_seek_count = 0;
- }
-
set_perms (out_file_des, file_hdr);
if (close (out_file_des) < 0)
close_error (file_hdr->c_name);
if (archive_format == arf_crcascii)
diff --git a/src/copypass.c b/src/copypass.c
index 5b1d594..a3ccb71 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -197,23 +197,14 @@ process_copy_pass ()
open_error (output_name.ds_string);
close (in_file_des);
continue;
}
copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
- disk_empty_output_buffer (out_file_des);
- /* Debian hack to fix a bug in the --sparse option.
- This bug has been reported to
- "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
- if (delayed_seek_count > 0)
- {
- lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
- write (out_file_des, "", 1);
- delayed_seek_count = 0;
- }
-
+ disk_empty_output_buffer (out_file_des, true);
+
set_copypass_perms (out_file_des,
output_name.ds_string, &in_file_stat);
if (reset_time_flag)
{
set_file_times (in_file_des,
diff --git a/src/extern.h b/src/extern.h
index c25a6ef..be329ae 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -73,13 +73,12 @@ extern char *new_media_message;
extern char *new_media_message_with_number;
extern char *new_media_message_after_number;
extern int archive_des;
extern char *archive_name;
extern char *rsh_command_option;
extern unsigned long crc;
-extern int delayed_seek_count;
#ifdef DEBUG_CPIO
extern int debug_flag;
#endif
extern char *input_buffer, *output_buffer;
extern char *in_buff, *out_buff;
@@ -154,13 +153,13 @@ int is_tar_filename_too_long (char *name);
/* userspec.c */
char *parse_user_spec (char *name, uid_t *uid, gid_t *gid,
char **username, char **groupname);
/* util.c */
void tape_empty_output_buffer (int out_des);
-void disk_empty_output_buffer (int out_des);
+void disk_empty_output_buffer (int out_des, bool flush);
void swahw_array (char *ptr, int count);
void tape_buffered_write (char *in_buf, int out_des, off_t num_bytes);
void tape_buffered_read (char *in_buf, int in_des, off_t num_bytes);
int tape_buffered_peek (char *peek_buf, int in_des, int num_bytes);
void tape_toss_input (int in_des, off_t num_bytes);
void copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes);
diff --git a/src/util.c b/src/util.c
index 7c6db52..22725e4 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,9 +1,9 @@
/* 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.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -97,28 +97,28 @@ tape_empty_output_buffer (int out_des)
}
output_bytes += output_size;
out_buff = output_buffer;
output_size = 0;
}
-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);
/* Write `output_size' bytes of `output_buffer' to file
descriptor OUT_DES and reset `output_size' and `out_buff'.
If `swapping_halfwords' or `swapping_bytes' is set,
do the appropriate swapping first. Our callers have
to make sure to only set these flags if `output_size'
is appropriate (a multiple of 4 for `swapping_halfwords',
2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
must always be a multiple of 4 helps us (and our callers)
insure this. */
void
-disk_empty_output_buffer (int out_des)
+disk_empty_output_buffer (int out_des, bool flush)
{
- int bytes_written;
+ ssize_t bytes_written;
if (swapping_halfwords || swapping_bytes)
{
if (swapping_halfwords)
{
int complete_words;
@@ -133,19 +133,22 @@ disk_empty_output_buffer (int out_des)
complete_halfwords = output_size /2;
swab_array (output_buffer, complete_halfwords);
}
}
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
bytes_written = write (out_des, output_buffer, output_size);
if (bytes_written != output_size)
{
- error (1, errno, _("write error"));
+ if (bytes_written == -1)
+ error (1, errno, _("write error"));
+ else
+ error (1, 0, _("write error: partial write"));
}
output_bytes += output_size;
out_buff = output_buffer;
output_size = 0;
}
@@ -272,13 +275,13 @@ disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
off_t space_left; /* Room left in output buffer. */
while (bytes_left > 0)
{
space_left = DISK_IO_BLOCK_SIZE - output_size;
if (space_left == 0)
- disk_empty_output_buffer (out_des);
+ disk_empty_output_buffer (out_des, false);
else
{
if (bytes_left < space_left)
space_left = bytes_left;
memcpy (out_buff, in_buf, (unsigned) space_left);
out_buff += space_left;
@@ -1108,113 +1111,101 @@ buf_all_zeros (char *buf, int bufsize)
if (*buf++ != '\0')
return 0;
}
return 1;
}
-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;
}
#define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid))
#define CPIO_GID(gid) (set_group_flag ? set_group : (gid))
void

Return to:

Send suggestions and report system problems to the System administrator.