diff options
Diffstat (limited to 'src/copypass.c')
-rw-r--r-- | src/copypass.c | 149 |
1 files changed, 58 insertions, 91 deletions
diff --git a/src/copypass.c b/src/copypass.c index db6f327159d8..78576c6231cd 100644 --- a/src/copypass.c +++ b/src/copypass.c @@ -1,5 +1,6 @@ /* copypass.c - cpio copy pass sub-function. - Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004, + 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,9 +12,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA. */ #include <system.h> @@ -24,11 +26,23 @@ #include "cpiohdr.h" #include "dstring.h" #include "extern.h" +#include "paxlib.h" #ifndef HAVE_LCHOWN -#define lchown chown +# define lchown chown #endif + +/* A wrapper around set_perms using another set of arguments */ +static void +set_copypass_perms (int fd, const char *name, struct stat *st) +{ + struct cpio_file_stat header; + header.c_name = name; + stat_to_cpio (&header, st); + set_perms (fd, &header); +} + /* Copy files listed on the standard input into directory `directory_name'. If `link_flag', link instead of copying. */ @@ -40,7 +54,6 @@ process_copy_pass () int dirname_len; /* Length of `directory_name'. */ int res; /* Result of functions. */ char *slash; /* For moving past slashes in input name. */ - struct utimbuf times; /* For resetting file times after copy. */ struct stat in_file_stat; /* Stat record for input file. */ struct stat out_file_stat; /* Stat record for output file. */ int in_file_des; /* Input file descriptor. */ @@ -51,6 +64,9 @@ process_copy_pass () int cdf_char; #endif + umask (0); /* Reset umask to preserve modes of + created files */ + /* Initialize the copy pass. */ dirname_len = strlen (directory_name); ds_init (&input_name, 128); @@ -58,8 +74,6 @@ process_copy_pass () strcpy (output_name.ds_string, directory_name); output_name.ds_string[dirname_len] = '/'; output_is_seekable = true; - /* Initialize this in case it has members we don't know to set. */ - bzero (×, sizeof (struct utimbuf)); /* Copy files with names read from stdin. */ while (ds_fgetstr (stdin, &input_name, name_end) != NULL) @@ -82,7 +96,7 @@ process_copy_pass () if ((*xstat) (input_name.ds_string, &in_file_stat) < 0) { - error (0, errno, "%s", input_name.ds_string); + stat_error (input_name.ds_string); continue; } @@ -150,7 +164,7 @@ process_copy_pass () O_RDONLY | O_BINARY, 0); if (in_file_des < 0) { - error (0, errno, "%s", input_name.ds_string); + open_error (input_name.ds_string); continue; } out_file_des = open (output_name.ds_string, @@ -163,7 +177,7 @@ process_copy_pass () } if (out_file_des < 0) { - error (0, errno, "%s", output_name.ds_string); + open_error (output_name.ds_string); close (in_file_des); continue; } @@ -179,43 +193,28 @@ process_copy_pass () write (out_file_des, "", 1); delayed_seek_count = 0; } + + set_copypass_perms (out_file_des, + output_name.ds_string, &in_file_stat); + + if (reset_time_flag) + { + set_file_times (in_file_des, + input_name.ds_string, + in_file_stat.st_atime, + in_file_stat.st_mtime); + set_file_times (out_file_des, + output_name.ds_string, + in_file_stat.st_atime, + in_file_stat.st_mtime); + } + if (close (in_file_des) < 0) - error (0, errno, "%s", input_name.ds_string); + close_error (input_name.ds_string); + if (close (out_file_des) < 0) - error (0, errno, "%s", output_name.ds_string); - - /* Set the attributes of the new file. */ - if (!no_chown_flag) - if ((chown (output_name.ds_string, - set_owner_flag ? set_owner : in_file_stat.st_uid, - set_group_flag ? set_group : in_file_stat.st_gid) < 0) - && errno != EPERM) - error (0, errno, "%s", output_name.ds_string); - /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) - error (0, errno, "%s", output_name.ds_string); - if (reset_time_flag) - { - times.actime = in_file_stat.st_atime; - times.modtime = in_file_stat.st_mtime; - /* Debian hack: Silently ignore EROFS because - reading the file won't have upset its timestamp - if it's on a read-only filesystem. This has been - submitted as a suggestion to - "bug-gnu-utils@prep.ai.mit.edu". -BEM */ - if (utime (input_name.ds_string, ×) < 0 - && errno != EROFS) - error (0, errno, "%s", input_name.ds_string); - if (utime (output_name.ds_string, ×) < 0 - && errno != EROFS) - error (0, errno, "%s", output_name.ds_string); - } - if (retain_time_flag) - { - times.actime = times.modtime = in_file_stat.st_mtime; - if (utime (output_name.ds_string, ×) < 0) - error (0, errno, "%s", output_name.ds_string); - } + close_error (output_name.ds_string); + warn_if_file_changed(input_name.ds_string, in_file_stat.st_size, in_file_stat.st_mtime); } @@ -261,31 +260,11 @@ process_copy_pass () (lstat (output_name.ds_string, &out_file_stat) != 0) || !(S_ISDIR (out_file_stat.st_mode) ) ) { - error (0, errno, "%s", output_name.ds_string); + stat_error (output_name.ds_string); continue; } } - if (!no_chown_flag) - if ((chown (output_name.ds_string, - set_owner_flag ? set_owner : in_file_stat.st_uid, - set_group_flag ? set_group : in_file_stat.st_gid) < 0) - && errno != EPERM) - error (0, errno, "%s", output_name.ds_string); - /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) - error (0, errno, "%s", output_name.ds_string); -#ifdef HPUX_CDF - if (cdf_flag) - /* Once we "hide" the directory with the chmod(), - we have to refer to it using name+ isntead of name. */ - output_name.ds_string [cdf_char] = '+'; -#endif - if (retain_time_flag) - { - times.actime = times.modtime = in_file_stat.st_mtime; - if (utime (output_name.ds_string, ×) < 0) - error (0, errno, "%s", output_name.ds_string); - } + set_copypass_perms (-1, output_name.ds_string, &in_file_stat); } else if (S_ISCHR (in_file_stat.st_mode) || S_ISBLK (in_file_stat.st_mode) || @@ -321,24 +300,10 @@ process_copy_pass () } if (res < 0) { - error (0, errno, "%s", output_name.ds_string); + mknod_error (output_name.ds_string); continue; } - if (!no_chown_flag) - if ((chown (output_name.ds_string, - set_owner_flag ? set_owner : in_file_stat.st_uid, - set_group_flag ? set_group : in_file_stat.st_gid) < 0) - && errno != EPERM) - error (0, errno, "%s", output_name.ds_string); - /* chown may have turned off some permissions we wanted. */ - if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0) - error (0, errno, "%s", output_name.ds_string); - if (retain_time_flag) - { - times.actime = times.modtime = in_file_stat.st_mtime; - if (utime (output_name.ds_string, ×) < 0) - error (0, errno, "%s", output_name.ds_string); - } + set_copypass_perms (-1, output_name.ds_string, &in_file_stat); } } @@ -353,7 +318,7 @@ process_copy_pass () in_file_stat.st_size); if (link_size < 0) { - error (0, errno, "%s", input_name.ds_string); + readlink_error (input_name.ds_string); free (link_name); continue; } @@ -369,18 +334,20 @@ process_copy_pass () } if (res < 0) { - error (0, errno, "%s", output_name.ds_string); + symlink_error (output_name.ds_string, link_name); free (link_name); continue; } /* Set the attributes of the new link. */ if (!no_chown_flag) - if ((lchown (output_name.ds_string, - set_owner_flag ? set_owner : in_file_stat.st_uid, - set_group_flag ? set_group : in_file_stat.st_gid) < 0) - && errno != EPERM) - error (0, errno, "%s", output_name.ds_string); + { + uid_t uid = set_owner_flag ? set_owner : in_file_stat.st_uid; + gid_t gid = set_group_flag ? set_group : in_file_stat.st_gid; + if ((lchown (output_name.ds_string, uid, gid) < 0) + && errno != EPERM) + chown_error_details (output_name.ds_string, uid, gid); + } free (link_name); } #endif |