00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #include <sys/types.h>
00063 #include <sys/stat.h>
00064 #include <fcntl.h>
00065 #include <pwd.h>
00066 #include <grp.h>
00067 #include <tar.h>
00068 #include <stdarg.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include <unistd.h>
00072 #include <utime.h>
00073 #include <sys/wait.h>
00074 #include <stdio.h>
00075 #include <errno.h>
00076
00077 #define POSIX_COMP
00078 #define DIRECT_3
00079
00080 #ifdef DIRECT_3
00081 #ifndef BSD
00082
00083
00084 #include <dirent.h>
00085 #define direct dirent
00086 #else
00087 #include <sys/dir.h>
00088 #include <dir.h>
00089 #endif
00090 #endif
00091
00092 #ifdef S_IFIFO
00093 #define HAVE_FIFO
00094 #endif
00095 #ifdef S_IFLNK
00096 #define HAVE_SYMLINK
00097 #endif
00098
00099 typedef char BOOL;
00100 #define TRUE 1
00101 #define FALSE 0
00102
00103 #define STRING_SIZE 256
00104 #define HEADER_SIZE TBLOCK
00105 #define NAME_SIZE NAMSIZ
00106
00107
00108 typedef union hblock HEADER;
00109
00110
00111 #define m_name name
00112 #define m_mode mode
00113 #define m_uid uid
00114 #define m_gid gid
00115 #define m_size size
00116 #define m_time mtime
00117 #define m_checksum chksum
00118 #define m_linked typeflag
00119 #define m_link linkname
00120 #define hdr_block dummy
00121 #define m header
00122 #define member dbuf
00123
00124 #if 0
00125
00126 typedef union {
00127 char hdr_block[HEADER_SIZE];
00128 struct m {
00129 char m_name[NAME_SIZE];
00130 char m_mode[8];
00131 char m_uid[8];
00132 char m_gid[8];
00133 char m_size[12];
00134 char m_time[12];
00135 char m_checksum[8];
00136 char m_linked;
00137 char m_link[NAME_SIZE];
00138 } member;
00139 } HEADER;
00140
00141 #endif
00142
00143
00144 struct link {
00145 ino_t ino;
00146 dev_t dev;
00147 nlink_t nlink;
00148 struct link *next;
00149 char name[1];
00150 } *link_top = NULL;
00151
00152 HEADER header;
00153
00154 #define INT_TYPE (sizeof(header.member.m_uid))
00155 #define LONG_TYPE (sizeof(header.member.m_size))
00156
00157 #define NIL_HEADER ((HEADER *) 0)
00158 #define NIL_PTR ((char *) 0)
00159 #define TBLOCK_SIZE TBLOCK
00160
00161 #define flush() print(NIL_PTR)
00162
00163 BOOL show_fl, creat_fl, ext_fl;
00164
00165 int tar_fd;
00166
00167 char usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
00168 char io_buffer[TBLOCK_SIZE];
00169 char path[NAME_SIZE];
00170 char pathname[NAME_SIZE];
00171 int force_flag = 0;
00172 #ifdef ORIGINAL_DEFAULTS
00173 int chown_flag = 1;
00174 int verbose_flag = 1;
00175 #else
00176 int chown_flag = 0;
00177 int verbose_flag = 0;
00178 #endif
00179 int norec_flag = 0;
00180
00181
00182 ino_t ar_inode;
00183 dev_t ar_dev;
00184
00185 int total_blocks;
00186 int u_mask;
00187
00188 #define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \
00189 + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE)
00190
00191 _PROTOTYPE(int main, (int argc, char **argv));
00192 _PROTOTYPE(void error, (char *s1, char *s2));
00193 _PROTOTYPE(BOOL get_header, (void));
00194 _PROTOTYPE(void tarfile, (void));
00195 _PROTOTYPE(void skip_entry, (void));
00196 _PROTOTYPE(void extract, (char *file));
00197 _PROTOTYPE(void delete, (char *file));
00198 _PROTOTYPE(void do_chown, (char *file));
00199 _PROTOTYPE(void timestamp, (char *file));
00200 _PROTOTYPE(void copy, (char *file, int from, int to, long bytes));
00201 _PROTOTYPE(long convert, (char str[], int type));
00202 _PROTOTYPE(int checksum, (void));
00203 _PROTOTYPE(int is_dir, (char *file));
00204 _PROTOTYPE(char *path_name, (char *file));
00205 _PROTOTYPE(void add_path, (char *name));
00206 _PROTOTYPE(void add_file, (char *file));
00207 _PROTOTYPE(void verb_print, (char *s1, char *s2));
00208 _PROTOTYPE(void add_close, (int fd));
00209 _PROTOTYPE(int add_open, (char *file, struct stat * st));
00210 _PROTOTYPE(void make_header, (char *file, struct stat * st));
00211 _PROTOTYPE(void is_added, (struct stat * st, char *file));
00212 _PROTOTYPE(void is_deleted, (struct stat * st));
00213 _PROTOTYPE(char *is_linked, (struct stat * st));
00214 _PROTOTYPE(void clear_header, (void));
00215 _PROTOTYPE(void adjust_boundary, (void));
00216 _PROTOTYPE(void mread, (int fd, char *address, int bytes));
00217 _PROTOTYPE(void mwrite, (int fd, char *address, int bytes));
00218 _PROTOTYPE(int bread, (int fd, char *address, int bytes));
00219 _PROTOTYPE(int bwrite, (int fd, char *address, int bytes));
00220 _PROTOTYPE(void print, (char *str));
00221 _PROTOTYPE(char *num_out, (long number));
00222 _PROTOTYPE(void string_print, (char *buffer, char *fmt,...));
00223
00224 void error(s1, s2)
00225 char *s1, *s2;
00226 {
00227 string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
00228 flush();
00229 exit(1);
00230 }
00231
00232 int main(argc, argv)
00233 int argc;
00234 register char *argv[];
00235 {
00236 register char *mem_name;
00237 register char *ptr;
00238 struct stat st;
00239 int i;
00240
00241 if (argc < 3) error(usage, NIL_PTR);
00242
00243 for (ptr = argv[1]; *ptr; ptr++) {
00244
00245 if(*ptr == '-' && ptr == argv[1]) continue;
00246 switch (*ptr) {
00247 case 'c': creat_fl = TRUE; break;
00248 case 'x': ext_fl = TRUE; break;
00249 case 't': show_fl = TRUE; break;
00250 case 'v':
00251 verbose_flag = !verbose_flag;
00252 break;
00253 case 'o':
00254 chown_flag = TRUE;
00255 break;
00256 case 'F':
00257 force_flag = TRUE;
00258 break;
00259 case 'f':
00260 break;
00261 case 'p':
00262 (void) umask(0);
00263 break;
00264 case 'D':
00265 norec_flag = TRUE;
00266 break;
00267 default: error(usage, NIL_PTR);
00268 }
00269 }
00270
00271 if (creat_fl + ext_fl + show_fl != 1) error(usage, NIL_PTR);
00272
00273 if (strcmp(argv[2], "-") == 0)
00274 tar_fd = creat_fl ? 1 : 0;
00275
00276 else
00277 tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], O_RDONLY);
00278
00279 if (tar_fd < 0) error("Cannot open ", argv[2]);
00280
00281 if (geteuid()) {
00282 int save_umask;
00283 save_umask = umask(0);
00284 u_mask = ~save_umask;
00285 umask(save_umask);
00286 chown_flag = TRUE;
00287 } else
00288 u_mask = ~0;
00289
00290 ar_dev = -1;
00291 if (creat_fl) {
00292 if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
00293 error("Can't stat ", argv[2]);
00294
00295 else {
00296 ar_inode = st.st_ino;
00297 ar_dev = st.st_dev;
00298 }
00299
00300 for (i = 3; i < argc; i++) {
00301 add_file(argv[i]);
00302 path[0] = '\0';
00303 }
00304 adjust_boundary();
00305 } else if (ext_fl) {
00306
00307 while (get_header()) {
00308 mem_name = header.member.m_name;
00309 if (is_dir(mem_name)) {
00310 for (ptr = mem_name; *ptr; ptr++);
00311 *(ptr - 1) = '\0';
00312 header.dbuf.typeflag = '5';
00313 }
00314 for (i = 3; i < argc; i++)
00315 if (!strncmp(argv[i], mem_name, strlen(argv[i])))
00316 break;
00317 if (argc == 3 || (i < argc)) {
00318 extract(mem_name);
00319 } else if (header.dbuf.typeflag == '0' ||
00320 header.dbuf.typeflag == 0 ||
00321 header.dbuf.typeflag == ' ')
00322 skip_entry();
00323 flush();
00324 }
00325 } else
00326 tarfile();
00327
00328 flush();
00329 return(0);
00330 }
00331
00332 BOOL get_header()
00333 {
00334 register int check;
00335
00336 mread(tar_fd, (char *) &header, sizeof(header));
00337 if (header.member.m_name[0] == '\0') return FALSE;
00338
00339 if (force_flag)
00340 return TRUE;
00341
00342 check = (int) convert(header.member.m_checksum, INT_TYPE);
00343
00344 if (check != checksum()) error("Tar: header checksum error.", NIL_PTR);
00345
00346 return TRUE;
00347 }
00348
00349
00350
00351
00352 void tarfile()
00353 {
00354 register char *mem_name;
00355
00356 while (get_header()) {
00357 mem_name = header.member.m_name;
00358 string_print(NIL_PTR, "%s%s", mem_name,
00359 (verbose_flag ? " " : "\n"));
00360 switch (header.dbuf.typeflag) {
00361 case '1':
00362 verb_print("linked to", header.dbuf.linkname);
00363 break;
00364 case '2':
00365 verb_print("symbolic link to", header.dbuf.linkname);
00366 break;
00367 case '6': verb_print("", "fifo"); break;
00368 case '3':
00369 case '4':
00370 if (verbose_flag) {
00371 char sizebuf[TSIZLEN + 1];
00372
00373 strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
00374 sizebuf[TSIZLEN] = 0;
00375 string_print(NIL_PTR,
00376 "%s special file major %s minor %s\n",
00377 (header.dbuf.typeflag == '3' ?
00378 "character" : "block"),
00379 header.dbuf.devmajor,
00380 header.dbuf.devminor,
00381 sizebuf);
00382 }
00383 break;
00384 case '0':
00385 case 0:
00386 case ' ':
00387 if (!is_dir(mem_name)) {
00388 if (verbose_flag)
00389 string_print(NIL_PTR, "%d tape blocks\n",
00390 block_size());
00391 skip_entry();
00392 break;
00393 } else
00394 case '5':
00395 verb_print("", "directory");
00396 break;
00397 default:
00398 string_print(NIL_PTR, "not recogised item %d\n",
00399 header.dbuf.typeflag);
00400 }
00401 flush();
00402 }
00403 }
00404
00405 void skip_entry()
00406 {
00407 register int blocks = block_size();
00408
00409 while (blocks--) (void) bread(tar_fd, io_buffer, TBLOCK_SIZE);
00410 }
00411
00412 void extract(file)
00413 register char *file;
00414 {
00415 register int fd, r;
00416 char *pd1, *pd2;
00417
00418 switch (header.dbuf.typeflag) {
00419 case '1':
00420 delete(file);
00421 if (link(header.member.m_link, file) < 0)
00422 string_print(NIL_PTR, "Cannot link %s to %s: %s\n",
00423 header.member.m_link, file, strerror(errno));
00424 else if (verbose_flag)
00425 string_print(NIL_PTR, "Linked %s to %s\n",
00426 header.member.m_link, file);
00427 return;
00428 case '5':
00429 if (!(file[0] == '.' && file[1] == '\0')) delete(file);
00430 if ((file[0] == '.' && file[1] == '\0') || mkdir(file, 0700) == 0) {
00431 do_chown(file);
00432 verb_print("created directory", file);
00433 } else {
00434 string_print(NIL_PTR, "Can't make directory %s: %s\n",
00435 file, strerror(errno));
00436 }
00437 return;
00438 case '3':
00439 case '4':
00440 {
00441 int dmajor, dminor, mode;
00442
00443 dmajor = (int) convert(header.dbuf.devmajor, INT_TYPE);
00444 dminor = (int) convert(header.dbuf.devminor, INT_TYPE);
00445 mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);
00446 delete(file);
00447 if (mknod(file, mode, (dmajor << 8 | dminor)) == 0) {
00448 if (verbose_flag) string_print(NIL_PTR,
00449 "made %s special file major %s minor %s\n",
00450 (header.dbuf.typeflag == '3' ?
00451 "character" : "block"),
00452 header.dbuf.devmajor,
00453 header.dbuf.devminor);
00454 do_chown(file);
00455 }
00456 else
00457 {
00458 string_print(NIL_PTR,
00459 "cannot make %s special file major %s minor %s: %s\n",
00460 (header.dbuf.typeflag == '3' ?
00461 "character" : "block"),
00462 header.dbuf.devmajor,
00463 header.dbuf.devminor,
00464 strerror(errno));
00465 }
00466 return;
00467 }
00468 case '2':
00469 #ifdef HAVE_SYMLINK
00470 delete(file);
00471 if (symlink(header.member.m_link, file) < 0)
00472 string_print(NIL_PTR, "Cannot make symbolic link %s to %s: %s\n",
00473 header.member.m_link, file, strerror(errno));
00474 else if (verbose_flag)
00475 string_print(NIL_PTR, "Symbolic link %s to %s\n",
00476 header.member.m_link, file);
00477 return;
00478 #endif
00479 case '7':
00480 print("Not implemented file type\n");
00481 return;
00482 #ifdef HAVE_FIFO
00483 case '6':
00484 delete(file);
00485 if (mkfifo(file, 0) == 0) {
00486 do_chown(file);
00487 verb_print("made fifo", file);
00488 } else
00489 string_print(NIL_PTR, "Can't make fifo %s: %s\n",
00490 file, strerror(errno));
00491 return;
00492 #endif
00493 }
00494
00495
00496 if ((fd = creat(file, 0600)) < 0) {
00497 pd1 = file;
00498 while ((pd2 = index(pd1, '/')) > (char *) 0) {
00499 *pd2 = '\0';
00500 if (access(file, 1) < 0)
00501 if (mkdir(file, 0777) < 0) {
00502 string_print(NIL_PTR, "Cannot mkdir %s: %s\n",
00503 file, strerror(errno));
00504 return;
00505 } else
00506 string_print(NIL_PTR, "Made directory %s\n", file);
00507 *pd2 = '/';
00508 pd1 = ++pd2;
00509 }
00510 if ((fd = creat(file, 0600)) < 0) {
00511 string_print(NIL_PTR, "Cannot create %s: %s\n",
00512 file, strerror(errno));
00513 return;
00514 }
00515 }
00516 copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));
00517 (void) close(fd);
00518
00519 do_chown(file);
00520 }
00521
00522 void delete(file)
00523 char *file;
00524 {
00525
00526 struct stat stbuf;
00527
00528 if (stat(file, &stbuf) < 0) return;
00529
00530 if (S_ISDIR(stbuf.st_mode)) (void) rmdir(file); else (void) unlink(file);
00531
00532 }
00533
00534 void do_chown(file)
00535 char *file;
00536 {
00537 int uid = -1, gid = -1;
00538
00539 if (!chown_flag) {
00540 if (header.dbuf.magic[TMAGLEN] == ' ')
00541 header.dbuf.magic[TMAGLEN] = '\0';
00542
00543 if (strncmp(TMAGIC, header.dbuf.magic, (size_t) TMAGLEN)) {
00544 struct passwd *pwd;
00545 struct group *grp;
00546
00547 pwd = getpwnam(header.dbuf.uname);
00548 if (pwd != NULL) uid = pwd->pw_uid;
00549 grp = getgrnam(header.dbuf.gname);
00550 if (grp != NULL) gid = grp->gr_gid;
00551 }
00552 if (uid == -1) uid = (int) convert(header.member.m_uid, INT_TYPE);
00553 if (gid == -1) gid = (int) convert(header.member.m_gid, INT_TYPE);
00554 chown(file, uid, gid);
00555 }
00556 chmod(file, u_mask & (int) convert(header.member.m_mode, INT_TYPE));
00557
00558
00559 timestamp(file);
00560
00561 }
00562
00563 void timestamp(file)
00564 char *file;
00565 {
00566 struct utimbuf buf;
00567
00568 buf.modtime = buf.actime = convert(header.dbuf.mtime, LONG_TYPE);
00569 utime(file, &buf);
00570 }
00571
00572 void copy(file, from, to, bytes)
00573 char *file;
00574 int from, to;
00575 register long bytes;
00576 {
00577 register int rest;
00578 int blocks = (int) ((bytes + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE);
00579
00580 if (verbose_flag)
00581 string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
00582
00583 while (blocks--) {
00584 (void) bread(from, io_buffer, TBLOCK_SIZE);
00585 rest = (bytes > (long) TBLOCK_SIZE) ? TBLOCK_SIZE : (int) bytes;
00586 mwrite(to, io_buffer, (to == tar_fd) ? TBLOCK_SIZE : rest);
00587 bytes -= (long) rest;
00588 }
00589 }
00590
00591 long convert(str, type)
00592 char str[];
00593 int type;
00594 {
00595 register long ac = 0L;
00596 register int i;
00597
00598 for (i = 0; i < type; i++) {
00599 if (str[i] >= '0' && str[i] <= '7') {
00600 ac <<= 3;
00601 ac += (long) (str[i] - '0');
00602 }
00603 }
00604
00605 return ac;
00606 }
00607
00608 int checksum()
00609 {
00610 register char *ptr = header.member.m_checksum;
00611 register int ac = 0;
00612
00613 while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' ';
00614
00615 ptr = header.hdr_block;
00616 while (ptr < &header.hdr_block[TBLOCK_SIZE]) ac += *ptr++;
00617
00618 return ac;
00619 }
00620
00621 int is_dir(file)
00622 register char *file;
00623 {
00624 while (*file++ != '\0');
00625
00626 return(*(file - 2) == '/');
00627 }
00628
00629
00630 char *path_name(file)
00631 register char *file;
00632 {
00633
00634 string_print(pathname, "%s%s", path, file);
00635 return pathname;
00636 }
00637
00638 void add_path(name)
00639 register char *name;
00640 {
00641 register char *path_ptr = path;
00642
00643 while (*path_ptr) path_ptr++;
00644
00645 if (name == NIL_PTR) {
00646 while (*path_ptr-- != '/');
00647 while (*path_ptr != '/' && path_ptr != path) path_ptr--;
00648 if (*path_ptr == '/') path_ptr++;
00649 *path_ptr = '\0';
00650 } else {
00651 while (*name) {
00652 if (path_ptr == &path[NAME_SIZE])
00653 error("Pathname too long", NIL_PTR);
00654 *path_ptr++ = *name++;
00655 }
00656 *path_ptr++ = '/';
00657 *path_ptr = '\0';
00658 }
00659 }
00660
00661
00662
00663
00664 void add_file(file)
00665 register char *file;
00666 {
00667 struct stat st;
00668 char *linkname;
00669 register int fd = -1;
00670 char namebuf[16];
00671 char cwd[129];
00672
00673 #ifdef HAVE_SYMLINK
00674 if (lstat(file, &st) < 0) {
00675 #else
00676 if (stat(file, &st) < 0) {
00677 #endif
00678 string_print(NIL_PTR, "%s: %s\n", file, strerror(errno));
00679 return;
00680 }
00681 if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
00682 string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
00683 return;
00684 }
00685 if ((fd = add_open(file, &st)) < 0) {
00686 string_print(NIL_PTR, "Cannot open %s\n", file);
00687 return;
00688 }
00689 make_header(path_name(file), &st);
00690 if ((linkname = is_linked(&st)) != NULL) {
00691 strncpy(header.dbuf.linkname, linkname, (size_t) NAMSIZ);
00692 header.dbuf.typeflag = '1';
00693 if (verbose_flag) string_print(NIL_PTR, "linked %s to %s\n",
00694 header.dbuf.linkname, file);
00695 string_print(header.member.m_checksum, "%I ", checksum());
00696 mwrite(tar_fd, (char *) &header, sizeof(header));
00697 } else {
00698 is_added(&st, file);
00699 switch (st.st_mode & S_IFMT) {
00700 case S_IFREG:
00701 header.dbuf.typeflag = '0';
00702 string_print(header.member.m_checksum, "%I ", checksum());
00703 mwrite(tar_fd, (char *) &header, sizeof(header));
00704 copy(path_name(file), fd, tar_fd, (long) st.st_size);
00705 break;
00706 case S_IFDIR:
00707 header.dbuf.typeflag = '5';
00708 string_print(header.member.m_checksum, "%I ", checksum());
00709 mwrite(tar_fd, (char *) &header, sizeof(header));
00710 verb_print("read directory", file);
00711 if (norec_flag) break;
00712 if (NULL == getcwd(cwd, (int) sizeof cwd))
00713 string_print(NIL_PTR, "Error: cannot getcwd()\n");
00714 else if (chdir(file) < 0)
00715 string_print(NIL_PTR, "Cannot chdir to %s: %s\n",
00716 file, strerror(errno));
00717 else {
00718 add_path(file);
00719 #ifdef DIRECT_3
00720 {
00721 DIR *dirp;
00722 struct direct *dp;
00723 struct stat dst;
00724
00725 add_close(fd);
00726 fd= 0;
00727 dirp = opendir(".");
00728 while (NULL != (dp = readdir(dirp)))
00729 if (strcmp(dp->d_name, ".") == 0)
00730 is_linked(&st);
00731 else if (strcmp(dp->d_name, "..") == 0) {
00732 if (stat("..", &dst) == 0)
00733 is_linked(&dst);
00734 } else {
00735 strcpy(namebuf, dp->d_name);
00736 add_file(namebuf);
00737 }
00738 closedir(dirp);
00739 }
00740 #else
00741 {
00742 int i;
00743 struct direct dir;
00744 struct stat dst;
00745
00746 for (i = 0; i < 2; i++) {
00747 mread(fd, &dir, sizeof(dir));
00748 if (strcmp(dir.d_name, ".") == 0)
00749 is_linked(&st);
00750 else if (strcmp(dir.d_name, "..") == 0) {
00751 if (stat("..", &dst) == 0)
00752 is_linked(&dst);
00753 } else
00754 break;
00755 }
00756 while (bread(fd, &dir, sizeof(dir)) == sizeof(dir))
00757 if (dir.d_ino) {
00758 strncpy(namebuf, dir.d_name,
00759 (size_t) DIRSIZ);
00760 namebuf[DIRSIZ] = '\0';
00761 add_file(namebuf);
00762 }
00763 }
00764 #endif
00765 chdir(cwd);
00766 add_path(NIL_PTR);
00767 *file = 0;
00768 }
00769 break;
00770 #ifdef HAVE_SYMLINK
00771 case S_IFLNK:
00772 {
00773 int i;
00774
00775 header.dbuf.typeflag = '2';
00776 verb_print("read symlink", file);
00777 i = readlink(file,
00778 header.dbuf.linkname,
00779 sizeof(header.dbuf.linkname) - 1);
00780 if (i < 0) {
00781 string_print(NIL_PTR,
00782 "Cannot read symbolic link %s: %s\n",
00783 file, strerror(errno));
00784 return;
00785 }
00786 header.dbuf.linkname[i] = 0;
00787 string_print(header.member.m_checksum, "%I ", checksum());
00788 mwrite(tar_fd, (char *) &header, sizeof(header));
00789 break;
00790 }
00791 #endif
00792 #ifdef HAVE_FIFO
00793 case S_IFIFO:
00794 header.dbuf.typeflag = '6';
00795 verb_print("read fifo", file);
00796 string_print(header.member.m_checksum, "%I ", checksum());
00797 mwrite(tar_fd, (char *) &header, sizeof(header));
00798 break;
00799 #endif
00800 case S_IFBLK:
00801 header.dbuf.typeflag = '4';
00802 if (verbose_flag) {
00803 char sizebuf[TSIZLEN + 1];
00804
00805 strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
00806 sizebuf[TSIZLEN] = 0;
00807 string_print(NIL_PTR,
00808 "read block device %s major %s minor %s\n",
00809 file, header.dbuf.devmajor, header.dbuf.devminor, sizebuf);
00810 }
00811 string_print(header.member.m_checksum, "%I ", checksum());
00812 mwrite(tar_fd, (char *) &header, sizeof(header));
00813 break;
00814 case S_IFCHR:
00815 header.dbuf.typeflag = '3';
00816 if (verbose_flag) string_print(NIL_PTR,
00817 "read character device %s major %s minor %s\n",
00818 file, header.dbuf.devmajor, header.dbuf.devminor);
00819 string_print(header.member.m_checksum, "%I ", checksum());
00820 mwrite(tar_fd, (char *) &header, sizeof(header));
00821 break;
00822 default:
00823 is_deleted(&st);
00824 string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
00825 *file = 0;
00826 }
00827 }
00828
00829 flush();
00830 add_close(fd);
00831 }
00832
00833 void verb_print(s1, s2)
00834 char *s1, *s2;
00835 {
00836 if (verbose_flag) string_print(NIL_PTR, "%s: %s\n", s1, s2);
00837 }
00838
00839 void add_close(fd)
00840 int fd;
00841 {
00842 if (fd != 0) close(fd);
00843 }
00844
00845
00846
00847
00848 int add_open(file, st)
00849 char *file;
00850 struct stat *st;
00851 {
00852 int fd;
00853 if (((st->st_mode & S_IFMT) != S_IFREG) &&
00854 ((st->st_mode & S_IFMT) != S_IFDIR))
00855 return 0;
00856 fd = open(file, O_RDONLY);
00857 if (fd == -1)
00858 fprintf(stderr, "open failed: %s\n", strerror(errno));
00859 return fd;
00860 }
00861
00862 void make_header(file, st)
00863 char *file;
00864 register struct stat *st;
00865 {
00866 register char *ptr = header.member.m_name;
00867 struct passwd *pwd;
00868 struct group *grp;
00869
00870 clear_header();
00871
00872 while (*ptr++ = *file++);
00873
00874 if ((st->st_mode & S_IFMT) == S_IFDIR) {
00875 *(ptr - 1) = '/';
00876 }
00877 string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
00878 string_print(header.member.m_uid, "%I ", st->st_uid);
00879 string_print(header.member.m_gid, "%I ", st->st_gid);
00880 if ((st->st_mode & S_IFMT) == S_IFREG)
00881 string_print(header.member.m_size, "%L ", st->st_size);
00882 else
00883 strncpy(header.dbuf.size, "0", (size_t) TSIZLEN);
00884 string_print(header.member.m_time, "%L ", st->st_mtime);
00885 strncpy(header.dbuf.magic, TMAGIC, (size_t) TMAGLEN);
00886 header.dbuf.version[0] = 0;
00887 header.dbuf.version[1] = 0;
00888 pwd = getpwuid(st->st_uid);
00889 strncpy(header.dbuf.uname,
00890 (pwd != NULL ? pwd->pw_name : "nobody"), TUNMLEN);
00891 grp = getgrgid(st->st_gid);
00892 strncpy(header.dbuf.gname,
00893 (grp != NULL ? grp->gr_name : "nobody"), TGNMLEN);
00894 if (st->st_mode & (S_IFBLK | S_IFCHR)) {
00895 string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
00896 string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
00897 }
00898 header.dbuf.prefix[0] = 0;
00899 }
00900
00901 void is_added(st, file)
00902 struct stat *st;
00903 char *file;
00904 {
00905 struct link *new;
00906 char *name;
00907
00908 if ((*file == 0) || (st->st_nlink == 1)) return;
00909 name = path_name(file);
00910 new = (struct link *) malloc(sizeof(struct link) + strlen(name));
00911 if (new == NULL) {
00912 print("Out of memory\n");
00913 return;
00914 }
00915 new->next = link_top;
00916 new->dev = st->st_dev;
00917 new->ino = st->st_ino;
00918 new->nlink = st->st_nlink - 1;
00919 strcpy(new->name, name);
00920 link_top = new;
00921 }
00922
00923 void is_deleted(st)
00924 struct stat *st;
00925 {
00926 struct link *old;
00927
00928 if ((old = link_top) != NULL) {
00929 link_top = old->next;
00930 free(old);
00931 }
00932 }
00933
00934 char *is_linked(st)
00935 struct stat *st;
00936 {
00937 struct link *cur = link_top;
00938 struct link **pre = &link_top;
00939 static char name[NAMSIZ];
00940
00941 while (cur != NULL)
00942 if ((cur->dev != st->st_dev) || (cur->ino != st->st_ino)) {
00943 pre = &cur->next;
00944 cur = cur->next;
00945 } else {
00946 if (--cur->nlink == 0) {
00947 *pre = cur->next;
00948 strncpy(name, cur->name, NAMSIZ);
00949 return name;
00950 }
00951 return cur->name;
00952 }
00953 return NULL;
00954 }
00955
00956 void clear_header()
00957 {
00958 register char *ptr = header.hdr_block;
00959
00960 while (ptr < &header.hdr_block[TBLOCK_SIZE]) *ptr++ = '\0';
00961 }
00962
00963 void adjust_boundary()
00964 {
00965 clear_header();
00966 mwrite(tar_fd, (char *) &header, sizeof(header));
00967 #ifndef POSIX_COMP
00968 while (total_blocks++ < BLOCK_BOUNDARY)
00969 mwrite(tar_fd, (char *) &header, sizeof(header));
00970 #else
00971 mwrite(tar_fd, (char *) &header, sizeof(header));
00972 #endif
00973 (void) close(tar_fd);
00974 }
00975
00976 void mread(fd, address, bytes)
00977 int fd, bytes;
00978 char *address;
00979 {
00980 if (bread(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR);
00981 }
00982
00983 void mwrite(fd, address, bytes)
00984 int fd, bytes;
00985 char *address;
00986 {
00987 if (bwrite(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR);
00988
00989 total_blocks++;
00990 }
00991
00992 int bread(fd, address, bytes)
00993 int fd, bytes;
00994 char *address;
00995 {
00996 int n = 0, r;
00997
00998 while (n < bytes) {
00999 if ((r = read(fd, address + n, bytes - n)) <= 0) {
01000 if (r < 0) return r;
01001 break;
01002 }
01003 n += r;
01004 }
01005 return n;
01006 }
01007
01008 int bwrite(fd, address, bytes)
01009 int fd, bytes;
01010 char *address;
01011 {
01012 int n = 0, r;
01013
01014 while (n < bytes) {
01015 if ((r = write(fd, address + n, bytes - n)) <= 0) {
01016 if (r < 0) return r;
01017 break;
01018 }
01019 n += r;
01020 }
01021 return n;
01022 }
01023
01024 char output[TBLOCK_SIZE];
01025 void print(str)
01026 register char *str;
01027 {
01028 int fd = (tar_fd == 1 ? 2 : 1);
01029 static int indx = 0;
01030
01031 if (str == NIL_PTR) {
01032 write(fd, output, indx);
01033 indx = 0;
01034 return;
01035 }
01036 while (*str) {
01037 output[indx++] = *str++;
01038 if (indx == TBLOCK_SIZE) {
01039 write(fd, output, TBLOCK_SIZE);
01040 indx = 0;
01041 }
01042 }
01043 }
01044
01045 char *num_out(number)
01046 register long number;
01047 {
01048 static char num_buf[12];
01049 register int i;
01050
01051 for (i = 11; i--;) {
01052 num_buf[i] = (number & 07) + '0';
01053 number >>= 3;
01054 }
01055
01056 return num_buf;
01057 }
01058
01059
01060 #if __STDC__
01061 void string_print(char *buffer, char *fmt,...)
01062 #else
01063 void string_print(buffer, fmt)
01064 char *buffer;
01065 char *fmt;
01066 #endif
01067 {
01068 va_list args;
01069 register char *buf_ptr;
01070 char *scan_ptr;
01071 char buf[STRING_SIZE];
01072 BOOL pr_fl, i;
01073
01074 if (pr_fl = (buffer == NIL_PTR)) buffer = buf;
01075
01076 va_start(args, fmt);
01077 buf_ptr = buffer;
01078 while (*fmt) {
01079 if (*fmt == '%') {
01080 fmt++;
01081 switch (*fmt++) {
01082 case 's':
01083 scan_ptr = (char *) (va_arg(args, char *));
01084 break;
01085 case 'I':
01086 scan_ptr = num_out((long) (va_arg(args, int)));
01087 for (i = 0; i < 5; i++) scan_ptr++;
01088 break;
01089 case 'L':
01090 scan_ptr = num_out((long) va_arg(args, long));
01091 break;
01092 case 'd':
01093 scan_ptr = num_out((long) va_arg(args, int));
01094 while (*scan_ptr == '0') scan_ptr++;
01095 scan_ptr--;
01096 break;
01097 default: scan_ptr = "";
01098 }
01099 while (*buf_ptr++ = *scan_ptr++);
01100 buf_ptr--;
01101 } else
01102 *buf_ptr++ = *fmt++;
01103 }
01104 *buf_ptr = '\0';
01105
01106 if (pr_fl) print(buffer);
01107 va_end(args);
01108 }