tar.c revision 102230
1193326Sed/*- 2193326Sed * Copyright (c) 1992 Keith Muller. 3193326Sed * Copyright (c) 1992, 1993 4193326Sed * The Regents of the University of California. All rights reserved. 5193326Sed * 6193326Sed * This code is derived from software contributed to Berkeley by 7193326Sed * Keith Muller of the University of California, San Diego. 8193326Sed * 9193326Sed * Redistribution and use in source and binary forms, with or without 10193326Sed * modification, are permitted provided that the following conditions 11193326Sed * are met: 12193326Sed * 1. Redistributions of source code must retain the above copyright 13193326Sed * notice, this list of conditions and the following disclaimer. 14193326Sed * 2. Redistributions in binary form must reproduce the above copyright 15198092Srdivacky * notice, this list of conditions and the following disclaimer in the 16193326Sed * documentation and/or other materials provided with the distribution. 17193326Sed * 3. All advertising materials mentioning features or use of this software 18193326Sed * must display the following acknowledgement: 19193326Sed * This product includes software developed by the University of 20193326Sed * California, Berkeley and its contributors. 21193326Sed * 4. Neither the name of the University nor the names of its contributors 22193326Sed * may be used to endorse or promote products derived from this software 23218893Sdim * without specific prior written permission. 24218893Sdim * 25223017Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26194179Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27218893Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29198893Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30198092Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34207619Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35207619Srdivacky * SUCH DAMAGE. 36207619Srdivacky */ 37207619Srdivacky 38207619Srdivacky#ifndef lint 39221345Sdim#if 0 40221345Sdimstatic char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; 41207619Srdivacky#endif 42221345Sdim#endif /* not lint */ 43207619Srdivacky#include <sys/cdefs.h> 44221345Sdim__FBSDID("$FreeBSD: head/bin/pax/tar.c 102230 2002-08-21 17:32:44Z trhodes $"); 45207619Srdivacky 46221345Sdim#include <sys/types.h> 47207619Srdivacky#include <sys/time.h> 48212904Sdim#include <sys/stat.h> 49207619Srdivacky#include <string.h> 50207619Srdivacky#include <stdio.h> 51207619Srdivacky#include <unistd.h> 52207619Srdivacky#include <stdlib.h> 53207619Srdivacky#include "pax.h" 54207619Srdivacky#include "extern.h" 55210299Sed#include "tar.h" 56210299Sed 57221345Sdim/* 58207619Srdivacky * Routines for reading, writing and header identify of various versions of tar 59207619Srdivacky */ 60221345Sdim 61207619Srdivackystatic u_long tar_chksm(char *, int); 62207619Srdivackystatic char *name_split(char *, int); 63212904Sdimstatic int ul_oct(u_long, char *, int, int); 64212904Sdim#ifndef NET2_STAT 65212904Sdimstatic int uqd_oct(u_quad_t, char *, int, int); 66212904Sdim#endif 67212904Sdim 68212904Sdim/* 69212904Sdim * Routines common to all versions of tar 70212904Sdim */ 71207619Srdivacky 72207619Srdivackystatic int tar_nodir; /* do not write dirs under old tar */ 73212904Sdim 74212904Sdim/* 75212904Sdim * tar_endwr() 76207619Srdivacky * add the tar trailer of two null blocks 77207619Srdivacky * Return: 78207619Srdivacky * 0 if ok, -1 otherwise (what wr_skip returns) 79207619Srdivacky */ 80212904Sdim 81212904Sdimint 82207619Srdivackytar_endwr(void) 83207619Srdivacky{ 84207619Srdivacky return(wr_skip((off_t)(NULLCNT*BLKMULT))); 85207619Srdivacky} 86221345Sdim 87207619Srdivacky/* 88207619Srdivacky * tar_endrd() 89207619Srdivacky * no cleanup needed here, just return size of trailer (for append) 90207619Srdivacky * Return: 91207619Srdivacky * size of trailer (2 * BLKMULT) 92207619Srdivacky */ 93218893Sdim 94218893Sdimoff_t 95218893Sdimtar_endrd(void) 96218893Sdim{ 97218893Sdim return((off_t)(NULLCNT*BLKMULT)); 98218893Sdim} 99218893Sdim 100218893Sdim/* 101218893Sdim * tar_trail() 102218893Sdim * Called to determine if a header block is a valid trailer. We are passed 103218893Sdim * the block, the in_sync flag (which tells us we are in resync mode; 104218893Sdim * looking for a valid header), and cnt (which starts at zero) which is 105218893Sdim * used to count the number of empty blocks we have seen so far. 106218893Sdim * Return: 107218893Sdim * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block 108218893Sdim * could never contain a header. 109218893Sdim */ 110218893Sdim 111218893Sdimint 112218893Sdimtar_trail(char *buf, int in_resync, int *cnt) 113218893Sdim{ 114218893Sdim int i; 115218893Sdim 116218893Sdim /* 117218893Sdim * look for all zero, trailer is two consecutive blocks of zero 118218893Sdim */ 119218893Sdim for (i = 0; i < BLKMULT; ++i) { 120218893Sdim if (buf[i] != '\0') 121218893Sdim break; 122218893Sdim } 123218893Sdim 124218893Sdim /* 125218893Sdim * if not all zero it is not a trailer, but MIGHT be a header. 126218893Sdim */ 127218893Sdim if (i != BLKMULT) 128218893Sdim return(-1); 129193326Sed 130193326Sed /* 131193326Sed * When given a zero block, we must be careful! 132193326Sed * If we are not in resync mode, check for the trailer. Have to watch 133224145Sdim * out that we do not mis-identify file data as the trailer, so we do 134224145Sdim * NOT try to id a trailer during resync mode. During resync mode we 135218893Sdim * might as well throw this block out since a valid header can NEVER be 136218893Sdim * a block of all 0 (we must have a valid file name). 137218893Sdim */ 138224145Sdim if (!in_resync && (++*cnt >= NULLCNT)) 139224145Sdim return(0); 140199990Srdivacky return(1); 141199990Srdivacky} 142224145Sdim 143199990Srdivacky/* 144199990Srdivacky * ul_oct() 145199990Srdivacky * convert an unsigned long to an octal string. many oddball field 146199990Srdivacky * termination characters are used by the various versions of tar in the 147199990Srdivacky * different fields. term selects which kind to use. str is '0' padded 148199990Srdivacky * at the front to len. we are unable to use only one format as many old 149199990Srdivacky * tar readers are very cranky about this. 150199990Srdivacky * Return: 151218893Sdim * 0 if the number fit into the string, -1 otherwise 152199990Srdivacky */ 153199990Srdivacky 154218893Sdimstatic int 155199990Srdivackyul_oct(u_long val, char *str, int len, int term) 156199990Srdivacky{ 157224145Sdim char *pt; 158218893Sdim 159224145Sdim /* 160224145Sdim * term selects the appropriate character(s) for the end of the string 161199990Srdivacky */ 162218893Sdim pt = str + len - 1; 163199990Srdivacky switch(term) { 164218893Sdim case 3: 165224145Sdim *pt-- = '\0'; 166224145Sdim break; 167224145Sdim case 2: 168224145Sdim *pt-- = ' '; 169224145Sdim *pt-- = '\0'; 170224145Sdim break; 171224145Sdim case 1: 172224145Sdim *pt-- = ' '; 173224145Sdim break; 174224145Sdim case 0: 175224145Sdim default: 176199990Srdivacky *pt-- = '\0'; 177224145Sdim *pt-- = ' '; 178218893Sdim break; 179218893Sdim } 180199990Srdivacky 181224145Sdim /* 182218893Sdim * convert and blank pad if there is space 183199990Srdivacky */ 184218893Sdim while (pt >= str) { 185199990Srdivacky *pt-- = '0' + (char)(val & 0x7); 186199990Srdivacky if ((val = val >> 3) == (u_long)0) 187218893Sdim break; 188210299Sed } 189202879Srdivacky 190203955Srdivacky while (pt >= str) 191224145Sdim *pt-- = '0'; 192202879Srdivacky if (val != (u_long)0) 193224145Sdim return(-1); 194224145Sdim return(0); 195208600Srdivacky} 196218893Sdim 197208600Srdivacky#ifndef NET2_STAT 198208600Srdivacky/* 199208600Srdivacky * uqd_oct() 200208600Srdivacky * convert an u_quad_t to an octal string. one of many oddball field 201224145Sdim * termination characters are used by the various versions of tar in the 202208600Srdivacky * different fields. term selects which kind to use. str is '0' padded 203224145Sdim * at the front to len. we are unable to use only one format as many old 204224145Sdim * tar readers are very cranky about this. 205218893Sdim * Return: 206218893Sdim * 0 if the number fit into the string, -1 otherwise 207218893Sdim */ 208218893Sdim 209208600Srdivackystatic int 210208600Srdivackyuqd_oct(u_quad_t val, char *str, int len, int term) 211208600Srdivacky{ 212218893Sdim char *pt; 213208600Srdivacky 214224145Sdim /* 215218893Sdim * term selects the appropriate character(s) for the end of the string 216218893Sdim */ 217199990Srdivacky pt = str + len - 1; 218199990Srdivacky switch(term) { 219218893Sdim case 3: 220218893Sdim *pt-- = '\0'; 221218893Sdim break; 222224145Sdim case 2: 223224145Sdim *pt-- = ' '; 224224145Sdim *pt-- = '\0'; 225218893Sdim break; 226218893Sdim case 1: 227218893Sdim *pt-- = ' '; 228218893Sdim break; 229218893Sdim case 0: 230218893Sdim default: 231218893Sdim *pt-- = '\0'; 232218893Sdim *pt-- = ' '; 233218893Sdim break; 234218893Sdim } 235218893Sdim 236218893Sdim /* 237224145Sdim * convert and blank pad if there is space 238224145Sdim */ 239218893Sdim while (pt >= str) { 240218893Sdim *pt-- = '0' + (char)(val & 0x7); 241224145Sdim if ((val = val >> 3) == 0) 242218893Sdim break; 243218893Sdim } 244218893Sdim 245218893Sdim while (pt >= str) 246224145Sdim *pt-- = '0'; 247218893Sdim if (val != (u_quad_t)0) 248218893Sdim return(-1); 249218893Sdim return(0); 250218893Sdim} 251218893Sdim#endif 252218893Sdim 253221345Sdim/* 254212904Sdim * tar_chksm() 255221345Sdim * calculate the checksum for a tar block counting the checksum field as 256212904Sdim * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). 257218893Sdim * NOTE: we use len to short circuit summing 0's on write since we ALWAYS 258224145Sdim * pad headers with 0. 259221345Sdim * Return: 260221345Sdim * unsigned long checksum 261221345Sdim */ 262221345Sdim 263221345Sdimstatic u_long 264221345Sdimtar_chksm(char *blk, int len) 265221345Sdim{ 266221345Sdim char *stop; 267224145Sdim char *pt; 268224145Sdim u_long chksm = BLNKSUM; /* initial value is checksum field sum */ 269224145Sdim 270224145Sdim /* 271224145Sdim * add the part of the block before the checksum field 272224145Sdim */ 273224145Sdim pt = blk; 274224145Sdim stop = blk + CHK_OFFSET; 275224145Sdim while (pt < stop) 276224145Sdim chksm += (u_long)(*pt++ & 0xff); 277226633Sdim /* 278226633Sdim * move past the checksum field and keep going, spec counts the 279212904Sdim * checksum field as the sum of 8 blanks (which is pre-computed as 280212904Sdim * BLNKSUM). 281212904Sdim * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding 282198893Srdivacky * starts, no point in summing zero's) 283221345Sdim */ 284200583Srdivacky pt += CHK_LEN; 285198893Srdivacky stop = blk + len; 286199990Srdivacky while (pt < stop) 287218893Sdim chksm += (u_long)(*pt++ & 0xff); 288221345Sdim return(chksm); 289199990Srdivacky} 290221345Sdim 291212904Sdim/* 292221345Sdim * Routines for old BSD style tar (also made portable to sysV tar) 293212904Sdim */ 294212904Sdim 295212904Sdim/* 296221345Sdim * tar_id() 297212904Sdim * determine if a block given to us is a valid tar header (and not a USTAR 298212904Sdim * header). We have to be on the lookout for those pesky blocks of all 299212904Sdim * zero's. 300218893Sdim * Return: 301221345Sdim * 0 if a tar header, -1 otherwise 302212904Sdim */ 303221345Sdim 304221345Sdimint 305221345Sdimtar_id(char *blk, int size) 306221345Sdim{ 307198893Srdivacky HD_TAR *hd; 308221345Sdim HD_USTAR *uhd; 309221345Sdim 310221345Sdim if (size < BLKMULT) 311221345Sdim return(-1); 312199990Srdivacky hd = (HD_TAR *)blk; 313226633Sdim uhd = (HD_USTAR *)blk; 314221345Sdim 315218893Sdim /* 316221345Sdim * check for block of zero's first, a simple and fast test, then make 317221345Sdim * sure this is not a ustar header by looking for the ustar magic 318198893Srdivacky * cookie. We should use TMAGLEN, but some USTAR archive programs are 319198893Srdivacky * wrong and create archives missing the \0. Last we check the 320221345Sdim * checksum. If this is ok we have to assume it is a valid header. 321218893Sdim */ 322221345Sdim if (hd->name[0] == '\0') 323218893Sdim return(-1); 324210299Sed if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) 325210299Sed return(-1); 326210299Sed if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 327221345Sdim return(-1); 328221345Sdim return(0); 329221345Sdim} 330218893Sdim 331226633Sdim/* 332221345Sdim * tar_opt() 333218893Sdim * handle tar format specific -o options 334210299Sed * Return: 335210299Sed * 0 if ok -1 otherwise 336210299Sed */ 337198893Srdivacky 338212904Sdimint 339198893Srdivackytar_opt(void) 340221345Sdim{ 341212904Sdim OPLIST *opt; 342198893Srdivacky 343198893Srdivacky while ((opt = opt_next()) != NULL) { 344198893Srdivacky if (strcmp(opt->name, TAR_OPTION) || 345198893Srdivacky strcmp(opt->value, TAR_NODIR)) { 346198092Srdivacky paxwarn(1, "Unknown tar format -o option/value pair %s=%s", 347198092Srdivacky opt->name, opt->value); 348203955Srdivacky paxwarn(1,"%s=%s is the only supported tar format option", 349203955Srdivacky TAR_OPTION, TAR_NODIR); 350203955Srdivacky return(-1); 351198092Srdivacky } 352203955Srdivacky 353198092Srdivacky /* 354193326Sed * we only support one option, and only when writing 355198092Srdivacky */ 356198092Srdivacky if ((act != APPND) && (act != ARCHIVE)) { 357193326Sed paxwarn(1, "%s=%s is only supported when writing.", 358198092Srdivacky opt->name, opt->value); 359203955Srdivacky return(-1); 360198092Srdivacky } 361201361Srdivacky tar_nodir = 1; 362201361Srdivacky } 363198092Srdivacky return(0); 364193326Sed} 365198092Srdivacky 366193326Sed 367198092Srdivacky/* 368193326Sed * tar_rd() 369198092Srdivacky * extract the values out of block already determined to be a tar header. 370198092Srdivacky * store the values in the ARCHD parameter. 371198092Srdivacky * Return: 372198092Srdivacky * 0 373198092Srdivacky */ 374198092Srdivacky 375198092Srdivackyint 376198092Srdivackytar_rd(ARCHD *arcn, char *buf) 377198092Srdivacky{ 378198092Srdivacky HD_TAR *hd; 379198092Srdivacky char *pt; 380198092Srdivacky 381198092Srdivacky /* 382198092Srdivacky * we only get proper sized buffers passed to us 383198092Srdivacky */ 384198092Srdivacky if (tar_id(buf, BLKMULT) < 0) 385198092Srdivacky return(-1); 386198092Srdivacky arcn->org_name = arcn->name; 387198092Srdivacky arcn->sb.st_nlink = 1; 388198092Srdivacky arcn->pat = NULL; 389198092Srdivacky 390198092Srdivacky /* 391201361Srdivacky * copy out the name and values in the stat buffer 392201361Srdivacky */ 393201361Srdivacky hd = (HD_TAR *)buf; 394201361Srdivacky arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(arcn->name) - 1); 395201361Srdivacky arcn->name[arcn->nlen] = '\0'; 396201361Srdivacky arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 397201361Srdivacky 0xfff); 398201361Srdivacky arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 399200583Srdivacky arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 400200583Srdivacky#ifdef NET2_STAT 401198092Srdivacky arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 402198092Srdivacky arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 403198092Srdivacky#else 404198092Srdivacky arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 405198092Srdivacky arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 406198092Srdivacky#endif 407198092Srdivacky arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 408198092Srdivacky 409198092Srdivacky /* 410198092Srdivacky * have to look at the last character, it may be a '/' and that is used 411198092Srdivacky * to encode this as a directory 412205408Srdivacky */ 413205408Srdivacky pt = &(arcn->name[arcn->nlen - 1]); 414205408Srdivacky arcn->pad = 0; 415205408Srdivacky arcn->skip = 0; 416226633Sdim switch(hd->linkflag) { 417205408Srdivacky case SYMTYPE: 418198092Srdivacky /* 419207619Srdivacky * symbolic link, need to get the link name and set the type in 420207619Srdivacky * the st_mode so -v printing will look correct. 421207619Srdivacky */ 422198092Srdivacky arcn->type = PAX_SLK; 423198092Srdivacky arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 424198092Srdivacky sizeof(arcn->ln_name) - 1); 425198092Srdivacky arcn->ln_name[arcn->ln_nlen] = '\0'; 426198092Srdivacky arcn->sb.st_mode |= S_IFLNK; 427198092Srdivacky break; 428198092Srdivacky case LNKTYPE: 429198092Srdivacky /* 430198092Srdivacky * hard link, need to get the link name, set the type in the 431198092Srdivacky * st_mode and st_nlink so -v printing will look better. 432198092Srdivacky */ 433198092Srdivacky arcn->type = PAX_HLK; 434193326Sed arcn->sb.st_nlink = 2; 435193326Sed arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 436212904Sdim sizeof(arcn->ln_name) - 1); 437212904Sdim arcn->ln_name[arcn->ln_nlen] = '\0'; 438212904Sdim 439212904Sdim /* 440212904Sdim * no idea of what type this thing really points at, but 441212904Sdim * we set something for printing only. 442212904Sdim */ 443212904Sdim arcn->sb.st_mode |= S_IFREG; 444212904Sdim break; 445212904Sdim case DIRTYPE: 446212904Sdim /* 447212904Sdim * It is a directory, set the mode for -v printing 448212904Sdim */ 449212904Sdim arcn->type = PAX_DIR; 450212904Sdim arcn->sb.st_mode |= S_IFDIR; 451212904Sdim arcn->sb.st_nlink = 2; 452212904Sdim arcn->ln_name[0] = '\0'; 453212904Sdim arcn->ln_nlen = 0; 454212904Sdim break; 455212904Sdim case AREGTYPE: 456212904Sdim case REGTYPE: 457212904Sdim default: 458212904Sdim /* 459212904Sdim * If we have a trailing / this is a directory and NOT a file. 460212904Sdim */ 461212904Sdim arcn->ln_name[0] = '\0'; 462212904Sdim arcn->ln_nlen = 0; 463212904Sdim if (*pt == '/') { 464212904Sdim /* 465212904Sdim * it is a directory, set the mode for -v printing 466212904Sdim */ 467212904Sdim arcn->type = PAX_DIR; 468212904Sdim arcn->sb.st_mode |= S_IFDIR; 469212904Sdim arcn->sb.st_nlink = 2; 470212904Sdim } else { 471212904Sdim /* 472212904Sdim * have a file that will be followed by data. Set the 473212904Sdim * skip value to the size field and calculate the size 474193326Sed * of the padding. 475193326Sed */ 476193326Sed arcn->type = PAX_REG; 477193326Sed arcn->sb.st_mode |= S_IFREG; 478193326Sed arcn->pad = TAR_PAD(arcn->sb.st_size); 479193326Sed arcn->skip = arcn->sb.st_size; 480193326Sed } 481193326Sed break; 482193326Sed } 483193326Sed 484193326Sed /* 485226633Sdim * strip off any trailing slash. 486226633Sdim */ 487198092Srdivacky if (*pt == '/') { 488193326Sed *pt = '\0'; 489193326Sed --arcn->nlen; 490193326Sed } 491193326Sed return(0); 492193326Sed} 493218893Sdim 494193326Sed/* 495198092Srdivacky * tar_wr() 496193326Sed * write a tar header for the file specified in the ARCHD to the archive. 497224145Sdim * Have to check for file types that cannot be stored and file names that 498224145Sdim * are too long. Be careful of the term (last arg) to ul_oct, each field 499193326Sed * of tar has it own spec for the termination character(s). 500224145Sdim * ASSUMED: space after header in header block is zero filled 501226633Sdim * Return: 502221345Sdim * 0 if file has data to be written after the header, 1 if file has NO 503193326Sed * data to write after the header, -1 if archive write failed 504193326Sed */ 505193326Sed 506193326Sedint 507193326Sedtar_wr(ARCHD *arcn) 508193326Sed{ 509193326Sed HD_TAR *hd; 510193326Sed int len; 511193326Sed char hdblk[sizeof(HD_TAR)]; 512193326Sed 513193326Sed /* 514218893Sdim * check for those file system types which tar cannot store 515193326Sed */ 516193326Sed switch(arcn->type) { 517193326Sed case PAX_DIR: 518193326Sed /* 519193326Sed * user asked that dirs not be written to the archive 520193326Sed */ 521193326Sed if (tar_nodir) 522226633Sdim return(1); 523198092Srdivacky break; 524198092Srdivacky case PAX_CHR: 525193326Sed paxwarn(1, "Tar cannot archive a character device %s", 526198092Srdivacky arcn->org_name); 527193326Sed return(1); 528193326Sed case PAX_BLK: 529218893Sdim paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); 530218893Sdim return(1); 531218893Sdim case PAX_SCK: 532218893Sdim paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); 533218893Sdim return(1); 534218893Sdim case PAX_FIF: 535218893Sdim paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); 536218893Sdim return(1); 537218893Sdim case PAX_SLK: 538218893Sdim case PAX_HLK: 539226633Sdim case PAX_HRG: 540226633Sdim if (arcn->ln_nlen > sizeof(hd->linkname)) { 541218893Sdim paxwarn(1,"Link name too long for tar %s", arcn->ln_name); 542218893Sdim return(1); 543218893Sdim } 544218893Sdim break; 545218893Sdim case PAX_REG: 546218893Sdim case PAX_CTG: 547218893Sdim default: 548218893Sdim break; 549218893Sdim } 550218893Sdim 551218893Sdim /* 552218893Sdim * check file name len, remember extra char for dirs (the / at the end) 553218893Sdim */ 554218893Sdim len = arcn->nlen; 555218893Sdim if (arcn->type == PAX_DIR) 556226633Sdim ++len; 557218893Sdim if (len >= sizeof(hd->name)) { 558218893Sdim paxwarn(1, "File name too long for tar %s", arcn->name); 559218893Sdim return(1); 560218893Sdim } 561218893Sdim 562218893Sdim /* 563218893Sdim * copy the data out of the ARCHD into the tar header based on the type 564218893Sdim * of the file. Remember many tar readers want the unused fields to be 565218893Sdim * padded with zero. We set the linkflag field (type), the linkname 566218893Sdim * (or zero if not used),the size, and set the padding (if any) to be 567218893Sdim * added after the file data (0 for all other types, as they only have 568218893Sdim * a header) 569218893Sdim */ 570218893Sdim hd = (HD_TAR *)hdblk; 571218893Sdim l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); 572218893Sdim hd->name[sizeof(hd->name) - 1] = '\0'; 573218893Sdim arcn->pad = 0; 574218893Sdim 575218893Sdim if (arcn->type == PAX_DIR) { 576218893Sdim /* 577218893Sdim * directories are the same as files, except have a filename 578218893Sdim * that ends with a /, we add the slash here. No data follows, 579224145Sdim * dirs, so no pad. 580218893Sdim */ 581218893Sdim hd->linkflag = AREGTYPE; 582218893Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 583218893Sdim hd->name[len-1] = '/'; 584218893Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 585218893Sdim goto out; 586218893Sdim } else if (arcn->type == PAX_SLK) { 587218893Sdim /* 588218893Sdim * no data follows this file, so no pad 589218893Sdim */ 590218893Sdim hd->linkflag = SYMTYPE; 591218893Sdim l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 592218893Sdim hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 593218893Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 594218893Sdim goto out; 595193326Sed } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 596193326Sed /* 597193326Sed * no data follows this file, so no pad 598193326Sed */ 599226633Sdim hd->linkflag = LNKTYPE; 600212904Sdim l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 601212904Sdim hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 602212904Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 603212904Sdim goto out; 604212904Sdim } else { 605212904Sdim /* 606212904Sdim * data follows this file, so set the pad 607212904Sdim */ 608212904Sdim hd->linkflag = AREGTYPE; 609212904Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 610212904Sdim# ifdef NET2_STAT 611212904Sdim if (ul_oct((u_long)arcn->sb.st_size, hd->size, 612212904Sdim sizeof(hd->size), 1)) { 613193326Sed# else 614193326Sed if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 615193326Sed sizeof(hd->size), 1)) { 616212904Sdim# endif 617193326Sed paxwarn(1,"File is too large for tar %s", arcn->org_name); 618193326Sed return(1); 619226633Sdim } 620212904Sdim arcn->pad = TAR_PAD(arcn->sb.st_size); 621212904Sdim } 622212904Sdim 623212904Sdim /* 624212904Sdim * copy those fields that are independent of the type 625212904Sdim */ 626212904Sdim if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || 627212904Sdim ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || 628193326Sed ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || 629193326Sed ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) 630193326Sed goto out; 631193326Sed 632193326Sed /* 633212904Sdim * calculate and add the checksum, then write the header. A return of 634212904Sdim * 0 tells the caller to now write the file data, 1 says no data needs 635212904Sdim * to be written 636212904Sdim */ 637212904Sdim if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, 638212904Sdim sizeof(hd->chksum), 3)) 639212904Sdim goto out; 640212904Sdim if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) 641193326Sed return(-1); 642193326Sed if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) 643193326Sed return(-1); 644193326Sed if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 645193326Sed return(0); 646193326Sed return(1); 647193326Sed 648193326Sed out: 649193326Sed /* 650218893Sdim * header field is out of range 651218893Sdim */ 652218893Sdim paxwarn(1, "Tar header field is too small for %s", arcn->org_name); 653218893Sdim return(1); 654218893Sdim} 655218893Sdim 656224145Sdim/* 657218893Sdim * Routines for POSIX ustar 658193326Sed */ 659198092Srdivacky 660218893Sdim/* 661193326Sed * ustar_strd() 662218893Sdim * initialization for ustar read 663218893Sdim * Return: 664218893Sdim * 0 if ok, -1 otherwise 665218893Sdim */ 666218893Sdim 667224145Sdimint 668224145Sdimustar_strd(void) 669218893Sdim{ 670218893Sdim if ((usrtb_start() < 0) || (grptb_start() < 0)) 671193326Sed return(-1); 672218893Sdim return(0); 673218893Sdim} 674218893Sdim 675218893Sdim/* 676193326Sed * ustar_stwr() 677193326Sed * initialization for ustar write 678193326Sed * Return: 679193326Sed * 0 if ok, -1 otherwise 680218893Sdim */ 681218893Sdim 682218893Sdimint 683218893Sdimustar_stwr(void) 684224145Sdim{ 685218893Sdim if ((uidtb_start() < 0) || (gidtb_start() < 0)) 686193326Sed return(-1); 687193326Sed return(0); 688218893Sdim} 689193326Sed 690218893Sdim/* 691218893Sdim * ustar_id() 692218893Sdim * determine if a block given to us is a valid ustar header. We have to 693218893Sdim * be on the lookout for those pesky blocks of all zero's 694218893Sdim * Return: 695224145Sdim * 0 if a ustar header, -1 otherwise 696224145Sdim */ 697218893Sdim 698218893Sdimint 699193326Sedustar_id(char *blk, int size) 700218893Sdim{ 701218893Sdim HD_USTAR *hd; 702218893Sdim 703218893Sdim if (size < BLKMULT) 704193326Sed return(-1); 705193326Sed hd = (HD_USTAR *)blk; 706193326Sed 707198092Srdivacky /* 708198092Srdivacky * check for block of zero's first, a simple and fast test then check 709218893Sdim * ustar magic cookie. We should use TMAGLEN, but some USTAR archive 710218893Sdim * programs are fouled up and create archives missing the \0. Last we 711218893Sdim * check the checksum. If ok we have to assume it is a valid header. 712193326Sed */ 713193326Sed if (hd->name[0] == '\0') 714218893Sdim return(-1); 715218893Sdim if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) 716218893Sdim return(-1); 717218893Sdim if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 718218893Sdim return(-1); 719218893Sdim return(0); 720218893Sdim} 721218893Sdim 722201361Srdivacky/* 723226633Sdim * ustar_rd() 724226633Sdim * extract the values out of block already determined to be a ustar header. 725226633Sdim * store the values in the ARCHD parameter. 726226633Sdim * Return: 727226633Sdim * 0 728226633Sdim */ 729226633Sdim 730218893Sdimint 731218893Sdimustar_rd(ARCHD *arcn, char *buf) 732218893Sdim{ 733218893Sdim HD_USTAR *hd; 734218893Sdim char *dest; 735218893Sdim int cnt = 0; 736218893Sdim dev_t devmajor; 737218893Sdim dev_t devminor; 738198092Srdivacky 739201361Srdivacky /* 740201361Srdivacky * we only get proper sized buffers 741201361Srdivacky */ 742198092Srdivacky if (ustar_id(buf, BLKMULT) < 0) 743198092Srdivacky return(-1); 744198092Srdivacky arcn->org_name = arcn->name; 745198092Srdivacky arcn->sb.st_nlink = 1; 746201361Srdivacky arcn->pat = NULL; 747201361Srdivacky arcn->nlen = 0; 748201361Srdivacky hd = (HD_USTAR *)buf; 749201361Srdivacky 750193326Sed /* 751193326Sed * see if the filename is split into two parts. if, so joint the parts. 752193326Sed * we copy the prefix first and add a / between the prefix and name. 753193326Sed */ 754193326Sed dest = arcn->name; 755193326Sed if (*(hd->prefix) != '\0') { 756198092Srdivacky cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2); 757193326Sed dest += cnt; 758193326Sed *dest++ = '/'; 759193326Sed cnt++; 760193326Sed } 761193326Sed arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt); 762193326Sed arcn->name[arcn->nlen] = '\0'; 763193326Sed 764218893Sdim /* 765218893Sdim * follow the spec to the letter. we should only have mode bits, strip 766193326Sed * off all other crud we may be passed. 767218893Sdim */ 768193326Sed arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 769193326Sed 0xfff); 770218893Sdim#ifdef NET2_STAT 771218893Sdim arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 772193326Sed arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 773198092Srdivacky#else 774193326Sed arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 775193326Sed arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 776193326Sed#endif 777193326Sed arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 778193326Sed 779193326Sed /* 780193326Sed * If we can find the ascii names for gname and uname in the password 781218893Sdim * and group files we will use the uid's and gid they bind. Otherwise 782193326Sed * we use the uid and gid values stored in the header. (This is what 783198092Srdivacky * the POSIX spec wants). 784193326Sed */ 785193326Sed hd->gname[sizeof(hd->gname) - 1] = '\0'; 786193326Sed if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) 787193326Sed arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 788198092Srdivacky hd->uname[sizeof(hd->uname) - 1] = '\0'; 789193326Sed if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) 790193326Sed arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 791193326Sed 792198092Srdivacky /* 793193326Sed * set the defaults, these may be changed depending on the file type 794193326Sed */ 795193326Sed arcn->ln_name[0] = '\0'; 796198092Srdivacky arcn->ln_nlen = 0; 797193326Sed arcn->pad = 0; 798193326Sed arcn->skip = 0; 799193326Sed arcn->sb.st_rdev = (dev_t)0; 800198092Srdivacky 801193326Sed /* 802193326Sed * set the mode and PAX type according to the typeflag in the header 803193326Sed */ 804193326Sed switch(hd->typeflag) { 805198092Srdivacky case FIFOTYPE: 806193326Sed arcn->type = PAX_FIF; 807198092Srdivacky arcn->sb.st_mode |= S_IFIFO; 808193326Sed break; 809221345Sdim case DIRTYPE: 810221345Sdim arcn->type = PAX_DIR; 811221345Sdim arcn->sb.st_mode |= S_IFDIR; 812210299Sed arcn->sb.st_nlink = 2; 813221345Sdim 814193326Sed /* 815193326Sed * Some programs that create ustar archives append a '/' 816193326Sed * to the pathname for directories. This clearly violates 817219077Sdim * ustar specs, but we will silently strip it off anyway. 818219077Sdim */ 819219077Sdim if (arcn->name[arcn->nlen - 1] == '/') 820219077Sdim arcn->name[--arcn->nlen] = '\0'; 821219077Sdim break; 822219077Sdim case BLKTYPE: 823219077Sdim case CHRTYPE: 824219077Sdim /* 825219077Sdim * this type requires the rdev field to be set. 826219077Sdim */ 827219077Sdim if (hd->typeflag == BLKTYPE) { 828219077Sdim arcn->type = PAX_BLK; 829219077Sdim arcn->sb.st_mode |= S_IFBLK; 830207619Srdivacky } else { 831207619Srdivacky arcn->type = PAX_CHR; 832207619Srdivacky arcn->sb.st_mode |= S_IFCHR; 833207619Srdivacky } 834207619Srdivacky devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); 835207619Srdivacky devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); 836207619Srdivacky arcn->sb.st_rdev = TODEV(devmajor, devminor); 837207619Srdivacky break; 838207619Srdivacky case SYMTYPE: 839207619Srdivacky case LNKTYPE: 840207619Srdivacky if (hd->typeflag == SYMTYPE) { 841207619Srdivacky arcn->type = PAX_SLK; 842207619Srdivacky arcn->sb.st_mode |= S_IFLNK; 843207619Srdivacky } else { 844207619Srdivacky arcn->type = PAX_HLK; 845207619Srdivacky /* 846207619Srdivacky * so printing looks better 847207619Srdivacky */ 848207619Srdivacky arcn->sb.st_mode |= S_IFREG; 849207619Srdivacky arcn->sb.st_nlink = 2; 850207619Srdivacky } 851207619Srdivacky /* 852207619Srdivacky * copy the link name 853207619Srdivacky */ 854207619Srdivacky arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 855207619Srdivacky sizeof(arcn->ln_name) - 1); 856207619Srdivacky arcn->ln_name[arcn->ln_nlen] = '\0'; 857218893Sdim break; 858218893Sdim case CONTTYPE: 859218893Sdim case AREGTYPE: 860224145Sdim case REGTYPE: 861218893Sdim default: 862207619Srdivacky /* 863207619Srdivacky * these types have file data that follows. Set the skip and 864207619Srdivacky * pad fields. 865207619Srdivacky */ 866207619Srdivacky arcn->type = PAX_REG; 867207619Srdivacky arcn->pad = TAR_PAD(arcn->sb.st_size); 868207619Srdivacky arcn->skip = arcn->sb.st_size; 869207619Srdivacky arcn->sb.st_mode |= S_IFREG; 870218893Sdim break; 871218893Sdim } 872218893Sdim return(0); 873218893Sdim} 874218893Sdim 875207619Srdivacky/* 876207619Srdivacky * ustar_wr() 877207619Srdivacky * write a ustar header for the file specified in the ARCHD to the archive 878207619Srdivacky * Have to check for file types that cannot be stored and file names that 879207619Srdivacky * are too long. Be careful of the term (last arg) to ul_oct, we only use 880207619Srdivacky * '\0' for the termination character (this is different than picky tar) 881207619Srdivacky * ASSUMED: space after header in header block is zero filled 882207619Srdivacky * Return: 883207619Srdivacky * 0 if file has data to be written after the header, 1 if file has NO 884207619Srdivacky * data to write after the header, -1 if archive write failed 885207619Srdivacky */ 886207619Srdivacky 887198092Srdivackyint 888221345Sdimustar_wr(ARCHD *arcn) 889200583Srdivacky{ 890207619Srdivacky HD_USTAR *hd; 891212904Sdim char *pt; 892199990Srdivacky char hdblk[sizeof(HD_USTAR)]; 893218893Sdim 894218893Sdim /* 895218893Sdim * check for those file system types ustar cannot store 896198092Srdivacky */ 897198092Srdivacky if (arcn->type == PAX_SCK) { 898221345Sdim paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); 899207619Srdivacky return(1); 900207619Srdivacky } 901206084Srdivacky 902206084Srdivacky /* 903206084Srdivacky * check the length of the linkname 904199990Srdivacky */ 905226633Sdim if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 906198092Srdivacky (arcn->type == PAX_HRG)) && (arcn->ln_nlen >= sizeof(hd->linkname))){ 907218893Sdim paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); 908218893Sdim return(1); 909218893Sdim } 910206084Srdivacky 911206084Srdivacky /* 912221345Sdim * split the path name into prefix and name fields (if needed). if 913221345Sdim * pt != arcn->name, the name has to be split 914206084Srdivacky */ 915206084Srdivacky if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { 916224145Sdim paxwarn(1, "File name too long for ustar %s", arcn->name); 917224145Sdim return(1); 918224145Sdim } 919224145Sdim hd = (HD_USTAR *)hdblk; 920224145Sdim arcn->pad = 0L; 921224145Sdim 922206084Srdivacky /* 923206084Srdivacky * split the name, or zero out the prefix 924206084Srdivacky */ 925221345Sdim if (pt != arcn->name) { 926206084Srdivacky /* 927206084Srdivacky * name was split, pt points at the / where the split is to 928206084Srdivacky * occur, we remove the / and copy the first part to the prefix 929206084Srdivacky */ 930224145Sdim *pt = '\0'; 931224145Sdim l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1); 932224145Sdim *pt++ = '/'; 933206084Srdivacky } else 934224145Sdim memset(hd->prefix, 0, sizeof(hd->prefix)); 935224145Sdim 936224145Sdim /* 937224145Sdim * copy the name part. this may be the whole path or the part after 938224145Sdim * the prefix 939206084Srdivacky */ 940206084Srdivacky l_strncpy(hd->name, pt, sizeof(hd->name) - 1); 941206084Srdivacky hd->name[sizeof(hd->name) - 1] = '\0'; 942198092Srdivacky 943198092Srdivacky /* 944221345Sdim * set the fields in the header that are type dependent 945221345Sdim */ 946221345Sdim switch(arcn->type) { 947221345Sdim case PAX_DIR: 948221345Sdim hd->typeflag = DIRTYPE; 949221345Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 950221345Sdim memset(hd->devmajor, 0, sizeof(hd->devmajor)); 951221345Sdim memset(hd->devminor, 0, sizeof(hd->devminor)); 952221345Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 953221345Sdim goto out; 954221345Sdim break; 955221345Sdim case PAX_CHR: 956221345Sdim case PAX_BLK: 957221345Sdim if (arcn->type == PAX_CHR) 958221345Sdim hd->typeflag = CHRTYPE; 959221345Sdim else 960221345Sdim hd->typeflag = BLKTYPE; 961221345Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 962221345Sdim if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, 963221345Sdim sizeof(hd->devmajor), 3) || 964221345Sdim ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, 965221345Sdim sizeof(hd->devminor), 3) || 966226633Sdim ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 967226633Sdim goto out; 968226633Sdim break; 969226633Sdim case PAX_FIF: 970226633Sdim hd->typeflag = FIFOTYPE; 971226633Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 972226633Sdim memset(hd->devmajor, 0, sizeof(hd->devmajor)); 973226633Sdim memset(hd->devminor, 0, sizeof(hd->devminor)); 974226633Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 975226633Sdim goto out; 976226633Sdim break; 977226633Sdim case PAX_SLK: 978226633Sdim case PAX_HLK: 979226633Sdim case PAX_HRG: 980226633Sdim if (arcn->type == PAX_SLK) 981226633Sdim hd->typeflag = SYMTYPE; 982226633Sdim else 983226633Sdim hd->typeflag = LNKTYPE; 984226633Sdim l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 985226633Sdim hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 986226633Sdim memset(hd->devmajor, 0, sizeof(hd->devmajor)); 987226633Sdim memset(hd->devminor, 0, sizeof(hd->devminor)); 988226633Sdim if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 989226633Sdim goto out; 990226633Sdim break; 991226633Sdim case PAX_REG: 992226633Sdim case PAX_CTG: 993226633Sdim default: 994226633Sdim /* 995226633Sdim * file data with this type, set the padding 996226633Sdim */ 997226633Sdim if (arcn->type == PAX_CTG) 998226633Sdim hd->typeflag = CONTTYPE; 999226633Sdim else 1000226633Sdim hd->typeflag = REGTYPE; 1001226633Sdim memset(hd->linkname, 0, sizeof(hd->linkname)); 1002226633Sdim memset(hd->devmajor, 0, sizeof(hd->devmajor)); 1003226633Sdim memset(hd->devminor, 0, sizeof(hd->devminor)); 1004226633Sdim arcn->pad = TAR_PAD(arcn->sb.st_size); 1005226633Sdim# ifdef NET2_STAT 1006226633Sdim if (ul_oct((u_long)arcn->sb.st_size, hd->size, 1007226633Sdim sizeof(hd->size), 3)) { 1008226633Sdim# else 1009226633Sdim if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 1010226633Sdim sizeof(hd->size), 3)) { 1011226633Sdim# endif 1012226633Sdim paxwarn(1,"File is too long for ustar %s",arcn->org_name); 1013226633Sdim return(1); 1014226633Sdim } 1015226633Sdim break; 1016226633Sdim } 1017226633Sdim 1018226633Sdim l_strncpy(hd->magic, TMAGIC, TMAGLEN); 1019226633Sdim l_strncpy(hd->version, TVERSION, TVERSLEN); 1020226633Sdim 1021226633Sdim /* 1022226633Sdim * set the remaining fields. Some versions want all 16 bits of mode 1023226633Sdim * we better humor them (they really do not meet spec though).... 1024226633Sdim */ 1025226633Sdim if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || 1026226633Sdim ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || 1027226633Sdim ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || 1028226633Sdim ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) 1029226633Sdim goto out; 1030226633Sdim l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); 1031226633Sdim l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); 1032226633Sdim 1033226633Sdim /* 1034226633Sdim * calculate and store the checksum write the header to the archive 1035226633Sdim * return 0 tells the caller to now write the file data, 1 says no data 1036226633Sdim * needs to be written 1037226633Sdim */ 1038226633Sdim if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, 1039226633Sdim sizeof(hd->chksum), 3)) 1040226633Sdim goto out; 1041226633Sdim if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) 1042226633Sdim return(-1); 1043226633Sdim if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) 1044226633Sdim return(-1); 1045226633Sdim if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 1046226633Sdim return(0); 1047226633Sdim return(1); 1048226633Sdim 1049226633Sdim out: 1050226633Sdim /* 1051226633Sdim * header field is out of range 1052226633Sdim */ 1053226633Sdim paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); 1054198092Srdivacky return(1); 1055198092Srdivacky} 1056218893Sdim 1057218893Sdim/* 1058212904Sdim * name_split() 1059198092Srdivacky * see if the name has to be split for storage in a ustar header. We try 1060212904Sdim * to fit the entire name in the name field without splitting if we can. 1061210299Sed * The split point is always at a / 1062218893Sdim * Return 1063218893Sdim * character pointer to split point (always the / that is to be removed 1064218893Sdim * if the split is not needed, the points is set to the start of the file 1065218893Sdim * name (it would violate the spec to split there). A NULL is returned if 1066212904Sdim * the file name is too long 1067198092Srdivacky */ 1068212904Sdim 1069199482Srdivackystatic char * 1070212904Sdimname_split(char *name, int len) 1071198092Srdivacky{ 1072212904Sdim char *start; 1073206084Srdivacky 1074212904Sdim /* 1075198092Srdivacky * check to see if the file name is small enough to fit in the name 1076212904Sdim * field. if so just return a pointer to the name. 1077198092Srdivacky */ 1078212904Sdim if (len < TNMSZ) 1079198092Srdivacky return(name); 1080212904Sdim if (len > (TPFSZ + TNMSZ)) 1081198092Srdivacky return(NULL); 1082212904Sdim 1083198092Srdivacky /* 1084218893Sdim * we start looking at the biggest sized piece that fits in the name 1085218893Sdim * field. We walk forward looking for a slash to split at. The idea is 1086212904Sdim * to find the biggest piece to fit in the name field (or the smallest 1087198092Srdivacky * prefix we can find) 1088212904Sdim */ 1089198893Srdivacky start = name + len - TNMSZ; 1090212904Sdim while ((*start != '\0') && (*start != '/')) 1091198092Srdivacky ++start; 1092212904Sdim 1093198092Srdivacky /* 1094212904Sdim * if we hit the end of the string, this name cannot be split, so we 1095198092Srdivacky * cannot store this file. 1096212904Sdim */ 1097198092Srdivacky if (*start == '\0') 1098218893Sdim return(NULL); 1099218893Sdim len = start - name; 1100212904Sdim 1101198398Srdivacky /* 1102212904Sdim * NOTE: /str where the length of str == TNMSZ can not be stored under 1103198398Srdivacky * the p1003.1-1990 spec for ustar. We could force a prefix of / and 1104212904Sdim * the file would then expand on extract to //str. The len == 0 below 1105198398Srdivacky * makes this special case follow the spec to the letter. 1106218893Sdim */ 1107218893Sdim if ((len >= TPFSZ) || (len == 0)) 1108212904Sdim return(NULL); 1109198398Srdivacky 1110212904Sdim /* 1111198398Srdivacky * ok have a split point, return it to the caller 1112212904Sdim */ 1113198398Srdivacky return(start); 1114218893Sdim} 1115218893Sdim