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 if((gid_t)gid < 0) gid = 0;
00555 chown(file, uid, gid);
00556 }
00557 chmod(file, u_mask & (int) convert(header.member.m_mode, INT_TYPE));
00558
00559
00560 timestamp(file);
00561
00562 }
00563
00564 void timestamp(file)
00565 char *file;
00566 {
00567 struct utimbuf buf;
00568
00569 buf.modtime = buf.actime = convert(header.dbuf.mtime, LONG_TYPE);
00570 utime(file, &buf);
00571 }
00572
00573 void copy(file, from, to, bytes)
00574 char *file;
00575 int from, to;
00576 register long bytes;
00577 {
00578 register int rest;
00579 int blocks = (int) ((bytes + (long) TBLOCK_SIZE - 1) / (long) TBLOCK_SIZE);
00580
00581 if (verbose_flag)
00582 string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
00583
00584 while (blocks--) {
00585 (void) bread(from, io_buffer, TBLOCK_SIZE);
00586 rest = (bytes > (long) TBLOCK_SIZE) ? TBLOCK_SIZE : (int) bytes;
00587 mwrite(to, io_buffer, (to == tar_fd) ? TBLOCK_SIZE : rest);
00588 bytes -= (long) rest;
00589 }
00590 }
00591
00592 long convert(str, type)
00593 char str[];
00594 int type;
00595 {
00596 register long ac = 0L;
00597 register int i;
00598
00599 for (i = 0; i < type; i++) {
00600 if (str[i] >= '0' && str[i] <= '7') {
00601 ac <<= 3;
00602 ac += (long) (str[i] - '0');
00603 }
00604 }
00605
00606 return ac;
00607 }
00608
00609 int checksum()
00610 {
00611 register char *ptr = header.member.m_checksum;
00612 register int ac = 0;
00613
00614 while (ptr < &header.member.m_checksum[INT_TYPE]) *ptr++ = ' ';
00615
00616 ptr = header.hdr_block;
00617 while (ptr < &header.hdr_block[TBLOCK_SIZE]) ac += *ptr++;
00618
00619 return ac;
00620 }
00621
00622 int is_dir(file)
00623 register char *file;
00624 {
00625 while (*file++ != '\0');
00626
00627 return(*(file - 2) == '/');
00628 }
00629
00630
00631 char *path_name(file)
00632 register char *file;
00633 {
00634
00635 string_print(pathname, "%s%s", path, file);
00636 return pathname;
00637 }
00638
00639 void add_path(name)
00640 register char *name;
00641 {
00642 register char *path_ptr = path;
00643
00644 while (*path_ptr) path_ptr++;
00645
00646 if (name == NIL_PTR) {
00647 while (*path_ptr-- != '/');
00648 while (*path_ptr != '/' && path_ptr != path) path_ptr--;
00649 if (*path_ptr == '/') path_ptr++;
00650 *path_ptr = '\0';
00651 } else {
00652 while (*name) {
00653 if (path_ptr == &path[NAME_SIZE])
00654 error("Pathname too long", NIL_PTR);
00655 *path_ptr++ = *name++;
00656 }
00657 *path_ptr++ = '/';
00658 *path_ptr = '\0';
00659 }
00660 }
00661
00662
00663
00664
00665 void add_file(file)
00666 register char *file;
00667 {
00668 struct stat st;
00669 char *linkname;
00670 register int fd = -1;
00671 char namebuf[16];
00672 char cwd[129];
00673
00674 #ifdef HAVE_SYMLINK
00675 if (lstat(file, &st) < 0) {
00676 #else
00677 if (stat(file, &st) < 0) {
00678 #endif
00679 string_print(NIL_PTR, "%s: %s\n", file, strerror(errno));
00680 return;
00681 }
00682 if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
00683 string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
00684 return;
00685 }
00686 if ((fd = add_open(file, &st)) < 0) {
00687 string_print(NIL_PTR, "Cannot open %s\n", file);
00688 return;
00689 }
00690 make_header(path_name(file), &st);
00691 if ((linkname = is_linked(&st)) != NULL) {
00692 strncpy(header.dbuf.linkname, linkname, (size_t) NAMSIZ);
00693 header.dbuf.typeflag = '1';
00694 if (verbose_flag) string_print(NIL_PTR, "linked %s to %s\n",
00695 header.dbuf.linkname, file);
00696 string_print(header.member.m_checksum, "%I ", checksum());
00697 mwrite(tar_fd, (char *) &header, sizeof(header));
00698 } else {
00699 is_added(&st, file);
00700 switch (st.st_mode & S_IFMT) {
00701 case S_IFREG:
00702 header.dbuf.typeflag = '0';
00703 string_print(header.member.m_checksum, "%I ", checksum());
00704 mwrite(tar_fd, (char *) &header, sizeof(header));
00705 copy(path_name(file), fd, tar_fd, (long) st.st_size);
00706 break;
00707 case S_IFDIR:
00708 header.dbuf.typeflag = '5';
00709 string_print(header.member.m_checksum, "%I ", checksum());
00710 mwrite(tar_fd, (char *) &header, sizeof(header));
00711 verb_print("read directory", file);
00712 if (norec_flag) break;
00713 if (NULL == getcwd(cwd, (int) sizeof cwd))
00714 string_print(NIL_PTR, "Error: cannot getcwd()\n");
00715 else if (chdir(file) < 0)
00716 string_print(NIL_PTR, "Cannot chdir to %s: %s\n",
00717 file, strerror(errno));
00718 else {
00719 add_path(file);
00720 #ifdef DIRECT_3
00721 {
00722 DIR *dirp;
00723 struct direct *dp;
00724 struct stat dst;
00725
00726 add_close(fd);
00727 fd= 0;
00728 dirp = opendir(".");
00729 while (NULL != (dp = readdir(dirp)))
00730 if (strcmp(dp->d_name, ".") == 0)
00731 is_linked(&st);
00732 else if (strcmp(dp->d_name, "..") == 0) {
00733 if (stat("..", &dst) == 0)
00734 is_linked(&dst);
00735 } else {
00736 strcpy(namebuf, dp->d_name);
00737 add_file(namebuf);
00738 }
00739 closedir(dirp);
00740 }
00741 #else
00742 {
00743 int i;
00744 struct direct dir;
00745 struct stat dst;
00746
00747 for (i = 0; i < 2; i++) {
00748 mread(fd, &dir, sizeof(dir));
00749 if (strcmp(dir.d_name, ".") == 0)
00750 is_linked(&st);
00751 else if (strcmp(dir.d_name, "..") == 0) {
00752 if (stat("..", &dst) == 0)
00753 is_linked(&dst);
00754 } else
00755 break;
00756 }
00757 while (bread(fd, &dir, sizeof(dir)) == sizeof(dir))
00758 if (dir.d_ino) {
00759 strncpy(namebuf, dir.d_name,
00760 (size_t) DIRSIZ);
00761 namebuf[DIRSIZ] = '\0';
00762 add_file(namebuf);
00763 }
00764 }
00765 #endif
00766 chdir(cwd);
00767 add_path(NIL_PTR);
00768 *file = 0;
00769 }
00770 break;
00771 #ifdef HAVE_SYMLINK
00772 case S_IFLNK:
00773 {
00774 int i;
00775
00776 header.dbuf.typeflag = '2';
00777 verb_print("read symlink", file);
00778 i = readlink(file,
00779 header.dbuf.linkname,
00780 sizeof(header.dbuf.linkname) - 1);
00781 if (i < 0) {
00782 string_print(NIL_PTR,
00783 "Cannot read symbolic link %s: %s\n",
00784 file, strerror(errno));
00785 return;
00786 }
00787 header.dbuf.linkname[i] = 0;
00788 string_print(header.member.m_checksum, "%I ", checksum());
00789 mwrite(tar_fd, (char *) &header, sizeof(header));
00790 break;
00791 }
00792 #endif
00793 #ifdef HAVE_FIFO
00794 case S_IFIFO:
00795 header.dbuf.typeflag = '6';
00796 verb_print("read fifo", file);
00797 string_print(header.member.m_checksum, "%I ", checksum());
00798 mwrite(tar_fd, (char *) &header, sizeof(header));
00799 break;
00800 #endif
00801 case S_IFBLK:
00802 header.dbuf.typeflag = '4';
00803 if (verbose_flag) {
00804 char sizebuf[TSIZLEN + 1];
00805
00806 strncpy(sizebuf, header.dbuf.size, (size_t) TSIZLEN);
00807 sizebuf[TSIZLEN] = 0;
00808 string_print(NIL_PTR,
00809 "read block device %s major %s minor %s\n",
00810 file, header.dbuf.devmajor, header.dbuf.devminor, sizebuf);
00811 }
00812 string_print(header.member.m_checksum, "%I ", checksum());
00813 mwrite(tar_fd, (char *) &header, sizeof(header));
00814 break;
00815 case S_IFCHR:
00816 header.dbuf.typeflag = '3';
00817 if (verbose_flag) string_print(NIL_PTR,
00818 "read character device %s major %s minor %s\n",
00819 file, header.dbuf.devmajor, header.dbuf.devminor);
00820 string_print(header.member.m_checksum, "%I ", checksum());
00821 mwrite(tar_fd, (char *) &header, sizeof(header));
00822 break;
00823 default:
00824 is_deleted(&st);
00825 string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
00826 *file = 0;
00827 }
00828 }
00829
00830 flush();
00831 add_close(fd);
00832 }
00833
00834 void verb_print(s1, s2)
00835 char *s1, *s2;
00836 {
00837 if (verbose_flag) string_print(NIL_PTR, "%s: %s\n", s1, s2);
00838 }
00839
00840 void add_close(fd)
00841 int fd;
00842 {
00843 if (fd != 0) close(fd);
00844 }
00845
00846
00847
00848
00849 int add_open(file, st)
00850 char *file;
00851 struct stat *st;
00852 {
00853 int fd;
00854 if (((st->st_mode & S_IFMT) != S_IFREG) &&
00855 ((st->st_mode & S_IFMT) != S_IFDIR))
00856 return 0;
00857 fd = open(file, O_RDONLY);
00858 if (fd == -1)
00859 fprintf(stderr, "open failed: %s\n", strerror(errno));
00860 return fd;
00861 }
00862
00863 void make_header(file, st)
00864 char *file;
00865 register struct stat *st;
00866 {
00867 register char *ptr = header.member.m_name;
00868 struct passwd *pwd;
00869 struct group *grp;
00870
00871 clear_header();
00872
00873 while (*ptr++ = *file++);
00874
00875 if ((st->st_mode & S_IFMT) == S_IFDIR) {
00876 *(ptr - 1) = '/';
00877 }
00878 string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
00879 string_print(header.member.m_uid, "%I ", st->st_uid);
00880 string_print(header.member.m_gid, "%I ", st->st_gid);
00881 if ((st->st_mode & S_IFMT) == S_IFREG)
00882 string_print(header.member.m_size, "%L ", st->st_size);
00883 else
00884 strncpy(header.dbuf.size, "0", (size_t) TSIZLEN);
00885 string_print(header.member.m_time, "%L ", st->st_mtime);
00886 strncpy(header.dbuf.magic, TMAGIC, (size_t) TMAGLEN);
00887 header.dbuf.version[0] = 0;
00888 header.dbuf.version[1] = 0;
00889 pwd = getpwuid(st->st_uid);
00890 strncpy(header.dbuf.uname,
00891 (pwd != NULL ? pwd->pw_name : "nobody"), TUNMLEN);
00892 grp = getgrgid(st->st_gid);
00893 strncpy(header.dbuf.gname,
00894 (grp != NULL ? grp->gr_name : "nobody"), TGNMLEN);
00895 if (st->st_mode & (S_IFBLK | S_IFCHR)) {
00896 string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
00897 string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
00898 }
00899 header.dbuf.prefix[0] = 0;
00900 }
00901
00902 void is_added(st, file)
00903 struct stat *st;
00904 char *file;
00905 {
00906 struct link *new;
00907 char *name;
00908
00909 if ((*file == 0) || (st->st_nlink == 1)) return;
00910 name = path_name(file);
00911 new = (struct link *) malloc(sizeof(struct link) + strlen(name));
00912 if (new == NULL) {
00913 print("Out of memory\n");
00914 return;
00915 }
00916 new->next = link_top;
00917 new->dev = st->st_dev;
00918 new->ino = st->st_ino;
00919 new->nlink = st->st_nlink - 1;
00920 strcpy(new->name, name);
00921 link_top = new;
00922 }
00923
00924 void is_deleted(st)
00925 struct stat *st;
00926 {
00927 struct link *old;
00928
00929 if ((old = link_top) != NULL) {
00930 link_top = old->next;
00931 free(old);
00932 }
00933 }
00934
00935 char *is_linked(st)
00936 struct stat *st;
00937 {
00938 struct link *cur = link_top;
00939 struct link **pre = &link_top;
00940 static char name[NAMSIZ];
00941
00942 while (cur != NULL)
00943 if ((cur->dev != st->st_dev) || (cur->ino != st->st_ino)) {
00944 pre = &cur->next;
00945 cur = cur->next;
00946 } else {
00947 if (--cur->nlink == 0) {
00948 *pre = cur->next;
00949 strncpy(name, cur->name, NAMSIZ);
00950 return name;
00951 }
00952 return cur->name;
00953 }
00954 return NULL;
00955 }
00956
00957 void clear_header()
00958 {
00959 register char *ptr = header.hdr_block;
00960
00961 while (ptr < &header.hdr_block[TBLOCK_SIZE]) *ptr++ = '\0';
00962 }
00963
00964 void adjust_boundary()
00965 {
00966 clear_header();
00967 mwrite(tar_fd, (char *) &header, sizeof(header));
00968 #ifndef POSIX_COMP
00969 while (total_blocks++ < BLOCK_BOUNDARY)
00970 mwrite(tar_fd, (char *) &header, sizeof(header));
00971 #else
00972 mwrite(tar_fd, (char *) &header, sizeof(header));
00973 #endif
00974 (void) close(tar_fd);
00975 }
00976
00977 void mread(fd, address, bytes)
00978 int fd, bytes;
00979 char *address;
00980 {
00981 if (bread(fd, address, bytes) != bytes) error("Tar: read error.", NIL_PTR);
00982 }
00983
00984 void mwrite(fd, address, bytes)
00985 int fd, bytes;
00986 char *address;
00987 {
00988 if (bwrite(fd, address, bytes) != bytes) error("Tar: write error.", NIL_PTR);
00989
00990 total_blocks++;
00991 }
00992
00993 int bread(fd, address, bytes)
00994 int fd, bytes;
00995 char *address;
00996 {
00997 int n = 0, r;
00998
00999 while (n < bytes) {
01000 if ((r = read(fd, address + n, bytes - n)) <= 0) {
01001 if (r < 0) return r;
01002 break;
01003 }
01004 n += r;
01005 }
01006 return n;
01007 }
01008
01009 int bwrite(fd, address, bytes)
01010 int fd, bytes;
01011 char *address;
01012 {
01013 int n = 0, r;
01014
01015 while (n < bytes) {
01016 if ((r = write(fd, address + n, bytes - n)) <= 0) {
01017 if (r < 0) return r;
01018 break;
01019 }
01020 n += r;
01021 }
01022 return n;
01023 }
01024
01025 char output[TBLOCK_SIZE];
01026 void print(str)
01027 register char *str;
01028 {
01029 int fd = (tar_fd == 1 ? 2 : 1);
01030 static int indx = 0;
01031
01032 if (str == NIL_PTR) {
01033 write(fd, output, indx);
01034 indx = 0;
01035 return;
01036 }
01037 while (*str) {
01038 output[indx++] = *str++;
01039 if (indx == TBLOCK_SIZE) {
01040 write(fd, output, TBLOCK_SIZE);
01041 indx = 0;
01042 }
01043 }
01044 }
01045
01046 char *num_out(number)
01047 register long number;
01048 {
01049 static char num_buf[12];
01050 register int i;
01051
01052 for (i = 11; i--;) {
01053 num_buf[i] = (number & 07) + '0';
01054 number >>= 3;
01055 }
01056
01057 return num_buf;
01058 }
01059
01060
01061 #if __STDC__
01062 void string_print(char *buffer, char *fmt,...)
01063 #else
01064 void string_print(buffer, fmt)
01065 char *buffer;
01066 char *fmt;
01067 #endif
01068 {
01069 va_list args;
01070 register char *buf_ptr;
01071 char *scan_ptr;
01072 char buf[STRING_SIZE];
01073 BOOL pr_fl, i;
01074
01075 if (pr_fl = (buffer == NIL_PTR)) buffer = buf;
01076
01077 va_start(args, fmt);
01078 buf_ptr = buffer;
01079 while (*fmt) {
01080 if (*fmt == '%') {
01081 fmt++;
01082 switch (*fmt++) {
01083 case 's':
01084 scan_ptr = (char *) (va_arg(args, char *));
01085 break;
01086 case 'I':
01087 scan_ptr = num_out((long) (va_arg(args, int)));
01088 for (i = 0; i < 5; i++) scan_ptr++;
01089 break;
01090 case 'L':
01091 scan_ptr = num_out((long) va_arg(args, long));
01092 break;
01093 case 'd':
01094 scan_ptr = num_out((long) va_arg(args, int));
01095 while (*scan_ptr == '0') scan_ptr++;
01096 scan_ptr--;
01097 break;
01098 default: scan_ptr = "";
01099 }
01100 while (*buf_ptr++ = *scan_ptr++);
01101 buf_ptr--;
01102 } else
01103 *buf_ptr++ = *fmt++;
01104 }
01105 *buf_ptr = '\0';
01106
01107 if (pr_fl) print(buffer);
01108 va_end(args);
01109 }