]> Dogcows Code - chaz/tar/blob - src/system.c
(sys_child_open_for_uncompress): Minor stylistic fix.
[chaz/tar] / src / system.c
1 /* System-dependent calls for tar.
2
3 Copyright (C) 2003 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 #include "system.h"
20
21 #include "common.h"
22 #include "rmt.h"
23 #include <signal.h>
24
25 void
26 sys_stat_nanoseconds(struct tar_stat_info *stat)
27 {
28 #if defined(HAVE_STRUCT_STAT_ST_SPARE1)
29 stat->atime_nsec = stat->stat.st_spare1 * 1000;
30 stat->mtime_nsec = stat->stat.st_spare2 * 1000;
31 stat->ctime_nsec = stat->stat.st_spare3 * 1000;
32 #elif defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
33 stat->atime_nsec = stat->stat.st_atim.tv_nsec;
34 stat->mtime_nsec = stat->stat.st_mtim.tv_nsec;
35 stat->ctime_nsec = stat->stat.st_ctim.tv_nsec;
36 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
37 stat->atime_nsec = stat->stat.st_atimespec.tv_nsec;
38 stat->mtime_nsec = stat->stat.st_mtimespec.tv_nsec;
39 stat->ctime_nsec = stat->stat.st_ctimespec.tv_nsec;
40 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
41 stat->atime_nsec = stat->stat.st_atimensec;
42 stat->mtime_nsec = stat->stat.st_mtimensec;
43 stat->ctime_nsec = stat->stat.st_ctimensec;
44 #else
45 stat->atime_nsec = stat->mtime_nsec = stat->ctime_nsec = 0;
46 #endif
47 }
48
49 int
50 sys_utimes(char *file_name, struct timeval tvp[3])
51 {
52 #ifdef HAVE_UTIMES
53 return utimes (file_name, tvp);
54 #else
55 struct utimbuf utimbuf;
56 utimbuf.actime = tvp[0].tv_sec;
57 utimbuf.modtime = tvp[1].tv_sec;
58 return utime (file_name, &utimbuf);
59 #endif
60 }
61
62 #if MSDOS
63
64 bool
65 sys_get_archive_stat ()
66 {
67 return 0;
68 }
69
70 bool
71 sys_file_is_archive (struct tar_stat_info *p)
72 {
73 return false;
74 }
75
76 void
77 sys_save_archive_dev_ino ()
78 {
79 }
80
81 void
82 sys_detect_dev_null_output ()
83 {
84 static char const dev_null[] = "nul";
85
86 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
87 || (! _isrmt (archive)));
88 }
89
90 void
91 sys_drain_input_pipe ()
92 {
93 }
94
95 void
96 sys_wait_for_child (pid_t child_pid)
97 {
98 }
99
100 void
101 sys_spawn_shell ()
102 {
103 spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
104 }
105
106 /* stat() in djgpp's C library gives a constant number of 42 as the
107 uid and gid of a file. So, comparing an FTP'ed archive just after
108 unpack would fail on MSDOS. */
109
110 bool
111 sys_compare_uid (struct stat *a, struct stat *b)
112 {
113 return true;
114 }
115
116 bool
117 sys_compare_gid (struct stat *a, struct stat *b)
118 {
119 return true;
120 }
121
122 void
123 sys_compare_links (struct stat *link_data, struct stat *stat_data)
124 {
125 return true;
126 }
127
128 int
129 sys_truncate (int fd)
130 {
131 return write (fd, "", 0);
132 }
133
134 void
135 sys_reset_uid_gid ()
136 {
137 }
138
139 ssize_t
140 sys_write_archive_buffer (void)
141 {
142 ssize_t status;
143 ssize_t written = 0;
144
145 while (0 <= (status = full_write (archive, record_start->buffer + written,
146 record_size - written)))
147 {
148 written += status;
149 if (written == record_size)
150 break;
151 }
152
153 return written ? written : status;
154 }
155
156 /* Set ARCHIVE for writing, then compressing an archive. */
157 void
158 sys_child_open_for_compress (void)
159 {
160 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
161 }
162
163 /* Set ARCHIVE for uncompressing, then reading an archive. */
164 void
165 sys_child_open_for_uncompress (void)
166 {
167 FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
168 }
169
170 #else
171
172 extern union block *record_start; /* FIXME */
173
174 static struct stat archive_stat; /* stat block for archive file */
175
176 bool
177 sys_get_archive_stat ()
178 {
179 return fstat (archive, &archive_stat) == 0;
180 }
181
182 bool
183 sys_file_is_archive (struct tar_stat_info *p)
184 {
185 return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
186 }
187
188 /* Save archive file inode and device numbers */
189 void
190 sys_save_archive_dev_ino ()
191 {
192 if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
193 {
194 ar_dev = archive_stat.st_dev;
195 ar_ino = archive_stat.st_ino;
196 }
197 else
198 ar_dev = 0;
199 }
200
201 /* Detect if outputting to "/dev/null". */
202 void
203 sys_detect_dev_null_output ()
204 {
205 static char const dev_null[] = "/dev/null";
206 struct stat dev_null_stat;
207
208 dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
209 || (! _isrmt (archive)
210 && S_ISCHR (archive_stat.st_mode)
211 && stat (dev_null, &dev_null_stat) == 0
212 && archive_stat.st_dev == dev_null_stat.st_dev
213 && archive_stat.st_ino == dev_null_stat.st_ino));
214 }
215
216 /* Manage to fully drain a pipe we might be reading, so to not break it on
217 the producer after the EOF block. FIXME: one of these days, GNU tar
218 might become clever enough to just stop working, once there is no more
219 work to do, we might have to revise this area in such time. */
220
221 void
222 sys_drain_input_pipe ()
223 {
224 if (access_mode == ACCESS_READ
225 && ! _isrmt (archive)
226 && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
227 while (rmtread (archive, record_start->buffer, record_size) > 0)
228 continue;
229 }
230
231 void
232 sys_wait_for_child (pid_t child_pid)
233 {
234 if (child_pid)
235 {
236 int wait_status;
237
238 while (waitpid (child_pid, &wait_status, 0) == -1)
239 if (errno != EINTR)
240 {
241 waitpid_error (use_compress_program_option);
242 break;
243 }
244
245 if (WIFSIGNALED (wait_status))
246 ERROR ((0, 0, _("Child died with signal %d"),
247 WTERMSIG (wait_status)));
248 else if (WEXITSTATUS (wait_status) != 0)
249 ERROR ((0, 0, _("Child returned status %d"),
250 WEXITSTATUS (wait_status)));
251 }
252 }
253
254 void
255 sys_spawn_shell ()
256 {
257 pid_t child;
258 const char *shell = getenv ("SHELL");
259 if (! shell)
260 shell = "/bin/sh";
261 child = xfork ();
262 if (child == 0)
263 {
264 execlp (shell, "-sh", "-i", (char *) 0);
265 exec_fatal (shell);
266 }
267 else
268 {
269 int wait_status;
270 while (waitpid (child, &wait_status, 0) == -1)
271 if (errno != EINTR)
272 {
273 waitpid_error (shell);
274 break;
275 }
276 }
277 }
278
279 bool
280 sys_compare_uid (struct stat *a, struct stat *b)
281 {
282 return a->st_uid == b->st_uid;
283 }
284
285 bool
286 sys_compare_gid (struct stat *a, struct stat *b)
287 {
288 return a->st_gid == b->st_gid;
289 }
290
291 bool
292 sys_compare_links (struct stat *link_data, struct stat *stat_data)
293 {
294 return stat_data->st_dev == link_data->st_dev
295 && stat_data->st_ino == link_data->st_ino;
296 }
297
298 int
299 sys_truncate (int fd)
300 {
301 off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
302 return pos < 0 ? -1 : ftruncate (fd, pos);
303 }
304
305 void
306 sys_reset_uid_gid ()
307 {
308 setuid (getuid ());
309 setgid (getgid ());
310 }
311
312 /* Return nonzero if NAME is the name of a regular file, or if the file
313 does not exist (so it would be created as a regular file). */
314 static int
315 is_regular_file (const char *name)
316 {
317 struct stat stbuf;
318
319 if (stat (name, &stbuf) == 0)
320 return S_ISREG (stbuf.st_mode);
321 else
322 return errno == ENOENT;
323 }
324
325 ssize_t
326 sys_write_archive_buffer (void)
327 {
328 ssize_t status;
329 ssize_t written = 0;
330
331 while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
332 record_size - written)))
333 {
334 written += status;
335 if (written == record_size
336 || _isrmt (archive)
337 || ! (S_ISFIFO (archive_stat.st_mode)
338 || S_ISSOCK (archive_stat.st_mode)))
339 break;
340 }
341
342 return written ? written : status;
343 }
344
345 #define PREAD 0 /* read file descriptor from pipe() */
346 #define PWRITE 1 /* write file descriptor from pipe() */
347
348 /* Duplicate file descriptor FROM into becoming INTO.
349 INTO is closed first and has to be the next available slot. */
350 static void
351 xdup2 (int from, int into)
352 {
353 if (from != into)
354 {
355 int status = close (into);
356
357 if (status != 0 && errno != EBADF)
358 {
359 int e = errno;
360 FATAL_ERROR ((0, e, _("Cannot close")));
361 }
362 status = dup (from);
363 if (status != into)
364 {
365 if (status < 0)
366 {
367 int e = errno;
368 FATAL_ERROR ((0, e, _("Cannot dup")));
369 }
370 abort ();
371 }
372 xclose (from);
373 }
374 }
375
376 /* Set ARCHIVE for writing, then compressing an archive. */
377 pid_t
378 sys_child_open_for_compress (void)
379 {
380 int parent_pipe[2];
381 int child_pipe[2];
382 pid_t grandchild_pid;
383 pid_t child_pid;
384 int wait_status;
385
386 xpipe (parent_pipe);
387 child_pid = xfork ();
388
389 if (child_pid > 0)
390 {
391 /* The parent tar is still here! Just clean up. */
392
393 archive = parent_pipe[PWRITE];
394 xclose (parent_pipe[PREAD]);
395 return child_pid;
396 }
397
398 /* The new born child tar is here! */
399
400 program_name = _("tar (child)");
401
402 xdup2 (parent_pipe[PREAD], STDIN_FILENO);
403 xclose (parent_pipe[PWRITE]);
404
405 /* Check if we need a grandchild tar. This happens only if either:
406 a) we are writing stdout: to force reblocking;
407 b) the file is to be accessed by rmt: compressor doesn't know how;
408 c) the file is not a plain file. */
409
410 if (strcmp (archive_name_array[0], "-") != 0
411 && !_remdev (archive_name_array[0])
412 && is_regular_file (archive_name_array[0]))
413 {
414 if (backup_option)
415 maybe_backup_file (archive_name_array[0], 1);
416
417 /* We don't need a grandchild tar. Open the archive and launch the
418 compressor. */
419
420 archive = creat (archive_name_array[0], MODE_RW);
421 if (archive < 0)
422 {
423 int saved_errno = errno;
424
425 if (backup_option)
426 undo_last_backup ();
427 errno = saved_errno;
428 open_fatal (archive_name_array[0]);
429 }
430 xdup2 (archive, STDOUT_FILENO);
431 execlp (use_compress_program_option, use_compress_program_option,
432 (char *) 0);
433 exec_fatal (use_compress_program_option);
434 }
435
436 /* We do need a grandchild tar. */
437
438 xpipe (child_pipe);
439 grandchild_pid = xfork ();
440
441 if (grandchild_pid == 0)
442 {
443 /* The newborn grandchild tar is here! Launch the compressor. */
444
445 program_name = _("tar (grandchild)");
446
447 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
448 xclose (child_pipe[PREAD]);
449 execlp (use_compress_program_option, use_compress_program_option,
450 (char *) 0);
451 exec_fatal (use_compress_program_option);
452 }
453
454 /* The child tar is still here! */
455
456 /* Prepare for reblocking the data from the compressor into the archive. */
457
458 xdup2 (child_pipe[PREAD], STDIN_FILENO);
459 xclose (child_pipe[PWRITE]);
460
461 if (strcmp (archive_name_array[0], "-") == 0)
462 archive = STDOUT_FILENO;
463 else
464 {
465 archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
466 if (archive < 0)
467 open_fatal (archive_name_array[0]);
468 }
469
470 /* Let's read out of the stdin pipe and write an archive. */
471
472 while (1)
473 {
474 ssize_t status = 0;
475 char *cursor;
476 size_t length;
477
478 /* Assemble a record. */
479
480 for (length = 0, cursor = record_start->buffer;
481 length < record_size;
482 length += status, cursor += status)
483 {
484 size_t size = record_size - length;
485
486 status = safe_read (STDIN_FILENO, cursor, size);
487 if (status <= 0)
488 break;
489 }
490
491 if (status < 0)
492 read_fatal (use_compress_program_option);
493
494 /* Copy the record. */
495
496 if (status == 0)
497 {
498 /* We hit the end of the file. Write last record at
499 full length, as the only role of the grandchild is
500 doing proper reblocking. */
501
502 if (length > 0)
503 {
504 memset (record_start->buffer + length, 0, record_size - length);
505 status = sys_write_archive_buffer ();
506 if (status != record_size)
507 archive_write_error (status);
508 }
509
510 /* There is nothing else to read, break out. */
511 break;
512 }
513
514 status = sys_write_archive_buffer ();
515 if (status != record_size)
516 archive_write_error (status);
517 }
518
519 /* Propagate any failure of the grandchild back to the parent. */
520
521 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
522 if (errno != EINTR)
523 {
524 waitpid_error (use_compress_program_option);
525 break;
526 }
527
528 if (WIFSIGNALED (wait_status))
529 {
530 kill (child_pid, WTERMSIG (wait_status));
531 exit_status = TAREXIT_FAILURE;
532 }
533 else if (WEXITSTATUS (wait_status) != 0)
534 exit_status = WEXITSTATUS (wait_status);
535
536 exit (exit_status);
537 }
538
539 /* Set ARCHIVE for uncompressing, then reading an archive. */
540 pid_t
541 sys_child_open_for_uncompress (void)
542 {
543 int parent_pipe[2];
544 int child_pipe[2];
545 pid_t grandchild_pid;
546 pid_t child_pid;
547 int wait_status;
548
549 xpipe (parent_pipe);
550 child_pid = xfork ();
551
552 if (child_pid > 0)
553 {
554 /* The parent tar is still here! Just clean up. */
555
556 read_full_records_option = true;
557 archive = parent_pipe[PREAD];
558 xclose (parent_pipe[PWRITE]);
559 return child_pid;
560 }
561
562 /* The newborn child tar is here! */
563
564 program_name = _("tar (child)");
565
566 xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
567 xclose (parent_pipe[PREAD]);
568
569 /* Check if we need a grandchild tar. This happens only if either:
570 a) we're reading stdin: to force unblocking;
571 b) the file is to be accessed by rmt: compressor doesn't know how;
572 c) the file is not a plain file. */
573
574 if (strcmp (archive_name_array[0], "-") != 0
575 && !_remdev (archive_name_array[0])
576 && is_regular_file (archive_name_array[0]))
577 {
578 /* We don't need a grandchild tar. Open the archive and lauch the
579 uncompressor. */
580
581 archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
582 if (archive < 0)
583 open_fatal (archive_name_array[0]);
584 xdup2 (archive, STDIN_FILENO);
585 execlp (use_compress_program_option, use_compress_program_option,
586 "-d", (char *) 0);
587 exec_fatal (use_compress_program_option);
588 }
589
590 /* We do need a grandchild tar. */
591
592 xpipe (child_pipe);
593 grandchild_pid = xfork ();
594
595 if (grandchild_pid == 0)
596 {
597 /* The newborn grandchild tar is here! Launch the uncompressor. */
598
599 program_name = _("tar (grandchild)");
600
601 xdup2 (child_pipe[PREAD], STDIN_FILENO);
602 xclose (child_pipe[PWRITE]);
603 execlp (use_compress_program_option, use_compress_program_option,
604 "-d", (char *) 0);
605 exec_fatal (use_compress_program_option);
606 }
607
608 /* The child tar is still here! */
609
610 /* Prepare for unblocking the data from the archive into the
611 uncompressor. */
612
613 xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
614 xclose (child_pipe[PREAD]);
615
616 if (strcmp (archive_name_array[0], "-") == 0)
617 archive = STDIN_FILENO;
618 else
619 archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
620 MODE_RW, rsh_command_option);
621 if (archive < 0)
622 open_fatal (archive_name_array[0]);
623
624 /* Let's read the archive and pipe it into stdout. */
625
626 while (1)
627 {
628 char *cursor;
629 size_t maximum;
630 size_t count;
631 ssize_t status;
632
633 clear_read_error_count ();
634
635 error_loop:
636 status = rmtread (archive, record_start->buffer, record_size);
637 if (status < 0)
638 {
639 archive_read_error ();
640 goto error_loop;
641 }
642 if (status == 0)
643 break;
644 cursor = record_start->buffer;
645 maximum = status;
646 while (maximum)
647 {
648 count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
649 if (full_write (STDOUT_FILENO, cursor, count) != count)
650 write_error (use_compress_program_option);
651 cursor += count;
652 maximum -= count;
653 }
654 }
655
656 xclose (STDOUT_FILENO);
657
658 /* Propagate any failure of the grandchild back to the parent. */
659
660 while (waitpid (grandchild_pid, &wait_status, 0) == -1)
661 if (errno != EINTR)
662 {
663 waitpid_error (use_compress_program_option);
664 break;
665 }
666
667 if (WIFSIGNALED (wait_status))
668 {
669 kill (child_pid, WTERMSIG (wait_status));
670 exit_status = TAREXIT_FAILURE;
671 }
672 else if (WEXITSTATUS (wait_status) != 0)
673 exit_status = WEXITSTATUS (wait_status);
674
675 exit (exit_status);
676 }
677
678 #endif /* not MSDOS */
679
This page took 0.062275 seconds and 5 git commands to generate.