diff options
Diffstat (limited to 'src/fcopy/main.c')
-rw-r--r-- | src/fcopy/main.c | 56 |
1 files changed, 48 insertions, 8 deletions
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 01633be59..d863b537b 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -172,6 +172,47 @@ static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { | |||
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | static char *proc_pid_to_self(const char *target) | ||
176 | { | ||
177 | char *use_target = 0; | ||
178 | char *proc_pid = 0; | ||
179 | |||
180 | if (!(use_target = canonicalize_file_name(target))) | ||
181 | goto done; | ||
182 | |||
183 | // target is under /proc/<PID>? | ||
184 | static const char proc[] = "/proc/"; | ||
185 | if (strncmp(use_target, proc, sizeof proc - 1)) | ||
186 | goto done; | ||
187 | |||
188 | int digit = use_target[sizeof proc - 1]; | ||
189 | if (digit < '1' || digit > '9') | ||
190 | goto done; | ||
191 | |||
192 | // check where /proc/self points to | ||
193 | static const char proc_self[] = "/proc/self"; | ||
194 | if (!(proc_pid = canonicalize_file_name(proc_self))) | ||
195 | goto done; | ||
196 | |||
197 | // redirect /proc/PID/xxx -> /proc/self/XXX | ||
198 | size_t pfix = strlen(proc_pid); | ||
199 | if (strncmp(use_target, proc_pid, pfix)) | ||
200 | goto done; | ||
201 | |||
202 | if (use_target[pfix] != 0 && use_target[pfix] != '/') | ||
203 | goto done; | ||
204 | |||
205 | char *tmp; | ||
206 | if (asprintf(&tmp, "%s%s", proc_self, use_target + pfix) != -1) { | ||
207 | if (arg_debug) | ||
208 | fprintf(stderr, "SYMLINK %s\n --> %s\n", use_target, tmp); | ||
209 | free(use_target), use_target = tmp; | ||
210 | } | ||
211 | |||
212 | done: | ||
213 | free(proc_pid); | ||
214 | return use_target; | ||
215 | } | ||
175 | 216 | ||
176 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { | 217 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { |
177 | (void) mode; | 218 | (void) mode; |
@@ -183,7 +224,7 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, | |||
183 | if (lstat(linkpath, &s) == 0) | 224 | if (lstat(linkpath, &s) == 0) |
184 | return; | 225 | return; |
185 | 226 | ||
186 | char *rp = realpath(target, NULL); | 227 | char *rp = proc_pid_to_self(target); |
187 | if (rp) { | 228 | if (rp) { |
188 | if (symlink(rp, linkpath) == -1) { | 229 | if (symlink(rp, linkpath) == -1) { |
189 | free(rp); | 230 | free(rp); |
@@ -227,16 +268,14 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
227 | first = 0; | 268 | first = 0; |
228 | else if (!arg_quiet) | 269 | else if (!arg_quiet) |
229 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); | 270 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); |
230 | free(outfname); | 271 | goto out; |
231 | return 0; | ||
232 | } | 272 | } |
233 | 273 | ||
234 | // extract mode and ownership | 274 | // extract mode and ownership |
235 | if (stat(infname, &s) != 0) { | 275 | if (stat(infname, &s) != 0) { |
236 | if (!arg_quiet) | 276 | if (!arg_quiet) |
237 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); | 277 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); |
238 | free(outfname); | 278 | goto out; |
239 | return 0; | ||
240 | } | 279 | } |
241 | uid_t uid = s.st_uid; | 280 | uid_t uid = s.st_uid; |
242 | gid_t gid = s.st_gid; | 281 | gid_t gid = s.st_gid; |
@@ -246,8 +285,7 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
246 | if ((s.st_size + size_cnt) > copy_limit) { | 285 | if ((s.st_size + size_cnt) > copy_limit) { |
247 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); | 286 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); |
248 | size_limit_reached = 1; | 287 | size_limit_reached = 1; |
249 | free(outfname); | 288 | goto out; |
250 | return 0; | ||
251 | } | 289 | } |
252 | 290 | ||
253 | file_cnt++; | 291 | file_cnt++; |
@@ -262,7 +300,8 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
262 | else if (ftype == FTW_SL) { | 300 | else if (ftype == FTW_SL) { |
263 | copy_link(infname, outfname, mode, uid, gid); | 301 | copy_link(infname, outfname, mode, uid, gid); |
264 | } | 302 | } |
265 | 303 | out: | |
304 | free(outfname); | ||
266 | return(0); | 305 | return(0); |
267 | } | 306 | } |
268 | 307 | ||
@@ -295,6 +334,7 @@ static char *check(const char *src) { | |||
295 | return rsrc; // normal exit from the function | 334 | return rsrc; // normal exit from the function |
296 | 335 | ||
297 | errexit: | 336 | errexit: |
337 | free(rsrc); | ||
298 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); | 338 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); |
299 | exit(1); | 339 | exit(1); |
300 | } | 340 | } |