/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1992 Keith Muller.4* Copyright (c) 1992, 19935* The Regents of the University of California. All rights reserved.6*7* This code is derived from software contributed to Berkeley by8* Keith Muller of the University of California, San Diego.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18* 3. Neither the name of the University nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#include <sys/types.h>36#include <sys/time.h>37#include <sys/stat.h>38#include <string.h>39#include <stdio.h>40#include "pax.h"41#include "extern.h"42#include "tar.h"4344/*45* Routines for reading, writing and header identify of various versions of tar46*/4748static u_long tar_chksm(char *, int);49static char *name_split(char *, int);50static int ul_oct(u_long, char *, int, int);51static int uqd_oct(u_quad_t, char *, int, int);5253/*54* Routines common to all versions of tar55*/5657static int tar_nodir; /* do not write dirs under old tar */5859/*60* tar_endwr()61* add the tar trailer of two null blocks62* Return:63* 0 if ok, -1 otherwise (what wr_skip returns)64*/6566int67tar_endwr(void)68{69return(wr_skip((off_t)(NULLCNT*BLKMULT)));70}7172/*73* tar_endrd()74* no cleanup needed here, just return size of trailer (for append)75* Return:76* size of trailer (2 * BLKMULT)77*/7879off_t80tar_endrd(void)81{82return((off_t)(NULLCNT*BLKMULT));83}8485/*86* tar_trail()87* Called to determine if a header block is a valid trailer. We are passed88* the block, the in_sync flag (which tells us we are in resync mode;89* looking for a valid header), and cnt (which starts at zero) which is90* used to count the number of empty blocks we have seen so far.91* Return:92* 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block93* could never contain a header.94*/9596int97tar_trail(char *buf, int in_resync, int *cnt)98{99int i;100101/*102* look for all zero, trailer is two consecutive blocks of zero103*/104for (i = 0; i < BLKMULT; ++i) {105if (buf[i] != '\0')106break;107}108109/*110* if not all zero it is not a trailer, but MIGHT be a header.111*/112if (i != BLKMULT)113return(-1);114115/*116* When given a zero block, we must be careful!117* If we are not in resync mode, check for the trailer. Have to watch118* out that we do not mis-identify file data as the trailer, so we do119* NOT try to id a trailer during resync mode. During resync mode we120* might as well throw this block out since a valid header can NEVER be121* a block of all 0 (we must have a valid file name).122*/123if (!in_resync && (++*cnt >= NULLCNT))124return(0);125return(1);126}127128/*129* ul_oct()130* convert an unsigned long to an octal string. many oddball field131* termination characters are used by the various versions of tar in the132* different fields. term selects which kind to use. str is '0' padded133* at the front to len. we are unable to use only one format as many old134* tar readers are very cranky about this.135* Return:136* 0 if the number fit into the string, -1 otherwise137*/138139static int140ul_oct(u_long val, char *str, int len, int term)141{142char *pt;143144/*145* term selects the appropriate character(s) for the end of the string146*/147pt = str + len - 1;148switch(term) {149case 3:150*pt-- = '\0';151break;152case 2:153*pt-- = ' ';154*pt-- = '\0';155break;156case 1:157*pt-- = ' ';158break;159case 0:160default:161*pt-- = '\0';162*pt-- = ' ';163break;164}165166/*167* convert and blank pad if there is space168*/169while (pt >= str) {170*pt-- = '0' + (char)(val & 0x7);171if ((val = val >> 3) == (u_long)0)172break;173}174175while (pt >= str)176*pt-- = '0';177if (val != (u_long)0)178return(-1);179return(0);180}181182/*183* uqd_oct()184* convert an u_quad_t to an octal string. one of many oddball field185* termination characters are used by the various versions of tar in the186* different fields. term selects which kind to use. str is '0' padded187* at the front to len. we are unable to use only one format as many old188* tar readers are very cranky about this.189* Return:190* 0 if the number fit into the string, -1 otherwise191*/192193static int194uqd_oct(u_quad_t val, char *str, int len, int term)195{196char *pt;197198/*199* term selects the appropriate character(s) for the end of the string200*/201pt = str + len - 1;202switch(term) {203case 3:204*pt-- = '\0';205break;206case 2:207*pt-- = ' ';208*pt-- = '\0';209break;210case 1:211*pt-- = ' ';212break;213case 0:214default:215*pt-- = '\0';216*pt-- = ' ';217break;218}219220/*221* convert and blank pad if there is space222*/223while (pt >= str) {224*pt-- = '0' + (char)(val & 0x7);225if ((val = val >> 3) == 0)226break;227}228229while (pt >= str)230*pt-- = '0';231if (val != (u_quad_t)0)232return(-1);233return(0);234}235236/*237* tar_chksm()238* calculate the checksum for a tar block counting the checksum field as239* all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).240* NOTE: we use len to short circuit summing 0's on write since we ALWAYS241* pad headers with 0.242* Return:243* unsigned long checksum244*/245246static u_long247tar_chksm(char *blk, int len)248{249char *stop;250char *pt;251u_long chksm = BLNKSUM; /* initial value is checksum field sum */252253/*254* add the part of the block before the checksum field255*/256pt = blk;257stop = blk + CHK_OFFSET;258while (pt < stop)259chksm += (u_long)(*pt++ & 0xff);260/*261* move past the checksum field and keep going, spec counts the262* checksum field as the sum of 8 blanks (which is pre-computed as263* BLNKSUM).264* ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding265* starts, no point in summing zero's)266*/267pt += CHK_LEN;268stop = blk + len;269while (pt < stop)270chksm += (u_long)(*pt++ & 0xff);271return(chksm);272}273274/*275* Routines for old BSD style tar (also made portable to sysV tar)276*/277278/*279* tar_id()280* determine if a block given to us is a valid tar header (and not a USTAR281* header). We have to be on the lookout for those pesky blocks of all282* zero's.283* Return:284* 0 if a tar header, -1 otherwise285*/286287int288tar_id(char *blk, int size)289{290HD_TAR *hd;291HD_USTAR *uhd;292293if (size < BLKMULT)294return(-1);295hd = (HD_TAR *)blk;296uhd = (HD_USTAR *)blk;297298/*299* check for block of zero's first, a simple and fast test, then make300* sure this is not a ustar header by looking for the ustar magic301* cookie. We should use TMAGLEN, but some USTAR archive programs are302* wrong and create archives missing the \0. Last we check the303* checksum. If this is ok we have to assume it is a valid header.304*/305if (hd->name[0] == '\0')306return(-1);307if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)308return(-1);309if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))310return(-1);311return(0);312}313314/*315* tar_opt()316* handle tar format specific -o options317* Return:318* 0 if ok -1 otherwise319*/320321int322tar_opt(void)323{324OPLIST *opt;325326while ((opt = opt_next()) != NULL) {327if (strcmp(opt->name, TAR_OPTION) ||328strcmp(opt->value, TAR_NODIR)) {329paxwarn(1, "Unknown tar format -o option/value pair %s=%s",330opt->name, opt->value);331paxwarn(1,"%s=%s is the only supported tar format option",332TAR_OPTION, TAR_NODIR);333return(-1);334}335336/*337* we only support one option, and only when writing338*/339if ((act != APPND) && (act != ARCHIVE)) {340paxwarn(1, "%s=%s is only supported when writing.",341opt->name, opt->value);342return(-1);343}344tar_nodir = 1;345}346return(0);347}348349350/*351* tar_rd()352* extract the values out of block already determined to be a tar header.353* store the values in the ARCHD parameter.354* Return:355* 0356*/357358int359tar_rd(ARCHD *arcn, char *buf)360{361HD_TAR *hd;362char *pt;363364/*365* we only get proper sized buffers passed to us366*/367if (tar_id(buf, BLKMULT) < 0)368return(-1);369memset(arcn, 0, sizeof *arcn);370arcn->org_name = arcn->name;371arcn->sb.st_nlink = 1;372373/*374* copy out the name and values in the stat buffer375*/376hd = (HD_TAR *)buf;377/*378* old tar format specifies the name always be null-terminated,379* but let's be robust to broken archives.380* the same applies to handling links below.381*/382arcn->nlen = l_strncpy(arcn->name, hd->name,383MIN(sizeof(hd->name), sizeof(arcn->name)) - 1);384arcn->name[arcn->nlen] = '\0';385arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &3860xfff);387arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);388arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);389arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);390arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);391arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;392393/*394* have to look at the last character, it may be a '/' and that is used395* to encode this as a directory396*/397pt = &(arcn->name[arcn->nlen - 1]);398switch(hd->linkflag) {399case SYMTYPE:400/*401* symbolic link, need to get the link name and set the type in402* the st_mode so -v printing will look correct.403*/404arcn->type = PAX_SLK;405arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,406MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);407arcn->ln_name[arcn->ln_nlen] = '\0';408arcn->sb.st_mode |= S_IFLNK;409break;410case LNKTYPE:411/*412* hard link, need to get the link name, set the type in the413* st_mode and st_nlink so -v printing will look better.414*/415arcn->type = PAX_HLK;416arcn->sb.st_nlink = 2;417arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,418MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);419arcn->ln_name[arcn->ln_nlen] = '\0';420421/*422* no idea of what type this thing really points at, but423* we set something for printing only.424*/425arcn->sb.st_mode |= S_IFREG;426break;427case DIRTYPE:428/*429* It is a directory, set the mode for -v printing430*/431arcn->type = PAX_DIR;432arcn->sb.st_mode |= S_IFDIR;433arcn->sb.st_nlink = 2;434break;435case AREGTYPE:436case REGTYPE:437default:438/*439* If we have a trailing / this is a directory and NOT a file.440*/441if (*pt == '/') {442/*443* it is a directory, set the mode for -v printing444*/445arcn->type = PAX_DIR;446arcn->sb.st_mode |= S_IFDIR;447arcn->sb.st_nlink = 2;448} else {449/*450* have a file that will be followed by data. Set the451* skip value to the size field and calculate the size452* of the padding.453*/454arcn->type = PAX_REG;455arcn->sb.st_mode |= S_IFREG;456arcn->pad = TAR_PAD(arcn->sb.st_size);457arcn->skip = arcn->sb.st_size;458}459break;460}461462/*463* strip off any trailing slash.464*/465if (*pt == '/') {466*pt = '\0';467--arcn->nlen;468}469return(0);470}471472/*473* tar_wr()474* write a tar header for the file specified in the ARCHD to the archive.475* Have to check for file types that cannot be stored and file names that476* are too long. Be careful of the term (last arg) to ul_oct, each field477* of tar has it own spec for the termination character(s).478* ASSUMED: space after header in header block is zero filled479* Return:480* 0 if file has data to be written after the header, 1 if file has NO481* data to write after the header, -1 if archive write failed482*/483484int485tar_wr(ARCHD *arcn)486{487HD_TAR *hd;488int len;489HD_TAR hdblk;490491/*492* check for those file system types which tar cannot store493*/494switch(arcn->type) {495case PAX_DIR:496/*497* user asked that dirs not be written to the archive498*/499if (tar_nodir)500return(1);501break;502case PAX_CHR:503paxwarn(1, "Tar cannot archive a character device %s",504arcn->org_name);505return(1);506case PAX_BLK:507paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);508return(1);509case PAX_SCK:510paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);511return(1);512case PAX_FIF:513paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);514return(1);515case PAX_SLK:516case PAX_HLK:517case PAX_HRG:518if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) {519paxwarn(1,"Link name too long for tar %s", arcn->ln_name);520return(1);521}522break;523case PAX_REG:524case PAX_CTG:525default:526break;527}528529/*530* check file name len, remember extra char for dirs (the / at the end)531*/532len = arcn->nlen;533if (arcn->type == PAX_DIR)534++len;535if (len >= (int)sizeof(hd->name)) {536paxwarn(1, "File name too long for tar %s", arcn->name);537return(1);538}539540/*541* Copy the data out of the ARCHD into the tar header based on the type542* of the file. Remember, many tar readers want all fields to be543* padded with zero so we zero the header first. We then set the544* linkflag field (type), the linkname, the size, and set the padding545* (if any) to be added after the file data (0 for all other types,546* as they only have a header).547*/548hd = &hdblk;549l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);550hd->name[sizeof(hd->name) - 1] = '\0';551arcn->pad = 0;552553if (arcn->type == PAX_DIR) {554/*555* directories are the same as files, except have a filename556* that ends with a /, we add the slash here. No data follows,557* dirs, so no pad.558*/559hd->linkflag = AREGTYPE;560memset(hd->linkname, 0, sizeof(hd->linkname));561hd->name[len-1] = '/';562if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))563goto out;564} else if (arcn->type == PAX_SLK) {565/*566* no data follows this file, so no pad567*/568hd->linkflag = SYMTYPE;569l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);570hd->linkname[sizeof(hd->linkname) - 1] = '\0';571if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))572goto out;573} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {574/*575* no data follows this file, so no pad576*/577hd->linkflag = LNKTYPE;578l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);579hd->linkname[sizeof(hd->linkname) - 1] = '\0';580if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))581goto out;582} else {583/*584* data follows this file, so set the pad585*/586hd->linkflag = AREGTYPE;587memset(hd->linkname, 0, sizeof(hd->linkname));588if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,589sizeof(hd->size), 1)) {590paxwarn(1,"File is too large for tar %s", arcn->org_name);591return(1);592}593arcn->pad = TAR_PAD(arcn->sb.st_size);594}595596/*597* copy those fields that are independent of the type598*/599if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||600ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||601ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||602ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))603goto out;604605/*606* calculate and add the checksum, then write the header. A return of607* 0 tells the caller to now write the file data, 1 says no data needs608* to be written609*/610if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum,611sizeof(hd->chksum), 3))612goto out;613if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0)614return(-1);615if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)616return(-1);617if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))618return(0);619return(1);620621out:622/*623* header field is out of range624*/625paxwarn(1, "Tar header field is too small for %s", arcn->org_name);626return(1);627}628629/*630* Routines for POSIX ustar631*/632633/*634* ustar_strd()635* initialization for ustar read636* Return:637* 0 if ok, -1 otherwise638*/639640int641ustar_strd(void)642{643if ((usrtb_start() < 0) || (grptb_start() < 0))644return(-1);645return(0);646}647648/*649* ustar_stwr()650* initialization for ustar write651* Return:652* 0 if ok, -1 otherwise653*/654655int656ustar_stwr(void)657{658if ((uidtb_start() < 0) || (gidtb_start() < 0))659return(-1);660return(0);661}662663/*664* ustar_id()665* determine if a block given to us is a valid ustar header. We have to666* be on the lookout for those pesky blocks of all zero's667* Return:668* 0 if a ustar header, -1 otherwise669*/670671int672ustar_id(char *blk, int size)673{674HD_USTAR *hd;675676if (size < BLKMULT)677return(-1);678hd = (HD_USTAR *)blk;679680/*681* check for block of zero's first, a simple and fast test then check682* ustar magic cookie. We should use TMAGLEN, but some USTAR archive683* programs are fouled up and create archives missing the \0. Last we684* check the checksum. If ok we have to assume it is a valid header.685*/686if (hd->name[0] == '\0')687return(-1);688if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)689return(-1);690if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))691return(-1);692return(0);693}694695/*696* ustar_rd()697* extract the values out of block already determined to be a ustar header.698* store the values in the ARCHD parameter.699* Return:700* 0701*/702703int704ustar_rd(ARCHD *arcn, char *buf)705{706HD_USTAR *hd;707char *dest;708int cnt = 0;709dev_t devmajor;710dev_t devminor;711712/*713* we only get proper sized buffers714*/715if (ustar_id(buf, BLKMULT) < 0)716return(-1);717memset(arcn, 0, sizeof *arcn);718arcn->org_name = arcn->name;719arcn->sb.st_nlink = 1;720hd = (HD_USTAR *)buf;721722/*723* see if the filename is split into two parts. if, so joint the parts.724* we copy the prefix first and add a / between the prefix and name.725*/726dest = arcn->name;727if (*(hd->prefix) != '\0') {728cnt = l_strncpy(dest, hd->prefix,729MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2));730dest += cnt;731*dest++ = '/';732cnt++;733}734/*735* ustar format specifies the name may be unterminated736* if it fills the entire field. this also applies to737* the prefix and the linkname.738*/739arcn->nlen = cnt + l_strncpy(dest, hd->name,740MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1));741arcn->name[arcn->nlen] = '\0';742743/*744* follow the spec to the letter. we should only have mode bits, strip745* off all other crud we may be passed.746*/747arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &7480xfff);749arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);750arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);751arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;752753/*754* If we can find the ascii names for gname and uname in the password755* and group files we will use the uid's and gid they bind. Otherwise756* we use the uid and gid values stored in the header. (This is what757* the POSIX spec wants).758*/759hd->gname[sizeof(hd->gname) - 1] = '\0';760if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)761arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);762hd->uname[sizeof(hd->uname) - 1] = '\0';763if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)764arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);765766/*767* set the mode and PAX type according to the typeflag in the header768*/769switch(hd->typeflag) {770case FIFOTYPE:771arcn->type = PAX_FIF;772arcn->sb.st_mode |= S_IFIFO;773break;774case DIRTYPE:775arcn->type = PAX_DIR;776arcn->sb.st_mode |= S_IFDIR;777arcn->sb.st_nlink = 2;778779/*780* Some programs that create ustar archives append a '/'781* to the pathname for directories. This clearly violates782* ustar specs, but we will silently strip it off anyway.783*/784if (arcn->name[arcn->nlen - 1] == '/')785arcn->name[--arcn->nlen] = '\0';786break;787case BLKTYPE:788case CHRTYPE:789/*790* this type requires the rdev field to be set.791*/792if (hd->typeflag == BLKTYPE) {793arcn->type = PAX_BLK;794arcn->sb.st_mode |= S_IFBLK;795} else {796arcn->type = PAX_CHR;797arcn->sb.st_mode |= S_IFCHR;798}799devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);800devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);801arcn->sb.st_rdev = TODEV(devmajor, devminor);802break;803case SYMTYPE:804case LNKTYPE:805if (hd->typeflag == SYMTYPE) {806arcn->type = PAX_SLK;807arcn->sb.st_mode |= S_IFLNK;808} else {809arcn->type = PAX_HLK;810/*811* so printing looks better812*/813arcn->sb.st_mode |= S_IFREG;814arcn->sb.st_nlink = 2;815}816/*817* copy the link name818*/819arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,820MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1));821arcn->ln_name[arcn->ln_nlen] = '\0';822break;823case CONTTYPE:824case AREGTYPE:825case REGTYPE:826default:827/*828* these types have file data that follows. Set the skip and829* pad fields.830*/831arcn->type = PAX_REG;832arcn->pad = TAR_PAD(arcn->sb.st_size);833arcn->skip = arcn->sb.st_size;834arcn->sb.st_mode |= S_IFREG;835break;836}837return(0);838}839840/*841* ustar_wr()842* write a ustar header for the file specified in the ARCHD to the archive843* Have to check for file types that cannot be stored and file names that844* are too long. Be careful of the term (last arg) to ul_oct, we only use845* '\0' for the termination character (this is different than picky tar)846* ASSUMED: space after header in header block is zero filled847* Return:848* 0 if file has data to be written after the header, 1 if file has NO849* data to write after the header, -1 if archive write failed850*/851852int853ustar_wr(ARCHD *arcn)854{855HD_USTAR *hd;856char *pt;857HD_USTAR hdblk;858859/*860* check for those file system types ustar cannot store861*/862if (arcn->type == PAX_SCK) {863paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);864return(1);865}866867/*868* check the length of the linkname869*/870if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||871(arcn->type == PAX_HRG)) &&872(arcn->ln_nlen > (int)sizeof(hd->linkname))) {873paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);874return(1);875}876877/*878* split the path name into prefix and name fields (if needed). if879* pt != arcn->name, the name has to be split880*/881if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {882paxwarn(1, "File name too long for ustar %s", arcn->name);883return(1);884}885hd = &hdblk;886arcn->pad = 0L;887888/*889* split the name, or zero out the prefix890*/891if (pt != arcn->name) {892/*893* name was split, pt points at the / where the split is to894* occur, we remove the / and copy the first part to the prefix895*/896*pt = '\0';897l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));898*pt++ = '/';899} else900memset(hd->prefix, 0, sizeof(hd->prefix));901902/*903* copy the name part. this may be the whole path or the part after904* the prefix. both the name and prefix may fill the entire field.905*/906l_strncpy(hd->name, pt, sizeof(hd->name));907908/*909* set the fields in the header that are type dependent910*/911switch(arcn->type) {912case PAX_DIR:913hd->typeflag = DIRTYPE;914memset(hd->linkname, 0, sizeof(hd->linkname));915memset(hd->devmajor, 0, sizeof(hd->devmajor));916memset(hd->devminor, 0, sizeof(hd->devminor));917if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))918goto out;919break;920case PAX_CHR:921case PAX_BLK:922if (arcn->type == PAX_CHR)923hd->typeflag = CHRTYPE;924else925hd->typeflag = BLKTYPE;926memset(hd->linkname, 0, sizeof(hd->linkname));927if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,928sizeof(hd->devmajor), 3) ||929ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,930sizeof(hd->devminor), 3) ||931ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))932goto out;933break;934case PAX_FIF:935hd->typeflag = FIFOTYPE;936memset(hd->linkname, 0, sizeof(hd->linkname));937memset(hd->devmajor, 0, sizeof(hd->devmajor));938memset(hd->devminor, 0, sizeof(hd->devminor));939if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))940goto out;941break;942case PAX_SLK:943case PAX_HLK:944case PAX_HRG:945if (arcn->type == PAX_SLK)946hd->typeflag = SYMTYPE;947else948hd->typeflag = LNKTYPE;949/* the link name may occupy the entire field in ustar */950l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));951memset(hd->devmajor, 0, sizeof(hd->devmajor));952memset(hd->devminor, 0, sizeof(hd->devminor));953if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))954goto out;955break;956case PAX_REG:957case PAX_CTG:958default:959/*960* file data with this type, set the padding961*/962if (arcn->type == PAX_CTG)963hd->typeflag = CONTTYPE;964else965hd->typeflag = REGTYPE;966memset(hd->linkname, 0, sizeof(hd->linkname));967memset(hd->devmajor, 0, sizeof(hd->devmajor));968memset(hd->devminor, 0, sizeof(hd->devminor));969arcn->pad = TAR_PAD(arcn->sb.st_size);970if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,971sizeof(hd->size), 3)) {972paxwarn(1,"File is too long for ustar %s",arcn->org_name);973return(1);974}975break;976}977978l_strncpy(hd->magic, TMAGIC, TMAGLEN);979l_strncpy(hd->version, TVERSION, TVERSLEN);980981/*982* set the remaining fields. Some versions want all 16 bits of mode983* we better humor them (they really do not meet spec though)....984*/985if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||986ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) ||987ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||988ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))989goto out;990l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));991l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));992993/*994* calculate and store the checksum write the header to the archive995* return 0 tells the caller to now write the file data, 1 says no data996* needs to be written997*/998if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum,999sizeof(hd->chksum), 3))1000goto out;1001if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0)1002return(-1);1003if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)1004return(-1);1005if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))1006return(0);1007return(1);10081009out:1010/*1011* header field is out of range1012*/1013paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);1014return(1);1015}10161017/*1018* name_split()1019* see if the name has to be split for storage in a ustar header. We try1020* to fit the entire name in the name field without splitting if we can.1021* The split point is always at a /1022* Return1023* character pointer to split point (always the / that is to be removed1024* if the split is not needed, the points is set to the start of the file1025* name (it would violate the spec to split there). A NULL is returned if1026* the file name is too long1027*/10281029static char *1030name_split(char *name, int len)1031{1032char *start;10331034/*1035* check to see if the file name is small enough to fit in the name1036* field. if so just return a pointer to the name.1037*/1038if (len <= TNMSZ)1039return(name);1040if (len > TPFSZ + TNMSZ)1041return(NULL);10421043/*1044* we start looking at the biggest sized piece that fits in the name1045* field. We walk forward looking for a slash to split at. The idea is1046* to find the biggest piece to fit in the name field (or the smallest1047* prefix we can find)1048*/1049start = name + len - TNMSZ;1050while ((*start != '\0') && (*start != '/'))1051++start;10521053/*1054* if we hit the end of the string, this name cannot be split, so we1055* cannot store this file.1056*/1057if (*start == '\0')1058return(NULL);1059len = start - name;10601061/*1062* NOTE: /str where the length of str == TNMSZ can not be stored under1063* the p1003.1-1990 spec for ustar. We could force a prefix of / and1064* the file would then expand on extract to //str. The len == 0 below1065* makes this special case follow the spec to the letter.1066*/1067if ((len > TPFSZ) || (len == 0))1068return(NULL);10691070/*1071* ok have a split point, return it to the caller1072*/1073return(start);1074}107510761077