home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / cpio-2.3-src.lha / src / amiga / cpio-2.3 / copypass.c < prev    next >
C/C++ Source or Header  |  1993-05-04  |  14KB  |  450 lines

  1. /* copypass.c - cpio copy pass sub-function.
  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.  
  27. #ifndef HAVE_LCHOWN
  28. #define lchown chown
  29. #endif
  30.  
  31. /* Copy files listed on the standard input into directory `directory_name'.
  32.    If `link_flag', link instead of copying.  */
  33.  
  34. void
  35. process_copy_pass ()
  36. {
  37.   dynamic_string input_name;    /* Name of file from stdin.  */
  38.   dynamic_string output_name;    /* Name of new file.  */
  39.   int dirname_len;        /* Length of `directory_name'.  */
  40.   int res;            /* Result of functions.  */
  41.   char *slash;            /* For moving past slashes in input name.  */
  42.   struct utimbuf times;        /* For resetting file times after copy.  */
  43.   struct stat in_file_stat;    /* Stat record for input file.  */
  44.   struct stat out_file_stat;    /* Stat record for output file.  */
  45.   int in_file_des;        /* Input file descriptor.  */
  46.   int out_file_des;        /* Output file descriptor.  */
  47.   int existing_dir;        /* True if file is a dir & already exists.  */
  48. #ifdef HPUX_CDF
  49.   int cdf_flag;
  50.   int cdf_char;
  51. #endif
  52.  
  53.   /* Initialize the copy pass.  */
  54.   dirname_len = strlen (directory_name);
  55.   ds_init (&input_name, 128);
  56.   ds_init (&output_name, dirname_len + 2);
  57.   strcpy (output_name.ds_string, directory_name);
  58.   output_name.ds_string[dirname_len] = '/';
  59.   output_is_seekable = TRUE;
  60.   /* Initialize this in case it has members we don't know to set.  */
  61.   bzero (×, sizeof (struct utimbuf));
  62.  
  63.   /* Copy files with names read from stdin.  */
  64.   while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
  65.     {
  66.       int link_res = -1;
  67.  
  68.       /* Check for blank line and ignore it if found.  */
  69.       if (input_name.ds_string[0] == '\0')
  70.     {
  71.       error (0, 0, "blank line ignored");
  72.       continue;
  73.     }
  74.  
  75.       /* Check for current directory and ignore it if found.  */
  76.       if (input_name.ds_string[0] == '.'
  77.       && (input_name.ds_string[1] == '\0'
  78.           || (input_name.ds_string[1] == '/'
  79.           && input_name.ds_string[2] == '\0')))
  80.     continue;
  81.  
  82.       if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
  83.     {
  84.       error (0, errno, "%s", input_name.ds_string);
  85.       continue;
  86.     }
  87.  
  88.       /* Make the name of the new file.  */
  89.       for (slash = input_name.ds_string; *slash == '/'; ++slash)
  90.     ;
  91. #ifdef HPUX_CDF
  92.       /* For CDF's we add a 2nd `/' after all "hidden" directories.
  93.      This kind of a kludge, but it's what we do when creating
  94.      archives, and it's easier to do this than to separately
  95.      keep track of which directories in a path are "hidden".  */
  96.       slash = add_cdf_double_slashes (slash);
  97. #endif
  98.       ds_resize (&output_name, dirname_len + strlen (slash) + 2);
  99.       strcpy (output_name.ds_string + dirname_len + 1, slash);
  100.  
  101.       existing_dir = FALSE;
  102.       if (lstat (output_name.ds_string, &out_file_stat) == 0)
  103.     {
  104.       if (S_ISDIR (out_file_stat.st_mode)
  105.           && S_ISDIR (in_file_stat.st_mode))
  106.         {
  107.           /* If there is already a directory there that
  108.          we are trying to create, don't complain about it.  */
  109.           existing_dir = TRUE;
  110.         }
  111.       else if (!unconditional_flag
  112.            && in_file_stat.st_mtime <= out_file_stat.st_mtime)
  113.         {
  114.           error (0, 0, "%s not created: newer or same age version exists",
  115.              output_name.ds_string);
  116.           continue;        /* Go to the next file.  */
  117.         }
  118.       else if (S_ISDIR (out_file_stat.st_mode)
  119.             ? rmdir (output_name.ds_string)
  120.             : unlink (output_name.ds_string))
  121.         {
  122.           error (0, errno, "cannot remove current %s",
  123.              output_name.ds_string);
  124.           continue;        /* Go to the next file.  */
  125.         }
  126.     }
  127.  
  128.       /* Do the real copy or link.  */
  129.       if (S_ISREG (in_file_stat.st_mode))
  130.     {
  131. #ifndef __MSDOS__
  132.       /* Can the current file be linked to a another file?
  133.          Set link_name to the original file name.  */
  134.       if (link_flag)
  135.         /* User said to link it if possible.  Try and link to
  136.            the original copy.  If that fails we'll still try
  137.            and link to a copy we've already made.  */
  138.         link_res = link_to_name (output_name.ds_string, 
  139.                      input_name.ds_string);
  140.       if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
  141.         link_res = link_to_maj_min_ino (output_name.ds_string, 
  142.                 major (in_file_stat.st_dev), 
  143.                 minor (in_file_stat.st_dev), 
  144.                 in_file_stat.st_ino);
  145. #endif
  146.  
  147.       /* If the file was not linked, copy contents of file.  */
  148.       if (link_res < 0)
  149.         {
  150.           in_file_des = open (input_name.ds_string,
  151.                   O_RDONLY | O_BINARY, 0);
  152.           if (in_file_des < 0)
  153.         {
  154.           error (0, errno, "%s", input_name.ds_string);
  155.           continue;
  156.         }
  157.           out_file_des = open (output_name.ds_string,
  158.                    O_CREAT | O_WRONLY | O_BINARY, 0600);
  159.           if (out_file_des < 0 && create_dir_flag)
  160.         {
  161.           create_all_directories (output_name.ds_string);
  162.           out_file_des = open (output_name.ds_string,
  163.                        O_CREAT | O_WRONLY | O_BINARY, 0600);
  164.         }
  165.           if (out_file_des < 0)
  166.         {
  167.           error (0, errno, "%s", output_name.ds_string);
  168.           close (in_file_des);
  169.           continue;
  170.         }
  171.  
  172.           copy_files (in_file_des, out_file_des, in_file_stat.st_size);
  173.           empty_output_buffer (out_file_des);
  174.           if (close (in_file_des) < 0)
  175.         error (0, errno, "%s", input_name.ds_string);
  176.           if (close (out_file_des) < 0)
  177.         error (0, errno, "%s", output_name.ds_string);
  178.  
  179.           /* Set the attributes of the new file.  */
  180.           if (!no_chown_flag)
  181.         if ((chown (output_name.ds_string,
  182.                 set_owner_flag ? set_owner : in_file_stat.st_uid,
  183.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  184.             && errno != EPERM)
  185.           error (0, errno, "%s", output_name.ds_string);
  186.           /* chown may have turned off some permissions we wanted. */
  187.           if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  188.         error (0, errno, "%s", output_name.ds_string);
  189.           if (reset_time_flag)
  190.         {
  191.           times.actime = in_file_stat.st_atime;
  192.           times.modtime = in_file_stat.st_mtime;
  193.           if (utime (input_name.ds_string, ×) < 0)
  194.             error (0, errno, "%s", input_name.ds_string);
  195.           if (utime (output_name.ds_string, ×) < 0)
  196.             error (0, errno, "%s", output_name.ds_string);
  197.         }
  198.           if (retain_time_flag)
  199.         {
  200.           times.actime = times.modtime = in_file_stat.st_mtime;
  201.           if (utime (output_name.ds_string, ×) < 0)
  202.             error (0, errno, "%s", output_name.ds_string);
  203.         }
  204.         }
  205.     }
  206.       else if (S_ISDIR (in_file_stat.st_mode))
  207.     {
  208. #ifdef HPUX_CDF
  209.       cdf_flag = 0;
  210. #endif
  211.       if (!existing_dir)
  212.         {
  213. #ifdef HPUX_CDF
  214.           /* If the directory name ends in a + and is SUID,
  215.          then it is a CDF.  Strip the trailing + from the name
  216.          before creating it.  */
  217.           cdf_char = strlen (output_name.ds_string) - 1;
  218.           if ( (cdf_char > 0) &&
  219.            (in_file_stat.st_mode & 04000) &&
  220.            (output_name.ds_string [cdf_char] == '+') )
  221.         {
  222.           output_name.ds_string [cdf_char] = '\0';
  223.           cdf_flag = 1;
  224.         }
  225. #endif
  226.           res = mkdir (output_name.ds_string, in_file_stat.st_mode);
  227.  
  228.         }
  229.       else
  230.         res = 0;
  231.       if (res < 0 && create_dir_flag)
  232.         {
  233.           create_all_directories (output_name.ds_string);
  234.           res = mkdir (output_name.ds_string, in_file_stat.st_mode);
  235.         }
  236.       if (res < 0)
  237.         {
  238.           error (0, errno, "%s", output_name.ds_string);
  239.           continue;
  240.         }
  241.       if (!no_chown_flag)
  242.         if ((chown (output_name.ds_string,
  243.             set_owner_flag ? set_owner : in_file_stat.st_uid,
  244.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  245.         && errno != EPERM)
  246.           error (0, errno, "%s", output_name.ds_string);
  247.       /* chown may have turned off some permissions we wanted. */
  248.       if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  249.         error (0, errno, "%s", output_name.ds_string);
  250. #ifdef HPUX_CDF
  251.       if (cdf_flag)
  252.         /* Once we "hide" the directory with the chmod(),
  253.            we have to refer to it using name+ isntead of name.  */
  254.         output_name.ds_string [cdf_char] = '+';
  255. #endif
  256.       if (retain_time_flag)
  257.         {
  258.           times.actime = times.modtime = in_file_stat.st_mtime;
  259.           if (utime (output_name.ds_string, ×) < 0)
  260.         error (0, errno, "%s", output_name.ds_string);
  261.         }
  262.     }
  263. #ifndef __MSDOS__
  264.       else if (S_ISCHR (in_file_stat.st_mode) ||
  265.            S_ISBLK (in_file_stat.st_mode) ||
  266. #ifdef S_ISFIFO
  267.            S_ISFIFO (in_file_stat.st_mode) ||
  268. #endif
  269. #ifdef S_ISSOCK
  270.            S_ISSOCK (in_file_stat.st_mode) ||
  271. #endif
  272.            0)
  273.     {
  274.       /* Can the current file be linked to a another file?
  275.          Set link_name to the original file name.  */
  276.       if (link_flag)
  277.         /* User said to link it if possible.  */
  278.         link_res = link_to_name (output_name.ds_string, 
  279.                      input_name.ds_string);
  280.       if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
  281.         link_res = link_to_maj_min_ino (output_name.ds_string, 
  282.             major (in_file_stat.st_dev),
  283.             minor (in_file_stat.st_dev),
  284.             in_file_stat.st_ino);
  285.  
  286.       if (link_res < 0)
  287.         {
  288.           res = mknod (output_name.ds_string, in_file_stat.st_mode,
  289.                in_file_stat.st_rdev);
  290.           if (res < 0 && create_dir_flag)
  291.         {
  292.           create_all_directories (output_name.ds_string);
  293.           res = mknod (output_name.ds_string, in_file_stat.st_mode,
  294.                    in_file_stat.st_rdev);
  295.         }
  296.           if (res < 0)
  297.         {
  298.           error (0, errno, "%s", output_name.ds_string);
  299.           continue;
  300.         }
  301.           if (!no_chown_flag)
  302.         if ((chown (output_name.ds_string,
  303.                 set_owner_flag ? set_owner : in_file_stat.st_uid,
  304.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  305.             && errno != EPERM)
  306.           error (0, errno, "%s", output_name.ds_string);
  307.           /* chown may have turned off some permissions we wanted. */
  308.           if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
  309.         error (0, errno, "%s", output_name.ds_string);
  310.           if (retain_time_flag)
  311.         {
  312.           times.actime = times.modtime = in_file_stat.st_mtime;
  313.           if (utime (output_name.ds_string, ×) < 0)
  314.             error (0, errno, "%s", output_name.ds_string);
  315.         }
  316.         }
  317.     }
  318. #endif
  319.  
  320. #ifdef S_ISLNK
  321.       else if (S_ISLNK (in_file_stat.st_mode))
  322.     {
  323.       char *link_name;
  324.       link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
  325.  
  326.       if (readlink (input_name.ds_string, link_name,
  327.             in_file_stat.st_size) < 0)
  328.         {
  329.           error (0, errno, "%s", input_name.ds_string);
  330.           free (link_name);
  331.           continue;
  332.         }
  333.       link_name[in_file_stat.st_size] = '\0';
  334.  
  335.       res = UMASKED_SYMLINK (link_name, output_name.ds_string,
  336.                  in_file_stat.st_mode);
  337.       if (res < 0 && create_dir_flag)
  338.         {
  339.           create_all_directories (output_name.ds_string);
  340.           res = UMASKED_SYMLINK (link_name, output_name.ds_string,
  341.                      in_file_stat.st_mode);
  342.         }
  343.       if (res < 0)
  344.         {
  345.           error (0, errno, "%s", output_name.ds_string);
  346.           free (link_name);
  347.           continue;
  348.         }
  349.  
  350.       /* Set the attributes of the new link.  */
  351.       if (!no_chown_flag)
  352.         if ((lchown (output_name.ds_string,
  353.              set_owner_flag ? set_owner : in_file_stat.st_uid,
  354.               set_group_flag ? set_group : in_file_stat.st_gid) < 0)
  355.         && errno != EPERM)
  356.           error (0, errno, "%s", output_name.ds_string);
  357.       free (link_name);
  358.     }
  359. #endif
  360.       else
  361.     {
  362.       error (0, 0, "%s: unknown file type", input_name.ds_string);
  363.     }
  364.  
  365.       if (verbose_flag)
  366.     fprintf (stderr, "%s\n", output_name.ds_string);
  367.       if (dot_flag)
  368.     fputc ('.', stderr);
  369.     }
  370.  
  371.   if (dot_flag)
  372.     fputc ('\n', stderr);
  373.   res = (output_bytes + io_block_size - 1) / io_block_size;
  374.   if (res == 1)
  375.     fprintf (stderr, "1 block\n");
  376.   else
  377.     fprintf (stderr, "%d blocks\n", res);
  378. }
  379.  
  380. /* Try and create a hard link from FILE_NAME to another file 
  381.    with the given major/minor device number and inode.  If no other
  382.    file with the same major/minor/inode numbers is known, add this file
  383.    to the list of known files and associated major/minor/inode numbers
  384.    and return -1.  If another file with the same major/minor/inode
  385.    numbers is found, try and create another link to it using
  386.    link_to_name, and return 0 for success and -1 for failure.  */
  387.  
  388. int
  389. link_to_maj_min_ino (file_name, st_dev_maj, st_dev_min, st_ino)
  390.   char *file_name;
  391.   int st_dev_maj;
  392.   int st_dev_min;
  393.   int st_ino;
  394. {
  395.   int    link_res;
  396.   char *link_name;
  397.   link_res = -1;
  398. #ifndef __MSDOS__
  399.   /* Is the file a link to a previously copied file?  */
  400.   link_name = find_inode_file (st_ino,
  401.                    st_dev_maj,
  402.                    st_dev_min);
  403.   if (link_name == NULL)
  404.     add_inode (st_ino, file_name,
  405.            st_dev_maj,
  406.            st_dev_min);
  407.   else
  408.     link_res = link_to_name (file_name, link_name);
  409. #endif
  410.   return link_res;
  411. }
  412.  
  413. /* Try and create a hard link from LINK_NAME to LINK_TARGET.  If
  414.    `create_dir_flag' is set, any non-existent (parent) directories 
  415.    needed by LINK_NAME will be created.  If the link is successfully
  416.    created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
  417.    If the link can not be created and `link_flag' is set, print
  418.    "cannot link LINK_TARGET to LINK_NAME\n".  Return 0 if the link
  419.    is created, -1 otherwise.  */
  420.  
  421. int
  422. link_to_name (link_name, link_target)
  423.   char *link_name;
  424.   char *link_target;
  425. {
  426.   int res;
  427. #ifdef __MSDOS__
  428.   res = -1;
  429. #else /* not __MSDOS__ */
  430.   res = link (link_target, link_name);
  431.   if (res < 0 && create_dir_flag)
  432.     {
  433.       create_all_directories (link_name);
  434.       res = link (link_target, link_name);
  435.     }
  436.   if (res == 0)
  437.     {
  438.       if (verbose_flag)
  439.     error (0, 0, "%s linked to %s",
  440.            link_target, link_name);
  441.     }
  442.   else if (link_flag)
  443.     {
  444.       error (0, errno, "cannot link %s to %s",
  445.          link_target, link_name);
  446.     }
  447. #endif /* not __MSDOS__ */
  448.   return res;
  449. }
  450.