(root)/
tar-1.35/
src/
update.c
       1  /* Update a tar archive.
       2  
       3     Copyright 1988-2023 Free Software Foundation, Inc.
       4  
       5     This file is part of GNU tar.
       6  
       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.
      11  
      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/>.  */
      19  
      20  /* Implement the 'r', 'u' and 'A' options for tar.  'A' means that the
      21     file names are tar files, and they should simply be appended to the end
      22     of the archive.  No attempt is made to record the reads from the args; if
      23     they're on raw tape or something like that, it'll probably lose...  */
      24  
      25  #include <system.h>
      26  #include <quotearg.h>
      27  #include "common.h"
      28  
      29  /* FIXME: This module should not directly handle the following variable,
      30     instead, this should be done in buffer.c only.  */
      31  extern union block *current_block;
      32  
      33  /* We've hit the end of the old stuff, and its time to start writing new
      34     stuff to the tape.  This involves seeking back one record and
      35     re-writing the current record (which has been changed).
      36     FIXME: Either eliminate it or move it to common.h.
      37  */
      38  bool time_to_start_writing;
      39  
      40  /* Pointer to where we started to write in the first record we write out.
      41     This is used if we can't backspace the output and have to null out the
      42     first part of the record.  */
      43  char *output_start;
      44  
      45  static bool acting_as_filter;
      46  
      47  /* Catenate file FILE_NAME to the archive without creating a header for it.
      48     It had better be a tar file or the archive is screwed.  */
      49  static void
      50  append_file (char *file_name)
      51  {
      52    int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
      53  
      54    if (handle < 0)
      55      {
      56        open_error (file_name);
      57        return;
      58      }
      59  
      60    while (true)
      61      {
      62        union block *start = find_next_block ();
      63        size_t status = full_read (handle, start->buffer,
      64  				 available_space_after (start));
      65        if (status == 0)
      66  	{
      67  	  if (errno == 0)
      68  	    break;
      69  	  read_fatal (file_name);
      70  	}
      71        if (status == SAFE_READ_ERROR)
      72  	read_fatal (file_name);
      73        if (status % BLOCKSIZE)
      74  	memset (start->buffer + status - status % BLOCKSIZE, 0,
      75  		BLOCKSIZE - status % BLOCKSIZE);
      76        set_next_block_after (start + (status - 1) / BLOCKSIZE);
      77      }
      78  
      79    if (close (handle) != 0)
      80      close_error (file_name);
      81  }
      82  
      83  /* If NAME is not a pattern, remove it from the namelist.  Otherwise,
      84     remove the FILE_NAME that matched it.  Take care to look for exact
      85     match when removing it. */
      86  static void
      87  remove_exact_name (struct name *name, char const *file_name)
      88  {
      89    if (name->is_wildcard)
      90      {
      91        struct name *match = name_scan (file_name, true);
      92        name->found_count++;
      93        if (match)
      94  	name = match;
      95        else
      96  	return;
      97      }
      98  
      99    remname (name);
     100  }
     101  
     102  /* Implement the 'r' (add files to end of archive), and 'u' (add files
     103     to end of archive if they aren't there, or are more up to date than
     104     the version in the archive) commands.  */
     105  void
     106  update_archive (void)
     107  {
     108    enum read_header previous_status = HEADER_STILL_UNREAD;
     109    bool found_end = false;
     110  
     111    name_gather ();
     112    open_archive (ACCESS_UPDATE);
     113    acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
     114    xheader_forbid_global ();
     115  
     116    while (!found_end)
     117      {
     118        enum read_header status = read_header (&current_header,
     119                                               &current_stat_info,
     120                                               read_header_auto);
     121  
     122        switch (status)
     123  	{
     124  	case HEADER_STILL_UNREAD:
     125  	case HEADER_SUCCESS_EXTENDED:
     126  	  abort ();
     127  
     128  	case HEADER_SUCCESS:
     129  	  {
     130  	    struct name *name;
     131  
     132  	    decode_header (current_header, &current_stat_info,
     133  			   &current_format, 0);
     134  	    transform_stat_info (current_header->header.typeflag,
     135  				 &current_stat_info);
     136  	    archive_format = current_format;
     137  
     138  	    if (subcommand_option == UPDATE_SUBCOMMAND
     139  		&& (name = name_scan (current_stat_info.file_name, false)) != NULL)
     140  	      {
     141  		struct stat s;
     142  
     143  		chdir_do (name->change_dir);
     144  		if (deref_stat (current_stat_info.file_name, &s) == 0)
     145  		  {
     146  		    if (S_ISDIR (s.st_mode))
     147  		      {
     148  			char *p, *dirp = tar_savedir (current_stat_info.file_name, 1);
     149  			if (dirp)
     150  			  {
     151  			    namebuf_t nbuf = namebuf_create (current_stat_info.file_name);
     152  
     153  			    for (p = dirp; *p; p += strlen (p) + 1)
     154  			      addname (namebuf_name (nbuf, p),
     155  				       name->change_dir, false, NULL);
     156  
     157  			    namebuf_free (nbuf);
     158  			    free (dirp);
     159  
     160  			    remove_exact_name (name, current_stat_info.file_name);
     161  			  }
     162  		      }
     163  		    else if (tar_timespec_cmp (get_stat_mtime (&s),
     164  					       current_stat_info.mtime)
     165  			     <= 0)
     166  		      {
     167  			remove_exact_name (name, current_stat_info.file_name);
     168  		      }
     169  		    else if (name->is_wildcard)
     170  		      addname (current_stat_info.file_name,
     171  			       name->change_dir, false, NULL);
     172  		  }
     173  	      }
     174  
     175  	    skim_member (acting_as_filter);
     176  	    break;
     177  	  }
     178  
     179  	case HEADER_ZERO_BLOCK:
     180  	  current_block = current_header;
     181  	  found_end = true;
     182  	  break;
     183  
     184  	case HEADER_END_OF_FILE:
     185  	  found_end = true;
     186  	  break;
     187  
     188  	case HEADER_FAILURE:
     189  	  set_next_block_after (current_header);
     190  	  switch (previous_status)
     191  	    {
     192  	    case HEADER_STILL_UNREAD:
     193  	      WARN ((0, 0, _("This does not look like a tar archive")));
     194  	      FALLTHROUGH;
     195  	    case HEADER_SUCCESS:
     196  	    case HEADER_ZERO_BLOCK:
     197  	      ERROR ((0, 0, _("Skipping to next header")));
     198  	      FALLTHROUGH;
     199  	    case HEADER_FAILURE:
     200  	      break;
     201  
     202  	    case HEADER_END_OF_FILE:
     203  	    case HEADER_SUCCESS_EXTENDED:
     204  	      abort ();
     205  	    }
     206  	  break;
     207  	}
     208  
     209        tar_stat_destroy (&current_stat_info);
     210        previous_status = status;
     211      }
     212  
     213    reset_eof ();
     214    time_to_start_writing = true;
     215    output_start = current_block->buffer;
     216  
     217    {
     218      struct name const *p;
     219      while ((p = name_from_list ()) != NULL)
     220        {
     221  	char *file_name = p->name;
     222  	if (excluded_name (file_name, NULL))
     223  	  continue;
     224  	if (interactive_option && !confirm ("add", file_name))
     225  	  continue;
     226  	if (subcommand_option == CAT_SUBCOMMAND)
     227  	  append_file (file_name);
     228  	else
     229  	  dump_file (0, file_name, file_name);
     230        }
     231    }
     232  
     233    write_eot ();
     234    close_archive ();
     235    finish_deferred_unlinks ();
     236    names_notfound ();
     237  }