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