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.14 (Berkeley) 12/02/86"; 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 /* I/O buffer; guarantee long-word alignment */ 79 static char buf[MAXBSIZE]; 80 81 copy(from, to) 82 char *from, *to; 83 { 84 int fold, fnew, n, exists; 85 char *last, destname[MAXPATHLEN + 1]; 86 struct stat stfrom, stto; 87 88 fold = open(from, 0); 89 if (fold < 0) { 90 Perror(from); 91 return (1); 92 } 93 if (fstat(fold, &stfrom) < 0) { 94 Perror(from); 95 (void) close(fold); 96 return (1); 97 } 98 if (stat(to, &stto) >= 0 && 99 (stto.st_mode&S_IFMT) == S_IFDIR) { 100 last = rindex(from, '/'); 101 if (last) last++; else last = from; 102 if (strlen(to) + strlen(last) >= sizeof destname - 1) { 103 fprintf(stderr, "cp: %s/%s: Name too long", to, last); 104 (void) close(fold); 105 return(1); 106 } 107 (void) sprintf(destname, "%s/%s", to, last); 108 to = destname; 109 } 110 if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { 111 int fixmode = 0; /* cleanup mode after rcopy */ 112 113 (void) close(fold); 114 if (stat(to, &stto) < 0) { 115 if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) { 116 Perror(to); 117 return (1); 118 } 119 fixmode = 1; 120 } else if ((stto.st_mode&S_IFMT) != S_IFDIR) { 121 fprintf(stderr, "cp: %s: Not a directory.\n", to); 122 return (1); 123 } else if (pflag) 124 fixmode = 1; 125 n = rcopy(from, to); 126 if (fixmode) 127 (void) chmod(to, stfrom.st_mode & 07777); 128 return (n); 129 } 130 131 if ((stfrom.st_mode&S_IFMT) == S_IFDIR) 132 fprintf(stderr, 133 "cp: %s: Is a directory (copying as plain file).\n", 134 from); 135 136 exists = stat(to, &stto) == 0; 137 if (exists) { 138 if (stfrom.st_dev == stto.st_dev && 139 stfrom.st_ino == stto.st_ino) { 140 fprintf(stderr, 141 "cp: %s and %s are identical (not copied).\n", 142 from, to); 143 (void) close(fold); 144 return (1); 145 } 146 if (iflag && isatty(fileno(stdin))) { 147 int i, c; 148 149 fprintf (stderr, "overwrite %s? ", to); 150 i = c = getchar(); 151 while (c != '\n' && c != EOF) 152 c = getchar(); 153 if (i != 'y') { 154 (void) close(fold); 155 return(1); 156 } 157 } 158 } 159 fnew = creat(to, stfrom.st_mode & 07777); 160 if (fnew < 0) { 161 Perror(to); 162 (void) close(fold); return(1); 163 } 164 if (exists && pflag) 165 (void) fchmod(fnew, stfrom.st_mode & 07777); 166 167 for (;;) { 168 n = read(fold, buf, sizeof buf); 169 if (n == 0) 170 break; 171 if (n < 0) { 172 Perror(from); 173 (void) close(fold); (void) close(fnew); return (1); 174 } 175 if (write(fnew, buf, n) != n) { 176 Perror(to); 177 (void) close(fold); (void) close(fnew); return (1); 178 } 179 } 180 (void) close(fold); (void) close(fnew); 181 if (pflag) 182 return (setimes(to, &stfrom)); 183 return (0); 184 } 185 186 rcopy(from, to) 187 char *from, *to; 188 { 189 DIR *fold = opendir(from); 190 struct direct *dp; 191 struct stat statb; 192 int errs = 0; 193 char fromname[MAXPATHLEN + 1]; 194 195 if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) { 196 Perror(from); 197 return (1); 198 } 199 for (;;) { 200 dp = readdir(fold); 201 if (dp == 0) { 202 closedir(fold); 203 if (pflag) 204 return (setimes(to, &statb) + errs); 205 return (errs); 206 } 207 if (dp->d_ino == 0) 208 continue; 209 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 210 continue; 211 if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) { 212 fprintf(stderr, "cp: %s/%s: Name too long.\n", 213 from, dp->d_name); 214 errs++; 215 continue; 216 } 217 (void) sprintf(fromname, "%s/%s", from, dp->d_name); 218 errs += copy(fromname, to); 219 } 220 } 221 222 int 223 setimes(path, statp) 224 char *path; 225 struct stat *statp; 226 { 227 struct timeval tv[2]; 228 229 tv[0].tv_sec = statp->st_atime; 230 tv[1].tv_sec = statp->st_mtime; 231 tv[0].tv_usec = tv[1].tv_usec = 0; 232 if (utimes(path, tv) < 0) { 233 Perror(path); 234 return (1); 235 } 236 return (0); 237 } 238 239 Perror(s) 240 char *s; 241 { 242 243 fprintf(stderr, "cp: "); 244 perror(s); 245 } 246