cp.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
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 != ENOEN… | |
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_mod… | |
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) … | |
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 } |