Set permissions of created file
[platform/upstream/busybox.git] / libbb / copy_file.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) tons of folks.  Tracking down who wrote what
6  * isn't something I'm going to worry about...  If you wrote something
7  * here, please feel free to acknowledge your work.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
24  * Permission has been granted to redistribute this code under the GPL.
25  *
26  */
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <utime.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/stat.h>
34 #include "libbb.h"
35
36
37 /*
38  * Copy one file to another, while possibly preserving its modes, times, and
39  * modes.  Returns TRUE if successful, or FALSE on a failure with an error
40  * message output.  (Failure is not indicated if attributes cannot be set.)
41  * -Erik Andersen
42  */
43 int
44 copy_file(const char *src_name, const char *dst_name,
45                  int set_modes, int follow_links, int force_flag, int quiet_flag)
46 {
47         FILE *src_file = NULL;
48         FILE *dst_file = NULL;
49         struct stat srcStatBuf;
50         struct stat dstStatBuf;
51         struct utimbuf times;
52         int src_status;
53         int dst_status;
54
55         if (follow_links == TRUE) {
56                 src_status = stat(src_name, &srcStatBuf);
57                 dst_status = stat(dst_name, &dstStatBuf);
58         } else {
59                 src_status = lstat(src_name, &srcStatBuf);
60                 dst_status = lstat(dst_name, &dstStatBuf);
61         }
62
63         if (src_status < 0) {
64                 if (!quiet_flag) {
65                         perror_msg("%s", src_name);
66                 }
67                 return FALSE;
68         }
69
70         if ((dst_status < 0) || force_flag) {
71                 unlink(dst_name);
72                 dstStatBuf.st_ino = -1;
73                 dstStatBuf.st_dev = -1;
74         }
75
76         if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
77                 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
78                 if (!quiet_flag) {
79                         error_msg("Copying file \"%s\" to itself", src_name);
80                 }
81                 return FALSE;
82         }
83
84         if (S_ISDIR(srcStatBuf.st_mode)) {
85                 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
86                 /* Make sure the directory is writable */
87                 dst_status = create_path(dst_name, 0777777 ^ umask(0));
88                 if ((dst_status < 0) && (errno != EEXIST)) {
89                         if (!quiet_flag) {
90                                 perror_msg("%s", dst_name);
91                         }
92                         return FALSE;
93                 }
94         } else if (S_ISLNK(srcStatBuf.st_mode)) {
95                 char link_val[BUFSIZ + 1];
96                 int link_size;
97
98                 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
99                 /* Warning: This could possibly truncate silently, to BUFSIZ chars */
100                 link_size = readlink(src_name, &link_val[0], BUFSIZ);
101                 if (link_size < 0) {
102                         if (quiet_flag) {
103                                 perror_msg("%s", src_name);
104                         }
105                         return FALSE;
106                 }
107                 link_val[link_size] = '\0';
108                 src_status = symlink(link_val, dst_name);
109                 if (src_status < 0) {
110                         if (!quiet_flag) {
111                                 perror_msg("%s", dst_name);
112                         }
113                         return FALSE;
114                 }
115 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
116                 if (set_modes == TRUE) {
117                         /* Try to set owner, but fail silently like GNU cp */
118                         lchown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid);
119                 }
120 #endif
121                 return TRUE;
122         } else if (S_ISFIFO(srcStatBuf.st_mode)) {
123                 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
124                 if (mkfifo(dst_name, 0644) < 0) {
125                         if (!quiet_flag) {
126                                 perror_msg("%s", dst_name);
127                         }
128                         return FALSE;
129                 }
130         } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
131                            || S_ISSOCK(srcStatBuf.st_mode)) {
132                 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
133                 if (mknod(dst_name, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
134                         if (!quiet_flag) {
135                                 perror_msg("%s", dst_name);
136                         }
137                         return FALSE;
138                 }
139         } else if (S_ISREG(srcStatBuf.st_mode)) {
140                 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
141                 src_file = fopen(src_name, "r");
142                 if (src_file == NULL) {
143                         if (!quiet_flag) {
144                                 perror_msg("%s", src_name);
145                         }
146                         return FALSE;
147                 }
148
149                 dst_file = fopen(dst_name, "w");
150                 chmod(dst_name, srcStatBuf.st_mode);
151                 if (dst_file == NULL) {
152                         if (!quiet_flag) {
153                                 perror_msg("%s", dst_name);
154                         }
155                         fclose(src_file);
156                         return FALSE;
157                 }
158
159                 if (copy_file_chunk(src_file, dst_file, srcStatBuf.st_size)==FALSE) {
160                         goto error_exit;
161                 }
162
163                 fclose(src_file);
164                 if (fclose(dst_file) < 0) {
165                         return FALSE;
166                 }
167         }
168
169         if (set_modes == TRUE) {
170                 /* This is fine, since symlinks never get here */
171                 if (chown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0)
172                         perror_msg("%s", dst_name);
173                 if (chmod(dst_name, srcStatBuf.st_mode) < 0)
174                         perror_msg("%s", dst_name);
175                 times.actime = srcStatBuf.st_atime;
176                 times.modtime = srcStatBuf.st_mtime;
177                 if (utime(dst_name, &times) < 0)
178                         perror_msg("%s", dst_name);
179         }
180
181         return TRUE;
182
183 error_exit:
184         perror_msg("%s", dst_name);
185         fclose(src_file);
186         fclose(dst_file);
187
188         return FALSE;
189 }
190
191 /* END CODE */
192 /*
193 Local Variables:
194 c-file-style: "linux"
195 c-basic-offset: 4
196 tab-width: 4
197 End:
198 */