]>
Commit | Line | Data |
---|---|---|
44a7a5ab A |
1 | /* $OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $ */ |
2 | /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ | |
3 | ||
4 | /*- | |
5 | * Copyright (c) 1992 Keith Muller. | |
6 | * Copyright (c) 1992, 1993 | |
7 | * The Regents of the University of California. All rights reserved. | |
8 | * | |
9 | * This code is derived from software contributed to Berkeley by | |
10 | * Keith Muller of the University of California, San Diego. | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. All advertising materials mentioning features or use of this software | |
21 | * must display the following acknowledgement: | |
22 | * This product includes software developed by the University of | |
23 | * California, Berkeley and its contributors. | |
24 | * 4. Neither the name of the University nor the names of its contributors | |
25 | * may be used to endorse or promote products derived from this software | |
26 | * without specific prior written permission. | |
27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
38 | * SUCH DAMAGE. | |
39 | */ | |
40 | ||
41 | #ifndef lint | |
42 | #if 0 | |
43 | static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; | |
44 | #else | |
45 | static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $"; | |
46 | #endif | |
47 | #endif /* not lint */ | |
48 | ||
49 | #include <sys/types.h> | |
50 | #include <sys/time.h> | |
51 | #include <sys/stat.h> | |
52 | #include <unistd.h> | |
53 | #include <sys/param.h> | |
54 | #include <fcntl.h> | |
55 | #include <string.h> | |
56 | #include <stdio.h> | |
57 | #include <errno.h> | |
58 | #include <sys/uio.h> | |
59 | #include <stdlib.h> | |
60 | #include "pax.h" | |
61 | #include "options.h" | |
62 | #include "extern.h" | |
63 | ||
64 | static int | |
65 | mk_link __P((register char *,register struct stat *,register char *, int)); | |
66 | ||
67 | /* | |
68 | * routines that deal with file operations such as: creating, removing; | |
69 | * and setting access modes, uid/gid and times of files | |
70 | */ | |
71 | ||
72 | #define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) | |
73 | #define SETBITS (S_ISUID | S_ISGID) | |
74 | #define ABITS (FILEBITS | SETBITS) | |
75 | ||
76 | /* | |
77 | * file_creat() | |
78 | * Create and open a file. | |
79 | * Return: | |
80 | * file descriptor or -1 for failure | |
81 | */ | |
82 | ||
83 | #ifdef __STDC__ | |
84 | int | |
85 | file_creat(register ARCHD *arcn) | |
86 | #else | |
87 | int | |
88 | file_creat(arcn) | |
89 | register ARCHD *arcn; | |
90 | #endif | |
91 | { | |
92 | int fd = -1; | |
93 | mode_t file_mode; | |
94 | int oerrno; | |
95 | ||
96 | /* | |
97 | * assume file doesn't exist, so just try to create it, most times this | |
98 | * works. We have to take special handling when the file does exist. To | |
99 | * detect this, we use O_EXCL. For example when trying to create a | |
100 | * file and a character device or fifo exists with the same name, we | |
101 | * can accidently open the device by mistake (or block waiting to open) | |
102 | * If we find that the open has failed, then figure spend the effore to | |
103 | * figure out why. This strategy was found to have better average | |
104 | * performance in common use than checking the file (and the path) | |
105 | * first with lstat. | |
106 | */ | |
107 | file_mode = arcn->sb.st_mode & FILEBITS; | |
108 | if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, | |
109 | file_mode)) >= 0) | |
110 | return(fd); | |
111 | ||
112 | /* | |
113 | * the file seems to exist. First we try to get rid of it (found to be | |
114 | * the second most common failure when traced). If this fails, only | |
115 | * then we go to the expense to check and create the path to the file | |
116 | */ | |
117 | if (unlnk_exist(arcn->name, arcn->type) != 0) | |
118 | return(-1); | |
119 | ||
120 | for (;;) { | |
121 | /* | |
122 | * try to open it again, if this fails, check all the nodes in | |
123 | * the path and give it a final try. if chk_path() finds that | |
124 | * it cannot fix anything, we will skip the last attempt | |
125 | */ | |
126 | if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC, | |
127 | file_mode)) >= 0) | |
128 | break; | |
129 | oerrno = errno; | |
130 | if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { | |
131 | syswarn(1, oerrno, "Unable to create %s", arcn->name); | |
132 | return(-1); | |
133 | } | |
134 | } | |
135 | return(fd); | |
136 | } | |
137 | ||
138 | /* | |
139 | * file_close() | |
140 | * Close file descriptor to a file just created by pax. Sets modes, | |
141 | * ownership and times as required. | |
142 | * Return: | |
143 | * 0 for success, -1 for failure | |
144 | */ | |
145 | ||
146 | #ifdef __STDC__ | |
147 | void | |
148 | file_close(register ARCHD *arcn, int fd) | |
149 | #else | |
150 | void | |
151 | file_close(arcn, fd) | |
152 | register ARCHD *arcn; | |
153 | int fd; | |
154 | #endif | |
155 | { | |
156 | int res = 0; | |
157 | ||
158 | if (fd < 0) | |
159 | return; | |
160 | if (close(fd) < 0) | |
161 | syswarn(0, errno, "Unable to close file descriptor on %s", | |
162 | arcn->name); | |
163 | ||
164 | /* | |
165 | * set owner/groups first as this may strip off mode bits we want | |
166 | * then set file permission modes. Then set file access and | |
167 | * modification times. | |
168 | */ | |
169 | if (pids) | |
170 | res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid); | |
171 | ||
172 | /* | |
173 | * IMPORTANT SECURITY NOTE: | |
174 | * if not preserving mode or we cannot set uid/gid, then PROHIBIT | |
175 | * set uid/gid bits | |
176 | */ | |
177 | if (!pmode || res) | |
178 | arcn->sb.st_mode &= ~(SETBITS); | |
179 | if (pmode) | |
180 | set_pmode(arcn->name, arcn->sb.st_mode); | |
181 | if (patime || pmtime) | |
182 | set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); | |
183 | } | |
184 | ||
185 | /* | |
186 | * lnk_creat() | |
187 | * Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name | |
188 | * must exist; | |
189 | * Return: | |
190 | * 0 if ok, -1 otherwise | |
191 | */ | |
192 | ||
193 | #ifdef __STDC__ | |
194 | int | |
195 | lnk_creat(register ARCHD *arcn) | |
196 | #else | |
197 | int | |
198 | lnk_creat(arcn) | |
199 | register ARCHD *arcn; | |
200 | #endif | |
201 | { | |
202 | struct stat sb; | |
203 | ||
204 | /* | |
205 | * we may be running as root, so we have to be sure that link target | |
206 | * is not a directory, so we lstat and check | |
207 | */ | |
208 | if (lstat(arcn->ln_name, &sb) < 0) { | |
209 | syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name, | |
210 | arcn->name); | |
211 | return(-1); | |
212 | } | |
213 | ||
214 | if (S_ISDIR(sb.st_mode)) { | |
215 | paxwarn(1, "A hard link to the directory %s is not allowed", | |
216 | arcn->ln_name); | |
217 | return(-1); | |
218 | } | |
219 | ||
220 | return(mk_link(arcn->ln_name, &sb, arcn->name, 0)); | |
221 | } | |
222 | ||
223 | /* | |
224 | * cross_lnk() | |
225 | * Create a hard link to arcn->org_name from arcn->name. Only used in copy | |
226 | * with the -l flag. No warning or error if this does not succeed (we will | |
227 | * then just create the file) | |
228 | * Return: | |
229 | * 1 if copy() should try to create this file node | |
230 | * 0 if cross_lnk() ok, -1 for fatal flaw (like linking to self). | |
231 | */ | |
232 | ||
233 | #ifdef __STDC__ | |
234 | int | |
235 | cross_lnk(register ARCHD *arcn) | |
236 | #else | |
237 | int | |
238 | cross_lnk(arcn) | |
239 | register ARCHD *arcn; | |
240 | #endif | |
241 | { | |
242 | /* | |
243 | * try to make a link to orginal file (-l flag in copy mode). make sure | |
244 | * we do not try to link to directories in case we are running as root | |
245 | * (and it might succeed). | |
246 | */ | |
247 | if (arcn->type == PAX_DIR) | |
248 | return(1); | |
249 | return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1)); | |
250 | } | |
251 | ||
252 | /* | |
253 | * chk_same() | |
254 | * In copy mode if we are not trying to make hard links between the src | |
255 | * and destinations, make sure we are not going to overwrite ourselves by | |
256 | * accident. This slows things down a little, but we have to protect all | |
257 | * those people who make typing errors. | |
258 | * Return: | |
259 | * 1 the target does not exist, go ahead and copy | |
260 | * 0 skip it file exists (-k) or may be the same as source file | |
261 | */ | |
262 | ||
263 | #ifdef __STDC__ | |
264 | int | |
265 | chk_same(register ARCHD *arcn) | |
266 | #else | |
267 | int | |
268 | chk_same(arcn) | |
269 | register ARCHD *arcn; | |
270 | #endif | |
271 | { | |
272 | struct stat sb; | |
273 | ||
274 | /* | |
275 | * if file does not exist, return. if file exists and -k, skip it | |
276 | * quietly | |
277 | */ | |
278 | if (lstat(arcn->name, &sb) < 0) | |
279 | return(1); | |
280 | if (kflag) | |
281 | return(0); | |
282 | ||
283 | /* | |
284 | * better make sure the user does not have src == dest by mistake | |
285 | */ | |
286 | if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) { | |
287 | paxwarn(1, "Unable to copy %s, file would overwrite itself", | |
288 | arcn->name); | |
289 | return(0); | |
290 | } | |
291 | return(1); | |
292 | } | |
293 | ||
294 | /* | |
295 | * mk_link() | |
296 | * try to make a hard link between two files. if ign set, we do not | |
297 | * complain. | |
298 | * Return: | |
299 | * 0 if successful (or we are done with this file but no error, such as | |
300 | * finding the from file exists and the user has set -k). | |
301 | * 1 when ign was set to indicates we could not make the link but we | |
302 | * should try to copy/extract the file as that might work (and is an | |
303 | * allowed option). -1 an error occurred. | |
304 | */ | |
305 | ||
306 | #ifdef __STDC__ | |
307 | static int | |
308 | mk_link(register char *to, register struct stat *to_sb, register char *from, | |
309 | int ign) | |
310 | #else | |
311 | static int | |
312 | mk_link(to, to_sb, from, ign) | |
313 | register char *to; | |
314 | register struct stat *to_sb; | |
315 | register char *from; | |
316 | int ign; | |
317 | #endif | |
318 | { | |
319 | struct stat sb; | |
320 | int oerrno; | |
321 | ||
322 | /* | |
323 | * if from file exists, it has to be unlinked to make the link. If the | |
324 | * file exists and -k is set, skip it quietly | |
325 | */ | |
326 | if (lstat(from, &sb) == 0) { | |
327 | if (kflag) | |
328 | return(0); | |
329 | ||
330 | /* | |
331 | * make sure it is not the same file, protect the user | |
332 | */ | |
333 | if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) { | |
334 | paxwarn(1, "Unable to link file %s to itself", to); | |
335 | return(-1);; | |
336 | } | |
337 | ||
338 | /* | |
339 | * try to get rid of the file, based on the type | |
340 | */ | |
341 | if (S_ISDIR(sb.st_mode)) { | |
342 | if (rmdir(from) < 0) { | |
343 | syswarn(1, errno, "Unable to remove %s", from); | |
344 | return(-1); | |
345 | } | |
346 | } else if (unlink(from) < 0) { | |
347 | if (!ign) { | |
348 | syswarn(1, errno, "Unable to remove %s", from); | |
349 | return(-1); | |
350 | } | |
351 | return(1); | |
352 | } | |
353 | } | |
354 | ||
355 | /* | |
356 | * from file is gone (or did not exist), try to make the hard link. | |
357 | * if it fails, check the path and try it again (if chk_path() says to | |
358 | * try again) | |
359 | */ | |
360 | for (;;) { | |
361 | if (link(to, from) == 0) | |
362 | break; | |
363 | oerrno = errno; | |
364 | if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0) | |
365 | continue; | |
366 | if (!ign) { | |
367 | syswarn(1, oerrno, "Could not link to %s from %s", to, | |
368 | from); | |
369 | return(-1); | |
370 | } | |
371 | return(1); | |
372 | } | |
373 | ||
374 | /* | |
375 | * all right the link was made | |
376 | */ | |
377 | return(0); | |
378 | } | |
379 | ||
380 | /* | |
381 | * node_creat() | |
382 | * create an entry in the file system (other than a file or hard link). | |
383 | * If successful, sets uid/gid modes and times as required. | |
384 | * Return: | |
385 | * 0 if ok, -1 otherwise | |
386 | */ | |
387 | ||
388 | #ifdef __STDC__ | |
389 | int | |
390 | node_creat(register ARCHD *arcn) | |
391 | #else | |
392 | int | |
393 | node_creat(arcn) | |
394 | register ARCHD *arcn; | |
395 | #endif | |
396 | { | |
397 | register int res; | |
398 | register int ign = 0; | |
399 | register int oerrno; | |
400 | register int pass = 0; | |
401 | mode_t file_mode; | |
402 | struct stat sb; | |
403 | ||
404 | /* | |
405 | * create node based on type, if that fails try to unlink the node and | |
406 | * try again. finally check the path and try again. As noted in the | |
407 | * file and link creation routines, this method seems to exhibit the | |
408 | * best performance in general use workloads. | |
409 | */ | |
410 | file_mode = arcn->sb.st_mode & FILEBITS; | |
411 | ||
412 | for (;;) { | |
413 | switch(arcn->type) { | |
414 | case PAX_DIR: | |
415 | res = mkdir(arcn->name, file_mode); | |
416 | if (ign) | |
417 | res = 0; | |
418 | break; | |
419 | case PAX_CHR: | |
420 | file_mode |= S_IFCHR; | |
421 | res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); | |
422 | break; | |
423 | case PAX_BLK: | |
424 | file_mode |= S_IFBLK; | |
425 | res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); | |
426 | break; | |
427 | case PAX_FIF: | |
428 | res = mkfifo(arcn->name, file_mode); | |
429 | break; | |
430 | case PAX_SCK: | |
431 | /* | |
432 | * Skip sockets, operation has no meaning under BSD | |
433 | */ | |
434 | paxwarn(0, | |
435 | "%s skipped. Sockets cannot be copied or extracted", | |
436 | arcn->name); | |
437 | return(-1); | |
438 | case PAX_SLK: | |
439 | res = symlink(arcn->ln_name, arcn->name); | |
440 | break; | |
441 | case PAX_CTG: | |
442 | case PAX_HLK: | |
443 | case PAX_HRG: | |
444 | case PAX_REG: | |
445 | default: | |
446 | /* | |
447 | * we should never get here | |
448 | */ | |
449 | paxwarn(0, "%s has an unknown file type, skipping", | |
450 | arcn->name); | |
451 | return(-1); | |
452 | } | |
453 | ||
454 | /* | |
455 | * if we were able to create the node break out of the loop, | |
456 | * otherwise try to unlink the node and try again. if that | |
457 | * fails check the full path and try a final time. | |
458 | */ | |
459 | if (res == 0) | |
460 | break; | |
461 | ||
462 | /* | |
463 | * we failed to make the node | |
464 | */ | |
465 | oerrno = errno; | |
466 | if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0) | |
467 | return(-1); | |
468 | ||
469 | if (++pass <= 1) | |
470 | continue; | |
471 | ||
472 | if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { | |
473 | syswarn(1, oerrno, "Could not create: %s", arcn->name); | |
474 | return(-1); | |
475 | } | |
476 | } | |
477 | ||
478 | /* | |
479 | * we were able to create the node. set uid/gid, modes and times | |
480 | */ | |
481 | if (pids) | |
482 | res = ((arcn->type == PAX_SLK) ? | |
fc155071 A |
483 | #if defined(__APPLE__) |
484 | /* Mac OS X doesn't have lchown, so don't bother */ | |
485 | 0 : | |
486 | #else | |
44a7a5ab | 487 | set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) : |
fc155071 | 488 | #endif |
44a7a5ab A |
489 | set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid)); |
490 | else | |
491 | res = 0; | |
492 | ||
493 | /* | |
494 | * symlinks are done now. | |
495 | */ | |
496 | if (arcn->type == PAX_SLK) | |
497 | return(0); | |
498 | ||
499 | /* | |
500 | * IMPORTANT SECURITY NOTE: | |
501 | * if not preserving mode or we cannot set uid/gid, then PROHIBIT any | |
502 | * set uid/gid bits | |
503 | */ | |
504 | if (!pmode || res) | |
505 | arcn->sb.st_mode &= ~(SETBITS); | |
506 | if (pmode) | |
507 | set_pmode(arcn->name, arcn->sb.st_mode); | |
508 | ||
509 | if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { | |
510 | /* | |
511 | * Dirs must be processed again at end of extract to set times | |
512 | * and modes to agree with those stored in the archive. However | |
513 | * to allow extract to continue, we may have to also set owner | |
514 | * rights. This allows nodes in the archive that are children | |
515 | * of this directory to be extracted without failure. Both time | |
516 | * and modes will be fixed after the entire archive is read and | |
517 | * before pax exits. | |
518 | */ | |
519 | if (access(arcn->name, R_OK | W_OK | X_OK) < 0) { | |
520 | if (lstat(arcn->name, &sb) < 0) { | |
521 | syswarn(0, errno,"Could not access %s (stat)", | |
522 | arcn->name); | |
523 | set_pmode(arcn->name,file_mode | S_IRWXU); | |
524 | } else { | |
525 | /* | |
526 | * We have to add rights to the dir, so we make | |
527 | * sure to restore the mode. The mode must be | |
528 | * restored AS CREATED and not as stored if | |
529 | * pmode is not set. | |
530 | */ | |
531 | set_pmode(arcn->name, | |
532 | ((sb.st_mode & FILEBITS) | S_IRWXU)); | |
533 | if (!pmode) | |
534 | arcn->sb.st_mode = sb.st_mode; | |
535 | } | |
536 | ||
537 | /* | |
538 | * we have to force the mode to what was set here, | |
539 | * since we changed it from the default as created. | |
540 | */ | |
541 | add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1); | |
542 | } else if (pmode || patime || pmtime) | |
543 | add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0); | |
544 | } | |
545 | ||
546 | if (patime || pmtime) | |
547 | set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); | |
548 | return(0); | |
549 | } | |
550 | ||
551 | /* | |
552 | * unlnk_exist() | |
553 | * Remove node from file system with the specified name. We pass the type | |
554 | * of the node that is going to replace it. When we try to create a | |
555 | * directory and find that it already exists, we allow processing to | |
556 | * continue as proper modes etc will always be set for it later on. | |
557 | * Return: | |
558 | * 0 is ok to proceed, no file with the specified name exists | |
559 | * -1 we were unable to remove the node, or we should not remove it (-k) | |
560 | * 1 we found a directory and we were going to create a directory. | |
561 | */ | |
562 | ||
563 | #ifdef __STDC__ | |
564 | int | |
565 | unlnk_exist(register char *name, register int type) | |
566 | #else | |
567 | int | |
568 | unlnk_exist(name, type) | |
569 | register char *name; | |
570 | register int type; | |
571 | #endif | |
572 | { | |
573 | struct stat sb; | |
574 | ||
575 | /* | |
576 | * the file does not exist, or -k we are done | |
577 | */ | |
578 | if (lstat(name, &sb) < 0) | |
579 | return(0); | |
580 | if (kflag) | |
581 | return(-1); | |
582 | ||
583 | if (S_ISDIR(sb.st_mode)) { | |
584 | /* | |
585 | * try to remove a directory, if it fails and we were going to | |
586 | * create a directory anyway, tell the caller (return a 1) | |
587 | */ | |
588 | if (rmdir(name) < 0) { | |
589 | if (type == PAX_DIR) | |
590 | return(1); | |
591 | syswarn(1,errno,"Unable to remove directory %s", name); | |
592 | return(-1); | |
593 | } | |
594 | return(0); | |
595 | } | |
596 | ||
597 | /* | |
598 | * try to get rid of all non-directory type nodes | |
599 | */ | |
600 | if (unlink(name) < 0) { | |
601 | syswarn(1, errno, "Could not unlink %s", name); | |
602 | return(-1); | |
603 | } | |
604 | return(0); | |
605 | } | |
606 | ||
607 | /* | |
608 | * chk_path() | |
609 | * We were trying to create some kind of node in the file system and it | |
610 | * failed. chk_path() makes sure the path up to the node exists and is | |
611 | * writeable. When we have to create a directory that is missing along the | |
612 | * path somewhere, the directory we create will be set to the same | |
613 | * uid/gid as the file has (when uid and gid are being preserved). | |
614 | * NOTE: this routine is a real performance loss. It is only used as a | |
615 | * last resort when trying to create entries in the file system. | |
616 | * Return: | |
617 | * -1 when it could find nothing it is allowed to fix. | |
618 | * 0 otherwise | |
619 | */ | |
620 | ||
621 | #ifdef __STDC__ | |
622 | int | |
623 | chk_path( register char *name, uid_t st_uid, gid_t st_gid) | |
624 | #else | |
625 | int | |
626 | chk_path(name, st_uid, st_gid) | |
627 | register char *name; | |
628 | uid_t st_uid; | |
629 | gid_t st_gid; | |
630 | #endif | |
631 | { | |
632 | register char *spt = name; | |
633 | struct stat sb; | |
634 | int retval = -1; | |
635 | ||
636 | /* | |
637 | * watch out for paths with nodes stored directly in / (e.g. /bozo) | |
638 | */ | |
639 | if (*spt == '/') | |
640 | ++spt; | |
641 | ||
642 | for(;;) { | |
643 | /* | |
644 | * work foward from the first / and check each part of the path | |
645 | */ | |
646 | spt = strchr(spt, '/'); | |
647 | if (spt == NULL) | |
648 | break; | |
649 | *spt = '\0'; | |
650 | ||
651 | /* | |
652 | * if it exists we assume it is a directory, it is not within | |
653 | * the spec (at least it seems to read that way) to alter the | |
654 | * file system for nodes NOT EXPLICITLY stored on the archive. | |
655 | * If that assumption is changed, you would test the node here | |
656 | * and figure out how to get rid of it (probably like some | |
657 | * recursive unlink()) or fix up the directory permissions if | |
658 | * required (do an access()). | |
659 | */ | |
660 | if (lstat(name, &sb) == 0) { | |
661 | *(spt++) = '/'; | |
662 | continue; | |
663 | } | |
664 | ||
665 | /* | |
666 | * the path fails at this point, see if we can create the | |
667 | * needed directory and continue on | |
668 | */ | |
669 | if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { | |
670 | *spt = '/'; | |
671 | retval = -1; | |
672 | break; | |
673 | } | |
674 | ||
675 | /* | |
676 | * we were able to create the directory. We will tell the | |
677 | * caller that we found something to fix, and it is ok to try | |
678 | * and create the node again. | |
679 | */ | |
680 | retval = 0; | |
681 | if (pids) | |
682 | (void)set_ids(name, st_uid, st_gid); | |
683 | ||
684 | /* | |
685 | * make sure the user doen't have some strange umask that | |
686 | * causes this newly created directory to be unusable. We fix | |
687 | * the modes and restore them back to the creation default at | |
688 | * the end of pax | |
689 | */ | |
690 | if ((access(name, R_OK | W_OK | X_OK) < 0) && | |
691 | (lstat(name, &sb) == 0)) { | |
692 | set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU)); | |
693 | add_dir(name, spt - name, &sb, 1); | |
694 | } | |
695 | *(spt++) = '/'; | |
696 | continue; | |
697 | } | |
698 | return(retval); | |
699 | } | |
700 | ||
701 | /* | |
702 | * set_ftime() | |
703 | * Set the access time and modification time for a named file. If frc is | |
704 | * non-zero we force these times to be set even if the user did not | |
705 | * request access and/or modification time preservation (this is also | |
706 | * used by -t to reset access times). | |
707 | * When ign is zero, only those times the user has asked for are set, the | |
708 | * other ones are left alone. We do not assume the un-documented feature | |
709 | * of many utimes() implementations that consider a 0 time value as a do | |
710 | * not set request. | |
711 | */ | |
712 | ||
713 | #ifdef __STDC__ | |
714 | void | |
715 | set_ftime(char *fnm, time_t mtime, time_t atime, int frc) | |
716 | #else | |
717 | void | |
718 | set_ftime(fnm, mtime, atime, frc) | |
719 | char *fnm; | |
720 | time_t mtime; | |
721 | time_t atime; | |
722 | int frc; | |
723 | #endif | |
724 | { | |
725 | static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}}; | |
726 | struct stat sb; | |
727 | ||
728 | tv[0].tv_sec = (long)atime; | |
729 | tv[1].tv_sec = (long)mtime; | |
730 | if (!frc && (!patime || !pmtime)) { | |
731 | /* | |
732 | * if we are not forcing, only set those times the user wants | |
733 | * set. We get the current values of the times if we need them. | |
734 | */ | |
735 | if (lstat(fnm, &sb) == 0) { | |
736 | if (!patime) | |
737 | tv[0].tv_sec = (long)sb.st_atime; | |
738 | if (!pmtime) | |
739 | tv[1].tv_sec = (long)sb.st_mtime; | |
740 | } else | |
741 | syswarn(0,errno,"Unable to obtain file stats %s", fnm); | |
742 | } | |
743 | ||
744 | /* | |
745 | * set the times | |
746 | */ | |
747 | if (utimes(fnm, tv) < 0) | |
748 | syswarn(1, errno, "Access/modification time set failed on: %s", | |
749 | fnm); | |
750 | return; | |
751 | } | |
752 | ||
753 | /* | |
754 | * set_ids() | |
755 | * set the uid and gid of a file system node | |
756 | * Return: | |
757 | * 0 when set, -1 on failure | |
758 | */ | |
759 | ||
760 | #ifdef __STDC__ | |
761 | int | |
762 | set_ids(char *fnm, uid_t uid, gid_t gid) | |
763 | #else | |
764 | int | |
765 | set_ids(fnm, uid, gid) | |
766 | char *fnm; | |
767 | uid_t uid; | |
768 | gid_t gid; | |
769 | #endif | |
770 | { | |
771 | if (chown(fnm, uid, gid) < 0) { | |
772 | /* | |
773 | * ignore EPERM unless in verbose mode or being run by root. | |
774 | * if running as pax, POSIX requires a warning. | |
775 | */ | |
776 | if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag || | |
777 | geteuid() == 0) | |
778 | syswarn(1, errno, "Unable to set file uid/gid of %s", | |
779 | fnm); | |
780 | return(-1); | |
781 | } | |
782 | return(0); | |
783 | } | |
784 | ||
fc155071 A |
785 | #if !defined(__APPLE__) |
786 | /* Mac OS X doesn't have lchown */ | |
787 | ||
44a7a5ab A |
788 | /* |
789 | * set_lids() | |
790 | * set the uid and gid of a file system node | |
791 | * Return: | |
792 | * 0 when set, -1 on failure | |
793 | */ | |
794 | ||
795 | #ifdef __STDC__ | |
796 | int | |
797 | set_lids(char *fnm, uid_t uid, gid_t gid) | |
798 | #else | |
799 | int | |
800 | set_lids(fnm, uid, gid) | |
801 | char *fnm; | |
802 | uid_t uid; | |
803 | gid_t gid; | |
804 | #endif | |
805 | { | |
44a7a5ab | 806 | if (lchown(fnm, uid, gid) < 0) { |
44a7a5ab A |
807 | /* |
808 | * ignore EPERM unless in verbose mode or being run by root. | |
809 | * if running as pax, POSIX requires a warning. | |
810 | */ | |
811 | if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag || | |
812 | geteuid() == 0) | |
813 | syswarn(1, errno, "Unable to set file uid/gid of %s", | |
814 | fnm); | |
815 | return(-1); | |
816 | } | |
817 | return(0); | |
818 | } | |
fc155071 | 819 | #endif |
44a7a5ab A |
820 | |
821 | /* | |
822 | * set_pmode() | |
823 | * Set file access mode | |
824 | */ | |
825 | ||
826 | #ifdef __STDC__ | |
827 | void | |
828 | set_pmode(char *fnm, mode_t mode) | |
829 | #else | |
830 | void | |
831 | set_pmode(fnm, mode) | |
832 | char *fnm; | |
833 | mode_t mode; | |
834 | #endif | |
835 | { | |
836 | mode &= ABITS; | |
837 | if (chmod(fnm, mode) < 0) | |
838 | syswarn(1, errno, "Could not set permissions on %s", fnm); | |
839 | return; | |
840 | } | |
841 | ||
842 | /* | |
843 | * file_write() | |
844 | * Write/copy a file (during copy or archive extract). This routine knows | |
845 | * how to copy files with lseek holes in it. (Which are read as file | |
846 | * blocks containing all 0's but do not have any file blocks associated | |
847 | * with the data). Typical examples of these are files created by dbm | |
848 | * variants (.pag files). While the file size of these files are huge, the | |
849 | * actual storage is quite small (the files are sparse). The problem is | |
850 | * the holes read as all zeros so are probably stored on the archive that | |
851 | * way (there is no way to determine if the file block is really a hole, | |
852 | * we only know that a file block of all zero's can be a hole). | |
853 | * At this writing, no major archive format knows how to archive files | |
854 | * with holes. However, on extraction (or during copy, -rw) we have to | |
855 | * deal with these files. Without detecting the holes, the files can | |
856 | * consume a lot of file space if just written to disk. This replacement | |
857 | * for write when passed the basic allocation size of a file system block, | |
858 | * uses lseek whenever it detects the input data is all 0 within that | |
859 | * file block. In more detail, the strategy is as follows: | |
860 | * While the input is all zero keep doing an lseek. Keep track of when we | |
861 | * pass over file block boundries. Only write when we hit a non zero | |
862 | * input. once we have written a file block, we continue to write it to | |
863 | * the end (we stop looking at the input). When we reach the start of the | |
864 | * next file block, start checking for zero blocks again. Working on file | |
865 | * block boundries significantly reduces the overhead when copying files | |
866 | * that are NOT very sparse. This overhead (when compared to a write) is | |
867 | * almost below the measurement resolution on many systems. Without it, | |
868 | * files with holes cannot be safely copied. It does has a side effect as | |
869 | * it can put holes into files that did not have them before, but that is | |
870 | * not a problem since the file contents are unchanged (in fact it saves | |
871 | * file space). (Except on paging files for diskless clients. But since we | |
872 | * cannot determine one of those file from here, we ignore them). If this | |
873 | * ever ends up on a system where CTG files are supported and the holes | |
874 | * are not desired, just do a conditional test in those routines that | |
875 | * call file_write() and have it call write() instead. BEFORE CLOSING THE | |
876 | * FILE, make sure to call file_flush() when the last write finishes with | |
877 | * an empty block. A lot of file systems will not create an lseek hole at | |
878 | * the end. In this case we drop a single 0 at the end to force the | |
879 | * trailing 0's in the file. | |
880 | * ---Parameters--- | |
881 | * rem: how many bytes left in this file system block | |
882 | * isempt: have we written to the file block yet (is it empty) | |
883 | * sz: basic file block allocation size | |
884 | * cnt: number of bytes on this write | |
885 | * str: buffer to write | |
886 | * Return: | |
887 | * number of bytes written, -1 on write (or lseek) error. | |
888 | */ | |
889 | ||
890 | #ifdef __STDC__ | |
891 | int | |
892 | file_write(int fd, char *str, register int cnt, int *rem, int *isempt, int sz, | |
893 | char *name) | |
894 | #else | |
895 | int | |
896 | file_write(fd, str, cnt, rem, isempt, sz, name) | |
897 | int fd; | |
898 | char *str; | |
899 | register int cnt; | |
900 | int *rem; | |
901 | int *isempt; | |
902 | int sz; | |
903 | char *name; | |
904 | #endif | |
905 | { | |
906 | register char *pt; | |
907 | register char *end; | |
908 | register int wcnt; | |
909 | register char *st = str; | |
910 | ||
911 | /* | |
912 | * while we have data to process | |
913 | */ | |
914 | while (cnt) { | |
915 | if (!*rem) { | |
916 | /* | |
917 | * We are now at the start of file system block again | |
918 | * (or what we think one is...). start looking for | |
919 | * empty blocks again | |
920 | */ | |
921 | *isempt = 1; | |
922 | *rem = sz; | |
923 | } | |
924 | ||
925 | /* | |
926 | * only examine up to the end of the current file block or | |
927 | * remaining characters to write, whatever is smaller | |
928 | */ | |
929 | wcnt = MIN(cnt, *rem); | |
930 | cnt -= wcnt; | |
931 | *rem -= wcnt; | |
932 | if (*isempt) { | |
933 | /* | |
934 | * have not written to this block yet, so we keep | |
935 | * looking for zero's | |
936 | */ | |
937 | pt = st; | |
938 | end = st + wcnt; | |
939 | ||
940 | /* | |
941 | * look for a zero filled buffer | |
942 | */ | |
943 | while ((pt < end) && (*pt == '\0')) | |
944 | ++pt; | |
945 | ||
946 | if (pt == end) { | |
947 | /* | |
948 | * skip, buf is empty so far | |
949 | */ | |
950 | if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) { | |
951 | syswarn(1,errno,"File seek on %s", | |
952 | name); | |
953 | return(-1); | |
954 | } | |
955 | st = pt; | |
956 | continue; | |
957 | } | |
958 | /* | |
959 | * drat, the buf is not zero filled | |
960 | */ | |
961 | *isempt = 0; | |
962 | } | |
963 | ||
964 | /* | |
965 | * have non-zero data in this file system block, have to write | |
966 | */ | |
967 | if (write(fd, st, wcnt) != wcnt) { | |
968 | syswarn(1, errno, "Failed write to file %s", name); | |
969 | return(-1); | |
970 | } | |
971 | st += wcnt; | |
972 | } | |
973 | return(st - str); | |
974 | } | |
975 | ||
976 | /* | |
977 | * file_flush() | |
978 | * when the last file block in a file is zero, many file systems will not | |
979 | * let us create a hole at the end. To get the last block with zeros, we | |
980 | * write the last BYTE with a zero (back up one byte and write a zero). | |
981 | */ | |
982 | ||
983 | #ifdef __STDC__ | |
984 | void | |
985 | file_flush(int fd, char *fname, int isempt) | |
986 | #else | |
987 | void | |
988 | file_flush(fd, fname, isempt) | |
989 | int fd; | |
990 | char *fname; | |
991 | int isempt; | |
992 | #endif | |
993 | { | |
994 | static char blnk[] = "\0"; | |
995 | ||
996 | /* | |
997 | * silly test, but make sure we are only called when the last block is | |
998 | * filled with all zeros. | |
999 | */ | |
1000 | if (!isempt) | |
1001 | return; | |
1002 | ||
1003 | /* | |
1004 | * move back one byte and write a zero | |
1005 | */ | |
1006 | if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) { | |
1007 | syswarn(1, errno, "Failed seek on file %s", fname); | |
1008 | return; | |
1009 | } | |
1010 | ||
1011 | if (write(fd, blnk, 1) < 0) | |
1012 | syswarn(1, errno, "Failed write to file %s", fname); | |
1013 | return; | |
1014 | } | |
1015 | ||
1016 | /* | |
1017 | * rdfile_close() | |
1018 | * close a file we have beed reading (to copy or archive). If we have to | |
1019 | * reset access time (tflag) do so (the times are stored in arcn). | |
1020 | */ | |
1021 | ||
1022 | #ifdef __STDC__ | |
1023 | void | |
1024 | rdfile_close(register ARCHD *arcn, register int *fd) | |
1025 | #else | |
1026 | void | |
1027 | rdfile_close(arcn, fd) | |
1028 | register ARCHD *arcn; | |
1029 | register int *fd; | |
1030 | #endif | |
1031 | { | |
1032 | /* | |
1033 | * make sure the file is open | |
1034 | */ | |
1035 | if (*fd < 0) | |
1036 | return; | |
1037 | ||
1038 | (void)close(*fd); | |
1039 | *fd = -1; | |
1040 | if (!tflag) | |
1041 | return; | |
1042 | ||
1043 | /* | |
1044 | * user wants last access time reset | |
1045 | */ | |
1046 | set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1); | |
1047 | return; | |
1048 | } | |
1049 | ||
1050 | /* | |
1051 | * set_crc() | |
1052 | * read a file to calculate its crc. This is a real drag. Archive formats | |
1053 | * that have this, end up reading the file twice (we have to write the | |
1054 | * header WITH the crc before writing the file contents. Oh well... | |
1055 | * Return: | |
1056 | * 0 if was able to calculate the crc, -1 otherwise | |
1057 | */ | |
1058 | ||
1059 | #ifdef __STDC__ | |
1060 | int | |
1061 | set_crc(register ARCHD *arcn, register int fd) | |
1062 | #else | |
1063 | int | |
1064 | set_crc(arcn, fd) | |
1065 | register ARCHD *arcn; | |
1066 | register int fd; | |
1067 | #endif | |
1068 | { | |
1069 | register int i; | |
1070 | register int res; | |
1071 | off_t cpcnt = 0L; | |
1072 | u_long size; | |
1073 | unsigned long crc = 0L; | |
1074 | char tbuf[FILEBLK]; | |
1075 | struct stat sb; | |
1076 | ||
1077 | if (fd < 0) { | |
1078 | /* | |
1079 | * hmm, no fd, should never happen. well no crc then. | |
1080 | */ | |
1081 | arcn->crc = 0L; | |
1082 | return(0); | |
1083 | } | |
1084 | ||
1085 | if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf)) | |
1086 | size = (u_long)sizeof(tbuf); | |
1087 | ||
1088 | /* | |
1089 | * read all the bytes we think that there are in the file. If the user | |
1090 | * is trying to archive an active file, forget this file. | |
1091 | */ | |
1092 | for(;;) { | |
1093 | if ((res = read(fd, tbuf, size)) <= 0) | |
1094 | break; | |
1095 | cpcnt += res; | |
1096 | for (i = 0; i < res; ++i) | |
1097 | crc += (tbuf[i] & 0xff); | |
1098 | } | |
1099 | ||
1100 | /* | |
1101 | * safety check. we want to avoid archiving files that are active as | |
1102 | * they can create inconsistant archive copies. | |
1103 | */ | |
1104 | if (cpcnt != arcn->sb.st_size) | |
1105 | paxwarn(1, "File changed size %s", arcn->org_name); | |
1106 | else if (fstat(fd, &sb) < 0) | |
1107 | syswarn(1, errno, "Failed stat on %s", arcn->org_name); | |
1108 | else if (arcn->sb.st_mtime != sb.st_mtime) | |
1109 | paxwarn(1, "File %s was modified during read", arcn->org_name); | |
1110 | else if (lseek(fd, (off_t)0L, SEEK_SET) < 0) | |
1111 | syswarn(1, errno, "File rewind failed on: %s", arcn->org_name); | |
1112 | else { | |
1113 | arcn->crc = crc; | |
1114 | return(0); | |
1115 | } | |
1116 | return(-1); | |
1117 | } |