1 /* Delete entries from a tar archive.
3 Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001 Free
4 Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any later
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 static union block *new_record;
26 static int new_blocks;
27 static bool acting_as_filter;
29 /* FIXME: This module should not directly handle the following
30 variables, instead, the interface should be cleaned up. */
31 extern union block *record_start;
32 extern union block *record_end;
33 extern union block *current_block;
34 extern union block *recent_long_name;
35 extern union block *recent_long_link;
36 extern size_t recent_long_name_blocks;
37 extern size_t recent_long_link_blocks;
38 extern off_t records_read;
39 extern off_t records_written;
41 /* The number of records skipped at the start of the archive, when
42 passing over members that are not deleted. */
43 static off_t records_skipped;
45 /* Move archive descriptor by COUNT records worth. If COUNT is
46 positive we move forward, else we move negative. If it's a tape,
47 MTIOCTOP had better work. If it's something else, we try to seek
48 on it. If we can't seek, we lose! */
50 move_archive (off_t count)
57 struct mtop operation;
60 ? (operation.mt_op = MTBSR,
61 operation.mt_count = -count,
62 operation.mt_count == -count)
63 : (operation.mt_op = MTFSR,
64 operation.mt_count = count,
65 operation.mt_count == count))
67 if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
71 && 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
78 off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
79 off_t increment = record_size * (off_t) count;
80 off_t position = position0 + increment;
82 if (increment / count != record_size
83 || (position < position0) != (increment < 0)
84 || (position = position < 0 ? 0 : position,
85 rmtlseek (archive, position, SEEK_SET) != position))
86 seek_error_details (archive_name_array[0], position);
92 /* Write out the record which has been filled. If MOVE_BACK_FLAG,
93 backspace to where we started. */
95 write_record (int move_back_flag)
97 union block *save_record = record_start;
98 record_start = new_record;
100 if (acting_as_filter)
102 archive = STDOUT_FILENO;
104 archive = STDIN_FILENO;
108 move_archive ((records_written + records_skipped) - records_read);
112 record_start = save_record;
116 /* Move the tape head back to where we were. */
118 if (! acting_as_filter)
119 move_archive (records_read - (records_written + records_skipped));
126 write_recent_blocks (union block *h, size_t blocks)
129 for (i = 0; i < blocks; i++)
131 new_record[new_blocks++] = h[i];
132 if (new_blocks == blocking_factor)
138 delete_archive_members (void)
140 enum read_header logical_status = HEADER_STILL_UNREAD;
141 enum read_header previous_status = HEADER_STILL_UNREAD;
143 /* FIXME: Should clean the routine before cleaning these variables :-( */
145 off_t blocks_to_skip = 0;
146 off_t blocks_to_keep = 0;
147 int kept_blocks_in_record;
150 open_archive (ACCESS_UPDATE);
151 acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
155 enum read_header status = read_header (1);
159 case HEADER_STILL_UNREAD:
163 if (name = name_scan (current_file_name), !name)
170 case HEADER_SUCCESS_EXTENDED:
171 logical_status = status;
174 case HEADER_ZERO_BLOCK:
175 if (ignore_zeros_option)
177 set_next_block_after (current_header);
181 case HEADER_END_OF_FILE:
182 logical_status = HEADER_END_OF_FILE;
186 set_next_block_after (current_header);
187 switch (previous_status)
189 case HEADER_STILL_UNREAD:
190 WARN ((0, 0, _("This does not look like a tar archive")));
194 case HEADER_ZERO_BLOCK:
195 ERROR ((0, 0, _("Skipping to next header")));
201 case HEADER_END_OF_FILE:
207 previous_status = status;
209 while (logical_status == HEADER_STILL_UNREAD);
211 records_skipped = records_read - 1;
212 new_record = xmalloc (record_size);
214 if (logical_status == HEADER_SUCCESS
215 || logical_status == HEADER_SUCCESS_EXTENDED)
217 write_archive_to_stdout = 0;
219 /* Save away blocks before this one in this record. */
221 new_blocks = current_block - record_start;
223 memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
225 if (logical_status == HEADER_SUCCESS)
227 /* FIXME: Pheew! This is crufty code! */
228 logical_status = HEADER_STILL_UNREAD;
232 /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
233 "delete.c", line 223: warning: loop not entered at top
234 Reported by Bruno Haible. */
237 enum read_header status;
239 /* Fill in a record. */
241 if (current_block == record_end)
243 status = read_header (0);
245 if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
247 set_next_block_after (current_header);
250 if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
252 logical_status = HEADER_END_OF_FILE;
256 if (status == HEADER_FAILURE)
258 ERROR ((0, 0, _("Deleting non-header from archive")));
259 set_next_block_after (current_header);
263 /* Found another header. */
265 if (name = name_scan (current_file_name), name)
269 set_next_block_after (current_header);
270 blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
272 while (record_end - current_block <= blocks_to_skip)
274 blocks_to_skip -= (record_end - current_block);
277 current_block += blocks_to_skip;
284 write_recent_blocks (recent_long_name, recent_long_name_blocks);
285 write_recent_blocks (recent_long_link, recent_long_link_blocks);
286 new_record[new_blocks] = *current_header;
289 = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
290 set_next_block_after (current_header);
291 if (new_blocks == blocking_factor)
296 kept_blocks_in_record = record_end - current_block;
297 if (kept_blocks_in_record > blocks_to_keep)
298 kept_blocks_in_record = blocks_to_keep;
300 while (blocks_to_keep)
304 if (current_block == record_end)
307 current_block = record_start;
308 kept_blocks_in_record = blocking_factor;
309 if (kept_blocks_in_record > blocks_to_keep)
310 kept_blocks_in_record = blocks_to_keep;
312 count = kept_blocks_in_record;
313 if (blocking_factor - new_blocks < count)
314 count = blocking_factor - new_blocks;
319 memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
321 current_block += count;
322 blocks_to_keep -= count;
323 kept_blocks_in_record -= count;
325 if (new_blocks == blocking_factor)
331 if (logical_status == HEADER_END_OF_FILE)
333 /* Write the end of tape. FIXME: we can't use write_eot here,
334 as it gets confused when the input is at end of file. */
336 int total_zero_blocks = 0;
340 int zero_blocks = blocking_factor - new_blocks;
341 memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
342 total_zero_blocks += zero_blocks;
343 write_record (total_zero_blocks < 2);
345 while (total_zero_blocks < 2);
350 if (! acting_as_filter && ! _isrmt (archive))
353 int status = write (archive, "", 0);
355 off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
356 int status = pos < 0 ? -1 : ftruncate (archive, pos);
359 truncate_warn (archive_name_array[0]);