cp.c (3081B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <dirent.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <limits.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/stat.h> 10 #include <sys/types.h> 11 #include <unistd.h> 12 #include <utime.h> 13 14 #include "../fs.h" 15 #include "../text.h" 16 #include "../util.h" 17 18 int cp_aflag = 0; 19 int cp_fflag = 0; 20 int cp_Pflag = 0; 21 int cp_pflag = 0; 22 int cp_rflag = 0; 23 int cp_vflag = 0; 24 int cp_status = 0; 25 26 int 27 cp(const char *s1, const char *s2) 28 { 29 FILE *f1, *f2; 30 char *ns1, *ns2; 31 long size1, size2; 32 struct dirent *d; 33 struct stat st; 34 struct utimbuf ut; 35 char buf[PATH_MAX]; 36 DIR *dp; 37 int r; 38 39 if (cp_vflag) 40 printf("'%s' -> '%s'\n", s1, s2); 41 42 r = cp_Pflag ? lstat(s1, &st) : stat(s1, &st); 43 if (r < 0) { 44 weprintf("%s %s:", cp_Pflag ? "lstat" : "stat", s1); 45 cp_status = 1; 46 return 0; 47 } 48 49 if (S_ISLNK(st.st_mode)) { 50 if (readlink(s1, buf, sizeof(buf) - 1) >= 0) { 51 if (cp_fflag) 52 unlink(s2); 53 if (symlink(buf, s2) != 0) { 54 weprintf("%s: can't create '%s'\n", argv0, s2); 55 cp_status = 1; 56 return 0; 57 } 58 } 59 goto preserve; 60 } 61 62 if (S_ISDIR(st.st_mode)) { 63 if (!cp_rflag) 64 eprintf("%s: is a directory\n", s1); 65 66 if (!(dp = opendir(s1))) 67 eprintf("opendir %s:", s1); 68 69 if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) 70 eprintf("mkdir %s:", s2); 71 72 apathmax(&ns1, &size1); 73 apathmax(&ns2, &size2); 74 while ((d = readdir(dp))) { 75 if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { 76 r = snprintf(ns1, size1, "%s/%s", s1, d->d_name); 77 if (r >= size1 || r < 0) { 78 eprintf("%s/%s: filename too long\n", 79 s1, d->d_name); 80 } 81 r = snprintf(ns2, size2, "%s/%s", s2, d->d_name); 82 if (r >= size2 || r < 0) { 83 eprintf("%s/%s: filename too long\n", 84 s2, d->d_name); 85 } 86 fnck(ns1, ns2, cp); 87 } 88 } 89 closedir(dp); 90 free(ns1); 91 free(ns2); 92 goto preserve; 93 } 94 95 if (cp_aflag) { 96 if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || 97 S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode)) { 98 unlink(s2); 99 if (mknod(s2, st.st_mode, st.st_rdev) < 0) { 100 weprintf("%s: can't create '%s':", argv0, s2); 101 cp_status = 1; 102 return 0; 103 } 104 goto preserve; 105 } 106 } 107 108 if (!(f1 = fopen(s1, "r"))) { 109 weprintf("fopen %s:", s1); 110 cp_status = 1; 111 return 0; 112 } 113 114 if (!(f2 = fopen(s2, "w"))) { 115 if (cp_fflag) { 116 unlink(s2); 117 if (!(f2 = fopen(s2, "w"))) { 118 weprintf("fopen %s:", s2); 119 cp_status = 1; 120 return 0; 121 } 122 } else { 123 weprintf("fopen %s:", s2); 124 cp_status = 1; 125 return 0; 126 } 127 } 128 concat(f1, s1, f2, s2); 129 /* preserve permissions by default */ 130 fchmod(fileno(f2), st.st_mode); 131 fclose(f2); 132 fclose(f1); 133 134 preserve: 135 if (cp_aflag || cp_pflag) { 136 if (!(S_ISLNK(st.st_mode))) { 137 /* timestamp */ 138 ut.actime = st.st_atime; 139 ut.modtime = st.st_mtime; 140 utime(s2, &ut); 141 } 142 /* preserve owner ? */ 143 if (S_ISLNK(st.st_mode)) 144 r = lchown(s2, st.st_uid, st.st_gid); 145 else 146 r = chown(s2, st.st_uid, st.st_gid); 147 if (r < 0) { 148 weprintf("cp: can't preserve ownership of '%s':", s2); 149 cp_status = 1; 150 } 151 } 152 return 0; 153 }