(print_total_written): Use a format compatible with
[debian/tar] / src / delete.c
1 /* Delete entries from a tar archive.
2    Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 2, or (at your option) any later
7    version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
12    Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include "system.h"
19
20 #define STDIN 0
21 #define STDOUT 1
22
23 #include "common.h"
24 #include "rmt.h"
25
26 static union block *new_record = NULL;
27 static union block *save_record = NULL;
28 static int records_read = 0;
29 static int new_blocks = 0;
30 static int blocks_needed = 0;
31
32 /* FIXME: This module should not directly handle the following three
33    variables, instead, this should be done in buffer.c only.  */
34 extern union block *record_start;
35 extern union block *record_end;
36 extern union block *current_block;
37
38 /*-------------------------------------------------------------------------.
39 | Move archive descriptor by COUNT records worth.  If COUNT is positive we |
40 | move forward, else we move negative.  If its a tape, MTIOCTOP had better |
41 | work.  If its something else, we try to seek on it.  If we can't seek,   |
42 | we loose!                                                                |
43 `-------------------------------------------------------------------------*/
44
45 static void
46 move_archive (int count)
47 {
48 #ifdef MTIOCTOP
49   {
50     struct mtop operation;
51     int status;
52
53     if (count > 0)
54       {
55         operation.mt_op = MTFSR;
56         operation.mt_count = count;
57       }
58     else
59       {
60         operation.mt_op = MTBSR;
61         operation.mt_count = -count;
62       }
63
64     if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
65         status >= 0)
66       return;
67
68     if (errno == EIO)
69       if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
70           status >= 0)
71       return;
72   }
73 #endif /* MTIOCTOP */
74
75   {
76     off_t position = rmtlseek (archive, 0L, 1);
77
78     position += record_size * count;
79
80     if (rmtlseek (archive, position, 0) != position)
81       FATAL_ERROR ((0, 0, _("Could not re-position archive file")));
82
83     return;
84   }
85 }
86
87 /*----------------------------------------------------------------.
88 | Write out the record which has been filled.  If MOVE_BACK_FLAG, |
89 | backspace to where we started.                                  |
90 `----------------------------------------------------------------*/
91
92 static void
93 write_record (int move_back_flag)
94 {
95   save_record = record_start;
96   record_start = new_record;
97
98   if (archive == STDIN)
99     {
100       archive = STDOUT;
101       flush_write ();
102       archive = STDIN;
103     }
104   else
105     {
106       move_archive (-(records_read + 1));
107       flush_write ();
108     }
109
110   record_start = save_record;
111
112   if (move_back_flag)
113     {
114       /* Move the tape head back to where we were.  */
115
116       if (archive != STDIN)
117         move_archive (records_read);
118
119       records_read--;
120     }
121
122   blocks_needed = blocking_factor;
123   new_blocks = 0;
124 }
125
126 /*---.
127 | ?  |
128 `---*/
129
130 void
131 delete_archive_members (void)
132 {
133   enum read_header logical_status = HEADER_STILL_UNREAD;
134   enum read_header previous_status = HEADER_STILL_UNREAD;
135
136   /* FIXME: Should clean the routine before cleaning these variables :-( */
137   struct name *name;
138   int blocks_to_skip = 0;
139   int blocks_to_keep = 0;
140   int kept_blocks_in_record;
141
142   name_gather ();
143   open_archive (ACCESS_UPDATE);
144
145   while (logical_status == HEADER_STILL_UNREAD)
146     {
147       enum read_header status = read_header ();
148
149       switch (status)
150         {
151         case HEADER_STILL_UNREAD:
152           abort ();
153
154         case HEADER_SUCCESS:
155           if (name = name_scan (current_file_name), !name)
156             {
157               set_next_block_after (current_header);
158               if (current_header->oldgnu_header.isextended)
159                 skip_extended_headers ();
160               skip_file ((long) (current_stat.st_size));
161               break;
162             }
163           name->found = 1;
164           logical_status = HEADER_SUCCESS;
165           break;
166
167         case HEADER_ZERO_BLOCK:
168         case HEADER_END_OF_FILE:
169           logical_status = HEADER_END_OF_FILE;
170           break;
171
172         case HEADER_FAILURE:
173           set_next_block_after (current_header);
174           switch (previous_status)
175             {
176             case HEADER_STILL_UNREAD:
177               WARN ((0, 0, _("This does not look like a tar archive")));
178               /* Fall through.  */
179
180             case HEADER_SUCCESS:
181             case HEADER_ZERO_BLOCK:
182               ERROR ((0, 0, _("Skipping to next header")));
183               /* Fall through.  */
184
185             case HEADER_FAILURE:
186               break;
187
188             case HEADER_END_OF_FILE:
189               abort ();
190             }
191           break;
192         }
193
194       previous_status = status;
195     }
196
197   if (logical_status != HEADER_SUCCESS)
198     {
199       write_eot ();
200       close_archive ();
201       names_notfound ();
202       return;
203     }
204
205   write_archive_to_stdout = 0;
206   new_record = (union block *) xmalloc ((size_t) record_size);
207
208   /* Save away blocks before this one in this record.  */
209
210   new_blocks = current_block - record_start;
211   blocks_needed = blocking_factor - new_blocks;
212   if (new_blocks)
213     memcpy ((void *) new_record, (void *) record_start,
214            (size_t) (new_blocks * BLOCKSIZE));
215
216 #if 0
217   /* FIXME: Old code, before the goto was inserted.  To be redesigned.  */
218   set_next_block_after (current_header);
219   if (current_header->oldgnu_header.isextended)
220     skip_extended_headers ();
221   skip_file ((long) (current_stat.st_size));
222 #endif
223   logical_status = HEADER_STILL_UNREAD;
224   goto flush_file;
225
226   /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
227        "delete.c", line 223: warning: loop not entered at top
228      Reported by Bruno Haible.  */
229   while (1)
230     {
231       enum read_header status;
232
233       /* Fill in a record.  */
234
235       if (current_block == record_end)
236         {
237           flush_archive ();
238           records_read++;
239         }
240       status = read_header ();
241
242       if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
243         {
244           set_next_block_after (current_header);
245           continue;
246         }
247       if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
248         {
249           logical_status = HEADER_END_OF_FILE;
250           memset (new_record[new_blocks].buffer, 0,
251                  (size_t) (BLOCKSIZE * blocks_needed));
252           new_blocks += blocks_needed;
253           blocks_needed = 0;
254           write_record (0);
255           break;
256         }
257
258       if (status == HEADER_FAILURE)
259         {
260           ERROR ((0, 0, _("Deleting non-header from archive")));
261           set_next_block_after (current_header);
262           continue;
263         }
264
265       /* Found another header.  */
266
267       if (name = name_scan (current_file_name), name)
268         {
269           name->found = 1;
270         flush_file:
271           set_next_block_after (current_header);
272           blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
273
274           while (record_end - current_block <= blocks_to_skip)
275             {
276               blocks_to_skip -= (record_end - current_block);
277               flush_archive ();
278               records_read++;
279             }
280           current_block += blocks_to_skip;
281           blocks_to_skip = 0;
282           continue;
283         }
284
285       /* Copy header.  */
286
287       new_record[new_blocks] = *current_header;
288       new_blocks++;
289       blocks_needed--;
290       blocks_to_keep
291         = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
292       set_next_block_after (current_header);
293       if (blocks_needed == 0)
294         write_record (1);
295
296       /* Copy data.  */
297
298       kept_blocks_in_record = record_end - current_block;
299       if (kept_blocks_in_record > blocks_to_keep)
300         kept_blocks_in_record = blocks_to_keep;
301
302       while (blocks_to_keep)
303         {
304           int count;
305
306           if (current_block == record_end)
307             {
308               flush_read ();
309               records_read++;
310               current_block = record_start;
311               kept_blocks_in_record = blocking_factor;
312               if (kept_blocks_in_record > blocks_to_keep)
313                 kept_blocks_in_record = blocks_to_keep;
314             }
315           count = kept_blocks_in_record;
316           if (count > blocks_needed)
317             count = blocks_needed;
318
319           memcpy ((void *) (new_record + new_blocks),
320                   (void *) current_block,
321                   (size_t) (count * BLOCKSIZE));
322           new_blocks += count;
323           blocks_needed -= count;
324           current_block += count;
325           blocks_to_keep -= count;
326           kept_blocks_in_record -= count;
327
328           if (blocks_needed == 0)
329             write_record (1);
330         }
331     }
332
333   write_eot ();
334   close_archive ();
335   names_notfound ();
336 }