14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1992 Keith Muller. 34b88c807SRodney W. Grimes * Copyright (c) 1992, 1993 44b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 54b88c807SRodney W. Grimes * 64b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 74b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego. 84b88c807SRodney W. Grimes * 94b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 104b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 114b88c807SRodney W. Grimes * are met: 124b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 134b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 144b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 164b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 17*fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 184b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 194b88c807SRodney W. Grimes * without specific prior written permission. 204b88c807SRodney W. Grimes * 214b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 224b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 234b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 244b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 254b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 264b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 274b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 284b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 294b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 304b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314b88c807SRodney W. Grimes * SUCH DAMAGE. 324b88c807SRodney W. Grimes */ 334b88c807SRodney W. Grimes 344b88c807SRodney W. Grimes #ifndef lint 35c9a8d1f4SPhilippe Charnier #if 0 36c9a8d1f4SPhilippe Charnier static char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; 37c9a8d1f4SPhilippe Charnier #endif 384b88c807SRodney W. Grimes #endif /* not lint */ 392749b141SDavid E. O'Brien #include <sys/cdefs.h> 402749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 414b88c807SRodney W. Grimes 424b88c807SRodney W. Grimes #include <sys/types.h> 434b88c807SRodney W. Grimes #include <sys/time.h> 444b88c807SRodney W. Grimes #include <sys/stat.h> 454b88c807SRodney W. Grimes #include <string.h> 464b88c807SRodney W. Grimes #include <stdio.h> 474b88c807SRodney W. Grimes #include "pax.h" 484b88c807SRodney W. Grimes #include "extern.h" 494b88c807SRodney W. Grimes #include "tar.h" 504b88c807SRodney W. Grimes 514b88c807SRodney W. Grimes /* 524b88c807SRodney W. Grimes * Routines for reading, writing and header identify of various versions of tar 534b88c807SRodney W. Grimes */ 544b88c807SRodney W. Grimes 55f789b261SWarner Losh static u_long tar_chksm(char *, int); 56f789b261SWarner Losh static char *name_split(char *, int); 57f789b261SWarner Losh static int ul_oct(u_long, char *, int, int); 584b88c807SRodney W. Grimes #ifndef NET2_STAT 59f789b261SWarner Losh static int uqd_oct(u_quad_t, char *, int, int); 604b88c807SRodney W. Grimes #endif 614b88c807SRodney W. Grimes 624b88c807SRodney W. Grimes /* 634b88c807SRodney W. Grimes * Routines common to all versions of tar 644b88c807SRodney W. Grimes */ 654b88c807SRodney W. Grimes 664b88c807SRodney W. Grimes static int tar_nodir; /* do not write dirs under old tar */ 674b88c807SRodney W. Grimes 684b88c807SRodney W. Grimes /* 694b88c807SRodney W. Grimes * tar_endwr() 704b88c807SRodney W. Grimes * add the tar trailer of two null blocks 714b88c807SRodney W. Grimes * Return: 724b88c807SRodney W. Grimes * 0 if ok, -1 otherwise (what wr_skip returns) 734b88c807SRodney W. Grimes */ 744b88c807SRodney W. Grimes 754b88c807SRodney W. Grimes int 764b88c807SRodney W. Grimes tar_endwr(void) 774b88c807SRodney W. Grimes { 784b88c807SRodney W. Grimes return(wr_skip((off_t)(NULLCNT*BLKMULT))); 794b88c807SRodney W. Grimes } 804b88c807SRodney W. Grimes 814b88c807SRodney W. Grimes /* 824b88c807SRodney W. Grimes * tar_endrd() 834b88c807SRodney W. Grimes * no cleanup needed here, just return size of trailer (for append) 844b88c807SRodney W. Grimes * Return: 854b88c807SRodney W. Grimes * size of trailer (2 * BLKMULT) 864b88c807SRodney W. Grimes */ 874b88c807SRodney W. Grimes 884b88c807SRodney W. Grimes off_t 894b88c807SRodney W. Grimes tar_endrd(void) 904b88c807SRodney W. Grimes { 914b88c807SRodney W. Grimes return((off_t)(NULLCNT*BLKMULT)); 924b88c807SRodney W. Grimes } 934b88c807SRodney W. Grimes 944b88c807SRodney W. Grimes /* 954b88c807SRodney W. Grimes * tar_trail() 964b88c807SRodney W. Grimes * Called to determine if a header block is a valid trailer. We are passed 974b88c807SRodney W. Grimes * the block, the in_sync flag (which tells us we are in resync mode; 984b88c807SRodney W. Grimes * looking for a valid header), and cnt (which starts at zero) which is 994b88c807SRodney W. Grimes * used to count the number of empty blocks we have seen so far. 1004b88c807SRodney W. Grimes * Return: 1014b88c807SRodney W. Grimes * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block 1024b88c807SRodney W. Grimes * could never contain a header. 1034b88c807SRodney W. Grimes */ 1044b88c807SRodney W. Grimes 1054b88c807SRodney W. Grimes int 106f789b261SWarner Losh tar_trail(char *buf, int in_resync, int *cnt) 1074b88c807SRodney W. Grimes { 108f789b261SWarner Losh int i; 1094b88c807SRodney W. Grimes 1104b88c807SRodney W. Grimes /* 1114b88c807SRodney W. Grimes * look for all zero, trailer is two consecutive blocks of zero 1124b88c807SRodney W. Grimes */ 1134b88c807SRodney W. Grimes for (i = 0; i < BLKMULT; ++i) { 1144b88c807SRodney W. Grimes if (buf[i] != '\0') 1154b88c807SRodney W. Grimes break; 1164b88c807SRodney W. Grimes } 1174b88c807SRodney W. Grimes 1184b88c807SRodney W. Grimes /* 1194b88c807SRodney W. Grimes * if not all zero it is not a trailer, but MIGHT be a header. 1204b88c807SRodney W. Grimes */ 1214b88c807SRodney W. Grimes if (i != BLKMULT) 1224b88c807SRodney W. Grimes return(-1); 1234b88c807SRodney W. Grimes 1244b88c807SRodney W. Grimes /* 1254b88c807SRodney W. Grimes * When given a zero block, we must be careful! 1264b88c807SRodney W. Grimes * If we are not in resync mode, check for the trailer. Have to watch 1274b88c807SRodney W. Grimes * out that we do not mis-identify file data as the trailer, so we do 1284b88c807SRodney W. Grimes * NOT try to id a trailer during resync mode. During resync mode we 1294b88c807SRodney W. Grimes * might as well throw this block out since a valid header can NEVER be 1304b88c807SRodney W. Grimes * a block of all 0 (we must have a valid file name). 1314b88c807SRodney W. Grimes */ 1324b88c807SRodney W. Grimes if (!in_resync && (++*cnt >= NULLCNT)) 1334b88c807SRodney W. Grimes return(0); 1344b88c807SRodney W. Grimes return(1); 1354b88c807SRodney W. Grimes } 1364b88c807SRodney W. Grimes 1374b88c807SRodney W. Grimes /* 1384b88c807SRodney W. Grimes * ul_oct() 1394b88c807SRodney W. Grimes * convert an unsigned long to an octal string. many oddball field 1404b88c807SRodney W. Grimes * termination characters are used by the various versions of tar in the 141b1787decSKris Kennaway * different fields. term selects which kind to use. str is '0' padded 1424b88c807SRodney W. Grimes * at the front to len. we are unable to use only one format as many old 1434b88c807SRodney W. Grimes * tar readers are very cranky about this. 1444b88c807SRodney W. Grimes * Return: 1454b88c807SRodney W. Grimes * 0 if the number fit into the string, -1 otherwise 1464b88c807SRodney W. Grimes */ 1474b88c807SRodney W. Grimes 1484b88c807SRodney W. Grimes static int 149f789b261SWarner Losh ul_oct(u_long val, char *str, int len, int term) 1504b88c807SRodney W. Grimes { 151f789b261SWarner Losh char *pt; 1524b88c807SRodney W. Grimes 1534b88c807SRodney W. Grimes /* 1544b88c807SRodney W. Grimes * term selects the appropriate character(s) for the end of the string 1554b88c807SRodney W. Grimes */ 1564b88c807SRodney W. Grimes pt = str + len - 1; 1574b88c807SRodney W. Grimes switch(term) { 1584b88c807SRodney W. Grimes case 3: 1594b88c807SRodney W. Grimes *pt-- = '\0'; 1604b88c807SRodney W. Grimes break; 1614b88c807SRodney W. Grimes case 2: 1624b88c807SRodney W. Grimes *pt-- = ' '; 1634b88c807SRodney W. Grimes *pt-- = '\0'; 1644b88c807SRodney W. Grimes break; 1654b88c807SRodney W. Grimes case 1: 1664b88c807SRodney W. Grimes *pt-- = ' '; 1674b88c807SRodney W. Grimes break; 1684b88c807SRodney W. Grimes case 0: 1694b88c807SRodney W. Grimes default: 1704b88c807SRodney W. Grimes *pt-- = '\0'; 1714b88c807SRodney W. Grimes *pt-- = ' '; 1724b88c807SRodney W. Grimes break; 1734b88c807SRodney W. Grimes } 1744b88c807SRodney W. Grimes 1754b88c807SRodney W. Grimes /* 1764b88c807SRodney W. Grimes * convert and blank pad if there is space 1774b88c807SRodney W. Grimes */ 1784b88c807SRodney W. Grimes while (pt >= str) { 1794b88c807SRodney W. Grimes *pt-- = '0' + (char)(val & 0x7); 1804b88c807SRodney W. Grimes if ((val = val >> 3) == (u_long)0) 1814b88c807SRodney W. Grimes break; 1824b88c807SRodney W. Grimes } 1834b88c807SRodney W. Grimes 1844b88c807SRodney W. Grimes while (pt >= str) 185b1787decSKris Kennaway *pt-- = '0'; 1864b88c807SRodney W. Grimes if (val != (u_long)0) 1874b88c807SRodney W. Grimes return(-1); 1884b88c807SRodney W. Grimes return(0); 1894b88c807SRodney W. Grimes } 1904b88c807SRodney W. Grimes 1914b88c807SRodney W. Grimes #ifndef NET2_STAT 1924b88c807SRodney W. Grimes /* 1934b88c807SRodney W. Grimes * uqd_oct() 1944b88c807SRodney W. Grimes * convert an u_quad_t to an octal string. one of many oddball field 1954b88c807SRodney W. Grimes * termination characters are used by the various versions of tar in the 196b1787decSKris Kennaway * different fields. term selects which kind to use. str is '0' padded 1974b88c807SRodney W. Grimes * at the front to len. we are unable to use only one format as many old 1984b88c807SRodney W. Grimes * tar readers are very cranky about this. 1994b88c807SRodney W. Grimes * Return: 2004b88c807SRodney W. Grimes * 0 if the number fit into the string, -1 otherwise 2014b88c807SRodney W. Grimes */ 2024b88c807SRodney W. Grimes 2034b88c807SRodney W. Grimes static int 204f789b261SWarner Losh uqd_oct(u_quad_t val, char *str, int len, int term) 2054b88c807SRodney W. Grimes { 206f789b261SWarner Losh char *pt; 2074b88c807SRodney W. Grimes 2084b88c807SRodney W. Grimes /* 2094b88c807SRodney W. Grimes * term selects the appropriate character(s) for the end of the string 2104b88c807SRodney W. Grimes */ 2114b88c807SRodney W. Grimes pt = str + len - 1; 2124b88c807SRodney W. Grimes switch(term) { 2134b88c807SRodney W. Grimes case 3: 2144b88c807SRodney W. Grimes *pt-- = '\0'; 2154b88c807SRodney W. Grimes break; 2164b88c807SRodney W. Grimes case 2: 2174b88c807SRodney W. Grimes *pt-- = ' '; 2184b88c807SRodney W. Grimes *pt-- = '\0'; 2194b88c807SRodney W. Grimes break; 2204b88c807SRodney W. Grimes case 1: 2214b88c807SRodney W. Grimes *pt-- = ' '; 2224b88c807SRodney W. Grimes break; 2234b88c807SRodney W. Grimes case 0: 2244b88c807SRodney W. Grimes default: 2254b88c807SRodney W. Grimes *pt-- = '\0'; 2264b88c807SRodney W. Grimes *pt-- = ' '; 2274b88c807SRodney W. Grimes break; 2284b88c807SRodney W. Grimes } 2294b88c807SRodney W. Grimes 2304b88c807SRodney W. Grimes /* 2314b88c807SRodney W. Grimes * convert and blank pad if there is space 2324b88c807SRodney W. Grimes */ 2334b88c807SRodney W. Grimes while (pt >= str) { 2344b88c807SRodney W. Grimes *pt-- = '0' + (char)(val & 0x7); 2354b88c807SRodney W. Grimes if ((val = val >> 3) == 0) 2364b88c807SRodney W. Grimes break; 2374b88c807SRodney W. Grimes } 2384b88c807SRodney W. Grimes 2394b88c807SRodney W. Grimes while (pt >= str) 240b1787decSKris Kennaway *pt-- = '0'; 2414b88c807SRodney W. Grimes if (val != (u_quad_t)0) 2424b88c807SRodney W. Grimes return(-1); 2434b88c807SRodney W. Grimes return(0); 2444b88c807SRodney W. Grimes } 2454b88c807SRodney W. Grimes #endif 2464b88c807SRodney W. Grimes 2474b88c807SRodney W. Grimes /* 2484b88c807SRodney W. Grimes * tar_chksm() 2494b88c807SRodney W. Grimes * calculate the checksum for a tar block counting the checksum field as 25046be34b9SKris Kennaway * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). 2514b88c807SRodney W. Grimes * NOTE: we use len to short circuit summing 0's on write since we ALWAYS 2524b88c807SRodney W. Grimes * pad headers with 0. 2534b88c807SRodney W. Grimes * Return: 2544b88c807SRodney W. Grimes * unsigned long checksum 2554b88c807SRodney W. Grimes */ 2564b88c807SRodney W. Grimes 2574b88c807SRodney W. Grimes static u_long 258f789b261SWarner Losh tar_chksm(char *blk, int len) 2594b88c807SRodney W. Grimes { 260f789b261SWarner Losh char *stop; 261f789b261SWarner Losh char *pt; 26246be34b9SKris Kennaway u_long chksm = BLNKSUM; /* initial value is checksum field sum */ 2634b88c807SRodney W. Grimes 2644b88c807SRodney W. Grimes /* 2654b88c807SRodney W. Grimes * add the part of the block before the checksum field 2664b88c807SRodney W. Grimes */ 2674b88c807SRodney W. Grimes pt = blk; 2684b88c807SRodney W. Grimes stop = blk + CHK_OFFSET; 2694b88c807SRodney W. Grimes while (pt < stop) 2704b88c807SRodney W. Grimes chksm += (u_long)(*pt++ & 0xff); 2714b88c807SRodney W. Grimes /* 2724b88c807SRodney W. Grimes * move past the checksum field and keep going, spec counts the 2734b88c807SRodney W. Grimes * checksum field as the sum of 8 blanks (which is pre-computed as 2744b88c807SRodney W. Grimes * BLNKSUM). 2754b88c807SRodney W. Grimes * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding 2764b88c807SRodney W. Grimes * starts, no point in summing zero's) 2774b88c807SRodney W. Grimes */ 2784b88c807SRodney W. Grimes pt += CHK_LEN; 2794b88c807SRodney W. Grimes stop = blk + len; 2804b88c807SRodney W. Grimes while (pt < stop) 2814b88c807SRodney W. Grimes chksm += (u_long)(*pt++ & 0xff); 2824b88c807SRodney W. Grimes return(chksm); 2834b88c807SRodney W. Grimes } 2844b88c807SRodney W. Grimes 2854b88c807SRodney W. Grimes /* 2864b88c807SRodney W. Grimes * Routines for old BSD style tar (also made portable to sysV tar) 2874b88c807SRodney W. Grimes */ 2884b88c807SRodney W. Grimes 2894b88c807SRodney W. Grimes /* 2904b88c807SRodney W. Grimes * tar_id() 2914b88c807SRodney W. Grimes * determine if a block given to us is a valid tar header (and not a USTAR 2924b88c807SRodney W. Grimes * header). We have to be on the lookout for those pesky blocks of all 2934b88c807SRodney W. Grimes * zero's. 2944b88c807SRodney W. Grimes * Return: 2954b88c807SRodney W. Grimes * 0 if a tar header, -1 otherwise 2964b88c807SRodney W. Grimes */ 2974b88c807SRodney W. Grimes 2984b88c807SRodney W. Grimes int 299f789b261SWarner Losh tar_id(char *blk, int size) 3004b88c807SRodney W. Grimes { 301f789b261SWarner Losh HD_TAR *hd; 302f789b261SWarner Losh HD_USTAR *uhd; 3034b88c807SRodney W. Grimes 3044b88c807SRodney W. Grimes if (size < BLKMULT) 3054b88c807SRodney W. Grimes return(-1); 3064b88c807SRodney W. Grimes hd = (HD_TAR *)blk; 3074b88c807SRodney W. Grimes uhd = (HD_USTAR *)blk; 3084b88c807SRodney W. Grimes 3094b88c807SRodney W. Grimes /* 3104b88c807SRodney W. Grimes * check for block of zero's first, a simple and fast test, then make 3114b88c807SRodney W. Grimes * sure this is not a ustar header by looking for the ustar magic 3124b88c807SRodney W. Grimes * cookie. We should use TMAGLEN, but some USTAR archive programs are 3134b88c807SRodney W. Grimes * wrong and create archives missing the \0. Last we check the 3144b88c807SRodney W. Grimes * checksum. If this is ok we have to assume it is a valid header. 3154b88c807SRodney W. Grimes */ 3164b88c807SRodney W. Grimes if (hd->name[0] == '\0') 3174b88c807SRodney W. Grimes return(-1); 3184b88c807SRodney W. Grimes if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) 3194b88c807SRodney W. Grimes return(-1); 3204b88c807SRodney W. Grimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 3214b88c807SRodney W. Grimes return(-1); 3224b88c807SRodney W. Grimes return(0); 3234b88c807SRodney W. Grimes } 3244b88c807SRodney W. Grimes 3254b88c807SRodney W. Grimes /* 3264b88c807SRodney W. Grimes * tar_opt() 3274b88c807SRodney W. Grimes * handle tar format specific -o options 3284b88c807SRodney W. Grimes * Return: 3294b88c807SRodney W. Grimes * 0 if ok -1 otherwise 3304b88c807SRodney W. Grimes */ 3314b88c807SRodney W. Grimes 3324b88c807SRodney W. Grimes int 3334b88c807SRodney W. Grimes tar_opt(void) 3344b88c807SRodney W. Grimes { 3354b88c807SRodney W. Grimes OPLIST *opt; 3364b88c807SRodney W. Grimes 3374b88c807SRodney W. Grimes while ((opt = opt_next()) != NULL) { 3384b88c807SRodney W. Grimes if (strcmp(opt->name, TAR_OPTION) || 3394b88c807SRodney W. Grimes strcmp(opt->value, TAR_NODIR)) { 340778766feSKris Kennaway paxwarn(1, "Unknown tar format -o option/value pair %s=%s", 3414b88c807SRodney W. Grimes opt->name, opt->value); 342778766feSKris Kennaway paxwarn(1,"%s=%s is the only supported tar format option", 3434b88c807SRodney W. Grimes TAR_OPTION, TAR_NODIR); 3444b88c807SRodney W. Grimes return(-1); 3454b88c807SRodney W. Grimes } 3464b88c807SRodney W. Grimes 3474b88c807SRodney W. Grimes /* 3484b88c807SRodney W. Grimes * we only support one option, and only when writing 3494b88c807SRodney W. Grimes */ 3504b88c807SRodney W. Grimes if ((act != APPND) && (act != ARCHIVE)) { 351778766feSKris Kennaway paxwarn(1, "%s=%s is only supported when writing.", 3524b88c807SRodney W. Grimes opt->name, opt->value); 3534b88c807SRodney W. Grimes return(-1); 3544b88c807SRodney W. Grimes } 3554b88c807SRodney W. Grimes tar_nodir = 1; 3564b88c807SRodney W. Grimes } 3574b88c807SRodney W. Grimes return(0); 3584b88c807SRodney W. Grimes } 3594b88c807SRodney W. Grimes 3604b88c807SRodney W. Grimes 3614b88c807SRodney W. Grimes /* 3624b88c807SRodney W. Grimes * tar_rd() 3634b88c807SRodney W. Grimes * extract the values out of block already determined to be a tar header. 3644b88c807SRodney W. Grimes * store the values in the ARCHD parameter. 3654b88c807SRodney W. Grimes * Return: 3664b88c807SRodney W. Grimes * 0 3674b88c807SRodney W. Grimes */ 3684b88c807SRodney W. Grimes 3694b88c807SRodney W. Grimes int 370f789b261SWarner Losh tar_rd(ARCHD *arcn, char *buf) 3714b88c807SRodney W. Grimes { 372f789b261SWarner Losh HD_TAR *hd; 373f789b261SWarner Losh char *pt; 3744b88c807SRodney W. Grimes 3754b88c807SRodney W. Grimes /* 3764b88c807SRodney W. Grimes * we only get proper sized buffers passed to us 3774b88c807SRodney W. Grimes */ 3784b88c807SRodney W. Grimes if (tar_id(buf, BLKMULT) < 0) 3794b88c807SRodney W. Grimes return(-1); 3804b88c807SRodney W. Grimes arcn->org_name = arcn->name; 3814b88c807SRodney W. Grimes arcn->sb.st_nlink = 1; 3824b88c807SRodney W. Grimes arcn->pat = NULL; 3834b88c807SRodney W. Grimes 3844b88c807SRodney W. Grimes /* 3854b88c807SRodney W. Grimes * copy out the name and values in the stat buffer 3864b88c807SRodney W. Grimes */ 3874b88c807SRodney W. Grimes hd = (HD_TAR *)buf; 3885512dc54SYaroslav Tykhiy /* 3895512dc54SYaroslav Tykhiy * old tar format specifies the name always be null-terminated, 3905512dc54SYaroslav Tykhiy * but let's be robust to broken archives. 3915512dc54SYaroslav Tykhiy * the same applies to handling links below. 3925512dc54SYaroslav Tykhiy */ 3935512dc54SYaroslav Tykhiy arcn->nlen = l_strncpy(arcn->name, hd->name, 3945512dc54SYaroslav Tykhiy MIN(sizeof(hd->name), sizeof(arcn->name)) - 1); 3954b88c807SRodney W. Grimes arcn->name[arcn->nlen] = '\0'; 3964b88c807SRodney W. Grimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 3974b88c807SRodney W. Grimes 0xfff); 3984b88c807SRodney W. Grimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 3994b88c807SRodney W. Grimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 400b1787decSKris Kennaway #ifdef NET2_STAT 401b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 402dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 403b1787decSKris Kennaway #else 404b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 405dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 406b1787decSKris Kennaway #endif 4074b88c807SRodney W. Grimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 4084b88c807SRodney W. Grimes 4094b88c807SRodney W. Grimes /* 4104b88c807SRodney W. Grimes * have to look at the last character, it may be a '/' and that is used 4114b88c807SRodney W. Grimes * to encode this as a directory 4124b88c807SRodney W. Grimes */ 4134b88c807SRodney W. Grimes pt = &(arcn->name[arcn->nlen - 1]); 4144b88c807SRodney W. Grimes arcn->pad = 0; 4154b88c807SRodney W. Grimes arcn->skip = 0; 4164b88c807SRodney W. Grimes switch(hd->linkflag) { 4174b88c807SRodney W. Grimes case SYMTYPE: 4184b88c807SRodney W. Grimes /* 4194b88c807SRodney W. Grimes * symbolic link, need to get the link name and set the type in 4204b88c807SRodney W. Grimes * the st_mode so -v printing will look correct. 4214b88c807SRodney W. Grimes */ 4224b88c807SRodney W. Grimes arcn->type = PAX_SLK; 4234b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4245512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4254b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4264b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFLNK; 4274b88c807SRodney W. Grimes break; 4284b88c807SRodney W. Grimes case LNKTYPE: 4294b88c807SRodney W. Grimes /* 4304b88c807SRodney W. Grimes * hard link, need to get the link name, set the type in the 4314b88c807SRodney W. Grimes * st_mode and st_nlink so -v printing will look better. 4324b88c807SRodney W. Grimes */ 4334b88c807SRodney W. Grimes arcn->type = PAX_HLK; 4344b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 4354b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4365512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4374b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4384b88c807SRodney W. Grimes 4394b88c807SRodney W. Grimes /* 4404b88c807SRodney W. Grimes * no idea of what type this thing really points at, but 4414b88c807SRodney W. Grimes * we set something for printing only. 4424b88c807SRodney W. Grimes */ 4434b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 4444b88c807SRodney W. Grimes break; 445b1787decSKris Kennaway case DIRTYPE: 446b1787decSKris Kennaway /* 447b1787decSKris Kennaway * It is a directory, set the mode for -v printing 448b1787decSKris Kennaway */ 449b1787decSKris Kennaway arcn->type = PAX_DIR; 450b1787decSKris Kennaway arcn->sb.st_mode |= S_IFDIR; 451b1787decSKris Kennaway arcn->sb.st_nlink = 2; 452b1787decSKris Kennaway arcn->ln_name[0] = '\0'; 453b1787decSKris Kennaway arcn->ln_nlen = 0; 454b1787decSKris Kennaway break; 4554b88c807SRodney W. Grimes case AREGTYPE: 4564b88c807SRodney W. Grimes case REGTYPE: 4574b88c807SRodney W. Grimes default: 4584b88c807SRodney W. Grimes /* 4594b88c807SRodney W. Grimes * If we have a trailing / this is a directory and NOT a file. 4604b88c807SRodney W. Grimes */ 4614b88c807SRodney W. Grimes arcn->ln_name[0] = '\0'; 4624b88c807SRodney W. Grimes arcn->ln_nlen = 0; 4634b88c807SRodney W. Grimes if (*pt == '/') { 4644b88c807SRodney W. Grimes /* 4654b88c807SRodney W. Grimes * it is a directory, set the mode for -v printing 4664b88c807SRodney W. Grimes */ 4674b88c807SRodney W. Grimes arcn->type = PAX_DIR; 4684b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFDIR; 4694b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 4704b88c807SRodney W. Grimes } else { 4714b88c807SRodney W. Grimes /* 4724b88c807SRodney W. Grimes * have a file that will be followed by data. Set the 47346be34b9SKris Kennaway * skip value to the size field and calculate the size 4744b88c807SRodney W. Grimes * of the padding. 4754b88c807SRodney W. Grimes */ 4764b88c807SRodney W. Grimes arcn->type = PAX_REG; 4774b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 4784b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 4794b88c807SRodney W. Grimes arcn->skip = arcn->sb.st_size; 4804b88c807SRodney W. Grimes } 4814b88c807SRodney W. Grimes break; 4824b88c807SRodney W. Grimes } 4834b88c807SRodney W. Grimes 4844b88c807SRodney W. Grimes /* 4854b88c807SRodney W. Grimes * strip off any trailing slash. 4864b88c807SRodney W. Grimes */ 4874b88c807SRodney W. Grimes if (*pt == '/') { 4884b88c807SRodney W. Grimes *pt = '\0'; 4894b88c807SRodney W. Grimes --arcn->nlen; 4904b88c807SRodney W. Grimes } 4914b88c807SRodney W. Grimes return(0); 4924b88c807SRodney W. Grimes } 4934b88c807SRodney W. Grimes 4944b88c807SRodney W. Grimes /* 4954b88c807SRodney W. Grimes * tar_wr() 4964b88c807SRodney W. Grimes * write a tar header for the file specified in the ARCHD to the archive. 4974b88c807SRodney W. Grimes * Have to check for file types that cannot be stored and file names that 4984b88c807SRodney W. Grimes * are too long. Be careful of the term (last arg) to ul_oct, each field 4994b88c807SRodney W. Grimes * of tar has it own spec for the termination character(s). 5004b88c807SRodney W. Grimes * ASSUMED: space after header in header block is zero filled 5014b88c807SRodney W. Grimes * Return: 5024b88c807SRodney W. Grimes * 0 if file has data to be written after the header, 1 if file has NO 5034b88c807SRodney W. Grimes * data to write after the header, -1 if archive write failed 5044b88c807SRodney W. Grimes */ 5054b88c807SRodney W. Grimes 5064b88c807SRodney W. Grimes int 507f789b261SWarner Losh tar_wr(ARCHD *arcn) 5084b88c807SRodney W. Grimes { 509f789b261SWarner Losh HD_TAR *hd; 5104b88c807SRodney W. Grimes int len; 511c65bb135SRuslan Ermilov HD_TAR hdblk; 5124b88c807SRodney W. Grimes 5134b88c807SRodney W. Grimes /* 5144b88c807SRodney W. Grimes * check for those file system types which tar cannot store 5154b88c807SRodney W. Grimes */ 5164b88c807SRodney W. Grimes switch(arcn->type) { 5174b88c807SRodney W. Grimes case PAX_DIR: 5184b88c807SRodney W. Grimes /* 5194b88c807SRodney W. Grimes * user asked that dirs not be written to the archive 5204b88c807SRodney W. Grimes */ 5214b88c807SRodney W. Grimes if (tar_nodir) 5224b88c807SRodney W. Grimes return(1); 5234b88c807SRodney W. Grimes break; 5244b88c807SRodney W. Grimes case PAX_CHR: 525778766feSKris Kennaway paxwarn(1, "Tar cannot archive a character device %s", 5264b88c807SRodney W. Grimes arcn->org_name); 5274b88c807SRodney W. Grimes return(1); 5284b88c807SRodney W. Grimes case PAX_BLK: 529778766feSKris Kennaway paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); 5304b88c807SRodney W. Grimes return(1); 5314b88c807SRodney W. Grimes case PAX_SCK: 532778766feSKris Kennaway paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); 5334b88c807SRodney W. Grimes return(1); 5344b88c807SRodney W. Grimes case PAX_FIF: 535778766feSKris Kennaway paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); 5364b88c807SRodney W. Grimes return(1); 5374b88c807SRodney W. Grimes case PAX_SLK: 5384b88c807SRodney W. Grimes case PAX_HLK: 5394b88c807SRodney W. Grimes case PAX_HRG: 5405512dc54SYaroslav Tykhiy if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) { 541778766feSKris Kennaway paxwarn(1,"Link name too long for tar %s", arcn->ln_name); 5424b88c807SRodney W. Grimes return(1); 5434b88c807SRodney W. Grimes } 5444b88c807SRodney W. Grimes break; 5454b88c807SRodney W. Grimes case PAX_REG: 5464b88c807SRodney W. Grimes case PAX_CTG: 5474b88c807SRodney W. Grimes default: 5484b88c807SRodney W. Grimes break; 5494b88c807SRodney W. Grimes } 5504b88c807SRodney W. Grimes 5514b88c807SRodney W. Grimes /* 5524b88c807SRodney W. Grimes * check file name len, remember extra char for dirs (the / at the end) 5534b88c807SRodney W. Grimes */ 5544b88c807SRodney W. Grimes len = arcn->nlen; 5554b88c807SRodney W. Grimes if (arcn->type == PAX_DIR) 5564b88c807SRodney W. Grimes ++len; 557cee22cbdSDavid E. O'Brien if (len >= (int)sizeof(hd->name)) { 558778766feSKris Kennaway paxwarn(1, "File name too long for tar %s", arcn->name); 5594b88c807SRodney W. Grimes return(1); 5604b88c807SRodney W. Grimes } 5614b88c807SRodney W. Grimes 5624b88c807SRodney W. Grimes /* 5634b88c807SRodney W. Grimes * copy the data out of the ARCHD into the tar header based on the type 5644b88c807SRodney W. Grimes * of the file. Remember many tar readers want the unused fields to be 5654b88c807SRodney W. Grimes * padded with zero. We set the linkflag field (type), the linkname 5664b88c807SRodney W. Grimes * (or zero if not used),the size, and set the padding (if any) to be 5674b88c807SRodney W. Grimes * added after the file data (0 for all other types, as they only have 5684b88c807SRodney W. Grimes * a header) 5694b88c807SRodney W. Grimes */ 570c65bb135SRuslan Ermilov hd = &hdblk; 571b1787decSKris Kennaway l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); 572b1787decSKris Kennaway hd->name[sizeof(hd->name) - 1] = '\0'; 5734b88c807SRodney W. Grimes arcn->pad = 0; 5744b88c807SRodney W. Grimes 5754b88c807SRodney W. Grimes if (arcn->type == PAX_DIR) { 5764b88c807SRodney W. Grimes /* 5774b88c807SRodney W. Grimes * directories are the same as files, except have a filename 5784b88c807SRodney W. Grimes * that ends with a /, we add the slash here. No data follows, 5794b88c807SRodney W. Grimes * dirs, so no pad. 5804b88c807SRodney W. Grimes */ 5814b88c807SRodney W. Grimes hd->linkflag = AREGTYPE; 582778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 5834b88c807SRodney W. Grimes hd->name[len-1] = '/'; 5844b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5854b88c807SRodney W. Grimes goto out; 5864b88c807SRodney W. Grimes } else if (arcn->type == PAX_SLK) { 5874b88c807SRodney W. Grimes /* 5884b88c807SRodney W. Grimes * no data follows this file, so no pad 5894b88c807SRodney W. Grimes */ 5904b88c807SRodney W. Grimes hd->linkflag = SYMTYPE; 591b1787decSKris Kennaway l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 592b1787decSKris Kennaway hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 5934b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5944b88c807SRodney W. Grimes goto out; 5954b88c807SRodney W. Grimes } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 5964b88c807SRodney W. Grimes /* 5974b88c807SRodney W. Grimes * no data follows this file, so no pad 5984b88c807SRodney W. Grimes */ 5994b88c807SRodney W. Grimes hd->linkflag = LNKTYPE; 600b1787decSKris Kennaway l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 601b1787decSKris Kennaway hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 6024b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 6034b88c807SRodney W. Grimes goto out; 6044b88c807SRodney W. Grimes } else { 6054b88c807SRodney W. Grimes /* 6064b88c807SRodney W. Grimes * data follows this file, so set the pad 6074b88c807SRodney W. Grimes */ 6084b88c807SRodney W. Grimes hd->linkflag = AREGTYPE; 609778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 6104b88c807SRodney W. Grimes # ifdef NET2_STAT 6114b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 6124b88c807SRodney W. Grimes sizeof(hd->size), 1)) { 6134b88c807SRodney W. Grimes # else 6144b88c807SRodney W. Grimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 6154b88c807SRodney W. Grimes sizeof(hd->size), 1)) { 6164b88c807SRodney W. Grimes # endif 617778766feSKris Kennaway paxwarn(1,"File is too large for tar %s", arcn->org_name); 6184b88c807SRodney W. Grimes return(1); 6194b88c807SRodney W. Grimes } 6204b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 6214b88c807SRodney W. Grimes } 6224b88c807SRodney W. Grimes 6234b88c807SRodney W. Grimes /* 6244b88c807SRodney W. Grimes * copy those fields that are independent of the type 6254b88c807SRodney W. Grimes */ 6264b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || 6274b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || 6284b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || 6294b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) 6304b88c807SRodney W. Grimes goto out; 6314b88c807SRodney W. Grimes 6324b88c807SRodney W. Grimes /* 6334b88c807SRodney W. Grimes * calculate and add the checksum, then write the header. A return of 6344b88c807SRodney W. Grimes * 0 tells the caller to now write the file data, 1 says no data needs 6354b88c807SRodney W. Grimes * to be written 6364b88c807SRodney W. Grimes */ 637c65bb135SRuslan Ermilov if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum, 638b1787decSKris Kennaway sizeof(hd->chksum), 3)) 6394b88c807SRodney W. Grimes goto out; 640c65bb135SRuslan Ermilov if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0) 6414b88c807SRodney W. Grimes return(-1); 6424b88c807SRodney W. Grimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) 6434b88c807SRodney W. Grimes return(-1); 6444b88c807SRodney W. Grimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 6454b88c807SRodney W. Grimes return(0); 6464b88c807SRodney W. Grimes return(1); 6474b88c807SRodney W. Grimes 6484b88c807SRodney W. Grimes out: 6494b88c807SRodney W. Grimes /* 6504b88c807SRodney W. Grimes * header field is out of range 6514b88c807SRodney W. Grimes */ 652778766feSKris Kennaway paxwarn(1, "Tar header field is too small for %s", arcn->org_name); 6534b88c807SRodney W. Grimes return(1); 6544b88c807SRodney W. Grimes } 6554b88c807SRodney W. Grimes 6564b88c807SRodney W. Grimes /* 6574b88c807SRodney W. Grimes * Routines for POSIX ustar 6584b88c807SRodney W. Grimes */ 6594b88c807SRodney W. Grimes 6604b88c807SRodney W. Grimes /* 6614b88c807SRodney W. Grimes * ustar_strd() 6624b88c807SRodney W. Grimes * initialization for ustar read 6634b88c807SRodney W. Grimes * Return: 6644b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 6654b88c807SRodney W. Grimes */ 6664b88c807SRodney W. Grimes 6674b88c807SRodney W. Grimes int 6684b88c807SRodney W. Grimes ustar_strd(void) 6694b88c807SRodney W. Grimes { 6704b88c807SRodney W. Grimes if ((usrtb_start() < 0) || (grptb_start() < 0)) 6714b88c807SRodney W. Grimes return(-1); 6724b88c807SRodney W. Grimes return(0); 6734b88c807SRodney W. Grimes } 6744b88c807SRodney W. Grimes 6754b88c807SRodney W. Grimes /* 6764b88c807SRodney W. Grimes * ustar_stwr() 6774b88c807SRodney W. Grimes * initialization for ustar write 6784b88c807SRodney W. Grimes * Return: 6794b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 6804b88c807SRodney W. Grimes */ 6814b88c807SRodney W. Grimes 6824b88c807SRodney W. Grimes int 6834b88c807SRodney W. Grimes ustar_stwr(void) 6844b88c807SRodney W. Grimes { 6854b88c807SRodney W. Grimes if ((uidtb_start() < 0) || (gidtb_start() < 0)) 6864b88c807SRodney W. Grimes return(-1); 6874b88c807SRodney W. Grimes return(0); 6884b88c807SRodney W. Grimes } 6894b88c807SRodney W. Grimes 6904b88c807SRodney W. Grimes /* 6914b88c807SRodney W. Grimes * ustar_id() 6924b88c807SRodney W. Grimes * determine if a block given to us is a valid ustar header. We have to 6934b88c807SRodney W. Grimes * be on the lookout for those pesky blocks of all zero's 6944b88c807SRodney W. Grimes * Return: 6954b88c807SRodney W. Grimes * 0 if a ustar header, -1 otherwise 6964b88c807SRodney W. Grimes */ 6974b88c807SRodney W. Grimes 6984b88c807SRodney W. Grimes int 6994b88c807SRodney W. Grimes ustar_id(char *blk, int size) 7004b88c807SRodney W. Grimes { 701f789b261SWarner Losh HD_USTAR *hd; 7024b88c807SRodney W. Grimes 7034b88c807SRodney W. Grimes if (size < BLKMULT) 7044b88c807SRodney W. Grimes return(-1); 7054b88c807SRodney W. Grimes hd = (HD_USTAR *)blk; 7064b88c807SRodney W. Grimes 7074b88c807SRodney W. Grimes /* 7084b88c807SRodney W. Grimes * check for block of zero's first, a simple and fast test then check 7094b88c807SRodney W. Grimes * ustar magic cookie. We should use TMAGLEN, but some USTAR archive 7104b88c807SRodney W. Grimes * programs are fouled up and create archives missing the \0. Last we 7114b88c807SRodney W. Grimes * check the checksum. If ok we have to assume it is a valid header. 7124b88c807SRodney W. Grimes */ 7134b88c807SRodney W. Grimes if (hd->name[0] == '\0') 7144b88c807SRodney W. Grimes return(-1); 7154b88c807SRodney W. Grimes if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) 7164b88c807SRodney W. Grimes return(-1); 7174b88c807SRodney W. Grimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 7184b88c807SRodney W. Grimes return(-1); 7194b88c807SRodney W. Grimes return(0); 7204b88c807SRodney W. Grimes } 7214b88c807SRodney W. Grimes 7224b88c807SRodney W. Grimes /* 7234b88c807SRodney W. Grimes * ustar_rd() 7244b88c807SRodney W. Grimes * extract the values out of block already determined to be a ustar header. 7254b88c807SRodney W. Grimes * store the values in the ARCHD parameter. 7264b88c807SRodney W. Grimes * Return: 7274b88c807SRodney W. Grimes * 0 7284b88c807SRodney W. Grimes */ 7294b88c807SRodney W. Grimes 7304b88c807SRodney W. Grimes int 731f789b261SWarner Losh ustar_rd(ARCHD *arcn, char *buf) 7324b88c807SRodney W. Grimes { 733f789b261SWarner Losh HD_USTAR *hd; 734f789b261SWarner Losh char *dest; 735f789b261SWarner Losh int cnt = 0; 7364b88c807SRodney W. Grimes dev_t devmajor; 7374b88c807SRodney W. Grimes dev_t devminor; 7384b88c807SRodney W. Grimes 7394b88c807SRodney W. Grimes /* 7404b88c807SRodney W. Grimes * we only get proper sized buffers 7414b88c807SRodney W. Grimes */ 7424b88c807SRodney W. Grimes if (ustar_id(buf, BLKMULT) < 0) 7434b88c807SRodney W. Grimes return(-1); 7444b88c807SRodney W. Grimes arcn->org_name = arcn->name; 7454b88c807SRodney W. Grimes arcn->sb.st_nlink = 1; 7464b88c807SRodney W. Grimes arcn->pat = NULL; 747b1787decSKris Kennaway arcn->nlen = 0; 7484b88c807SRodney W. Grimes hd = (HD_USTAR *)buf; 7494b88c807SRodney W. Grimes 7504b88c807SRodney W. Grimes /* 7514b88c807SRodney W. Grimes * see if the filename is split into two parts. if, so joint the parts. 7524b88c807SRodney W. Grimes * we copy the prefix first and add a / between the prefix and name. 7534b88c807SRodney W. Grimes */ 7544b88c807SRodney W. Grimes dest = arcn->name; 7554b88c807SRodney W. Grimes if (*(hd->prefix) != '\0') { 7565512dc54SYaroslav Tykhiy cnt = l_strncpy(dest, hd->prefix, 7575512dc54SYaroslav Tykhiy MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2)); 758b1787decSKris Kennaway dest += cnt; 7594b88c807SRodney W. Grimes *dest++ = '/'; 760b1787decSKris Kennaway cnt++; 7614b88c807SRodney W. Grimes } 7625512dc54SYaroslav Tykhiy /* 7635512dc54SYaroslav Tykhiy * ustar format specifies the name may be unterminated 7645512dc54SYaroslav Tykhiy * if it fills the entire field. this also applies to 7655512dc54SYaroslav Tykhiy * the prefix and the linkname. 7665512dc54SYaroslav Tykhiy */ 7675512dc54SYaroslav Tykhiy arcn->nlen = cnt + l_strncpy(dest, hd->name, 7685512dc54SYaroslav Tykhiy MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1)); 7694b88c807SRodney W. Grimes arcn->name[arcn->nlen] = '\0'; 7704b88c807SRodney W. Grimes 7714b88c807SRodney W. Grimes /* 7724b88c807SRodney W. Grimes * follow the spec to the letter. we should only have mode bits, strip 7734b88c807SRodney W. Grimes * off all other crud we may be passed. 7744b88c807SRodney W. Grimes */ 7754b88c807SRodney W. Grimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 7764b88c807SRodney W. Grimes 0xfff); 777b1787decSKris Kennaway #ifdef NET2_STAT 778b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); 779dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); 780b1787decSKris Kennaway #else 781b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 782dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 783b1787decSKris Kennaway #endif 7844b88c807SRodney W. Grimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 7854b88c807SRodney W. Grimes 7864b88c807SRodney W. Grimes /* 7874b88c807SRodney W. Grimes * If we can find the ascii names for gname and uname in the password 7884b88c807SRodney W. Grimes * and group files we will use the uid's and gid they bind. Otherwise 7894b88c807SRodney W. Grimes * we use the uid and gid values stored in the header. (This is what 79046be34b9SKris Kennaway * the POSIX spec wants). 7914b88c807SRodney W. Grimes */ 7924b88c807SRodney W. Grimes hd->gname[sizeof(hd->gname) - 1] = '\0'; 7934b88c807SRodney W. Grimes if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) 7944b88c807SRodney W. Grimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 7954b88c807SRodney W. Grimes hd->uname[sizeof(hd->uname) - 1] = '\0'; 7964b88c807SRodney W. Grimes if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) 7974b88c807SRodney W. Grimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 7984b88c807SRodney W. Grimes 7994b88c807SRodney W. Grimes /* 8004b88c807SRodney W. Grimes * set the defaults, these may be changed depending on the file type 8014b88c807SRodney W. Grimes */ 8024b88c807SRodney W. Grimes arcn->ln_name[0] = '\0'; 8034b88c807SRodney W. Grimes arcn->ln_nlen = 0; 8044b88c807SRodney W. Grimes arcn->pad = 0; 8054b88c807SRodney W. Grimes arcn->skip = 0; 8064b88c807SRodney W. Grimes arcn->sb.st_rdev = (dev_t)0; 8074b88c807SRodney W. Grimes 8084b88c807SRodney W. Grimes /* 8094b88c807SRodney W. Grimes * set the mode and PAX type according to the typeflag in the header 8104b88c807SRodney W. Grimes */ 8114b88c807SRodney W. Grimes switch(hd->typeflag) { 8124b88c807SRodney W. Grimes case FIFOTYPE: 8134b88c807SRodney W. Grimes arcn->type = PAX_FIF; 8144b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFIFO; 8154b88c807SRodney W. Grimes break; 8164b88c807SRodney W. Grimes case DIRTYPE: 8174b88c807SRodney W. Grimes arcn->type = PAX_DIR; 8184b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFDIR; 8194b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 8204b88c807SRodney W. Grimes 8214b88c807SRodney W. Grimes /* 8224b88c807SRodney W. Grimes * Some programs that create ustar archives append a '/' 8234b88c807SRodney W. Grimes * to the pathname for directories. This clearly violates 8244b88c807SRodney W. Grimes * ustar specs, but we will silently strip it off anyway. 8254b88c807SRodney W. Grimes */ 8264b88c807SRodney W. Grimes if (arcn->name[arcn->nlen - 1] == '/') 8274b88c807SRodney W. Grimes arcn->name[--arcn->nlen] = '\0'; 8284b88c807SRodney W. Grimes break; 8294b88c807SRodney W. Grimes case BLKTYPE: 8304b88c807SRodney W. Grimes case CHRTYPE: 8314b88c807SRodney W. Grimes /* 8324b88c807SRodney W. Grimes * this type requires the rdev field to be set. 8334b88c807SRodney W. Grimes */ 8344b88c807SRodney W. Grimes if (hd->typeflag == BLKTYPE) { 8354b88c807SRodney W. Grimes arcn->type = PAX_BLK; 8364b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFBLK; 8374b88c807SRodney W. Grimes } else { 8384b88c807SRodney W. Grimes arcn->type = PAX_CHR; 8394b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFCHR; 8404b88c807SRodney W. Grimes } 8414b88c807SRodney W. Grimes devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); 8424b88c807SRodney W. Grimes devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); 8434b88c807SRodney W. Grimes arcn->sb.st_rdev = TODEV(devmajor, devminor); 8444b88c807SRodney W. Grimes break; 8454b88c807SRodney W. Grimes case SYMTYPE: 8464b88c807SRodney W. Grimes case LNKTYPE: 8474b88c807SRodney W. Grimes if (hd->typeflag == SYMTYPE) { 8484b88c807SRodney W. Grimes arcn->type = PAX_SLK; 8494b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFLNK; 8504b88c807SRodney W. Grimes } else { 8514b88c807SRodney W. Grimes arcn->type = PAX_HLK; 8524b88c807SRodney W. Grimes /* 8534b88c807SRodney W. Grimes * so printing looks better 8544b88c807SRodney W. Grimes */ 8554b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 8564b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 8574b88c807SRodney W. Grimes } 8584b88c807SRodney W. Grimes /* 8594b88c807SRodney W. Grimes * copy the link name 8604b88c807SRodney W. Grimes */ 8614b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 8625512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1)); 8634b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 8644b88c807SRodney W. Grimes break; 8654b88c807SRodney W. Grimes case CONTTYPE: 8664b88c807SRodney W. Grimes case AREGTYPE: 8674b88c807SRodney W. Grimes case REGTYPE: 8684b88c807SRodney W. Grimes default: 8694b88c807SRodney W. Grimes /* 8704b88c807SRodney W. Grimes * these types have file data that follows. Set the skip and 8714b88c807SRodney W. Grimes * pad fields. 8724b88c807SRodney W. Grimes */ 8734b88c807SRodney W. Grimes arcn->type = PAX_REG; 8744b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 8754b88c807SRodney W. Grimes arcn->skip = arcn->sb.st_size; 8764b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 8774b88c807SRodney W. Grimes break; 8784b88c807SRodney W. Grimes } 8794b88c807SRodney W. Grimes return(0); 8804b88c807SRodney W. Grimes } 8814b88c807SRodney W. Grimes 8824b88c807SRodney W. Grimes /* 8834b88c807SRodney W. Grimes * ustar_wr() 8844b88c807SRodney W. Grimes * write a ustar header for the file specified in the ARCHD to the archive 8854b88c807SRodney W. Grimes * Have to check for file types that cannot be stored and file names that 8864b88c807SRodney W. Grimes * are too long. Be careful of the term (last arg) to ul_oct, we only use 8874b88c807SRodney W. Grimes * '\0' for the termination character (this is different than picky tar) 8884b88c807SRodney W. Grimes * ASSUMED: space after header in header block is zero filled 8894b88c807SRodney W. Grimes * Return: 8904b88c807SRodney W. Grimes * 0 if file has data to be written after the header, 1 if file has NO 8914b88c807SRodney W. Grimes * data to write after the header, -1 if archive write failed 8924b88c807SRodney W. Grimes */ 8934b88c807SRodney W. Grimes 8944b88c807SRodney W. Grimes int 895f789b261SWarner Losh ustar_wr(ARCHD *arcn) 8964b88c807SRodney W. Grimes { 897f789b261SWarner Losh HD_USTAR *hd; 898f789b261SWarner Losh char *pt; 899c65bb135SRuslan Ermilov HD_USTAR hdblk; 9004b88c807SRodney W. Grimes 9014b88c807SRodney W. Grimes /* 9024b88c807SRodney W. Grimes * check for those file system types ustar cannot store 9034b88c807SRodney W. Grimes */ 9044b88c807SRodney W. Grimes if (arcn->type == PAX_SCK) { 905778766feSKris Kennaway paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); 9064b88c807SRodney W. Grimes return(1); 9074b88c807SRodney W. Grimes } 9084b88c807SRodney W. Grimes 9094b88c807SRodney W. Grimes /* 9104b88c807SRodney W. Grimes * check the length of the linkname 9114b88c807SRodney W. Grimes */ 9124b88c807SRodney W. Grimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 913cee22cbdSDavid E. O'Brien (arcn->type == PAX_HRG)) && 9145512dc54SYaroslav Tykhiy (arcn->ln_nlen > (int)sizeof(hd->linkname))) { 915778766feSKris Kennaway paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); 9164b88c807SRodney W. Grimes return(1); 9174b88c807SRodney W. Grimes } 9184b88c807SRodney W. Grimes 9194b88c807SRodney W. Grimes /* 9204b88c807SRodney W. Grimes * split the path name into prefix and name fields (if needed). if 9214b88c807SRodney W. Grimes * pt != arcn->name, the name has to be split 9224b88c807SRodney W. Grimes */ 9234b88c807SRodney W. Grimes if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { 924778766feSKris Kennaway paxwarn(1, "File name too long for ustar %s", arcn->name); 9254b88c807SRodney W. Grimes return(1); 9264b88c807SRodney W. Grimes } 927c65bb135SRuslan Ermilov hd = &hdblk; 9284b88c807SRodney W. Grimes arcn->pad = 0L; 9294b88c807SRodney W. Grimes 9304b88c807SRodney W. Grimes /* 9314b88c807SRodney W. Grimes * split the name, or zero out the prefix 9324b88c807SRodney W. Grimes */ 9334b88c807SRodney W. Grimes if (pt != arcn->name) { 9344b88c807SRodney W. Grimes /* 9354b88c807SRodney W. Grimes * name was split, pt points at the / where the split is to 9364b88c807SRodney W. Grimes * occur, we remove the / and copy the first part to the prefix 9374b88c807SRodney W. Grimes */ 9384b88c807SRodney W. Grimes *pt = '\0'; 9395512dc54SYaroslav Tykhiy l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); 9404b88c807SRodney W. Grimes *pt++ = '/'; 9414b88c807SRodney W. Grimes } else 942778766feSKris Kennaway memset(hd->prefix, 0, sizeof(hd->prefix)); 9434b88c807SRodney W. Grimes 9444b88c807SRodney W. Grimes /* 9454b88c807SRodney W. Grimes * copy the name part. this may be the whole path or the part after 9465512dc54SYaroslav Tykhiy * the prefix. both the name and prefix may fill the entire field. 9474b88c807SRodney W. Grimes */ 9485512dc54SYaroslav Tykhiy l_strncpy(hd->name, pt, sizeof(hd->name)); 9494b88c807SRodney W. Grimes 9504b88c807SRodney W. Grimes /* 9514b88c807SRodney W. Grimes * set the fields in the header that are type dependent 9524b88c807SRodney W. Grimes */ 9534b88c807SRodney W. Grimes switch(arcn->type) { 9544b88c807SRodney W. Grimes case PAX_DIR: 9554b88c807SRodney W. Grimes hd->typeflag = DIRTYPE; 956778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 957778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 958778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9594b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9604b88c807SRodney W. Grimes goto out; 9614b88c807SRodney W. Grimes break; 9624b88c807SRodney W. Grimes case PAX_CHR: 9634b88c807SRodney W. Grimes case PAX_BLK: 9644b88c807SRodney W. Grimes if (arcn->type == PAX_CHR) 9654b88c807SRodney W. Grimes hd->typeflag = CHRTYPE; 9664b88c807SRodney W. Grimes else 9674b88c807SRodney W. Grimes hd->typeflag = BLKTYPE; 968778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 9694b88c807SRodney W. Grimes if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, 9704b88c807SRodney W. Grimes sizeof(hd->devmajor), 3) || 9714b88c807SRodney W. Grimes ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, 9724b88c807SRodney W. Grimes sizeof(hd->devminor), 3) || 9734b88c807SRodney W. Grimes ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9744b88c807SRodney W. Grimes goto out; 9754b88c807SRodney W. Grimes break; 9764b88c807SRodney W. Grimes case PAX_FIF: 9774b88c807SRodney W. Grimes hd->typeflag = FIFOTYPE; 978778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 979778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 980778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9814b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9824b88c807SRodney W. Grimes goto out; 9834b88c807SRodney W. Grimes break; 9844b88c807SRodney W. Grimes case PAX_SLK: 9854b88c807SRodney W. Grimes case PAX_HLK: 9864b88c807SRodney W. Grimes case PAX_HRG: 9874b88c807SRodney W. Grimes if (arcn->type == PAX_SLK) 9884b88c807SRodney W. Grimes hd->typeflag = SYMTYPE; 9894b88c807SRodney W. Grimes else 9904b88c807SRodney W. Grimes hd->typeflag = LNKTYPE; 9915512dc54SYaroslav Tykhiy /* the link name may occupy the entire field in ustar */ 9925512dc54SYaroslav Tykhiy l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 993778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 994778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9954b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9964b88c807SRodney W. Grimes goto out; 9974b88c807SRodney W. Grimes break; 9984b88c807SRodney W. Grimes case PAX_REG: 9994b88c807SRodney W. Grimes case PAX_CTG: 10004b88c807SRodney W. Grimes default: 10014b88c807SRodney W. Grimes /* 10024b88c807SRodney W. Grimes * file data with this type, set the padding 10034b88c807SRodney W. Grimes */ 10044b88c807SRodney W. Grimes if (arcn->type == PAX_CTG) 10054b88c807SRodney W. Grimes hd->typeflag = CONTTYPE; 10064b88c807SRodney W. Grimes else 10074b88c807SRodney W. Grimes hd->typeflag = REGTYPE; 1008778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 1009778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 1010778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 10114b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 10124b88c807SRodney W. Grimes # ifdef NET2_STAT 10134b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_size, hd->size, 10144b88c807SRodney W. Grimes sizeof(hd->size), 3)) { 10154b88c807SRodney W. Grimes # else 10164b88c807SRodney W. Grimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 10174b88c807SRodney W. Grimes sizeof(hd->size), 3)) { 10184b88c807SRodney W. Grimes # endif 1019778766feSKris Kennaway paxwarn(1,"File is too long for ustar %s",arcn->org_name); 10204b88c807SRodney W. Grimes return(1); 10214b88c807SRodney W. Grimes } 10224b88c807SRodney W. Grimes break; 10234b88c807SRodney W. Grimes } 10244b88c807SRodney W. Grimes 1025b1787decSKris Kennaway l_strncpy(hd->magic, TMAGIC, TMAGLEN); 1026b1787decSKris Kennaway l_strncpy(hd->version, TVERSION, TVERSLEN); 10274b88c807SRodney W. Grimes 10284b88c807SRodney W. Grimes /* 10294b88c807SRodney W. Grimes * set the remaining fields. Some versions want all 16 bits of mode 10304b88c807SRodney W. Grimes * we better humor them (they really do not meet spec though).... 10314b88c807SRodney W. Grimes */ 10324b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || 10334b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || 10344b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || 10354b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) 10364b88c807SRodney W. Grimes goto out; 1037b1787decSKris Kennaway l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); 1038b1787decSKris Kennaway l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); 10394b88c807SRodney W. Grimes 10404b88c807SRodney W. Grimes /* 10414b88c807SRodney W. Grimes * calculate and store the checksum write the header to the archive 10424b88c807SRodney W. Grimes * return 0 tells the caller to now write the file data, 1 says no data 10434b88c807SRodney W. Grimes * needs to be written 10444b88c807SRodney W. Grimes */ 1045c65bb135SRuslan Ermilov if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum, 10464b88c807SRodney W. Grimes sizeof(hd->chksum), 3)) 10474b88c807SRodney W. Grimes goto out; 1048c65bb135SRuslan Ermilov if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0) 10494b88c807SRodney W. Grimes return(-1); 10504b88c807SRodney W. Grimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) 10514b88c807SRodney W. Grimes return(-1); 10524b88c807SRodney W. Grimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 10534b88c807SRodney W. Grimes return(0); 10544b88c807SRodney W. Grimes return(1); 10554b88c807SRodney W. Grimes 10564b88c807SRodney W. Grimes out: 10574b88c807SRodney W. Grimes /* 10584b88c807SRodney W. Grimes * header field is out of range 10594b88c807SRodney W. Grimes */ 1060778766feSKris Kennaway paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); 10614b88c807SRodney W. Grimes return(1); 10624b88c807SRodney W. Grimes } 10634b88c807SRodney W. Grimes 10644b88c807SRodney W. Grimes /* 10654b88c807SRodney W. Grimes * name_split() 10664b88c807SRodney W. Grimes * see if the name has to be split for storage in a ustar header. We try 10674b88c807SRodney W. Grimes * to fit the entire name in the name field without splitting if we can. 10684b88c807SRodney W. Grimes * The split point is always at a / 10694b88c807SRodney W. Grimes * Return 10704b88c807SRodney W. Grimes * character pointer to split point (always the / that is to be removed 10714b88c807SRodney W. Grimes * if the split is not needed, the points is set to the start of the file 10724b88c807SRodney W. Grimes * name (it would violate the spec to split there). A NULL is returned if 10734b88c807SRodney W. Grimes * the file name is too long 10744b88c807SRodney W. Grimes */ 10754b88c807SRodney W. Grimes 10764b88c807SRodney W. Grimes static char * 1077f789b261SWarner Losh name_split(char *name, int len) 10784b88c807SRodney W. Grimes { 1079f789b261SWarner Losh char *start; 10804b88c807SRodney W. Grimes 10814b88c807SRodney W. Grimes /* 10824b88c807SRodney W. Grimes * check to see if the file name is small enough to fit in the name 10834b88c807SRodney W. Grimes * field. if so just return a pointer to the name. 10844b88c807SRodney W. Grimes */ 10855512dc54SYaroslav Tykhiy if (len <= TNMSZ) 10864b88c807SRodney W. Grimes return(name); 1087cd14b457SBrian Somers if (len > TPFSZ + TNMSZ) 10884b88c807SRodney W. Grimes return(NULL); 10894b88c807SRodney W. Grimes 10904b88c807SRodney W. Grimes /* 10914b88c807SRodney W. Grimes * we start looking at the biggest sized piece that fits in the name 109246be34b9SKris Kennaway * field. We walk forward looking for a slash to split at. The idea is 10934b88c807SRodney W. Grimes * to find the biggest piece to fit in the name field (or the smallest 10944757e526SMike Smith * prefix we can find) 10954b88c807SRodney W. Grimes */ 1096f77b6c6aSBrian Somers start = name + len - TNMSZ; 10974b88c807SRodney W. Grimes while ((*start != '\0') && (*start != '/')) 10984b88c807SRodney W. Grimes ++start; 10994b88c807SRodney W. Grimes 11004b88c807SRodney W. Grimes /* 11014b88c807SRodney W. Grimes * if we hit the end of the string, this name cannot be split, so we 11024b88c807SRodney W. Grimes * cannot store this file. 11034b88c807SRodney W. Grimes */ 11044b88c807SRodney W. Grimes if (*start == '\0') 11054b88c807SRodney W. Grimes return(NULL); 11064b88c807SRodney W. Grimes len = start - name; 11074b88c807SRodney W. Grimes 11084b88c807SRodney W. Grimes /* 11094b88c807SRodney W. Grimes * NOTE: /str where the length of str == TNMSZ can not be stored under 11104b88c807SRodney W. Grimes * the p1003.1-1990 spec for ustar. We could force a prefix of / and 11114b88c807SRodney W. Grimes * the file would then expand on extract to //str. The len == 0 below 11124b88c807SRodney W. Grimes * makes this special case follow the spec to the letter. 11134b88c807SRodney W. Grimes */ 11145512dc54SYaroslav Tykhiy if ((len > TPFSZ) || (len == 0)) 11154b88c807SRodney W. Grimes return(NULL); 11164b88c807SRodney W. Grimes 11174b88c807SRodney W. Grimes /* 11184b88c807SRodney W. Grimes * ok have a split point, return it to the caller 11194b88c807SRodney W. Grimes */ 11204b88c807SRodney W. Grimes return(start); 11214b88c807SRodney W. Grimes } 1122