Implement window size passing between real tty and virtual console.
[dragonfly/vkernel-mp.git] / contrib / tar / src / delete.c
blobad7b590d08e877773208de718cfe02495cdd05d1
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
9 version.
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. */
20 #include "system.h"
22 #include "common.h"
23 #include "rmt.h"
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! */
49 static void
50 move_archive (off_t count)
52 if (count == 0)
53 return;
55 #ifdef MTIOCTOP
57 struct mtop operation;
59 if (count < 0
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))
68 return;
70 if (errno == EIO
71 && 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
72 return;
75 #endif /* MTIOCTOP */
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);
88 return;
92 /* Write out the record which has been filled. If MOVE_BACK_FLAG,
93 backspace to where we started. */
94 static void
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;
103 flush_write ();
104 archive = STDIN_FILENO;
106 else
108 move_archive ((records_written + records_skipped) - records_read);
109 flush_write ();
112 record_start = save_record;
114 if (move_back_flag)
116 /* Move the tape head back to where we were. */
118 if (! acting_as_filter)
119 move_archive (records_read - (records_written + records_skipped));
122 new_blocks = 0;
125 static void
126 write_recent_blocks (union block *h, size_t blocks)
128 size_t i;
129 for (i = 0; i < blocks; i++)
131 new_record[new_blocks++] = h[i];
132 if (new_blocks == blocking_factor)
133 write_record (1);
137 void
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 :-( */
144 struct name *name;
145 off_t blocks_to_skip = 0;
146 off_t blocks_to_keep = 0;
147 int kept_blocks_in_record;
149 name_gather ();
150 open_archive (ACCESS_UPDATE);
151 acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
155 enum read_header status = read_header (1);
157 switch (status)
159 case HEADER_STILL_UNREAD:
160 abort ();
162 case HEADER_SUCCESS:
163 if (name = name_scan (current_file_name), !name)
165 skip_member ();
166 break;
168 name->found = 1;
169 /* Fall through. */
170 case HEADER_SUCCESS_EXTENDED:
171 logical_status = status;
172 break;
174 case HEADER_ZERO_BLOCK:
175 if (ignore_zeros_option)
177 set_next_block_after (current_header);
178 break;
180 /* Fall through. */
181 case HEADER_END_OF_FILE:
182 logical_status = HEADER_END_OF_FILE;
183 break;
185 case HEADER_FAILURE:
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")));
191 /* Fall through. */
193 case HEADER_SUCCESS:
194 case HEADER_ZERO_BLOCK:
195 ERROR ((0, 0, _("Skipping to next header")));
196 /* Fall through. */
198 case HEADER_FAILURE:
199 break;
201 case HEADER_END_OF_FILE:
202 abort ();
204 break;
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;
222 if (new_blocks)
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;
229 goto flush_file;
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. */
235 while (1)
237 enum read_header status;
239 /* Fill in a record. */
241 if (current_block == record_end)
242 flush_archive ();
243 status = read_header (0);
245 if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
247 set_next_block_after (current_header);
248 continue;
250 if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
252 logical_status = HEADER_END_OF_FILE;
253 break;
256 if (status == HEADER_FAILURE)
258 ERROR ((0, 0, _("Deleting non-header from archive")));
259 set_next_block_after (current_header);
260 continue;
263 /* Found another header. */
265 if (name = name_scan (current_file_name), name)
267 name->found = 1;
268 flush_file:
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);
275 flush_archive ();
277 current_block += blocks_to_skip;
278 blocks_to_skip = 0;
279 continue;
282 /* Copy header. */
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;
287 new_blocks++;
288 blocks_to_keep
289 = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
290 set_next_block_after (current_header);
291 if (new_blocks == blocking_factor)
292 write_record (1);
294 /* Copy data. */
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)
302 int count;
304 if (current_block == record_end)
306 flush_read ();
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;
316 if (! count)
317 abort ();
319 memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
320 new_blocks += count;
321 current_block += count;
322 blocks_to_keep -= count;
323 kept_blocks_in_record -= count;
325 if (new_blocks == blocking_factor)
326 write_record (1);
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);
348 free (new_record);
350 if (! acting_as_filter && ! _isrmt (archive))
352 #if MSDOS
353 int status = write (archive, "", 0);
354 #else
355 off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
356 int status = pos < 0 ? -1 : ftruncate (archive, pos);
357 #endif
358 if (status != 0)
359 truncate_warn (archive_name_array[0]);
362 close_archive ();
363 names_notfound ();