1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)cp.c 4.13 (Berkeley) 10/11/85"; 15 #endif not lint 16 17 /* 18 * cp 19 */ 20 #include <stdio.h> 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <sys/dir.h> 24 #include <sys/time.h> 25 26 int iflag; 27 int rflag; 28 int pflag; 29 char *rindex(); 30 31 main(argc, argv) 32 int argc; 33 char **argv; 34 { 35 struct stat stb; 36 int rc, i; 37 38 argc--, argv++; 39 while (argc > 0 && **argv == '-') { 40 (*argv)++; 41 while (**argv) switch (*(*argv)++) { 42 43 case 'i': 44 iflag++; break; 45 46 case 'R': 47 case 'r': 48 rflag++; break; 49 50 case 'p': /* preserve mtimes, atimes, and modes */ 51 pflag++; 52 (void) umask(0); 53 break; 54 55 default: 56 goto usage; 57 } 58 argc--; argv++; 59 } 60 if (argc < 2) 61 goto usage; 62 if (argc > 2) { 63 if (stat(argv[argc-1], &stb) < 0) 64 goto usage; 65 if ((stb.st_mode&S_IFMT) != S_IFDIR) 66 goto usage; 67 } 68 rc = 0; 69 for (i = 0; i < argc-1; i++) 70 rc |= copy(argv[i], argv[argc-1]); 71 exit(rc); 72 usage: 73 fprintf(stderr, 74 "Usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn d2\n"); 75 exit(1); 76 } 77 78 copy(from, to) 79 char *from, *to; 80 { 81 int fold, fnew, n, exists; 82 char *last, destname[MAXPATHLEN + 1], buf[MAXBSIZE]; 83 struct stat stfrom, stto; 84 85 fold = open(from, 0); 86 if (fold < 0) { 87 Perror(from); 88 return (1); 89 } 90 if (fstat(fold, &stfrom) < 0) { 91 Perror(from); 92 (void) close(fold); 93 return (1); 94 } 95 if (stat(to, &stto) >= 0 && 96 (stto.st_mode&S_IFMT) == S_IFDIR) { 97 last = rindex(from, '/'); 98 if (last) last++; else last = from; 99 if (strlen(to) + strlen(last) >= sizeof destname - 1) { 100 fprintf(stderr, "cp: %s/%s: Name too long", to, last); 101 (void) close(fold); 102 return(1); 103 } 104 (void) sprintf(destname, "%s/%s", to, last); 105 to = destname; 106 } 107 if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { 108 int fixmode = 0; /* cleanup mode after rcopy */ 109 110 (void) close(fold); 111 if (stat(to, &stto) < 0) { 112 if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) { 113 Perror(to); 114 return (1); 115 } 116 fixmode = 1; 117 } else if ((stto.st_mode&S_IFMT) != S_IFDIR) { 118 fprintf(stderr, "cp: %s: Not a directory.\n", to); 119 return (1); 120 } else if (pflag) 121 fixmode = 1; 122 n = rcopy(from, to); 123 if (fixmode) 124 (void) chmod(to, stfrom.st_mode & 07777); 125 return (n); 126 } 127 128 if ((stfrom.st_mode&S_IFMT) == S_IFDIR) 129 fprintf(stderr, 130 "cp: %s: Is a directory (copying as plain file).\n", 131 from); 132 133 exists = stat(to, &stto) == 0; 134 if (exists) { 135 if (stfrom.st_dev == stto.st_dev && 136 stfrom.st_ino == stto.st_ino) { 137 fprintf(stderr, 138 "cp: %s and %s are identical (not copied).\n", 139 from, to); 140 (void) close(fold); 141 return (1); 142 } 143 if (iflag && isatty(fileno(stdin))) { 144 int i, c; 145 146 fprintf (stderr, "overwrite %s? ", to); 147 i = c = getchar(); 148 while (c != '\n' && c != EOF) 149 c = getchar(); 150 if (i != 'y') { 151 (void) close(fold); 152 return(1); 153 } 154 } 155 } 156 fnew = creat(to, stfrom.st_mode & 07777); 157 if (fnew < 0) { 158 Perror(to); 159 (void) close(fold); return(1); 160 } 161 if (exists && pflag) 162 (void) fchmod(fnew, stfrom.st_mode & 07777); 163 164 for (;;) { 165 n = read(fold, buf, sizeof buf); 166 if (n == 0) 167 break; 168 if (n < 0) { 169 Perror(from); 170 (void) close(fold); (void) close(fnew); return (1); 171 } 172 if (write(fnew, buf, n) != n) { 173 Perror(to); 174 (void) close(fold); (void) close(fnew); return (1); 175 } 176 } 177 (void) close(fold); (void) close(fnew); 178 if (pflag) 179 return (setimes(to, &stfrom)); 180 return (0); 181 } 182 183 rcopy(from, to) 184 char *from, *to; 185 { 186 DIR *fold = opendir(from); 187 struct direct *dp; 188 struct stat statb; 189 int errs = 0; 190 char fromname[MAXPATHLEN + 1]; 191 192 if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) { 193 Perror(from); 194 return (1); 195 } 196 for (;;) { 197 dp = readdir(fold); 198 if (dp == 0) { 199 closedir(fold); 200 if (pflag) 201 return (setimes(to, &statb) + errs); 202 return (errs); 203 } 204 if (dp->d_ino == 0) 205 continue; 206 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 207 continue; 208 if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) { 209 fprintf(stderr, "cp: %s/%s: Name too long.\n", 210 from, dp->d_name); 211 errs++; 212 continue; 213 } 214 (void) sprintf(fromname, "%s/%s", from, dp->d_name); 215 errs += copy(fromname, to); 216 } 217 } 218 219 int 220 setimes(path, statp) 221 char *path; 222 struct stat *statp; 223 { 224 struct timeval tv[2]; 225 226 tv[0].tv_sec = statp->st_atime; 227 tv[1].tv_sec = statp->st_mtime; 228 tv[0].tv_usec = tv[1].tv_usec = 0; 229 if (utimes(path, tv) < 0) { 230 Perror(path); 231 return (1); 232 } 233 return (0); 234 } 235 236 Perror(s) 237 char *s; 238 { 239 240 fprintf(stderr, "cp: "); 241 perror(s); 242 } 243