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