source: MondoRescue/branches/stable/mindi-busybox/libbb/copy_file.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 5.7 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini copy_file implementation for busybox
4 *
5 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 *
9 */
10
11#include "libbb.h"
12#include <utime.h>
13#include <errno.h>
14
15int copy_file(const char *source, const char *dest, int flags)
16{
17    struct stat source_stat;
18    struct stat dest_stat;
19    int dest_exists = 0;
20    int status = 0;
21
22    if ((!(flags & FILEUTILS_DEREFERENCE) &&
23            lstat(source, &source_stat) < 0) ||
24            ((flags & FILEUTILS_DEREFERENCE) &&
25             stat(source, &source_stat) < 0)) {
26        bb_perror_msg("%s", source);
27        return -1;
28    }
29
30    if (lstat(dest, &dest_stat) < 0) {
31        if (errno != ENOENT) {
32            bb_perror_msg("unable to stat `%s'", dest);
33            return -1;
34        }
35    } else {
36        if (source_stat.st_dev == dest_stat.st_dev &&
37            source_stat.st_ino == dest_stat.st_ino)
38        {
39            bb_error_msg("`%s' and `%s' are the same file", source, dest);
40            return -1;
41        }
42        dest_exists = 1;
43    }
44
45    if (S_ISDIR(source_stat.st_mode)) {
46        DIR *dp;
47        struct dirent *d;
48        mode_t saved_umask = 0;
49
50        if (!(flags & FILEUTILS_RECUR)) {
51            bb_error_msg("%s: omitting directory", source);
52            return -1;
53        }
54
55        /* Create DEST.  */
56        if (dest_exists) {
57            if (!S_ISDIR(dest_stat.st_mode)) {
58                bb_error_msg("`%s' is not a directory", dest);
59                return -1;
60            }
61        } else {
62            mode_t mode;
63            saved_umask = umask(0);
64
65            mode = source_stat.st_mode;
66            if (!(flags & FILEUTILS_PRESERVE_STATUS))
67                mode = source_stat.st_mode & ~saved_umask;
68            mode |= S_IRWXU;
69
70            if (mkdir(dest, mode) < 0) {
71                umask(saved_umask);
72                bb_perror_msg("cannot create directory `%s'", dest);
73                return -1;
74            }
75
76            umask(saved_umask);
77        }
78
79        /* Recursively copy files in SOURCE.  */
80        if ((dp = bb_opendir(source)) == NULL) {
81            status = -1;
82            goto preserve_status;
83        }
84
85        while ((d = readdir(dp)) != NULL) {
86            char *new_source, *new_dest;
87
88            new_source = concat_subpath_file(source, d->d_name);
89            if(new_source == NULL)
90                continue;
91            new_dest = concat_path_file(dest, d->d_name);
92            if (copy_file(new_source, new_dest, flags) < 0)
93                status = -1;
94            free(new_source);
95            free(new_dest);
96        }
97        /* closedir have only EBADF error, but "dp" not changes */
98        closedir(dp);
99
100        if (!dest_exists &&
101                chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
102            bb_perror_msg("unable to change permissions of `%s'", dest);
103            status = -1;
104        }
105    } else if (S_ISREG(source_stat.st_mode) ||
106           (S_ISLNK(source_stat.st_mode) && (flags & FILEUTILS_DEREFERENCE)))
107    {
108        int src_fd;
109        int dst_fd;
110        if (ENABLE_FEATURE_PRESERVE_HARDLINKS) {
111            char *link_name;
112
113            if (!(flags & FILEUTILS_DEREFERENCE) &&
114                    is_in_ino_dev_hashtable(&source_stat, &link_name)) {
115                if (link(link_name, dest) < 0) {
116                    bb_perror_msg("unable to link `%s'", dest);
117                    return -1;
118                }
119
120                return 0;
121            }
122            add_to_ino_dev_hashtable(&source_stat, dest);
123        }
124        src_fd = open(source, O_RDONLY);
125        if (src_fd == -1) {
126            bb_perror_msg("unable to open `%s'", source);
127            return(-1);
128        }
129
130        if (dest_exists) {
131            if (flags & FILEUTILS_INTERACTIVE) {
132                fprintf(stderr, "%s: overwrite `%s'? ", bb_applet_name, dest);
133                if (!bb_ask_confirmation()) {
134                    close (src_fd);
135                    return 0;
136                }
137            }
138
139            dst_fd = open(dest, O_WRONLY|O_TRUNC);
140            if (dst_fd == -1) {
141                if (!(flags & FILEUTILS_FORCE)) {
142                    bb_perror_msg("unable to open `%s'", dest);
143                    close(src_fd);
144                    return -1;
145                }
146
147                if (unlink(dest) < 0) {
148                    bb_perror_msg("unable to remove `%s'", dest);
149                    close(src_fd);
150                    return -1;
151                }
152
153                goto dest_removed;
154            }
155        } else {
156dest_removed:
157            dst_fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode);
158            if (dst_fd == -1) {
159                bb_perror_msg("unable to open `%s'", dest);
160                close(src_fd);
161                return(-1);
162            }
163        }
164
165        if (bb_copyfd_eof(src_fd, dst_fd) == -1)
166            status = -1;
167
168        if (close(dst_fd) < 0) {
169            bb_perror_msg("unable to close `%s'", dest);
170            status = -1;
171        }
172
173        if (close(src_fd) < 0) {
174            bb_perror_msg("unable to close `%s'", source);
175            status = -1;
176        }
177    } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
178        S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ||
179        S_ISLNK(source_stat.st_mode)) {
180
181        if (dest_exists) {
182            if((flags & FILEUTILS_FORCE) == 0) {
183                fprintf(stderr, "`%s' exists\n", dest);
184                return -1;
185            }
186            if(unlink(dest) < 0) {
187                bb_perror_msg("unable to remove `%s'", dest);
188                return -1;
189            }
190        }
191        if (S_ISFIFO(source_stat.st_mode)) {
192            if (mkfifo(dest, source_stat.st_mode) < 0) {
193                bb_perror_msg("cannot create fifo `%s'", dest);
194                return -1;
195            }
196        } else if (S_ISLNK(source_stat.st_mode)) {
197            char *lpath;
198
199            lpath = xreadlink(source);
200            if (symlink(lpath, dest) < 0) {
201                bb_perror_msg("cannot create symlink `%s'", dest);
202                return -1;
203            }
204            free(lpath);
205
206            if (flags & FILEUTILS_PRESERVE_STATUS)
207                if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
208                    bb_perror_msg("unable to preserve ownership of `%s'", dest);
209
210            return 0;
211
212        } else {
213            if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
214                bb_perror_msg("unable to create `%s'", dest);
215                return -1;
216            }
217        }
218    } else {
219        bb_error_msg("internal error: unrecognized file type");
220        return -1;
221    }
222
223preserve_status:
224
225    if (flags & FILEUTILS_PRESERVE_STATUS) {
226        struct utimbuf times;
227        char *msg="unable to preserve %s of `%s'";
228
229        times.actime = source_stat.st_atime;
230        times.modtime = source_stat.st_mtime;
231        if (utime(dest, &times) < 0)
232            bb_perror_msg(msg, "times", dest);
233        if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
234            source_stat.st_mode &= ~(S_ISUID | S_ISGID);
235            bb_perror_msg(msg, "ownership", dest);
236        }
237        if (chmod(dest, source_stat.st_mode) < 0)
238            bb_perror_msg(msg, "permissions", dest);
239    }
240
241    return status;
242}
Note: See TracBrowser for help on using the repository browser.