Commit | Line | Data |
---|---|---|
5f89032b | 1 | #ifndef lint |
7afd0a98 | 2 | static char *sccsid = "@(#)cp.c 4.8 83/07/01"; |
5f89032b BJ |
3 | #endif |
4 | ||
84592a94 | 5 | /* |
5f89032b | 6 | * cp |
84592a94 | 7 | */ |
84592a94 | 8 | #include <stdio.h> |
f4d092e2 | 9 | #include <sys/param.h> |
84592a94 | 10 | #include <sys/stat.h> |
7afd0a98 | 11 | #include <sys/dir.h> |
5f89032b | 12 | |
f4d092e2 | 13 | #define BSIZE 8192 |
5f89032b BJ |
14 | |
15 | int iflag; | |
16 | int rflag; | |
17 | char *rindex(), *sprintf(); | |
84592a94 BJ |
18 | |
19 | main(argc, argv) | |
5f89032b BJ |
20 | int argc; |
21 | char **argv; | |
84592a94 | 22 | { |
5f89032b BJ |
23 | struct stat stb; |
24 | int rc, i; | |
84592a94 | 25 | |
5f89032b BJ |
26 | argc--, argv++; |
27 | while (argc > 0 && **argv == '-') { | |
28 | (*argv)++; | |
29 | while (**argv) switch (*(*argv)++) { | |
84592a94 | 30 | |
5f89032b BJ |
31 | case 'i': |
32 | iflag++; break; | |
84592a94 | 33 | |
5f89032b BJ |
34 | case 'r': |
35 | rflag++; break; | |
84592a94 | 36 | |
5f89032b BJ |
37 | default: |
38 | goto usage; | |
39 | } | |
40 | argc--; argv++; | |
84592a94 | 41 | } |
5f89032b | 42 | if (argc < 2) |
84592a94 | 43 | goto usage; |
5f89032b | 44 | if (argc > 2 || rflag) { |
3e9da018 | 45 | if (stat(argv[argc-1], &stb) < 0) |
84592a94 | 46 | goto usage; |
5f89032b | 47 | if ((stb.st_mode&S_IFMT) != S_IFDIR) |
84592a94 BJ |
48 | goto usage; |
49 | } | |
5f89032b BJ |
50 | rc = 0; |
51 | for (i = 0; i < argc-1; i++) | |
52 | rc |= copy(argv[i], argv[argc-1]); | |
53 | exit(rc); | |
84592a94 | 54 | usage: |
5f89032b BJ |
55 | fprintf(stderr, |
56 | "Usage: cp f1 f2; or cp [ -r ] f1 ... fn d2\n"); | |
84592a94 BJ |
57 | exit(1); |
58 | } | |
59 | ||
60 | copy(from, to) | |
5f89032b | 61 | char *from, *to; |
84592a94 BJ |
62 | { |
63 | int fold, fnew, n; | |
5f89032b BJ |
64 | char *last, destname[BSIZE], buf[BSIZE]; |
65 | struct stat stfrom, stto; | |
66 | ||
67 | fold = open(from, 0); | |
68 | if (fold < 0) { | |
1a4b831f | 69 | Perror(from); |
5f89032b | 70 | return (1); |
84592a94 | 71 | } |
5f89032b | 72 | if (fstat(fold, &stfrom) < 0) { |
1a4b831f SL |
73 | Perror(from); |
74 | (void) close(fold); | |
5f89032b | 75 | return (1); |
84592a94 | 76 | } |
3e9da018 | 77 | if (stat(to, &stto) >= 0 && |
5f89032b BJ |
78 | (stto.st_mode&S_IFMT) == S_IFDIR) { |
79 | last = rindex(from, '/'); | |
80 | if (last) last++; else last = from; | |
81 | if (strlen(to) + strlen(last) >= BSIZE - 1) { | |
82 | fprintf(stderr, "cp: %s/%s: Name too long", to, last); | |
1a4b831f | 83 | (void) close(fold); |
84592a94 | 84 | return(1); |
5f89032b BJ |
85 | } |
86 | (void) sprintf(destname, "%s/%s", to, last); | |
87 | to = destname; | |
88 | } | |
89 | if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { | |
90 | (void) close(fold); | |
3e9da018 | 91 | if (stat(to, &stto) < 0) { |
e01c32c9 | 92 | if (mkdir(to, (int)stfrom.st_mode) < 0) { |
1a4b831f | 93 | Perror(to); |
5f89032b | 94 | return (1); |
e01c32c9 | 95 | } |
5f89032b BJ |
96 | } else if ((stto.st_mode&S_IFMT) != S_IFDIR) { |
97 | fprintf(stderr, "cp: %s: Not a directory.\n", to); | |
98 | return (1); | |
99 | } | |
100 | return (rcopy(from, to)); | |
101 | } | |
3e9da018 | 102 | if (stat(to, &stto) >= 0) { |
5f89032b BJ |
103 | if (stfrom.st_dev == stto.st_dev && |
104 | stfrom.st_ino == stto.st_ino) { | |
105 | fprintf(stderr, "cp: Cannot copy file to itself.\n"); | |
1a4b831f | 106 | (void) close(fold); |
5f89032b BJ |
107 | return (1); |
108 | } | |
109 | if (iflag) { | |
110 | int i, c; | |
111 | ||
84592a94 BJ |
112 | fprintf (stderr, "overwrite %s? ", to); |
113 | i = c = getchar(); | |
114 | while (c != '\n' && c != EOF) | |
115 | c = getchar(); | |
1a4b831f SL |
116 | if (i != 'y') { |
117 | (void) close(fold); | |
84592a94 | 118 | return(1); |
1a4b831f | 119 | } |
84592a94 BJ |
120 | } |
121 | } | |
5f89032b BJ |
122 | fnew = creat(to, (int)stfrom.st_mode); |
123 | if (fnew < 0) { | |
1a4b831f | 124 | Perror(to); |
5f89032b | 125 | (void) close(fold); return(1); |
84592a94 | 126 | } |
5f89032b BJ |
127 | for (;;) { |
128 | n = read(fold, buf, BSIZE); | |
129 | if (n == 0) | |
130 | break; | |
84592a94 | 131 | if (n < 0) { |
1a4b831f | 132 | Perror(from); |
5f89032b BJ |
133 | (void) close(fold); (void) close(fnew); return (1); |
134 | } | |
135 | if (write(fnew, buf, n) != n) { | |
1a4b831f | 136 | Perror(to); |
5f89032b BJ |
137 | (void) close(fold); (void) close(fnew); return (1); |
138 | } | |
139 | } | |
140 | (void) close(fold); (void) close(fnew); return (0); | |
141 | } | |
142 | ||
143 | rcopy(from, to) | |
144 | char *from, *to; | |
145 | { | |
146 | DIR *fold = opendir(from); | |
147 | struct direct *dp; | |
148 | int errs = 0; | |
149 | char fromname[BUFSIZ]; | |
150 | ||
151 | if (fold == 0) { | |
1a4b831f | 152 | Perror(from); |
5f89032b BJ |
153 | return (1); |
154 | } | |
155 | for (;;) { | |
156 | dp = readdir(fold); | |
c4ac082c KM |
157 | if (dp == 0) { |
158 | closedir(fold); | |
5f89032b | 159 | return (errs); |
c4ac082c | 160 | } |
5f89032b BJ |
161 | if (dp->d_ino == 0) |
162 | continue; | |
163 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
164 | continue; | |
165 | if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { | |
166 | fprintf(stderr, "cp: %s/%s: Name too long.\n", | |
167 | from, dp->d_name); | |
168 | errs++; | |
169 | continue; | |
170 | } | |
171 | (void) sprintf(fromname, "%s/%s", from, dp->d_name); | |
172 | errs += copy(fromname, to); | |
173 | } | |
174 | } | |
1a4b831f SL |
175 | |
176 | Perror(s) | |
177 | char *s; | |
178 | { | |
179 | ||
180 | fprintf(stderr, "cp: "); | |
181 | perror(s); | |
182 | } |