3 /* copypass.c - cpio copy pass sub-function.
4 Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include <sys/types.h>
25 #include "filetypes.h"
34 /* Copy files listed on the standard input into directory `directory_name'.
35 If `link_flag', link instead of copying. */
40 dynamic_string input_name; /* Name of file from stdin. */
41 dynamic_string output_name; /* Name of new file. */
42 int dirname_len; /* Length of `directory_name'. */
43 int res; /* Result of functions. */
44 char *slash; /* For moving past slashes in input name. */
45 struct utimbuf times; /* For resetting file times after copy. */
46 struct stat in_file_stat; /* Stat record for input file. */
47 struct stat out_file_stat; /* Stat record for output file. */
48 int in_file_des; /* Input file descriptor. */
49 int out_file_des; /* Output file descriptor. */
50 int existing_dir; /* True if file is a dir & already exists. */
56 /* Initialize the copy pass. */
57 dirname_len = strlen (directory_name);
58 ds_init (&input_name, 128);
59 ds_init (&output_name, dirname_len + 2);
60 strcpy (output_name.ds_string, directory_name);
61 output_name.ds_string[dirname_len] = '/';
62 output_is_seekable = true;
63 /* Initialize this in case it has members we don't know to set. */
64 bzero (×, sizeof (struct utimbuf));
66 /* Copy files with names read from stdin. */
67 while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
71 /* Check for blank line and ignore it if found. */
72 if (input_name.ds_string[0] == '\0')
74 error (0, 0, _("blank line ignored"));
78 /* Check for current directory and ignore it if found. */
79 if (input_name.ds_string[0] == '.'
80 && (input_name.ds_string[1] == '\0'
81 || (input_name.ds_string[1] == '/'
82 && input_name.ds_string[2] == '\0')))
85 if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
87 error (0, errno, "%s", input_name.ds_string);
91 /* Make the name of the new file. */
92 for (slash = input_name.ds_string; *slash == '/'; ++slash)
95 /* For CDF's we add a 2nd `/' after all "hidden" directories.
96 This kind of a kludge, but it's what we do when creating
97 archives, and it's easier to do this than to separately
98 keep track of which directories in a path are "hidden". */
99 slash = add_cdf_double_slashes (slash);
101 ds_resize (&output_name, dirname_len + strlen (slash) + 2);
102 strcpy (output_name.ds_string + dirname_len + 1, slash);
104 existing_dir = false;
105 if (lstat (output_name.ds_string, &out_file_stat) == 0)
107 if (S_ISDIR (out_file_stat.st_mode)
108 && S_ISDIR (in_file_stat.st_mode))
110 /* If there is already a directory there that
111 we are trying to create, don't complain about it. */
114 else if (!unconditional_flag
115 && in_file_stat.st_mtime <= out_file_stat.st_mtime)
117 error (0, 0, _("%s not created: newer or same age version exists"),
118 output_name.ds_string);
119 continue; /* Go to the next file. */
121 else if (S_ISDIR (out_file_stat.st_mode)
122 ? rmdir (output_name.ds_string)
123 : unlink (output_name.ds_string))
125 error (0, errno, _("cannot remove current %s"),
126 output_name.ds_string);
127 continue; /* Go to the next file. */
131 /* Do the real copy or link. */
132 if (S_ISREG (in_file_stat.st_mode))
134 /* Can the current file be linked to a another file?
135 Set link_name to the original file name. */
137 /* User said to link it if possible. Try and link to
138 the original copy. If that fails we'll still try
139 and link to a copy we've already made. */
140 link_res = link_to_name (output_name.ds_string,
141 input_name.ds_string);
142 if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
143 link_res = link_to_maj_min_ino (output_name.ds_string,
144 major (in_file_stat.st_dev),
145 minor (in_file_stat.st_dev),
146 in_file_stat.st_ino);
148 /* If the file was not linked, copy contents of file. */
151 in_file_des = open (input_name.ds_string,
152 O_RDONLY | O_BINARY, 0);
155 error (0, errno, "%s", input_name.ds_string);
158 out_file_des = open (output_name.ds_string,
159 O_CREAT | O_WRONLY | O_BINARY, 0600);
160 if (out_file_des < 0 && create_dir_flag)
162 create_all_directories (output_name.ds_string);
163 out_file_des = open (output_name.ds_string,
164 O_CREAT | O_WRONLY | O_BINARY, 0600);
166 if (out_file_des < 0)
168 error (0, errno, "%s", output_name.ds_string);
173 copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
174 disk_empty_output_buffer (out_file_des);
175 /* Debian hack to fix a bug in the --sparse option.
176 This bug has been reported to
177 "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
178 if (delayed_seek_count > 0)
180 lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
181 write (out_file_des, "", 1);
182 delayed_seek_count = 0;
184 if (close (in_file_des) < 0)
185 error (0, errno, "%s", input_name.ds_string);
186 if (close (out_file_des) < 0)
187 error (0, errno, "%s", output_name.ds_string);
189 /* Set the attributes of the new file. */
191 if ((chown (output_name.ds_string,
192 set_owner_flag ? set_owner : in_file_stat.st_uid,
193 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
195 error (0, errno, "%s", output_name.ds_string);
196 /* chown may have turned off some permissions we wanted. */
197 if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
198 error (0, errno, "%s", output_name.ds_string);
201 times.actime = in_file_stat.st_atime;
202 times.modtime = in_file_stat.st_mtime;
203 /* Debian hack: Silently ignore EROFS because
204 reading the file won't have upset its timestamp
205 if it's on a read-only filesystem. This has been
206 submitted as a suggestion to
207 "bug-gnu-utils@prep.ai.mit.edu". -BEM */
208 if (utime (input_name.ds_string, ×) < 0
210 error (0, errno, "%s", input_name.ds_string);
211 if (utime (output_name.ds_string, ×) < 0
213 error (0, errno, "%s", output_name.ds_string);
215 if (retain_time_flag)
217 times.actime = times.modtime = in_file_stat.st_mtime;
218 if (utime (output_name.ds_string, ×) < 0)
219 error (0, errno, "%s", output_name.ds_string);
221 warn_if_file_changed(input_name.ds_string, in_file_stat.st_size,
222 in_file_stat.st_mtime);
225 else if (S_ISDIR (in_file_stat.st_mode))
233 /* If the directory name ends in a + and is SUID,
234 then it is a CDF. Strip the trailing + from the name
235 before creating it. */
236 cdf_char = strlen (output_name.ds_string) - 1;
237 if ( (cdf_char > 0) &&
238 (in_file_stat.st_mode & 04000) &&
239 (output_name.ds_string [cdf_char] == '+') )
241 output_name.ds_string [cdf_char] = '\0';
245 res = mkdir (output_name.ds_string, in_file_stat.st_mode);
250 if (res < 0 && create_dir_flag)
252 create_all_directories (output_name.ds_string);
253 res = mkdir (output_name.ds_string, in_file_stat.st_mode);
257 /* In some odd cases where the output_name includes `.',
258 the directory may have actually been created by
259 create_all_directories(), so the mkdir will fail
260 because the directory exists. If that's the case,
261 don't complain about it. */
262 if ( (errno != EEXIST) ||
263 (lstat (output_name.ds_string, &out_file_stat) != 0) ||
264 !(S_ISDIR (out_file_stat.st_mode) ) )
266 error (0, errno, "%s", output_name.ds_string);
271 if ((chown (output_name.ds_string,
272 set_owner_flag ? set_owner : in_file_stat.st_uid,
273 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
275 error (0, errno, "%s", output_name.ds_string);
276 /* chown may have turned off some permissions we wanted. */
277 if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
278 error (0, errno, "%s", output_name.ds_string);
281 /* Once we "hide" the directory with the chmod(),
282 we have to refer to it using name+ isntead of name. */
283 output_name.ds_string [cdf_char] = '+';
285 if (retain_time_flag)
287 times.actime = times.modtime = in_file_stat.st_mtime;
288 if (utime (output_name.ds_string, ×) < 0)
289 error (0, errno, "%s", output_name.ds_string);
292 else if (S_ISCHR (in_file_stat.st_mode) ||
293 S_ISBLK (in_file_stat.st_mode) ||
295 S_ISFIFO (in_file_stat.st_mode) ||
298 S_ISSOCK (in_file_stat.st_mode) ||
302 /* Can the current file be linked to a another file?
303 Set link_name to the original file name. */
305 /* User said to link it if possible. */
306 link_res = link_to_name (output_name.ds_string,
307 input_name.ds_string);
308 if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
309 link_res = link_to_maj_min_ino (output_name.ds_string,
310 major (in_file_stat.st_dev),
311 minor (in_file_stat.st_dev),
312 in_file_stat.st_ino);
317 if (S_ISFIFO (in_file_stat.st_mode))
318 res = mkfifo (output_name.ds_string, in_file_stat.st_mode);
321 res = mknod (output_name.ds_string, in_file_stat.st_mode,
322 in_file_stat.st_rdev);
323 if (res < 0 && create_dir_flag)
325 create_all_directories (output_name.ds_string);
327 if (S_ISFIFO (in_file_stat.st_mode))
328 res = mkfifo (output_name.ds_string, in_file_stat.st_mode);
331 res = mknod (output_name.ds_string, in_file_stat.st_mode,
332 in_file_stat.st_rdev);
336 error (0, errno, "%s", output_name.ds_string);
340 if ((chown (output_name.ds_string,
341 set_owner_flag ? set_owner : in_file_stat.st_uid,
342 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
344 error (0, errno, "%s", output_name.ds_string);
345 /* chown may have turned off some permissions we wanted. */
346 if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
347 error (0, errno, "%s", output_name.ds_string);
348 if (retain_time_flag)
350 times.actime = times.modtime = in_file_stat.st_mtime;
351 if (utime (output_name.ds_string, ×) < 0)
352 error (0, errno, "%s", output_name.ds_string);
358 else if (S_ISLNK (in_file_stat.st_mode))
362 link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
364 link_size = readlink (input_name.ds_string, link_name,
365 in_file_stat.st_size);
368 error (0, errno, "%s", input_name.ds_string);
372 link_name[link_size] = '\0';
374 res = UMASKED_SYMLINK (link_name, output_name.ds_string,
375 in_file_stat.st_mode);
376 if (res < 0 && create_dir_flag)
378 create_all_directories (output_name.ds_string);
379 res = UMASKED_SYMLINK (link_name, output_name.ds_string,
380 in_file_stat.st_mode);
384 error (0, errno, "%s", output_name.ds_string);
389 /* Set the attributes of the new link. */
391 if ((lchown (output_name.ds_string,
392 set_owner_flag ? set_owner : in_file_stat.st_uid,
393 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
395 error (0, errno, "%s", output_name.ds_string);
401 error (0, 0, _("%s: unknown file type"), input_name.ds_string);
405 fprintf (stderr, "%s\n", output_name.ds_string);
411 fputc ('\n', stderr);
414 res = (output_bytes + io_block_size - 1) / io_block_size;
415 fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", res), res);
419 /* Try and create a hard link from FILE_NAME to another file
420 with the given major/minor device number and inode. If no other
421 file with the same major/minor/inode numbers is known, add this file
422 to the list of known files and associated major/minor/inode numbers
423 and return -1. If another file with the same major/minor/inode
424 numbers is found, try and create another link to it using
425 link_to_name, and return 0 for success and -1 for failure. */
428 link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min,
434 /* Is the file a link to a previously copied file? */
435 link_name = find_inode_file (st_ino,
438 if (link_name == NULL)
439 add_inode (st_ino, file_name,
443 link_res = link_to_name (file_name, link_name);
447 /* Try and create a hard link from LINK_NAME to LINK_TARGET. If
448 `create_dir_flag' is set, any non-existent (parent) directories
449 needed by LINK_NAME will be created. If the link is successfully
450 created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
451 If the link can not be created and `link_flag' is set, print
452 "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
453 is created, -1 otherwise. */
456 link_to_name (char *link_name, char *link_target)
458 int res = link (link_target, link_name);
459 if (res < 0 && create_dir_flag)
461 create_all_directories (link_name);
462 res = link (link_target, link_name);
467 error (0, 0, _("%s linked to %s"),
468 link_target, link_name);
472 error (0, errno, _("cannot link %s to %s (will copy instead)"),
473 link_target, link_name);