Latest and greatest.
[platform/upstream/busybox.git] / coreutils / cp.c
1 /*
2  * Mini cp implementation for busybox
3  *
4  * Copyright (C) 1998 by Erik Andersen <andersee@debian.org>
5  *
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 of the License, or
9  * (at your option) any later version.
10  *
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 GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21
22 #include "internal.h"
23 #include <stdio.h>
24 #include <time.h>
25 #include <utime.h>
26 #include <dirent.h>
27
28 const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n"
29     "   or: cp [OPTION]... SOURCE... DIRECTORY\n"
30     "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
31     "\n"
32     "\t-a\tsame as -dpR\n"
33     "\t-d\tpreserve links\n"
34     "\t-p\tpreserve file attributes if possable\n"
35     "\t-R\tcopy directories recursively\n";
36
37
38 static int recursiveFlag = FALSE;
39 static int followLinks = FALSE;
40 static int preserveFlag = FALSE;
41 static const char *srcName;
42 static const char *destName;
43
44
45 static int fileAction(const char *fileName)
46 {
47     char newdestName[NAME_MAX];
48     strcpy(newdestName, destName);
49     strcat(newdestName, fileName+(strlen(srcName)));
50     fprintf(stderr, "A: copying %s to %s\n", fileName, newdestName);
51     return (copyFile(fileName, newdestName, preserveFlag, followLinks));
52 }
53
54 static int dirAction(const char *fileName)
55 {
56     char newdestName[NAME_MAX];
57     struct stat statBuf;
58     struct  utimbuf times;
59
60     strcpy(newdestName, destName);
61     strcat(newdestName, fileName+(strlen(srcName)));
62     if (stat(newdestName, &statBuf)) {
63         if (mkdir( newdestName, 0777777 ^ umask (0))) {
64             perror(newdestName);
65             return( FALSE);
66         }
67     }
68     else if (!S_ISDIR (statBuf.st_mode)) {
69         fprintf(stderr, "`%s' exists but is not a directory", newdestName);
70         return( FALSE);
71     }
72     if (preserveFlag==TRUE) {
73         /* Try to preserve premissions, but don't whine on failure */
74         if (stat(newdestName, &statBuf)) {
75             perror(newdestName);
76             return( FALSE);
77         }
78         chmod(newdestName, statBuf.st_mode);
79         chown(newdestName, statBuf.st_uid, statBuf.st_gid);
80         times.actime = statBuf.st_atime;
81         times.modtime = statBuf.st_mtime;
82         utime(newdestName, &times);
83     }
84     return TRUE;
85 }
86
87 extern int cp_main(int argc, char **argv)
88 {
89
90     int dirFlag;
91
92     if (argc < 3) {
93         fprintf(stderr, "Usage: %s", cp_usage);
94         exit (FALSE);
95     }
96     argc--;
97     argv++;
98
99     /* Parse any options */
100     while (**argv == '-') {
101         while (*++(*argv))
102             switch (**argv) {
103             case 'a':
104                 followLinks = TRUE;
105                 preserveFlag = TRUE;
106                 recursiveFlag = TRUE;
107                 break;
108             case 'd':
109                 followLinks = TRUE;
110                 break;
111             case 'p':
112                 preserveFlag = TRUE;
113                 break;
114             case 'R':
115                 recursiveFlag = TRUE;
116                 break;
117             default:
118                 fprintf(stderr, "Usage: %s\n", cp_usage);
119                 exit(FALSE);
120             }
121         argc--;
122         argv++;
123     }
124
125
126     destName = argv[argc - 1];
127
128     dirFlag = isDirectory(destName);
129
130     if ((argc > 3) && !dirFlag) {
131         fprintf(stderr, "%s: not a directory\n", destName);
132         exit (FALSE);
133     }
134
135     while (argc-- >= 2) {
136         srcName = *(argv++);
137         exit( recursiveAction(srcName, recursiveFlag, followLinks,
138                                fileAction, fileAction));
139     }
140     exit( TRUE);
141 }