tar.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1992 Keith Muller.
00003  * Copyright (c) 1992, 1993
00004  *      The Regents of the University of California.  All rights reserved.
00005  *
00006  * This code is derived from software contributed to Berkeley by
00007  * Keith Muller of the University of California, San Diego.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer.
00014  * 2. Redistributions in binary form must reproduce the above copyright
00015  *    notice, this list of conditions and the following disclaimer in the
00016  *    documentation and/or other materials provided with the distribution.
00017  * 4. Neither the name of the University nor the names of its contributors
00018  *    may be used to endorse or promote products derived from this software
00019  *    without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  */
00033 
00034 #ifndef lint
00035 #if 0
00036 static char sccsid[] = "@(#)tar.c       8.2 (Berkeley) 4/18/94";
00037 #endif
00038 #endif /* not lint */
00039 
00040 #include <sys/types.h>
00041 #include <sys/time.h>
00042 #include <sys/stat.h>
00043 #include <string.h>
00044 #include <stdio.h>
00045 #include <unistd.h>
00046 #include <stdlib.h>
00047 #include "pax.h"
00048 #include "extern.h"
00049 #include "tar.h"
00050 
00051 /*
00052  * Routines for reading, writing and header identify of various versions of tar
00053  */
00054 
00055 static u_long tar_chksm(char *, int);
00056 static char *name_split(char *, int);
00057 static int ul_oct(u_long, char *, int, int);
00058 #ifndef NET2_STAT
00059 static int uqd_oct(u_quad_t, char *, int, int);
00060 #endif
00061 
00062 /*
00063  * Routines common to all versions of tar
00064  */
00065 
00066 static int tar_nodir;                   /* do not write dirs under old tar */
00067 
00068 /*
00069  * tar_endwr()
00070  *      add the tar trailer of two null blocks
00071  * Return:
00072  *      0 if ok, -1 otherwise (what wr_skip returns)
00073  */
00074 
00075 int
00076 tar_endwr(void)
00077 {
00078         return(wr_skip((off_t)(NULLCNT*BLKMULT)));
00079 }
00080 
00081 /*
00082  * tar_endrd()
00083  *      no cleanup needed here, just return size of trailer (for append)
00084  * Return:
00085  *      size of trailer (2 * BLKMULT)
00086  */
00087 
00088 off_t
00089 tar_endrd(void)
00090 {
00091         return((off_t)(NULLCNT*BLKMULT));
00092 }
00093 
00094 /*
00095  * tar_trail()
00096  *      Called to determine if a header block is a valid trailer. We are passed
00097  *      the block, the in_sync flag (which tells us we are in resync mode;
00098  *      looking for a valid header), and cnt (which starts at zero) which is
00099  *      used to count the number of empty blocks we have seen so far.
00100  * Return:
00101  *      0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
00102  *      could never contain a header.
00103  */
00104 
00105 int
00106 tar_trail(char *buf, int in_resync, int *cnt)
00107 {
00108         int i;
00109 
00110         /*
00111          * look for all zero, trailer is two consecutive blocks of zero
00112          */
00113         for (i = 0; i < BLKMULT; ++i) {
00114                 if (buf[i] != '\0')
00115                         break;
00116         }
00117 
00118         /*
00119          * if not all zero it is not a trailer, but MIGHT be a header.
00120          */
00121         if (i != BLKMULT)
00122                 return(-1);
00123 
00124         /*
00125          * When given a zero block, we must be careful!
00126          * If we are not in resync mode, check for the trailer. Have to watch
00127          * out that we do not mis-identify file data as the trailer, so we do
00128          * NOT try to id a trailer during resync mode. During resync mode we
00129          * might as well throw this block out since a valid header can NEVER be
00130          * a block of all 0 (we must have a valid file name).
00131          */
00132         if (!in_resync && (++*cnt >= NULLCNT))
00133                 return(0);
00134         return(1);
00135 }
00136 
00137 /*
00138  * ul_oct()
00139  *      convert an unsigned long to an octal string. many oddball field
00140  *      termination characters are used by the various versions of tar in the
00141  *      different fields. term selects which kind to use. str is '0' padded
00142  *      at the front to len. we are unable to use only one format as many old
00143  *      tar readers are very cranky about this.
00144  * Return:
00145  *      0 if the number fit into the string, -1 otherwise
00146  */
00147 
00148 static int
00149 ul_oct(u_long val, char *str, int len, int term)
00150 {
00151         char *pt;
00152 
00153         /*
00154          * term selects the appropriate character(s) for the end of the string
00155          */
00156         pt = str + len - 1;
00157         switch(term) {
00158         case 3:
00159                 *pt-- = '\0';
00160                 break;
00161         case 2:
00162                 *pt-- = ' ';
00163                 *pt-- = '\0';
00164                 break;
00165         case 1:
00166                 *pt-- = ' ';
00167                 break;
00168         case 0:
00169         default:
00170                 *pt-- = '\0';
00171                 *pt-- = ' ';
00172                 break;
00173         }
00174 
00175         /*
00176          * convert and blank pad if there is space
00177          */
00178         while (pt >= str) {
00179                 *pt-- = '0' + (char)(val & 0x7);
00180                 if ((val = val >> 3) == (u_long)0)
00181                         break;
00182         }
00183 
00184         while (pt >= str)
00185                 *pt-- = '0';
00186         if (val != (u_long)0)
00187                 return(-1);
00188         return(0);
00189 }
00190 
00191 #ifndef NET2_STAT
00192 /*
00193  * uqd_oct()
00194  *      convert an u_quad_t to an octal string. one of many oddball field
00195  *      termination characters are used by the various versions of tar in the
00196  *      different fields. term selects which kind to use. str is '0' padded
00197  *      at the front to len. we are unable to use only one format as many old
00198  *      tar readers are very cranky about this.
00199  * Return:
00200  *      0 if the number fit into the string, -1 otherwise
00201  */
00202 
00203 static int
00204 uqd_oct(u_quad_t val, char *str, int len, int term)
00205 {
00206         char *pt;
00207 
00208         /*
00209          * term selects the appropriate character(s) for the end of the string
00210          */
00211         pt = str + len - 1;
00212         switch(term) {
00213         case 3:
00214                 *pt-- = '\0';
00215                 break;
00216         case 2:
00217                 *pt-- = ' ';
00218                 *pt-- = '\0';
00219                 break;
00220         case 1:
00221                 *pt-- = ' ';
00222                 break;
00223         case 0:
00224         default:
00225                 *pt-- = '\0';
00226                 *pt-- = ' ';
00227                 break;
00228         }
00229 
00230         /*
00231          * convert and blank pad if there is space
00232          */
00233         while (pt >= str) {
00234                 *pt-- = '0' + (char)(val & 0x7);
00235                 if ((val = val >> 3) == 0)
00236                         break;
00237         }
00238 
00239         while (pt >= str)
00240                 *pt-- = '0';
00241         if (val != (u_quad_t)0)
00242                 return(-1);
00243         return(0);
00244 }
00245 #endif
00246 
00247 /*
00248  * tar_chksm()
00249  *      calculate the checksum for a tar block counting the checksum field as
00250  *      all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
00251  *      NOTE: we use len to short circuit summing 0's on write since we ALWAYS
00252  *      pad headers with 0.
00253  * Return:
00254  *      unsigned long checksum
00255  */
00256 
00257 static u_long
00258 tar_chksm(char *blk, int len)
00259 {
00260         char *stop;
00261         char *pt;
00262         u_long chksm = BLNKSUM; /* initial value is checksum field sum */
00263 
00264         /*
00265          * add the part of the block before the checksum field
00266          */
00267         pt = blk;
00268         stop = blk + CHK_OFFSET;
00269         while (pt < stop)
00270                 chksm += (u_long)(*pt++ & 0xff);
00271         /*
00272          * move past the checksum field and keep going, spec counts the
00273          * checksum field as the sum of 8 blanks (which is pre-computed as
00274          * BLNKSUM).
00275          * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
00276          * starts, no point in summing zero's)
00277          */
00278         pt += CHK_LEN;
00279         stop = blk + len;
00280         while (pt < stop)
00281                 chksm += (u_long)(*pt++ & 0xff);
00282         return(chksm);
00283 }
00284 
00285 /*
00286  * Routines for old BSD style tar (also made portable to sysV tar)
00287  */
00288 
00289 /*
00290  * tar_id()
00291  *      determine if a block given to us is a valid tar header (and not a USTAR
00292  *      header). We have to be on the lookout for those pesky blocks of all
00293  *      zero's.
00294  * Return:
00295  *      0 if a tar header, -1 otherwise
00296  */
00297 
00298 int
00299 tar_id(char *blk, int size)
00300 {
00301         HD_TAR *hd;
00302         HD_USTAR *uhd;
00303 
00304         if (size < BLKMULT)
00305                 return(-1);
00306         hd = (HD_TAR *)blk;
00307         uhd = (HD_USTAR *)blk;
00308 
00309         /*
00310          * check for block of zero's first, a simple and fast test, then make
00311          * sure this is not a ustar header by looking for the ustar magic
00312          * cookie. We should use TMAGLEN, but some USTAR archive programs are
00313          * wrong and create archives missing the \0. Last we check the
00314          * checksum. If this is ok we have to assume it is a valid header.
00315          */
00316         if (hd->name[0] == '\0')
00317                 return(-1);
00318         if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
00319                 return(-1);
00320         if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
00321                 return(-1);
00322         return(0);
00323 }
00324 
00325 /*
00326  * tar_opt()
00327  *      handle tar format specific -o options
00328  * Return:
00329  *      0 if ok -1 otherwise
00330  */
00331 
00332 int
00333 tar_opt(void)
00334 {
00335         OPLIST *opt;
00336 
00337         while ((opt = opt_next()) != NULL) {
00338                 if (strcmp(opt->name, TAR_OPTION) ||
00339                     strcmp(opt->value, TAR_NODIR)) {
00340                         paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
00341                             opt->name, opt->value);
00342                         paxwarn(1,"%s=%s is the only supported tar format option",
00343                             TAR_OPTION, TAR_NODIR);
00344                         return(-1);
00345                 }
00346 
00347                 /*
00348                  * we only support one option, and only when writing
00349                  */
00350                 if ((act != APPND) && (act != ARCHIVE)) {
00351                         paxwarn(1, "%s=%s is only supported when writing.",
00352                             opt->name, opt->value);
00353                         return(-1);
00354                 }
00355                 tar_nodir = 1;
00356         }
00357         return(0);
00358 }
00359 
00360 
00361 /*
00362  * tar_rd()
00363  *      extract the values out of block already determined to be a tar header.
00364  *      store the values in the ARCHD parameter.
00365  * Return:
00366  *      0
00367  */
00368 
00369 int
00370 tar_rd(ARCHD *arcn, char *buf)
00371 {
00372         HD_TAR *hd;
00373         char *pt;
00374 
00375         /*
00376          * we only get proper sized buffers passed to us
00377          */
00378         if (tar_id(buf, BLKMULT) < 0)
00379                 return(-1);
00380         arcn->org_name = arcn->name;
00381         arcn->sb.st_nlink = 1;
00382         arcn->pat = NULL;
00383 
00384         /*
00385          * copy out the name and values in the stat buffer
00386          */
00387         hd = (HD_TAR *)buf;
00388         /*
00389          * old tar format specifies the name always be null-terminated,
00390          * but let's be robust to broken archives.
00391          * the same applies to handling links below.
00392          */
00393         arcn->nlen = l_strncpy(arcn->name, hd->name,
00394             MIN(sizeof(hd->name), sizeof(arcn->name)) - 1);
00395         arcn->name[arcn->nlen] = '\0';
00396         arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
00397             0xfff);
00398         arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
00399         arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
00400 #ifdef NET2_STAT
00401         arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
00402         arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
00403 #else
00404         arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
00405         arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
00406 #endif
00407         arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
00408 
00409         /*
00410          * have to look at the last character, it may be a '/' and that is used
00411          * to encode this as a directory
00412          */
00413         pt = &(arcn->name[arcn->nlen - 1]);
00414         arcn->pad = 0;
00415         arcn->skip = 0;
00416         switch(hd->linkflag) {
00417         case SYMTYPE:
00418                 /*
00419                  * symbolic link, need to get the link name and set the type in
00420                  * the st_mode so -v printing will look correct.
00421                  */
00422                 arcn->type = PAX_SLK;
00423                 arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
00424                     MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
00425                 arcn->ln_name[arcn->ln_nlen] = '\0';
00426                 arcn->sb.st_mode |= S_IFLNK;
00427                 break;
00428         case LNKTYPE:
00429                 /*
00430                  * hard link, need to get the link name, set the type in the
00431                  * st_mode and st_nlink so -v printing will look better.
00432                  */
00433                 arcn->type = PAX_HLK;
00434                 arcn->sb.st_nlink = 2;
00435                 arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
00436                     MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
00437                 arcn->ln_name[arcn->ln_nlen] = '\0';
00438 
00439                 /*
00440                  * no idea of what type this thing really points at, but
00441                  * we set something for printing only.
00442                  */
00443                 arcn->sb.st_mode |= S_IFREG;
00444                 break;
00445         case DIRTYPE:
00446                 /*
00447                  * It is a directory, set the mode for -v printing
00448                  */
00449                 arcn->type = PAX_DIR;
00450                 arcn->sb.st_mode |= S_IFDIR;
00451                 arcn->sb.st_nlink = 2;
00452                 arcn->ln_name[0] = '\0';
00453                 arcn->ln_nlen = 0;
00454                 break;
00455         case AREGTYPE:
00456         case REGTYPE:
00457         default:
00458                 /*
00459                  * If we have a trailing / this is a directory and NOT a file.
00460                  */
00461                 arcn->ln_name[0] = '\0';
00462                 arcn->ln_nlen = 0;
00463                 if (*pt == '/') {
00464                         /*
00465                          * it is a directory, set the mode for -v printing
00466                          */
00467                         arcn->type = PAX_DIR;
00468                         arcn->sb.st_mode |= S_IFDIR;
00469                         arcn->sb.st_nlink = 2;
00470                 } else {
00471                         /*
00472                          * have a file that will be followed by data. Set the
00473                          * skip value to the size field and calculate the size
00474                          * of the padding.
00475                          */
00476                         arcn->type = PAX_REG;
00477                         arcn->sb.st_mode |= S_IFREG;
00478                         arcn->pad = TAR_PAD(arcn->sb.st_size);
00479                         arcn->skip = arcn->sb.st_size;
00480                 }
00481                 break;
00482         }
00483 
00484         /*
00485          * strip off any trailing slash.
00486          */
00487         if (*pt == '/') {
00488                 *pt = '\0';
00489                 --arcn->nlen;
00490         }
00491         return(0);
00492 }
00493 
00494 /*
00495  * tar_wr()
00496  *      write a tar header for the file specified in the ARCHD to the archive.
00497  *      Have to check for file types that cannot be stored and file names that
00498  *      are too long. Be careful of the term (last arg) to ul_oct, each field
00499  *      of tar has it own spec for the termination character(s).
00500  *      ASSUMED: space after header in header block is zero filled
00501  * Return:
00502  *      0 if file has data to be written after the header, 1 if file has NO
00503  *      data to write after the header, -1 if archive write failed
00504  */
00505 
00506 int
00507 tar_wr(ARCHD *arcn)
00508 {
00509         HD_TAR *hd;
00510         int len;
00511         char hdblk[sizeof(HD_TAR)];
00512 
00513         /*
00514          * check for those file system types which tar cannot store
00515          */
00516         switch(arcn->type) {
00517         case PAX_DIR:
00518                 /*
00519                  * user asked that dirs not be written to the archive
00520                  */
00521                 if (tar_nodir)
00522                         return(1);
00523                 break;
00524         case PAX_CHR:
00525                 paxwarn(1, "Tar cannot archive a character device %s",
00526                     arcn->org_name);
00527                 return(1);
00528         case PAX_BLK:
00529                 paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
00530                 return(1);
00531         case PAX_SCK:
00532                 paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
00533                 return(1);
00534         case PAX_FIF:
00535                 paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
00536                 return(1);
00537         case PAX_SLK:
00538         case PAX_HLK:
00539         case PAX_HRG:
00540                 if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) {
00541                         paxwarn(1,"Link name too long for tar %s", arcn->ln_name);
00542                         return(1);
00543                 }
00544                 break;
00545         case PAX_REG:
00546         case PAX_CTG:
00547         default:
00548                 break;
00549         }
00550 
00551         /*
00552          * check file name len, remember extra char for dirs (the / at the end)
00553          */
00554         len = arcn->nlen;
00555         if (arcn->type == PAX_DIR)
00556                 ++len;
00557         if (len >= (int)sizeof(hd->name)) {
00558                 paxwarn(1, "File name too long for tar %s", arcn->name);
00559                 return(1);
00560         }
00561 
00562         /*
00563          * copy the data out of the ARCHD into the tar header based on the type
00564          * of the file. Remember many tar readers want the unused fields to be
00565          * padded with zero. We set the linkflag field (type), the linkname
00566          * (or zero if not used),the size, and set the padding (if any) to be
00567          * added after the file data (0 for all other types, as they only have
00568          * a header)
00569          */
00570         hd = (HD_TAR *)hdblk;
00571         l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);
00572         hd->name[sizeof(hd->name) - 1] = '\0';
00573         arcn->pad = 0;
00574 
00575         if (arcn->type == PAX_DIR) {
00576                 /*
00577                  * directories are the same as files, except have a filename
00578                  * that ends with a /, we add the slash here. No data follows,
00579                  * dirs, so no pad.
00580                  */
00581                 hd->linkflag = AREGTYPE;
00582                 memset(hd->linkname, 0, sizeof(hd->linkname));
00583                 hd->name[len-1] = '/';
00584                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
00585                         goto out;
00586         } else if (arcn->type == PAX_SLK) {
00587                 /*
00588                  * no data follows this file, so no pad
00589                  */
00590                 hd->linkflag = SYMTYPE;
00591                 l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
00592                 hd->linkname[sizeof(hd->linkname) - 1] = '\0';
00593                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
00594                         goto out;
00595         } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
00596                 /*
00597                  * no data follows this file, so no pad
00598                  */
00599                 hd->linkflag = LNKTYPE;
00600                 l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
00601                 hd->linkname[sizeof(hd->linkname) - 1] = '\0';
00602                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
00603                         goto out;
00604         } else {
00605                 /*
00606                  * data follows this file, so set the pad
00607                  */
00608                 hd->linkflag = AREGTYPE;
00609                 memset(hd->linkname, 0, sizeof(hd->linkname));
00610 #               ifdef NET2_STAT
00611                 if (ul_oct((u_long)arcn->sb.st_size, hd->size,
00612                     sizeof(hd->size), 1)) {
00613 #               else
00614                 if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
00615                     sizeof(hd->size), 1)) {
00616 #               endif
00617                         paxwarn(1,"File is too large for tar %s", arcn->org_name);
00618                         return(1);
00619                 }
00620                 arcn->pad = TAR_PAD(arcn->sb.st_size);
00621         }
00622 
00623         /*
00624          * copy those fields that are independent of the type
00625          */
00626         if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
00627             ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
00628             ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
00629             ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
00630                 goto out;
00631 
00632         /*
00633          * calculate and add the checksum, then write the header. A return of
00634          * 0 tells the caller to now write the file data, 1 says no data needs
00635          * to be written
00636          */
00637         if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,
00638             sizeof(hd->chksum), 3))
00639                 goto out;
00640         if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0)
00641                 return(-1);
00642         if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
00643                 return(-1);
00644         if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
00645                 return(0);
00646         return(1);
00647 
00648     out:
00649         /*
00650          * header field is out of range
00651          */
00652         paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
00653         return(1);
00654 }
00655 
00656 /*
00657  * Routines for POSIX ustar
00658  */
00659 
00660 /*
00661  * ustar_strd()
00662  *      initialization for ustar read
00663  * Return:
00664  *      0 if ok, -1 otherwise
00665  */
00666 
00667 int
00668 ustar_strd(void)
00669 {
00670         if ((usrtb_start() < 0) || (grptb_start() < 0))
00671                 return(-1);
00672         return(0);
00673 }
00674 
00675 /*
00676  * ustar_stwr()
00677  *      initialization for ustar write
00678  * Return:
00679  *      0 if ok, -1 otherwise
00680  */
00681 
00682 int
00683 ustar_stwr(void)
00684 {
00685         if ((uidtb_start() < 0) || (gidtb_start() < 0))
00686                 return(-1);
00687         return(0);
00688 }
00689 
00690 /*
00691  * ustar_id()
00692  *      determine if a block given to us is a valid ustar header. We have to
00693  *      be on the lookout for those pesky blocks of all zero's
00694  * Return:
00695  *      0 if a ustar header, -1 otherwise
00696  */
00697 
00698 int
00699 ustar_id(char *blk, int size)
00700 {
00701         HD_USTAR *hd;
00702 
00703         if (size < BLKMULT)
00704                 return(-1);
00705         hd = (HD_USTAR *)blk;
00706 
00707         /*
00708          * check for block of zero's first, a simple and fast test then check
00709          * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
00710          * programs are fouled up and create archives missing the \0. Last we
00711          * check the checksum. If ok we have to assume it is a valid header.
00712          */
00713         if (hd->name[0] == '\0')
00714                 return(-1);
00715         if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
00716                 return(-1);
00717         if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
00718                 return(-1);
00719         return(0);
00720 }
00721 
00722 /*
00723  * ustar_rd()
00724  *      extract the values out of block already determined to be a ustar header.
00725  *      store the values in the ARCHD parameter.
00726  * Return:
00727  *      0
00728  */
00729 
00730 int
00731 ustar_rd(ARCHD *arcn, char *buf)
00732 {
00733         HD_USTAR *hd;
00734         char *dest;
00735         int cnt = 0;
00736         dev_t devmajor;
00737         dev_t devminor;
00738 
00739         /*
00740          * we only get proper sized buffers
00741          */
00742         if (ustar_id(buf, BLKMULT) < 0)
00743                 return(-1);
00744         arcn->org_name = arcn->name;
00745         arcn->sb.st_nlink = 1;
00746         arcn->pat = NULL;
00747         arcn->nlen = 0;
00748         hd = (HD_USTAR *)buf;
00749 
00750         /*
00751          * see if the filename is split into two parts. if, so joint the parts.
00752          * we copy the prefix first and add a / between the prefix and name.
00753          */
00754         dest = arcn->name;
00755         if (*(hd->prefix) != '\0') {
00756                 cnt = l_strncpy(dest, hd->prefix,
00757                     MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2));
00758                 dest += cnt;
00759                 *dest++ = '/';
00760                 cnt++;
00761         }
00762         /*
00763          * ustar format specifies the name may be unterminated
00764          * if it fills the entire field.  this also applies to
00765          * the prefix and the linkname.
00766          */
00767         arcn->nlen = cnt + l_strncpy(dest, hd->name,
00768             MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1));
00769         arcn->name[arcn->nlen] = '\0';
00770 
00771         /*
00772          * follow the spec to the letter. we should only have mode bits, strip
00773          * off all other crud we may be passed.
00774          */
00775         arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
00776             0xfff);
00777 #ifdef NET2_STAT
00778         arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
00779         arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
00780 #else
00781         arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
00782         arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
00783 #endif
00784         arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
00785 
00786         /*
00787          * If we can find the ascii names for gname and uname in the password
00788          * and group files we will use the uid's and gid they bind. Otherwise
00789          * we use the uid and gid values stored in the header. (This is what
00790          * the POSIX spec wants).
00791          */
00792         hd->gname[sizeof(hd->gname) - 1] = '\0';
00793         if (gid_name((char *) hd->gname, (gid_t *) &(arcn->sb.st_gid)) < 0)
00794                 arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
00795         hd->uname[sizeof(hd->uname) - 1] = '\0';
00796         if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
00797                 arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
00798 
00799         /*
00800          * set the defaults, these may be changed depending on the file type
00801          */
00802         arcn->ln_name[0] = '\0';
00803         arcn->ln_nlen = 0;
00804         arcn->pad = 0;
00805         arcn->skip = 0;
00806         arcn->sb.st_rdev = (dev_t)0;
00807 
00808         /*
00809          * set the mode and PAX type according to the typeflag in the header
00810          */
00811         switch(hd->typeflag) {
00812         case FIFOTYPE:
00813                 arcn->type = PAX_FIF;
00814                 arcn->sb.st_mode |= S_IFIFO;
00815                 break;
00816         case DIRTYPE:
00817                 arcn->type = PAX_DIR;
00818                 arcn->sb.st_mode |= S_IFDIR;
00819                 arcn->sb.st_nlink = 2;
00820 
00821                 /*
00822                  * Some programs that create ustar archives append a '/'
00823                  * to the pathname for directories. This clearly violates
00824                  * ustar specs, but we will silently strip it off anyway.
00825                  */
00826                 if (arcn->name[arcn->nlen - 1] == '/')
00827                         arcn->name[--arcn->nlen] = '\0';
00828                 break;
00829         case BLKTYPE:
00830         case CHRTYPE:
00831                 /*
00832                  * this type requires the rdev field to be set.
00833                  */
00834                 if (hd->typeflag == BLKTYPE) {
00835                         arcn->type = PAX_BLK;
00836                         arcn->sb.st_mode |= S_IFBLK;
00837                 } else {
00838                         arcn->type = PAX_CHR;
00839                         arcn->sb.st_mode |= S_IFCHR;
00840                 }
00841                 devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
00842                 devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
00843                 arcn->sb.st_rdev = TODEV(devmajor, devminor);
00844                 break;
00845         case SYMTYPE:
00846         case LNKTYPE:
00847                 if (hd->typeflag == SYMTYPE) {
00848                         arcn->type = PAX_SLK;
00849                         arcn->sb.st_mode |= S_IFLNK;
00850                 } else {
00851                         arcn->type = PAX_HLK;
00852                         /*
00853                          * so printing looks better
00854                          */
00855                         arcn->sb.st_mode |= S_IFREG;
00856                         arcn->sb.st_nlink = 2;
00857                 }
00858                 /*
00859                  * copy the link name
00860                  */
00861                 arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
00862                     MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1));
00863                 arcn->ln_name[arcn->ln_nlen] = '\0';
00864                 break;
00865         case CONTTYPE:
00866         case AREGTYPE:
00867         case REGTYPE:
00868         default:
00869                 /*
00870                  * these types have file data that follows. Set the skip and
00871                  * pad fields.
00872                  */
00873                 arcn->type = PAX_REG;
00874                 arcn->pad = TAR_PAD(arcn->sb.st_size);
00875                 arcn->skip = arcn->sb.st_size;
00876                 arcn->sb.st_mode |= S_IFREG;
00877                 break;
00878         }
00879         return(0);
00880 }
00881 
00882 /*
00883  * ustar_wr()
00884  *      write a ustar header for the file specified in the ARCHD to the archive
00885  *      Have to check for file types that cannot be stored and file names that
00886  *      are too long. Be careful of the term (last arg) to ul_oct, we only use
00887  *      '\0' for the termination character (this is different than picky tar)
00888  *      ASSUMED: space after header in header block is zero filled
00889  * Return:
00890  *      0 if file has data to be written after the header, 1 if file has NO
00891  *      data to write after the header, -1 if archive write failed
00892  */
00893 
00894 int
00895 ustar_wr(ARCHD *arcn)
00896 {
00897         HD_USTAR *hd;
00898         char *pt;
00899         char hdblk[sizeof(HD_USTAR)];
00900 
00901         /*
00902          * check for those file system types ustar cannot store
00903          */
00904         if (arcn->type == PAX_SCK) {
00905                 paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
00906                 return(1);
00907         }
00908 
00909         /*
00910          * check the length of the linkname
00911          */
00912         if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
00913             (arcn->type == PAX_HRG)) &&
00914             (arcn->ln_nlen > (int)sizeof(hd->linkname))) {
00915                 paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
00916                 return(1);
00917         }
00918 
00919         /*
00920          * split the path name into prefix and name fields (if needed). if
00921          * pt != arcn->name, the name has to be split
00922          */
00923         if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
00924                 paxwarn(1, "File name too long for ustar %s", arcn->name);
00925                 return(1);
00926         }
00927         hd = (HD_USTAR *)hdblk;
00928         arcn->pad = 0L;
00929 
00930         /*
00931          * split the name, or zero out the prefix
00932          */
00933         if (pt != arcn->name) {
00934                 /*
00935                  * name was split, pt points at the / where the split is to
00936                  * occur, we remove the / and copy the first part to the prefix
00937                  */
00938                 *pt = '\0';
00939                 l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));
00940                 *pt++ = '/';
00941         } else
00942                 memset(hd->prefix, 0, sizeof(hd->prefix));
00943 
00944         /*
00945          * copy the name part. this may be the whole path or the part after
00946          * the prefix.  both the name and prefix may fill the entire field.
00947          */
00948         l_strncpy(hd->name, pt, sizeof(hd->name));
00949 
00950         /*
00951          * set the fields in the header that are type dependent
00952          */
00953         switch(arcn->type) {
00954         case PAX_DIR:
00955                 hd->typeflag = DIRTYPE;
00956                 memset(hd->linkname, 0, sizeof(hd->linkname));
00957                 memset(hd->devmajor, 0, sizeof(hd->devmajor));
00958                 memset(hd->devminor, 0, sizeof(hd->devminor));
00959                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
00960                         goto out;
00961                 break;
00962         case PAX_CHR:
00963         case PAX_BLK:
00964                 if (arcn->type == PAX_CHR)
00965                         hd->typeflag = CHRTYPE;
00966                 else
00967                         hd->typeflag = BLKTYPE;
00968                 memset(hd->linkname, 0, sizeof(hd->linkname));
00969                 if (ul_oct((u_long)major(arcn->sb.st_rdev), hd->devmajor,
00970                    sizeof(hd->devmajor), 3) ||
00971                    ul_oct((u_long)minor(arcn->sb.st_rdev), hd->devminor,
00972                    sizeof(hd->devminor), 3) ||
00973                    ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
00974                         goto out;
00975                 break;
00976         case PAX_FIF:
00977                 hd->typeflag = FIFOTYPE;
00978                 memset(hd->linkname, 0, sizeof(hd->linkname));
00979                 memset(hd->devmajor, 0, sizeof(hd->devmajor));
00980                 memset(hd->devminor, 0, sizeof(hd->devminor));
00981                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
00982                         goto out;
00983                 break;
00984         case PAX_SLK:
00985         case PAX_HLK:
00986         case PAX_HRG:
00987                 if (arcn->type == PAX_SLK)
00988                         hd->typeflag = SYMTYPE;
00989                 else
00990                         hd->typeflag = LNKTYPE;
00991                 /* the link name may occupy the entire field in ustar */
00992                 l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
00993                 memset(hd->devmajor, 0, sizeof(hd->devmajor));
00994                 memset(hd->devminor, 0, sizeof(hd->devminor));
00995                 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
00996                         goto out;
00997                 break;
00998         case PAX_REG:
00999         case PAX_CTG:
01000         default:
01001                 /*
01002                  * file data with this type, set the padding
01003                  */
01004                 if (arcn->type == PAX_CTG)
01005                         hd->typeflag = CONTTYPE;
01006                 else
01007                         hd->typeflag = REGTYPE;
01008                 memset(hd->linkname, 0, sizeof(hd->linkname));
01009                 memset(hd->devmajor, 0, sizeof(hd->devmajor));
01010                 memset(hd->devminor, 0, sizeof(hd->devminor));
01011                 arcn->pad = TAR_PAD(arcn->sb.st_size);
01012 #               ifdef NET2_STAT
01013                 if (ul_oct((u_long)arcn->sb.st_size, hd->size,
01014                     sizeof(hd->size), 3)) {
01015 #               else
01016                 if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
01017                     sizeof(hd->size), 3)) {
01018 #               endif
01019                         paxwarn(1,"File is too long for ustar %s",arcn->org_name);
01020                         return(1);
01021                 }
01022                 break;
01023         }
01024 
01025         l_strncpy(hd->magic, TMAGIC, TMAGLEN);
01026         l_strncpy(hd->version, TVERSION, TVERSLEN);
01027 
01028         /*
01029          * set the remaining fields. Some versions want all 16 bits of mode
01030          * we better humor them (they really do not meet spec though)....
01031          */
01032         if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
01033             ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
01034             ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
01035             ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
01036                 goto out;
01037         l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
01038         l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
01039 
01040         /*
01041          * calculate and store the checksum write the header to the archive
01042          * return 0 tells the caller to now write the file data, 1 says no data
01043          * needs to be written
01044          */
01045         if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
01046            sizeof(hd->chksum), 3))
01047                 goto out;
01048         if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
01049                 return(-1);
01050         if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
01051                 return(-1);
01052         if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
01053                 return(0);
01054         return(1);
01055 
01056     out:
01057         /*
01058          * header field is out of range
01059          */
01060         paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
01061         return(1);
01062 }
01063 
01064 /*
01065  * name_split()
01066  *      see if the name has to be split for storage in a ustar header. We try
01067  *      to fit the entire name in the name field without splitting if we can.
01068  *      The split point is always at a /
01069  * Return
01070  *      character pointer to split point (always the / that is to be removed
01071  *      if the split is not needed, the points is set to the start of the file
01072  *      name (it would violate the spec to split there). A NULL is returned if
01073  *      the file name is too long
01074  */
01075 
01076 static char *
01077 name_split(char *name, int len)
01078 {
01079         char *start;
01080 
01081         /*
01082          * check to see if the file name is small enough to fit in the name
01083          * field. if so just return a pointer to the name.
01084          */
01085         if (len <= TNMSZ)
01086                 return(name);
01087         if (len > (TPFSZ + TNMSZ + 1))
01088                 return(NULL);
01089 
01090         /*
01091          * we start looking at the biggest sized piece that fits in the name
01092          * field. We walk forward looking for a slash to split at. The idea is
01093          * to find the biggest piece to fit in the name field (or the smallest
01094          * prefix we can find)
01095          */
01096         start = name + len - TNMSZ - 1;
01097         while ((*start != '\0') && (*start != '/'))
01098                 ++start;
01099 
01100         /*
01101          * if we hit the end of the string, this name cannot be split, so we
01102          * cannot store this file.
01103          */
01104         if (*start == '\0')
01105                 return(NULL);
01106         len = start - name;
01107 
01108         /*
01109          * NOTE: /str where the length of str == TNMSZ can not be stored under
01110          * the p1003.1-1990 spec for ustar. We could force a prefix of / and
01111          * the file would then expand on extract to //str. The len == 0 below
01112          * makes this special case follow the spec to the letter.
01113          */
01114         if ((len > TPFSZ) || (len == 0))
01115                 return(NULL);
01116 
01117         /*
01118          * ok have a split point, return it to the caller
01119          */
01120         return(start);
01121 }

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