/[tar]/tar/src/create.c
ViewVC logotype

Diff of /tar/src/create.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.69 by gray, Fri Nov 14 12:27:50 2003 UTC revision 1.70 by gray, Mon Nov 17 07:36:18 2003 UTC
# Line 251  mode_to_chars (mode_t v, char *p, size_t Line 251  mode_to_chars (mode_t v, char *p, size_t
251        && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC        && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
252        && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC        && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
253        && archive_format != POSIX_FORMAT        && archive_format != POSIX_FORMAT
254          && archive_format != USTAR_FORMAT
255        && archive_format != GNU_FORMAT)        && archive_format != GNU_FORMAT)
256      {      {
257        negative = v < 0;        negative = v < 0;
# Line 329  string_to_chars (char *str, char *p, siz Line 330  string_to_chars (char *str, char *p, siz
330  }  }
331    
332    
333  /* Writing routines.  */  /* A file is not dumpable if
334       a) it is empty *and* world-readable, or
335  /* Zero out the buffer so we don't confuse ourselves with leftover     b) current archive is /dev/null */
336     data.  */  
337  static void  bool
338  clear_buffer (char *buffer)  file_dumpable_p (struct tar_stat_info *stat)
339  {  {
340    memset (buffer, 0, BLOCKSIZE);    return !(dev_null_output
341               || (stat->archive_file_size == 0
342                   && (stat->stat.st_mode & MODE_R) == MODE_R));
343  }  }
344    
345    
346    /* Writing routines.  */
347    
348  /* Write the EOT block(s).  Zero at least two blocks, through the end  /* Write the EOT block(s).  Zero at least two blocks, through the end
349     of the record.  Old tar, as previous versions of GNU tar, writes     of the record.  Old tar, as previous versions of GNU tar, writes
350     garbage after two zeroed blocks.  */     garbage after two zeroed blocks.  */
# Line 400  write_short_name (struct tar_stat_info * Line 406  write_short_name (struct tar_stat_info *
406    
407  /* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block.  */  /* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block.  */
408  static void  static void
409  write_gnu_long_link (const char *p, char type)  write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
410  {  {
411    size_t size = strlen (p) + 1;    size_t size = strlen (p) + 1;
412    size_t bufsize;    size_t bufsize;
# Line 408  write_gnu_long_link (const char *p, char Line 414  write_gnu_long_link (const char *p, char
414    
415    header = start_private_header ("././@LongLink", size);    header = start_private_header ("././@LongLink", size);
416    header->header.typeflag = type;    header->header.typeflag = type;
417    finish_header (header, -1);    finish_header (st, header, -1);
418    
419    header = find_next_block ();    header = find_next_block ();
420    
# Line 457  write_ustar_long_name (const char *name) Line 463  write_ustar_long_name (const char *name)
463      }      }
464        
465    i = split_long_name (name, length);    i = split_long_name (name, length);
466    if (i == 0 || length - i -1 > NAME_FIELD_SIZE)    if (i == 0 || length - i - 1 > NAME_FIELD_SIZE)
467      {      {
468        WARN ((0, 0,        WARN ((0, 0,
469               _("%s: file name is too long (cannot be split); not dumped"),               _("%s: file name is too long (cannot be split); not dumped"),
470               quotearg_colon (name),               quotearg_colon (name)));
              PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1));  
471        return NULL;        return NULL;
472      }      }
473    
# Line 494  write_long_link (struct tar_stat_info *s Line 499  write_long_link (struct tar_stat_info *s
499                
500      case OLDGNU_FORMAT:      case OLDGNU_FORMAT:
501      case GNU_FORMAT:      case GNU_FORMAT:
502        write_gnu_long_link (st->link_name, GNUTYPE_LONGLINK);        write_gnu_long_link (st, st->link_name, GNUTYPE_LONGLINK);
503        break;        break;
504    
505      default:      default:
# Line 518  write_long_name (struct tar_stat_info *s Line 523  write_long_name (struct tar_stat_info *s
523                
524      case OLDGNU_FORMAT:      case OLDGNU_FORMAT:
525      case GNU_FORMAT:      case GNU_FORMAT:
526        write_gnu_long_link (st->file_name, GNUTYPE_LONGNAME);        write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME);
527        break;        break;
528    
529      default:      default:
# Line 528  write_long_name (struct tar_stat_info *s Line 533  write_long_name (struct tar_stat_info *s
533  }  }
534    
535  static union block *  static union block *
536  write_extended (union block *old_header, char type)  write_extended (struct tar_stat_info *st, union block *old_header, char type)
537  {  {
538    union block *header, hp;    union block *header, hp;
   struct tar_stat_info foo;  
539    size_t size;    size_t size;
540    char *p;    char *p;
541    
# Line 546  write_extended (union block *old_header, Line 550  write_extended (union block *old_header,
550    header = start_private_header ("././@PaxHeader", size);    header = start_private_header ("././@PaxHeader", size);
551    header->header.typeflag = type;    header->header.typeflag = type;
552    
553    finish_header (header, -1);    finish_header (st, header, -1);
554    
555    p = extended_header.buffer;    p = extended_header.buffer;
556    
# Line 588  write_header_name (struct tar_stat_info Line 592  write_header_name (struct tar_stat_info
592  /* Make a header block for the file whose stat info is st,  /* Make a header block for the file whose stat info is st,
593     and return its address.  */     and return its address.  */
594    
595  static union block *  union block *
596  start_header (const char *name, struct tar_stat_info *st)  start_header (struct tar_stat_info *st)
597  {  {
598    union block *header;    union block *header;
599    
   name = safer_name_suffix (name, 0);  
   assign_string (&st->file_name, name);  
   
600    header = write_header_name (st);    header = write_header_name (st);
601    if (!header)    if (!header)
602      return NULL;      return NULL;
603    
   assign_string (&current_stat_info.file_name, name);  
   
604    /* Override some stat fields, if requested to do so.  */    /* Override some stat fields, if requested to do so.  */
605    
606    if (owner_option != (uid_t) -1)    if (owner_option != (uid_t) -1)
# Line 700  start_header (const char *name, struct t Line 699  start_header (const char *name, struct t
699        break;        break;
700    
701      case OLDGNU_FORMAT:      case OLDGNU_FORMAT:
702        case GNU_FORMAT:   /*FIXME?*/
703        /* Overwrite header->header.magic and header.version in one blow.  */        /* Overwrite header->header.magic and header.version in one blow.  */
704        strcpy (header->header.magic, OLDGNU_MAGIC);        strcpy (header->header.magic, OLDGNU_MAGIC);
705        break;        break;
706    
707      case POSIX_FORMAT:      case POSIX_FORMAT:
708      case USTAR_FORMAT:      case USTAR_FORMAT:
     case GNU_FORMAT:   /*FIXME?*/  
709        strncpy (header->header.magic, TMAGIC, TMAGLEN);        strncpy (header->header.magic, TMAGIC, TMAGLEN);
710        strncpy (header->header.version, TVERSION, TVERSLEN);        strncpy (header->header.version, TVERSION, TVERSLEN);
711        break;        break;
# Line 745  start_header (const char *name, struct t Line 744  start_header (const char *name, struct t
744     is not negative, is the block ordinal of the first record for this     is not negative, is the block ordinal of the first record for this
745     file, which may be a preceding long name or long link record.  */     file, which may be a preceding long name or long link record.  */
746  void  void
747  finish_header (union block *header, off_t block_ordinal)  finish_header (struct tar_stat_info *st,
748                   union block *header, off_t block_ordinal)
749  {  {
750    size_t i;    size_t i;
751    int sum;    int sum;
# Line 762  finish_header (union block *header, off_ Line 762  finish_header (union block *header, off_
762        /* These globals are parameters to print_header, sigh.  */        /* These globals are parameters to print_header, sigh.  */
763    
764        current_header = header;        current_header = header;
       /* current_stat_info is already set up.  */  
765        current_format = archive_format;        current_format = archive_format;
766        print_header (block_ordinal);        print_header (st, block_ordinal);
767      }      }
768    
769    header = write_extended (header, XHDTYPE);    header = write_extended (st, header, XHDTYPE);
770        
771    memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);    memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
772    
# Line 792  finish_header (union block *header, off_ Line 791  finish_header (union block *header, off_
791    set_next_block_after (header);    set_next_block_after (header);
792  }  }
793    
 /* Sparse file processing.  */  
   
 /* Takes a blockful of data and basically cruises through it to see if  
    it's made *entirely* of zeros, returning a 0 the instant it finds  
    something that is a nonzero, i.e., useful data.  */  
 static int  
 zero_block_p (char *buffer)  
 {  
   int counter;  
   
   for (counter = 0; counter < BLOCKSIZE; counter++)  
     if (buffer[counter] != '\0')  
       return 0;  
   return 1;  
 }  
794    
795  void  void
796  init_sparsearray (void)  pad_archive (off_t size_left)
 {  
   if (! sp_array_size)  
     sp_array_size = SPARSES_IN_OLDGNU_HEADER;  
   sparsearray = xmalloc (sp_array_size * sizeof *sparsearray);  
 }  
   
 static off_t  
 find_new_file_size (int sparses)  
797  {  {
798    int i;    union block *blk;
799    off_t s = 0;    while (size_left > 0)
800    for (i = 0; i < sparses; i++)      {
801      s += sparsearray[i].numbytes;        save_sizeleft = size_left;
802    return s;        blk = find_next_block ();
803  }        memset (blk->buffer, 0, BLOCKSIZE);
804          set_next_block_after (blk);
805  /* Make one pass over the file NAME, studying where any non-zero data        size_left -= BLOCKSIZE;
806     is, that is, how far into the file each instance of data is, and      }
807     how many bytes are there.  Save this information in the  }  
    sparsearray, which will later be translated into header  
    information.  */  
   
 /* There is little point in trimming small amounts of null data at the head  
    and tail of blocks, only avoid dumping full null blocks.  */  
   
 /* FIXME: this routine might accept bits of algorithmic cleanup, it is  
    too kludgey for my taste...  */  
808    
809  static int  static enum dump_status
810  deal_with_sparse (char *name, union block *header)  dump_regular_file (int fd, struct tar_stat_info *stat)
811  {  {
812    size_t numbytes = 0;    off_t size_left = stat->stat.st_size;
813    off_t offset = 0;    off_t block_ordinal;
814    int file;    union block *blk;
815    int sparses = 0;    
816    ssize_t count;    block_ordinal = current_block_ordinal ();
817    char buffer[BLOCKSIZE];    blk = start_header (stat);
818      if (!blk)
819    if (archive_format == OLDGNU_FORMAT)      return dump_status_fail;
     header->oldgnu_header.isextended = 0;  
820    
821    if (file = open (name, O_RDONLY), file < 0)    /* Mark contiguous files, if we support them.  */
822      /* This problem will be caught later on, so just return.  */    if (archive_format != V7_FORMAT && S_ISCTG (stat->stat.st_mode))
823      return 0;      blk->header.typeflag = CONTTYPE;
824    
825    init_sparsearray ();    finish_header (stat, blk, block_ordinal);
   clear_buffer (buffer);  
826    
827    for (;;)    while (size_left > 0)
828      {      {
829        /* Realloc the scratch area as necessary.  FIXME: should reallocate        size_t bufsize, count;
830           only at beginning of a new instance of non-zero data.  */        
831          if (multi_volume_option)
       if (sp_array_size <= sparses)  
832          {          {
833            sparsearray =            assign_string (&save_name, stat->file_name);
834              xrealloc (sparsearray,            save_sizeleft = size_left;
835                        2 * sp_array_size * sizeof (struct sp_array));            save_totsize = stat->stat.st_size;
           sp_array_size *= 2;  
836          }          }
837          blk = find_next_block ();
838                
839        count = safe_read (file, buffer, sizeof buffer);        bufsize = available_space_after (blk);
840        if (count <= 0)        
841          break;        if (size_left < bufsize)
842            {
843        /* Process one block.  */            /* Last read -- zero out area beyond.  */
844              bufsize = size_left;
845        if (count == sizeof buffer)            count = bufsize % BLOCKSIZE;
846              if (count)
847          if (zero_block_p (buffer))              memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
848            {          }
849              if (numbytes)        
850                {        count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
851                  sparsearray[sparses++].numbytes = numbytes;        if (count < 0)
852                  numbytes = 0;          {
853                }            read_diag_details (stat->orig_file_name,
854            }                               stat->stat.st_size - size_left, bufsize);
855          else            pad_archive (size_left);
856            {            return dump_status_short;
857              if (!numbytes)          }
858                sparsearray[sparses].offset = offset;        size_left -= count;
             numbytes += count;  
           }  
   
       else  
   
         /* Since count < sizeof buffer, we have the last bit of the file.  */  
859    
860          if (!zero_block_p (buffer))        set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
           {  
             if (!numbytes)  
               sparsearray[sparses].offset = offset;  
             numbytes += count;  
           }  
         else  
           /* The next two lines are suggested by Andreas Degert, who says  
              they are required for trailing full blocks to be written to the  
              archive, when all zeroed.  Yet, it seems to me that the case  
              does not apply.  Further, at restore time, the file is not as  
              sparse as it should.  So, some serious cleanup is *also* needed  
              in this area.  Just one more... :-(.  FIXME.  */  
           if (numbytes)  
             numbytes += count;  
   
       /* Prepare for next block.  */  
   
       offset += count;  
       /* FIXME: do not clear unless necessary.  */  
       clear_buffer (buffer);  
     }  
861    
862    if (numbytes)        if (count != bufsize)
863      sparsearray[sparses++].numbytes = numbytes;          {
864    else            char buf[UINTMAX_STRSIZE_BOUND];
865      {            memset (blk->buffer + count, 0, bufsize - count);
866        sparsearray[sparses].offset = offset - 1;            WARN ((0, 0,
867        sparsearray[sparses++].numbytes = 1;                   ngettext ("%s: File shrank by %s byte; padding with zeros",
868                               "%s: File shrank by %s bytes; padding with zeros",
869                               size_left),
870                     quotearg_colon (stat->orig_file_name),
871                     STRINGIFY_BIGINT (size_left, buf)));
872              if (! ignore_failed_read_option)
873                exit_status = TAREXIT_FAILURE;
874              pad_archive (size_left);
875              return dump_status_short;
876            }
877      }      }
878      return dump_status_ok;
   return close (file) == 0 && 0 <= count ? sparses : 0;  
879  }  }
880    
881  static int  void
882  finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)  dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
883  {  {
884    union block *start;    if (fd >= 0)
   size_t bufsize;  
   int sparses = 0;  
   ssize_t count;  
   
   while (*sizeleft > 0)  
885      {      {
886        start = find_next_block ();        struct stat final_stat;
887        memset (start->buffer, 0, BLOCKSIZE);        if (fstat (fd, &final_stat) != 0)
       bufsize = sparsearray[sparses].numbytes;  
       if (! bufsize)  
         abort ();  
   
       if (lseek (file, sparsearray[sparses++].offset, SEEK_SET) < 0)  
888          {          {
889            (ignore_failed_read_option ? seek_warn_details : seek_error_details)            stat_diag (st->orig_file_name);
             (name, sparsearray[sparses - 1].offset);  
           break;  
890          }          }
891          else if (final_stat.st_ctime != original_ctime)
892            {
893              WARN ((0, 0, _("%s: file changed as we read it"),
894                     quotearg_colon (st->orig_file_name)));
895            }
896          if (close (fd) != 0)
897            {
898              close_diag (st->orig_file_name);
899            }
900        }
901      if (remove_files_option)
902        {
903          if (unlink (st->orig_file_name) == -1)
904            unlink_error (st->orig_file_name);
905        }
906    }
907    
908        /* If the number of bytes to be written here exceeds the size of  void
909           the temporary buffer, do it in steps.  */  dump_dir0 (char *directory,
910               struct tar_stat_info *stat, int top_level, dev_t parent_device)
911        while (bufsize > BLOCKSIZE)  {
912      dev_t our_device = stat->stat.st_dev;
913      
914      if (!is_avoided_name (stat->orig_file_name))
915        {
916          union block *blk = NULL;
917          off_t block_ordinal = current_block_ordinal ();
918          stat->stat.st_size = 0;   /* force 0 size on dir */
919    
920          blk = start_header (stat);
921          if (!blk)
922            return;
923              
924          if (incremental_option)
925            blk->header.typeflag = GNUTYPE_DUMPDIR;
926          else /* if (standard_option) */
927            blk->header.typeflag = DIRTYPE;
928    
929          /* If we're gnudumping, we aren't done yet so don't close it.  */
930    
931          if (!incremental_option)
932            finish_header (stat, blk, block_ordinal);
933          else if (gnu_list_name->dir_contents)
934          {          {
935            count = safe_read (file, start->buffer, BLOCKSIZE);            off_t size_left;
936            if (count < 0)            off_t totsize;
937              size_t bufsize;
938              ssize_t count;
939              const char *buffer, *p_buffer;
940              off_t block_ordinal = current_block_ordinal ();
941              
942              buffer = gnu_list_name->dir_contents; /* FOO */
943              totsize = 0;
944              if (buffer)
945                for (p_buffer = buffer; *p_buffer; )
946                  {
947                    size_t size = strlen (p_buffer) + 1;
948                    totsize += size;
949                    p_buffer += size;
950                  }
951              totsize++;
952              OFF_TO_CHARS (totsize, blk->header.size);
953              finish_header (stat, blk, block_ordinal);
954              p_buffer = buffer;
955              size_left = totsize;
956              while (size_left > 0)
957              {              {
958                (ignore_failed_read_option                if (multi_volume_option)
959                 ? read_warn_details                  {
960                 : read_error_details)                    assign_string (&save_name, stat->orig_file_name);
961                  (name, fullsize - *sizeleft, bufsize);                    save_sizeleft = size_left;
962                return 1;                    save_totsize = totsize;
963                    }
964                  blk = find_next_block ();
965                  bufsize = available_space_after (blk);
966                  if (size_left < bufsize)
967                    {
968                      bufsize = size_left;
969                      count = bufsize % BLOCKSIZE;
970                      if (count)
971                        memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
972                    }
973                  memcpy (blk->buffer, p_buffer, bufsize);
974                  size_left -= bufsize;
975                  p_buffer += bufsize;
976                  set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
977              }              }
978            bufsize -= count;            if (multi_volume_option)
979            *sizeleft -= count;              assign_string (&save_name, 0);
980            set_next_block_after (start);            return;
           start = find_next_block ();  
           memset (start->buffer, 0, BLOCKSIZE);  
981          }          }
982        }
983      else if (!recursion_option)
984        return;
985      else if (one_file_system_option
986               && !top_level
987               && parent_device != stat->stat.st_dev)
988        {
989          if (verbose_option)
990            WARN ((0, 0,
991                   _("%s: file is on a different filesystem; not dumped"),
992                   quotearg_colon (stat->orig_file_name)));
993          return;
994        }
995    
996      {
997        char const *entry;
998        size_t entry_len;
999        char *name_buf = strdup (stat->orig_file_name);
1000        size_t name_size = strlen (name_buf);
1001        size_t name_len = name_size;
1002        
1003        /* Now output all the files in the directory.  */
1004        /* FIXME: Should speed this up by cd-ing into the dir.  */
1005        
1006        for (entry = directory; (entry_len = strlen (entry)) != 0;
1007             entry += entry_len + 1)
1008        {        {
1009          char buffer[BLOCKSIZE];          if (name_size < name_len + entry_len)
1010              {
1011          clear_buffer (buffer);              name_size = name_len + entry_len;
1012          count = safe_read (file, buffer, bufsize);              name_buf = xrealloc (name_buf, name_size + 1);
1013          memcpy (start->buffer, buffer, BLOCKSIZE);            }
1014            strcpy (name_buf + name_len, entry);
1015            if (!excluded_name (name_buf))
1016              dump_file (name_buf, 0, our_device);
1017        }        }
1018        
1019        free (name_buf);
1020      }
1021    }
1022    
1023        if (count < 0)  /* Ensure exactly one trailing slash.  */
1024          {  static void
1025            (ignore_failed_read_option  ensure_slash (char **pstr)
1026             ? read_warn_details  {
1027             : read_error_details)    size_t len = strlen (*pstr);
1028              (name, fullsize - *sizeleft, bufsize);    while (len >= 1 && ISSLASH ((*pstr)[len - 1]))
1029            return 1;      len--;
1030          }    if (!ISSLASH ((*pstr)[len]))
1031        *pstr = xrealloc (*pstr, len + 2);
1032      (*pstr)[len++] = '/';
1033      (*pstr)[len] = '\0';
1034    }
1035    
1036        *sizeleft -= count;  bool
1037        set_next_block_after (start);  dump_dir (struct tar_stat_info *stat, int top_level, dev_t parent_device)
1038    {
1039      char *directory;
1040    
1041      directory = savedir (stat->orig_file_name);
1042      if (!directory)
1043        {
1044          savedir_diag (stat->orig_file_name);
1045          return false;
1046      }      }
1047    free (sparsearray);  
1048  #if 0    ensure_slash (&stat->orig_file_name);
1049    set_next_block_after (start + (count - 1) / BLOCKSIZE);    ensure_slash (&stat->file_name);
1050  #endif  
1051    return 0;    dump_dir0 (directory, stat, top_level, parent_device);
1052    
1053      free (directory);
1054      return true;
1055  }  }
1056    
1057    
1058  /* Main functions of this module.  */  /* Main functions of this module.  */
1059    
# Line 1020  create_archive (void) Line 1072  create_archive (void)
1072    
1073        collect_and_sort_names ();        collect_and_sort_names ();
1074    
1075        while (p = name_from_list (), p)        while ((p = name_from_list ()) != NULL)
1076          if (!excluded_name (p))          if (!excluded_name (p))
1077            dump_file (p, -1, (dev_t) 0);            dump_file (p, -1, (dev_t) 0);
1078    
1079        blank_name_list ();        blank_name_list ();
1080        while (p = name_from_list (), p)        while ((p = name_from_list ()) != NULL)
1081          if (!excluded_name (p))          if (!excluded_name (p))
1082            {            {
1083              size_t plen = strlen (p);              size_t plen = strlen (p);
# Line 1050  create_archive (void) Line 1102  create_archive (void)
1102                            while ((buffer_size *=2 ) < plen + qlen)                            while ((buffer_size *=2 ) < plen + qlen)
1103                              continue;                              continue;
1104                            buffer = xrealloc (buffer, buffer_size);                            buffer = xrealloc (buffer, buffer_size);
1105                          }                          }
1106                        strcpy (buffer + plen, q + 1);                        strcpy (buffer + plen, q + 1);
1107                        dump_file (buffer, -1, (dev_t) 0);                        dump_file (buffer, -1, (dev_t) 0);
1108                      }                      }
# Line 1061  create_archive (void) Line 1113  create_archive (void)
1113      }      }
1114    else    else
1115      {      {
1116        while (p = name_next (1), p)        while ((p = name_next (1)) != NULL)
1117          if (!excluded_name (p))          if (!excluded_name (p))
1118            dump_file (p, 1, (dev_t) 0);            dump_file (p, 1, (dev_t) 0);
1119      }      }
# Line 1091  compare_links (void const *entry1, void Line 1143  compare_links (void const *entry1, void
1143    return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;    return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
1144  }  }
1145    
1146    static void
1147    unknown_file_error (char *p)
1148    {
1149      WARN ((0, 0, _("%s: Unknown file type; file ignored"),
1150             quotearg_colon (p)));
1151      if (!ignore_failed_read_option)
1152        exit_status = TAREXIT_FAILURE;
1153    }
1154    
1155    
1156    /* Handling of hard links */
1157    
1158  /* Table of all non-directories that we've written so far.  Any time  /* Table of all non-directories that we've written so far.  Any time
1159     we see another, we check the table and avoid dumping the data     we see another, we check the table and avoid dumping the data
1160     again if we've done it once already.  */     again if we've done it once already.  */
1161  static Hash_table *link_table;  static Hash_table *link_table;
1162    
1163    /* Try to dump stat as a hard link to another file in the archive. If
1164       succeeded returns true */
1165    static bool
1166    dump_hard_link (struct tar_stat_info *stat)
1167    {
1168      if (link_table && stat->stat.st_nlink > 1)
1169        {
1170          struct link lp;
1171          struct link *dup;
1172          off_t block_ordinal;
1173          union block *blk;
1174          
1175          lp.ino = stat->stat.st_ino;
1176          lp.dev = stat->stat.st_dev;
1177    
1178          if ((dup = hash_lookup (link_table, &lp)))
1179            {
1180              /* We found a link.  */
1181              char const *link_name = safer_name_suffix (dup->name, 1);
1182    
1183              dup->nlink--;
1184                  
1185              block_ordinal = current_block_ordinal ();
1186              assign_string (&stat->link_name, link_name);
1187              if (NAME_FIELD_SIZE < strlen (link_name))
1188                write_long_link (stat);
1189              
1190              stat->stat.st_size = 0;
1191              blk = start_header (stat);
1192              if (!blk)
1193                return true;
1194              tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE);
1195    
1196              blk->header.typeflag = LNKTYPE;
1197              finish_header (stat, blk, block_ordinal);
1198    
1199              if (remove_files_option && unlink (stat->orig_file_name) != 0)
1200                unlink_error (stat->orig_file_name);
1201    
1202              return true;
1203            }
1204        }
1205      return false;
1206    }
1207    
1208    static void
1209    file_count_links (struct tar_stat_info *stat)
1210    {
1211      if (stat->stat.st_nlink > 1)
1212        {
1213          struct link *dup;
1214          struct link *lp = xmalloc (offsetof (struct link, name)
1215                                     + strlen (stat->orig_file_name) + 1);
1216          lp->ino = stat->stat.st_ino;
1217          lp->dev = stat->stat.st_dev;
1218          lp->nlink = stat->stat.st_nlink;
1219          strcpy (lp->name, stat->orig_file_name);
1220    
1221          if (! ((link_table
1222                  || (link_table = hash_initialize (0, 0, hash_link,
1223                                                    compare_links, 0)))
1224                 && (dup = hash_insert (link_table, lp))))
1225            xalloc_die ();
1226    
1227          if (dup != lp)
1228            abort ();
1229          lp->nlink--;
1230        }
1231    }
1232    
1233    /* For each dumped file, check if all its links were dumped. Emit
1234       warnings if it is not so. */
1235    void
1236    check_links ()
1237    {
1238      struct link *lp;
1239    
1240      if (!link_table)
1241        return;
1242    
1243      for (lp = hash_get_first (link_table); lp;
1244           lp = hash_get_next (link_table, lp))
1245        {
1246          if (lp->nlink)
1247            {
1248              WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name));
1249            }
1250        }
1251    }
1252    
1253    
1254  /* Dump a single file, recursing on directories.  P is the file name  /* Dump a single file, recursing on directories.  P is the file name
1255     to dump.  TOP_LEVEL tells whether this is a top-level call; zero     to dump.  TOP_LEVEL tells whether this is a top-level call; zero
1256     means no, positive means yes, and negative means the top level     means no, positive means yes, and negative means the top level
1257     of an incremental dump.  PARENT_DEVICE is the device of P's     of an incremental dump.  PARENT_DEVICE is the device of P's
1258     parent directory; it is examined only if TOP_LEVEL is zero.     parent directory; it is examined only if TOP_LEVEL is zero. */
   
    Set global CURRENT_STAT_INFO to stat output for this file.  */  
