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