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