1259    
1260  /* FIXME: One should make sure that for *every* path leading to setting  /* FIXME: One should make sure that for *every* path leading to setting
1261     exit_status to failure, a clear diagnostic has been issued.  */     exit_status to failure, a clear diagnostic has been issued.  */
1262    
1263  void  void
1264  dump_file (char *p, int top_level, dev_t parent_device)  dump_file0 (struct tar_stat_info *stat, char *p,
1265                int top_level, dev_t parent_device)
1266  {  {
1267    union block *header;    union block *header;
1268    char type;    char type;
   union block *exhdr;  
   char save_typeflag;  
1269    time_t original_ctime;    time_t original_ctime;
1270    struct utimbuf restore_times;    struct utimbuf restore_times;
1271    off_t block_ordinal = -1;    off_t block_ordinal = -1;
1272      
   /* FIXME: `header' might be used uninitialized in this  
      function.  Reported by Bruno Haible.  */  
   
1273    if (interactive_option && !confirm ("add", p))    if (interactive_option && !confirm ("add", p))
1274      return;      return;
1275    
1276    if (deref_stat (dereference_option, p, &current_stat_info.stat) != 0)    assign_string (&stat->orig_file_name, p);
1277      assign_string (&stat->file_name, safer_name_suffix (p, 0));
1278    
1279      if (deref_stat (dereference_option, p, &stat->stat) != 0)
1280      {      {
1281        if (ignore_failed_read_option)        stat_diag (p);
         stat_warn (p);  
       else  
         stat_error (p);  
1282        return;        return;
1283      }      }
1284      stat->archive_file_size = stat->stat.st_size;
1285    original_ctime = current_stat_info.stat.st_ctime;    
1286    restore_times.actime = current_stat_info.stat.st_atime;    original_ctime = stat->stat.st_ctime;
1287    restore_times.modtime = current_stat_info.stat.st_mtime;    restore_times.actime = stat->stat.st_atime;
1288      restore_times.modtime = stat->stat.st_mtime;
1289    
1290  #ifdef S_ISHIDDEN  #ifdef S_ISHIDDEN
1291    if (S_ISHIDDEN (current_stat_info.stat.st_mode))    if (S_ISHIDDEN (stat->stat.st_mode))
1292      {      {
1293        char *new = (char *) alloca (strlen (p) + 2);        char *new = (char *) alloca (strlen (p) + 2);
1294        if (new)        if (new)
# Line 1154  dump_file (char *p, int top_level, dev_t Line 1304  dump_file (char *p, int top_level, dev_t
1304       put in the archive.  */       put in the archive.  */
1305    
1306    if ((0 < top_level || !incremental_option)    if ((0 < top_level || !incremental_option)
1307        && !S_ISDIR (current_stat_info.stat.st_mode)        && !S_ISDIR (stat->stat.st_mode)
1308        && current_stat_info.stat.st_mtime < newer_mtime_option        && stat->stat.st_mtime < newer_mtime_option
1309        && (!after_date_option || current_stat_info.stat.st_ctime < newer_ctime_option))        && (!after_date_option || stat->stat.st_ctime < newer_ctime_option))
1310      {      {
1311        if (0 < top_level)        if (0 < top_level)
1312          WARN ((0, 0, _("%s: file is unchanged; not dumped"),          WARN ((0, 0, _("%s: file is unchanged; not dumped"),
# Line 1166  dump_file (char *p, int top_level, dev_t Line 1316  dump_file (char *p, int top_level, dev_t
1316      }      }
1317    
1318    /* See if we are trying to dump the archive.  */    /* See if we are trying to dump the archive.  */
1319    if (sys_file_is_archive (&current_stat_info))    if (sys_file_is_archive (stat))
1320      {      {
1321        WARN ((0, 0, _("%s: file is the archive; not dumped"),        WARN ((0, 0, _("%s: file is the archive; not dumped"),
1322               quotearg_colon (p)));               quotearg_colon (p)));
1323        return;        return;
1324      }      }
1325    
1326    if (S_ISDIR (current_stat_info.stat.st_mode))    if (S_ISDIR (stat->stat.st_mode))
1327      {      {
1328        char *directory;        dump_dir (stat, top_level, parent_device);
       char const *entry;  
       size_t entrylen;  
       char *namebuf;  
       size_t buflen;  
       size_t len;  
       dev_t our_device = current_stat_info.stat.st_dev;  
   
       errno = 0;  
   
       directory = savedir (p);  
       if (! directory)  
         {  
           if (ignore_failed_read_option)  
             savedir_warn (p);  
           else  
             savedir_error (p);  
           return;  
         }  
   
       /* Build new prototype name.  Ensure exactly one trailing slash.  */  
   
       len = strlen (p);  
       buflen = len + NAME_FIELD_SIZE;  
       namebuf = xmalloc (buflen + 1);  
       memcpy (namebuf, p, len);  
       while (len >= 1 && ISSLASH (namebuf[len - 1]))  
         len--;  
       namebuf[len++] = '/';  
       namebuf[len] = '\0';  
   
       if (! is_avoided_name (namebuf))  
         {  
           /* The condition above used to be "archive_format != V7_FORMAT".  
              GNU tar was not writing directory blocks at all.  Daniel Trinkle  
              writes: ``All old versions of tar I have ever seen have  
              correctly archived an empty directory.  The really old ones I  
              checked included HP-UX 7 and Mt. Xinu More/BSD.  There may be  
              some subtle reason for the exclusion that I don't know, but the  
              current behavior is broken.''  I do not know those subtle  
              reasons either, so until these are reported (anew?), just allow  
              directory blocks to be written even with old archives.  */  
   
           block_ordinal = current_block_ordinal ();  
           current_stat_info.stat.st_size = 0;   /* force 0 size on dir */  
   
           header = start_header (namebuf, &current_stat_info);  
           if (!header)  
             return;  
             
           if (incremental_option)  
             header->header.typeflag = GNUTYPE_DUMPDIR;  
           else /* if (standard_option) */  
             header->header.typeflag = DIRTYPE;  
   
           /* If we're gnudumping, we aren't done yet so don't close it.  */  
   
           if (!incremental_option)  
             finish_header (header, block_ordinal);  
         }  
   
       if (incremental_option && gnu_list_name->dir_contents)  
         {  
           off_t sizeleft;  
           off_t totsize;  
           size_t bufsize;  
           union block *start;  
           ssize_t count;  
           const char *buffer, *p_buffer;  
   
           buffer = gnu_list_name->dir_contents; /* FOO */  
           totsize = 0;  
           if (buffer)  
             for (p_buffer = buffer; *p_buffer; )  
               {  
                 size_t size = strlen (p_buffer) + 1;  
                 totsize += size;  
                 p_buffer += size;  
               }  
           totsize++;  
           OFF_TO_CHARS (totsize, header->header.size);  
           finish_header (header, block_ordinal);  
           p_buffer = buffer;  
           sizeleft = totsize;  
           while (sizeleft > 0)  
             {  
               if (multi_volume_option)  
                 {  
                   assign_string (&save_name, p);  
                   save_sizeleft = sizeleft;  
                   save_totsize = totsize;  
                 }  
               start = find_next_block ();  
               bufsize = available_space_after (start);  
               if (sizeleft < bufsize)  
                 {  
                   bufsize = sizeleft;  
                   count = bufsize % BLOCKSIZE;  
                   if (count)  
                     memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);  
                 }  
               memcpy (start->buffer, p_buffer, bufsize);  
               sizeleft -= bufsize;  
               p_buffer += bufsize;  
               set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);  
             }  
           if (multi_volume_option)  
             assign_string (&save_name, 0);  
           goto finish_dir;  
         }  
   
       /* See if we are about to recurse into a directory, and avoid doing  
          so if the user wants that we do not descend into directories.  */  
   
       if (! recursion_option)  
         goto finish_dir;  
   
       /* See if we are crossing from one file system to another, and  
          avoid doing so if the user only wants to dump one file system.  */  
   
       if (one_file_system_option && !top_level  
           && parent_device != current_stat_info.stat.st_dev)  
         {  
           if (verbose_option)  
             WARN ((0, 0,  
                    _("%s: file is on a different filesystem; not dumped"),  
                    quotearg_colon (p)));  
           goto finish_dir;  
         }  
   
       /* Now output all the files in the directory.  */  
   
       /* FIXME: Should speed this up by cd-ing into the dir.  */  
   
       for (entry = directory;  
            (entrylen = strlen (entry)) != 0;  
            entry += entrylen + 1)  
         {  
           if (buflen < len + entrylen)  
             {  
               buflen = len + entrylen;  
               namebuf = xrealloc (namebuf, buflen + 1);  
             }  
           strcpy (namebuf + len, entry);  
           if (!excluded_name (namebuf))  
             dump_file (namebuf, 0, our_device);  
         }  
   
     finish_dir:  
   
       free (directory);  
       free (namebuf);  
1329        if (atime_preserve_option)        if (atime_preserve_option)
1330          utime (p, &restore_times);          utime (p, &restore_times);
1331        return;        return;
# Line 1336  dump_file (char *p, int top_level, dev_t Line 1335  dump_file (char *p, int top_level, dev_t
1335    else    else
1336      {      {
1337        /* Check for multiple links.  */        /* Check for multiple links.  */
1338          if (dump_hard_link (stat))
1339        if (1 < current_stat_info.stat.st_nlink && link_table)          return;
1340          {        
           struct link lp;  
           struct link *dup;  
           lp.ino = current_stat_info.stat.st_ino;  
           lp.dev = current_stat_info.stat.st_dev;  
   
           if ((dup = hash_lookup (link_table, &lp)))  
             {  
               /* We found a link.  */  
               char const *link_name = safer_name_suffix (dup->name, 1);  
   
               dup->nlink--;  
                 
               block_ordinal = current_block_ordinal ();  
               assign_string (&current_stat_info.link_name, link_name);  
               if (NAME_FIELD_SIZE < strlen (link_name))  
                 write_long_link (&current_stat_info);  
   
               current_stat_info.stat.st_size = 0;  
               header = start_header (p, &current_stat_info);  
               if (!header)  
                 return;  
               tar_copy_str (header->header.linkname, link_name,  
                             NAME_FIELD_SIZE);  
   
               header->header.typeflag = LNKTYPE;  
               finish_header (header, block_ordinal);  
   
               /* FIXME: Maybe remove from table after all links found?  */  
   
               if (remove_files_option && unlink (p) != 0)  
                 unlink_error (p);  
   
               /* We dumped it, and we don't need to put it in the  
                  table again.  */  
               return;  
             }  
         }  
   
1341        /* This is not a link to a previously dumped file, so dump it.  */        /* This is not a link to a previously dumped file, so dump it.  */
1342    
1343        if (S_ISREG (current_stat_info.stat.st_mode)        if (S_ISREG (stat->stat.st_mode)
1344            || S_ISCTG (current_stat_info.stat.st_mode))            || S_ISCTG (stat->stat.st_mode))
1345          {          {
1346            int f;                        /* file descriptor */            int fd;
1347            size_t bufsize;            enum dump_status status;
           ssize_t count;  
           off_t sizeleft;  
           union block *start;  
           int header_moved;  
           char isextended = 0;  
           int sparses = 0;  
1348    
1349            header_moved = 0;            if (file_dumpable_p (stat))
   
           if (sparse_option)  
1350              {              {
1351                /* Check the size of the file against the number of blocks                fd = open (stat->orig_file_name,
1352                   allocated for it, counting both data and indirect blocks.                           O_RDONLY | O_BINARY);
1353                   If there is a smaller number of blocks than would be                if (fd < 0)
                  necessary to accommodate a file of this size, this is safe  
                  to say that we have a sparse file: at least one of those  
                  blocks in the file is just a useless hole.  For sparse  
                  files not having more hole blocks than indirect blocks, the  
                  sparseness will go undetected.  */  
   
               /* Bruno Haible sent me these statistics for Linux.  It seems  
                  that some filesystems count indirect blocks in st_blocks,  
                  while others do not seem to:  
   
                  minix-fs   tar: size=7205, st_blocks=18 and ST_NBLOCKS=18  
                  extfs      tar: size=7205, st_blocks=18 and ST_NBLOCKS=18  
                  ext2fs     tar: size=7205, st_blocks=16 and ST_NBLOCKS=16  
                  msdos-fs   tar: size=7205, st_blocks=16 and ST_NBLOCKS=16  
   
                  Dick Streefland reports the previous numbers as misleading,  
                  because ext2fs use 12 direct blocks, while minix-fs uses only  
                  6 direct blocks.  Dick gets:  
   
                  ext2   size=20480      ls listed blocks=21  
                  minix  size=20480      ls listed blocks=21  
                  msdos  size=20480      ls listed blocks=20  
   
                  It seems that indirect blocks *are* included in st_blocks.  
                  The minix filesystem does not account for phantom blocks in  
                  st_blocks, so `du' and `ls -s' give wrong results.  So, the  
                  --sparse option would not work on a minix filesystem.  */  
   
               if (ST_NBLOCKS (current_stat_info.stat)  
                   < (current_stat_info.stat.st_size / ST_NBLOCKSIZE  
                      + (current_stat_info.stat.st_size % ST_NBLOCKSIZE != 0)))  
1354                  {                  {
1355                    int counter;                    if (!top_level && errno == ENOENT)
   
                   block_ordinal = current_block_ordinal ();  
                   header = start_header (p, &current_stat_info);  
                   if (!header)  
                     return;  
                   header->header.typeflag = GNUTYPE_SPARSE;  
                   header_moved = 1;  
   
                   /* Call the routine that figures out the layout of the  
                      sparse file in question.  SPARSES is the index of the  
                      first unused element of the "sparsearray," i.e.,  
                      the number of elements it needed to describe the file.  */  
   
                   sparses = deal_with_sparse (p, header);  
   
                   /* See if we'll need an extended header later.  */  
   
                   if (SPARSES_IN_OLDGNU_HEADER < sparses)  
                     header->oldgnu_header.isextended = 1;  
   
                   /* We store the "real" file size so we can show that in  
                      case someone wants to list the archive, i.e., tar tvf  
                      <file>.  It might be kind of disconcerting if the  
                      shrunken file size was the one that showed up.  */  
   
                   OFF_TO_CHARS (current_stat_info.stat.st_size,  
                                 header->oldgnu_header.realsize);  
   
                   /* This will be the new "size" of the file, i.e., the size  
                      of the file minus the blocks of holes that we're  
                      skipping over.  */  
   
                   current_stat_info.stat.st_size = find_new_file_size (sparses);  
                   OFF_TO_CHARS (current_stat_info.stat.st_size, header->header.size);  
   
                   for (counter = 0;  
                        counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;  
                        counter++)  
                     {  
                       OFF_TO_CHARS (sparsearray[counter].offset,  
                                     header->oldgnu_header.sp[counter].offset);  
                       SIZE_TO_CHARS (sparsearray[counter].numbytes,  
                                      header->oldgnu_header.sp[counter].numbytes);  
                     }  
                 }  
             }  
   
           sizeleft = current_stat_info.stat.st_size;  
   
           /* Don't bother opening empty, world readable files.  Also do not  
              open files when archive is meant for /dev/null.  */  
   
           if (dev_null_output  
               || (sizeleft == 0  
                   && MODE_R == (MODE_R & current_stat_info.stat.st_mode)))  
             f = -1;  
           else  
             {  
               f = open (p, O_RDONLY | O_BINARY);  
               if (f < 0)  
                 {  
                   if (! top_level && errno == ENOENT)  
1356                      WARN ((0, 0, _("%s: File removed before we read it"),                      WARN ((0, 0, _("%s: File removed before we read it"),
1357                             quotearg_colon (p)));                             quotearg_colon (stat->orig_file_name)));
1358                    else                    else
1359                      (ignore_failed_read_option ? open_warn : open_error) (p);                      open_diag (stat->orig_file_name);
1360                    return;                    return;
1361                  }                  }
1362              }              }
   
           /* If the file is sparse, we've already taken care of this.  */  
   
           if (!header_moved)  
             {  
               block_ordinal = current_block_ordinal ();  
               header = start_header (p, &current_stat_info);  
               if (!header)  
                 return;  
             }  
   
           /* Mark contiguous files, if we support them.  */  
   
           if (archive_format != V7_FORMAT  
               && S_ISCTG (current_stat_info.stat.st_mode))  
             header->header.typeflag = CONTTYPE;  
   
           if (archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)  
             isextended = header->oldgnu_header.isextended;  
1363            else            else
1364              isextended = 0;              fd = -1;
1365              
1366            save_typeflag = header->header.typeflag;            if (sparse_option && sparse_file_p (stat))
           finish_header (header, block_ordinal);  
           if (isextended)  
             {  
               int sparses_emitted = SPARSES_IN_OLDGNU_HEADER;  
   
               for (;;)  
                 {  
                   int i;  
                   exhdr = find_next_block ();  
                   memset (exhdr->buffer, 0, BLOCKSIZE);  
                   for (i = 0;  
                        (i < SPARSES_IN_SPARSE_HEADER  
                         && sparses_emitted + i < sparses);  
                        i++)  
                     {  
                       SIZE_TO_CHARS (sparsearray[sparses_emitted + i].numbytes,  
                                      exhdr->sparse_header.sp[i].numbytes);  
                       OFF_TO_CHARS (sparsearray[sparses_emitted + i].offset,  
                                     exhdr->sparse_header.sp[i].offset);  
                     }  
                   set_next_block_after (exhdr);  
                   sparses_emitted += i;  
                   if (sparses == sparses_emitted)  
                     break;  
                   exhdr->sparse_header.isextended = 1;  
                 }  
             }  
           if (save_typeflag == GNUTYPE_SPARSE)  
1367              {              {
1368                if (f < 0                status = sparse_dump_file (fd, stat);
1369                    || finish_sparse_file (f, &sizeleft,                if (status == dump_status_not_implemented)
1370                                           current_stat_info.stat.st_size, p))                  status = dump_regular_file (fd, stat);
                 goto padit;  
1371              }              }
1372            else            else
1373              while (sizeleft > 0)              status = dump_regular_file (fd, stat);
               {  
                 if (multi_volume_option)  
                   {  
                     assign_string (&save_name, p);  
                     save_sizeleft = sizeleft;  
                     save_totsize = current_stat_info.stat.st_size;  
                   }  
                 start = find_next_block ();  
   
                 bufsize = available_space_after (start);  
   
                 if (sizeleft < bufsize)  
                   {  
                     /* Last read -- zero out area beyond.  */  
   
                     bufsize = sizeleft;  
                     count = bufsize % BLOCKSIZE;  
                     if (count)  
                       memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);  
                   }  
                 if (f < 0)  
                   count = bufsize;  
                 else  
                   count = safe_read (f, start->buffer, bufsize);  
                 if (count < 0)  
                   {  
                     (ignore_failed_read_option  
                      ? read_warn_details  
                      : read_error_details)  
                       (p, current_stat_info.stat.st_size - sizeleft, bufsize);  
                     goto padit;  
                   }  
                 sizeleft -= count;  
   
                 /* This is nonportable (the type of set_next_block_after's arg).  */  
   
                 set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);  
   
   
                 if (count != bufsize)  
                   {  
                     char buf[UINTMAX_STRSIZE_BOUND];  
                     memset (start->buffer + count, 0, bufsize - count);  
                     WARN ((0, 0,  
                            ngettext ("%s: File shrank by %s byte; padding with zeros",  
                                      "%s: File shrank by %s bytes; padding with zeros",  
                                      sizeleft),  
                            quotearg_colon (p),  
                            STRINGIFY_BIGINT (sizeleft, buf)));  
                     if (! ignore_failed_read_option)  
                       exit_status = TAREXIT_FAILURE;  
                     goto padit;         /* short read */  
                   }  
               }  
1374    
1375            if (multi_volume_option)            switch (status)
             assign_string (&save_name, 0);  
   
           if (f >= 0)  
1376              {              {
1377                struct stat final_stat;              case dump_status_ok:
1378                if (fstat (f, &final_stat) != 0)                if (multi_volume_option)
1379                  {                  assign_string (&save_name, 0);
1380                    if (ignore_failed_read_option)                dump_regular_finish (fd, stat, original_ctime);
1381                      stat_warn (p);                break;
                   else  
                     stat_error (p);  
                 }  
               else if (final_stat.st_ctime != original_ctime)  
                 {  
                   char const *qp = quotearg_colon (p);  
                   WARN ((0, 0, _("%s: file changed as we read it"), qp));  
                 }  
               if (close (f) != 0)  
                 {  
                   if (ignore_failed_read_option)  
                     close_warn (p);  
                   else  
                     close_error (p);  
                 }  
               if (atime_preserve_option)  
                 utime (p, &restore_times);  
             }  
           if (remove_files_option)  
             {  
               if (unlink (p) == -1)  
                 unlink_error (p);  
             }  
           goto file_was_dumped;  
1382    
1383            /* File shrunk or gave error, pad out tape to match the size we              case dump_status_short:
1384               specified in the header.  */                if (multi_volume_option)
1385                    assign_string (&save_name, 0);
1386                  close (fd);
1387                  break;
1388          
1389                case dump_status_fail:
1390                  close (fd);
1391                  return;
1392    
1393          padit:              case dump_status_not_implemented:
1394            while (sizeleft > 0)                abort ();
             {  
               save_sizeleft = sizeleft;  
               start = find_next_block ();  
               memset (start->buffer, 0, BLOCKSIZE);  
               set_next_block_after (start);  
               sizeleft -= BLOCKSIZE;  
1395              }              }
1396            if (multi_volume_option)  
1397              assign_string (&save_name, 0);            if (atime_preserve_option)
1398            if (f >= 0)              utime (stat->orig_file_name, &restore_times);
1399              {            file_count_links (stat);
1400                close (f);            return;
               if (atime_preserve_option)  
                 utime (p, &restore_times);  
             }  
           goto file_was_dumped;  
1401          }          }
1402  #ifdef HAVE_READLINK  #ifdef HAVE_READLINK
1403        else if (S_ISLNK (current_stat_info.stat.st_mode))        else if (S_ISLNK (stat->stat.st_mode))
1404          {          {
1405            char *buffer;            char *buffer;
1406            int size;            int size;
1407            size_t linklen = current_stat_info.stat.st_size;            size_t linklen = stat->stat.st_size;
1408            if (linklen != current_stat_info.stat.st_size || linklen + 1 == 0)            if (linklen != stat->stat.st_size || linklen + 1 == 0)
1409              xalloc_die ();              xalloc_die ();
1410            buffer = (char *) alloca (linklen + 1);            buffer = (char *) alloca (linklen + 1);
1411            size = readlink (p, buffer, linklen + 1);            size = readlink (p, buffer, linklen + 1);
1412            if (size < 0)            if (size < 0)
1413              {              {
1414                if (ignore_failed_read_option)                readlink_diag (p);
                 readlink_warn (p);  
               else  
                 readlink_error (p);  
1415                return;                return;
1416              }              }
1417            buffer[size] = '\0';            buffer[size] = '\0';
1418            assign_string (&current_stat_info.link_name, buffer);            assign_string (&stat->link_name, buffer);
1419            if (size > NAME_FIELD_SIZE)            if (size > NAME_FIELD_SIZE)
1420              write_long_link (&current_stat_info);              write_long_link (stat);
1421    
1422            block_ordinal = current_block_ordinal ();            block_ordinal = current_block_ordinal ();
1423            current_stat_info.stat.st_size = 0;   /* force 0 size on symlink */            stat->stat.st_size = 0;       /* force 0 size on symlink */
1424            header = start_header (p, &current_stat_info);            header = start_header (stat);
1425            if (!header)            if (!header)
1426              return;              return;
1427            tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);            tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
1428            header->header.typeflag = SYMTYPE;            header->header.typeflag = SYMTYPE;
1429            finish_header (header, block_ordinal);            finish_header (stat, header, block_ordinal);
1430            /* nothing more to do to it */            /* nothing more to do to it */
1431    
1432            if (remove_files_option)            if (remove_files_option)
# Line 1709  dump_file (char *p, int top_level, dev_t Line 1434  dump_file (char *p, int top_level, dev_t
1434                if (unlink (p) == -1)                if (unlink (p) == -1)
1435                  unlink_error (p);                  unlink_error (p);
1436              }              }
1437            goto file_was_dumped;            file_count_links (stat);
1438              return;
1439          }          }
1440  #endif  #endif
1441        else if (S_ISCHR (current_stat_info.stat.st_mode))        else if (S_ISCHR (stat->stat.st_mode))
1442          type = CHRTYPE;          type = CHRTYPE;
1443        else if (S_ISBLK (current_stat_info.stat.st_mode))        else if (S_ISBLK (stat->stat.st_mode))
1444          type = BLKTYPE;          type = BLKTYPE;
1445        else if (S_ISFIFO (current_stat_info.stat.st_mode))        else if (S_ISFIFO (stat->stat.st_mode))
1446          type = FIFOTYPE;          type = FIFOTYPE;
1447        else if (S_ISSOCK (current_stat_info.stat.st_mode))        else if (S_ISSOCK (stat->stat.st_mode))
1448          {          {
1449            WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));            WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
1450            return;            return;
1451          }          }
1452        else if (S_ISDOOR (current_stat_info.stat.st_mode))        else if (S_ISDOOR (stat->stat.st_mode))
1453          {          {
1454            WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));            WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
1455            return;            return;
1456          }          }
1457        else        else
1458          goto unknown;          {
1459              unknown_file_error (p);
1460              return;
1461            }
1462      }      }
1463    
1464    if (archive_format == V7_FORMAT)    if (archive_format == V7_FORMAT)
1465      goto unknown;      {
1466          unknown_file_error (p);
1467          return;
1468        }
1469    
1470    block_ordinal = current_block_ordinal ();    block_ordinal = current_block_ordinal ();
1471    current_stat_info.stat.st_size = 0;   /* force 0 size */    stat->stat.st_size = 0;       /* force 0 size */
1472    header = start_header (p, &current_stat_info);    header = start_header (stat);
1473    if (!header)    if (!header)
1474      return;      return;
1475    header->header.typeflag = type;    header->header.typeflag = type;
1476    
1477    if (type != FIFOTYPE)    if (type != FIFOTYPE)
1478      {      {
1479        MAJOR_TO_CHARS (major (current_stat_info.stat.st_rdev),        MAJOR_TO_CHARS (major (stat->stat.st_rdev),
1480                        header->header.devmajor);                        header->header.devmajor);
1481        MINOR_TO_CHARS (minor (current_stat_info.stat.st_rdev),        MINOR_TO_CHARS (minor (stat->stat.st_rdev),
1482                        header->header.devminor);                        header->header.devminor);
1483      }      }
1484    
1485    finish_header (header, block_ordinal);    finish_header (stat, header, block_ordinal);
1486    if (remove_files_option)    if (remove_files_option)
1487      {      {
1488        if (unlink (p) == -1)        if (unlink (p) == -1)
1489          unlink_error (p);          unlink_error (p);
1490      }      }
   goto file_was_dumped;  
   
 unknown:  
   WARN ((0, 0, _("%s: Unknown file type; file ignored"),  
          quotearg_colon (p)));  
   if (! ignore_failed_read_option)  
     exit_status = TAREXIT_FAILURE;  
   return;  
   
 file_was_dumped:  
   if (1 < current_stat_info.stat.st_nlink)  
     {  
       struct link *dup;  
       struct link *lp = xmalloc (offsetof (struct link, name)  
                                  + strlen (p) + 1);  
       lp->ino = current_stat_info.stat.st_ino;  
       lp->dev = current_stat_info.stat.st_dev;  
       lp->nlink = current_stat_info.stat.st_nlink;  
       strcpy (lp->name, p);  
   
       if (! ((link_table  
               || (link_table = hash_initialize (0, 0, hash_link,  
                                                 compare_links, 0)))  
              && (dup = hash_insert (link_table, lp))))  
         xalloc_die ();  
   
       if (dup != lp)  
         abort ();  
       lp->nlink--;  
     }  
   
1491  }  }
1492    
 /* For each dumped file, check if all its links were dumped. Emit  
    warnings if it is not so. */  
1493  void  void
1494  check_links ()  dump_file (char *p, int top_level, dev_t parent_device)
1495  {  {
1496    struct link *lp;    struct tar_stat_info stat;
1497      tar_stat_init (&stat);
1498    if (!link_table)    dump_file0 (&stat, p, top_level, parent_device);
1499      return;    tar_stat_destroy (&stat);
   
   for (lp = hash_get_first (link_table); lp;  
        lp = hash_get_next (link_table, lp))  
     {  
       if (lp->nlink)  
         {  
           WARN ((0, 0, _("Missing links to '%s'.\n"), lp->name));  
         }  
     }  
1500  }  }

Legend:
Removed from v.1.69  
changed lines
  Added in v.1.70

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26