⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tar.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Keith Muller of the University of California, San Diego. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)tar.c	8.2 (Berkeley) 4/18/94";#endif /* not lint */#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/param.h>#include <string.h>#include <stdio.h>#include <ctype.h>#include <unistd.h>#include <stdlib.h>#include "pax.h"#include "extern.h"#include "tar.h"/* * Routines for reading, writing and header identify of various versions of tar */static u_long tar_chksm __P((register char *, register int));static char *name_split __P((register char *, register int));static int ul_oct __P((u_long, register char *, register int, int));#ifndef NET2_STATstatic int uqd_oct __P((u_quad_t, register char *, register int, int));#endif/* * Routines common to all versions of tar */static int tar_nodir;			/* do not write dirs under old tar *//* * tar_endwr() *	add the tar trailer of two null blocks * Return: *	0 if ok, -1 otherwise (what wr_skip returns) */#if __STDC__inttar_endwr(void)#elseinttar_endwr()#endif{	return(wr_skip((off_t)(NULLCNT*BLKMULT)));}/* * tar_endrd() *	no cleanup needed here, just return size of trailer (for append) * Return: *	size of trailer (2 * BLKMULT) */#if __STDC__off_ttar_endrd(void)#elseoff_ttar_endrd()#endif{	return((off_t)(NULLCNT*BLKMULT));}/* * tar_trail() *	Called to determine if a header block is a valid trailer. We are passed *	the block, the in_sync flag (which tells us we are in resync mode; *	looking for a valid header), and cnt (which starts at zero) which is *	used to count the number of empty blocks we have seen so far. * Return: *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block *	could never contain a header. */#if __STDC__inttar_trail(register char *buf, register int in_resync, register int *cnt)#elseinttar_trail(buf, in_resync, cnt)	register char *buf;	register int in_resync;	register int *cnt;#endif{	register int i;	/*	 * look for all zero, trailer is two consecutive blocks of zero	 */	for (i = 0; i < BLKMULT; ++i) {		if (buf[i] != '\0')			break;	}	/*	 * if not all zero it is not a trailer, but MIGHT be a header.	 */	if (i != BLKMULT)		return(-1);	/*	 * When given a zero block, we must be careful!	 * If we are not in resync mode, check for the trailer. Have to watch	 * out that we do not mis-identify file data as the trailer, so we do	 * NOT try to id a trailer during resync mode. During resync mode we	 * might as well throw this block out since a valid header can NEVER be	 * a block of all 0 (we must have a valid file name).	 */	if (!in_resync && (++*cnt >= NULLCNT))		return(0);	return(1);}/* * ul_oct() *	convert an unsigned long to an octal string. many oddball field *	termination characters are used by the various versions of tar in the *	different fields. term selects which kind to use. str is BLANK padded *	at the front to len. we are unable to use only one format as many old *	tar readers are very cranky about this. * Return: *	0 if the number fit into the string, -1 otherwise */#if __STDC__static intul_oct(u_long val, register char *str, register int len, int term)#elsestatic intul_oct(val, str, len, term)	u_long val;	register char *str;	register int len;	int term;#endif{	register char *pt;		/*	 * term selects the appropriate character(s) for the end of the string	 */	pt = str + len - 1;	switch(term) {	case 3:		*pt-- = '\0';		break;	case 2:		*pt-- = ' ';		*pt-- = '\0';		break;	case 1:		*pt-- = ' ';		break;	case 0:	default:		*pt-- = '\0';		*pt-- = ' ';		break;	}	/*	 * convert and blank pad if there is space	 */	while (pt >= str) {		*pt-- = '0' + (char)(val & 0x7);		if ((val = val >> 3) == (u_long)0)			break;	}	while (pt >= str)		*pt-- = ' ';	if (val != (u_long)0)		return(-1);	return(0);}#ifndef NET2_STAT/* * uqd_oct() *	convert an u_quad_t to an octal string. one of many oddball field *	termination characters are used by the various versions of tar in the *	different fields. term selects which kind to use. str is BLANK padded *	at the front to len. we are unable to use only one format as many old *	tar readers are very cranky about this. * Return: *	0 if the number fit into the string, -1 otherwise */#if __STDC__static intuqd_oct(u_quad_t val, register char *str, register int len, int term)#elsestatic intuqd_oct(val, str, len, term)	u_quad_t val;	register char *str;	register int len;	int term;#endif{	register char *pt;		/*	 * term selects the appropriate character(s) for the end of the string	 */	pt = str + len - 1;	switch(term) {	case 3:		*pt-- = '\0';		break;	case 2:		*pt-- = ' ';		*pt-- = '\0';		break;	case 1:		*pt-- = ' ';		break;	case 0:	default:		*pt-- = '\0';		*pt-- = ' ';		break;	}	/*	 * convert and blank pad if there is space	 */	while (pt >= str) {		*pt-- = '0' + (char)(val & 0x7);		if ((val = val >> 3) == 0)			break;	}	while (pt >= str)		*pt-- = ' ';	if (val != (u_quad_t)0)		return(-1);	return(0);}#endif/* * tar_chksm() *	calculate the checksum for a tar block counting the checksum field as *	all blanks (BLNKSUM is that value pre-calculated, the sume of 8 blanks). *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS *	pad headers with 0. * Return: *	unsigned long checksum */#if __STDC__static u_longtar_chksm(register char *blk, register int len)#elsestatic u_longtar_chksm(blk, len)	register char *blk;	register int len;#endif{	register char *stop;	register char *pt;	u_long chksm = BLNKSUM;	/* inital value is checksum field sum */	/*	 * add the part of the block before the checksum field	 */	pt = blk;	stop = blk + CHK_OFFSET;	while (pt < stop)			chksm += (u_long)(*pt++ & 0xff);		/*	 * move past the checksum field and keep going, spec counts the	 * checksum field as the sum of 8 blanks (which is pre-computed as	 * BLNKSUM).	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding	 * starts, no point in summing zero's)	 */	pt += CHK_LEN;	stop = blk + len;	while (pt < stop)		chksm += (u_long)(*pt++ & 0xff);		return(chksm);}/* * Routines for old BSD style tar (also made portable to sysV tar) *//* * tar_id() *	determine if a block given to us is a valid tar header (and not a USTAR *	header). We have to be on the lookout for those pesky blocks of	all *	zero's. * Return: *	0 if a tar header, -1 otherwise */#if __STDC__inttar_id(register char *blk, int size)#elseinttar_id(blk, size)	register char *blk;	int size;#endif{	register HD_TAR *hd;	register HD_USTAR *uhd;	if (size < BLKMULT)		return(-1);	hd = (HD_TAR *)blk;	uhd = (HD_USTAR *)blk;	/*	 * check for block of zero's first, a simple and fast test, then make	 * sure this is not a ustar header by looking for the ustar magic	 * cookie. We should use TMAGLEN, but some USTAR archive programs are	 * wrong and create archives missing the \0. Last we check the	 * checksum. If this is ok we have to assume it is a valid header.	 */	if (hd->name[0] == '\0')		return(-1);	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)		return(-1);	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))		return(-1);	return(0);}/* * tar_opt() *	handle tar format specific -o options * Return: *	0 if ok -1 otherwise */#if __STDC__inttar_opt(void)#elseinttar_opt()#endif{	OPLIST *opt;	while ((opt = opt_next()) != NULL) {		if (strcmp(opt->name, TAR_OPTION) ||		    strcmp(opt->value, TAR_NODIR)) {			warn(1, "Unknown tar format -o option/value pair %s=%s",			    opt->name, opt->value);			warn(1,"%s=%s is the only supported tar format option",			    TAR_OPTION, TAR_NODIR);			return(-1);		}		/*		 * we only support one option, and only when writing		 */		if ((act != APPND) && (act != ARCHIVE)) {			warn(1, "%s=%s is only supported when writing.",			    opt->name, opt->value);			return(-1);		}		tar_nodir = 1;	}	return(0);}/* * tar_rd() *	extract the values out of block already determined to be a tar header. *	store the values in the ARCHD parameter. * Return: *	0 */#if __STDC__inttar_rd(register ARCHD *arcn, register char *buf)#elseinttar_rd(arcn, buf)	register ARCHD *arcn;	register char *buf;#endif{	register HD_TAR *hd;	register char *pt;	/*	 * we only get proper sized buffers passed to us	 */	if (tar_id(buf, BLKMULT) < 0)		return(-1);	arcn->org_name = arcn->name;	arcn->sb.st_nlink = 1;	arcn->pat = NULL;	/*	 * copy out the name and values in the stat buffer	 */	hd = (HD_TAR *)buf;	arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(hd->name));	arcn->name[arcn->nlen] = '\0';	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &	    0xfff);	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);	arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT);	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;	/*	 * have to look at the last character, it may be a '/' and that is used	 * to encode this as a directory	 */	pt = &(arcn->name[arcn->nlen - 1]);	arcn->pad = 0;	arcn->skip = 0;	switch(hd->linkflag) {	case SYMTYPE:		/*		 * symbolic link, need to get the link name and set the type in		 * the st_mode so -v printing will look correct.		 */		arcn->type = PAX_SLK;		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,			sizeof(hd->linkname));		arcn->ln_name[arcn->ln_nlen] = '\0';		arcn->sb.st_mode |= S_IFLNK;		break;	case LNKTYPE:		/*		 * hard link, need to get the link name, set the type in the		 * st_mode and st_nlink so -v printing will look better.		 */		arcn->type = PAX_HLK;		arcn->sb.st_nlink = 2;		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,			sizeof(hd->linkname));		arcn->ln_name[arcn->ln_nlen] = '\0';		/*		 * no idea of what type this thing really points at, but		 * we set something for printing only.		 */		arcn->sb.st_mode |= S_IFREG;		break;	case AREGTYPE:	case REGTYPE:	default:		/*		 * If we have a trailing / this is a directory and NOT a file.		 */		arcn->ln_name[0] = '\0';		arcn->ln_nlen = 0;		if (*pt == '/') {			/*			 * it is a directory, set the mode for -v printing			 */			arcn->type = PAX_DIR;			arcn->sb.st_mode |= S_IFDIR;			arcn->sb.st_nlink = 2;		} else {			/*			 * have a file that will be followed by data. Set the			 * skip value to the size field and caluculate the size			 * of the padding.			 */			arcn->type = PAX_REG;			arcn->sb.st_mode |= S_IFREG;			arcn->pad = TAR_PAD(arcn->sb.st_size);			arcn->skip = arcn->sb.st_size;		}		break;	}	/*	 * strip off any trailing slash.	 */	if (*pt == '/') {		*pt = '\0'; 		--arcn->nlen;	}	return(0);}/* * tar_wr() *	write a tar header for the file specified in the ARCHD to the archive. *	Have to check for file types that cannot be stored and file names that *	are too long. Be careful of the term (last arg) to ul_oct, each field *	of tar has it own spec for the termination character(s). *	ASSUMED: space after header in header block is zero filled * Return: *	0 if file has data to be written after the header, 1 if file has NO *	data to write after the header, -1 if archive write failed */#if __STDC__inttar_wr(register ARCHD *arcn)#elseinttar_wr(arcn)	register ARCHD *arcn;#endif{	register HD_TAR *hd;	int len;	char hdblk[sizeof(HD_TAR)];	/*	 * check for those file system types which tar cannot store	 */	switch(arcn->type) {	case PAX_DIR:		/*		 * user asked that dirs not be written to the archive		 */		if (tar_nodir)			return(1);		break;	case PAX_CHR:		warn(1, "Tar cannot archive a character device %s",		    arcn->org_name);		return(1);	case PAX_BLK:		warn(1, "Tar cannot archive a block device %s", arcn->org_name);		return(1);	case PAX_SCK:		warn(1, "Tar cannot archive a socket %s", arcn->org_name);		return(1);	case PAX_FIF:		warn(1, "Tar cannot archive a fifo %s", arcn->org_name);		return(1);	case PAX_SLK:	case PAX_HLK:	case PAX_HRG:		if (arcn->ln_nlen > sizeof(hd->linkname)) {			warn(1,"Link name too long for tar %s", arcn->ln_name);			return(1);		}		break;	case PAX_REG:	case PAX_CTG:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -