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