xref: /original-bsd/bin/cp/cp.c (revision 1403a0cd)
1 #ifndef lint
2 static char *sccsid = "@(#)cp.c	4.8 83/07/01";
3 #endif
4 
5 /*
6  * cp
7  */
8 #include <stdio.h>
9 #include <sys/param.h>
10 #include <sys/stat.h>
11 #include <sys/dir.h>
12 
13 #define	BSIZE	8192
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 		Perror(from);
70 		return (1);
71 	}
72 	if (fstat(fold, &stfrom) < 0) {
73 		Perror(from);
74 		(void) close(fold);
75 		return (1);
76 	}
77 	if (stat(to, &stto) >= 0 &&
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);
83 			(void) close(fold);
84 			return(1);
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);
91 		if (stat(to, &stto) < 0) {
92 			if (mkdir(to, (int)stfrom.st_mode) < 0) {
93 				Perror(to);
94 				return (1);
95 			}
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 	}
102 	if (stat(to, &stto) >= 0) {
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");
106 			(void) close(fold);
107 			return (1);
108 		}
109 		if (iflag) {
110 			int i, c;
111 
112 			fprintf (stderr, "overwrite %s? ", to);
113 			i = c = getchar();
114 			while (c != '\n' && c != EOF)
115 				c = getchar();
116 			if (i != 'y') {
117 				(void) close(fold);
118 				return(1);
119 			}
120 		}
121 	}
122 	fnew = creat(to, (int)stfrom.st_mode);
123 	if (fnew < 0) {
124 		Perror(to);
125 		(void) close(fold); return(1);
126 	}
127 	for (;;) {
128 		n = read(fold, buf, BSIZE);
129 		if (n == 0)
130 			break;
131 		if (n < 0) {
132 			Perror(from);
133 			(void) close(fold); (void) close(fnew); return (1);
134 		}
135 		if (write(fnew, buf, n) != n) {
136 			Perror(to);
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) {
152 		Perror(from);
153 		return (1);
154 	}
155 	for (;;) {
156 		dp = readdir(fold);
157 		if (dp == 0) {
158 			closedir(fold);
159 			return (errs);
160 		}
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 }
175 
176 Perror(s)
177 	char *s;
178 {
179 
180 	fprintf(stderr, "cp: ");
181 	perror(s);
182 }
183