tar.c revision 211864
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3536049Scharnier#if 0 3636049Scharnierstatic char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; 3736049Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999110Sobrien#include <sys/cdefs.h> 4099110Sobrien__FBSDID("$FreeBSD: head/bin/pax/tar.c 211864 2010-08-27 08:54:40Z brian $"); 411556Srgrimes 421556Srgrimes#include <sys/types.h> 431556Srgrimes#include <sys/time.h> 441556Srgrimes#include <sys/stat.h> 451556Srgrimes#include <string.h> 461556Srgrimes#include <stdio.h> 471556Srgrimes#include <unistd.h> 481556Srgrimes#include <stdlib.h> 491556Srgrimes#include "pax.h" 501556Srgrimes#include "extern.h" 511556Srgrimes#include "tar.h" 521556Srgrimes 531556Srgrimes/* 541556Srgrimes * Routines for reading, writing and header identify of various versions of tar 551556Srgrimes */ 561556Srgrimes 5790113Simpstatic u_long tar_chksm(char *, int); 5890113Simpstatic char *name_split(char *, int); 5990113Simpstatic int ul_oct(u_long, char *, int, int); 601556Srgrimes#ifndef NET2_STAT 6190113Simpstatic int uqd_oct(u_quad_t, char *, int, int); 621556Srgrimes#endif 631556Srgrimes 641556Srgrimes/* 651556Srgrimes * Routines common to all versions of tar 661556Srgrimes */ 671556Srgrimes 681556Srgrimesstatic int tar_nodir; /* do not write dirs under old tar */ 691556Srgrimes 701556Srgrimes/* 711556Srgrimes * tar_endwr() 721556Srgrimes * add the tar trailer of two null blocks 731556Srgrimes * Return: 741556Srgrimes * 0 if ok, -1 otherwise (what wr_skip returns) 751556Srgrimes */ 761556Srgrimes 771556Srgrimesint 781556Srgrimestar_endwr(void) 791556Srgrimes{ 801556Srgrimes return(wr_skip((off_t)(NULLCNT*BLKMULT))); 811556Srgrimes} 821556Srgrimes 831556Srgrimes/* 841556Srgrimes * tar_endrd() 851556Srgrimes * no cleanup needed here, just return size of trailer (for append) 861556Srgrimes * Return: 871556Srgrimes * size of trailer (2 * BLKMULT) 881556Srgrimes */ 891556Srgrimes 901556Srgrimesoff_t 911556Srgrimestar_endrd(void) 921556Srgrimes{ 931556Srgrimes return((off_t)(NULLCNT*BLKMULT)); 941556Srgrimes} 951556Srgrimes 961556Srgrimes/* 971556Srgrimes * tar_trail() 981556Srgrimes * Called to determine if a header block is a valid trailer. We are passed 991556Srgrimes * the block, the in_sync flag (which tells us we are in resync mode; 1001556Srgrimes * looking for a valid header), and cnt (which starts at zero) which is 1011556Srgrimes * used to count the number of empty blocks we have seen so far. 1021556Srgrimes * Return: 1031556Srgrimes * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block 1041556Srgrimes * could never contain a header. 1051556Srgrimes */ 1061556Srgrimes 1071556Srgrimesint 10890113Simptar_trail(char *buf, int in_resync, int *cnt) 1091556Srgrimes{ 11090113Simp int i; 1111556Srgrimes 1121556Srgrimes /* 1131556Srgrimes * look for all zero, trailer is two consecutive blocks of zero 1141556Srgrimes */ 1151556Srgrimes for (i = 0; i < BLKMULT; ++i) { 1161556Srgrimes if (buf[i] != '\0') 1171556Srgrimes break; 1181556Srgrimes } 1191556Srgrimes 1201556Srgrimes /* 1211556Srgrimes * if not all zero it is not a trailer, but MIGHT be a header. 1221556Srgrimes */ 1231556Srgrimes if (i != BLKMULT) 1241556Srgrimes return(-1); 1251556Srgrimes 1261556Srgrimes /* 1271556Srgrimes * When given a zero block, we must be careful! 1281556Srgrimes * If we are not in resync mode, check for the trailer. Have to watch 1291556Srgrimes * out that we do not mis-identify file data as the trailer, so we do 1301556Srgrimes * NOT try to id a trailer during resync mode. During resync mode we 1311556Srgrimes * might as well throw this block out since a valid header can NEVER be 1321556Srgrimes * a block of all 0 (we must have a valid file name). 1331556Srgrimes */ 1341556Srgrimes if (!in_resync && (++*cnt >= NULLCNT)) 1351556Srgrimes return(0); 1361556Srgrimes return(1); 1371556Srgrimes} 1381556Srgrimes 1391556Srgrimes/* 1401556Srgrimes * ul_oct() 1411556Srgrimes * convert an unsigned long to an octal string. many oddball field 1421556Srgrimes * termination characters are used by the various versions of tar in the 14376351Skris * different fields. term selects which kind to use. str is '0' padded 1441556Srgrimes * at the front to len. we are unable to use only one format as many old 1451556Srgrimes * tar readers are very cranky about this. 1461556Srgrimes * Return: 1471556Srgrimes * 0 if the number fit into the string, -1 otherwise 1481556Srgrimes */ 1491556Srgrimes 1501556Srgrimesstatic int 15190113Simpul_oct(u_long val, char *str, int len, int term) 1521556Srgrimes{ 15390113Simp char *pt; 1548855Srgrimes 1551556Srgrimes /* 1561556Srgrimes * term selects the appropriate character(s) for the end of the string 1571556Srgrimes */ 1581556Srgrimes pt = str + len - 1; 1591556Srgrimes switch(term) { 1601556Srgrimes case 3: 1611556Srgrimes *pt-- = '\0'; 1621556Srgrimes break; 1631556Srgrimes case 2: 1641556Srgrimes *pt-- = ' '; 1651556Srgrimes *pt-- = '\0'; 1661556Srgrimes break; 1671556Srgrimes case 1: 1681556Srgrimes *pt-- = ' '; 1691556Srgrimes break; 1701556Srgrimes case 0: 1711556Srgrimes default: 1721556Srgrimes *pt-- = '\0'; 1731556Srgrimes *pt-- = ' '; 1741556Srgrimes break; 1751556Srgrimes } 1761556Srgrimes 1771556Srgrimes /* 1781556Srgrimes * convert and blank pad if there is space 1791556Srgrimes */ 1801556Srgrimes while (pt >= str) { 1811556Srgrimes *pt-- = '0' + (char)(val & 0x7); 1821556Srgrimes if ((val = val >> 3) == (u_long)0) 1831556Srgrimes break; 1841556Srgrimes } 1851556Srgrimes 1861556Srgrimes while (pt >= str) 18776351Skris *pt-- = '0'; 1881556Srgrimes if (val != (u_long)0) 1891556Srgrimes return(-1); 1901556Srgrimes return(0); 1911556Srgrimes} 1921556Srgrimes 1931556Srgrimes#ifndef NET2_STAT 1941556Srgrimes/* 1951556Srgrimes * uqd_oct() 1961556Srgrimes * convert an u_quad_t to an octal string. one of many oddball field 1971556Srgrimes * termination characters are used by the various versions of tar in the 19876351Skris * different fields. term selects which kind to use. str is '0' padded 1991556Srgrimes * at the front to len. we are unable to use only one format as many old 2001556Srgrimes * tar readers are very cranky about this. 2011556Srgrimes * Return: 2021556Srgrimes * 0 if the number fit into the string, -1 otherwise 2031556Srgrimes */ 2041556Srgrimes 2051556Srgrimesstatic int 20690113Simpuqd_oct(u_quad_t val, char *str, int len, int term) 2071556Srgrimes{ 20890113Simp char *pt; 2098855Srgrimes 2101556Srgrimes /* 2111556Srgrimes * term selects the appropriate character(s) for the end of the string 2121556Srgrimes */ 2131556Srgrimes pt = str + len - 1; 2141556Srgrimes switch(term) { 2151556Srgrimes case 3: 2161556Srgrimes *pt-- = '\0'; 2171556Srgrimes break; 2181556Srgrimes case 2: 2191556Srgrimes *pt-- = ' '; 2201556Srgrimes *pt-- = '\0'; 2211556Srgrimes break; 2221556Srgrimes case 1: 2231556Srgrimes *pt-- = ' '; 2241556Srgrimes break; 2251556Srgrimes case 0: 2261556Srgrimes default: 2271556Srgrimes *pt-- = '\0'; 2281556Srgrimes *pt-- = ' '; 2291556Srgrimes break; 2301556Srgrimes } 2311556Srgrimes 2321556Srgrimes /* 2331556Srgrimes * convert and blank pad if there is space 2341556Srgrimes */ 2351556Srgrimes while (pt >= str) { 2361556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2371556Srgrimes if ((val = val >> 3) == 0) 2381556Srgrimes break; 2391556Srgrimes } 2401556Srgrimes 2411556Srgrimes while (pt >= str) 24276351Skris *pt-- = '0'; 2431556Srgrimes if (val != (u_quad_t)0) 2441556Srgrimes return(-1); 2451556Srgrimes return(0); 2461556Srgrimes} 2471556Srgrimes#endif 2481556Srgrimes 2491556Srgrimes/* 2501556Srgrimes * tar_chksm() 2511556Srgrimes * calculate the checksum for a tar block counting the checksum field as 25246684Skris * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). 2531556Srgrimes * NOTE: we use len to short circuit summing 0's on write since we ALWAYS 2541556Srgrimes * pad headers with 0. 2551556Srgrimes * Return: 2561556Srgrimes * unsigned long checksum 2571556Srgrimes */ 2581556Srgrimes 2591556Srgrimesstatic u_long 26090113Simptar_chksm(char *blk, int len) 2611556Srgrimes{ 26290113Simp char *stop; 26390113Simp char *pt; 26446684Skris u_long chksm = BLNKSUM; /* initial value is checksum field sum */ 2651556Srgrimes 2661556Srgrimes /* 2671556Srgrimes * add the part of the block before the checksum field 2681556Srgrimes */ 2691556Srgrimes pt = blk; 2701556Srgrimes stop = blk + CHK_OFFSET; 2718855Srgrimes while (pt < stop) 2728855Srgrimes chksm += (u_long)(*pt++ & 0xff); 2731556Srgrimes /* 2741556Srgrimes * move past the checksum field and keep going, spec counts the 2751556Srgrimes * checksum field as the sum of 8 blanks (which is pre-computed as 2761556Srgrimes * BLNKSUM). 2771556Srgrimes * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding 2781556Srgrimes * starts, no point in summing zero's) 2791556Srgrimes */ 2801556Srgrimes pt += CHK_LEN; 2811556Srgrimes stop = blk + len; 2821556Srgrimes while (pt < stop) 2838855Srgrimes chksm += (u_long)(*pt++ & 0xff); 2841556Srgrimes return(chksm); 2851556Srgrimes} 2861556Srgrimes 2871556Srgrimes/* 2881556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar) 2891556Srgrimes */ 2901556Srgrimes 2911556Srgrimes/* 2921556Srgrimes * tar_id() 2931556Srgrimes * determine if a block given to us is a valid tar header (and not a USTAR 2941556Srgrimes * header). We have to be on the lookout for those pesky blocks of all 2951556Srgrimes * zero's. 2961556Srgrimes * Return: 2971556Srgrimes * 0 if a tar header, -1 otherwise 2981556Srgrimes */ 2991556Srgrimes 3001556Srgrimesint 30190113Simptar_id(char *blk, int size) 3021556Srgrimes{ 30390113Simp HD_TAR *hd; 30490113Simp HD_USTAR *uhd; 3051556Srgrimes 3061556Srgrimes if (size < BLKMULT) 3071556Srgrimes return(-1); 3081556Srgrimes hd = (HD_TAR *)blk; 3091556Srgrimes uhd = (HD_USTAR *)blk; 3101556Srgrimes 3111556Srgrimes /* 3121556Srgrimes * check for block of zero's first, a simple and fast test, then make 3131556Srgrimes * sure this is not a ustar header by looking for the ustar magic 3141556Srgrimes * cookie. We should use TMAGLEN, but some USTAR archive programs are 3151556Srgrimes * wrong and create archives missing the \0. Last we check the 3161556Srgrimes * checksum. If this is ok we have to assume it is a valid header. 3171556Srgrimes */ 3181556Srgrimes if (hd->name[0] == '\0') 3191556Srgrimes return(-1); 3201556Srgrimes if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) 3211556Srgrimes return(-1); 3221556Srgrimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 3231556Srgrimes return(-1); 3241556Srgrimes return(0); 3251556Srgrimes} 3261556Srgrimes 3271556Srgrimes/* 3281556Srgrimes * tar_opt() 3291556Srgrimes * handle tar format specific -o options 3301556Srgrimes * Return: 3311556Srgrimes * 0 if ok -1 otherwise 3321556Srgrimes */ 3331556Srgrimes 3341556Srgrimesint 3351556Srgrimestar_opt(void) 3361556Srgrimes{ 3371556Srgrimes OPLIST *opt; 3381556Srgrimes 3391556Srgrimes while ((opt = opt_next()) != NULL) { 3401556Srgrimes if (strcmp(opt->name, TAR_OPTION) || 3411556Srgrimes strcmp(opt->value, TAR_NODIR)) { 34276017Skris paxwarn(1, "Unknown tar format -o option/value pair %s=%s", 3431556Srgrimes opt->name, opt->value); 34476017Skris paxwarn(1,"%s=%s is the only supported tar format option", 3451556Srgrimes TAR_OPTION, TAR_NODIR); 3461556Srgrimes return(-1); 3471556Srgrimes } 3481556Srgrimes 3491556Srgrimes /* 3501556Srgrimes * we only support one option, and only when writing 3511556Srgrimes */ 3521556Srgrimes if ((act != APPND) && (act != ARCHIVE)) { 35376017Skris paxwarn(1, "%s=%s is only supported when writing.", 3541556Srgrimes opt->name, opt->value); 3551556Srgrimes return(-1); 3561556Srgrimes } 3571556Srgrimes tar_nodir = 1; 3581556Srgrimes } 3591556Srgrimes return(0); 3601556Srgrimes} 3611556Srgrimes 3621556Srgrimes 3631556Srgrimes/* 3641556Srgrimes * tar_rd() 3651556Srgrimes * extract the values out of block already determined to be a tar header. 3661556Srgrimes * store the values in the ARCHD parameter. 3671556Srgrimes * Return: 3681556Srgrimes * 0 3691556Srgrimes */ 3701556Srgrimes 3711556Srgrimesint 37290113Simptar_rd(ARCHD *arcn, char *buf) 3731556Srgrimes{ 37490113Simp HD_TAR *hd; 37590113Simp char *pt; 3761556Srgrimes 3771556Srgrimes /* 3781556Srgrimes * we only get proper sized buffers passed to us 3791556Srgrimes */ 3801556Srgrimes if (tar_id(buf, BLKMULT) < 0) 3811556Srgrimes return(-1); 3821556Srgrimes arcn->org_name = arcn->name; 3831556Srgrimes arcn->sb.st_nlink = 1; 3841556Srgrimes arcn->pat = NULL; 3851556Srgrimes 3861556Srgrimes /* 3871556Srgrimes * copy out the name and values in the stat buffer 3881556Srgrimes */ 3891556Srgrimes hd = (HD_TAR *)buf; 390137645Syar /* 391137645Syar * old tar format specifies the name always be null-terminated, 392137645Syar * but let's be robust to broken archives. 393137645Syar * the same applies to handling links below. 394137645Syar */ 395137645Syar arcn->nlen = l_strncpy(arcn->name, hd->name, 396137645Syar MIN(sizeof(hd->name), sizeof(arcn->name)) - 1); 3971556Srgrimes arcn->name[arcn->nlen] = '\0'; 3981556Srgrimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 3991556Srgrimes 0xfff); 4001556Srgrimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 4011556Srgrimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 40276351Skris#ifdef NET2_STAT 40376351Skris arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 40485618Sdillon arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 40576351Skris#else 40676351Skris arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 40785618Sdillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 40876351Skris#endif 4091556Srgrimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 4101556Srgrimes 4111556Srgrimes /* 4121556Srgrimes * have to look at the last character, it may be a '/' and that is used 4131556Srgrimes * to encode this as a directory 4141556Srgrimes */ 4151556Srgrimes pt = &(arcn->name[arcn->nlen - 1]); 4161556Srgrimes arcn->pad = 0; 4171556Srgrimes arcn->skip = 0; 4181556Srgrimes switch(hd->linkflag) { 4191556Srgrimes case SYMTYPE: 4201556Srgrimes /* 4211556Srgrimes * symbolic link, need to get the link name and set the type in 4221556Srgrimes * the st_mode so -v printing will look correct. 4231556Srgrimes */ 4241556Srgrimes arcn->type = PAX_SLK; 4251556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 426137645Syar MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4271556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4281556Srgrimes arcn->sb.st_mode |= S_IFLNK; 4291556Srgrimes break; 4301556Srgrimes case LNKTYPE: 4311556Srgrimes /* 4321556Srgrimes * hard link, need to get the link name, set the type in the 4331556Srgrimes * st_mode and st_nlink so -v printing will look better. 4341556Srgrimes */ 4351556Srgrimes arcn->type = PAX_HLK; 4361556Srgrimes arcn->sb.st_nlink = 2; 4371556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 438137645Syar MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4391556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4401556Srgrimes 4411556Srgrimes /* 4421556Srgrimes * no idea of what type this thing really points at, but 4431556Srgrimes * we set something for printing only. 4441556Srgrimes */ 4451556Srgrimes arcn->sb.st_mode |= S_IFREG; 4461556Srgrimes break; 44776351Skris case DIRTYPE: 44876351Skris /* 44976351Skris * It is a directory, set the mode for -v printing 45076351Skris */ 45176351Skris arcn->type = PAX_DIR; 45276351Skris arcn->sb.st_mode |= S_IFDIR; 45376351Skris arcn->sb.st_nlink = 2; 45476351Skris arcn->ln_name[0] = '\0'; 45576351Skris arcn->ln_nlen = 0; 45676351Skris break; 4571556Srgrimes case AREGTYPE: 4581556Srgrimes case REGTYPE: 4591556Srgrimes default: 4601556Srgrimes /* 4611556Srgrimes * If we have a trailing / this is a directory and NOT a file. 4621556Srgrimes */ 4631556Srgrimes arcn->ln_name[0] = '\0'; 4641556Srgrimes arcn->ln_nlen = 0; 4651556Srgrimes if (*pt == '/') { 4661556Srgrimes /* 4671556Srgrimes * it is a directory, set the mode for -v printing 4681556Srgrimes */ 4691556Srgrimes arcn->type = PAX_DIR; 4701556Srgrimes arcn->sb.st_mode |= S_IFDIR; 4711556Srgrimes arcn->sb.st_nlink = 2; 4721556Srgrimes } else { 4731556Srgrimes /* 4741556Srgrimes * have a file that will be followed by data. Set the 47546684Skris * skip value to the size field and calculate the size 4761556Srgrimes * of the padding. 4771556Srgrimes */ 4781556Srgrimes arcn->type = PAX_REG; 4791556Srgrimes arcn->sb.st_mode |= S_IFREG; 4801556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 4811556Srgrimes arcn->skip = arcn->sb.st_size; 4821556Srgrimes } 4831556Srgrimes break; 4841556Srgrimes } 4851556Srgrimes 4861556Srgrimes /* 4871556Srgrimes * strip off any trailing slash. 4881556Srgrimes */ 4891556Srgrimes if (*pt == '/') { 4908855Srgrimes *pt = '\0'; 4911556Srgrimes --arcn->nlen; 4921556Srgrimes } 4931556Srgrimes return(0); 4941556Srgrimes} 4951556Srgrimes 4961556Srgrimes/* 4971556Srgrimes * tar_wr() 4981556Srgrimes * write a tar header for the file specified in the ARCHD to the archive. 4991556Srgrimes * Have to check for file types that cannot be stored and file names that 5001556Srgrimes * are too long. Be careful of the term (last arg) to ul_oct, each field 5011556Srgrimes * of tar has it own spec for the termination character(s). 5021556Srgrimes * ASSUMED: space after header in header block is zero filled 5031556Srgrimes * Return: 5041556Srgrimes * 0 if file has data to be written after the header, 1 if file has NO 5051556Srgrimes * data to write after the header, -1 if archive write failed 5061556Srgrimes */ 5071556Srgrimes 5081556Srgrimesint 50990113Simptar_wr(ARCHD *arcn) 5101556Srgrimes{ 51190113Simp HD_TAR *hd; 5121556Srgrimes int len; 513164699Sru HD_TAR hdblk; 5141556Srgrimes 5151556Srgrimes /* 516102230Strhodes * check for those file system types which tar cannot store 5171556Srgrimes */ 5181556Srgrimes switch(arcn->type) { 5191556Srgrimes case PAX_DIR: 5201556Srgrimes /* 5211556Srgrimes * user asked that dirs not be written to the archive 5221556Srgrimes */ 5231556Srgrimes if (tar_nodir) 5241556Srgrimes return(1); 5251556Srgrimes break; 5261556Srgrimes case PAX_CHR: 52776017Skris paxwarn(1, "Tar cannot archive a character device %s", 5281556Srgrimes arcn->org_name); 5291556Srgrimes return(1); 5301556Srgrimes case PAX_BLK: 53176017Skris paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); 5321556Srgrimes return(1); 5331556Srgrimes case PAX_SCK: 53476017Skris paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); 5351556Srgrimes return(1); 5361556Srgrimes case PAX_FIF: 53776017Skris paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); 5381556Srgrimes return(1); 5391556Srgrimes case PAX_SLK: 5401556Srgrimes case PAX_HLK: 5411556Srgrimes case PAX_HRG: 542137645Syar if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) { 54376017Skris paxwarn(1,"Link name too long for tar %s", arcn->ln_name); 5441556Srgrimes return(1); 5451556Srgrimes } 5461556Srgrimes break; 5471556Srgrimes case PAX_REG: 5481556Srgrimes case PAX_CTG: 5491556Srgrimes default: 5501556Srgrimes break; 5511556Srgrimes } 5521556Srgrimes 5531556Srgrimes /* 5541556Srgrimes * check file name len, remember extra char for dirs (the / at the end) 5551556Srgrimes */ 5561556Srgrimes len = arcn->nlen; 5571556Srgrimes if (arcn->type == PAX_DIR) 5581556Srgrimes ++len; 559114469Sobrien if (len >= (int)sizeof(hd->name)) { 56076017Skris paxwarn(1, "File name too long for tar %s", arcn->name); 5611556Srgrimes return(1); 5621556Srgrimes } 5631556Srgrimes 5641556Srgrimes /* 5651556Srgrimes * copy the data out of the ARCHD into the tar header based on the type 5661556Srgrimes * of the file. Remember many tar readers want the unused fields to be 5671556Srgrimes * padded with zero. We set the linkflag field (type), the linkname 5681556Srgrimes * (or zero if not used),the size, and set the padding (if any) to be 5691556Srgrimes * added after the file data (0 for all other types, as they only have 5701556Srgrimes * a header) 5711556Srgrimes */ 572164699Sru hd = &hdblk; 57376351Skris l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); 57476351Skris hd->name[sizeof(hd->name) - 1] = '\0'; 5751556Srgrimes arcn->pad = 0; 5761556Srgrimes 5771556Srgrimes if (arcn->type == PAX_DIR) { 5781556Srgrimes /* 5791556Srgrimes * directories are the same as files, except have a filename 5801556Srgrimes * that ends with a /, we add the slash here. No data follows, 5811556Srgrimes * dirs, so no pad. 5821556Srgrimes */ 5831556Srgrimes hd->linkflag = AREGTYPE; 58476017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 5851556Srgrimes hd->name[len-1] = '/'; 5861556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5871556Srgrimes goto out; 5881556Srgrimes } else if (arcn->type == PAX_SLK) { 5891556Srgrimes /* 5901556Srgrimes * no data follows this file, so no pad 5911556Srgrimes */ 5921556Srgrimes hd->linkflag = SYMTYPE; 59376351Skris l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 59476351Skris hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 5951556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5961556Srgrimes goto out; 5971556Srgrimes } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 5981556Srgrimes /* 5991556Srgrimes * no data follows this file, so no pad 6001556Srgrimes */ 6011556Srgrimes hd->linkflag = LNKTYPE; 60276351Skris l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 60376351Skris hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 6041556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 6051556Srgrimes goto out; 6061556Srgrimes } else { 6071556Srgrimes /* 6081556Srgrimes * data follows this file, so set the pad 6091556Srgrimes */ 6101556Srgrimes hd->linkflag = AREGTYPE; 61176017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 6121556Srgrimes# ifdef NET2_STAT 6131556Srgrimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 6141556Srgrimes sizeof(hd->size), 1)) { 6151556Srgrimes# else 6161556Srgrimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 6171556Srgrimes sizeof(hd->size), 1)) { 6181556Srgrimes# endif 61976017Skris paxwarn(1,"File is too large for tar %s", arcn->org_name); 6201556Srgrimes return(1); 6211556Srgrimes } 6221556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 6231556Srgrimes } 6241556Srgrimes 6251556Srgrimes /* 6261556Srgrimes * copy those fields that are independent of the type 6271556Srgrimes */ 6281556Srgrimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || 6291556Srgrimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || 6301556Srgrimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || 6311556Srgrimes ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) 6321556Srgrimes goto out; 6331556Srgrimes 6341556Srgrimes /* 6351556Srgrimes * calculate and add the checksum, then write the header. A return of 6361556Srgrimes * 0 tells the caller to now write the file data, 1 says no data needs 6371556Srgrimes * to be written 6381556Srgrimes */ 639164699Sru if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum, 64076351Skris sizeof(hd->chksum), 3)) 6411556Srgrimes goto out; 642164699Sru if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0) 6431556Srgrimes return(-1); 6441556Srgrimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) 6451556Srgrimes return(-1); 6461556Srgrimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 6471556Srgrimes return(0); 6481556Srgrimes return(1); 6491556Srgrimes 6501556Srgrimes out: 6511556Srgrimes /* 6521556Srgrimes * header field is out of range 6531556Srgrimes */ 65476017Skris paxwarn(1, "Tar header field is too small for %s", arcn->org_name); 6551556Srgrimes return(1); 6561556Srgrimes} 6571556Srgrimes 6581556Srgrimes/* 6591556Srgrimes * Routines for POSIX ustar 6601556Srgrimes */ 6611556Srgrimes 6621556Srgrimes/* 6631556Srgrimes * ustar_strd() 6641556Srgrimes * initialization for ustar read 6651556Srgrimes * Return: 6661556Srgrimes * 0 if ok, -1 otherwise 6671556Srgrimes */ 6681556Srgrimes 6691556Srgrimesint 6701556Srgrimesustar_strd(void) 6711556Srgrimes{ 6721556Srgrimes if ((usrtb_start() < 0) || (grptb_start() < 0)) 6731556Srgrimes return(-1); 6741556Srgrimes return(0); 6751556Srgrimes} 6761556Srgrimes 6771556Srgrimes/* 6781556Srgrimes * ustar_stwr() 6791556Srgrimes * initialization for ustar write 6801556Srgrimes * Return: 6811556Srgrimes * 0 if ok, -1 otherwise 6821556Srgrimes */ 6831556Srgrimes 6841556Srgrimesint 6851556Srgrimesustar_stwr(void) 6861556Srgrimes{ 6871556Srgrimes if ((uidtb_start() < 0) || (gidtb_start() < 0)) 6881556Srgrimes return(-1); 6891556Srgrimes return(0); 6901556Srgrimes} 6911556Srgrimes 6921556Srgrimes/* 6931556Srgrimes * ustar_id() 6941556Srgrimes * determine if a block given to us is a valid ustar header. We have to 6951556Srgrimes * be on the lookout for those pesky blocks of all zero's 6961556Srgrimes * Return: 6971556Srgrimes * 0 if a ustar header, -1 otherwise 6981556Srgrimes */ 6991556Srgrimes 7001556Srgrimesint 7011556Srgrimesustar_id(char *blk, int size) 7021556Srgrimes{ 70390113Simp HD_USTAR *hd; 7041556Srgrimes 7051556Srgrimes if (size < BLKMULT) 7061556Srgrimes return(-1); 7071556Srgrimes hd = (HD_USTAR *)blk; 7081556Srgrimes 7091556Srgrimes /* 7101556Srgrimes * check for block of zero's first, a simple and fast test then check 7111556Srgrimes * ustar magic cookie. We should use TMAGLEN, but some USTAR archive 7121556Srgrimes * programs are fouled up and create archives missing the \0. Last we 7131556Srgrimes * check the checksum. If ok we have to assume it is a valid header. 7141556Srgrimes */ 7151556Srgrimes if (hd->name[0] == '\0') 7161556Srgrimes return(-1); 7171556Srgrimes if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) 7181556Srgrimes return(-1); 7191556Srgrimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 7201556Srgrimes return(-1); 7211556Srgrimes return(0); 7221556Srgrimes} 7231556Srgrimes 7241556Srgrimes/* 7251556Srgrimes * ustar_rd() 7261556Srgrimes * extract the values out of block already determined to be a ustar header. 7271556Srgrimes * store the values in the ARCHD parameter. 7281556Srgrimes * Return: 7291556Srgrimes * 0 7301556Srgrimes */ 7311556Srgrimes 7321556Srgrimesint 73390113Simpustar_rd(ARCHD *arcn, char *buf) 7341556Srgrimes{ 73590113Simp HD_USTAR *hd; 73690113Simp char *dest; 73790113Simp int cnt = 0; 7381556Srgrimes dev_t devmajor; 7391556Srgrimes dev_t devminor; 7401556Srgrimes 7411556Srgrimes /* 7421556Srgrimes * we only get proper sized buffers 7431556Srgrimes */ 7441556Srgrimes if (ustar_id(buf, BLKMULT) < 0) 7451556Srgrimes return(-1); 7461556Srgrimes arcn->org_name = arcn->name; 7471556Srgrimes arcn->sb.st_nlink = 1; 7481556Srgrimes arcn->pat = NULL; 74976351Skris arcn->nlen = 0; 7501556Srgrimes hd = (HD_USTAR *)buf; 7511556Srgrimes 7521556Srgrimes /* 7531556Srgrimes * see if the filename is split into two parts. if, so joint the parts. 7541556Srgrimes * we copy the prefix first and add a / between the prefix and name. 7551556Srgrimes */ 7561556Srgrimes dest = arcn->name; 7571556Srgrimes if (*(hd->prefix) != '\0') { 758137645Syar cnt = l_strncpy(dest, hd->prefix, 759137645Syar MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2)); 76076351Skris dest += cnt; 7611556Srgrimes *dest++ = '/'; 76276351Skris cnt++; 7631556Srgrimes } 764137645Syar /* 765137645Syar * ustar format specifies the name may be unterminated 766137645Syar * if it fills the entire field. this also applies to 767137645Syar * the prefix and the linkname. 768137645Syar */ 769137645Syar arcn->nlen = cnt + l_strncpy(dest, hd->name, 770137645Syar MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1)); 7711556Srgrimes arcn->name[arcn->nlen] = '\0'; 7721556Srgrimes 7731556Srgrimes /* 7741556Srgrimes * follow the spec to the letter. we should only have mode bits, strip 7751556Srgrimes * off all other crud we may be passed. 7761556Srgrimes */ 7771556Srgrimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 7781556Srgrimes 0xfff); 77976351Skris#ifdef NET2_STAT 78076351Skris arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 78185618Sdillon arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 78276351Skris#else 78376351Skris arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 78485618Sdillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 78576351Skris#endif 7861556Srgrimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 7871556Srgrimes 7881556Srgrimes /* 7891556Srgrimes * If we can find the ascii names for gname and uname in the password 7901556Srgrimes * and group files we will use the uid's and gid they bind. Otherwise 7911556Srgrimes * we use the uid and gid values stored in the header. (This is what 79246684Skris * the POSIX spec wants). 7931556Srgrimes */ 7941556Srgrimes hd->gname[sizeof(hd->gname) - 1] = '\0'; 7951556Srgrimes if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) 7961556Srgrimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 7971556Srgrimes hd->uname[sizeof(hd->uname) - 1] = '\0'; 7981556Srgrimes if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) 7991556Srgrimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 8001556Srgrimes 8011556Srgrimes /* 8021556Srgrimes * set the defaults, these may be changed depending on the file type 8031556Srgrimes */ 8041556Srgrimes arcn->ln_name[0] = '\0'; 8051556Srgrimes arcn->ln_nlen = 0; 8061556Srgrimes arcn->pad = 0; 8071556Srgrimes arcn->skip = 0; 8081556Srgrimes arcn->sb.st_rdev = (dev_t)0; 8091556Srgrimes 8101556Srgrimes /* 8111556Srgrimes * set the mode and PAX type according to the typeflag in the header 8121556Srgrimes */ 8131556Srgrimes switch(hd->typeflag) { 8141556Srgrimes case FIFOTYPE: 8151556Srgrimes arcn->type = PAX_FIF; 8161556Srgrimes arcn->sb.st_mode |= S_IFIFO; 8171556Srgrimes break; 8181556Srgrimes case DIRTYPE: 8191556Srgrimes arcn->type = PAX_DIR; 8201556Srgrimes arcn->sb.st_mode |= S_IFDIR; 8211556Srgrimes arcn->sb.st_nlink = 2; 8221556Srgrimes 8231556Srgrimes /* 8241556Srgrimes * Some programs that create ustar archives append a '/' 8251556Srgrimes * to the pathname for directories. This clearly violates 8261556Srgrimes * ustar specs, but we will silently strip it off anyway. 8271556Srgrimes */ 8281556Srgrimes if (arcn->name[arcn->nlen - 1] == '/') 8291556Srgrimes arcn->name[--arcn->nlen] = '\0'; 8301556Srgrimes break; 8311556Srgrimes case BLKTYPE: 8321556Srgrimes case CHRTYPE: 8331556Srgrimes /* 8341556Srgrimes * this type requires the rdev field to be set. 8351556Srgrimes */ 8361556Srgrimes if (hd->typeflag == BLKTYPE) { 8371556Srgrimes arcn->type = PAX_BLK; 8381556Srgrimes arcn->sb.st_mode |= S_IFBLK; 8391556Srgrimes } else { 8401556Srgrimes arcn->type = PAX_CHR; 8411556Srgrimes arcn->sb.st_mode |= S_IFCHR; 8421556Srgrimes } 8431556Srgrimes devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); 8441556Srgrimes devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); 8451556Srgrimes arcn->sb.st_rdev = TODEV(devmajor, devminor); 8461556Srgrimes break; 8471556Srgrimes case SYMTYPE: 8481556Srgrimes case LNKTYPE: 8491556Srgrimes if (hd->typeflag == SYMTYPE) { 8501556Srgrimes arcn->type = PAX_SLK; 8511556Srgrimes arcn->sb.st_mode |= S_IFLNK; 8521556Srgrimes } else { 8531556Srgrimes arcn->type = PAX_HLK; 8541556Srgrimes /* 8551556Srgrimes * so printing looks better 8561556Srgrimes */ 8571556Srgrimes arcn->sb.st_mode |= S_IFREG; 8581556Srgrimes arcn->sb.st_nlink = 2; 8591556Srgrimes } 8601556Srgrimes /* 8611556Srgrimes * copy the link name 8621556Srgrimes */ 8631556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 864137645Syar MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1)); 8651556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 8661556Srgrimes break; 8671556Srgrimes case CONTTYPE: 8681556Srgrimes case AREGTYPE: 8691556Srgrimes case REGTYPE: 8701556Srgrimes default: 8711556Srgrimes /* 8721556Srgrimes * these types have file data that follows. Set the skip and 8731556Srgrimes * pad fields. 8741556Srgrimes */ 8751556Srgrimes arcn->type = PAX_REG; 8761556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 8771556Srgrimes arcn->skip = arcn->sb.st_size; 8781556Srgrimes arcn->sb.st_mode |= S_IFREG; 8791556Srgrimes break; 8801556Srgrimes } 8811556Srgrimes return(0); 8821556Srgrimes} 8831556Srgrimes 8841556Srgrimes/* 8851556Srgrimes * ustar_wr() 8861556Srgrimes * write a ustar header for the file specified in the ARCHD to the archive 8871556Srgrimes * Have to check for file types that cannot be stored and file names that 8881556Srgrimes * are too long. Be careful of the term (last arg) to ul_oct, we only use 8891556Srgrimes * '\0' for the termination character (this is different than picky tar) 8901556Srgrimes * ASSUMED: space after header in header block is zero filled 8911556Srgrimes * Return: 8921556Srgrimes * 0 if file has data to be written after the header, 1 if file has NO 8931556Srgrimes * data to write after the header, -1 if archive write failed 8941556Srgrimes */ 8951556Srgrimes 8961556Srgrimesint 89790113Simpustar_wr(ARCHD *arcn) 8981556Srgrimes{ 89990113Simp HD_USTAR *hd; 90090113Simp char *pt; 901164699Sru HD_USTAR hdblk; 9021556Srgrimes 9031556Srgrimes /* 904102230Strhodes * check for those file system types ustar cannot store 9051556Srgrimes */ 9061556Srgrimes if (arcn->type == PAX_SCK) { 90776017Skris paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); 9081556Srgrimes return(1); 9091556Srgrimes } 9101556Srgrimes 9111556Srgrimes /* 9121556Srgrimes * check the length of the linkname 9131556Srgrimes */ 9141556Srgrimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 915114469Sobrien (arcn->type == PAX_HRG)) && 916137645Syar (arcn->ln_nlen > (int)sizeof(hd->linkname))) { 91776017Skris paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); 9181556Srgrimes return(1); 9191556Srgrimes } 9201556Srgrimes 9211556Srgrimes /* 9221556Srgrimes * split the path name into prefix and name fields (if needed). if 9231556Srgrimes * pt != arcn->name, the name has to be split 9241556Srgrimes */ 9251556Srgrimes if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { 92676017Skris paxwarn(1, "File name too long for ustar %s", arcn->name); 9271556Srgrimes return(1); 9281556Srgrimes } 929164699Sru hd = &hdblk; 9301556Srgrimes arcn->pad = 0L; 9311556Srgrimes 9321556Srgrimes /* 9331556Srgrimes * split the name, or zero out the prefix 9341556Srgrimes */ 9351556Srgrimes if (pt != arcn->name) { 9361556Srgrimes /* 9371556Srgrimes * name was split, pt points at the / where the split is to 9381556Srgrimes * occur, we remove the / and copy the first part to the prefix 9391556Srgrimes */ 9401556Srgrimes *pt = '\0'; 941137645Syar l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); 9421556Srgrimes *pt++ = '/'; 9431556Srgrimes } else 94476017Skris memset(hd->prefix, 0, sizeof(hd->prefix)); 9451556Srgrimes 9461556Srgrimes /* 9471556Srgrimes * copy the name part. this may be the whole path or the part after 948137645Syar * the prefix. both the name and prefix may fill the entire field. 9491556Srgrimes */ 950137645Syar l_strncpy(hd->name, pt, sizeof(hd->name)); 9511556Srgrimes 9528855Srgrimes /* 9531556Srgrimes * set the fields in the header that are type dependent 9541556Srgrimes */ 9551556Srgrimes switch(arcn->type) { 9561556Srgrimes case PAX_DIR: 9571556Srgrimes hd->typeflag = DIRTYPE; 95876017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 95976017Skris memset(hd->devmajor, 0, sizeof(hd->devmajor)); 96076017Skris memset(hd->devminor, 0, sizeof(hd->devminor)); 9611556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9621556Srgrimes goto out; 9631556Srgrimes break; 9641556Srgrimes case PAX_CHR: 9651556Srgrimes case PAX_BLK: 9661556Srgrimes if (arcn->type == PAX_CHR) 9671556Srgrimes hd->typeflag = CHRTYPE; 9681556Srgrimes else 9691556Srgrimes hd->typeflag = BLKTYPE; 97076017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 9711556Srgrimes if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, 9721556Srgrimes sizeof(hd->devmajor), 3) || 9731556Srgrimes ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, 9741556Srgrimes sizeof(hd->devminor), 3) || 9751556Srgrimes ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9761556Srgrimes goto out; 9771556Srgrimes break; 9781556Srgrimes case PAX_FIF: 9791556Srgrimes hd->typeflag = FIFOTYPE; 98076017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 98176017Skris memset(hd->devmajor, 0, sizeof(hd->devmajor)); 98276017Skris memset(hd->devminor, 0, sizeof(hd->devminor)); 9831556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9841556Srgrimes goto out; 9851556Srgrimes break; 9861556Srgrimes case PAX_SLK: 9871556Srgrimes case PAX_HLK: 9881556Srgrimes case PAX_HRG: 9891556Srgrimes if (arcn->type == PAX_SLK) 9901556Srgrimes hd->typeflag = SYMTYPE; 9911556Srgrimes else 9921556Srgrimes hd->typeflag = LNKTYPE; 993137645Syar /* the link name may occupy the entire field in ustar */ 994137645Syar l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 99576017Skris memset(hd->devmajor, 0, sizeof(hd->devmajor)); 99676017Skris memset(hd->devminor, 0, sizeof(hd->devminor)); 9971556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9981556Srgrimes goto out; 9991556Srgrimes break; 10001556Srgrimes case PAX_REG: 10011556Srgrimes case PAX_CTG: 10021556Srgrimes default: 10031556Srgrimes /* 10041556Srgrimes * file data with this type, set the padding 10051556Srgrimes */ 10061556Srgrimes if (arcn->type == PAX_CTG) 10071556Srgrimes hd->typeflag = CONTTYPE; 10081556Srgrimes else 10091556Srgrimes hd->typeflag = REGTYPE; 101076017Skris memset(hd->linkname, 0, sizeof(hd->linkname)); 101176017Skris memset(hd->devmajor, 0, sizeof(hd->devmajor)); 101276017Skris memset(hd->devminor, 0, sizeof(hd->devminor)); 10131556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 10141556Srgrimes# ifdef NET2_STAT 10151556Srgrimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 10161556Srgrimes sizeof(hd->size), 3)) { 10171556Srgrimes# else 10181556Srgrimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 10191556Srgrimes sizeof(hd->size), 3)) { 10201556Srgrimes# endif 102176017Skris paxwarn(1,"File is too long for ustar %s",arcn->org_name); 10221556Srgrimes return(1); 10231556Srgrimes } 10241556Srgrimes break; 10251556Srgrimes } 10261556Srgrimes 102776351Skris l_strncpy(hd->magic, TMAGIC, TMAGLEN); 102876351Skris l_strncpy(hd->version, TVERSION, TVERSLEN); 10291556Srgrimes 10301556Srgrimes /* 10311556Srgrimes * set the remaining fields. Some versions want all 16 bits of mode 10321556Srgrimes * we better humor them (they really do not meet spec though).... 10331556Srgrimes */ 10341556Srgrimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || 10351556Srgrimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || 10361556Srgrimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || 10371556Srgrimes ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) 10381556Srgrimes goto out; 103976351Skris l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); 104076351Skris l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); 10411556Srgrimes 10421556Srgrimes /* 10431556Srgrimes * calculate and store the checksum write the header to the archive 10441556Srgrimes * return 0 tells the caller to now write the file data, 1 says no data 10451556Srgrimes * needs to be written 10461556Srgrimes */ 1047164699Sru if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum, 10481556Srgrimes sizeof(hd->chksum), 3)) 10491556Srgrimes goto out; 1050164699Sru if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0) 10511556Srgrimes return(-1); 10521556Srgrimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) 10531556Srgrimes return(-1); 10541556Srgrimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 10551556Srgrimes return(0); 10561556Srgrimes return(1); 10571556Srgrimes 10581556Srgrimes out: 10591556Srgrimes /* 10601556Srgrimes * header field is out of range 10611556Srgrimes */ 106276017Skris paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); 10631556Srgrimes return(1); 10641556Srgrimes} 10651556Srgrimes 10661556Srgrimes/* 10671556Srgrimes * name_split() 10681556Srgrimes * see if the name has to be split for storage in a ustar header. We try 10691556Srgrimes * to fit the entire name in the name field without splitting if we can. 10701556Srgrimes * The split point is always at a / 10711556Srgrimes * Return 10721556Srgrimes * character pointer to split point (always the / that is to be removed 10731556Srgrimes * if the split is not needed, the points is set to the start of the file 10741556Srgrimes * name (it would violate the spec to split there). A NULL is returned if 10751556Srgrimes * the file name is too long 10761556Srgrimes */ 10771556Srgrimes 10781556Srgrimesstatic char * 107990113Simpname_split(char *name, int len) 10801556Srgrimes{ 108190113Simp char *start; 10821556Srgrimes 10831556Srgrimes /* 10841556Srgrimes * check to see if the file name is small enough to fit in the name 10851556Srgrimes * field. if so just return a pointer to the name. 10861556Srgrimes */ 1087137645Syar if (len <= TNMSZ) 10881556Srgrimes return(name); 1089137645Syar if (len > (TPFSZ + TNMSZ + 1)) 10901556Srgrimes return(NULL); 10911556Srgrimes 10921556Srgrimes /* 10931556Srgrimes * we start looking at the biggest sized piece that fits in the name 109446684Skris * field. We walk forward looking for a slash to split at. The idea is 10951556Srgrimes * to find the biggest piece to fit in the name field (or the smallest 109640533Smsmith * prefix we can find) 10971556Srgrimes */ 1098211864Sbrian start = name + len - TNMSZ; 10991556Srgrimes while ((*start != '\0') && (*start != '/')) 11001556Srgrimes ++start; 11011556Srgrimes 11021556Srgrimes /* 11031556Srgrimes * if we hit the end of the string, this name cannot be split, so we 11041556Srgrimes * cannot store this file. 11051556Srgrimes */ 11061556Srgrimes if (*start == '\0') 11071556Srgrimes return(NULL); 11081556Srgrimes len = start - name; 11091556Srgrimes 11101556Srgrimes /* 11111556Srgrimes * NOTE: /str where the length of str == TNMSZ can not be stored under 11121556Srgrimes * the p1003.1-1990 spec for ustar. We could force a prefix of / and 11131556Srgrimes * the file would then expand on extract to //str. The len == 0 below 11141556Srgrimes * makes this special case follow the spec to the letter. 11151556Srgrimes */ 1116137645Syar if ((len > TPFSZ) || (len == 0)) 11171556Srgrimes return(NULL); 11181556Srgrimes 11191556Srgrimes /* 11201556Srgrimes * ok have a split point, return it to the caller 11211556Srgrimes */ 11221556Srgrimes return(start); 11231556Srgrimes} 1124