cp.c (3791B)
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 "../util.h" 16 17 int cp_aflag = 0; 18 int cp_fflag = 0; 19 int cp_iflag = 0; 20 int cp_pflag = 0; 21 int cp_rflag = 0; 22 int cp_vflag = 0; 23 int cp_status = 0; 24 int cp_follow; 25 26 int 27 cp(const char *s1, const char *s2, int depth) 28 { 29 DIR *dp; 30 int f1, f2, flags = 0; 31 struct dirent *d; 32 struct stat st; 33 struct timespec times[2]; 34 ssize_t r; 35 char target[PATH_MAX], ns1[PATH_MAX], ns2[PATH_MAX]; 36 37 if (cp_follow == 'P' || (cp_follow == 'H' && depth)) 38 flags |= AT_SYMLINK_NOFOLLOW; 39 40 if (fstatat(AT_FDCWD, s1, &st, flags) < 0) { 41 weprintf("stat %s:", s1); 42 cp_status = 1; 43 return 0; 44 } 45 46 if (cp_iflag && access(s2, F_OK) == 0) { 47 if (!confirm("overwrite '%s'? ", s2)) 48 return 0; 49 } 50 51 if (cp_vflag) 52 printf("%s -> %s\n", s1, s2); 53 54 if (S_ISLNK(st.st_mode)) { 55 if ((r = readlink(s1, target, sizeof(target) - 1)) >= 0) { 56 target[r] = '\0'; 57 if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) { 58 weprintf("unlink %s:", s2); 59 cp_status = 1; 60 return 0; 61 } else if (symlink(target, s2) < 0) { 62 weprintf("symlink %s -> %s:", s2, target); 63 cp_status = 1; 64 return 0; 65 } 66 } 67 } else if (S_ISDIR(st.st_mode)) { 68 if (!cp_rflag) { 69 weprintf("%s is a directory\n", s1); 70 cp_status = 1; 71 return 0; 72 } 73 if (!(dp = opendir(s1))) { 74 weprintf("opendir %s:", s1); 75 cp_status = 1; 76 return 0; 77 } 78 if (mkdir(s2, st.st_mode) < 0 && errno != EEXIST) { 79 weprintf("mkdir %s:", s2); 80 cp_status = 1; 81 closedir(dp); 82 return 0; 83 } 84 85 while ((d = readdir(dp))) { 86 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 87 continue; 88 89 estrlcpy(ns1, s1, sizeof(ns1)); 90 if (s1[strlen(s1) - 1] != '/') 91 estrlcat(ns1, "/", sizeof(ns1)); 92 estrlcat(ns1, d->d_name, sizeof(ns1)); 93 94 estrlcpy(ns2, s2, sizeof(ns2)); 95 if (s2[strlen(s2) - 1] != '/') 96 estrlcat(ns2, "/", sizeof(ns2)); 97 estrlcat(ns2, d->d_name, sizeof(ns2)); 98 99 fnck(ns1, ns2, cp, depth + 1); 100 } 101 102 closedir(dp); 103 } else if (cp_aflag && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || 104 S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) { 105 if (cp_fflag && unlink(s2) < 0 && errno != ENOENT) { 106 weprintf("unlink %s:", s2); 107 cp_status = 1; 108 return 0; 109 } else if (mknod(s2, st.st_mode, st.st_rdev) < 0) { 110 weprintf("mknod %s:", s2); 111 cp_status = 1; 112 return 0; 113 } 114 } else { 115 if ((f1 = open(s1, O_RDONLY)) < 0) { 116 weprintf("open %s:", s1); 117 cp_status = 1; 118 return 0; 119 } 120 if ((f2 = creat(s2, st.st_mode)) < 0 && cp_fflag) { 121 if (unlink(s2) < 0 && errno != ENOENT) { 122 weprintf("unlink %s:", s2); 123 cp_status = 1; 124 close(f1); 125 return 0; 126 } 127 f2 = creat(s2, st.st_mode); 128 } 129 if (f2 < 0) { 130 weprintf("creat %s:", s2); 131 cp_status = 1; 132 close(f1); 133 return 0; 134 } 135 if (concat(f1, s1, f2, s2) < 0) { 136 cp_status = 1; 137 close(f1); 138 close(f2); 139 return 0; 140 } 141 142 close(f1); 143 close(f2); 144 } 145 146 if (cp_aflag || cp_pflag) { 147 /* atime and mtime */ 148 times[0] = st.st_atim; 149 times[1] = st.st_mtim; 150 if (utimensat(AT_FDCWD, s2, times, AT_SYMLINK_NOFOLLOW) < 0) { 151 weprintf("utimensat %s:", s2); 152 cp_status = 1; 153 } 154 155 /* owner and mode */ 156 if (!S_ISLNK(st.st_mode)) { 157 if (chown(s2, st.st_uid, st.st_gid) < 0) { 158 weprintf("chown %s:", s2); 159 cp_status = 1; 160 st.st_mode &= ~(S_ISUID | S_ISGID); 161 } 162 if (chmod(s2, st.st_mode) < 0) { 163 weprintf("chmod %s:", s2); 164 cp_status = 1; 165 } 166 } else { 167 if (lchown(s2, st.st_uid, st.st_gid) < 0) { 168 weprintf("lchown %s:", s2); 169 cp_status = 1; 170 return 0; 171 } 172 } 173 } 174 175 return 0; 176 }