Commit | Line | Data |
---|---|---|
5f89032b | 1 | #ifndef lint |
d21f2625 | 2 | static char *sccsid = "@(#)cp.c 4.6 82/12/21"; |
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> |
f4d092e2 | 11 | #include <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) { | |
69 | fprintf(stderr, "cp: "); perror(from); | |
70 | return (1); | |
84592a94 | 71 | } |
5f89032b BJ |
72 | if (fstat(fold, &stfrom) < 0) { |
73 | fprintf(stderr, "cp: "); perror(from); | |
74 | return (1); | |
84592a94 | 75 | } |
3e9da018 | 76 | if (stat(to, &stto) >= 0 && |
5f89032b BJ |
77 | (stto.st_mode&S_IFMT) == S_IFDIR) { |
78 | last = rindex(from, '/'); | |
79 | if (last) last++; else last = from; | |
80 | if (strlen(to) + strlen(last) >= BSIZE - 1) { | |
81 | fprintf(stderr, "cp: %s/%s: Name too long", to, last); | |
84592a94 | 82 | return(1); |
5f89032b BJ |
83 | } |
84 | (void) sprintf(destname, "%s/%s", to, last); | |
85 | to = destname; | |
86 | } | |
87 | if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { | |
88 | (void) close(fold); | |
3e9da018 | 89 | if (stat(to, &stto) < 0) { |
e01c32c9 SL |
90 | if (mkdir(to, (int)stfrom.st_mode) < 0) { |
91 | fprintf(stderr, "cp: "); perror(to); | |
5f89032b | 92 | return (1); |
e01c32c9 | 93 | } |
5f89032b BJ |
94 | } else if ((stto.st_mode&S_IFMT) != S_IFDIR) { |
95 | fprintf(stderr, "cp: %s: Not a directory.\n", to); | |
96 | return (1); | |
97 | } | |
98 | return (rcopy(from, to)); | |
99 | } | |
3e9da018 | 100 | if (stat(to, &stto) >= 0) { |
5f89032b BJ |
101 | if (stfrom.st_dev == stto.st_dev && |
102 | stfrom.st_ino == stto.st_ino) { | |
103 | fprintf(stderr, "cp: Cannot copy file to itself.\n"); | |
104 | return (1); | |
105 | } | |
106 | if (iflag) { | |
107 | int i, c; | |
108 | ||
84592a94 BJ |
109 | fprintf (stderr, "overwrite %s? ", to); |
110 | i = c = getchar(); | |
111 | while (c != '\n' && c != EOF) | |
112 | c = getchar(); | |
113 | if (i != 'y') | |
114 | return(1); | |
115 | } | |
116 | } | |
5f89032b BJ |
117 | fnew = creat(to, (int)stfrom.st_mode); |
118 | if (fnew < 0) { | |
119 | fprintf(stderr, "cp: "); | |
120 | perror(to); | |
121 | (void) close(fold); return(1); | |
84592a94 | 122 | } |
5f89032b BJ |
123 | for (;;) { |
124 | n = read(fold, buf, BSIZE); | |
125 | if (n == 0) | |
126 | break; | |
84592a94 | 127 | if (n < 0) { |
5f89032b BJ |
128 | fprintf(stderr, "cp: "); perror(from); |
129 | (void) close(fold); (void) close(fnew); return (1); | |
130 | } | |
131 | if (write(fnew, buf, n) != n) { | |
132 | fprintf(stderr, "cp: "); perror(to); | |
133 | (void) close(fold); (void) close(fnew); return (1); | |
134 | } | |
135 | } | |
136 | (void) close(fold); (void) close(fnew); return (0); | |
137 | } | |
138 | ||
139 | rcopy(from, to) | |
140 | char *from, *to; | |
141 | { | |
142 | DIR *fold = opendir(from); | |
143 | struct direct *dp; | |
144 | int errs = 0; | |
145 | char fromname[BUFSIZ]; | |
146 | ||
147 | if (fold == 0) { | |
148 | perror(from); | |
149 | return (1); | |
150 | } | |
151 | for (;;) { | |
152 | dp = readdir(fold); | |
c4ac082c KM |
153 | if (dp == 0) { |
154 | closedir(fold); | |
5f89032b | 155 | return (errs); |
c4ac082c | 156 | } |
5f89032b BJ |
157 | if (dp->d_ino == 0) |
158 | continue; | |
159 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
160 | continue; | |
161 | if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { | |
162 | fprintf(stderr, "cp: %s/%s: Name too long.\n", | |
163 | from, dp->d_name); | |
164 | errs++; | |
165 | continue; | |
166 | } | |
167 | (void) sprintf(fromname, "%s/%s", from, dp->d_name); | |
168 | errs += copy(fromname, to); | |
169 | } | |
170 | } |