home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / arc / Archiver / cpio / src / copyout.c < prev    next >
C/C++ Source or Header  |  1992-09-19  |  14KB  |  492 lines

  1. /* copyout.c - create a cpio archive
  2.    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  3.  
  4.    This program 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 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include "filetypes.h"
  22. #include "system.h"
  23. #include "cpiohdr.h"
  24. #include "dstring.h"
  25. #include "extern.h"
  26. #include "rmt.h"
  27.  
  28. static unsigned long read_for_checksum ();
  29. static void clear_rest_of_block ();
  30. static void pad_output ();
  31.  
  32. /* Write out header FILE_HDR, including the file name, to file
  33.    descriptor OUT_DES.  */
  34.  
  35. void
  36. write_out_header (file_hdr, out_des)
  37.      struct new_cpio_header *file_hdr;
  38.      int out_des;
  39. {
  40.   if (archive_format == arf_newascii || archive_format == arf_crcascii)
  41.     {
  42.       char ascii_header[112];
  43.       char *magic_string;
  44.  
  45.       if (archive_format == arf_crcascii)
  46.     magic_string = "070702";
  47.       else
  48.     magic_string = "070701";
  49.       sprintf (ascii_header,
  50.            "%6s%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
  51.            magic_string,
  52.            file_hdr->c_ino, file_hdr->c_mode, file_hdr->c_uid,
  53.            file_hdr->c_gid, file_hdr->c_nlink, file_hdr->c_mtime,
  54.          file_hdr->c_filesize, file_hdr->c_dev_maj, file_hdr->c_dev_min,
  55.        file_hdr->c_rdev_maj, file_hdr->c_rdev_min, file_hdr->c_namesize,
  56.            file_hdr->c_chksum);
  57.       copy_buf_out (ascii_header, out_des, 110L);
  58.  
  59.       /* Write file name to output.  */
  60.       copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
  61.       pad_output (out_des, file_hdr->c_namesize + 110);
  62.     }
  63.   else if (archive_format == arf_oldascii)
  64.     {
  65.       char ascii_header[78];
  66. #ifndef __MSDOS__
  67.       dev_t dev;
  68.       dev_t rdev;
  69.  
  70.       dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
  71.       rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
  72. #else
  73.       int dev = 0, rdev = 0;
  74. #endif
  75.  
  76.       if ((file_hdr->c_ino >> 16) != 0)
  77.     error (0, 0, "%s: truncating inode number", file_hdr->c_name);
  78.  
  79.       sprintf (ascii_header,
  80.            "%06o%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo",
  81.            file_hdr->c_magic & 0xFFFF, dev & 0xFFFF,
  82.            file_hdr->c_ino & 0xFFFF, file_hdr->c_mode & 0xFFFF,
  83.            file_hdr->c_uid & 0xFFFF, file_hdr->c_gid & 0xFFFF,
  84.            file_hdr->c_nlink & 0xFFFF, rdev & 0xFFFF,
  85.            file_hdr->c_mtime, file_hdr->c_namesize & 0xFFFF,
  86.            file_hdr->c_filesize);
  87.       copy_buf_out (ascii_header, out_des, 76L);
  88.  
  89.       /* Write file name to output.  */
  90.       copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
  91.     }
  92.   else if (archive_format == arf_tar || archive_format == arf_ustar)
  93.     {
  94.       write_out_tar_header (file_hdr, out_des);
  95.     }
  96.   else
  97.     {
  98.       struct old_cpio_header short_hdr;
  99.  
  100.       short_hdr.c_magic = 070707;
  101.       short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
  102.  
  103.       if ((file_hdr->c_ino >> 16) != 0)
  104.     error (0, 0, "%s: truncating inode number", file_hdr->c_name);
  105.  
  106.       short_hdr.c_ino = file_hdr->c_ino & 0xFFFF;
  107.       short_hdr.c_mode = file_hdr->c_mode & 0xFFFF;
  108.       short_hdr.c_uid = file_hdr->c_uid & 0xFFFF;
  109.       short_hdr.c_gid = file_hdr->c_gid & 0xFFFF;
  110.       short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF;
  111.       short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
  112.       short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16;
  113.       short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF;
  114.  
  115.       short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF;
  116.  
  117.       short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16;
  118.       short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF;
  119.  
  120.       /* Output the file header.  */
  121.       copy_buf_out ((char *) &short_hdr, out_des, 26L);
  122.  
  123.       /* Write file name to output.  */
  124.       copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
  125.  
  126.       pad_output (out_des, file_hdr->c_namesize + 26);
  127.     }
  128. }
  129.  
  130. /* Read a list of file names from the standard input
  131.    and write a cpio collection on the standard output.
  132.    The format of the header depends on the compatibility (-c) flag.  */
  133.  
  134. void
  135. process_copy_out ()
  136. {
  137.   int res;            /* Result of functions.  */
  138.   dynamic_string input_name;    /* Name of file read from stdin.  */
  139.   struct utimbuf times;        /* For resetting file times after copy.  */
  140.   struct stat file_stat;    /* Stat record for file.  */
  141.   struct new_cpio_header file_hdr; /* Output header information.  */
  142.   int in_file_des;        /* Source file descriptor.  */
  143.   int out_file_des;        /* Output file descriptor.  */
  144.   char *p;
  145.  
  146.   /* Initialize the copy out.  */
  147.   ds_init (&input_name, 128);
  148.   /* Initialize this in case it has members we don't know to set.  */
  149.   bzero (×, sizeof (struct utimbuf));
  150.   file_hdr.c_magic = 070707;
  151.  
  152. #ifdef __MSDOS__
  153.   setmode (archive_des, O_BINARY);
  154. #endif
  155.   /* Check whether the output file might be a tape.  */
  156.   out_file_des = archive_des;
  157.   if (_isrmt (out_file_des))
  158.     {
  159.       output_is_special = 1;
  160.       output_is_seekable = 0;
  161.     }
  162.   else
  163.     {
  164.       if (fstat (out_file_des, &file_stat))
  165.     error (1, errno, "standard output is closed");
  166.       output_is_special =
  167. #ifdef S_ISBLK
  168.     S_ISBLK (file_stat.st_mode) ||
  169. #endif
  170.     S_ISCHR (file_stat.st_mode);
  171.       output_is_seekable = S_ISREG (file_stat.st_mode);
  172.     }
  173.  
  174.   if (append_flag)
  175.     {
  176.       process_copy_in ();
  177.       prepare_append (out_file_des);
  178.     }
  179.  
  180.   /* Copy files with names read from stdin.  */
  181.   while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
  182.     {
  183.       /* Check for blank line.  */
  184.       if (input_name.ds_string[0] == 0)
  185.     {
  186.       error (0, 0, "blank line ignored");
  187.       continue;
  188.     }
  189.  
  190.       /* Process next file.  */
  191.       if ((*xstat) (input_name.ds_string, &file_stat) < 0)
  192.     error (0, errno, "%s", input_name.ds_string);
  193.       else
  194.     {
  195.       /* Set values in output header.  */
  196.       file_hdr.c_dev_maj = major (file_stat.st_dev);
  197.       file_hdr.c_dev_min = minor (file_stat.st_dev);
  198.       file_hdr.c_ino = file_stat.st_ino;
  199.       /* For POSIX systems that don't define the S_IF macros,
  200.          we can't assume that S_ISfoo means the standard Unix
  201.          S_IFfoo bit(s) are set.  So do it manually, with a
  202.          different name.  Bleah.  */
  203.       file_hdr.c_mode = (file_stat.st_mode & 07777);
  204.       if (S_ISREG (file_stat.st_mode))
  205.         file_hdr.c_mode |= CP_IFREG;
  206.       else if (S_ISDIR (file_stat.st_mode))
  207.         file_hdr.c_mode |= CP_IFDIR;
  208. #ifdef S_ISBLK
  209.       else if (S_ISBLK (file_stat.st_mode))
  210.         file_hdr.c_mode |= CP_IFBLK;
  211. #endif
  212. #ifdef S_ISCHR
  213.       else if (S_ISCHR (file_stat.st_mode))
  214.         file_hdr.c_mode |= CP_IFCHR;
  215. #endif
  216. #ifdef S_ISFIFO
  217.       else if (S_ISFIFO (file_stat.st_mode))
  218.         file_hdr.c_mode |= CP_IFIFO;
  219. #endif
  220. #ifdef S_ISLNK
  221.       else if (S_ISLNK (file_stat.st_mode))
  222.         file_hdr.c_mode |= CP_IFLNK;
  223. #endif
  224. #ifdef S_ISSOCK
  225.       else if (S_ISSOCK (file_stat.st_mode))
  226.         file_hdr.c_mode |= CP_IFSOCK;
  227. #endif
  228. #ifdef S_ISNWK
  229.       else if (S_ISNWK (file_stat.st_mode))
  230.         file_hdr.c_mode |= CP_IFNWK;
  231. #endif
  232.       file_hdr.c_uid = file_stat.st_uid;
  233.       file_hdr.c_gid = file_stat.st_gid;
  234.       file_hdr.c_nlink = file_stat.st_nlink;
  235.       file_hdr.c_rdev_maj = major (file_stat.st_rdev);
  236.       file_hdr.c_rdev_min = minor (file_stat.st_rdev);
  237.       file_hdr.c_mtime = file_stat.st_mtime;
  238.       file_hdr.c_filesize = file_stat.st_size;
  239.       file_hdr.c_chksum = 0;
  240.       file_hdr.c_tar_linkname = NULL;
  241.  
  242.       /* Strip leading `./' from the filename.  */
  243.       p = input_name.ds_string;
  244.       while (*p == '.' && *(p + 1) == '/')
  245.         {
  246.           ++p;
  247.           while (*p == '/')
  248.         ++p;
  249.         }
  250.       file_hdr.c_name = p;
  251.       file_hdr.c_namesize = strlen (p) + 1;
  252.       if ((archive_format == arf_tar || archive_format == arf_ustar)
  253.           && is_tar_filename_too_long (file_hdr.c_name))
  254.         {
  255.           error (0, 0, "%s: file name too long", file_hdr.c_name);
  256.           continue;
  257.         }
  258.  
  259.       /* Copy the named file to the output.  */
  260.       switch (file_hdr.c_mode & CP_IFMT)
  261.         {
  262.         case CP_IFREG:
  263. #ifndef __MSDOS__
  264.           if (archive_format == arf_tar || archive_format == arf_ustar)
  265.         {
  266.           char *otherfile;
  267.           if (otherfile = find_inode_file (file_hdr.c_ino,
  268.                            file_hdr.c_dev_maj,
  269.                            file_hdr.c_dev_min))
  270.             {
  271.               file_hdr.c_tar_linkname = otherfile;
  272.               write_out_header (&file_hdr, out_file_des);
  273.               break;
  274.             }
  275.         }
  276. #endif
  277.           in_file_des = open (input_name.ds_string,
  278.                   O_RDONLY | O_BINARY, 0);
  279.           if (in_file_des < 0)
  280.         {
  281.           error (0, errno, "%s", input_name.ds_string);
  282.           continue;
  283.         }
  284.  
  285.           if (archive_format == arf_crcascii)
  286.         file_hdr.c_chksum = read_for_checksum (in_file_des,
  287.                                file_hdr.c_filesize,
  288.                                input_name.ds_string);
  289.  
  290.           write_out_header (&file_hdr, out_file_des);
  291.           copy_files (in_file_des, out_file_des, file_hdr.c_filesize);
  292.  
  293. #ifndef __MSDOS__
  294.           if (archive_format == arf_tar || archive_format == arf_ustar)
  295.         add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
  296.                file_hdr.c_dev_min);
  297. #endif
  298.  
  299.           pad_output (out_file_des, file_hdr.c_filesize);
  300.  
  301.           if (close (in_file_des) < 0)
  302.         error (0, errno, "%s", input_name.ds_string);
  303.           if (reset_time_flag)
  304.         {
  305.           times.actime = file_stat.st_atime;
  306.           times.modtime = file_stat.st_mtime;
  307.           if (utime (file_hdr.c_name, ×) < 0)
  308.             error (0, errno, "%s", file_hdr.c_name);
  309.         }
  310.           break;
  311.  
  312.         case CP_IFDIR:
  313.           file_hdr.c_filesize = 0;
  314.           write_out_header (&file_hdr, out_file_des);
  315.           break;
  316.  
  317. #ifndef __MSDOS__
  318.         case CP_IFCHR:
  319.         case CP_IFBLK:
  320. #ifdef CP_IFSOCK
  321.         case CP_IFSOCK:
  322. #endif
  323. #ifdef CP_IFIFO
  324.         case CP_IFIFO:
  325. #endif
  326.           if (archive_format == arf_tar)
  327.         {
  328.           error (0, 0, "%s not dumped: not a regular file",
  329.              file_hdr.c_name);
  330.           continue;
  331.         }
  332.           file_hdr.c_filesize = 0;
  333.           write_out_header (&file_hdr, out_file_des);
  334.           break;
  335. #endif
  336.  
  337. #ifdef CP_IFLNK
  338.         case CP_IFLNK:
  339.           {
  340.         char *link_name = (char *) xmalloc (file_stat.st_size + 1);
  341.  
  342.         if (readlink (input_name.ds_string, link_name,
  343.                   file_stat.st_size) < 0)
  344.           {
  345.             error (0, errno, "%s", input_name.ds_string);
  346.             free (link_name);
  347.             continue;
  348.           }
  349.         if (archive_format == arf_tar || archive_format == arf_ustar)
  350.           {
  351.             if (file_stat.st_size + 1 > 100)
  352.               {
  353.             error (0, 0, "%s: symbolic link too long",
  354.                    file_hdr.c_name);
  355.               }
  356.             else
  357.               {
  358.             link_name[file_stat.st_size] = '\0';
  359.             file_hdr.c_tar_linkname = link_name;
  360.             write_out_header (&file_hdr, out_file_des);
  361.               }
  362.           }
  363.         else
  364.           {
  365.             write_out_header (&file_hdr, out_file_des);
  366.             copy_buf_out (link_name, out_file_des, file_stat.st_size);
  367.             pad_output (out_file_des, file_hdr.c_filesize);
  368.           }
  369.         free (link_name);
  370.           }
  371.           break;
  372. #endif
  373.  
  374.         default:
  375.           error (0, 0, "%s: unknown file type", input_name.ds_string);
  376.         }
  377.  
  378.       if (verbose_flag)
  379.         fprintf (stderr, "%s\n", input_name.ds_string);
  380.       if (dot_flag)
  381.         fputc ('.', stderr);
  382.     }
  383.     }
  384.  
  385.   /* The collection is complete; append the trailer.  */
  386.   file_hdr.c_ino = 0;
  387.   file_hdr.c_mode = 0;
  388.   file_hdr.c_uid = 0;
  389.   file_hdr.c_gid = 0;
  390.   file_hdr.c_nlink = 1;        /* Must be 1 for SVR4 crc format.  */
  391.   file_hdr.c_dev_maj = 0;
  392.   file_hdr.c_dev_min = 0;
  393.   file_hdr.c_rdev_maj = 0;
  394.   file_hdr.c_rdev_min = 0;
  395.   file_hdr.c_mtime = 0;
  396.   file_hdr.c_chksum = 0;
  397.  
  398.   file_hdr.c_filesize = 0;
  399.   file_hdr.c_namesize = 11;
  400.   file_hdr.c_name = "TRAILER!!!";
  401.   if (archive_format != arf_tar && archive_format != arf_ustar)
  402.     write_out_header (&file_hdr, out_file_des);
  403.   else
  404.     {
  405.       copy_buf_out (zeros_512, out_file_des, 512);
  406.       copy_buf_out (zeros_512, out_file_des, 512);
  407.     }
  408.  
  409.   /* Fill up the output block.  */
  410.   clear_rest_of_block (out_file_des);
  411.   empty_output_buffer (out_file_des);
  412.   if (dot_flag)
  413.     fputc ('\n', stderr);
  414.   res = (output_bytes + io_block_size - 1) / io_block_size;
  415.   if (res == 1)
  416.     fprintf (stderr, "1 block\n");
  417.   else
  418.     fprintf (stderr, "%d blocks\n", res);
  419. }
  420.  
  421. /* Read FILE_SIZE bytes of FILE_NAME from IN_FILE_DES and
  422.    compute and return a checksum for them.  */
  423.  
  424. static unsigned long
  425. read_for_checksum (in_file_des, file_size, file_name)
  426.      int in_file_des;
  427.      int file_size;
  428.      char *file_name;
  429. {
  430.   unsigned long crc;
  431.   char buf[BUFSIZ];
  432.   int bytes_left;
  433.   int bytes_read;
  434.   int i;
  435.  
  436.   crc = 0;
  437.  
  438.   for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read)
  439.     {
  440.       bytes_read = read (in_file_des, buf, BUFSIZ);
  441.       if (bytes_read < 0)
  442.     error (1, errno, "cannot read checksum for %s", file_name);
  443.       if (bytes_read == 0)
  444.     break;
  445.       for (i = 0; i < bytes_read; ++i)
  446.     crc += buf[i] & 0xff;
  447.     }
  448.   if (lseek (in_file_des, 0L, SEEK_SET))
  449.     error (1, errno, "cannot read checksum for %s", file_name);
  450.  
  451.   return crc;
  452. }
  453.  
  454. /* Write out NULs to fill out the rest of the current block on
  455.    OUT_FILE_DES.  */
  456.  
  457. static void
  458. clear_rest_of_block (out_file_des)
  459.      int out_file_des;
  460. {
  461.   while (output_size < io_block_size)
  462.     {
  463.       if ((io_block_size - output_size) > 512)
  464.     copy_buf_out (zeros_512, out_file_des, 512);
  465.       else
  466.     copy_buf_out (zeros_512, out_file_des, io_block_size - output_size);
  467.     }
  468. }
  469.  
  470. /* Write NULs on OUT_FILE_DES to move from OFFSET (the current location)
  471.    to the end of the header.  */
  472.  
  473. static void
  474. pad_output (out_file_des, offset)
  475.      int out_file_des;
  476.      int offset;
  477. {
  478.   int pad;
  479.  
  480.   if (archive_format == arf_newascii || archive_format == arf_crcascii)
  481.     pad = (4 - (offset % 4)) % 4;
  482.   else if (archive_format == arf_tar || archive_format == arf_ustar)
  483.     pad = (512 - (offset % 512)) % 512;
  484.   else if (archive_format != arf_oldascii)
  485.     pad = (2 - (offset % 2)) % 2;
  486.   else
  487.     pad = 0;
  488.  
  489.   if (pad != 0)
  490.     copy_buf_out (zeros_512, out_file_des, pad);
  491. }
  492.