tar.c

Go to the documentation of this file.
00001 /* tar - tape archiver                  Author: Michiel Huisjes */
00002 
00003 /* Usage: tar [cxt][vo][F][f] tapefile [files]
00004  *
00005  * attempt to make tar to conform to POSIX 1003.1
00006  * disclaimer: based on an old (1986) POSIX draft.
00007  * Klamer Schutte, 20/9/89
00008  *
00009  * Changes:
00010  *  Changed to handle the original minix-tar format.    KS 22/9/89
00011  *  Changed to handle BSD4.3 tar format.                KS 22/9/89
00012  *  Conform to current umask if not super-user.         KS 22/9/89
00013  *  Update usage message to show f option               KS 22/9/89
00014  *
00015  *
00016  * 1)   tar will back itself up, should check archive inode num(&dev) and
00017   then check the target inode number. In verbose mode, issue
00018   warning, in all cases ignore target.
00019   marks@mgse            Mon Sep 25 10:38:58 CDT 1989
00020         added global varaibles, made changes to main() and add_file();
00021   maks@mgse Mon Sep 25 12:09:20 CDT 1989
00022 
00023    2)   tar will not notice that a file has changed size while it was being
00024   backed up. should issue warning.
00025   marks@mgse            Mon Sep 25 10:38:58 CDT 1989
00026 
00027    3)   the 'f' option was not documented in usage[].
00028   marks@mgse            Mon Sep 25 12:03:20 CDT 1989
00029         changed both usage[] defines. Why are there two (one is commented out)?
00030         ( deleted by me (was done twice) -- KS, 2/10/89 )
00031  *
00032  *  changed stat on tar_fd to an fstat                          KS 2/10/89
00033  *  deleted mkfifo() code -- belongs in libc.a                  KS 2/10/89
00034  *  made ar_dev default to -1 : an illegal device               KS 2/10/89
00035  *  made impossible to chown if normal user                     KS 2/10/89
00036  *  if names in owner fields not known use numirical values     KS 2/10/89
00037  *  creat with mask 666 -- use umask if to liberal              KS 2/10/89
00038  *  allow to make directories as ../directory                   KS 2/10/89
00039  *  allow tmagic field to end with a space (instead of \0)      KS 2/10/89
00040  *  correct usage of tmagic field                               KS 3/10/89
00041  *  made mkdir() to return a value if directory == "."          KS 3/10/89
00042  *  made lint complains less (On a BSD 4.3 system)              KS 3/10/89
00043  *  use of directory(3) routines                                KS 3/10/89
00044  *  deleted use of d_namlen selector of struct dirent           KS 18/10/89
00045  *  support mknod4(2)                                           EC 7/7/90
00046  *  forget inodes when link count expires                       EC 6/4/91
00047  *  don't remember directories *twice*!
00048  *  added 'p' flag to ignore umask for normal user              KJB 6/10/92
00049  *  mknod4(2) out                                               KJB 30/10/94
00050  *  added 'D' flag to not recurse into directories              KJB 19/12/94
00051  *  status output to stdout unless 'tar cvf -'                  KJB 3/5/97
00052  *
00053  * Bugs:
00054  *  verbose mode is not reporting consistent
00055  *  code needs cleanup
00056  *  prefix field is not used
00057  *  timestamp of a directory will not be correct if there are files to be
00058  *  unpacked in the directory
00059  *      (add you favorite bug here (or two (or three (or ...))))
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>              /* need NULL */
00075 #include <errno.h>
00076 
00077 #define POSIX_COMP              /* POSIX compatible */
00078 #define DIRECT_3                /* use directory(3) routines */
00079 
00080 #ifdef DIRECT_3
00081 #ifndef BSD
00082 /* To all minix users: i am sorry, developed this piece of code on a
00083  * BSD system. KS 18/10/89 */
00084 #include <dirent.h>
00085 #define direct  dirent          /* stupid BSD non-POSIX compatible name! */
00086 #else                           /* BSD */
00087 #include <sys/dir.h>
00088 #include <dir.h>
00089 #endif                          /* BSD */
00090 #endif                          /* DIRECT_3 */
00091 
00092 #ifdef S_IFIFO
00093 #define HAVE_FIFO               /* have incorporated Simon Pooles' changes */
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     /* string buffer size */
00104 #define HEADER_SIZE     TBLOCK
00105 #define NAME_SIZE       NAMSIZ
00106 /* #define BLOCK_BOUNDARY        20 -- not in POSIX ! */
00107 
00108 typedef union hblock HEADER;
00109 
00110 /* Make the MINIX member names overlap to the POSIX names */
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                           /* original structure -- see tar.h for new
00125                          * structure */
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 /* Structure used to note links */
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 /* Char usage[] = "Usage: tar [cxt] tarfile [files]."; */
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 /* Make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
00182 ino_t ar_inode;                 /* archive inode number  */
00183 dev_t ar_dev;                   /* archive device number */
00184 
00185 int total_blocks;
00186 int u_mask;                     /* one's complement of current umask */
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         /* Ignore - as first char */
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':           /* verbose output  -Dal */
00251                 verbose_flag = !verbose_flag;
00252                 break;
00253             case 'o':           /* chown/chgrp files  -Dal */
00254                 chown_flag = TRUE;
00255                 break;
00256             case 'F':           /* IGNORE ERRORS  -Dal */
00257                 force_flag = TRUE;
00258                 break;
00259             case 'f':           /* standard U*IX usage -KS */
00260                 break;
00261             case 'p':           /* restore file modes right, ignore umask. */
00262                 (void) umask(0);
00263                 break;
00264             case 'D':           /* do not recursively add directories. */
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)/* only - means stdin/stdout - KS */
00274         tar_fd = creat_fl ? 1 : 0;      /* '-' means used
00275                                          * stdin/stdout  -Dal */
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()) {              /* check if super-user */
00282         int save_umask;
00283         save_umask = umask(0);
00284         u_mask = ~save_umask;
00285         umask(save_umask);
00286         chown_flag = TRUE;      /* normal user can't chown */
00287   } else
00288         u_mask = ~0;            /* don't restrict if 'privileged utility' */
00289 
00290   ar_dev = -1;                  /* impossible device nr */
00291   if (creat_fl) {
00292         if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
00293                 error("Can't stat ", argv[2]);  /* will never be here,
00294                                                  * right? */
00295         else {                  /* get archive inode & device    */
00296                 ar_inode = st.st_ino;   /* save files inode      */
00297                 ar_dev = st.st_dev;     /* save files device     */
00298         }                       /* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
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         /* Extraction code moved here from tarfile() MSP */
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();              /* tarfile() justs prints info. now MSP */
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)               /* skip checksum verification  -Dal */
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 /* Tarfile() just lists info about archive now; as of the t flag. */
00350 /* Extraction has been moved into main() as that needs access to argv[] */
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':           /* official POSIX */
00385             case 0:             /* also mentioned in POSIX */
00386             case ' ':           /* ofetn used */
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          /* FALL TROUGH */
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;              /* walk thru failed directory path */
00417 
00418   switch (header.dbuf.typeflag) {
00419       case '1':                 /* Link */
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':                 /* directory */
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':                 /* character special */
00439       case '4':                 /* block special */
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':                 /* symbolic link */
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':                 /* contiguous file -- what is this (KS) */
00480         print("Not implemented file type\n");
00481         return;                 /* not implemented, but break out */
00482 #ifdef HAVE_FIFO
00483       case '6':                 /* fifo */
00484         delete(file);
00485         if (mkfifo(file, 0) == 0) {     /* is chmod'ed in do_chown */
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   /* Create regular file.  If failure, try to make missing directories. */
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   /* remove a file or an empty directory */
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   /* leave error reporting to the create following soon. */
00532 }
00533 
00534 void do_chown(file)
00535 char *file;
00536 {
00537   int uid = -1, gid = -1;       /* these are illegal ??? -- KS */
00538 
00539   if (!chown_flag) {            /* set correct owner and group  -Dal */
00540         if (header.dbuf.magic[TMAGLEN] == ' ')
00541                 header.dbuf.magic[TMAGLEN] = '\0';      /* some tars out there
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   /* Should there be a timestamp if the chown failes? -- KS */
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  *      add a file to the archive
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];             /* -Dal */
00671   char cwd[129];                /* -KS */
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   }                             /* marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
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++) {       /* . and .. */
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  *      open file 'file' to be added to archive, return file descriptor
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) {      /* fixed test  -Dal */
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 /*VARARGS2*/
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 }

Generated on Fri Apr 14 22:57:02 2006 for minix by  doxygen 1.4.6