14b88c807SRodney W. Grimes /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 44b88c807SRodney W. Grimes * Copyright (c) 1992 Keith Muller. 54b88c807SRodney W. Grimes * Copyright (c) 1992, 1993 64b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 94b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego. 104b88c807SRodney W. Grimes * 114b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 124b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 134b88c807SRodney W. Grimes * are met: 144b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 164b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 174b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 184b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 204b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 214b88c807SRodney W. Grimes * without specific prior written permission. 224b88c807SRodney W. Grimes * 234b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 244b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 254b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 264b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 274b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 284b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 294b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 304b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 314b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 324b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 334b88c807SRodney W. Grimes * SUCH DAMAGE. 344b88c807SRodney W. Grimes */ 354b88c807SRodney W. Grimes 364b88c807SRodney W. Grimes #include <sys/types.h> 374b88c807SRodney W. Grimes #include <sys/time.h> 384b88c807SRodney W. Grimes #include <sys/stat.h> 394b88c807SRodney W. Grimes #include <string.h> 404b88c807SRodney W. Grimes #include <stdio.h> 414b88c807SRodney W. Grimes #include "pax.h" 424b88c807SRodney W. Grimes #include "extern.h" 434b88c807SRodney W. Grimes #include "tar.h" 444b88c807SRodney W. Grimes 454b88c807SRodney W. Grimes /* 464b88c807SRodney W. Grimes * Routines for reading, writing and header identify of various versions of tar 474b88c807SRodney W. Grimes */ 484b88c807SRodney W. Grimes 49f789b261SWarner Losh static u_long tar_chksm(char *, int); 50f789b261SWarner Losh static char *name_split(char *, int); 51f789b261SWarner Losh static int ul_oct(u_long, char *, int, int); 52f789b261SWarner Losh static int uqd_oct(u_quad_t, char *, int, int); 534b88c807SRodney W. Grimes 544b88c807SRodney W. Grimes /* 554b88c807SRodney W. Grimes * Routines common to all versions of tar 564b88c807SRodney W. Grimes */ 574b88c807SRodney W. Grimes 584b88c807SRodney W. Grimes static int tar_nodir; /* do not write dirs under old tar */ 594b88c807SRodney W. Grimes 604b88c807SRodney W. Grimes /* 614b88c807SRodney W. Grimes * tar_endwr() 624b88c807SRodney W. Grimes * add the tar trailer of two null blocks 634b88c807SRodney W. Grimes * Return: 644b88c807SRodney W. Grimes * 0 if ok, -1 otherwise (what wr_skip returns) 654b88c807SRodney W. Grimes */ 664b88c807SRodney W. Grimes 674b88c807SRodney W. Grimes int 684b88c807SRodney W. Grimes tar_endwr(void) 694b88c807SRodney W. Grimes { 704b88c807SRodney W. Grimes return(wr_skip((off_t)(NULLCNT*BLKMULT))); 714b88c807SRodney W. Grimes } 724b88c807SRodney W. Grimes 734b88c807SRodney W. Grimes /* 744b88c807SRodney W. Grimes * tar_endrd() 754b88c807SRodney W. Grimes * no cleanup needed here, just return size of trailer (for append) 764b88c807SRodney W. Grimes * Return: 774b88c807SRodney W. Grimes * size of trailer (2 * BLKMULT) 784b88c807SRodney W. Grimes */ 794b88c807SRodney W. Grimes 804b88c807SRodney W. Grimes off_t 814b88c807SRodney W. Grimes tar_endrd(void) 824b88c807SRodney W. Grimes { 834b88c807SRodney W. Grimes return((off_t)(NULLCNT*BLKMULT)); 844b88c807SRodney W. Grimes } 854b88c807SRodney W. Grimes 864b88c807SRodney W. Grimes /* 874b88c807SRodney W. Grimes * tar_trail() 884b88c807SRodney W. Grimes * Called to determine if a header block is a valid trailer. We are passed 894b88c807SRodney W. Grimes * the block, the in_sync flag (which tells us we are in resync mode; 904b88c807SRodney W. Grimes * looking for a valid header), and cnt (which starts at zero) which is 914b88c807SRodney W. Grimes * used to count the number of empty blocks we have seen so far. 924b88c807SRodney W. Grimes * Return: 934b88c807SRodney W. Grimes * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block 944b88c807SRodney W. Grimes * could never contain a header. 954b88c807SRodney W. Grimes */ 964b88c807SRodney W. Grimes 974b88c807SRodney W. Grimes int 98f789b261SWarner Losh tar_trail(char *buf, int in_resync, int *cnt) 994b88c807SRodney W. Grimes { 100f789b261SWarner Losh int i; 1014b88c807SRodney W. Grimes 1024b88c807SRodney W. Grimes /* 1034b88c807SRodney W. Grimes * look for all zero, trailer is two consecutive blocks of zero 1044b88c807SRodney W. Grimes */ 1054b88c807SRodney W. Grimes for (i = 0; i < BLKMULT; ++i) { 1064b88c807SRodney W. Grimes if (buf[i] != '\0') 1074b88c807SRodney W. Grimes break; 1084b88c807SRodney W. Grimes } 1094b88c807SRodney W. Grimes 1104b88c807SRodney W. Grimes /* 1114b88c807SRodney W. Grimes * if not all zero it is not a trailer, but MIGHT be a header. 1124b88c807SRodney W. Grimes */ 1134b88c807SRodney W. Grimes if (i != BLKMULT) 1144b88c807SRodney W. Grimes return(-1); 1154b88c807SRodney W. Grimes 1164b88c807SRodney W. Grimes /* 1174b88c807SRodney W. Grimes * When given a zero block, we must be careful! 1184b88c807SRodney W. Grimes * If we are not in resync mode, check for the trailer. Have to watch 1194b88c807SRodney W. Grimes * out that we do not mis-identify file data as the trailer, so we do 1204b88c807SRodney W. Grimes * NOT try to id a trailer during resync mode. During resync mode we 1214b88c807SRodney W. Grimes * might as well throw this block out since a valid header can NEVER be 1224b88c807SRodney W. Grimes * a block of all 0 (we must have a valid file name). 1234b88c807SRodney W. Grimes */ 1244b88c807SRodney W. Grimes if (!in_resync && (++*cnt >= NULLCNT)) 1254b88c807SRodney W. Grimes return(0); 1264b88c807SRodney W. Grimes return(1); 1274b88c807SRodney W. Grimes } 1284b88c807SRodney W. Grimes 1294b88c807SRodney W. Grimes /* 1304b88c807SRodney W. Grimes * ul_oct() 1314b88c807SRodney W. Grimes * convert an unsigned long to an octal string. many oddball field 1324b88c807SRodney W. Grimes * termination characters are used by the various versions of tar in the 133b1787decSKris Kennaway * different fields. term selects which kind to use. str is '0' padded 1344b88c807SRodney W. Grimes * at the front to len. we are unable to use only one format as many old 1354b88c807SRodney W. Grimes * tar readers are very cranky about this. 1364b88c807SRodney W. Grimes * Return: 1374b88c807SRodney W. Grimes * 0 if the number fit into the string, -1 otherwise 1384b88c807SRodney W. Grimes */ 1394b88c807SRodney W. Grimes 1404b88c807SRodney W. Grimes static int 141f789b261SWarner Losh ul_oct(u_long val, char *str, int len, int term) 1424b88c807SRodney W. Grimes { 143f789b261SWarner Losh char *pt; 1444b88c807SRodney W. Grimes 1454b88c807SRodney W. Grimes /* 1464b88c807SRodney W. Grimes * term selects the appropriate character(s) for the end of the string 1474b88c807SRodney W. Grimes */ 1484b88c807SRodney W. Grimes pt = str + len - 1; 1494b88c807SRodney W. Grimes switch(term) { 1504b88c807SRodney W. Grimes case 3: 1514b88c807SRodney W. Grimes *pt-- = '\0'; 1524b88c807SRodney W. Grimes break; 1534b88c807SRodney W. Grimes case 2: 1544b88c807SRodney W. Grimes *pt-- = ' '; 1554b88c807SRodney W. Grimes *pt-- = '\0'; 1564b88c807SRodney W. Grimes break; 1574b88c807SRodney W. Grimes case 1: 1584b88c807SRodney W. Grimes *pt-- = ' '; 1594b88c807SRodney W. Grimes break; 1604b88c807SRodney W. Grimes case 0: 1614b88c807SRodney W. Grimes default: 1624b88c807SRodney W. Grimes *pt-- = '\0'; 1634b88c807SRodney W. Grimes *pt-- = ' '; 1644b88c807SRodney W. Grimes break; 1654b88c807SRodney W. Grimes } 1664b88c807SRodney W. Grimes 1674b88c807SRodney W. Grimes /* 1684b88c807SRodney W. Grimes * convert and blank pad if there is space 1694b88c807SRodney W. Grimes */ 1704b88c807SRodney W. Grimes while (pt >= str) { 1714b88c807SRodney W. Grimes *pt-- = '0' + (char)(val & 0x7); 1724b88c807SRodney W. Grimes if ((val = val >> 3) == (u_long)0) 1734b88c807SRodney W. Grimes break; 1744b88c807SRodney W. Grimes } 1754b88c807SRodney W. Grimes 1764b88c807SRodney W. Grimes while (pt >= str) 177b1787decSKris Kennaway *pt-- = '0'; 1784b88c807SRodney W. Grimes if (val != (u_long)0) 1794b88c807SRodney W. Grimes return(-1); 1804b88c807SRodney W. Grimes return(0); 1814b88c807SRodney W. Grimes } 1824b88c807SRodney W. Grimes 1834b88c807SRodney W. Grimes /* 1844b88c807SRodney W. Grimes * uqd_oct() 1854b88c807SRodney W. Grimes * convert an u_quad_t to an octal string. one of many oddball field 1864b88c807SRodney W. Grimes * termination characters are used by the various versions of tar in the 187b1787decSKris Kennaway * different fields. term selects which kind to use. str is '0' padded 1884b88c807SRodney W. Grimes * at the front to len. we are unable to use only one format as many old 1894b88c807SRodney W. Grimes * tar readers are very cranky about this. 1904b88c807SRodney W. Grimes * Return: 1914b88c807SRodney W. Grimes * 0 if the number fit into the string, -1 otherwise 1924b88c807SRodney W. Grimes */ 1934b88c807SRodney W. Grimes 1944b88c807SRodney W. Grimes static int 195f789b261SWarner Losh uqd_oct(u_quad_t val, char *str, int len, int term) 1964b88c807SRodney W. Grimes { 197f789b261SWarner Losh char *pt; 1984b88c807SRodney W. Grimes 1994b88c807SRodney W. Grimes /* 2004b88c807SRodney W. Grimes * term selects the appropriate character(s) for the end of the string 2014b88c807SRodney W. Grimes */ 2024b88c807SRodney W. Grimes pt = str + len - 1; 2034b88c807SRodney W. Grimes switch(term) { 2044b88c807SRodney W. Grimes case 3: 2054b88c807SRodney W. Grimes *pt-- = '\0'; 2064b88c807SRodney W. Grimes break; 2074b88c807SRodney W. Grimes case 2: 2084b88c807SRodney W. Grimes *pt-- = ' '; 2094b88c807SRodney W. Grimes *pt-- = '\0'; 2104b88c807SRodney W. Grimes break; 2114b88c807SRodney W. Grimes case 1: 2124b88c807SRodney W. Grimes *pt-- = ' '; 2134b88c807SRodney W. Grimes break; 2144b88c807SRodney W. Grimes case 0: 2154b88c807SRodney W. Grimes default: 2164b88c807SRodney W. Grimes *pt-- = '\0'; 2174b88c807SRodney W. Grimes *pt-- = ' '; 2184b88c807SRodney W. Grimes break; 2194b88c807SRodney W. Grimes } 2204b88c807SRodney W. Grimes 2214b88c807SRodney W. Grimes /* 2224b88c807SRodney W. Grimes * convert and blank pad if there is space 2234b88c807SRodney W. Grimes */ 2244b88c807SRodney W. Grimes while (pt >= str) { 2254b88c807SRodney W. Grimes *pt-- = '0' + (char)(val & 0x7); 2264b88c807SRodney W. Grimes if ((val = val >> 3) == 0) 2274b88c807SRodney W. Grimes break; 2284b88c807SRodney W. Grimes } 2294b88c807SRodney W. Grimes 2304b88c807SRodney W. Grimes while (pt >= str) 231b1787decSKris Kennaway *pt-- = '0'; 2324b88c807SRodney W. Grimes if (val != (u_quad_t)0) 2334b88c807SRodney W. Grimes return(-1); 2344b88c807SRodney W. Grimes return(0); 2354b88c807SRodney W. Grimes } 2364b88c807SRodney W. Grimes 2374b88c807SRodney W. Grimes /* 2384b88c807SRodney W. Grimes * tar_chksm() 2394b88c807SRodney W. Grimes * calculate the checksum for a tar block counting the checksum field as 24046be34b9SKris Kennaway * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). 2414b88c807SRodney W. Grimes * NOTE: we use len to short circuit summing 0's on write since we ALWAYS 2424b88c807SRodney W. Grimes * pad headers with 0. 2434b88c807SRodney W. Grimes * Return: 2444b88c807SRodney W. Grimes * unsigned long checksum 2454b88c807SRodney W. Grimes */ 2464b88c807SRodney W. Grimes 2474b88c807SRodney W. Grimes static u_long 248f789b261SWarner Losh tar_chksm(char *blk, int len) 2494b88c807SRodney W. Grimes { 250f789b261SWarner Losh char *stop; 251f789b261SWarner Losh char *pt; 25246be34b9SKris Kennaway u_long chksm = BLNKSUM; /* initial value is checksum field sum */ 2534b88c807SRodney W. Grimes 2544b88c807SRodney W. Grimes /* 2554b88c807SRodney W. Grimes * add the part of the block before the checksum field 2564b88c807SRodney W. Grimes */ 2574b88c807SRodney W. Grimes pt = blk; 2584b88c807SRodney W. Grimes stop = blk + CHK_OFFSET; 2594b88c807SRodney W. Grimes while (pt < stop) 2604b88c807SRodney W. Grimes chksm += (u_long)(*pt++ & 0xff); 2614b88c807SRodney W. Grimes /* 2624b88c807SRodney W. Grimes * move past the checksum field and keep going, spec counts the 2634b88c807SRodney W. Grimes * checksum field as the sum of 8 blanks (which is pre-computed as 2644b88c807SRodney W. Grimes * BLNKSUM). 2654b88c807SRodney W. Grimes * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding 2664b88c807SRodney W. Grimes * starts, no point in summing zero's) 2674b88c807SRodney W. Grimes */ 2684b88c807SRodney W. Grimes pt += CHK_LEN; 2694b88c807SRodney W. Grimes stop = blk + len; 2704b88c807SRodney W. Grimes while (pt < stop) 2714b88c807SRodney W. Grimes chksm += (u_long)(*pt++ & 0xff); 2724b88c807SRodney W. Grimes return(chksm); 2734b88c807SRodney W. Grimes } 2744b88c807SRodney W. Grimes 2754b88c807SRodney W. Grimes /* 2764b88c807SRodney W. Grimes * Routines for old BSD style tar (also made portable to sysV tar) 2774b88c807SRodney W. Grimes */ 2784b88c807SRodney W. Grimes 2794b88c807SRodney W. Grimes /* 2804b88c807SRodney W. Grimes * tar_id() 2814b88c807SRodney W. Grimes * determine if a block given to us is a valid tar header (and not a USTAR 2824b88c807SRodney W. Grimes * header). We have to be on the lookout for those pesky blocks of all 2834b88c807SRodney W. Grimes * zero's. 2844b88c807SRodney W. Grimes * Return: 2854b88c807SRodney W. Grimes * 0 if a tar header, -1 otherwise 2864b88c807SRodney W. Grimes */ 2874b88c807SRodney W. Grimes 2884b88c807SRodney W. Grimes int 289f789b261SWarner Losh tar_id(char *blk, int size) 2904b88c807SRodney W. Grimes { 291f789b261SWarner Losh HD_TAR *hd; 292f789b261SWarner Losh HD_USTAR *uhd; 2934b88c807SRodney W. Grimes 2944b88c807SRodney W. Grimes if (size < BLKMULT) 2954b88c807SRodney W. Grimes return(-1); 2964b88c807SRodney W. Grimes hd = (HD_TAR *)blk; 2974b88c807SRodney W. Grimes uhd = (HD_USTAR *)blk; 2984b88c807SRodney W. Grimes 2994b88c807SRodney W. Grimes /* 3004b88c807SRodney W. Grimes * check for block of zero's first, a simple and fast test, then make 3014b88c807SRodney W. Grimes * sure this is not a ustar header by looking for the ustar magic 3024b88c807SRodney W. Grimes * cookie. We should use TMAGLEN, but some USTAR archive programs are 3034b88c807SRodney W. Grimes * wrong and create archives missing the \0. Last we check the 3044b88c807SRodney W. Grimes * checksum. If this is ok we have to assume it is a valid header. 3054b88c807SRodney W. Grimes */ 3064b88c807SRodney W. Grimes if (hd->name[0] == '\0') 3074b88c807SRodney W. Grimes return(-1); 3084b88c807SRodney W. Grimes if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) 3094b88c807SRodney W. Grimes return(-1); 3104b88c807SRodney W. Grimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 3114b88c807SRodney W. Grimes return(-1); 3124b88c807SRodney W. Grimes return(0); 3134b88c807SRodney W. Grimes } 3144b88c807SRodney W. Grimes 3154b88c807SRodney W. Grimes /* 3164b88c807SRodney W. Grimes * tar_opt() 3174b88c807SRodney W. Grimes * handle tar format specific -o options 3184b88c807SRodney W. Grimes * Return: 3194b88c807SRodney W. Grimes * 0 if ok -1 otherwise 3204b88c807SRodney W. Grimes */ 3214b88c807SRodney W. Grimes 3224b88c807SRodney W. Grimes int 3234b88c807SRodney W. Grimes tar_opt(void) 3244b88c807SRodney W. Grimes { 3254b88c807SRodney W. Grimes OPLIST *opt; 3264b88c807SRodney W. Grimes 3274b88c807SRodney W. Grimes while ((opt = opt_next()) != NULL) { 3284b88c807SRodney W. Grimes if (strcmp(opt->name, TAR_OPTION) || 3294b88c807SRodney W. Grimes strcmp(opt->value, TAR_NODIR)) { 330778766feSKris Kennaway paxwarn(1, "Unknown tar format -o option/value pair %s=%s", 3314b88c807SRodney W. Grimes opt->name, opt->value); 332778766feSKris Kennaway paxwarn(1,"%s=%s is the only supported tar format option", 3334b88c807SRodney W. Grimes TAR_OPTION, TAR_NODIR); 3344b88c807SRodney W. Grimes return(-1); 3354b88c807SRodney W. Grimes } 3364b88c807SRodney W. Grimes 3374b88c807SRodney W. Grimes /* 3384b88c807SRodney W. Grimes * we only support one option, and only when writing 3394b88c807SRodney W. Grimes */ 3404b88c807SRodney W. Grimes if ((act != APPND) && (act != ARCHIVE)) { 341778766feSKris Kennaway paxwarn(1, "%s=%s is only supported when writing.", 3424b88c807SRodney W. Grimes opt->name, opt->value); 3434b88c807SRodney W. Grimes return(-1); 3444b88c807SRodney W. Grimes } 3454b88c807SRodney W. Grimes tar_nodir = 1; 3464b88c807SRodney W. Grimes } 3474b88c807SRodney W. Grimes return(0); 3484b88c807SRodney W. Grimes } 3494b88c807SRodney W. Grimes 3504b88c807SRodney W. Grimes 3514b88c807SRodney W. Grimes /* 3524b88c807SRodney W. Grimes * tar_rd() 3534b88c807SRodney W. Grimes * extract the values out of block already determined to be a tar header. 3544b88c807SRodney W. Grimes * store the values in the ARCHD parameter. 3554b88c807SRodney W. Grimes * Return: 3564b88c807SRodney W. Grimes * 0 3574b88c807SRodney W. Grimes */ 3584b88c807SRodney W. Grimes 3594b88c807SRodney W. Grimes int 360f789b261SWarner Losh tar_rd(ARCHD *arcn, char *buf) 3614b88c807SRodney W. Grimes { 362f789b261SWarner Losh HD_TAR *hd; 363f789b261SWarner Losh char *pt; 3644b88c807SRodney W. Grimes 3654b88c807SRodney W. Grimes /* 3664b88c807SRodney W. Grimes * we only get proper sized buffers passed to us 3674b88c807SRodney W. Grimes */ 3684b88c807SRodney W. Grimes if (tar_id(buf, BLKMULT) < 0) 3694b88c807SRodney W. Grimes return(-1); 370*f890020dSDag-Erling Smørgrav memset(arcn, 0, sizeof *arcn); 3714b88c807SRodney W. Grimes arcn->org_name = arcn->name; 3724b88c807SRodney W. Grimes arcn->sb.st_nlink = 1; 3734b88c807SRodney W. Grimes 3744b88c807SRodney W. Grimes /* 3754b88c807SRodney W. Grimes * copy out the name and values in the stat buffer 3764b88c807SRodney W. Grimes */ 3774b88c807SRodney W. Grimes hd = (HD_TAR *)buf; 3785512dc54SYaroslav Tykhiy /* 3795512dc54SYaroslav Tykhiy * old tar format specifies the name always be null-terminated, 3805512dc54SYaroslav Tykhiy * but let's be robust to broken archives. 3815512dc54SYaroslav Tykhiy * the same applies to handling links below. 3825512dc54SYaroslav Tykhiy */ 3835512dc54SYaroslav Tykhiy arcn->nlen = l_strncpy(arcn->name, hd->name, 3845512dc54SYaroslav Tykhiy MIN(sizeof(hd->name), sizeof(arcn->name)) - 1); 3854b88c807SRodney W. Grimes arcn->name[arcn->nlen] = '\0'; 3864b88c807SRodney W. Grimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 3874b88c807SRodney W. Grimes 0xfff); 3884b88c807SRodney W. Grimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 3894b88c807SRodney W. Grimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 390b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 391dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 3924b88c807SRodney W. Grimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 3934b88c807SRodney W. Grimes 3944b88c807SRodney W. Grimes /* 3954b88c807SRodney W. Grimes * have to look at the last character, it may be a '/' and that is used 3964b88c807SRodney W. Grimes * to encode this as a directory 3974b88c807SRodney W. Grimes */ 3984b88c807SRodney W. Grimes pt = &(arcn->name[arcn->nlen - 1]); 3994b88c807SRodney W. Grimes switch(hd->linkflag) { 4004b88c807SRodney W. Grimes case SYMTYPE: 4014b88c807SRodney W. Grimes /* 4024b88c807SRodney W. Grimes * symbolic link, need to get the link name and set the type in 4034b88c807SRodney W. Grimes * the st_mode so -v printing will look correct. 4044b88c807SRodney W. Grimes */ 4054b88c807SRodney W. Grimes arcn->type = PAX_SLK; 4064b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4075512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4084b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4094b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFLNK; 4104b88c807SRodney W. Grimes break; 4114b88c807SRodney W. Grimes case LNKTYPE: 4124b88c807SRodney W. Grimes /* 4134b88c807SRodney W. Grimes * hard link, need to get the link name, set the type in the 4144b88c807SRodney W. Grimes * st_mode and st_nlink so -v printing will look better. 4154b88c807SRodney W. Grimes */ 4164b88c807SRodney W. Grimes arcn->type = PAX_HLK; 4174b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 4184b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 4195512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); 4204b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 4214b88c807SRodney W. Grimes 4224b88c807SRodney W. Grimes /* 4234b88c807SRodney W. Grimes * no idea of what type this thing really points at, but 4244b88c807SRodney W. Grimes * we set something for printing only. 4254b88c807SRodney W. Grimes */ 4264b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 4274b88c807SRodney W. Grimes break; 428b1787decSKris Kennaway case DIRTYPE: 429b1787decSKris Kennaway /* 430b1787decSKris Kennaway * It is a directory, set the mode for -v printing 431b1787decSKris Kennaway */ 432b1787decSKris Kennaway arcn->type = PAX_DIR; 433b1787decSKris Kennaway arcn->sb.st_mode |= S_IFDIR; 434b1787decSKris Kennaway arcn->sb.st_nlink = 2; 435b1787decSKris Kennaway break; 4364b88c807SRodney W. Grimes case AREGTYPE: 4374b88c807SRodney W. Grimes case REGTYPE: 4384b88c807SRodney W. Grimes default: 4394b88c807SRodney W. Grimes /* 4404b88c807SRodney W. Grimes * If we have a trailing / this is a directory and NOT a file. 4414b88c807SRodney W. Grimes */ 4424b88c807SRodney W. Grimes if (*pt == '/') { 4434b88c807SRodney W. Grimes /* 4444b88c807SRodney W. Grimes * it is a directory, set the mode for -v printing 4454b88c807SRodney W. Grimes */ 4464b88c807SRodney W. Grimes arcn->type = PAX_DIR; 4474b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFDIR; 4484b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 4494b88c807SRodney W. Grimes } else { 4504b88c807SRodney W. Grimes /* 4514b88c807SRodney W. Grimes * have a file that will be followed by data. Set the 45246be34b9SKris Kennaway * skip value to the size field and calculate the size 4534b88c807SRodney W. Grimes * of the padding. 4544b88c807SRodney W. Grimes */ 4554b88c807SRodney W. Grimes arcn->type = PAX_REG; 4564b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 4574b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 4584b88c807SRodney W. Grimes arcn->skip = arcn->sb.st_size; 4594b88c807SRodney W. Grimes } 4604b88c807SRodney W. Grimes break; 4614b88c807SRodney W. Grimes } 4624b88c807SRodney W. Grimes 4634b88c807SRodney W. Grimes /* 4644b88c807SRodney W. Grimes * strip off any trailing slash. 4654b88c807SRodney W. Grimes */ 4664b88c807SRodney W. Grimes if (*pt == '/') { 4674b88c807SRodney W. Grimes *pt = '\0'; 4684b88c807SRodney W. Grimes --arcn->nlen; 4694b88c807SRodney W. Grimes } 4704b88c807SRodney W. Grimes return(0); 4714b88c807SRodney W. Grimes } 4724b88c807SRodney W. Grimes 4734b88c807SRodney W. Grimes /* 4744b88c807SRodney W. Grimes * tar_wr() 4754b88c807SRodney W. Grimes * write a tar header for the file specified in the ARCHD to the archive. 4764b88c807SRodney W. Grimes * Have to check for file types that cannot be stored and file names that 4774b88c807SRodney W. Grimes * are too long. Be careful of the term (last arg) to ul_oct, each field 4784b88c807SRodney W. Grimes * of tar has it own spec for the termination character(s). 4794b88c807SRodney W. Grimes * ASSUMED: space after header in header block is zero filled 4804b88c807SRodney W. Grimes * Return: 4814b88c807SRodney W. Grimes * 0 if file has data to be written after the header, 1 if file has NO 4824b88c807SRodney W. Grimes * data to write after the header, -1 if archive write failed 4834b88c807SRodney W. Grimes */ 4844b88c807SRodney W. Grimes 4854b88c807SRodney W. Grimes int 486f789b261SWarner Losh tar_wr(ARCHD *arcn) 4874b88c807SRodney W. Grimes { 488f789b261SWarner Losh HD_TAR *hd; 4894b88c807SRodney W. Grimes int len; 490c65bb135SRuslan Ermilov HD_TAR hdblk; 4914b88c807SRodney W. Grimes 4924b88c807SRodney W. Grimes /* 4934b88c807SRodney W. Grimes * check for those file system types which tar cannot store 4944b88c807SRodney W. Grimes */ 4954b88c807SRodney W. Grimes switch(arcn->type) { 4964b88c807SRodney W. Grimes case PAX_DIR: 4974b88c807SRodney W. Grimes /* 4984b88c807SRodney W. Grimes * user asked that dirs not be written to the archive 4994b88c807SRodney W. Grimes */ 5004b88c807SRodney W. Grimes if (tar_nodir) 5014b88c807SRodney W. Grimes return(1); 5024b88c807SRodney W. Grimes break; 5034b88c807SRodney W. Grimes case PAX_CHR: 504778766feSKris Kennaway paxwarn(1, "Tar cannot archive a character device %s", 5054b88c807SRodney W. Grimes arcn->org_name); 5064b88c807SRodney W. Grimes return(1); 5074b88c807SRodney W. Grimes case PAX_BLK: 508778766feSKris Kennaway paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); 5094b88c807SRodney W. Grimes return(1); 5104b88c807SRodney W. Grimes case PAX_SCK: 511778766feSKris Kennaway paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); 5124b88c807SRodney W. Grimes return(1); 5134b88c807SRodney W. Grimes case PAX_FIF: 514778766feSKris Kennaway paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); 5154b88c807SRodney W. Grimes return(1); 5164b88c807SRodney W. Grimes case PAX_SLK: 5174b88c807SRodney W. Grimes case PAX_HLK: 5184b88c807SRodney W. Grimes case PAX_HRG: 5195512dc54SYaroslav Tykhiy if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) { 520778766feSKris Kennaway paxwarn(1,"Link name too long for tar %s", arcn->ln_name); 5214b88c807SRodney W. Grimes return(1); 5224b88c807SRodney W. Grimes } 5234b88c807SRodney W. Grimes break; 5244b88c807SRodney W. Grimes case PAX_REG: 5254b88c807SRodney W. Grimes case PAX_CTG: 5264b88c807SRodney W. Grimes default: 5274b88c807SRodney W. Grimes break; 5284b88c807SRodney W. Grimes } 5294b88c807SRodney W. Grimes 5304b88c807SRodney W. Grimes /* 5314b88c807SRodney W. Grimes * check file name len, remember extra char for dirs (the / at the end) 5324b88c807SRodney W. Grimes */ 5334b88c807SRodney W. Grimes len = arcn->nlen; 5344b88c807SRodney W. Grimes if (arcn->type == PAX_DIR) 5354b88c807SRodney W. Grimes ++len; 536cee22cbdSDavid E. O'Brien if (len >= (int)sizeof(hd->name)) { 537778766feSKris Kennaway paxwarn(1, "File name too long for tar %s", arcn->name); 5384b88c807SRodney W. Grimes return(1); 5394b88c807SRodney W. Grimes } 5404b88c807SRodney W. Grimes 5414b88c807SRodney W. Grimes /* 5420266a5d6SDag-Erling Smørgrav * Copy the data out of the ARCHD into the tar header based on the type 5430266a5d6SDag-Erling Smørgrav * of the file. Remember, many tar readers want all fields to be 5440266a5d6SDag-Erling Smørgrav * padded with zero so we zero the header first. We then set the 5450266a5d6SDag-Erling Smørgrav * linkflag field (type), the linkname, the size, and set the padding 5460266a5d6SDag-Erling Smørgrav * (if any) to be added after the file data (0 for all other types, 5470266a5d6SDag-Erling Smørgrav * as they only have a header). 5484b88c807SRodney W. Grimes */ 549c65bb135SRuslan Ermilov hd = &hdblk; 550b1787decSKris Kennaway l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); 551b1787decSKris Kennaway hd->name[sizeof(hd->name) - 1] = '\0'; 5524b88c807SRodney W. Grimes arcn->pad = 0; 5534b88c807SRodney W. Grimes 5544b88c807SRodney W. Grimes if (arcn->type == PAX_DIR) { 5554b88c807SRodney W. Grimes /* 5564b88c807SRodney W. Grimes * directories are the same as files, except have a filename 5574b88c807SRodney W. Grimes * that ends with a /, we add the slash here. No data follows, 5584b88c807SRodney W. Grimes * dirs, so no pad. 5594b88c807SRodney W. Grimes */ 5604b88c807SRodney W. Grimes hd->linkflag = AREGTYPE; 561778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 5624b88c807SRodney W. Grimes hd->name[len-1] = '/'; 5634b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5644b88c807SRodney W. Grimes goto out; 5654b88c807SRodney W. Grimes } else if (arcn->type == PAX_SLK) { 5664b88c807SRodney W. Grimes /* 5674b88c807SRodney W. Grimes * no data follows this file, so no pad 5684b88c807SRodney W. Grimes */ 5694b88c807SRodney W. Grimes hd->linkflag = SYMTYPE; 570b1787decSKris Kennaway l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 571b1787decSKris Kennaway hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 5724b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5734b88c807SRodney W. Grimes goto out; 5744b88c807SRodney W. Grimes } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 5754b88c807SRodney W. Grimes /* 5764b88c807SRodney W. Grimes * no data follows this file, so no pad 5774b88c807SRodney W. Grimes */ 5784b88c807SRodney W. Grimes hd->linkflag = LNKTYPE; 579b1787decSKris Kennaway l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); 580b1787decSKris Kennaway hd->linkname[sizeof(hd->linkname) - 1] = '\0'; 5814b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) 5824b88c807SRodney W. Grimes goto out; 5834b88c807SRodney W. Grimes } else { 5844b88c807SRodney W. Grimes /* 5854b88c807SRodney W. Grimes * data follows this file, so set the pad 5864b88c807SRodney W. Grimes */ 5874b88c807SRodney W. Grimes hd->linkflag = AREGTYPE; 588778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 5894b88c807SRodney W. Grimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 5904b88c807SRodney W. Grimes sizeof(hd->size), 1)) { 591778766feSKris Kennaway paxwarn(1,"File is too large for tar %s", arcn->org_name); 5924b88c807SRodney W. Grimes return(1); 5934b88c807SRodney W. Grimes } 5944b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 5954b88c807SRodney W. Grimes } 5964b88c807SRodney W. Grimes 5974b88c807SRodney W. Grimes /* 5984b88c807SRodney W. Grimes * copy those fields that are independent of the type 5994b88c807SRodney W. Grimes */ 6004b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || 6014b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || 6024b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || 6034b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) 6044b88c807SRodney W. Grimes goto out; 6054b88c807SRodney W. Grimes 6064b88c807SRodney W. Grimes /* 6074b88c807SRodney W. Grimes * calculate and add the checksum, then write the header. A return of 6084b88c807SRodney W. Grimes * 0 tells the caller to now write the file data, 1 says no data needs 6094b88c807SRodney W. Grimes * to be written 6104b88c807SRodney W. Grimes */ 611c65bb135SRuslan Ermilov if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum, 612b1787decSKris Kennaway sizeof(hd->chksum), 3)) 6134b88c807SRodney W. Grimes goto out; 614c65bb135SRuslan Ermilov if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0) 6154b88c807SRodney W. Grimes return(-1); 6164b88c807SRodney W. Grimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) 6174b88c807SRodney W. Grimes return(-1); 6184b88c807SRodney W. Grimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 6194b88c807SRodney W. Grimes return(0); 6204b88c807SRodney W. Grimes return(1); 6214b88c807SRodney W. Grimes 6224b88c807SRodney W. Grimes out: 6234b88c807SRodney W. Grimes /* 6244b88c807SRodney W. Grimes * header field is out of range 6254b88c807SRodney W. Grimes */ 626778766feSKris Kennaway paxwarn(1, "Tar header field is too small for %s", arcn->org_name); 6274b88c807SRodney W. Grimes return(1); 6284b88c807SRodney W. Grimes } 6294b88c807SRodney W. Grimes 6304b88c807SRodney W. Grimes /* 6314b88c807SRodney W. Grimes * Routines for POSIX ustar 6324b88c807SRodney W. Grimes */ 6334b88c807SRodney W. Grimes 6344b88c807SRodney W. Grimes /* 6354b88c807SRodney W. Grimes * ustar_strd() 6364b88c807SRodney W. Grimes * initialization for ustar read 6374b88c807SRodney W. Grimes * Return: 6384b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 6394b88c807SRodney W. Grimes */ 6404b88c807SRodney W. Grimes 6414b88c807SRodney W. Grimes int 6424b88c807SRodney W. Grimes ustar_strd(void) 6434b88c807SRodney W. Grimes { 6444b88c807SRodney W. Grimes if ((usrtb_start() < 0) || (grptb_start() < 0)) 6454b88c807SRodney W. Grimes return(-1); 6464b88c807SRodney W. Grimes return(0); 6474b88c807SRodney W. Grimes } 6484b88c807SRodney W. Grimes 6494b88c807SRodney W. Grimes /* 6504b88c807SRodney W. Grimes * ustar_stwr() 6514b88c807SRodney W. Grimes * initialization for ustar write 6524b88c807SRodney W. Grimes * Return: 6534b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 6544b88c807SRodney W. Grimes */ 6554b88c807SRodney W. Grimes 6564b88c807SRodney W. Grimes int 6574b88c807SRodney W. Grimes ustar_stwr(void) 6584b88c807SRodney W. Grimes { 6594b88c807SRodney W. Grimes if ((uidtb_start() < 0) || (gidtb_start() < 0)) 6604b88c807SRodney W. Grimes return(-1); 6614b88c807SRodney W. Grimes return(0); 6624b88c807SRodney W. Grimes } 6634b88c807SRodney W. Grimes 6644b88c807SRodney W. Grimes /* 6654b88c807SRodney W. Grimes * ustar_id() 6664b88c807SRodney W. Grimes * determine if a block given to us is a valid ustar header. We have to 6674b88c807SRodney W. Grimes * be on the lookout for those pesky blocks of all zero's 6684b88c807SRodney W. Grimes * Return: 6694b88c807SRodney W. Grimes * 0 if a ustar header, -1 otherwise 6704b88c807SRodney W. Grimes */ 6714b88c807SRodney W. Grimes 6724b88c807SRodney W. Grimes int 6734b88c807SRodney W. Grimes ustar_id(char *blk, int size) 6744b88c807SRodney W. Grimes { 675f789b261SWarner Losh HD_USTAR *hd; 6764b88c807SRodney W. Grimes 6774b88c807SRodney W. Grimes if (size < BLKMULT) 6784b88c807SRodney W. Grimes return(-1); 6794b88c807SRodney W. Grimes hd = (HD_USTAR *)blk; 6804b88c807SRodney W. Grimes 6814b88c807SRodney W. Grimes /* 6824b88c807SRodney W. Grimes * check for block of zero's first, a simple and fast test then check 6834b88c807SRodney W. Grimes * ustar magic cookie. We should use TMAGLEN, but some USTAR archive 6844b88c807SRodney W. Grimes * programs are fouled up and create archives missing the \0. Last we 6854b88c807SRodney W. Grimes * check the checksum. If ok we have to assume it is a valid header. 6864b88c807SRodney W. Grimes */ 6874b88c807SRodney W. Grimes if (hd->name[0] == '\0') 6884b88c807SRodney W. Grimes return(-1); 6894b88c807SRodney W. Grimes if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) 6904b88c807SRodney W. Grimes return(-1); 6914b88c807SRodney W. Grimes if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) 6924b88c807SRodney W. Grimes return(-1); 6934b88c807SRodney W. Grimes return(0); 6944b88c807SRodney W. Grimes } 6954b88c807SRodney W. Grimes 6964b88c807SRodney W. Grimes /* 6974b88c807SRodney W. Grimes * ustar_rd() 6984b88c807SRodney W. Grimes * extract the values out of block already determined to be a ustar header. 6994b88c807SRodney W. Grimes * store the values in the ARCHD parameter. 7004b88c807SRodney W. Grimes * Return: 7014b88c807SRodney W. Grimes * 0 7024b88c807SRodney W. Grimes */ 7034b88c807SRodney W. Grimes 7044b88c807SRodney W. Grimes int 705f789b261SWarner Losh ustar_rd(ARCHD *arcn, char *buf) 7064b88c807SRodney W. Grimes { 707f789b261SWarner Losh HD_USTAR *hd; 708f789b261SWarner Losh char *dest; 709f789b261SWarner Losh int cnt = 0; 7104b88c807SRodney W. Grimes dev_t devmajor; 7114b88c807SRodney W. Grimes dev_t devminor; 7124b88c807SRodney W. Grimes 7134b88c807SRodney W. Grimes /* 7144b88c807SRodney W. Grimes * we only get proper sized buffers 7154b88c807SRodney W. Grimes */ 7164b88c807SRodney W. Grimes if (ustar_id(buf, BLKMULT) < 0) 7174b88c807SRodney W. Grimes return(-1); 718*f890020dSDag-Erling Smørgrav memset(arcn, 0, sizeof *arcn); 7194b88c807SRodney W. Grimes arcn->org_name = arcn->name; 7204b88c807SRodney W. Grimes arcn->sb.st_nlink = 1; 7214b88c807SRodney W. Grimes hd = (HD_USTAR *)buf; 7224b88c807SRodney W. Grimes 7234b88c807SRodney W. Grimes /* 7244b88c807SRodney W. Grimes * see if the filename is split into two parts. if, so joint the parts. 7254b88c807SRodney W. Grimes * we copy the prefix first and add a / between the prefix and name. 7264b88c807SRodney W. Grimes */ 7274b88c807SRodney W. Grimes dest = arcn->name; 7284b88c807SRodney W. Grimes if (*(hd->prefix) != '\0') { 7295512dc54SYaroslav Tykhiy cnt = l_strncpy(dest, hd->prefix, 7305512dc54SYaroslav Tykhiy MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2)); 731b1787decSKris Kennaway dest += cnt; 7324b88c807SRodney W. Grimes *dest++ = '/'; 733b1787decSKris Kennaway cnt++; 7344b88c807SRodney W. Grimes } 7355512dc54SYaroslav Tykhiy /* 7365512dc54SYaroslav Tykhiy * ustar format specifies the name may be unterminated 7375512dc54SYaroslav Tykhiy * if it fills the entire field. this also applies to 7385512dc54SYaroslav Tykhiy * the prefix and the linkname. 7395512dc54SYaroslav Tykhiy */ 7405512dc54SYaroslav Tykhiy arcn->nlen = cnt + l_strncpy(dest, hd->name, 7415512dc54SYaroslav Tykhiy MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1)); 7424b88c807SRodney W. Grimes arcn->name[arcn->nlen] = '\0'; 7434b88c807SRodney W. Grimes 7444b88c807SRodney W. Grimes /* 7454b88c807SRodney W. Grimes * follow the spec to the letter. we should only have mode bits, strip 7464b88c807SRodney W. Grimes * off all other crud we may be passed. 7474b88c807SRodney W. Grimes */ 7484b88c807SRodney W. Grimes arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 7494b88c807SRodney W. Grimes 0xfff); 750b1787decSKris Kennaway arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); 751dbd9746fSMatthew Dillon arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); 7524b88c807SRodney W. Grimes arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; 7534b88c807SRodney W. Grimes 7544b88c807SRodney W. Grimes /* 7554b88c807SRodney W. Grimes * If we can find the ascii names for gname and uname in the password 7564b88c807SRodney W. Grimes * and group files we will use the uid's and gid they bind. Otherwise 7574b88c807SRodney W. Grimes * we use the uid and gid values stored in the header. (This is what 75846be34b9SKris Kennaway * the POSIX spec wants). 7594b88c807SRodney W. Grimes */ 7604b88c807SRodney W. Grimes hd->gname[sizeof(hd->gname) - 1] = '\0'; 7614b88c807SRodney W. Grimes if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) 7624b88c807SRodney W. Grimes arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); 7634b88c807SRodney W. Grimes hd->uname[sizeof(hd->uname) - 1] = '\0'; 7644b88c807SRodney W. Grimes if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) 7654b88c807SRodney W. Grimes arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); 7664b88c807SRodney W. Grimes 7674b88c807SRodney W. Grimes /* 7684b88c807SRodney W. Grimes * set the mode and PAX type according to the typeflag in the header 7694b88c807SRodney W. Grimes */ 7704b88c807SRodney W. Grimes switch(hd->typeflag) { 7714b88c807SRodney W. Grimes case FIFOTYPE: 7724b88c807SRodney W. Grimes arcn->type = PAX_FIF; 7734b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFIFO; 7744b88c807SRodney W. Grimes break; 7754b88c807SRodney W. Grimes case DIRTYPE: 7764b88c807SRodney W. Grimes arcn->type = PAX_DIR; 7774b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFDIR; 7784b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 7794b88c807SRodney W. Grimes 7804b88c807SRodney W. Grimes /* 7814b88c807SRodney W. Grimes * Some programs that create ustar archives append a '/' 7824b88c807SRodney W. Grimes * to the pathname for directories. This clearly violates 7834b88c807SRodney W. Grimes * ustar specs, but we will silently strip it off anyway. 7844b88c807SRodney W. Grimes */ 7854b88c807SRodney W. Grimes if (arcn->name[arcn->nlen - 1] == '/') 7864b88c807SRodney W. Grimes arcn->name[--arcn->nlen] = '\0'; 7874b88c807SRodney W. Grimes break; 7884b88c807SRodney W. Grimes case BLKTYPE: 7894b88c807SRodney W. Grimes case CHRTYPE: 7904b88c807SRodney W. Grimes /* 7914b88c807SRodney W. Grimes * this type requires the rdev field to be set. 7924b88c807SRodney W. Grimes */ 7934b88c807SRodney W. Grimes if (hd->typeflag == BLKTYPE) { 7944b88c807SRodney W. Grimes arcn->type = PAX_BLK; 7954b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFBLK; 7964b88c807SRodney W. Grimes } else { 7974b88c807SRodney W. Grimes arcn->type = PAX_CHR; 7984b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFCHR; 7994b88c807SRodney W. Grimes } 8004b88c807SRodney W. Grimes devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); 8014b88c807SRodney W. Grimes devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); 8024b88c807SRodney W. Grimes arcn->sb.st_rdev = TODEV(devmajor, devminor); 8034b88c807SRodney W. Grimes break; 8044b88c807SRodney W. Grimes case SYMTYPE: 8054b88c807SRodney W. Grimes case LNKTYPE: 8064b88c807SRodney W. Grimes if (hd->typeflag == SYMTYPE) { 8074b88c807SRodney W. Grimes arcn->type = PAX_SLK; 8084b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFLNK; 8094b88c807SRodney W. Grimes } else { 8104b88c807SRodney W. Grimes arcn->type = PAX_HLK; 8114b88c807SRodney W. Grimes /* 8124b88c807SRodney W. Grimes * so printing looks better 8134b88c807SRodney W. Grimes */ 8144b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 8154b88c807SRodney W. Grimes arcn->sb.st_nlink = 2; 8164b88c807SRodney W. Grimes } 8174b88c807SRodney W. Grimes /* 8184b88c807SRodney W. Grimes * copy the link name 8194b88c807SRodney W. Grimes */ 8204b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, 8215512dc54SYaroslav Tykhiy MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1)); 8224b88c807SRodney W. Grimes arcn->ln_name[arcn->ln_nlen] = '\0'; 8234b88c807SRodney W. Grimes break; 8244b88c807SRodney W. Grimes case CONTTYPE: 8254b88c807SRodney W. Grimes case AREGTYPE: 8264b88c807SRodney W. Grimes case REGTYPE: 8274b88c807SRodney W. Grimes default: 8284b88c807SRodney W. Grimes /* 8294b88c807SRodney W. Grimes * these types have file data that follows. Set the skip and 8304b88c807SRodney W. Grimes * pad fields. 8314b88c807SRodney W. Grimes */ 8324b88c807SRodney W. Grimes arcn->type = PAX_REG; 8334b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 8344b88c807SRodney W. Grimes arcn->skip = arcn->sb.st_size; 8354b88c807SRodney W. Grimes arcn->sb.st_mode |= S_IFREG; 8364b88c807SRodney W. Grimes break; 8374b88c807SRodney W. Grimes } 8384b88c807SRodney W. Grimes return(0); 8394b88c807SRodney W. Grimes } 8404b88c807SRodney W. Grimes 8414b88c807SRodney W. Grimes /* 8424b88c807SRodney W. Grimes * ustar_wr() 8434b88c807SRodney W. Grimes * write a ustar header for the file specified in the ARCHD to the archive 8444b88c807SRodney W. Grimes * Have to check for file types that cannot be stored and file names that 8454b88c807SRodney W. Grimes * are too long. Be careful of the term (last arg) to ul_oct, we only use 8464b88c807SRodney W. Grimes * '\0' for the termination character (this is different than picky tar) 8474b88c807SRodney W. Grimes * ASSUMED: space after header in header block is zero filled 8484b88c807SRodney W. Grimes * Return: 8494b88c807SRodney W. Grimes * 0 if file has data to be written after the header, 1 if file has NO 8504b88c807SRodney W. Grimes * data to write after the header, -1 if archive write failed 8514b88c807SRodney W. Grimes */ 8524b88c807SRodney W. Grimes 8534b88c807SRodney W. Grimes int 854f789b261SWarner Losh ustar_wr(ARCHD *arcn) 8554b88c807SRodney W. Grimes { 856f789b261SWarner Losh HD_USTAR *hd; 857f789b261SWarner Losh char *pt; 858c65bb135SRuslan Ermilov HD_USTAR hdblk; 8594b88c807SRodney W. Grimes 8604b88c807SRodney W. Grimes /* 8614b88c807SRodney W. Grimes * check for those file system types ustar cannot store 8624b88c807SRodney W. Grimes */ 8634b88c807SRodney W. Grimes if (arcn->type == PAX_SCK) { 864778766feSKris Kennaway paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); 8654b88c807SRodney W. Grimes return(1); 8664b88c807SRodney W. Grimes } 8674b88c807SRodney W. Grimes 8684b88c807SRodney W. Grimes /* 8694b88c807SRodney W. Grimes * check the length of the linkname 8704b88c807SRodney W. Grimes */ 8714b88c807SRodney W. Grimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 872cee22cbdSDavid E. O'Brien (arcn->type == PAX_HRG)) && 8735512dc54SYaroslav Tykhiy (arcn->ln_nlen > (int)sizeof(hd->linkname))) { 874778766feSKris Kennaway paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); 8754b88c807SRodney W. Grimes return(1); 8764b88c807SRodney W. Grimes } 8774b88c807SRodney W. Grimes 8784b88c807SRodney W. Grimes /* 8794b88c807SRodney W. Grimes * split the path name into prefix and name fields (if needed). if 8804b88c807SRodney W. Grimes * pt != arcn->name, the name has to be split 8814b88c807SRodney W. Grimes */ 8824b88c807SRodney W. Grimes if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { 883778766feSKris Kennaway paxwarn(1, "File name too long for ustar %s", arcn->name); 8844b88c807SRodney W. Grimes return(1); 8854b88c807SRodney W. Grimes } 886c65bb135SRuslan Ermilov hd = &hdblk; 8874b88c807SRodney W. Grimes arcn->pad = 0L; 8884b88c807SRodney W. Grimes 8894b88c807SRodney W. Grimes /* 8904b88c807SRodney W. Grimes * split the name, or zero out the prefix 8914b88c807SRodney W. Grimes */ 8924b88c807SRodney W. Grimes if (pt != arcn->name) { 8934b88c807SRodney W. Grimes /* 8944b88c807SRodney W. Grimes * name was split, pt points at the / where the split is to 8954b88c807SRodney W. Grimes * occur, we remove the / and copy the first part to the prefix 8964b88c807SRodney W. Grimes */ 8974b88c807SRodney W. Grimes *pt = '\0'; 8985512dc54SYaroslav Tykhiy l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); 8994b88c807SRodney W. Grimes *pt++ = '/'; 9004b88c807SRodney W. Grimes } else 901778766feSKris Kennaway memset(hd->prefix, 0, sizeof(hd->prefix)); 9024b88c807SRodney W. Grimes 9034b88c807SRodney W. Grimes /* 9044b88c807SRodney W. Grimes * copy the name part. this may be the whole path or the part after 9055512dc54SYaroslav Tykhiy * the prefix. both the name and prefix may fill the entire field. 9064b88c807SRodney W. Grimes */ 9075512dc54SYaroslav Tykhiy l_strncpy(hd->name, pt, sizeof(hd->name)); 9084b88c807SRodney W. Grimes 9094b88c807SRodney W. Grimes /* 9104b88c807SRodney W. Grimes * set the fields in the header that are type dependent 9114b88c807SRodney W. Grimes */ 9124b88c807SRodney W. Grimes switch(arcn->type) { 9134b88c807SRodney W. Grimes case PAX_DIR: 9144b88c807SRodney W. Grimes hd->typeflag = DIRTYPE; 915778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 916778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 917778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9184b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9194b88c807SRodney W. Grimes goto out; 9204b88c807SRodney W. Grimes break; 9214b88c807SRodney W. Grimes case PAX_CHR: 9224b88c807SRodney W. Grimes case PAX_BLK: 9234b88c807SRodney W. Grimes if (arcn->type == PAX_CHR) 9244b88c807SRodney W. Grimes hd->typeflag = CHRTYPE; 9254b88c807SRodney W. Grimes else 9264b88c807SRodney W. Grimes hd->typeflag = BLKTYPE; 927778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 9284b88c807SRodney W. Grimes if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, 9294b88c807SRodney W. Grimes sizeof(hd->devmajor), 3) || 9304b88c807SRodney W. Grimes ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, 9314b88c807SRodney W. Grimes sizeof(hd->devminor), 3) || 9324b88c807SRodney W. Grimes ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9334b88c807SRodney W. Grimes goto out; 9344b88c807SRodney W. Grimes break; 9354b88c807SRodney W. Grimes case PAX_FIF: 9364b88c807SRodney W. Grimes hd->typeflag = FIFOTYPE; 937778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 938778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 939778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9404b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9414b88c807SRodney W. Grimes goto out; 9424b88c807SRodney W. Grimes break; 9434b88c807SRodney W. Grimes case PAX_SLK: 9444b88c807SRodney W. Grimes case PAX_HLK: 9454b88c807SRodney W. Grimes case PAX_HRG: 9464b88c807SRodney W. Grimes if (arcn->type == PAX_SLK) 9474b88c807SRodney W. Grimes hd->typeflag = SYMTYPE; 9484b88c807SRodney W. Grimes else 9494b88c807SRodney W. Grimes hd->typeflag = LNKTYPE; 9505512dc54SYaroslav Tykhiy /* the link name may occupy the entire field in ustar */ 9515512dc54SYaroslav Tykhiy l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); 952778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 953778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9544b88c807SRodney W. Grimes if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) 9554b88c807SRodney W. Grimes goto out; 9564b88c807SRodney W. Grimes break; 9574b88c807SRodney W. Grimes case PAX_REG: 9584b88c807SRodney W. Grimes case PAX_CTG: 9594b88c807SRodney W. Grimes default: 9604b88c807SRodney W. Grimes /* 9614b88c807SRodney W. Grimes * file data with this type, set the padding 9624b88c807SRodney W. Grimes */ 9634b88c807SRodney W. Grimes if (arcn->type == PAX_CTG) 9644b88c807SRodney W. Grimes hd->typeflag = CONTTYPE; 9654b88c807SRodney W. Grimes else 9664b88c807SRodney W. Grimes hd->typeflag = REGTYPE; 967778766feSKris Kennaway memset(hd->linkname, 0, sizeof(hd->linkname)); 968778766feSKris Kennaway memset(hd->devmajor, 0, sizeof(hd->devmajor)); 969778766feSKris Kennaway memset(hd->devminor, 0, sizeof(hd->devminor)); 9704b88c807SRodney W. Grimes arcn->pad = TAR_PAD(arcn->sb.st_size); 9714b88c807SRodney W. Grimes if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, 9724b88c807SRodney W. Grimes sizeof(hd->size), 3)) { 973778766feSKris Kennaway paxwarn(1,"File is too long for ustar %s",arcn->org_name); 9744b88c807SRodney W. Grimes return(1); 9754b88c807SRodney W. Grimes } 9764b88c807SRodney W. Grimes break; 9774b88c807SRodney W. Grimes } 9784b88c807SRodney W. Grimes 979b1787decSKris Kennaway l_strncpy(hd->magic, TMAGIC, TMAGLEN); 980b1787decSKris Kennaway l_strncpy(hd->version, TVERSION, TVERSLEN); 9814b88c807SRodney W. Grimes 9824b88c807SRodney W. Grimes /* 9834b88c807SRodney W. Grimes * set the remaining fields. Some versions want all 16 bits of mode 9844b88c807SRodney W. Grimes * we better humor them (they really do not meet spec though).... 9854b88c807SRodney W. Grimes */ 9864b88c807SRodney W. Grimes if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || 9874b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || 9884b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || 9894b88c807SRodney W. Grimes ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) 9904b88c807SRodney W. Grimes goto out; 991b1787decSKris Kennaway l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); 992b1787decSKris Kennaway l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); 9934b88c807SRodney W. Grimes 9944b88c807SRodney W. Grimes /* 9954b88c807SRodney W. Grimes * calculate and store the checksum write the header to the archive 9964b88c807SRodney W. Grimes * return 0 tells the caller to now write the file data, 1 says no data 9974b88c807SRodney W. Grimes * needs to be written 9984b88c807SRodney W. Grimes */ 999c65bb135SRuslan Ermilov if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum, 10004b88c807SRodney W. Grimes sizeof(hd->chksum), 3)) 10014b88c807SRodney W. Grimes goto out; 1002c65bb135SRuslan Ermilov if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0) 10034b88c807SRodney W. Grimes return(-1); 10044b88c807SRodney W. Grimes if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) 10054b88c807SRodney W. Grimes return(-1); 10064b88c807SRodney W. Grimes if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) 10074b88c807SRodney W. Grimes return(0); 10084b88c807SRodney W. Grimes return(1); 10094b88c807SRodney W. Grimes 10104b88c807SRodney W. Grimes out: 10114b88c807SRodney W. Grimes /* 10124b88c807SRodney W. Grimes * header field is out of range 10134b88c807SRodney W. Grimes */ 1014778766feSKris Kennaway paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); 10154b88c807SRodney W. Grimes return(1); 10164b88c807SRodney W. Grimes } 10174b88c807SRodney W. Grimes 10184b88c807SRodney W. Grimes /* 10194b88c807SRodney W. Grimes * name_split() 10204b88c807SRodney W. Grimes * see if the name has to be split for storage in a ustar header. We try 10214b88c807SRodney W. Grimes * to fit the entire name in the name field without splitting if we can. 10224b88c807SRodney W. Grimes * The split point is always at a / 10234b88c807SRodney W. Grimes * Return 10244b88c807SRodney W. Grimes * character pointer to split point (always the / that is to be removed 10254b88c807SRodney W. Grimes * if the split is not needed, the points is set to the start of the file 10264b88c807SRodney W. Grimes * name (it would violate the spec to split there). A NULL is returned if 10274b88c807SRodney W. Grimes * the file name is too long 10284b88c807SRodney W. Grimes */ 10294b88c807SRodney W. Grimes 10304b88c807SRodney W. Grimes static char * 1031f789b261SWarner Losh name_split(char *name, int len) 10324b88c807SRodney W. Grimes { 1033f789b261SWarner Losh char *start; 10344b88c807SRodney W. Grimes 10354b88c807SRodney W. Grimes /* 10364b88c807SRodney W. Grimes * check to see if the file name is small enough to fit in the name 10374b88c807SRodney W. Grimes * field. if so just return a pointer to the name. 10384b88c807SRodney W. Grimes */ 10395512dc54SYaroslav Tykhiy if (len <= TNMSZ) 10404b88c807SRodney W. Grimes return(name); 1041cd14b457SBrian Somers if (len > TPFSZ + TNMSZ) 10424b88c807SRodney W. Grimes return(NULL); 10434b88c807SRodney W. Grimes 10444b88c807SRodney W. Grimes /* 10454b88c807SRodney W. Grimes * we start looking at the biggest sized piece that fits in the name 104646be34b9SKris Kennaway * field. We walk forward looking for a slash to split at. The idea is 10474b88c807SRodney W. Grimes * to find the biggest piece to fit in the name field (or the smallest 10484757e526SMike Smith * prefix we can find) 10494b88c807SRodney W. Grimes */ 1050f77b6c6aSBrian Somers start = name + len - TNMSZ; 10514b88c807SRodney W. Grimes while ((*start != '\0') && (*start != '/')) 10524b88c807SRodney W. Grimes ++start; 10534b88c807SRodney W. Grimes 10544b88c807SRodney W. Grimes /* 10554b88c807SRodney W. Grimes * if we hit the end of the string, this name cannot be split, so we 10564b88c807SRodney W. Grimes * cannot store this file. 10574b88c807SRodney W. Grimes */ 10584b88c807SRodney W. Grimes if (*start == '\0') 10594b88c807SRodney W. Grimes return(NULL); 10604b88c807SRodney W. Grimes len = start - name; 10614b88c807SRodney W. Grimes 10624b88c807SRodney W. Grimes /* 10634b88c807SRodney W. Grimes * NOTE: /str where the length of str == TNMSZ can not be stored under 10644b88c807SRodney W. Grimes * the p1003.1-1990 spec for ustar. We could force a prefix of / and 10654b88c807SRodney W. Grimes * the file would then expand on extract to //str. The len == 0 below 10664b88c807SRodney W. Grimes * makes this special case follow the spec to the letter. 10674b88c807SRodney W. Grimes */ 10685512dc54SYaroslav Tykhiy if ((len > TPFSZ) || (len == 0)) 10694b88c807SRodney W. Grimes return(NULL); 10704b88c807SRodney W. Grimes 10714b88c807SRodney W. Grimes /* 10724b88c807SRodney W. Grimes * ok have a split point, return it to the caller 10734b88c807SRodney W. Grimes */ 10744b88c807SRodney W. Grimes return(start); 10754b88c807SRodney W. Grimes } 1076