xref: /original-bsd/bin/cp/cp.c (revision b3b53e97)
1 #ifndef lint
2 static char *sccsid = "@(#)cp.c	4.3 82/03/31";
3 #endif
4 
5 /*
6  * cp
7  */
8 #include <stdio.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <ndir.h>
12 
13 #define	BSIZE	1024
14 
15 int	iflag;
16 int	rflag;
17 char	*rindex(), *sprintf();
18 
19 main(argc, argv)
20 	int argc;
21 	char **argv;
22 {
23 	struct stat stb;
24 	int rc, i;
25 
26 	argc--, argv++;
27 	while (argc > 0 && **argv == '-') {
28 		(*argv)++;
29 		while (**argv) switch (*(*argv)++) {
30 
31 		case 'i':
32 			iflag++; break;
33 
34 		case 'r':
35 			rflag++; break;
36 
37 		default:
38 			goto usage;
39 		}
40 		argc--; argv++;
41 	}
42 	if (argc < 2)
43 		goto usage;
44 	if (argc > 2 || rflag) {
45 		if (stat(argv[argc-1], &stb) < 0)
46 			goto usage;
47 		if ((stb.st_mode&S_IFMT) != S_IFDIR)
48 			goto usage;
49 	}
50 	rc = 0;
51 	for (i = 0; i < argc-1; i++)
52 		rc |= copy(argv[i], argv[argc-1]);
53 	exit(rc);
54 usage:
55 	fprintf(stderr,
56 	    "Usage: cp f1 f2; or cp [ -r ] f1 ... fn d2\n");
57 	exit(1);
58 }
59 
60 copy(from, to)
61 	char *from, *to;
62 {
63 	int fold, fnew, n;
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);
71 	}
72 	if (fstat(fold, &stfrom) < 0) {
73 		fprintf(stderr, "cp: "); perror(from);
74 		return (1);
75 	}
76 	if (stat(to, &stto) >= 0 &&
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);
82 			return(1);
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);
89 		if (stat(to, &stto) < 0) {
90 			if (mkdir(to, (int)stfrom.st_mode) < 0)
91 				return (1);
92 		} else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
93 			fprintf(stderr, "cp: %s: Not a directory.\n", to);
94 			return (1);
95 		}
96 		return (rcopy(from, to));
97 	}
98 	if (stat(to, &stto) >= 0) {
99 		if (stfrom.st_dev == stto.st_dev &&
100 		   stfrom.st_ino == stto.st_ino) {
101 			fprintf(stderr, "cp: Cannot copy file to itself.\n");
102 			return (1);
103 		}
104 		if (iflag) {
105 			int i, c;
106 
107 			fprintf (stderr, "overwrite %s? ", to);
108 			i = c = getchar();
109 			while (c != '\n' && c != EOF)
110 				c = getchar();
111 			if (i != 'y')
112 				return(1);
113 		}
114 	}
115 	fnew = creat(to, (int)stfrom.st_mode);
116 	if (fnew < 0) {
117 		fprintf(stderr, "cp: ");
118 		perror(to);
119 		(void) close(fold); return(1);
120 	}
121 	for (;;) {
122 		n = read(fold, buf, BSIZE);
123 		if (n == 0)
124 			break;
125 		if (n < 0) {
126 			fprintf(stderr, "cp: "); perror(from);
127 			(void) close(fold); (void) close(fnew); return (1);
128 		}
129 		if (write(fnew, buf, n) != n) {
130 			fprintf(stderr, "cp: "); perror(to);
131 			(void) close(fold); (void) close(fnew); return (1);
132 		}
133 	}
134 	(void) close(fold); (void) close(fnew); return (0);
135 }
136 
137 rcopy(from, to)
138 	char *from, *to;
139 {
140 	DIR *fold = opendir(from);
141 	struct direct *dp;
142 	int errs = 0;
143 	char fromname[BUFSIZ];
144 
145 	if (fold == 0) {
146 		perror(from);
147 		return (1);
148 	}
149 	for (;;) {
150 		dp = readdir(fold);
151 		if (dp == 0)
152 			return (errs);
153 		if (dp->d_ino == 0)
154 			continue;
155 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
156 			continue;
157 		if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
158 			fprintf(stderr, "cp: %s/%s: Name too long.\n",
159 			    from, dp->d_name);
160 			errs++;
161 			continue;
162 		}
163 		(void) sprintf(fromname, "%s/%s", from, dp->d_name);
164 		errs += copy(fromname, to);
165 	}
166 }
167 
168 mkdir(name, mode)
169 	char *name;
170 	int mode;
171 {
172 	char *argv[4];
173 	int pid, rc;
174 
175 	argv[0] = "mkdir";
176 	argv[1] = name;
177 	argv[2] = 0;
178 	pid = fork();
179 	if (pid < 0) {
180 		perror("cp");
181 		return (1);
182 	}
183 	if (pid) {
184 		while (wait(&rc) != pid)
185 			continue;
186 		if (rc == 0)
187 			if (chmod(name, mode) < 0) {
188 				perror(name);
189 				rc = 1;
190 			}
191 		return (rc);
192 	}
193 	execv("/bin/mkdir", argv);
194 	execv("/usr/bin/mkdir", argv);
195 	perror("mkdir");
196 	_exit(1);
197 	/*NOTREACHED*/
198 }
199