delete.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* Delete entries from a tar archive.
  2. Copyright 1988-2022 Free Software Foundation, Inc.
  3. This file is part of GNU tar.
  4. GNU tar is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. GNU tar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <system.h>
  15. #include "common.h"
  16. #include <rmt.h>
  17. static union block *new_record;
  18. static int new_blocks;
  19. static bool acting_as_filter;
  20. /* FIXME: This module should not directly handle the following
  21. variables, instead, the interface should be cleaned up. */
  22. extern union block *record_start;
  23. extern union block *record_end;
  24. extern union block *current_block;
  25. extern union block *recent_long_name;
  26. extern union block *recent_long_link;
  27. extern off_t records_read;
  28. /* The number of records skipped at the start of the archive, when
  29. passing over members that are not deleted. */
  30. off_t records_skipped;
  31. /* Move archive descriptor by COUNT records worth. If COUNT is
  32. positive we move forward, else we move negative. If it's a tape,
  33. MTIOCTOP had better work. If it's something else, we try to seek
  34. on it. If we can't seek, we lose! */
  35. static void
  36. move_archive (off_t count)
  37. {
  38. if (count == 0)
  39. return;
  40. if (mtioseek (false, count))
  41. return;
  42. off_t position0 = rmtlseek (archive, 0, SEEK_CUR), position = 0;
  43. if (0 <= position0)
  44. {
  45. off_t increment;
  46. if (INT_MULTIPLY_WRAPV (record_size, count, &increment)
  47. || INT_ADD_WRAPV (position0, increment, &position)
  48. || position < 0)
  49. {
  50. ERROR ((0, EOVERFLOW, "lseek: %s", archive_name_array[0]));
  51. return;
  52. }
  53. else if (rmtlseek (archive, position, SEEK_SET) == position)
  54. return;
  55. }
  56. if (!_isrmt (archive))
  57. seek_error_details (archive_name_array[0], position);
  58. }
  59. /* Write out the record which has been filled. If MOVE_BACK_FLAG,
  60. backspace to where we started. */
  61. static void
  62. write_record (int move_back_flag)
  63. {
  64. union block *save_record = record_start;
  65. record_start = new_record;
  66. if (acting_as_filter)
  67. {
  68. archive = STDOUT_FILENO;
  69. flush_write ();
  70. archive = STDIN_FILENO;
  71. }
  72. else
  73. {
  74. move_archive ((records_written + records_skipped) - records_read);
  75. flush_write ();
  76. }
  77. record_start = save_record;
  78. if (move_back_flag)
  79. {
  80. /* Move the tape head back to where we were. */
  81. if (! acting_as_filter)
  82. move_archive (records_read - (records_written + records_skipped));
  83. }
  84. new_blocks = 0;
  85. }
  86. static void
  87. write_recent_blocks (union block *h, size_t blocks)
  88. {
  89. size_t i;
  90. for (i = 0; i < blocks; i++)
  91. {
  92. new_record[new_blocks++] = h[i];
  93. if (new_blocks == blocking_factor)
  94. write_record (1);
  95. }
  96. }
  97. static void
  98. write_recent_bytes (char *data, size_t bytes)
  99. {
  100. size_t blocks = bytes / BLOCKSIZE;
  101. size_t rest = bytes - blocks * BLOCKSIZE;
  102. write_recent_blocks ((union block *)data, blocks);
  103. memcpy (new_record[new_blocks].buffer, data + blocks * BLOCKSIZE, rest);
  104. if (rest < BLOCKSIZE)
  105. memset (new_record[new_blocks].buffer + rest, 0, BLOCKSIZE - rest);
  106. new_blocks++;
  107. if (new_blocks == blocking_factor)
  108. write_record (1);
  109. }
  110. static void
  111. flush_file (void)
  112. {
  113. off_t blocks_to_skip;
  114. set_next_block_after (current_header);
  115. blocks_to_skip = (current_stat_info.stat.st_size
  116. + BLOCKSIZE - 1) / BLOCKSIZE;
  117. while (record_end - current_block <= blocks_to_skip)
  118. {
  119. blocks_to_skip -= (record_end - current_block);
  120. flush_archive ();
  121. }
  122. current_block += blocks_to_skip;
  123. }
  124. void
  125. delete_archive_members (void)
  126. {
  127. enum read_header logical_status = HEADER_STILL_UNREAD;
  128. enum read_header previous_status = HEADER_STILL_UNREAD;
  129. /* FIXME: Should clean the routine before cleaning these variables :-( */
  130. struct name *name;
  131. off_t blocks_to_keep = 0;
  132. int kept_blocks_in_record;
  133. name_gather ();
  134. open_archive (ACCESS_UPDATE);
  135. acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
  136. /* Skip to the first member that matches the name list. */
  137. do
  138. {
  139. enum read_header status = read_header (&current_header,
  140. &current_stat_info,
  141. read_header_x_raw);
  142. switch (status)
  143. {
  144. case HEADER_STILL_UNREAD:
  145. abort ();
  146. case HEADER_SUCCESS:
  147. if ((name = name_scan (current_stat_info.file_name)) == NULL)
  148. {
  149. skip_member ();
  150. break;
  151. }
  152. name->found_count++;
  153. if (!ISFOUND (name))
  154. {
  155. skip_member ();
  156. break;
  157. }
  158. FALLTHROUGH;
  159. case HEADER_SUCCESS_EXTENDED:
  160. logical_status = status;
  161. break;
  162. case HEADER_ZERO_BLOCK:
  163. if (ignore_zeros_option)
  164. {
  165. set_next_block_after (current_header);
  166. break;
  167. }
  168. FALLTHROUGH;
  169. case HEADER_END_OF_FILE:
  170. logical_status = HEADER_END_OF_FILE;
  171. break;
  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. FALLTHROUGH;
  179. case HEADER_SUCCESS:
  180. case HEADER_SUCCESS_EXTENDED:
  181. case HEADER_ZERO_BLOCK:
  182. ERROR ((0, 0, _("Skipping to next header")));
  183. FALLTHROUGH;
  184. case HEADER_FAILURE:
  185. break;
  186. case HEADER_END_OF_FILE:
  187. abort ();
  188. }
  189. break;
  190. }
  191. previous_status = status;
  192. }
  193. while (logical_status == HEADER_STILL_UNREAD);
  194. records_skipped = records_read - 1;
  195. new_record = xmalloc (record_size);
  196. if (logical_status == HEADER_SUCCESS
  197. || logical_status == HEADER_SUCCESS_EXTENDED)
  198. {
  199. write_archive_to_stdout = false;
  200. /* Save away blocks before this one in this record. */
  201. new_blocks = current_block - record_start;
  202. if (new_blocks)
  203. memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
  204. if (logical_status == HEADER_SUCCESS)
  205. {
  206. logical_status = HEADER_STILL_UNREAD;
  207. flush_file ();
  208. }
  209. /* Skip matching members and move the rest up the archive. */
  210. while (logical_status != HEADER_END_OF_FILE)
  211. {
  212. enum read_header status;
  213. /* Fill in a record. */
  214. if (current_block == record_end)
  215. flush_archive ();
  216. status = read_header (&current_header, &current_stat_info,
  217. read_header_auto);
  218. switch (status)
  219. {
  220. case HEADER_STILL_UNREAD:
  221. case HEADER_SUCCESS_EXTENDED:
  222. abort ();
  223. case HEADER_SUCCESS:
  224. /* Found another header. */
  225. xheader_decode (&current_stat_info);
  226. if ((name = name_scan (current_stat_info.file_name)) != NULL)
  227. {
  228. name->found_count++;
  229. if (ISFOUND (name))
  230. {
  231. flush_file ();
  232. break;
  233. }
  234. }
  235. /* Copy header. */
  236. if (current_stat_info.xhdr.size)
  237. {
  238. write_recent_bytes (current_stat_info.xhdr.buffer,
  239. current_stat_info.xhdr.size);
  240. }
  241. else
  242. {
  243. write_recent_blocks (recent_long_name,
  244. recent_long_name_blocks);
  245. write_recent_blocks (recent_long_link,
  246. recent_long_link_blocks);
  247. }
  248. new_record[new_blocks] = *current_header;
  249. new_blocks++;
  250. blocks_to_keep
  251. = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
  252. set_next_block_after (current_header);
  253. if (new_blocks == blocking_factor)
  254. write_record (1);
  255. /* Copy data. */
  256. kept_blocks_in_record = record_end - current_block;
  257. if (kept_blocks_in_record > blocks_to_keep)
  258. kept_blocks_in_record = blocks_to_keep;
  259. while (blocks_to_keep)
  260. {
  261. int count;
  262. if (current_block == record_end)
  263. {
  264. flush_read ();
  265. current_block = record_start;
  266. kept_blocks_in_record = blocking_factor;
  267. if (kept_blocks_in_record > blocks_to_keep)
  268. kept_blocks_in_record = blocks_to_keep;
  269. }
  270. count = kept_blocks_in_record;
  271. if (blocking_factor - new_blocks < count)
  272. count = blocking_factor - new_blocks;
  273. if (! count)
  274. abort ();
  275. memcpy (new_record + new_blocks, current_block,
  276. count * BLOCKSIZE);
  277. new_blocks += count;
  278. current_block += count;
  279. blocks_to_keep -= count;
  280. kept_blocks_in_record -= count;
  281. if (new_blocks == blocking_factor)
  282. write_record (1);
  283. }
  284. break;
  285. case HEADER_ZERO_BLOCK:
  286. if (ignore_zeros_option)
  287. set_next_block_after (current_header);
  288. else
  289. logical_status = HEADER_END_OF_FILE;
  290. break;
  291. case HEADER_END_OF_FILE:
  292. logical_status = HEADER_END_OF_FILE;
  293. break;
  294. case HEADER_FAILURE:
  295. ERROR ((0, 0, _("Deleting non-header from archive")));
  296. set_next_block_after (current_header);
  297. break;
  298. default:
  299. abort ();
  300. }
  301. tar_stat_destroy (&current_stat_info);
  302. }
  303. if (logical_status == HEADER_END_OF_FILE)
  304. {
  305. /* Write the end of tape. FIXME: we can't use write_eot here,
  306. as it gets confused when the input is at end of file. */
  307. int total_zero_blocks = 0;
  308. do
  309. {
  310. int zero_blocks = blocking_factor - new_blocks;
  311. memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
  312. total_zero_blocks += zero_blocks;
  313. write_record (total_zero_blocks < 2);
  314. }
  315. while (total_zero_blocks < 2);
  316. }
  317. if (! acting_as_filter && ! _isrmt (archive))
  318. {
  319. if (sys_truncate (archive))
  320. truncate_warn (archive_name_array[0]);
  321. }
  322. }
  323. free (new_record);
  324. close_archive ();
  325. names_notfound ();
  326. }