Change mailer spec to have labelled fields for future expansion.
[unix-history] / usr / src / bin / cp / cp.c
CommitLineData
5f89032b 1#ifndef lint
d21f2625 2static 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
15int iflag;
16int rflag;
17char *rindex(), *sprintf();
84592a94
BJ
18
19main(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 54usage:
5f89032b
BJ
55 fprintf(stderr,
56 "Usage: cp f1 f2; or cp [ -r ] f1 ... fn d2\n");
84592a94
BJ
57 exit(1);
58}
59
60copy(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
139rcopy(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}