]> Dogcows Code - chaz/tar/commitdiff
GNU tar 1.12
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 25 Apr 1997 17:10:08 +0000 (17:10 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 25 Apr 1997 17:10:08 +0000 (17:10 +0000)
src/delete.c [new file with mode: 0644]

diff --git a/src/delete.c b/src/delete.c
new file mode 100644 (file)
index 0000000..4cb73b3
--- /dev/null
@@ -0,0 +1,336 @@
+/* Delete entries from a tar archive.
+   Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+   Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "system.h"
+
+#define STDIN 0
+#define STDOUT 1
+
+#include "common.h"
+#include "rmt.h"
+
+static union block *new_record = NULL;
+static union block *save_record = NULL;
+static int records_read = 0;
+static int new_blocks = 0;
+static int blocks_needed = 0;
+
+/* FIXME: This module should not directly handle the following three
+   variables, instead, this should be done in buffer.c only.  */
+extern union block *record_start;
+extern union block *record_end;
+extern union block *current_block;
+
+/*-------------------------------------------------------------------------.
+| Move archive descriptor by COUNT records worth.  If COUNT is positive we |
+| move forward, else we move negative.  If its a tape, MTIOCTOP had better |
+| work.  If its something else, we try to seek on it.  If we can't seek,   |
+| we loose!                                                               |
+`-------------------------------------------------------------------------*/
+
+static void
+move_archive (int count)
+{
+#ifdef MTIOCTOP
+  {
+    struct mtop operation;
+    int status;
+
+    if (count > 0)
+      {
+       operation.mt_op = MTFSR;
+       operation.mt_count = count;
+      }
+    else
+      {
+       operation.mt_op = MTBSR;
+       operation.mt_count = -count;
+      }
+
+    if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
+       status >= 0)
+      return;
+
+    if (errno == EIO)
+      if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
+         status >= 0)
+      return;
+  }
+#endif /* MTIOCTOP */
+
+  {
+    off_t position = rmtlseek (archive, 0L, 1);
+
+    position += record_size * count;
+
+    if (rmtlseek (archive, position, 0) != position)
+      FATAL_ERROR ((0, 0, _("Could not re-position archive file")));
+
+    return;
+  }
+}
+
+/*----------------------------------------------------------------.
+| Write out the record which has been filled.  If MOVE_BACK_FLAG, |
+| backspace to where we started.                                  |
+`----------------------------------------------------------------*/
+
+static void
+write_record (int move_back_flag)
+{
+  save_record = record_start;
+  record_start = new_record;
+
+  if (archive == STDIN)
+    {
+      archive = STDOUT;
+      flush_write ();
+      archive = STDIN;
+    }
+  else
+    {
+      move_archive (-(records_read + 1));
+      flush_write ();
+    }
+
+  record_start = save_record;
+
+  if (move_back_flag)
+    {
+      /* Move the tape head back to where we were.  */
+
+      if (archive != STDIN)
+       move_archive (records_read);
+
+      records_read--;
+    }
+
+  blocks_needed = blocking_factor;
+  new_blocks = 0;
+}
+
+/*---.
+| ?  |
+`---*/
+
+void
+delete_archive_members (void)
+{
+  enum read_header logical_status = HEADER_STILL_UNREAD;
+  enum read_header previous_status = HEADER_STILL_UNREAD;
+
+  /* FIXME: Should clean the routine before cleaning these variables :-( */
+  struct name *name;
+  int blocks_to_skip = 0;
+  int blocks_to_keep = 0;
+  int kept_blocks_in_record;
+
+  name_gather ();
+  open_archive (ACCESS_UPDATE);
+
+  while (logical_status == HEADER_STILL_UNREAD)
+    {
+      enum read_header status = read_header ();
+
+      switch (status)
+       {
+       case HEADER_STILL_UNREAD:
+         abort ();
+
+       case HEADER_SUCCESS:
+         if (name = name_scan (current_file_name), !name)
+           {
+             set_next_block_after (current_header);
+             if (current_header->oldgnu_header.isextended)
+               skip_extended_headers ();
+             skip_file ((long) (current_stat.st_size));
+             break;
+           }
+         name->found = 1;
+         logical_status = HEADER_SUCCESS;
+         break;
+
+       case HEADER_ZERO_BLOCK:
+       case HEADER_END_OF_FILE:
+         logical_status = HEADER_END_OF_FILE;
+         break;
+
+       case HEADER_FAILURE:
+         set_next_block_after (current_header);
+         switch (previous_status)
+           {
+           case HEADER_STILL_UNREAD:
+             WARN ((0, 0, _("This does not look like a tar archive")));
+             /* Fall through.  */
+
+           case HEADER_SUCCESS:
+           case HEADER_ZERO_BLOCK:
+             ERROR ((0, 0, _("Skipping to next header")));
+             /* Fall through.  */
+
+           case HEADER_FAILURE:
+             break;
+
+           case HEADER_END_OF_FILE:
+             abort ();
+           }
+         break;
+       }
+
+      previous_status = status;
+    }
+
+  if (logical_status != HEADER_SUCCESS)
+    {
+      write_eot ();
+      close_archive ();
+      names_notfound ();
+      return;
+    }
+
+  write_archive_to_stdout = 0;
+  new_record = (union block *) xmalloc ((size_t) record_size);
+
+  /* Save away blocks before this one in this record.  */
+
+  new_blocks = current_block - record_start;
+  blocks_needed = blocking_factor - new_blocks;
+  if (new_blocks)
+    memcpy ((void *) new_record, (void *) record_start,
+          (size_t) (new_blocks * BLOCKSIZE));
+
+#if 0
+  /* FIXME: Old code, before the goto was inserted.  To be redesigned.  */
+  set_next_block_after (current_header);
+  if (current_header->oldgnu_header.isextended)
+    skip_extended_headers ();
+  skip_file ((long) (current_stat.st_size));
+#endif
+  logical_status = HEADER_STILL_UNREAD;
+  goto flush_file;
+
+  /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
+       "delete.c", line 223: warning: loop not entered at top
+     Reported by Bruno Haible.  */
+  while (1)
+    {
+      enum read_header status;
+
+      /* Fill in a record.  */
+
+      if (current_block == record_end)
+       {
+         flush_archive ();
+         records_read++;
+       }
+      status = read_header ();
+
+      if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
+       {
+         set_next_block_after (current_header);
+         continue;
+       }
+      if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
+       {
+         logical_status = HEADER_END_OF_FILE;
+         memset (new_record[new_blocks].buffer, 0,
+                (size_t) (BLOCKSIZE * blocks_needed));
+         new_blocks += blocks_needed;
+         blocks_needed = 0;
+         write_record (0);
+         break;
+       }
+
+      if (status == HEADER_FAILURE)
+       {
+         ERROR ((0, 0, _("Deleting non-header from archive")));
+         set_next_block_after (current_header);
+         continue;
+       }
+
+      /* Found another header.  */
+
+      if (name = name_scan (current_file_name), name)
+       {
+         name->found = 1;
+       flush_file:
+         set_next_block_after (current_header);
+         blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
+
+         while (record_end - current_block <= blocks_to_skip)
+           {
+             blocks_to_skip -= (record_end - current_block);
+             flush_archive ();
+             records_read++;
+           }
+         current_block += blocks_to_skip;
+         blocks_to_skip = 0;
+         continue;
+       }
+
+      /* Copy header.  */
+
+      new_record[new_blocks] = *current_header;
+      new_blocks++;
+      blocks_needed--;
+      blocks_to_keep
+       = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
+      set_next_block_after (current_header);
+      if (blocks_needed == 0)
+       write_record (1);
+
+      /* Copy data.  */
+
+      kept_blocks_in_record = record_end - current_block;
+      if (kept_blocks_in_record > blocks_to_keep)
+       kept_blocks_in_record = blocks_to_keep;
+
+      while (blocks_to_keep)
+       {
+         int count;
+
+         if (current_block == record_end)
+           {
+             flush_read ();
+             records_read++;
+             current_block = record_start;
+             kept_blocks_in_record = blocking_factor;
+             if (kept_blocks_in_record > blocks_to_keep)
+               kept_blocks_in_record = blocks_to_keep;
+           }
+         count = kept_blocks_in_record;
+         if (count > blocks_needed)
+           count = blocks_needed;
+
+         memcpy ((void *) (new_record + new_blocks),
+                 (void *) current_block,
+                 (size_t) (count * BLOCKSIZE));
+         new_blocks += count;
+         blocks_needed -= count;
+         current_block += count;
+         blocks_to_keep -= count;
+         kept_blocks_in_record -= count;
+
+         if (blocks_needed == 0)
+           write_record (1);
+       }
+    }
+
+  write_eot ();
+  close_archive ();
+  names_notfound ();
+}
This page took 0.03318 seconds and 4 git commands to generate.