diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-25 21:14:55 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-25 21:14:55 +0000 |
commit | 30bab71f7bd8b3b31fedb90c2510fc89ade04619 (patch) | |
tree | 320c44b82b0e77898c2d85bb754bf7905d66f0dd /libbb | |
parent | 737d131e5e7a795ef771f987d7b02cbf4fa670d6 (diff) | |
download | busybox-w32-30bab71f7bd8b3b31fedb90c2510fc89ade04619.tar.gz busybox-w32-30bab71f7bd8b3b31fedb90c2510fc89ade04619.tar.bz2 busybox-w32-30bab71f7bd8b3b31fedb90c2510fc89ade04619.zip |
make copy_file() a bit easier to understand, and smaller
function old new delta
copy_file 1565 1447 -118
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-118) Total: -118 bytes
text data bss dec hex filename
770938 1063 10788 782789 bf1c5 busybox_old
770814 1063 10788 782665 bf149 busybox_unstripped
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/copy_file.c | 133 | ||||
-rw-r--r-- | libbb/inode_hash.c | 2 |
2 files changed, 66 insertions, 69 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 8a7db77e6..a86e497f0 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
@@ -60,9 +60,11 @@ static int ask_and_unlink(const char *dest, int flags) | |||
60 | */ | 60 | */ |
61 | int copy_file(const char *source, const char *dest, int flags) | 61 | int copy_file(const char *source, const char *dest, int flags) |
62 | { | 62 | { |
63 | /* This is a recursive function, try to minimize stack usage */ | ||
64 | /* NB: each struct stat is ~100 bytes */ | ||
63 | struct stat source_stat; | 65 | struct stat source_stat; |
64 | struct stat dest_stat; | 66 | struct stat dest_stat; |
65 | int status = 0; | 67 | signed char retval = 0; |
66 | signed char dest_exists = 0; | 68 | signed char dest_exists = 0; |
67 | signed char ovr; | 69 | signed char ovr; |
68 | 70 | ||
@@ -120,7 +122,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
120 | return -1; | 122 | return -1; |
121 | } | 123 | } |
122 | 124 | ||
123 | /* Create DEST. */ | 125 | /* Create DEST */ |
124 | if (dest_exists) { | 126 | if (dest_exists) { |
125 | if (!S_ISDIR(dest_stat.st_mode)) { | 127 | if (!S_ISDIR(dest_stat.st_mode)) { |
126 | bb_error_msg("target '%s' is not a directory", dest); | 128 | bb_error_msg("target '%s' is not a directory", dest); |
@@ -133,22 +135,21 @@ int copy_file(const char *source, const char *dest, int flags) | |||
133 | mode = source_stat.st_mode; | 135 | mode = source_stat.st_mode; |
134 | if (!(flags & FILEUTILS_PRESERVE_STATUS)) | 136 | if (!(flags & FILEUTILS_PRESERVE_STATUS)) |
135 | mode = source_stat.st_mode & ~saved_umask; | 137 | mode = source_stat.st_mode & ~saved_umask; |
138 | /* Allow owner to access new dir (at least for now) */ | ||
136 | mode |= S_IRWXU; | 139 | mode |= S_IRWXU; |
137 | |||
138 | if (mkdir(dest, mode) < 0) { | 140 | if (mkdir(dest, mode) < 0) { |
139 | umask(saved_umask); | 141 | umask(saved_umask); |
140 | bb_perror_msg("cannot create directory '%s'", dest); | 142 | bb_perror_msg("cannot create directory '%s'", dest); |
141 | return -1; | 143 | return -1; |
142 | } | 144 | } |
143 | |||
144 | umask(saved_umask); | 145 | umask(saved_umask); |
145 | } | 146 | } |
146 | 147 | ||
147 | /* Recursively copy files in SOURCE. */ | 148 | /* Recursively copy files in SOURCE */ |
148 | dp = opendir(source); | 149 | dp = opendir(source); |
149 | if (dp == NULL) { | 150 | if (dp == NULL) { |
150 | status = -1; | 151 | retval = -1; |
151 | goto preserve_status; | 152 | goto preserve_mode_ugid_time; |
152 | } | 153 | } |
153 | 154 | ||
154 | while ((d = readdir(dp)) != NULL) { | 155 | while ((d = readdir(dp)) != NULL) { |
@@ -159,7 +160,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
159 | continue; | 160 | continue; |
160 | new_dest = concat_path_file(dest, d->d_name); | 161 | new_dest = concat_path_file(dest, d->d_name); |
161 | if (copy_file(new_source, new_dest, flags) < 0) | 162 | if (copy_file(new_source, new_dest, flags) < 0) |
162 | status = -1; | 163 | retval = -1; |
163 | free(new_source); | 164 | free(new_source); |
164 | free(new_dest); | 165 | free(new_dest); |
165 | } | 166 | } |
@@ -169,10 +170,12 @@ int copy_file(const char *source, const char *dest, int flags) | |||
169 | && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 | 170 | && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 |
170 | ) { | 171 | ) { |
171 | bb_perror_msg("cannot change permissions of '%s'", dest); | 172 | bb_perror_msg("cannot change permissions of '%s'", dest); |
172 | status = -1; | 173 | retval = -1; |
173 | } | 174 | } |
175 | goto preserve_mode_ugid_time; | ||
176 | } | ||
174 | 177 | ||
175 | } else if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { | 178 | if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { |
176 | int (*lf)(const char *oldpath, const char *newpath); | 179 | int (*lf)(const char *oldpath, const char *newpath); |
177 | make_links: | 180 | make_links: |
178 | // Hmm... maybe | 181 | // Hmm... maybe |
@@ -188,39 +191,40 @@ int copy_file(const char *source, const char *dest, int flags) | |||
188 | return -1; | 191 | return -1; |
189 | } | 192 | } |
190 | } | 193 | } |
194 | /* _Not_ jumping to preserve_mode_ugid_time: | ||
195 | * hard/softlinks don't have those */ | ||
191 | return 0; | 196 | return 0; |
197 | } | ||
192 | 198 | ||
193 | } else if (S_ISREG(source_stat.st_mode) | 199 | if (S_ISREG(source_stat.st_mode) |
194 | /* Huh? DEREF uses stat, which never returns links! */ | 200 | /* Huh? DEREF uses stat, which never returns links! */ |
195 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ | 201 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ |
196 | ) { | 202 | ) { |
197 | int src_fd; | 203 | int src_fd; |
198 | int dst_fd; | 204 | int dst_fd; |
199 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { | 205 | |
206 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { | ||
200 | char *link_target; | 207 | char *link_target; |
201 | 208 | ||
202 | if (!FLAGS_DEREF) { | 209 | link_target = is_in_ino_dev_hashtable(&source_stat); |
203 | link_target = is_in_ino_dev_hashtable(&source_stat); | 210 | if (link_target) { |
204 | if (link_target) { | 211 | if (link(link_target, dest) < 0) { |
212 | ovr = ask_and_unlink(dest, flags); | ||
213 | if (ovr <= 0) | ||
214 | return ovr; | ||
205 | if (link(link_target, dest) < 0) { | 215 | if (link(link_target, dest) < 0) { |
206 | ovr = ask_and_unlink(dest, flags); | 216 | bb_perror_msg("cannot create link '%s'", dest); |
207 | if (ovr <= 0) | 217 | return -1; |
208 | return ovr; | ||
209 | if (link(link_target, dest) < 0) { | ||
210 | bb_perror_msg("cannot create link '%s'", dest); | ||
211 | return -1; | ||
212 | } | ||
213 | } | 218 | } |
214 | return 0; | ||
215 | } | 219 | } |
220 | return 0; | ||
216 | } | 221 | } |
217 | add_to_ino_dev_hashtable(&source_stat, dest); | 222 | add_to_ino_dev_hashtable(&source_stat, dest); |
218 | } | 223 | } |
219 | 224 | ||
220 | src_fd = open_or_warn(source, O_RDONLY); | 225 | src_fd = open_or_warn(source, O_RDONLY); |
221 | if (src_fd < 0) { | 226 | if (src_fd < 0) |
222 | return -1; | 227 | return -1; |
223 | } | ||
224 | 228 | ||
225 | #if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */ | 229 | #if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */ |
226 | dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) | 230 | dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE) |
@@ -264,61 +268,56 @@ int copy_file(const char *source, const char *dest, int flags) | |||
264 | } | 268 | } |
265 | #endif | 269 | #endif |
266 | if (bb_copyfd_eof(src_fd, dst_fd) == -1) | 270 | if (bb_copyfd_eof(src_fd, dst_fd) == -1) |
267 | status = -1; | 271 | retval = -1; |
268 | if (close(dst_fd) < 0) { | 272 | if (close(dst_fd) < 0) { |
269 | bb_perror_msg("cannot close '%s'", dest); | 273 | bb_perror_msg("cannot close '%s'", dest); |
270 | status = -1; | 274 | retval = -1; |
271 | } | 275 | } |
272 | if (close(src_fd) < 0) { | 276 | if (close(src_fd) < 0) { |
273 | bb_perror_msg("cannot close '%s'", source); | 277 | bb_perror_msg("cannot close '%s'", source); |
274 | status = -1; | 278 | retval = -1; |
275 | } | 279 | } |
280 | goto preserve_mode_ugid_time; | ||
281 | } | ||
276 | 282 | ||
277 | } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) | 283 | /* Source is a symlink or a special file */ |
278 | || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) | 284 | /* We are lazy here, a bit lax with races... */ |
279 | || S_ISLNK(source_stat.st_mode) | 285 | if (dest_exists) { |
280 | ) { | 286 | errno = EEXIST; |
281 | // We are lazy here, a bit lax with races... | 287 | ovr = ask_and_unlink(dest, flags); |
282 | if (dest_exists) { | 288 | if (ovr <= 0) |
283 | errno = EEXIST; | 289 | return ovr; |
284 | ovr = ask_and_unlink(dest, flags); | 290 | } |
285 | if (ovr <= 0) | 291 | if (S_ISLNK(source_stat.st_mode)) { |
286 | return ovr; | 292 | char *lpath; |
287 | } | ||
288 | if (S_ISFIFO(source_stat.st_mode)) { | ||
289 | if (mkfifo(dest, source_stat.st_mode) < 0) { | ||
290 | bb_perror_msg("cannot create fifo '%s'", dest); | ||
291 | return -1; | ||
292 | } | ||
293 | } else if (S_ISLNK(source_stat.st_mode)) { | ||
294 | char *lpath; | ||
295 | 293 | ||
296 | lpath = xmalloc_readlink_or_warn(source); | 294 | lpath = xmalloc_readlink_or_warn(source); |
297 | if (lpath && symlink(lpath, dest) < 0) { | 295 | if (lpath && symlink(lpath, dest) < 0) { |
298 | bb_perror_msg("cannot create symlink '%s'", dest); | 296 | bb_perror_msg("cannot create symlink '%s'", dest); |
299 | free(lpath); | ||
300 | return -1; | ||
301 | } | ||
302 | free(lpath); | 297 | free(lpath); |
303 | 298 | return -1; | |
304 | if (flags & FILEUTILS_PRESERVE_STATUS) | 299 | } |
305 | if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) | 300 | free(lpath); |
306 | bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); | 301 | if (flags & FILEUTILS_PRESERVE_STATUS) |
307 | 302 | if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) | |
308 | return 0; | 303 | bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest); |
309 | 304 | /* _Not_ jumping to preserve_mode_ugid_time: | |
310 | } else { | 305 | * symlinks don't have those */ |
311 | if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { | 306 | return 0; |
312 | bb_perror_msg("cannot create '%s'", dest); | 307 | } |
313 | return -1; | 308 | if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) |
314 | } | 309 | || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) |
310 | ) { | ||
311 | if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { | ||
312 | bb_perror_msg("cannot create '%s'", dest); | ||
313 | return -1; | ||
315 | } | 314 | } |
316 | } else { | 315 | } else { |
317 | bb_error_msg("internal error: unrecognized file type"); | 316 | bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); |
318 | return -1; | 317 | return -1; |
319 | } | 318 | } |
320 | 319 | ||
321 | preserve_status: | 320 | preserve_mode_ugid_time: |
322 | 321 | ||
323 | if (flags & FILEUTILS_PRESERVE_STATUS | 322 | if (flags & FILEUTILS_PRESERVE_STATUS |
324 | /* Cannot happen: */ | 323 | /* Cannot happen: */ |
@@ -338,5 +337,5 @@ int copy_file(const char *source, const char *dest, int flags) | |||
338 | bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); | 337 | bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest); |
339 | } | 338 | } |
340 | 339 | ||
341 | return status; | 340 | return retval; |
342 | } | 341 | } |
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c index 69e39af63..9cca74bcb 100644 --- a/libbb/inode_hash.c +++ b/libbb/inode_hash.c | |||
@@ -84,6 +84,4 @@ void reset_ino_dev_hashtable(void) | |||
84 | free(ino_dev_hashtable); | 84 | free(ino_dev_hashtable); |
85 | ino_dev_hashtable = NULL; | 85 | ino_dev_hashtable = NULL; |
86 | } | 86 | } |
87 | #else | ||
88 | void reset_ino_dev_hashtable(void); | ||
89 | #endif | 87 | #endif |