/ [cpio] / cpio / src / copypass.c
To checkout: cvs -d:pserver:anonymous@cvs.gnu.org.ua:/cvsmirror/cpio co cpio/src/copypass.c
Puszcza

Annotation of /cpio/src/copypass.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations)
Thu Jun 28 12:22:49 2007 UTC (14 years, 7 months ago) by gray
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +4 -1 lines
File MIME type: text/plain
Save current umask before processing and call apply_delayed_set_stat afterwards

1 gray 1.1 /* copypass.c - cpio copy pass sub-function.
2 gray 1.11 Copyright (C) 1990, 1991, 1992, 2001, 2003, 2004,
3 gray 1.15 2006, 2007 Free Software Foundation, Inc.
4 gray 1.1
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7 gray 1.15 the Free Software Foundation; either version 3, or (at your option)
8 gray 1.1 any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15 gray 1.6 You should have received a copy of the GNU General Public
16     License along with this program; if not, write to the Free
17     Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301 USA. */
19 gray 1.1
20 gray 1.3 #include <system.h>
21    
22 gray 1.1 #include <stdio.h>
23     #include <sys/types.h>
24     #include <sys/stat.h>
25     #include "filetypes.h"
26     #include "cpiohdr.h"
27     #include "dstring.h"
28     #include "extern.h"
29 gray 1.13 #include "paxlib.h"
30 gray 1.1
31     #ifndef HAVE_LCHOWN
32 gray 1.8 # define lchown chown
33 gray 1.1 #endif
34    
35 gray 1.8
36     /* A wrapper around set_perms using another set of arguments */
37     static void
38 gray 1.14 set_copypass_perms (int fd, const char *name, struct stat *st)
39 gray 1.8 {
40 gray 1.10 struct cpio_file_stat header;
41 gray 1.16 header.c_name = (char*)name;
42 gray 1.8 stat_to_cpio (&header, st);
43 gray 1.14 set_perms (fd, &header);
44 gray 1.8 }
45    
46 gray 1.1 /* Copy files listed on the standard input into directory `directory_name'.
47     If `link_flag', link instead of copying. */
48    
49     void
50     process_copy_pass ()
51     {
52     dynamic_string input_name; /* Name of file from stdin. */
53     dynamic_string output_name; /* Name of new file. */
54     int dirname_len; /* Length of `directory_name'. */
55     int res; /* Result of functions. */
56     char *slash; /* For moving past slashes in input name. */
57     struct stat in_file_stat; /* Stat record for input file. */
58     struct stat out_file_stat; /* Stat record for output file. */
59     int in_file_des; /* Input file descriptor. */
60     int out_file_des; /* Output file descriptor. */
61     int existing_dir; /* True if file is a dir & already exists. */
62     #ifdef HPUX_CDF
63     int cdf_flag;
64     int cdf_char;
65     #endif
66    
67 gray 1.17 newdir_umask = umask (0); /* Reset umask to preserve modes of
68 gray 1.5 created files */
69    
70 gray 1.1 /* Initialize the copy pass. */
71     dirname_len = strlen (directory_name);
72     ds_init (&input_name, 128);
73     ds_init (&output_name, dirname_len + 2);
74     strcpy (output_name.ds_string, directory_name);
75     output_name.ds_string[dirname_len] = '/';
76 gray 1.3 output_is_seekable = true;
77 gray 1.1
78     /* Copy files with names read from stdin. */
79     while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
80     {
81     int link_res = -1;
82    
83     /* Check for blank line and ignore it if found. */
84     if (input_name.ds_string[0] == '\0')
85     {
86     error (0, 0, _("blank line ignored"));
87     continue;
88     }
89    
90     /* Check for current directory and ignore it if found. */
91     if (input_name.ds_string[0] == '.'
92     && (input_name.ds_string[1] == '\0'
93     || (input_name.ds_string[1] == '/'
94     && input_name.ds_string[2] == '\0')))
95     continue;
96    
97     if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
98     {
99 gray 1.7 stat_error (input_name.ds_string);
100 gray 1.1 continue;
101     }
102    
103     /* Make the name of the new file. */
104     for (slash = input_name.ds_string; *slash == '/'; ++slash)
105     ;
106     #ifdef HPUX_CDF
107     /* For CDF's we add a 2nd `/' after all "hidden" directories.
108     This kind of a kludge, but it's what we do when creating
109     archives, and it's easier to do this than to separately
110     keep track of which directories in a path are "hidden". */
111     slash = add_cdf_double_slashes (slash);
112     #endif
113     ds_resize (&output_name, dirname_len + strlen (slash) + 2);
114     strcpy (output_name.ds_string + dirname_len + 1, slash);
115    
116 gray 1.3 existing_dir = false;
117 gray 1.1 if (lstat (output_name.ds_string, &out_file_stat) == 0)
118     {
119     if (S_ISDIR (out_file_stat.st_mode)
120     && S_ISDIR (in_file_stat.st_mode))
121     {
122     /* If there is already a directory there that
123     we are trying to create, don't complain about it. */
124 gray 1.3 existing_dir = true;
125 gray 1.1 }
126     else if (!unconditional_flag
127     && in_file_stat.st_mtime <= out_file_stat.st_mtime)
128     {
129     error (0, 0, _("%s not created: newer or same age version exists"),
130     output_name.ds_string);
131     continue; /* Go to the next file. */
132     }
133     else if (S_ISDIR (out_file_stat.st_mode)
134     ? rmdir (output_name.ds_string)
135     : unlink (output_name.ds_string))
136     {
137     error (0, errno, _("cannot remove current %s"),
138     output_name.ds_string);
139     continue; /* Go to the next file. */
140     }
141     }
142    
143     /* Do the real copy or link. */
144     if (S_ISREG (in_file_stat.st_mode))
145     {
146     /* Can the current file be linked to a another file?
147     Set link_name to the original file name. */
148     if (link_flag)
149     /* User said to link it if possible. Try and link to
150     the original copy. If that fails we'll still try
151     and link to a copy we've already made. */
152     link_res = link_to_name (output_name.ds_string,
153     input_name.ds_string);
154     if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
155     link_res = link_to_maj_min_ino (output_name.ds_string,
156     major (in_file_stat.st_dev),
157     minor (in_file_stat.st_dev),
158     in_file_stat.st_ino);
159    
160     /* If the file was not linked, copy contents of file. */
161     if (link_res < 0)
162     {
163     in_file_des = open (input_name.ds_string,
164     O_RDONLY | O_BINARY, 0);
165     if (in_file_des < 0)
166     {
167 gray 1.7 open_error (input_name.ds_string);
168 gray 1.1 continue;
169     }
170     out_file_des = open (output_name.ds_string,
171     O_CREAT | O_WRONLY | O_BINARY, 0600);
172     if (out_file_des < 0 && create_dir_flag)
173     {
174     create_all_directories (output_name.ds_string);
175     out_file_des = open (output_name.ds_string,
176     O_CREAT | O_WRONLY | O_BINARY, 0600);
177     }
178     if (out_file_des < 0)
179     {
180 gray 1.7 open_error (output_name.ds_string);
181 gray 1.1 close (in_file_des);
182     continue;
183     }
184    
185     copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
186     disk_empty_output_buffer (out_file_des);
187     /* Debian hack to fix a bug in the --sparse option.
188     This bug has been reported to
189     "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */
190     if (delayed_seek_count > 0)
191     {
192     lseek (out_file_des, delayed_seek_count-1, SEEK_CUR);
193     write (out_file_des, "", 1);
194     delayed_seek_count = 0;
195     }
196    
197 gray 1.14 set_copypass_perms (out_file_des,
198     output_name.ds_string, &in_file_stat);
199 gray 1.8
200 gray 1.1 if (reset_time_flag)
201 gray 1.9 {
202 gray 1.14 set_file_times (in_file_des,
203     input_name.ds_string,
204 gray 1.9 in_file_stat.st_atime,
205     in_file_stat.st_mtime);
206 gray 1.14 set_file_times (out_file_des,
207     output_name.ds_string,
208 gray 1.9 in_file_stat.st_atime,
209     in_file_stat.st_mtime);
210     }
211 gray 1.14
212     if (close (in_file_des) < 0)
213     close_error (input_name.ds_string);
214    
215     if (close (out_file_des) < 0)
216     close_error (output_name.ds_string);
217    
218 gray 1.1 warn_if_file_changed(input_name.ds_string, in_file_stat.st_size,
219     in_file_stat.st_mtime);
220     }
221     }
222     else if (S_ISDIR (in_file_stat.st_mode))
223     {
224     #ifdef HPUX_CDF
225     cdf_flag = 0;
226     #endif
227     if (!existing_dir)
228     {
229     #ifdef HPUX_CDF
230     /* If the directory name ends in a + and is SUID,
231     then it is a CDF. Strip the trailing + from the name
232     before creating it. */
233     cdf_char = strlen (output_name.ds_string) - 1;
234     if ( (cdf_char > 0) &&
235     (in_file_stat.st_mode & 04000) &&
236     (output_name.ds_string [cdf_char] == '+') )
237     {
238     output_name.ds_string [cdf_char] = '\0';
239     cdf_flag = 1;
240     }
241     #endif
242     res = mkdir (output_name.ds_string, in_file_stat.st_mode);
243    
244     }
245     else
246     res = 0;
247     if (res < 0 && create_dir_flag)
248     {
249     create_all_directories (output_name.ds_string);
250     res = mkdir (output_name.ds_string, in_file_stat.st_mode);
251     }
252     if (res < 0)
253     {
254     /* In some odd cases where the output_name includes `.',
255     the directory may have actually been created by
256     create_all_directories(), so the mkdir will fail
257     because the directory exists. If that's the case,
258     don't complain about it. */
259     if ( (errno != EEXIST) ||
260     (lstat (output_name.ds_string, &out_file_stat) != 0) ||
261     !(S_ISDIR (out_file_stat.st_mode) ) )
262     {
263 gray 1.7 stat_error (output_name.ds_string);
264 gray 1.1 continue;
265     }
266     }
267 gray 1.14 set_copypass_perms (-1, output_name.ds_string, &in_file_stat);
268 gray 1.1 }
269     else if (S_ISCHR (in_file_stat.st_mode) ||
270     S_ISBLK (in_file_stat.st_mode) ||
271     #ifdef S_ISFIFO
272     S_ISFIFO (in_file_stat.st_mode) ||
273     #endif
274     #ifdef S_ISSOCK
275     S_ISSOCK (in_file_stat.st_mode) ||
276     #endif
277     0)
278     {
279     /* Can the current file be linked to a another file?
280     Set link_name to the original file name. */
281     if (link_flag)
282     /* User said to link it if possible. */
283     link_res = link_to_name (output_name.ds_string,
284     input_name.ds_string);
285     if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
286     link_res = link_to_maj_min_ino (output_name.ds_string,
287     major (in_file_stat.st_dev),
288     minor (in_file_stat.st_dev),
289     in_file_stat.st_ino);
290    
291     if (link_res < 0)
292     {
293     res = mknod (output_name.ds_string, in_file_stat.st_mode,
294     in_file_stat.st_rdev);
295     if (res < 0 && create_dir_flag)
296     {
297     create_all_directories (output_name.ds_string);
298     res = mknod (output_name.ds_string, in_file_stat.st_mode,
299     in_file_stat.st_rdev);
300     }
301     if (res < 0)
302     {
303 gray 1.7 mknod_error (output_name.ds_string);
304 gray 1.1 continue;
305     }
306 gray 1.14 set_copypass_perms (-1, output_name.ds_string, &in_file_stat);
307 gray 1.1 }
308     }
309    
310     #ifdef S_ISLNK
311     else if (S_ISLNK (in_file_stat.st_mode))
312     {
313     char *link_name;
314     int link_size;
315     link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
316    
317     link_size = readlink (input_name.ds_string, link_name,
318     in_file_stat.st_size);
319     if (link_size < 0)
320     {
321 gray 1.7 readlink_error (input_name.ds_string);
322 gray 1.1 free (link_name);
323     continue;
324     }
325     link_name[link_size] = '\0';
326    
327     res = UMASKED_SYMLINK (link_name, output_name.ds_string,
328     in_file_stat.st_mode);
329     if (res < 0 && create_dir_flag)
330     {
331     create_all_directories (output_name.ds_string);
332     res = UMASKED_SYMLINK (link_name, output_name.ds_string,
333     in_file_stat.st_mode);
334     }
335     if (res < 0)
336     {
337 gray 1.13 symlink_error (output_name.ds_string, link_name);
338 gray 1.1 free (link_name);
339     continue;
340     }
341    
342     /* Set the attributes of the new link. */
343     if (!no_chown_flag)
344 gray 1.7 {
345     uid_t uid = set_owner_flag ? set_owner : in_file_stat.st_uid;
346     gid_t gid = set_group_flag ? set_group : in_file_stat.st_gid;
347     if ((lchown (output_name.ds_string, uid, gid) < 0)
348     && errno != EPERM)
349     chown_error_details (output_name.ds_string, uid, gid);
350     }
351 gray 1.1 free (link_name);
352     }
353     #endif
354     else
355     {
356     error (0, 0, _("%s: unknown file type"), input_name.ds_string);
357     }
358    
359     if (verbose_flag)
360     fprintf (stderr, "%s\n", output_name.ds_string);
361     if (dot_flag)
362     fputc ('.', stderr);
363     }
364    
365     if (dot_flag)
366     fputc ('\n', stderr);
367 gray 1.17
368     apply_delayed_set_stat ();
369    
370 gray 1.1 if (!quiet_flag)
371     {
372 gray 1.16 size_t blocks = (output_bytes + io_block_size - 1) / io_block_size;
373     fprintf (stderr,
374     ngettext ("%lu block\n", "%lu blocks\n",
375     (unsigned long) blocks),
376     (unsigned long) blocks);
377 gray 1.1 }
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 gray 1.3 link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min,
390     int st_ino)
391 gray 1.1 {
392     int link_res;
393     char *link_name;
394     link_res = -1;
395     /* Is the file a link to a previously copied file? */
396     link_name = find_inode_file (st_ino,
397     st_dev_maj,
398     st_dev_min);
399     if (link_name == NULL)
400     add_inode (st_ino, file_name,
401     st_dev_maj,
402     st_dev_min);
403     else
404     link_res = link_to_name (file_name, link_name);
405     return link_res;
406     }
407    
408     /* Try and create a hard link from LINK_NAME to LINK_TARGET. If
409     `create_dir_flag' is set, any non-existent (parent) directories
410     needed by LINK_NAME will be created. If the link is successfully
411     created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
412     If the link can not be created and `link_flag' is set, print
413     "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
414     is created, -1 otherwise. */
415    
416     int
417 gray 1.3 link_to_name (char *link_name, char *link_target)
418 gray 1.1 {
419 gray 1.2 int res = link (link_target, link_name);
420 gray 1.1 if (res < 0 && create_dir_flag)
421     {
422     create_all_directories (link_name);
423     res = link (link_target, link_name);
424     }
425     if (res == 0)
426     {
427     if (verbose_flag)
428     error (0, 0, _("%s linked to %s"),
429     link_target, link_name);
430     }
431     else if (link_flag)
432     {
433     error (0, errno, _("cannot link %s to %s"),
434     link_target, link_name);
435     }
436     return res;
437     }

Send suggestions and bug reports to Sergey Poznyakoff
ViewVC Help
Powered by ViewVC 1.1.20