]> git.ipfire.org Git - thirdparty/tar.git/blame - src/delete.c
Use stdopen from gnulib
[thirdparty/tar.git] / src / delete.c
CommitLineData
3e3d9b7e 1/* Delete entries from a tar archive.
d858a433 2
afa743ac 3 Copyright 1988-2021 Free Software Foundation, Inc.
3e3d9b7e 4
cd7bdd40 5 This file is part of GNU tar.
3e3d9b7e 6
cd7bdd40
PE
7 GNU tar is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
3e3d9b7e 11
cd7bdd40
PE
12 GNU tar is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
3e3d9b7e 19
7347b4f5 20#include <system.h>
f2bf9f2f 21#include <system-ioctl.h>
3e3d9b7e 22
3e3d9b7e 23#include "common.h"
7347b4f5 24#include <rmt.h>
3e3d9b7e 25
d858a433
SP
26static union block *new_record;
27static int new_blocks;
28static bool acting_as_filter;
3e3d9b7e 29
d858a433
SP
30/* FIXME: This module should not directly handle the following
31 variables, instead, the interface should be cleaned up. */
3e3d9b7e
PE
32extern union block *record_start;
33extern union block *record_end;
34extern union block *current_block;
d858a433
SP
35extern union block *recent_long_name;
36extern union block *recent_long_link;
f2bf9f2f 37extern off_t records_read;
d858a433
SP
38
39/* The number of records skipped at the start of the archive, when
40 passing over members that are not deleted. */
05b250d4 41off_t records_skipped;
d858a433
SP
42
43/* Move archive descriptor by COUNT records worth. If COUNT is
44 positive we move forward, else we move negative. If it's a tape,
45 MTIOCTOP had better work. If it's something else, we try to seek
46 on it. If we can't seek, we lose! */
3e3d9b7e 47static void
d858a433 48move_archive (off_t count)
3e3d9b7e 49{
d858a433
SP
50 if (count == 0)
51 return;
52
3e3d9b7e
PE
53#ifdef MTIOCTOP
54 {
55 struct mtop operation;
3e3d9b7e 56
d858a433
SP
57 if (count < 0
58 ? (operation.mt_op = MTBSR,
59 operation.mt_count = -count,
60 operation.mt_count == -count)
61 : (operation.mt_op = MTFSR,
62 operation.mt_count = count,
63 operation.mt_count == count))
3e3d9b7e 64 {
d858a433
SP
65 if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
66 return;
3e3d9b7e 67
d858a433
SP
68 if (errno == EIO
69 && 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
70 return;
71 }
3e3d9b7e
PE
72 }
73#endif /* MTIOCTOP */
74
75 {
d858a433
SP
76 off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
77 off_t increment = record_size * (off_t) count;
78 off_t position = position0 + increment;
3e3d9b7e 79
d858a433
SP
80 if (increment / count != record_size
81 || (position < position0) != (increment < 0)
82 || (position = position < 0 ? 0 : position,
83 rmtlseek (archive, position, SEEK_SET) != position))
84 seek_error_details (archive_name_array[0], position);
3e3d9b7e
PE
85
86 return;
87 }
88}
89
d858a433
SP
90/* Write out the record which has been filled. If MOVE_BACK_FLAG,
91 backspace to where we started. */
3e3d9b7e
PE
92static void
93write_record (int move_back_flag)
94{
d858a433 95 union block *save_record = record_start;
3e3d9b7e
PE
96 record_start = new_record;
97
d858a433 98 if (acting_as_filter)
3e3d9b7e 99 {
d858a433 100 archive = STDOUT_FILENO;
3e3d9b7e 101 flush_write ();
d858a433 102 archive = STDIN_FILENO;
3e3d9b7e
PE
103 }
104 else
105 {
d858a433 106 move_archive ((records_written + records_skipped) - records_read);
3e3d9b7e
PE
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
d858a433
SP
116 if (! acting_as_filter)
117 move_archive (records_read - (records_written + records_skipped));
3e3d9b7e
PE
118 }
119
3e3d9b7e
PE
120 new_blocks = 0;
121}
122
d858a433
SP
123static void
124write_recent_blocks (union block *h, size_t blocks)
125{
126 size_t i;
127 for (i = 0; i < blocks; i++)
128 {
129 new_record[new_blocks++] = h[i];
130 if (new_blocks == blocking_factor)
131 write_record (1);
132 }
133}
3e3d9b7e 134
08780d28
SP
135static void
136write_recent_bytes (char *data, size_t bytes)
137{
138 size_t blocks = bytes / BLOCKSIZE;
139 size_t rest = bytes - blocks * BLOCKSIZE;
140
141 write_recent_blocks ((union block *)data, blocks);
142 memcpy (new_record[new_blocks].buffer, data + blocks * BLOCKSIZE, rest);
143 if (rest < BLOCKSIZE)
144 memset (new_record[new_blocks].buffer + rest, 0, BLOCKSIZE - rest);
145 new_blocks++;
146 if (new_blocks == blocking_factor)
147 write_record (1);
148}
149
3e3d9b7e
PE
150void
151delete_archive_members (void)
152{
153 enum read_header logical_status = HEADER_STILL_UNREAD;
154 enum read_header previous_status = HEADER_STILL_UNREAD;
155
156 /* FIXME: Should clean the routine before cleaning these variables :-( */
157 struct name *name;
d858a433
SP
158 off_t blocks_to_skip = 0;
159 off_t blocks_to_keep = 0;
3e3d9b7e
PE
160 int kept_blocks_in_record;
161
162 name_gather ();
163 open_archive (ACCESS_UPDATE);
d858a433 164 acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
3e3d9b7e 165
d858a433 166 do
3e3d9b7e 167 {
166b7c7d
SP
168 enum read_header status = read_header (&current_header,
169 &current_stat_info,
c3fa22fc 170 read_header_x_raw);
3e3d9b7e
PE
171
172 switch (status)
173 {
174 case HEADER_STILL_UNREAD:
175 abort ();
176
177 case HEADER_SUCCESS:
6d1e9ab6 178 if ((name = name_scan (current_stat_info.file_name)) == NULL)
3e3d9b7e 179 {
d858a433 180 skip_member ();
3e3d9b7e
PE
181 break;
182 }
f4935ab5
SP
183 name->found_count++;
184 if (!ISFOUND(name))
185 {
186 skip_member ();
187 break;
188 }
d44d5920 189 FALLTHROUGH;
d858a433
SP
190 case HEADER_SUCCESS_EXTENDED:
191 logical_status = status;
3e3d9b7e
PE
192 break;
193
194 case HEADER_ZERO_BLOCK:
d858a433
SP
195 if (ignore_zeros_option)
196 {
197 set_next_block_after (current_header);
198 break;
199 }
d44d5920 200 FALLTHROUGH;
3e3d9b7e
PE
201 case HEADER_END_OF_FILE:
202 logical_status = HEADER_END_OF_FILE;
203 break;
204
205 case HEADER_FAILURE:
206 set_next_block_after (current_header);
207 switch (previous_status)
208 {
209 case HEADER_STILL_UNREAD:
210 WARN ((0, 0, _("This does not look like a tar archive")));
d44d5920 211 FALLTHROUGH;
3e3d9b7e 212 case HEADER_SUCCESS:
86a9b926 213 case HEADER_SUCCESS_EXTENDED:
3e3d9b7e
PE
214 case HEADER_ZERO_BLOCK:
215 ERROR ((0, 0, _("Skipping to next header")));
d44d5920 216 FALLTHROUGH;
3e3d9b7e
PE
217 case HEADER_FAILURE:
218 break;
219
220 case HEADER_END_OF_FILE:
221 abort ();
222 }
223 break;
224 }
225
226 previous_status = status;
227 }
d858a433 228 while (logical_status == HEADER_STILL_UNREAD);
3e3d9b7e 229
d858a433
SP
230 records_skipped = records_read - 1;
231 new_record = xmalloc (record_size);
3e3d9b7e 232
d858a433
SP
233 if (logical_status == HEADER_SUCCESS
234 || logical_status == HEADER_SUCCESS_EXTENDED)
3e3d9b7e 235 {
829b1dc3 236 write_archive_to_stdout = false;
3e3d9b7e 237
d858a433 238 /* Save away blocks before this one in this record. */
3e3d9b7e 239
d858a433
SP
240 new_blocks = current_block - record_start;
241 if (new_blocks)
242 memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
3e3d9b7e 243
d858a433 244 if (logical_status == HEADER_SUCCESS)
3e3d9b7e 245 {
d858a433
SP
246 /* FIXME: Pheew! This is crufty code! */
247 logical_status = HEADER_STILL_UNREAD;
248 goto flush_file;
3e3d9b7e
PE
249 }
250
d858a433
SP
251 /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
252 "delete.c", line 223: warning: loop not entered at top
253 Reported by Bruno Haible. */
254 while (1)
3e3d9b7e 255 {
d858a433 256 enum read_header status;
3e3d9b7e 257
d858a433 258 /* Fill in a record. */
3e3d9b7e 259
d858a433
SP
260 if (current_block == record_end)
261 flush_archive ();
0ab5e64a 262 status = read_header (&current_header, &current_stat_info,
c3fa22fc 263 read_header_auto);
f2bf9f2f 264
64cca92a 265 xheader_decode (&current_stat_info);
f2bf9f2f 266
d858a433 267 if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
3e3d9b7e 268 {
d858a433
SP
269 set_next_block_after (current_header);
270 continue;
271 }
272 if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
273 {
274 logical_status = HEADER_END_OF_FILE;
275 break;
3e3d9b7e 276 }
3e3d9b7e 277
d858a433
SP
278 if (status == HEADER_FAILURE)
279 {
280 ERROR ((0, 0, _("Deleting non-header from archive")));
281 set_next_block_after (current_header);
282 continue;
283 }
3e3d9b7e 284
d858a433
SP
285 /* Found another header. */
286
6d1e9ab6 287 if ((name = name_scan (current_stat_info.file_name)) != NULL)
d858a433 288 {
f4935ab5
SP
289 name->found_count++;
290 if (ISFOUND(name))
d858a433 291 {
f4935ab5
SP
292 flush_file:
293 set_next_block_after (current_header);
294 blocks_to_skip = (current_stat_info.stat.st_size
295 + BLOCKSIZE - 1) / BLOCKSIZE;
0ab5e64a 296
f4935ab5
SP
297 while (record_end - current_block <= blocks_to_skip)
298 {
299 blocks_to_skip -= (record_end - current_block);
300 flush_archive ();
301 }
302 current_block += blocks_to_skip;
303 blocks_to_skip = 0;
304 continue;
d858a433 305 }
d858a433 306 }
d858a433 307 /* Copy header. */
3e3d9b7e 308
250db35f 309 if (current_stat_info.xhdr.size)
08780d28 310 {
250db35f
SP
311 write_recent_bytes (current_stat_info.xhdr.buffer,
312 current_stat_info.xhdr.size);
08780d28
SP
313 }
314 else
315 {
316 write_recent_blocks (recent_long_name, recent_long_name_blocks);
317 write_recent_blocks (recent_long_link, recent_long_link_blocks);
318 }
d858a433
SP
319 new_record[new_blocks] = *current_header;
320 new_blocks++;
321 blocks_to_keep
322 = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
323 set_next_block_after (current_header);
324 if (new_blocks == blocking_factor)
325 write_record (1);
3e3d9b7e 326
d858a433 327 /* Copy data. */
3e3d9b7e 328
d858a433
SP
329 kept_blocks_in_record = record_end - current_block;
330 if (kept_blocks_in_record > blocks_to_keep)
331 kept_blocks_in_record = blocks_to_keep;
332
333 while (blocks_to_keep)
3e3d9b7e 334 {
d858a433
SP
335 int count;
336
337 if (current_block == record_end)
338 {
339 flush_read ();
340 current_block = record_start;
341 kept_blocks_in_record = blocking_factor;
342 if (kept_blocks_in_record > blocks_to_keep)
343 kept_blocks_in_record = blocks_to_keep;
344 }
345 count = kept_blocks_in_record;
346 if (blocking_factor - new_blocks < count)
347 count = blocking_factor - new_blocks;
348
349 if (! count)
350 abort ();
351
352 memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
353 new_blocks += count;
354 current_block += count;
355 blocks_to_keep -= count;
356 kept_blocks_in_record -= count;
357
358 if (new_blocks == blocking_factor)
359 write_record (1);
3e3d9b7e 360 }
3e3d9b7e 361 }
3e3d9b7e 362
e6a67c2e
SP
363 if (logical_status == HEADER_END_OF_FILE)
364 {
365 /* Write the end of tape. FIXME: we can't use write_eot here,
366 as it gets confused when the input is at end of file. */
d858a433 367
e6a67c2e 368 int total_zero_blocks = 0;
d858a433 369
e6a67c2e
SP
370 do
371 {
372 int zero_blocks = blocking_factor - new_blocks;
373 memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
374 total_zero_blocks += zero_blocks;
375 write_record (total_zero_blocks < 2);
376 }
377 while (total_zero_blocks < 2);
378 }
379
380 if (! acting_as_filter && ! _isrmt (archive))
d858a433 381 {
e6a67c2e
SP
382 if (sys_truncate (archive))
383 truncate_warn (archive_name_array[0]);
d858a433 384 }
d858a433 385 }
d858a433
SP
386 free (new_record);
387
3e3d9b7e
PE
388 close_archive ();
389 names_notfound ();
390}