tar.c revision 36049
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 * 3. All advertising materials mentioning features or use of this software 181556Srgrimes * must display the following acknowledgement: 191556Srgrimes * This product includes software developed by the University of 201556Srgrimes * California, Berkeley and its contributors. 211556Srgrimes * 4. Neither the name of the University nor the names of its contributors 221556Srgrimes * may be used to endorse or promote products derived from this software 231556Srgrimes * without specific prior written permission. 241556Srgrimes * 251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351556Srgrimes * SUCH DAMAGE. 361556Srgrimes */ 371556Srgrimes 381556Srgrimes#ifndef lint 3936049Scharnier#if 0 4036049Scharnierstatic char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; 4136049Scharnier#endif 4236049Scharnierstatic const char rcsid[] = 4336049Scharnier "$Id$"; 441556Srgrimes#endif /* not lint */ 451556Srgrimes 461556Srgrimes#include <sys/types.h> 471556Srgrimes#include <sys/time.h> 481556Srgrimes#include <sys/stat.h> 491556Srgrimes#include <string.h> 501556Srgrimes#include <stdio.h> 511556Srgrimes#include <unistd.h> 521556Srgrimes#include <stdlib.h> 531556Srgrimes#include "pax.h" 541556Srgrimes#include "extern.h" 551556Srgrimes#include "tar.h" 561556Srgrimes 571556Srgrimes/* 581556Srgrimes * Routines for reading, writing and header identify of various versions of tar 591556Srgrimes */ 601556Srgrimes 611556Srgrimesstatic u_long tar_chksm __P((register char *, register int)); 621556Srgrimesstatic char *name_split __P((register char *, register int)); 631556Srgrimesstatic int ul_oct __P((u_long, register char *, register int, int)); 641556Srgrimes#ifndef NET2_STAT 651556Srgrimesstatic int uqd_oct __P((u_quad_t, register char *, register int, int)); 661556Srgrimes#endif 671556Srgrimes 681556Srgrimes/* 691556Srgrimes * Routines common to all versions of tar 701556Srgrimes */ 711556Srgrimes 721556Srgrimesstatic int tar_nodir; /* do not write dirs under old tar */ 731556Srgrimes 741556Srgrimes/* 751556Srgrimes * tar_endwr() 761556Srgrimes * add the tar trailer of two null blocks 771556Srgrimes * Return: 781556Srgrimes * 0 if ok, -1 otherwise (what wr_skip returns) 791556Srgrimes */ 801556Srgrimes 811556Srgrimes#if __STDC__ 821556Srgrimesint 831556Srgrimestar_endwr(void) 841556Srgrimes#else 851556Srgrimesint 861556Srgrimestar_endwr() 871556Srgrimes#endif 881556Srgrimes{ 891556Srgrimes return(wr_skip((off_t)(NULLCNT*BLKMULT))); 901556Srgrimes} 911556Srgrimes 921556Srgrimes/* 931556Srgrimes * tar_endrd() 941556Srgrimes * no cleanup needed here, just return size of trailer (for append) 951556Srgrimes * Return: 961556Srgrimes * size of trailer (2 * BLKMULT) 971556Srgrimes */ 981556Srgrimes 991556Srgrimes#if __STDC__ 1001556Srgrimesoff_t 1011556Srgrimestar_endrd(void) 1021556Srgrimes#else 1031556Srgrimesoff_t 1041556Srgrimestar_endrd() 1051556Srgrimes#endif 1061556Srgrimes{ 1071556Srgrimes return((off_t)(NULLCNT*BLKMULT)); 1081556Srgrimes} 1091556Srgrimes 1101556Srgrimes/* 1111556Srgrimes * tar_trail() 1121556Srgrimes * Called to determine if a header block is a valid trailer. We are passed 1131556Srgrimes * the block, the in_sync flag (which tells us we are in resync mode; 1141556Srgrimes * looking for a valid header), and cnt (which starts at zero) which is 1151556Srgrimes * used to count the number of empty blocks we have seen so far. 1161556Srgrimes * Return: 1171556Srgrimes * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block 1181556Srgrimes * could never contain a header. 1191556Srgrimes */ 1201556Srgrimes 1211556Srgrimes#if __STDC__ 1221556Srgrimesint 1231556Srgrimestar_trail(register char *buf, register int in_resync, register int *cnt) 1241556Srgrimes#else 1251556Srgrimesint 1261556Srgrimestar_trail(buf, in_resync, cnt) 1271556Srgrimes register char *buf; 1281556Srgrimes register int in_resync; 1291556Srgrimes register int *cnt; 1301556Srgrimes#endif 1311556Srgrimes{ 1321556Srgrimes register int i; 1331556Srgrimes 1341556Srgrimes /* 1351556Srgrimes * look for all zero, trailer is two consecutive blocks of zero 1361556Srgrimes */ 1371556Srgrimes for (i = 0; i < BLKMULT; ++i) { 1381556Srgrimes if (buf[i] != '\0') 1391556Srgrimes break; 1401556Srgrimes } 1411556Srgrimes 1421556Srgrimes /* 1431556Srgrimes * if not all zero it is not a trailer, but MIGHT be a header. 1441556Srgrimes */ 1451556Srgrimes if (i != BLKMULT) 1461556Srgrimes return(-1); 1471556Srgrimes 1481556Srgrimes /* 1491556Srgrimes * When given a zero block, we must be careful! 1501556Srgrimes * If we are not in resync mode, check for the trailer. Have to watch 1511556Srgrimes * out that we do not mis-identify file data as the trailer, so we do 1521556Srgrimes * NOT try to id a trailer during resync mode. During resync mode we 1531556Srgrimes * might as well throw this block out since a valid header can NEVER be 1541556Srgrimes * a block of all 0 (we must have a valid file name). 1551556Srgrimes */ 1561556Srgrimes if (!in_resync && (++*cnt >= NULLCNT)) 1571556Srgrimes return(0); 1581556Srgrimes return(1); 1591556Srgrimes} 1601556Srgrimes 1611556Srgrimes/* 1621556Srgrimes * ul_oct() 1631556Srgrimes * convert an unsigned long to an octal string. many oddball field 1641556Srgrimes * termination characters are used by the various versions of tar in the 1651556Srgrimes * different fields. term selects which kind to use. str is BLANK padded 1661556Srgrimes * at the front to len. we are unable to use only one format as many old 1671556Srgrimes * tar readers are very cranky about this. 1681556Srgrimes * Return: 1691556Srgrimes * 0 if the number fit into the string, -1 otherwise 1701556Srgrimes */ 1711556Srgrimes 1721556Srgrimes#if __STDC__ 1731556Srgrimesstatic int 1741556Srgrimesul_oct(u_long val, register char *str, register int len, int term) 1751556Srgrimes#else 1761556Srgrimesstatic int 1771556Srgrimesul_oct(val, str, len, term) 1781556Srgrimes u_long val; 1791556Srgrimes register char *str; 1801556Srgrimes register int len; 1811556Srgrimes int term; 1821556Srgrimes#endif 1831556Srgrimes{ 1841556Srgrimes register char *pt; 1858855Srgrimes 1861556Srgrimes /* 1871556Srgrimes * term selects the appropriate character(s) for the end of the string 1881556Srgrimes */ 1891556Srgrimes pt = str + len - 1; 1901556Srgrimes switch(term) { 1911556Srgrimes case 3: 1921556Srgrimes *pt-- = '\0'; 1931556Srgrimes break; 1941556Srgrimes case 2: 1951556Srgrimes *pt-- = ' '; 1961556Srgrimes *pt-- = '\0'; 1971556Srgrimes break; 1981556Srgrimes case 1: 1991556Srgrimes *pt-- = ' '; 2001556Srgrimes break; 2011556Srgrimes case 0: 2021556Srgrimes default: 2031556Srgrimes *pt-- = '\0'; 2041556Srgrimes *pt-- = ' '; 2051556Srgrimes break; 2061556Srgrimes } 2071556Srgrimes 2081556Srgrimes /* 2091556Srgrimes * convert and blank pad if there is space 2101556Srgrimes */ 2111556Srgrimes while (pt >= str) { 2121556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2131556Srgrimes if ((val = val >> 3) == (u_long)0) 2141556Srgrimes break; 2151556Srgrimes } 2161556Srgrimes 2171556Srgrimes while (pt >= str) 2181556Srgrimes *pt-- = ' '; 2191556Srgrimes if (val != (u_long)0) 2201556Srgrimes return(-1); 2211556Srgrimes return(0); 2221556Srgrimes} 2231556Srgrimes 2241556Srgrimes#ifndef NET2_STAT 2251556Srgrimes/* 2261556Srgrimes * uqd_oct() 2271556Srgrimes * convert an u_quad_t to an octal string. one of many oddball field 2281556Srgrimes * termination characters are used by the various versions of tar in the 2291556Srgrimes * different fields. term selects which kind to use. str is BLANK padded 2301556Srgrimes * at the front to len. we are unable to use only one format as many old 2311556Srgrimes * tar readers are very cranky about this. 2321556Srgrimes * Return: 2331556Srgrimes * 0 if the number fit into the string, -1 otherwise 2341556Srgrimes */ 2351556Srgrimes 2361556Srgrimes#if __STDC__ 2371556Srgrimesstatic int 2381556Srgrimesuqd_oct(u_quad_t val, register char *str, register int len, int term) 2391556Srgrimes#else 2401556Srgrimesstatic int 2411556Srgrimesuqd_oct(val, str, len, term) 2421556Srgrimes u_quad_t val; 2431556Srgrimes register char *str; 2441556Srgrimes register int len; 2451556Srgrimes int term; 2461556Srgrimes#endif 2471556Srgrimes{ 2481556Srgrimes register char *pt; 2498855Srgrimes 2501556Srgrimes /* 2511556Srgrimes * term selects the appropriate character(s) for the end of the string 2521556Srgrimes */ 2531556Srgrimes pt = str + len - 1; 2541556Srgrimes switch(term) { 2551556Srgrimes case 3: 2561556Srgrimes *pt-- = '\0'; 2571556Srgrimes break; 2581556Srgrimes case 2: 2591556Srgrimes *pt-- = ' '; 2601556Srgrimes *pt-- = '\0'; 2611556Srgrimes break; 2621556Srgrimes case 1: 2631556Srgrimes *pt-- = ' '; 2641556Srgrimes break; 2651556Srgrimes case 0: 2661556Srgrimes default: 2671556Srgrimes *pt-- = '\0'; 2681556Srgrimes *pt-- = ' '; 2691556Srgrimes break; 2701556Srgrimes } 2711556Srgrimes 2721556Srgrimes /* 2731556Srgrimes * convert and blank pad if there is space 2741556Srgrimes */ 2751556Srgrimes while (pt >= str) { 2761556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2771556Srgrimes if ((val = val >> 3) == 0) 2781556Srgrimes break; 2791556Srgrimes } 2801556Srgrimes 2811556Srgrimes while (pt >= str) 2821556Srgrimes *pt-- = ' '; 2831556Srgrimes if (val != (u_quad_t)0) 2841556Srgrimes return(-1); 2851556Srgrimes return(0); 2861556Srgrimes} 2871556Srgrimes#endif 2881556Srgrimes 2891556Srgrimes/* 2901556Srgrimes * tar_chksm() 2911556Srgrimes * calculate the checksum for a tar block counting the checksum field as 2921556Srgrimes * all blanks (BLNKSUM is that value pre-calculated, the sume of 8 blanks). 2931556Srgrimes * NOTE: we use len to short circuit summing 0's on write since we ALWAYS 2941556Srgrimes * pad headers with 0. 2951556Srgrimes * Return: 2961556Srgrimes * unsigned long checksum 2971556Srgrimes */ 2981556Srgrimes 2991556Srgrimes#if __STDC__ 3001556Srgrimesstatic u_long 3011556Srgrimestar_chksm(register char *blk, register int len) 3021556Srgrimes#else 3031556Srgrimesstatic u_long 3041556Srgrimestar_chksm(blk, len) 3051556Srgrimes register char *blk; 3061556Srgrimes register int len; 3071556Srgrimes#endif 3081556Srgrimes{ 3091556Srgrimes register char *stop; 3101556Srgrimes register char *pt; 3111556Srgrimes u_long chksm = BLNKSUM; /* inital value is checksum field sum */ 3121556Srgrimes 3131556Srgrimes /* 3141556Srgrimes * add the part of the block before the checksum field 3151556Srgrimes */ 3161556Srgrimes pt = blk; 3171556Srgrimes stop = blk + CHK_OFFSET; 3188855Srgrimes while (pt < stop) 3198855Srgrimes chksm += (u_long)(*pt++ & 0xff); 3201556Srgrimes /* 3211556Srgrimes * move past the checksum field and keep going, spec counts the 3221556Srgrimes * checksum field as the sum of 8 blanks (which is pre-computed as 3231556Srgrimes * BLNKSUM). 3241556Srgrimes * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding 3251556Srgrimes * starts, no point in summing zero's) 3261556Srgrimes */ 3271556Srgrimes pt += CHK_LEN; 3281556Srgrimes stop = blk + len; 3291556Srgrimes while (pt < stop) 3308855Srgrimes chksm += (u_long)(*pt++ & 0xff); 3311556Srgrimes return(chksm); 3321556Srgrimes} 3331556Srgrimes 3341556Srgrimes/* 3351556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar) 3361556Srgrimes */ 3371556Srgrimes 3381556Srgrimes/* 3391556Srgrimes * tar_id() 3401556Srgrimes * determine if a block given to us is a valid tar header (and not a USTAR 3411556Srgrimes * header). We have to be on the lookout for those pesky blocks of all 3421556Srgrimes * zero's. 3431556Srgrimes * Return: 3441556Srgrimes * 0 if a tar header, -1 otherwise 3451556Srgrimes */ 3461556Srgrimes 3471556Srgrimes#if __STDC__ 3481556Srgrimesint 3491556Srgrimestar_id(register char *blk, int size) 3501556Srgrimes#else 3511556Srgrimesint 3521556Srgrimestar_id(blk, size) 3531556Srgrimes register char *blk; 3541556Srgrimes int size; 3551556Srgrimes#endif 3561556Srgrimes{ 3571556Srgrimes register HD_TAR *hd; 3581556Srgrimes register HD_USTAR *uhd; 3591556Srgrimes 3601556Srgrimes if (size < BLKMULT) 3611556Srgrimes return(-1); 3621556Srgrimes hd = (HD_TAR *)blk; 3631556Srgrimes uhd = (HD_USTAR *)blk; 3641556Srgrimes 3651556Srgrimes /* 3661556Srgrimes * check for block of zero's first, a simple and fast test, then make 3671556Srgrimes * sure this is not a ustar header by looking for the ustar magic 3681556Srgrimes * cookie. We should use TMAGLEN, but some USTAR archive programs are 3691556Srgrimes * wrong and create archives missing the \0. Last we check the 3701556Srgrimes * checksum. If this is ok we have to assume it is a valid header. 3711556Srgrimes */ 3721556Srgrimes if (hd->name[0] == '\0') 3731556Srgrimes return(-1); 3741556Srgrimes if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) 3751556Srgrimes return(-1); 3761556Srgrimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 3771556Srgrimes return(-1); 3781556Srgrimes return(0); 3791556Srgrimes} 3801556Srgrimes 3811556Srgrimes/* 3821556Srgrimes * tar_opt() 3831556Srgrimes * handle tar format specific -o options 3841556Srgrimes * Return: 3851556Srgrimes * 0 if ok -1 otherwise 3861556Srgrimes */ 3871556Srgrimes 3881556Srgrimes#if __STDC__ 3891556Srgrimesint 3901556Srgrimestar_opt(void) 3911556Srgrimes#else 3921556Srgrimesint 3931556Srgrimestar_opt() 3941556Srgrimes#endif 3951556Srgrimes{ 3961556Srgrimes OPLIST *opt; 3971556Srgrimes 3981556Srgrimes while ((opt = opt_next()) != NULL) { 3991556Srgrimes if (strcmp(opt->name, TAR_OPTION) || 4001556Srgrimes strcmp(opt->value, TAR_NODIR)) { 40128904Ssos pax_warn(1, "Unknown tar format -o option/value pair %s=%s", 4021556Srgrimes opt->name, opt->value); 40328904Ssos pax_warn(1,"%s=%s is the only supported tar format option", 4041556Srgrimes TAR_OPTION, TAR_NODIR); 4051556Srgrimes return(-1); 4061556Srgrimes } 4071556Srgrimes 4081556Srgrimes /* 4091556Srgrimes * we only support one option, and only when writing 4101556Srgrimes */ 4111556Srgrimes if ((act != APPND) && (act != ARCHIVE)) { 41228904Ssos pax_warn(1, "%s=%s is only supported when writing.", 4131556Srgrimes opt->name, opt->value); 4141556Srgrimes return(-1); 4151556Srgrimes } 4161556Srgrimes tar_nodir = 1; 4171556Srgrimes } 4181556Srgrimes return(0); 4191556Srgrimes} 4201556Srgrimes 4211556Srgrimes 4221556Srgrimes/* 4231556Srgrimes * tar_rd() 4241556Srgrimes * extract the values out of block already determined to be a tar header. 4251556Srgrimes * store the values in the ARCHD parameter. 4261556Srgrimes * Return: 4271556Srgrimes * 0 4281556Srgrimes */ 4291556Srgrimes 4301556Srgrimes#if __STDC__ 4311556Srgrimesint 4321556Srgrimestar_rd(register ARCHD *arcn, register char *buf) 4331556Srgrimes#else 4341556Srgrimesint 4351556Srgrimestar_rd(arcn, buf) 4361556Srgrimes register ARCHD *arcn; 4371556Srgrimes register char *buf; 4381556Srgrimes#endif 4391556Srgrimes{ 4401556Srgrimes register HD_TAR *hd; 4411556Srgrimes register char *pt; 4421556Srgrimes 4431556Srgrimes /* 4441556Srgrimes * we only get proper sized buffers passed to us 4451556Srgrimes */ 4461556Srgrimes if (tar_id(buf, BLKMULT) < 0) 4471556Srgrimes return(-1); 4481556Srgrimes arcn->org_name = arcn->name; 4491556Srgrimes arcn->sb.st_nlink = 1; 4501556Srgrimes arcn->pat = NULL; 4511556Srgrimes 4521556Srgrimes /* 4531556Srgrimes * copy out the name and values in the stat buffer 4541556Srgrimes */ 4551556Srgrimes hd = (HD_TAR *)buf; 4561556Srgrimes arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(hd->name)); 4571556Srgrimes arcn->name[arcn->nlen] = '\0'; 4581556Srgrimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 4591556Srgrimes 0xfff); 4601556Srgrimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 4611556Srgrimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 4621556Srgrimes arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); 4631556Srgrimes arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 4641556Srgrimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 4651556Srgrimes 4661556Srgrimes /* 4671556Srgrimes * have to look at the last character, it may be a '/' and that is used 4681556Srgrimes * to encode this as a directory 4691556Srgrimes */ 4701556Srgrimes pt = &(arcn->name[arcn->nlen - 1]); 4711556Srgrimes arcn->pad = 0; 4721556Srgrimes arcn->skip = 0; 4731556Srgrimes switch(hd->linkflag) { 4741556Srgrimes case SYMTYPE: 4751556Srgrimes /* 4761556Srgrimes * symbolic link, need to get the link name and set the type in 4771556Srgrimes * the st_mode so -v printing will look correct. 4781556Srgrimes */ 4791556Srgrimes arcn->type = PAX_SLK; 4801556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4811556Srgrimes sizeof(hd->linkname)); 4821556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4831556Srgrimes arcn->sb.st_mode |= S_IFLNK; 4841556Srgrimes break; 4851556Srgrimes case LNKTYPE: 4861556Srgrimes /* 4871556Srgrimes * hard link, need to get the link name, set the type in the 4881556Srgrimes * st_mode and st_nlink so -v printing will look better. 4891556Srgrimes */ 4901556Srgrimes arcn->type = PAX_HLK; 4911556Srgrimes arcn->sb.st_nlink = 2; 4921556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4931556Srgrimes sizeof(hd->linkname)); 4941556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4951556Srgrimes 4961556Srgrimes /* 4971556Srgrimes * no idea of what type this thing really points at, but 4981556Srgrimes * we set something for printing only. 4991556Srgrimes */ 5001556Srgrimes arcn->sb.st_mode |= S_IFREG; 5011556Srgrimes break; 5021556Srgrimes case AREGTYPE: 5031556Srgrimes case REGTYPE: 5041556Srgrimes default: 5051556Srgrimes /* 5061556Srgrimes * If we have a trailing / this is a directory and NOT a file. 5071556Srgrimes */ 5081556Srgrimes arcn->ln_name[0] = '\0'; 5091556Srgrimes arcn->ln_nlen = 0; 5101556Srgrimes if (*pt == '/') { 5111556Srgrimes /* 5121556Srgrimes * it is a directory, set the mode for -v printing 5131556Srgrimes */ 5141556Srgrimes arcn->type = PAX_DIR; 5151556Srgrimes arcn->sb.st_mode |= S_IFDIR; 5161556Srgrimes arcn->sb.st_nlink = 2; 5171556Srgrimes } else { 5181556Srgrimes /* 5191556Srgrimes * have a file that will be followed by data. Set the 5201556Srgrimes * skip value to the size field and caluculate the size 5211556Srgrimes * of the padding. 5221556Srgrimes */ 5231556Srgrimes arcn->type = PAX_REG; 5241556Srgrimes arcn->sb.st_mode |= S_IFREG; 5251556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 5261556Srgrimes arcn->skip = arcn->sb.st_size; 5271556Srgrimes } 5281556Srgrimes break; 5291556Srgrimes } 5301556Srgrimes 5311556Srgrimes /* 5321556Srgrimes * strip off any trailing slash. 5331556Srgrimes */ 5341556Srgrimes if (*pt == '/') { 5358855Srgrimes *pt = '\0'; 5361556Srgrimes --arcn->nlen; 5371556Srgrimes } 5381556Srgrimes return(0); 5391556Srgrimes} 5401556Srgrimes 5411556Srgrimes/* 5421556Srgrimes * tar_wr() 5431556Srgrimes * write a tar header for the file specified in the ARCHD to the archive. 5441556Srgrimes * Have to check for file types that cannot be stored and file names that 5451556Srgrimes * are too long. Be careful of the term (last arg) to ul_oct, each field 5461556Srgrimes * of tar has it own spec for the termination character(s). 5471556Srgrimes * ASSUMED: space after header in header block is zero filled 5481556Srgrimes * Return: 5491556Srgrimes * 0 if file has data to be written after the header, 1 if file has NO 5501556Srgrimes * data to write after the header, -1 if archive write failed 5511556Srgrimes */ 5521556Srgrimes 5531556Srgrimes#if __STDC__ 5541556Srgrimesint 5551556Srgrimestar_wr(register ARCHD *arcn) 5561556Srgrimes#else 5571556Srgrimesint 5581556Srgrimestar_wr(arcn) 5591556Srgrimes register ARCHD *arcn; 5601556Srgrimes#endif 5611556Srgrimes{ 5621556Srgrimes register HD_TAR *hd; 5631556Srgrimes int len; 5641556Srgrimes char hdblk[sizeof(HD_TAR)]; 5651556Srgrimes 5661556Srgrimes /* 5671556Srgrimes * check for those file system types which tar cannot store 5681556Srgrimes */ 5691556Srgrimes switch(arcn->type) { 5701556Srgrimes case PAX_DIR: 5711556Srgrimes /* 5721556Srgrimes * user asked that dirs not be written to the archive 5731556Srgrimes */ 5741556Srgrimes if (tar_nodir) 5751556Srgrimes return(1); 5761556Srgrimes break; 5771556Srgrimes case PAX_CHR: 57828904Ssos pax_warn(1, "Tar cannot archive a character device %s", 5791556Srgrimes arcn->org_name); 5801556Srgrimes return(1); 5811556Srgrimes case PAX_BLK: 58228904Ssos pax_warn(1, "Tar cannot archive a block device %s", arcn->org_name); 5831556Srgrimes return(1); 5841556Srgrimes case PAX_SCK: 58528904Ssos pax_warn(1, "Tar cannot archive a socket %s", arcn->org_name); 5861556Srgrimes return(1); 5871556Srgrimes case PAX_FIF: 58828904Ssos pax_warn(1, "Tar cannot archive a fifo %s", arcn->org_name); 5891556Srgrimes return(1); 5901556Srgrimes case PAX_SLK: 5911556Srgrimes case PAX_HLK: 5921556Srgrimes case PAX_HRG: 5931556Srgrimes if (arcn->ln_nlen > sizeof(hd->linkname)) { 59428904Ssos pax_warn(1,"Link name too long for tar %s", arcn->ln_name); 5951556Srgrimes return(1); 5961556Srgrimes } 5971556Srgrimes break; 5981556Srgrimes case PAX_REG: 5991556Srgrimes case PAX_CTG: 6001556Srgrimes default: 6011556Srgrimes break; 6021556Srgrimes } 6031556Srgrimes 6041556Srgrimes /* 6051556Srgrimes * check file name len, remember extra char for dirs (the / at the end) 6061556Srgrimes */ 6071556Srgrimes len = arcn->nlen; 6081556Srgrimes if (arcn->type == PAX_DIR) 6091556Srgrimes ++len; 6101556Srgrimes if (len > sizeof(hd->name)) { 61128904Ssos pax_warn(1, "File name too long for tar %s", arcn->name); 6121556Srgrimes return(1); 6131556Srgrimes } 6141556Srgrimes 6151556Srgrimes /* 6161556Srgrimes * copy the data out of the ARCHD into the tar header based on the type 6171556Srgrimes * of the file. Remember many tar readers want the unused fields to be 6181556Srgrimes * padded with zero. We set the linkflag field (type), the linkname 6191556Srgrimes * (or zero if not used),the size, and set the padding (if any) to be 6201556Srgrimes * added after the file data (0 for all other types, as they only have 6211556Srgrimes * a header) 6221556Srgrimes */ 6231556Srgrimes hd = (HD_TAR *)hdblk; 6241556Srgrimes zf_strncpy(hd->name, arcn->name, sizeof(hd->name)); 6251556Srgrimes arcn->pad = 0; 6261556Srgrimes 6271556Srgrimes if (arcn->type == PAX_DIR) { 6281556Srgrimes /* 6291556Srgrimes * directories are the same as files, except have a filename 6301556Srgrimes * that ends with a /, we add the slash here. No data follows, 6311556Srgrimes * dirs, so no pad. 6321556Srgrimes */ 6331556Srgrimes hd->linkflag = AREGTYPE; 6341556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 6351556Srgrimes hd->name[len-1] = '/'; 6361556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 6371556Srgrimes goto out; 6381556Srgrimes } else if (arcn->type == PAX_SLK) { 6391556Srgrimes /* 6401556Srgrimes * no data follows this file, so no pad 6411556Srgrimes */ 6421556Srgrimes hd->linkflag = SYMTYPE; 6431556Srgrimes zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 6441556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 6451556Srgrimes goto out; 6461556Srgrimes } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 6471556Srgrimes /* 6481556Srgrimes * no data follows this file, so no pad 6491556Srgrimes */ 6501556Srgrimes hd->linkflag = LNKTYPE; 6511556Srgrimes zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 6521556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 6531556Srgrimes goto out; 6541556Srgrimes } else { 6551556Srgrimes /* 6561556Srgrimes * data follows this file, so set the pad 6571556Srgrimes */ 6581556Srgrimes hd->linkflag = AREGTYPE; 6591556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 6601556Srgrimes# ifdef NET2_STAT 6611556Srgrimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 6621556Srgrimes sizeof(hd->size), 1)) { 6631556Srgrimes# else 6641556Srgrimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 6651556Srgrimes sizeof(hd->size), 1)) { 6661556Srgrimes# endif 66728904Ssos pax_warn(1,"File is too large for tar %s", arcn->org_name); 6681556Srgrimes return(1); 6691556Srgrimes } 6701556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 6711556Srgrimes } 6721556Srgrimes 6731556Srgrimes /* 6741556Srgrimes * copy those fields that are independent of the type 6751556Srgrimes */ 6761556Srgrimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || 6771556Srgrimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || 6781556Srgrimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || 6791556Srgrimes ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) 6801556Srgrimes goto out; 6811556Srgrimes 6821556Srgrimes /* 6831556Srgrimes * calculate and add the checksum, then write the header. A return of 6841556Srgrimes * 0 tells the caller to now write the file data, 1 says no data needs 6851556Srgrimes * to be written 6861556Srgrimes */ 6871556Srgrimes if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, 6881556Srgrimes sizeof(hd->chksum), 2)) 6891556Srgrimes goto out; 6901556Srgrimes if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) 6911556Srgrimes return(-1); 6921556Srgrimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) 6931556Srgrimes return(-1); 6941556Srgrimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 6951556Srgrimes return(0); 6961556Srgrimes return(1); 6971556Srgrimes 6981556Srgrimes out: 6991556Srgrimes /* 7001556Srgrimes * header field is out of range 7011556Srgrimes */ 70228904Ssos pax_warn(1, "Tar header field is too small for %s", arcn->org_name); 7031556Srgrimes return(1); 7041556Srgrimes} 7051556Srgrimes 7061556Srgrimes/* 7071556Srgrimes * Routines for POSIX ustar 7081556Srgrimes */ 7091556Srgrimes 7101556Srgrimes/* 7111556Srgrimes * ustar_strd() 7121556Srgrimes * initialization for ustar read 7131556Srgrimes * Return: 7141556Srgrimes * 0 if ok, -1 otherwise 7151556Srgrimes */ 7161556Srgrimes 7171556Srgrimes#if __STDC__ 7181556Srgrimesint 7191556Srgrimesustar_strd(void) 7201556Srgrimes#else 7211556Srgrimesint 7221556Srgrimesustar_strd() 7231556Srgrimes#endif 7241556Srgrimes{ 7251556Srgrimes if ((usrtb_start() < 0) || (grptb_start() < 0)) 7261556Srgrimes return(-1); 7271556Srgrimes return(0); 7281556Srgrimes} 7291556Srgrimes 7301556Srgrimes/* 7311556Srgrimes * ustar_stwr() 7321556Srgrimes * initialization for ustar write 7331556Srgrimes * Return: 7341556Srgrimes * 0 if ok, -1 otherwise 7351556Srgrimes */ 7361556Srgrimes 7371556Srgrimes#if __STDC__ 7381556Srgrimesint 7391556Srgrimesustar_stwr(void) 7401556Srgrimes#else 7411556Srgrimesint 7421556Srgrimesustar_stwr() 7431556Srgrimes#endif 7441556Srgrimes{ 7451556Srgrimes if ((uidtb_start() < 0) || (gidtb_start() < 0)) 7461556Srgrimes return(-1); 7471556Srgrimes return(0); 7481556Srgrimes} 7491556Srgrimes 7501556Srgrimes/* 7511556Srgrimes * ustar_id() 7521556Srgrimes * determine if a block given to us is a valid ustar header. We have to 7531556Srgrimes * be on the lookout for those pesky blocks of all zero's 7541556Srgrimes * Return: 7551556Srgrimes * 0 if a ustar header, -1 otherwise 7561556Srgrimes */ 7571556Srgrimes 7581556Srgrimes#if __STDC__ 7591556Srgrimesint 7601556Srgrimesustar_id(char *blk, int size) 7611556Srgrimes#else 7621556Srgrimesint 7631556Srgrimesustar_id(blk, size) 7641556Srgrimes char *blk; 7651556Srgrimes int size; 7661556Srgrimes#endif 7671556Srgrimes{ 7681556Srgrimes register HD_USTAR *hd; 7691556Srgrimes 7701556Srgrimes if (size < BLKMULT) 7711556Srgrimes return(-1); 7721556Srgrimes hd = (HD_USTAR *)blk; 7731556Srgrimes 7741556Srgrimes /* 7751556Srgrimes * check for block of zero's first, a simple and fast test then check 7761556Srgrimes * ustar magic cookie. We should use TMAGLEN, but some USTAR archive 7771556Srgrimes * programs are fouled up and create archives missing the \0. Last we 7781556Srgrimes * check the checksum. If ok we have to assume it is a valid header. 7791556Srgrimes */ 7801556Srgrimes if (hd->name[0] == '\0') 7811556Srgrimes return(-1); 7821556Srgrimes if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) 7831556Srgrimes return(-1); 7841556Srgrimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 7851556Srgrimes return(-1); 7861556Srgrimes return(0); 7871556Srgrimes} 7881556Srgrimes 7891556Srgrimes/* 7901556Srgrimes * ustar_rd() 7911556Srgrimes * extract the values out of block already determined to be a ustar header. 7921556Srgrimes * store the values in the ARCHD parameter. 7931556Srgrimes * Return: 7941556Srgrimes * 0 7951556Srgrimes */ 7961556Srgrimes 7971556Srgrimes#if __STDC__ 7981556Srgrimesint 7991556Srgrimesustar_rd(register ARCHD *arcn, register char *buf) 8001556Srgrimes#else 8011556Srgrimesint 8021556Srgrimesustar_rd(arcn, buf) 8031556Srgrimes register ARCHD *arcn; 8041556Srgrimes register char *buf; 8051556Srgrimes#endif 8061556Srgrimes{ 8071556Srgrimes register HD_USTAR *hd; 8081556Srgrimes register char *dest; 8091556Srgrimes register int cnt = 0; 8101556Srgrimes dev_t devmajor; 8111556Srgrimes dev_t devminor; 8121556Srgrimes 8131556Srgrimes /* 8141556Srgrimes * we only get proper sized buffers 8151556Srgrimes */ 8161556Srgrimes if (ustar_id(buf, BLKMULT) < 0) 8171556Srgrimes return(-1); 8181556Srgrimes arcn->org_name = arcn->name; 8191556Srgrimes arcn->sb.st_nlink = 1; 8201556Srgrimes arcn->pat = NULL; 8211556Srgrimes hd = (HD_USTAR *)buf; 8221556Srgrimes 8231556Srgrimes /* 8241556Srgrimes * see if the filename is split into two parts. if, so joint the parts. 8251556Srgrimes * we copy the prefix first and add a / between the prefix and name. 8261556Srgrimes */ 8271556Srgrimes dest = arcn->name; 8281556Srgrimes if (*(hd->prefix) != '\0') { 8291556Srgrimes cnt = l_strncpy(arcn->name, hd->prefix, sizeof(hd->prefix)); 8301556Srgrimes dest = arcn->name + arcn->nlen; 8311556Srgrimes *dest++ = '/'; 8321556Srgrimes } 8331556Srgrimes arcn->nlen = l_strncpy(dest, hd->name, sizeof(hd->name)); 8341556Srgrimes arcn->nlen += cnt; 8351556Srgrimes arcn->name[arcn->nlen] = '\0'; 8361556Srgrimes 8371556Srgrimes /* 8381556Srgrimes * follow the spec to the letter. we should only have mode bits, strip 8391556Srgrimes * off all other crud we may be passed. 8401556Srgrimes */ 8411556Srgrimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 8421556Srgrimes 0xfff); 8431556Srgrimes arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); 8441556Srgrimes arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 8451556Srgrimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 8461556Srgrimes 8471556Srgrimes /* 8481556Srgrimes * If we can find the ascii names for gname and uname in the password 8491556Srgrimes * and group files we will use the uid's and gid they bind. Otherwise 8501556Srgrimes * we use the uid and gid values stored in the header. (This is what 8511556Srgrimes * the posix spec wants). 8521556Srgrimes */ 8531556Srgrimes hd->gname[sizeof(hd->gname) - 1] = '\0'; 8541556Srgrimes if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) 8551556Srgrimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 8561556Srgrimes hd->uname[sizeof(hd->uname) - 1] = '\0'; 8571556Srgrimes if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) 8581556Srgrimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 8591556Srgrimes 8601556Srgrimes /* 8611556Srgrimes * set the defaults, these may be changed depending on the file type 8621556Srgrimes */ 8631556Srgrimes arcn->ln_name[0] = '\0'; 8641556Srgrimes arcn->ln_nlen = 0; 8651556Srgrimes arcn->pad = 0; 8661556Srgrimes arcn->skip = 0; 8671556Srgrimes arcn->sb.st_rdev = (dev_t)0; 8681556Srgrimes 8691556Srgrimes /* 8701556Srgrimes * set the mode and PAX type according to the typeflag in the header 8711556Srgrimes */ 8721556Srgrimes switch(hd->typeflag) { 8731556Srgrimes case FIFOTYPE: 8741556Srgrimes arcn->type = PAX_FIF; 8751556Srgrimes arcn->sb.st_mode |= S_IFIFO; 8761556Srgrimes break; 8771556Srgrimes case DIRTYPE: 8781556Srgrimes arcn->type = PAX_DIR; 8791556Srgrimes arcn->sb.st_mode |= S_IFDIR; 8801556Srgrimes arcn->sb.st_nlink = 2; 8811556Srgrimes 8821556Srgrimes /* 8831556Srgrimes * Some programs that create ustar archives append a '/' 8841556Srgrimes * to the pathname for directories. This clearly violates 8851556Srgrimes * ustar specs, but we will silently strip it off anyway. 8861556Srgrimes */ 8871556Srgrimes if (arcn->name[arcn->nlen - 1] == '/') 8881556Srgrimes arcn->name[--arcn->nlen] = '\0'; 8891556Srgrimes break; 8901556Srgrimes case BLKTYPE: 8911556Srgrimes case CHRTYPE: 8921556Srgrimes /* 8931556Srgrimes * this type requires the rdev field to be set. 8941556Srgrimes */ 8951556Srgrimes if (hd->typeflag == BLKTYPE) { 8961556Srgrimes arcn->type = PAX_BLK; 8971556Srgrimes arcn->sb.st_mode |= S_IFBLK; 8981556Srgrimes } else { 8991556Srgrimes arcn->type = PAX_CHR; 9001556Srgrimes arcn->sb.st_mode |= S_IFCHR; 9011556Srgrimes } 9021556Srgrimes devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); 9031556Srgrimes devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); 9041556Srgrimes arcn->sb.st_rdev = TODEV(devmajor, devminor); 9051556Srgrimes break; 9061556Srgrimes case SYMTYPE: 9071556Srgrimes case LNKTYPE: 9081556Srgrimes if (hd->typeflag == SYMTYPE) { 9091556Srgrimes arcn->type = PAX_SLK; 9101556Srgrimes arcn->sb.st_mode |= S_IFLNK; 9111556Srgrimes } else { 9121556Srgrimes arcn->type = PAX_HLK; 9131556Srgrimes /* 9141556Srgrimes * so printing looks better 9151556Srgrimes */ 9161556Srgrimes arcn->sb.st_mode |= S_IFREG; 9171556Srgrimes arcn->sb.st_nlink = 2; 9181556Srgrimes } 9191556Srgrimes /* 9201556Srgrimes * copy the link name 9211556Srgrimes */ 9221556Srgrimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 9231556Srgrimes sizeof(hd->linkname)); 9241556Srgrimes arcn->ln_name[arcn->ln_nlen] = '\0'; 9251556Srgrimes break; 9261556Srgrimes case CONTTYPE: 9271556Srgrimes case AREGTYPE: 9281556Srgrimes case REGTYPE: 9291556Srgrimes default: 9301556Srgrimes /* 9311556Srgrimes * these types have file data that follows. Set the skip and 9321556Srgrimes * pad fields. 9331556Srgrimes */ 9341556Srgrimes arcn->type = PAX_REG; 9351556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 9361556Srgrimes arcn->skip = arcn->sb.st_size; 9371556Srgrimes arcn->sb.st_mode |= S_IFREG; 9381556Srgrimes break; 9391556Srgrimes } 9401556Srgrimes return(0); 9411556Srgrimes} 9421556Srgrimes 9431556Srgrimes/* 9441556Srgrimes * ustar_wr() 9451556Srgrimes * write a ustar header for the file specified in the ARCHD to the archive 9461556Srgrimes * Have to check for file types that cannot be stored and file names that 9471556Srgrimes * are too long. Be careful of the term (last arg) to ul_oct, we only use 9481556Srgrimes * '\0' for the termination character (this is different than picky tar) 9491556Srgrimes * ASSUMED: space after header in header block is zero filled 9501556Srgrimes * Return: 9511556Srgrimes * 0 if file has data to be written after the header, 1 if file has NO 9521556Srgrimes * data to write after the header, -1 if archive write failed 9531556Srgrimes */ 9541556Srgrimes 9551556Srgrimes#if __STDC__ 9561556Srgrimesint 9571556Srgrimesustar_wr(register ARCHD *arcn) 9581556Srgrimes#else 9591556Srgrimesint 9601556Srgrimesustar_wr(arcn) 9611556Srgrimes register ARCHD *arcn; 9621556Srgrimes#endif 9631556Srgrimes{ 9641556Srgrimes register HD_USTAR *hd; 9651556Srgrimes register char *pt; 9661556Srgrimes char hdblk[sizeof(HD_USTAR)]; 9671556Srgrimes 9681556Srgrimes /* 9691556Srgrimes * check for those file system types ustar cannot store 9701556Srgrimes */ 9711556Srgrimes if (arcn->type == PAX_SCK) { 97228904Ssos pax_warn(1, "Ustar cannot archive a socket %s", arcn->org_name); 9731556Srgrimes return(1); 9741556Srgrimes } 9751556Srgrimes 9761556Srgrimes /* 9771556Srgrimes * check the length of the linkname 9781556Srgrimes */ 9791556Srgrimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 9801556Srgrimes (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){ 98128904Ssos pax_warn(1, "Link name too long for ustar %s", arcn->ln_name); 9821556Srgrimes return(1); 9831556Srgrimes } 9841556Srgrimes 9851556Srgrimes /* 9861556Srgrimes * split the path name into prefix and name fields (if needed). if 9871556Srgrimes * pt != arcn->name, the name has to be split 9881556Srgrimes */ 9891556Srgrimes if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { 99028904Ssos pax_warn(1, "File name too long for ustar %s", arcn->name); 9911556Srgrimes return(1); 9921556Srgrimes } 9931556Srgrimes hd = (HD_USTAR *)hdblk; 9941556Srgrimes arcn->pad = 0L; 9951556Srgrimes 9961556Srgrimes /* 9971556Srgrimes * split the name, or zero out the prefix 9981556Srgrimes */ 9991556Srgrimes if (pt != arcn->name) { 10001556Srgrimes /* 10011556Srgrimes * name was split, pt points at the / where the split is to 10021556Srgrimes * occur, we remove the / and copy the first part to the prefix 10031556Srgrimes */ 10041556Srgrimes *pt = '\0'; 10051556Srgrimes zf_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); 10061556Srgrimes *pt++ = '/'; 10071556Srgrimes } else 10081556Srgrimes bzero(hd->prefix, sizeof(hd->prefix)); 10091556Srgrimes 10101556Srgrimes /* 10111556Srgrimes * copy the name part. this may be the whole path or the part after 10121556Srgrimes * the prefix 10131556Srgrimes */ 10141556Srgrimes zf_strncpy(hd->name, pt, sizeof(hd->name)); 10151556Srgrimes 10168855Srgrimes /* 10171556Srgrimes * set the fields in the header that are type dependent 10181556Srgrimes */ 10191556Srgrimes switch(arcn->type) { 10201556Srgrimes case PAX_DIR: 10211556Srgrimes hd->typeflag = DIRTYPE; 10221556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 10231556Srgrimes bzero(hd->devmajor, sizeof(hd->devmajor)); 10241556Srgrimes bzero(hd->devminor, sizeof(hd->devminor)); 10251556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 10261556Srgrimes goto out; 10271556Srgrimes break; 10281556Srgrimes case PAX_CHR: 10291556Srgrimes case PAX_BLK: 10301556Srgrimes if (arcn->type == PAX_CHR) 10311556Srgrimes hd->typeflag = CHRTYPE; 10321556Srgrimes else 10331556Srgrimes hd->typeflag = BLKTYPE; 10341556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 10351556Srgrimes if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, 10361556Srgrimes sizeof(hd->devmajor), 3) || 10371556Srgrimes ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, 10381556Srgrimes sizeof(hd->devminor), 3) || 10391556Srgrimes ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 10401556Srgrimes goto out; 10411556Srgrimes break; 10421556Srgrimes case PAX_FIF: 10431556Srgrimes hd->typeflag = FIFOTYPE; 10441556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 10451556Srgrimes bzero(hd->devmajor, sizeof(hd->devmajor)); 10461556Srgrimes bzero(hd->devminor, sizeof(hd->devminor)); 10471556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 10481556Srgrimes goto out; 10491556Srgrimes break; 10501556Srgrimes case PAX_SLK: 10511556Srgrimes case PAX_HLK: 10521556Srgrimes case PAX_HRG: 10531556Srgrimes if (arcn->type == PAX_SLK) 10541556Srgrimes hd->typeflag = SYMTYPE; 10551556Srgrimes else 10561556Srgrimes hd->typeflag = LNKTYPE; 10571556Srgrimes zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 10581556Srgrimes bzero(hd->devmajor, sizeof(hd->devmajor)); 10591556Srgrimes bzero(hd->devminor, sizeof(hd->devminor)); 10601556Srgrimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 10611556Srgrimes goto out; 10621556Srgrimes break; 10631556Srgrimes case PAX_REG: 10641556Srgrimes case PAX_CTG: 10651556Srgrimes default: 10661556Srgrimes /* 10671556Srgrimes * file data with this type, set the padding 10681556Srgrimes */ 10691556Srgrimes if (arcn->type == PAX_CTG) 10701556Srgrimes hd->typeflag = CONTTYPE; 10711556Srgrimes else 10721556Srgrimes hd->typeflag = REGTYPE; 10731556Srgrimes bzero(hd->linkname, sizeof(hd->linkname)); 10741556Srgrimes bzero(hd->devmajor, sizeof(hd->devmajor)); 10751556Srgrimes bzero(hd->devminor, sizeof(hd->devminor)); 10761556Srgrimes arcn->pad = TAR_PAD(arcn->sb.st_size); 10771556Srgrimes# ifdef NET2_STAT 10781556Srgrimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 10791556Srgrimes sizeof(hd->size), 3)) { 10801556Srgrimes# else 10811556Srgrimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 10821556Srgrimes sizeof(hd->size), 3)) { 10831556Srgrimes# endif 108428904Ssos pax_warn(1,"File is too long for ustar %s",arcn->org_name); 10851556Srgrimes return(1); 10861556Srgrimes } 10871556Srgrimes break; 10881556Srgrimes } 10891556Srgrimes 10901556Srgrimes zf_strncpy(hd->magic, TMAGIC, TMAGLEN); 10911556Srgrimes zf_strncpy(hd->version, TVERSION, TVERSLEN); 10921556Srgrimes 10931556Srgrimes /* 10941556Srgrimes * set the remaining fields. Some versions want all 16 bits of mode 10951556Srgrimes * we better humor them (they really do not meet spec though).... 10961556Srgrimes */ 10971556Srgrimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || 10981556Srgrimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || 10991556Srgrimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || 11001556Srgrimes ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) 11011556Srgrimes goto out; 11021556Srgrimes zf_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); 11031556Srgrimes zf_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); 11041556Srgrimes 11051556Srgrimes /* 11061556Srgrimes * calculate and store the checksum write the header to the archive 11071556Srgrimes * return 0 tells the caller to now write the file data, 1 says no data 11081556Srgrimes * needs to be written 11091556Srgrimes */ 11101556Srgrimes if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, 11111556Srgrimes sizeof(hd->chksum), 3)) 11121556Srgrimes goto out; 11131556Srgrimes if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) 11141556Srgrimes return(-1); 11151556Srgrimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) 11161556Srgrimes return(-1); 11171556Srgrimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 11181556Srgrimes return(0); 11191556Srgrimes return(1); 11201556Srgrimes 11211556Srgrimes out: 11221556Srgrimes /* 11231556Srgrimes * header field is out of range 11241556Srgrimes */ 112528904Ssos pax_warn(1, "Ustar header field is too small for %s", arcn->org_name); 11261556Srgrimes return(1); 11271556Srgrimes} 11281556Srgrimes 11291556Srgrimes/* 11301556Srgrimes * name_split() 11311556Srgrimes * see if the name has to be split for storage in a ustar header. We try 11321556Srgrimes * to fit the entire name in the name field without splitting if we can. 11331556Srgrimes * The split point is always at a / 11341556Srgrimes * Return 11351556Srgrimes * character pointer to split point (always the / that is to be removed 11361556Srgrimes * if the split is not needed, the points is set to the start of the file 11371556Srgrimes * name (it would violate the spec to split there). A NULL is returned if 11381556Srgrimes * the file name is too long 11391556Srgrimes */ 11401556Srgrimes 11411556Srgrimes#if __STDC__ 11421556Srgrimesstatic char * 11431556Srgrimesname_split(register char *name, register int len) 11441556Srgrimes#else 11451556Srgrimesstatic char * 11461556Srgrimesname_split(name, len) 11471556Srgrimes register char *name; 11481556Srgrimes register int len; 11491556Srgrimes#endif 11501556Srgrimes{ 11511556Srgrimes register char *start; 11521556Srgrimes 11531556Srgrimes /* 11541556Srgrimes * check to see if the file name is small enough to fit in the name 11551556Srgrimes * field. if so just return a pointer to the name. 11561556Srgrimes */ 11571556Srgrimes if (len <= TNMSZ) 11581556Srgrimes return(name); 11591556Srgrimes if (len > (TPFSZ + TNMSZ + 1)) 11601556Srgrimes return(NULL); 11611556Srgrimes 11621556Srgrimes /* 11631556Srgrimes * we start looking at the biggest sized piece that fits in the name 11641556Srgrimes * field. We walk foward looking for a slash to split at. The idea is 11651556Srgrimes * to find the biggest piece to fit in the name field (or the smallest 11661556Srgrimes * prefix we can find) (the -1 is correct the biggest piece would 11671556Srgrimes * include the slash between the two parts that gets thrown away) 11681556Srgrimes */ 11691556Srgrimes start = name + len - TNMSZ - 1; 11701556Srgrimes while ((*start != '\0') && (*start != '/')) 11711556Srgrimes ++start; 11721556Srgrimes 11731556Srgrimes /* 11741556Srgrimes * if we hit the end of the string, this name cannot be split, so we 11751556Srgrimes * cannot store this file. 11761556Srgrimes */ 11771556Srgrimes if (*start == '\0') 11781556Srgrimes return(NULL); 11791556Srgrimes len = start - name; 11801556Srgrimes 11811556Srgrimes /* 11821556Srgrimes * NOTE: /str where the length of str == TNMSZ can not be stored under 11831556Srgrimes * the p1003.1-1990 spec for ustar. We could force a prefix of / and 11841556Srgrimes * the file would then expand on extract to //str. The len == 0 below 11851556Srgrimes * makes this special case follow the spec to the letter. 11861556Srgrimes */ 11871556Srgrimes if ((len > TPFSZ) || (len == 0)) 11881556Srgrimes return(NULL); 11891556Srgrimes 11901556Srgrimes /* 11911556Srgrimes * ok have a split point, return it to the caller 11921556Srgrimes */ 11931556Srgrimes return(start); 11941556Srgrimes} 1195