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);
187 * Avoid race condition.
188 * Set chown and chmod before closing the file desc.
191 /* Set the attributes of the new file. */
193 if ((fchown (out_file_des,
194 set_owner_flag ? set_owner : in_file_stat.st_uid,
195 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
197 error (0, errno, "%s", output_name.ds_string);
198 /* chown may have turned off some permissions we wanted. */
199 if (fchmod (out_file_des, in_file_stat.st_mode) < 0)
200 error (0, errno, "%s", output_name.ds_string);
202 if (close (out_file_des) < 0)
203 error (0, errno, "%s", output_name.ds_string);
207 times.actime = in_file_stat.st_atime;
208 times.modtime = in_file_stat.st_mtime;
209 /* Debian hack: Silently ignore EROFS because
210 reading the file won't have upset its timestamp
211 if it's on a read-only filesystem. This has been
212 submitted as a suggestion to
213 "bug-gnu-utils@prep.ai.mit.edu". -BEM */
214 if (utime (input_name.ds_string, ×) < 0
216 error (0, errno, "%s", input_name.ds_string);
217 if (utime (output_name.ds_string, ×) < 0
219 error (0, errno, "%s", output_name.ds_string);
221 if (retain_time_flag)
223 times.actime = times.modtime = in_file_stat.st_mtime;
224 if (utime (output_name.ds_string, ×) < 0)
225 error (0, errno, "%s", output_name.ds_string);
227 warn_if_file_changed(input_name.ds_string, in_file_stat.st_size,
228 in_file_stat.st_mtime);
231 else if (S_ISDIR (in_file_stat.st_mode))
239 /* If the directory name ends in a + and is SUID,
240 then it is a CDF. Strip the trailing + from the name
241 before creating it. */
242 cdf_char = strlen (output_name.ds_string) - 1;
243 if ( (cdf_char > 0) &&
244 (in_file_stat.st_mode & 04000) &&
245 (output_name.ds_string [cdf_char] == '+') )
247 output_name.ds_string [cdf_char] = '\0';
251 res = mkdir (output_name.ds_string, in_file_stat.st_mode);
256 if (res < 0 && create_dir_flag)
258 create_all_directories (output_name.ds_string);
259 res = mkdir (output_name.ds_string, in_file_stat.st_mode);
263 /* In some odd cases where the output_name includes `.',
264 the directory may have actually been created by
265 create_all_directories(), so the mkdir will fail
266 because the directory exists. If that's the case,
267 don't complain about it. */
268 if ( (errno != EEXIST) ||
269 (lstat (output_name.ds_string, &out_file_stat) != 0) ||
270 !(S_ISDIR (out_file_stat.st_mode) ) )
272 error (0, errno, "%s", output_name.ds_string);
277 if ((chown (output_name.ds_string,
278 set_owner_flag ? set_owner : in_file_stat.st_uid,
279 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
281 error (0, errno, "%s", output_name.ds_string);
282 /* chown may have turned off some permissions we wanted. */
283 if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
284 error (0, errno, "%s", output_name.ds_string);
287 /* Once we "hide" the directory with the chmod(),
288 we have to refer to it using name+ isntead of name. */
289 output_name.ds_string [cdf_char] = '+';
291 if (retain_time_flag)
293 times.actime = times.modtime = in_file_stat.st_mtime;
294 if (utime (output_name.ds_string, ×) < 0)
295 error (0, errno, "%s", output_name.ds_string);
298 else if (S_ISCHR (in_file_stat.st_mode) ||
299 S_ISBLK (in_file_stat.st_mode) ||
301 S_ISFIFO (in_file_stat.st_mode) ||
304 S_ISSOCK (in_file_stat.st_mode) ||
308 /* Can the current file be linked to a another file?
309 Set link_name to the original file name. */
311 /* User said to link it if possible. */
312 link_res = link_to_name (output_name.ds_string,
313 input_name.ds_string);
314 if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
315 link_res = link_to_maj_min_ino (output_name.ds_string,
316 major (in_file_stat.st_dev),
317 minor (in_file_stat.st_dev),
318 in_file_stat.st_ino);
323 if (S_ISFIFO (in_file_stat.st_mode))
324 res = mkfifo (output_name.ds_string, in_file_stat.st_mode);
327 res = mknod (output_name.ds_string, in_file_stat.st_mode,
328 in_file_stat.st_rdev);
329 if (res < 0 && create_dir_flag)
331 create_all_directories (output_name.ds_string);
333 if (S_ISFIFO (in_file_stat.st_mode))
334 res = mkfifo (output_name.ds_string, in_file_stat.st_mode);
337 res = mknod (output_name.ds_string, in_file_stat.st_mode,
338 in_file_stat.st_rdev);
342 error (0, errno, "%s", output_name.ds_string);
346 if ((chown (output_name.ds_string,
347 set_owner_flag ? set_owner : in_file_stat.st_uid,
348 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
350 error (0, errno, "%s", output_name.ds_string);
351 /* chown may have turned off some permissions we wanted. */
352 if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
353 error (0, errno, "%s", output_name.ds_string);
354 if (retain_time_flag)
356 times.actime = times.modtime = in_file_stat.st_mtime;
357 if (utime (output_name.ds_string, ×) < 0)
358 error (0, errno, "%s", output_name.ds_string);
364 else if (S_ISLNK (in_file_stat.st_mode))
368 link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
370 link_size = readlink (input_name.ds_string, link_name,
371 in_file_stat.st_size);
374 error (0, errno, "%s", input_name.ds_string);
378 link_name[link_size] = '\0';
380 res = UMASKED_SYMLINK (link_name, output_name.ds_string,
381 in_file_stat.st_mode);
382 if (res < 0 && create_dir_flag)
384 create_all_directories (output_name.ds_string);
385 res = UMASKED_SYMLINK (link_name, output_name.ds_string,
386 in_file_stat.st_mode);
390 error (0, errno, "%s", output_name.ds_string);
395 /* Set the attributes of the new link. */
397 if ((lchown (output_name.ds_string,
398 set_owner_flag ? set_owner : in_file_stat.st_uid,
399 set_group_flag ? set_group : in_file_stat.st_gid) < 0)
401 error (0, errno, "%s", output_name.ds_string);
407 error (0, 0, _("%s: unknown file type"), input_name.ds_string);
411 fprintf (stderr, "%s\n", output_name.ds_string);
417 fputc ('\n', stderr);
420 res = (output_bytes + io_block_size - 1) / io_block_size;
421 fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", res), res);
425 /* Try and create a hard link from FILE_NAME to another file
426 with the given major/minor device number and inode. If no other
427 file with the same major/minor/inode numbers is known, add this file
428 to the list of known files and associated major/minor/inode numbers
429 and return -1. If another file with the same major/minor/inode
430 numbers is found, try and create another link to it using
431 link_to_name, and return 0 for success and -1 for failure. */
434 link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min,
440 /* Is the file a link to a previously copied file? */
441 link_name = find_inode_file (st_ino,
444 if (link_name == NULL)
445 add_inode (st_ino, file_name,
449 link_res = link_to_name (file_name, link_name);
453 /* Try and create a hard link from LINK_NAME to LINK_TARGET. If
454 `create_dir_flag' is set, any non-existent (parent) directories
455 needed by LINK_NAME will be created. If the link is successfully
456 created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
457 If the link can not be created and `link_flag' is set, print
458 "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
459 is created, -1 otherwise. */
462 link_to_name (char *link_name, char *link_target)
464 int res = link (link_target, link_name);
465 if (res < 0 && create_dir_flag)
467 create_all_directories (link_name);
468 res = link (link_target, link_name);
473 error (0, 0, _("%s linked to %s"),
474 link_target, link_name);
478 error (0, errno, _("cannot link %s to %s (will copy instead)"),
479 link_target, link_name);