source: trunk/minix/commands/simple/tar.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 27.1 KB
Line 
1/* tar - tape archiver Author: Michiel Huisjes */
2
3/* Usage: tar [cxt][vo][F][f] tapefile [files]
4 *
5 * attempt to make tar to conform to POSIX 1003.1
6 * disclaimer: based on an old (1986) POSIX draft.
7 * Klamer Schutte, 20/9/89
8 *
9 * Changes:
10 * Changed to handle the original minix-tar format. KS 22/9/89
11 * Changed to handle BSD4.3 tar format. KS 22/9/89
12 * Conform to current umask if not super-user. KS 22/9/89
13 * Update usage message to show f option KS 22/9/89
14 *
15 *
16 * 1) tar will back itself up, should check archive inode num(&dev) and
17 then check the target inode number. In verbose mode, issue
18 warning, in all cases ignore target.
19 marks@mgse Mon Sep 25 10:38:58 CDT 1989
20 added global varaibles, made changes to main() and add_file();
21 maks@mgse Mon Sep 25 12:09:20 CDT 1989
22
23 2) tar will not notice that a file has changed size while it was being
24 backed up. should issue warning.
25 marks@mgse Mon Sep 25 10:38:58 CDT 1989
26
27 3) the 'f' option was not documented in usage[].
28 marks@mgse Mon Sep 25 12:03:20 CDT 1989
29 changed both usage[] defines. Why are there two (one is commented out)?
30 ( deleted by me (was done twice) -- KS, 2/10/89 )
31 *
32 * changed stat on tar_fd to an fstat KS 2/10/89
33 * deleted mkfifo() code -- belongs in libc.a KS 2/10/89
34 * made ar_dev default to -1 : an illegal device KS 2/10/89
35 * made impossible to chown if normal user KS 2/10/89
36 * if names in owner fields not known use numirical values KS 2/10/89
37 * creat with mask 666 -- use umask if to liberal KS 2/10/89
38 * allow to make directories as ../directory KS 2/10/89
39 * allow tmagic field to end with a space (instead of \0) KS 2/10/89
40 * correct usage of tmagic field KS 3/10/89
41 * made mkdir() to return a value if directory == "." KS 3/10/89
42 * made lint complains less (On a BSD 4.3 system) KS 3/10/89
43 * use of directory(3) routines KS 3/10/89
44 * deleted use of d_namlen selector of struct dirent KS 18/10/89
45 * support mknod4(2) EC 7/7/90
46 * forget inodes when link count expires EC 6/4/91
47 * don't remember directories *twice*!
48 * added 'p' flag to ignore umask for normal user KJB 6/10/92
49 * mknod4(2) out KJB 30/10/94
50 * added 'D' flag to not recurse into directories KJB 19/12/94
51 * status output to stdout unless 'tar cvf -' KJB 3/5/97
52 *
53 * Bugs:
54 * verbose mode is not reporting consistent
55 * code needs cleanup
56 * prefix field is not used
57 * timestamp of a directory will not be correct if there are files to be
58 * unpacked in the directory
59 * (add you favorite bug here (or two (or three (or ...))))
60*/
61
62#include <sys/types.h>
63#include <sys/stat.h>
64#include <fcntl.h>
65#include <pwd.h>
66#include <grp.h>
67#include <tar.h>
68#include <stdarg.h>
69#include <stdlib.h>
70#include <string.h>
71#include <unistd.h>
72#include <utime.h>
73#include <sys/wait.h>
74#include <stdio.h> /* need NULL */
75#include <errno.h>
76
77#define POSIX_COMP /* POSIX compatible */
78#define DIRECT_3 /* use directory(3) routines */
79
80#ifdef DIRECT_3
81#ifndef BSD
82/* To all minix users: i am sorry, developed this piece of code on a
83 * BSD system. KS 18/10/89 */
84#include <dirent.h>
85#define direct dirent /* stupid BSD non-POSIX compatible name! */
86#else /* BSD */
87#include <sys/dir.h>
88#include <dir.h>
89#endif /* BSD */
90#endif /* DIRECT_3 */
91
92#ifdef S_IFIFO
93#define HAVE_FIFO /* have incorporated Simon Pooles' changes */
94#endif
95#ifdef S_IFLNK
96#define HAVE_SYMLINK
97#endif
98
99typedef char BOOL;
100#define TRUE 1
101#define FALSE 0
102
103#define STRING_SIZE 256 /* string buffer size */
104#define HEADER_SIZE TBLOCK
105#define NAME_SIZE NAMSIZ
106/* #define BLOCK_BOUNDARY 20 -- not in POSIX ! */
107
108typedef union hblock HEADER;
109
110/* Make the MINIX member names overlap to the POSIX names */
111#define m_name name
112#define m_mode mode
113#define m_uid uid
114#define m_gid gid
115#define m_size size
116#define m_time mtime
117#define m_checksum chksum
118#define m_linked typeflag
119#define m_link linkname
120#define hdr_block dummy
121#define m header
122#define member dbuf
123
124#if 0 /* original structure -- see tar.h for new
125 * structure */
126typedef union {
127 char hdr_block[HEADER_SIZE];
128 struct m {
129 char m_name[NAME_SIZE];
130 char m_mode[8];
131 char m_uid[8];
132 char m_gid[8];
133 char m_size[12];
134 char m_time[12];
135 char m_checksum[8];
136 char m_linked;
137 char m_link[NAME_SIZE];
138 } member;
139} HEADER;
140
141#endif
142
143/* Structure used to note links */
144struct link {
145 ino_t ino;
146 dev_t dev;
147 nlink_t nlink;
148 struct link *next;
149 char name[1];
150} *link_top = NULL;
151
152HEADER header;
153
154#define INT_TYPE (sizeof(header.member.m_uid))
155#define LONG_TYPE (sizeof(header.member.m_size))
156
157#define NIL_HEADER ((HEADER *) 0)
158#define NIL_PTR ((char *) 0)
159#define TBLOCK_SIZE TBLOCK
160
161#define flush() print(NIL_PTR)
162
163BOOL show_fl, creat_fl, ext_fl;
164
165int tar_fd;
166/* Char usage[] = "Usage: tar [cxt] tarfile [files]."; */
167char usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
168char io_buffer[TBLOCK_SIZE];
169char path[NAME_SIZE];
170char pathname[NAME_SIZE];
171int force_flag = 0;
172#ifdef ORIGINAL_DEFAULTS
173int chown_flag = 1;
174int verbose_flag = 1;
175#else
176int chown_flag = 0;
177int verbose_flag = 0;
178#endif
179int norec_flag = 0;
180
181/* Make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
182ino_t ar_inode; /* archive inode number */
183dev_t ar_dev; /* archive device number */
184
185int total_blocks;
186int u_mask; /* one's complement of current umask */
187
188#define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \
189 + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE)
190
191_PROTOTYPE(int main, (int argc, char **argv));
192_PROTOTYPE(void error, (char *s1, char *s2));
193_PROTOTYPE(BOOL get_header, (void));
194_PROTOTYPE(void tarfile, (void));
195_PROTOTYPE(void skip_entry, (void));
196_PROTOTYPE(void extract, (char *file));
197_PROTOTYPE(void delete, (char *file));
198_PROTOTYPE(void do_chown, (char *file));
199_PROTOTYPE(void timestamp, (char *file));
200_PROTOTYPE(void copy, (char *file, int from, int to, long bytes));
201_PROTOTYPE(long convert, (char str[], int type));
202_PROTOTYPE(int checksum, (void));
203_PROTOTYPE(int is_dir, (char *file));
204_PROTOTYPE(char *path_name, (char *file));
205_PROTOTYPE(void add_path, (char *name));
206_PROTOTYPE(void add_file, (char *file));
207_PROTOTYPE(void verb_print, (char *s1, char *s2));
208_PROTOTYPE(void add_close, (int fd));
209_PROTOTYPE(int add_open, (char *file, struct stat * st));
210_PROTOTYPE(void make_header, (char *file, struct stat * st));
211_PROTOTYPE(void is_added, (struct stat * st, char *file));
212_PROTOTYPE(void is_deleted, (struct stat * st));
213_PROTOTYPE(char *is_linked, (struct stat * st));
214_PROTOTYPE(void clear_header, (void));
215_PROTOTYPE(void adjust_boundary, (void));
216_PROTOTYPE(void mread, (int fd, char *address, int bytes));
217_PROTOTYPE(void mwrite, (int fd, char *address, int bytes));
218_PROTOTYPE(int bread, (int fd, char *address, int bytes));
219_PROTOTYPE(int bwrite, (int fd, char *address, int bytes));
220_PROTOTYPE(void print, (char *str));
221_PROTOTYPE(char *num_out, (long number));
222_PROTOTYPE(void string_print, (char *buffer, char *fmt,...));
223
224void error(s1, s2)
225char *s1, *s2;
226{
227 string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
228 flush();
229 exit(1);
230}
231
232int main(argc, argv)
233int argc;
234register char *argv[];
235{
236 register char *mem_name;
237 register char *ptr;
238 struct stat st;
239 int i;
240
241 if (argc < 3) error(usage, NIL_PTR);
242
243 for (ptr = argv[1]; *ptr; ptr++) {
244 /* Ignore - as first char */
245 if(*ptr == '-' && ptr == argv[1]) continue;
246 switch (*ptr) {
247 case 'c': creat_fl = TRUE; break;
248 case 'x': ext_fl = TRUE; break;
249 case 't': show_fl = TRUE; break;
250 case 'v': /* verbose output -Dal */
251 verbose_flag = !verbose_flag;
252 break;
253 case 'o': /* chown/chgrp files -Dal */
254 chown_flag = TRUE;
255 break;
256 case 'F': /* IGNORE ERRORS -Dal */
257 force_flag = TRUE;
258 break;
259 case 'f': /* standard U*IX usage -KS */
260 break;
261 case 'p': /* restore file modes right, ignore umask. */
262 (void) umask(0);
263 break;
264 case 'D': /* do not recursively add directories. */
265 norec_flag = TRUE;
266 break;
267 default: error(usage, NIL_PTR);
268 }
269 }
270
271 if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR);
272
273 if (strcmp(argv[2], "-") == 0)/* only - means stdin/stdout - KS */
274 tar_fd = creat_fl ? 1 : 0; /* '-' means used
275 * stdin/stdout -Dal */
276 else
277 tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], O_RDONLY);
278
279 if (tar_fd < 0) error("Cannot open ", argv[2]);
280
281 if (geteuid()) { /* check if super-user */
282 int save_umask;
283 save_umask = umask(0);
284 u_mask = ~save_umask;
285 umask(save_umask);
286 chown_flag = TRUE; /* normal user can't chown */
287 } else
288 u_mask = ~0; /* don't restrict if 'privileged utility' */
289
290 ar_dev = -1; /* impossible device nr */
291 if (creat_fl) {
292 if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
293 error("Can't stat ", argv[2]); /* will never be here,
294 * right? */
295 else { /* get archive inode & device */
296 ar_inode = st.st_ino; /* save files inode */
297 ar_dev = st.st_dev; /* save files device */
298 } /* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
299
300 for (i = 3; i < argc; i++) {
301 add_file(argv[i]);
302 path[0] = '\0';
303 }
304 adjust_boundary();
305 } else if (ext_fl) {
306 /* Extraction code moved here from tarfile() MSP */
307 while (get_header()) {
308 mem_name = header.member.m_name;
309 if (is_dir(mem_name)) {
310 for (ptr = mem_name; *ptr; ptr++);
311 *(ptr - 1) = '\0';
312 header.dbuf.typeflag = '5';
313 }
314 for (i = 3; i < argc; i++)
315 if (!strncmp(argv[i], mem_name, strlen(argv[i])))
316 break;
317 if (argc == 3 || (i < argc)) {
318 extract(mem_name);
319 } else if (header.dbuf.typeflag == '0' ||
320 header.dbuf.typeflag == 0 ||
321 header.dbuf.typeflag == ' ')
322 skip_entry();
323 flush();
324 }
325 } else
326 tarfile(); /* tarfile() justs prints info. now MSP */
327
328 flush();
329 return(0);
330}
331
332BOOL get_header()
333{
334 register int check;
335
336 mread(tar_fd, (char *) &header, sizeof(header));
337 if (header.member.m_name[0] == '\0') return FALSE;
338
339 if (force_flag) /* skip checksum verification -Dal */
340 return TRUE;
341
342 check = (int) convert(header.member.m_checksum, INT_TYPE);
343
344 if (check != checksum()) error("Tar: header checksum error.", NIL_PTR);
345
346 return TRUE;
347}
348
349/* Tarfile() just lists info about archive now; as of the t flag. */
350/* Extraction has been moved into main() as that needs access to argv[] */
351
352void tarfile()
353{
354 register char *mem_name;
355
356 while (get_header()) {
357 mem_name = header.member.m_name;
358 string_print(NIL_PTR, "%s%s", mem_name,
359 (verbose_flag ? " " : "\n"));
360 switch (header.dbuf.typeflag) {
361 case '1':
362 verb_print("linked to", header.dbuf.linkname);
363 break;
364 case '2':
365 verb_print("symbolic link to", header.dbuf.linkname);
366 break;
367 case '6': verb_print("", "fifo"); break;
368 case '3':
369 case '4':
370 if (verbose_flag) {
371 char sizebuf[TSIZLEN + 1];
372
373 strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
374 sizebuf[TSIZLEN] = 0;
375 string_print(NIL_PTR,
376 "%s special file major %s minor %s\n",
377 (header.dbuf.typeflag == '3' ?
378 "character" : "block"),
379 header.dbuf.devmajor,
380 header.dbuf.devminor,
381 sizebuf);
382 }
383 break;
384 case '0': /* official POSIX */
385 case 0: /* also mentioned in POSIX */
386 case ' ': /* ofetn used */
387 if (!is_dir(mem_name)) {
388 if (verbose_flag)
389 string_print(NIL_PTR, "%d tape blocks\n",
390 block_size());
391 skip_entry();
392 break;
393 } else /* FALL TROUGH */
394 case '5':
395 verb_print("", "directory");
396 break;
397 default:
398 string_print(NIL_PTR, "not recogised item %d\n",
399 header.dbuf.typeflag);
400 }
401 flush();
402 }
403}
404
405void skip_entry()
406{
407 register int blocks = block_size();
408
409 while (blocks--) (void) bread(tar_fd, io_buffer, TBLOCK_SIZE);
410}
411
412void extract(file)
413register char *file;
414{
415 register int fd, r;
416 char *pd1, *pd2; /* walk thru failed directory path */
417
418 switch (header.dbuf.typeflag) {
419 case '1': /* Link */
420 delete(file);
421 if (link(header.member.m_link, file) < 0)
422 string_print(NIL_PTR, "Cannot link %s to %s: %s\n",
423 header.member.m_link, file, strerror(errno));
424 else if (verbose_flag)
425 string_print(NIL_PTR, "Linked %s to %s\n",
426 header.member.m_link, file);
427 return;
428 case '5': /* directory */
429 if (!(file[0] == '.' && file[1] == '\0')) delete(file);
430 if ((file[0] == '.' && file[1] == '\0') || mkdir(file, 0700) == 0) {
431 do_chown(file);
432 verb_print("created directory", file);
433 } else {
434 string_print(NIL_PTR, "Can't make directory %s: %s\n",
435 file, strerror(errno));
436 }
437 return;
438 case '3': /* character special */
439 case '4': /* block special */
440 {
441 int dmajor, dminor, mode;
442
443 dmajor = (int) convert(header.dbuf.devmajor, INT_TYPE);
444 dminor = (int) convert(header.dbuf.devminor, INT_TYPE);
445 mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);
446 delete(file);
447 if (mknod(file, mode, (dmajor << 8 | dminor)) == 0) {
448 if (verbose_flag) string_print(NIL_PTR,
449 "made %s special file major %s minor %s\n",
450 (header.dbuf.typeflag == '3' ?
451 "character" : "block"),
452 header.dbuf.devmajor,
453 header.dbuf.devminor);
454 do_chown(file);
455 }
456 else
457 {
458 string_print(NIL_PTR,
459 "cannot make %s special file major %s minor %s: %s\n",
460 (header.dbuf.typeflag == '3' ?
461 "character" : "block"),
462 header.dbuf.devmajor,
463 header.dbuf.devminor,
464 strerror(errno));
465 }
466 return;
467 }
468 case '2': /* symbolic link */
469#ifdef HAVE_SYMLINK
470 delete(file);
471 if (symlink(header.member.m_link, file) < 0)
472 string_print(NIL_PTR, "Cannot make symbolic link %s to %s: %s\n",
473 header.member.m_link, file, strerror(errno));
474 else if (verbose_flag)
475 string_print(NIL_PTR, "Symbolic link %s to %s\n",
476 header.member.m_link, file);
477 return;
478#endif
479 case '7': /* contiguous file -- what is this (KS) */
480 print("Not implemented file type\n");
481 return; /* not implemented, but break out */
482#ifdef HAVE_FIFO
483 case '6': /* fifo */
484 delete(file);
485 if (mkfifo(file, 0) == 0) { /* is chmod'ed in do_chown */
486 do_chown(file);
487 verb_print("made fifo", file);
488 } else
489 string_print(NIL_PTR, "Can't make fifo %s: %s\n",
490 file, strerror(errno));
491 return;
492#endif
493 }
494
495 /* Create regular file. If failure, try to make missing directories. */
496 if ((fd = creat(file, 0600)) < 0) {
497 pd1 = file;
498 while ((pd2 = index(pd1, '/')) > (char *) 0) {
499 *pd2 = '\0';
500 if (access(file, 1) < 0)
501 if (mkdir(file, 0777) < 0) {
502 string_print(NIL_PTR, "Cannot mkdir %s: %s\n",
503 file, strerror(errno));
504 return;
505 } else
506 string_print(NIL_PTR, "Made directory %s\n", file);
507 *pd2 = '/';
508 pd1 = ++pd2;
509 }
510 if ((fd = creat(file, 0600)) < 0) {
511 string_print(NIL_PTR, "Cannot create %s: %s\n",
512 file, strerror(errno));
513 return;
514 }
515 }
516 copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));
517 (void) close(fd);
518
519 do_chown(file);
520}
521
522void delete(file)
523char *file;
524{
525 /* remove a file or an empty directory */
526 struct stat stbuf;
527
528 if (stat(file, &stbuf) < 0) return;
529
530 if (S_ISDIR(stbuf.st_mode)) (void) rmdir(file); else (void) unlink(file);
531 /* leave error reporting to the create following soon. */
532}
533
534void do_chown(file)
535char *file;
536{
537 int uid = -1, gid = -1; /* these are illegal ??? -- KS */
538
539 if (!chown_flag) { /* set correct owner and group -Dal */
540 if (header.dbuf.magic[TMAGLEN] == ' ')
541 header.dbuf.magic[TMAGLEN] = '\0'; /* some tars out there
542 * ... */
543 if (strncmp(TMAGIC, header.dbuf.magic, (size_t) TMAGLEN)) {
544 struct passwd *pwd;
545 struct group *grp;
546
547 pwd = getpwnam(header.dbuf.uname);
548 if (pwd != NULL) uid = pwd->pw_uid;
549 grp = getgrnam(header.dbuf.gname);
550 if (grp != NULL) gid = grp->gr_gid;
551 }
552 if (uid == -1) uid = (int) convert(header.member.m_uid, INT_TYPE);
553 if (gid == -1) gid = (int) convert(header.member.m_gid, INT_TYPE);
554 chown(file, uid, gid);
555 }
556 chmod(file, u_mask & (int) convert(header.member.m_mode, INT_TYPE));
557
558 /* Should there be a timestamp if the chown failes? -- KS */
559 timestamp(file);
560
561}
562
563void timestamp(file)
564char *file;
565{
566 struct utimbuf buf;
567
568 buf.modtime = buf.actime = convert(header.dbuf.mtime, LONG_TYPE);
569 utime(file, &buf);
570}
571
572void copy(file, from, to, bytes)
573char *file;
574int from, to;
575register long bytes;
576{
577 register int rest;
578 int blocks = (int) ((bytes + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE);
579
580 if (verbose_flag)
581 string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
582
583 while (blocks--) {
584 (void) bread(from, io_buffer, TBLOCK_SIZE);
585 rest = (bytes > (long) TBLOCK_SIZE) ? TBLOCK_SIZE : (int) bytes;
586 mwrite(to, io_buffer, (to == tar_fd) ? TBLOCK_SIZE : rest);
587 bytes -= (long) rest;
588 }
589}
590
591long convert(str, type)
592char str[];
593int type;
594{
595 register long ac = 0L;
596 register int i;
597
598 for (i = 0; i < type; i++) {
599 if (str[i] >= '0' && str[i] <= '7') {
600 ac <<= 3;
601 ac += (long) (str[i] - '0');
602 }
603 }
604
605 return ac;
606}
607
608int checksum()
609{
610 register char *ptr = header.member.m_checksum;
611 register int ac = 0;
612
613 while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' ';
614
615 ptr = header.hdr_block;
616 while (ptr < &header.hdr_block[TBLOCK_SIZE]) ac += *ptr++;
617
618 return ac;
619}
620
621int is_dir(file)
622register char *file;
623{
624 while (*file++ != '\0');
625
626 return(*(file - 2) == '/');
627}
628
629
630char *path_name(file)
631register char *file;
632{
633
634 string_print(pathname, "%s%s", path, file);
635 return pathname;
636}
637
638void add_path(name)
639register char *name;
640{
641 register char *path_ptr = path;
642
643 while (*path_ptr) path_ptr++;
644
645 if (name == NIL_PTR) {
646 while (*path_ptr-- != '/');
647 while (*path_ptr != '/' && path_ptr != path) path_ptr--;
648 if (*path_ptr == '/') path_ptr++;
649 *path_ptr = '\0';
650 } else {
651 while (*name) {
652 if (path_ptr == &path[NAME_SIZE])
653 error("Pathname too long", NIL_PTR);
654 *path_ptr++ = *name++;
655 }
656 *path_ptr++ = '/';
657 *path_ptr = '\0';
658 }
659}
660
661/*
662 * add a file to the archive
663*/
664void add_file(file)
665register char *file;
666{
667 struct stat st;
668 char *linkname;
669 register int fd = -1;
670 char namebuf[16]; /* -Dal */
671 char cwd[129]; /* -KS */
672
673#ifdef HAVE_SYMLINK
674 if (lstat(file, &st) < 0) {
675#else
676 if (stat(file, &st) < 0) {
677#endif
678 string_print(NIL_PTR, "%s: %s\n", file, strerror(errno));
679 return;
680 }
681 if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
682 string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
683 return;
684 } /* marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
685 if ((fd = add_open(file, &st)) < 0) {
686 string_print(NIL_PTR, "Cannot open %s\n", file);
687 return;
688 }
689 make_header(path_name(file), &st);
690 if ((linkname = is_linked(&st)) != NULL) {
691 strncpy(header.dbuf.linkname, linkname, (size_t) NAMSIZ);
692 header.dbuf.typeflag = '1';
693 if (verbose_flag) string_print(NIL_PTR, "linked %s to %s\n",
694 header.dbuf.linkname, file);
695 string_print(header.member.m_checksum, "%I ", checksum());
696 mwrite(tar_fd, (char *) &header, sizeof(header));
697 } else {
698 is_added(&st, file);
699 switch (st.st_mode & S_IFMT) {
700 case S_IFREG:
701 header.dbuf.typeflag = '0';
702 string_print(header.member.m_checksum, "%I ", checksum());
703 mwrite(tar_fd, (char *) &header, sizeof(header));
704 copy(path_name(file), fd, tar_fd, (long) st.st_size);
705 break;
706 case S_IFDIR:
707 header.dbuf.typeflag = '5';
708 string_print(header.member.m_checksum, "%I ", checksum());
709 mwrite(tar_fd, (char *) &header, sizeof(header));
710 verb_print("read directory", file);
711 if (norec_flag) break;
712 if (NULL == getcwd(cwd, (int) sizeof cwd))
713 string_print(NIL_PTR, "Error: cannot getcwd()\n");
714 else if (chdir(file) < 0)
715 string_print(NIL_PTR, "Cannot chdir to %s: %s\n",
716 file, strerror(errno));
717 else {
718 add_path(file);
719#ifdef DIRECT_3
720 {
721 DIR *dirp;
722 struct direct *dp;
723 struct stat dst;
724
725 add_close(fd);
726 fd= 0;
727 dirp = opendir(".");
728 while (NULL != (dp = readdir(dirp)))
729 if (strcmp(dp->d_name, ".") == 0)
730 is_linked(&st);
731 else if (strcmp(dp->d_name, "..") == 0) {
732 if (stat("..", &dst) == 0)
733 is_linked(&dst);
734 } else {
735 strcpy(namebuf, dp->d_name);
736 add_file(namebuf);
737 }
738 closedir(dirp);
739 }
740#else
741 {
742 int i;
743 struct direct dir;
744 struct stat dst;
745
746 for (i = 0; i < 2; i++) { /* . and .. */
747 mread(fd, &dir, sizeof(dir));
748 if (strcmp(dir.d_name, ".") == 0)
749 is_linked(&st);
750 else if (strcmp(dir.d_name, "..") == 0) {
751 if (stat("..", &dst) == 0)
752 is_linked(&dst);
753 } else
754 break;
755 }
756 while (bread(fd, &dir, sizeof(dir)) == sizeof(dir))
757 if (dir.d_ino) {
758 strncpy(namebuf, dir.d_name,
759 (size_t) DIRSIZ);
760 namebuf[DIRSIZ] = '\0';
761 add_file(namebuf);
762 }
763 }
764#endif
765 chdir(cwd);
766 add_path(NIL_PTR);
767 *file = 0;
768 }
769 break;
770#ifdef HAVE_SYMLINK
771 case S_IFLNK:
772 {
773 int i;
774
775 header.dbuf.typeflag = '2';
776 verb_print("read symlink", file);
777 i = readlink(file,
778 header.dbuf.linkname,
779 sizeof(header.dbuf.linkname) - 1);
780 if (i < 0) {
781 string_print(NIL_PTR,
782 "Cannot read symbolic link %s: %s\n",
783 file, strerror(errno));
784 return;
785 }
786 header.dbuf.linkname[i] = 0;
787 string_print(header.member.m_checksum, "%I ", checksum());
788 mwrite(tar_fd, (char *) &header, sizeof(header));
789 break;
790 }
791#endif
792#ifdef HAVE_FIFO
793 case S_IFIFO:
794 header.dbuf.typeflag = '6';
795 verb_print("read fifo", file);
796 string_print(header.member.m_checksum, "%I ", checksum());
797 mwrite(tar_fd, (char *) &header, sizeof(header));
798 break;
799#endif
800 case S_IFBLK:
801 header.dbuf.typeflag = '4';
802 if (verbose_flag) {
803 char sizebuf[TSIZLEN + 1];
804
805 strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
806 sizebuf[TSIZLEN] = 0;
807 string_print(NIL_PTR,
808 "read block device %s major %s minor %s\n",
809 file, header.dbuf.devmajor, header.dbuf.devminor, sizebuf);
810 }
811 string_print(header.member.m_checksum, "%I ", checksum());
812 mwrite(tar_fd, (char *) &header, sizeof(header));
813 break;
814 case S_IFCHR:
815 header.dbuf.typeflag = '3';
816 if (verbose_flag) string_print(NIL_PTR,
817 "read character device %s major %s minor %s\n",
818 file, header.dbuf.devmajor, header.dbuf.devminor);
819 string_print(header.member.m_checksum, "%I ", checksum());
820 mwrite(tar_fd, (char *) &header, sizeof(header));
821 break;
822 default:
823 is_deleted(&st);
824 string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
825 *file = 0;
826 }
827 }
828
829 flush();
830 add_close(fd);
831}
832
833void verb_print(s1, s2)
834char *s1, *s2;
835{
836 if (verbose_flag) string_print(NIL_PTR, "%s: %s\n", s1, s2);
837}
838
839void add_close(fd)
840int fd;
841{
842 if (fd != 0) close(fd);
843}
844
845/*
846 * open file 'file' to be added to archive, return file descriptor
847*/
848int add_open(file, st)
849char *file;
850struct stat *st;
851{
852 int fd;
853 if (((st->st_mode & S_IFMT) != S_IFREG) &&
854 ((st->st_mode & S_IFMT) != S_IFDIR))
855 return 0;
856 fd = open(file, O_RDONLY);
857 if (fd == -1)
858 fprintf(stderr, "open failed: %s\n", strerror(errno));
859 return fd;
860}
861
862void make_header(file, st)
863char *file;
864register struct stat *st;
865{
866 register char *ptr = header.member.m_name;
867 struct passwd *pwd;
868 struct group *grp;
869
870 clear_header();
871
872 while (*ptr++ = *file++);
873
874 if ((st->st_mode & S_IFMT) == S_IFDIR) { /* fixed test -Dal */
875 *(ptr - 1) = '/';
876 }
877 string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
878 string_print(header.member.m_uid, "%I ", st->st_uid);
879 string_print(header.member.m_gid, "%I ", st->st_gid);
880 if ((st->st_mode & S_IFMT) == S_IFREG)
881 string_print(header.member.m_size, "%L ", st->st_size);
882 else
883 strncpy(header.dbuf.size, "0", (size_t) TSIZLEN);
884 string_print(header.member.m_time, "%L ", st->st_mtime);
885 strncpy(header.dbuf.magic, TMAGIC, (size_t) TMAGLEN);
886 header.dbuf.version[0] = 0;
887 header.dbuf.version[1] = 0;
888 pwd = getpwuid(st->st_uid);
889 strncpy(header.dbuf.uname,
890 (pwd != NULL ? pwd->pw_name : "nobody"), TUNMLEN);
891 grp = getgrgid(st->st_gid);
892 strncpy(header.dbuf.gname,
893 (grp != NULL ? grp->gr_name : "nobody"), TGNMLEN);
894 if (st->st_mode & (S_IFBLK | S_IFCHR)) {
895 string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
896 string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
897 }
898 header.dbuf.prefix[0] = 0;
899}
900
901void is_added(st, file)
902struct stat *st;
903char *file;
904{
905 struct link *new;
906 char *name;
907
908 if ((*file == 0) || (st->st_nlink == 1)) return;
909 name = path_name(file);
910 new = (struct link *) malloc(sizeof(struct link) + strlen(name));
911 if (new == NULL) {
912 print("Out of memory\n");
913 return;
914 }
915 new->next = link_top;
916 new->dev = st->st_dev;
917 new->ino = st->st_ino;
918 new->nlink = st->st_nlink - 1;
919 strcpy(new->name, name);
920 link_top = new;
921}
922
923void is_deleted(st)
924struct stat *st;
925{
926 struct link *old;
927
928 if ((old = link_top) != NULL) {
929 link_top = old->next;
930 free(old);
931 }
932}
933
934char *is_linked(st)
935struct stat *st;
936{
937 struct link *cur = link_top;
938 struct link **pre = &link_top;
939 static char name[NAMSIZ];
940
941 while (cur != NULL)
942 if ((cur->dev != st->st_dev) || (cur->ino != st->st_ino)) {
943 pre = &cur->next;
944 cur = cur->next;
945 } else {
946 if (--cur->nlink == 0) {
947 *pre = cur->next;
948 strncpy(name, cur->name, NAMSIZ);
949 return name;
950 }
951 return cur->name;
952 }
953 return NULL;
954}
955
956void clear_header()
957{
958 register char *ptr = header.hdr_block;
959
960 while (ptr < &header.hdr_block[TBLOCK_SIZE]) *ptr++ = '\0';
961}
962
963void adjust_boundary()
964{
965 clear_header();
966 mwrite(tar_fd, (char *) &header, sizeof(header));
967#ifndef POSIX_COMP
968 while (total_blocks++ < BLOCK_BOUNDARY)
969 mwrite(tar_fd, (char *) &header, sizeof(header));
970#else
971 mwrite(tar_fd, (char *) &header, sizeof(header));
972#endif
973 (void) close(tar_fd);
974}
975
976void mread(fd, address, bytes)
977int fd, bytes;
978char *address;
979{
980 if (bread(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR);
981}
982
983void mwrite(fd, address, bytes)
984int fd, bytes;
985char *address;
986{
987 if (bwrite(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR);
988
989 total_blocks++;
990}
991
992int bread(fd, address, bytes)
993int fd, bytes;
994char *address;
995{
996 int n = 0, r;
997
998 while (n < bytes) {
999 if ((r = read(fd, address + n, bytes - n)) <= 0) {
1000 if (r < 0) return r;
1001 break;
1002 }
1003 n += r;
1004 }
1005 return n;
1006}
1007
1008int bwrite(fd, address, bytes)
1009int fd, bytes;
1010char *address;
1011{
1012 int n = 0, r;
1013
1014 while (n < bytes) {
1015 if ((r = write(fd, address + n, bytes - n)) <= 0) {
1016 if (r < 0) return r;
1017 break;
1018 }
1019 n += r;
1020 }
1021 return n;
1022}
1023
1024char output[TBLOCK_SIZE];
1025void print(str)
1026register char *str;
1027{
1028 int fd = (tar_fd == 1 ? 2 : 1);
1029 static int indx = 0;
1030
1031 if (str == NIL_PTR) {
1032 write(fd, output, indx);
1033 indx = 0;
1034 return;
1035 }
1036 while (*str) {
1037 output[indx++] = *str++;
1038 if (indx == TBLOCK_SIZE) {
1039 write(fd, output, TBLOCK_SIZE);
1040 indx = 0;
1041 }
1042 }
1043}
1044
1045char *num_out(number)
1046register long number;
1047{
1048 static char num_buf[12];
1049 register int i;
1050
1051 for (i = 11; i--;) {
1052 num_buf[i] = (number & 07) + '0';
1053 number >>= 3;
1054 }
1055
1056 return num_buf;
1057}
1058
1059/*VARARGS2*/
1060#if __STDC__
1061void string_print(char *buffer, char *fmt,...)
1062#else
1063void string_print(buffer, fmt)
1064char *buffer;
1065char *fmt;
1066#endif
1067{
1068 va_list args;
1069 register char *buf_ptr;
1070 char *scan_ptr;
1071 char buf[STRING_SIZE];
1072 BOOL pr_fl, i;
1073
1074 if (pr_fl = (buffer == NIL_PTR)) buffer = buf;
1075
1076 va_start(args, fmt);
1077 buf_ptr = buffer;
1078 while (*fmt) {
1079 if (*fmt == '%') {
1080 fmt++;
1081 switch (*fmt++) {
1082 case 's':
1083 scan_ptr = (char *) (va_arg(args, char *));
1084 break;
1085 case 'I':
1086 scan_ptr = num_out((long) (va_arg(args, int)));
1087 for (i = 0; i < 5; i++) scan_ptr++;
1088 break;
1089 case 'L':
1090 scan_ptr = num_out((long) va_arg(args, long));
1091 break;
1092 case 'd':
1093 scan_ptr = num_out((long) va_arg(args, int));
1094 while (*scan_ptr == '0') scan_ptr++;
1095 scan_ptr--;
1096 break;
1097 default: scan_ptr = "";
1098 }
1099 while (*buf_ptr++ = *scan_ptr++);
1100 buf_ptr--;
1101 } else
1102 *buf_ptr++ = *fmt++;
1103 }
1104 *buf_ptr = '\0';
1105
1106 if (pr_fl) print(buffer);
1107 va_end(args);
1108}
Note: See TracBrowser for help on using the repository browser.