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