summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2011-09-18 21:37:43 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-09-19 00:14:47 (GMT)
commit1f6b4122815eb16dca584faac123ef46da2d538f (patch) (unidiff)
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.
Diffstat (more/less context) (ignore whitespace changes)
-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
@@ -518,7 +518,7 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
518 file_hdr->c_name); 518 file_hdr->c_name);
519 } 519 }
520 copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize); 520 copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize);
521 disk_empty_output_buffer (out_file_des); 521 disk_empty_output_buffer (out_file_des, true);
522 522
523 if (to_stdout_option) 523 if (to_stdout_option)
524 { 524 {
@@ -532,16 +532,6 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des)
532 return; 532 return;
533 } 533 }
534 534
535 /* Debian hack to fix a bug in the --sparse option.
536 This bug has been reported to
537 "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
538 if (delayed_seek_count > 0)
539 {
540 lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
541 write (out_file_des, "", 1);
542 delayed_seek_count = 0;
543 }
544
545 set_perms (out_file_des, file_hdr); 535 set_perms (out_file_des, file_hdr);
546 536
547 if (close (out_file_des) < 0) 537 if (close (out_file_des) < 0)
diff --git a/src/copypass.c b/src/copypass.c
index 5b1d594..a3ccb71 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -200,17 +200,8 @@ process_copy_pass ()
200 } 200 }
201 201
202 copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string); 202 copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
203 disk_empty_output_buffer (out_file_des); 203 disk_empty_output_buffer (out_file_des, true);
204 /* Debian hack to fix a bug in the --sparse option. 204
205 This bug has been reported to
206 "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
207 if (delayed_seek_count > 0)
208 {
209 lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
210 write (out_file_des, "", 1);
211 delayed_seek_count = 0;
212 }
213
214 set_copypass_perms (out_file_des, 205 set_copypass_perms (out_file_des,
215 output_name.ds_string, &in_file_stat); 206 output_name.ds_string, &in_file_stat);
216 207
diff --git a/src/extern.h b/src/extern.h
index c25a6ef..be329ae 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -76,7 +76,6 @@ extern int archive_des;
76extern char *archive_name; 76extern char *archive_name;
77extern char *rsh_command_option; 77extern char *rsh_command_option;
78extern unsigned long crc; 78extern unsigned long crc;
79extern int delayed_seek_count;
80#ifdef DEBUG_CPIO 79#ifdef DEBUG_CPIO
81extern int debug_flag; 80extern int debug_flag;
82#endif 81#endif
@@ -157,7 +156,7 @@ char *parse_user_spec (char *name, uid_t *uid, gid_t *gid,
157 156
158/* util.c */ 157/* util.c */
159void tape_empty_output_buffer (int out_des); 158void tape_empty_output_buffer (int out_des);
160void disk_empty_output_buffer (int out_des); 159void disk_empty_output_buffer (int out_des, bool flush);
161void swahw_array (char *ptr, int count); 160void swahw_array (char *ptr, int count);
162void tape_buffered_write (char *in_buf, int out_des, off_t num_bytes); 161void tape_buffered_write (char *in_buf, int out_des, off_t num_bytes);
163void tape_buffered_read (char *in_buf, int in_des, off_t num_bytes); 162void tape_buffered_read (char *in_buf, int in_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,6 +1,6 @@
1/* util.c - Several utility routines for cpio. 1/* util.c - Several utility routines for cpio.
2 Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010 Free 2 Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010,
3 Software Foundation, Inc. 3 2011 Free Software Foundation, Inc.
4 4
5 This program is free software; you can redistribute it and/or modify 5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
@@ -100,7 +100,7 @@ tape_empty_output_buffer (int out_des)
100 output_size = 0; 100 output_size = 0;
101} 101}
102 102
103static int sparse_write (int fildes, char *buf, unsigned int nbyte); 103static ssize_t sparse_write (int fildes, char *buf, size_t nbyte, bool flush);
104 104
105/* Write `output_size' bytes of `output_buffer' to file 105/* Write `output_size' bytes of `output_buffer' to file
106 descriptor OUT_DES and reset `output_size' and `out_buff'. 106 descriptor OUT_DES and reset `output_size' and `out_buff'.
@@ -113,9 +113,9 @@ static int sparse_write (int fildes, char *buf, unsigned int nbyte);
113 insure this. */ 113 insure this. */
114 114
115void 115void
116disk_empty_output_buffer (int out_des) 116disk_empty_output_buffer (int out_des, bool flush)
117{ 117{
118 int bytes_written; 118 ssize_t bytes_written;
119 119
120 if (swapping_halfwords || swapping_bytes) 120 if (swapping_halfwords || swapping_bytes)
121 { 121 {
@@ -136,13 +136,16 @@ disk_empty_output_buffer (int out_des)
136 } 136 }
137 137
138 if (sparse_flag) 138 if (sparse_flag)
139 bytes_written = sparse_write (out_des, output_buffer, output_size); 139 bytes_written = sparse_write (out_des, output_buffer, output_size, flush);
140 else 140 else
141 bytes_written = write (out_des, output_buffer, output_size); 141 bytes_written = write (out_des, output_buffer, output_size);
142 142
143 if (bytes_written != output_size) 143 if (bytes_written != output_size)
144 { 144 {
145 error (1, errno, _("write error")); 145 if (bytes_written == -1)
146 error (1, errno, _("write error"));
147 else
148 error (1, 0, _("write error: partial write"));
146 } 149 }
147 output_bytes += output_size; 150 output_bytes += output_size;
148 out_buff = output_buffer; 151 out_buff = output_buffer;
@@ -275,7 +278,7 @@ disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
275 { 278 {
276 space_left = DISK_IO_BLOCK_SIZE - output_size; 279 space_left = DISK_IO_BLOCK_SIZE - output_size;
277 if (space_left == 0) 280 if (space_left == 0)
278 disk_empty_output_buffer (out_des); 281 disk_empty_output_buffer (out_des, false);
279 else 282 else
280 { 283 {
281 if (bytes_left < space_left) 284 if (bytes_left < space_left)
@@ -1111,107 +1114,95 @@ buf_all_zeros (char *buf, int bufsize)
1111 return 1; 1114 return 1;
1112} 1115}
1113 1116
1114int delayed_seek_count = 0; 1117/* Write NBYTE bytes from BUF to file descriptor FILDES, trying to
1118 create holes instead of writing blockfuls of zeros.
1119
1120 Return the number of bytes written (including bytes in zero
1121 regions) on success, -1 on error.
1115 1122
1116/* Write NBYTE bytes from BUF to remote tape connection FILDES. 1123 If FLUSH is set, make sure the trailing zero region is flushed
1117 Return the number of bytes written on success, -1 on error. */ 1124 on disk.
1125*/
1118 1126
1119static int 1127static ssize_t
1120sparse_write (int fildes, char *buf, unsigned int nbyte) 1128sparse_write (int fildes, char *buf, size_t nbytes, bool flush)
1121{ 1129{
1122 int complete_block_count; 1130 size_t nwritten = 0;
1123 int leftover_bytes_count; 1131 ssize_t n;
1124 int seek_count; 1132 char *start_ptr = buf;
1125 int write_count;
1126 char *cur_write_start;
1127 int lseek_rc;
1128 int write_rc;
1129 int i;
1130 enum { begin, in_zeros, not_in_zeros } state;
1131
1132 complete_block_count = nbyte / DISKBLOCKSIZE;
1133 leftover_bytes_count = nbyte % DISKBLOCKSIZE;
1134
1135 if (delayed_seek_count != 0)
1136 state = in_zeros;
1137 else
1138 state = begin;
1139 1133
1140 seek_count = delayed_seek_count; 1134 static off_t delayed_seek_count = 0;
1135 off_t seek_count = 0;
1141 1136
1142 for (i = 0; i < complete_block_count; ++i) 1137 enum { begin, in_zeros, not_in_zeros } state =
1138 delayed_seek_count ? in_zeros : begin;
1139
1140 while (nbytes)
1143 { 1141 {
1144 switch (state) 1142 size_t rest = nbytes;
1143
1144 if (rest < DISKBLOCKSIZE)
1145 /* Force write */
1146 state = not_in_zeros;
1147 else
1145 { 1148 {
1146 case begin : 1149 if (buf_all_zeros (buf, rest))
1147 if (buf_all_zeros (buf, DISKBLOCKSIZE)) 1150 {
1148 { 1151 if (state == not_in_zeros)
1149 seek_count = DISKBLOCKSIZE; 1152 {
1150 state = in_zeros; 1153 ssize_t bytes = buf - start_ptr + rest;
1151 } 1154
1152 else 1155 n = write (fildes, start_ptr, bytes);
1153 { 1156 if (n == -1)
1154 cur_write_start = buf; 1157 return -1;
1155 write_count = DISKBLOCKSIZE; 1158 nwritten += n;
1156 state = not_in_zeros; 1159 if (n < bytes)
1157 } 1160 return nwritten + seek_count;
1158 buf += DISKBLOCKSIZE; 1161 start_ptr = NULL;
1159 break; 1162 }
1160 1163 else
1161 case in_zeros : 1164 seek_count += rest;
1162 if (buf_all_zeros (buf, DISKBLOCKSIZE)) 1165 state = in_zeros;
1163 { 1166 }
1164 seek_count += DISKBLOCKSIZE; 1167 else
1165 } 1168 {
1166 else 1169 seek_count += delayed_seek_count;
1167 { 1170 if (lseek (fildes, seek_count, SEEK_CUR) == -1)
1168 lseek (fildes, seek_count, SEEK_CUR); 1171 return -1;
1169 cur_write_start = buf; 1172 delayed_seek_count = seek_count = 0;
1170 write_count = DISKBLOCKSIZE; 1173 state = not_in_zeros;
1171 state = not_in_zeros; 1174 start_ptr = buf;
1172 } 1175 }
1173 buf += DISKBLOCKSIZE;
1174 break;
1175
1176 case not_in_zeros :
1177 if (buf_all_zeros (buf, DISKBLOCKSIZE))
1178 {
1179 write_rc = write (fildes, cur_write_start, write_count);
1180 seek_count = DISKBLOCKSIZE;
1181 state = in_zeros;
1182 }
1183 else
1184 {
1185 write_count += DISKBLOCKSIZE;
1186 }
1187 buf += DISKBLOCKSIZE;
1188 break;
1189 } 1176 }
1177 buf += rest;
1178 nbytes -= rest;
1190 } 1179 }
1191 1180
1192 switch (state) 1181 if (state != in_zeros)
1193 { 1182 {
1194 case begin : 1183 seek_count += delayed_seek_count;
1195 case in_zeros : 1184 if (seek_count && lseek (fildes, seek_count, SEEK_CUR) == -1)
1196 delayed_seek_count = seek_count; 1185 return -1;
1197 break; 1186 delayed_seek_count = seek_count = 0;
1198 1187
1199 case not_in_zeros : 1188 n = write (fildes, start_ptr, buf - start_ptr);
1200 write_rc = write (fildes, cur_write_start, write_count); 1189 if (n == -1)
1201 delayed_seek_count = 0; 1190 return n;
1202 break; 1191 nwritten += n;
1203 } 1192 }
1193 delayed_seek_count += seek_count;
1204 1194
1205 if (leftover_bytes_count != 0) 1195 if (flush && delayed_seek_count)
1206 { 1196 {
1207 if (delayed_seek_count != 0) 1197 if (lseek (fildes, delayed_seek_count - 1, SEEK_CUR) == -1)
1208 { 1198 return -1;
1209 lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR); 1199 n = write (fildes, "", 1);
1210 delayed_seek_count = 0; 1200 if (n != 1)
1211 } 1201 return n;
1212 write_rc = write (fildes, buf, leftover_bytes_count); 1202 delayed_seek_count = 0;
1213 } 1203 }
1214 return nbyte; 1204
1205 return nwritten + seek_count;
1215} 1206}
1216 1207
1217#define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid)) 1208#define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid))

Return to:

Send suggestions and report system problems to the System administrator.