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

📄 tar.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	default:		break;	}	/*	 * check file name len, remember extra char for dirs (the / at the end)	 */	len = arcn->nlen;	if (arcn->type == PAX_DIR)		++len;	if (len > sizeof(hd->name)) {		warn(1, "File name too long for tar %s", arcn->name);		return(1);	}	/*	 * copy the data out of the ARCHD into the tar header based on the type	 * of the file. Remember many tar readers want the unused fields to be	 * padded with zero. We set the linkflag field (type), the linkname	 * (or zero if not used),the size, and set the padding (if any) to be	 * added after the file data (0 for all other types, as they only have	 * a header)	 */	hd = (HD_TAR *)hdblk;	zf_strncpy(hd->name, arcn->name, sizeof(hd->name));	arcn->pad = 0;	if (arcn->type == PAX_DIR) {		/*		 * directories are the same as files, except have a filename		 * that ends with a /, we add the slash here. No data follows,		 * dirs, so no pad.		 */		hd->linkflag = AREGTYPE;		bzero(hd->linkname, sizeof(hd->linkname));		hd->name[len-1] = '/';		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))			goto out;	} else if (arcn->type == PAX_SLK) {		/*		 * no data follows this file, so no pad		 */		hd->linkflag = SYMTYPE;		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))			goto out;	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {		/*		 * no data follows this file, so no pad		 */		hd->linkflag = LNKTYPE;		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))			goto out;	} else {		/*		 * data follows this file, so set the pad		 */		hd->linkflag = AREGTYPE;		bzero(hd->linkname, sizeof(hd->linkname));#		ifdef NET2_STAT		if (ul_oct((u_long)arcn->sb.st_size, hd->size,		    sizeof(hd->size), 1)) {#		else		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,		    sizeof(hd->size), 1)) {#		endif			warn(1,"File is too large for tar %s", arcn->org_name);			return(1);		}		arcn->pad = TAR_PAD(arcn->sb.st_size);	}	/*	 * copy those fields that are independent of the type	 */	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))		goto out;	/*	 * calculate and add the checksum, then write the header. A return of	 * 0 tells the caller to now write the file data, 1 says no data needs	 * to be written	 */	if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,	    sizeof(hd->chksum), 2))		goto out;	if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0)		return(-1);	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)		return(-1);	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))		return(0);	return(1);    out:	/*	 * header field is out of range	 */	warn(1, "Tar header field is too small for %s", arcn->org_name);	return(1);}/* * Routines for POSIX ustar *//* * ustar_strd() *	initialization for ustar read * Return: *	0 if ok, -1 otherwise */#if __STDC__intustar_strd(void)#elseintustar_strd()#endif{	if ((usrtb_start() < 0) || (grptb_start() < 0))		return(-1);	return(0);}/* * ustar_stwr() *	initialization for ustar write * Return: *	0 if ok, -1 otherwise */#if __STDC__intustar_stwr(void)#elseintustar_stwr()#endif{	if ((uidtb_start() < 0) || (gidtb_start() < 0))		return(-1);	return(0);}/* * ustar_id() *	determine if a block given to us is a valid ustar header. We have to *	be on the lookout for those pesky blocks of all zero's * Return: *	0 if a ustar header, -1 otherwise */#if __STDC__intustar_id(char *blk, int size)#elseintustar_id(blk, size)	char *blk;	int size;#endif{	register HD_USTAR *hd;	if (size < BLKMULT)		return(-1);	hd = (HD_USTAR *)blk;	/*	 * check for block of zero's first, a simple and fast test then check	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive	 * programs are fouled up and create archives missing the \0. Last we	 * check the checksum. If ok we have to assume it is a valid header.	 */	if (hd->name[0] == '\0')		return(-1);	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)		return(-1);	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))		return(-1);	return(0);}/* * ustar_rd() *	extract the values out of block already determined to be a ustar header. *	store the values in the ARCHD parameter. * Return: *	0 */#if __STDC__intustar_rd(register ARCHD *arcn, register char *buf)#elseintustar_rd(arcn, buf)	register ARCHD *arcn;	register char *buf;#endif{	register HD_USTAR *hd;	register char *dest;	register int cnt = 0;	dev_t devmajor;	dev_t devminor;	/*	 * we only get proper sized buffers	 */	if (ustar_id(buf, BLKMULT) < 0)		return(-1);	arcn->org_name = arcn->name;	arcn->sb.st_nlink = 1;	arcn->pat = NULL;	hd = (HD_USTAR *)buf;	/*	 * see if the filename is split into two parts. if, so joint the parts.	 * we copy the prefix first and add a / between the prefix and name.	 */	dest = arcn->name;	if (*(hd->prefix) != '\0') {		cnt = l_strncpy(arcn->name, hd->prefix, sizeof(hd->prefix));		dest = arcn->name + arcn->nlen;		*dest++ = '/';	}	arcn->nlen = l_strncpy(dest, hd->name, sizeof(hd->name));	arcn->nlen += cnt;	arcn->name[arcn->nlen] = '\0';	/*	 * follow the spec to the letter. we should only have mode bits, strip	 * off all other crud we may be passed.	 */	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &	    0xfff);	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;	/*	 * If we can find the ascii names for gname and uname in the password	 * and group files we will use the uid's and gid they bind. Otherwise	 * we use the uid and gid values stored in the header. (This is what	 * the posix spec wants).	 */	hd->gname[sizeof(hd->gname) - 1] = '\0';	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);	hd->uname[sizeof(hd->uname) - 1] = '\0';	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);	/*	 * set the defaults, these may be changed depending on the file type	 */	arcn->ln_name[0] = '\0';	arcn->ln_nlen = 0;	arcn->pad = 0;	arcn->skip = 0;	arcn->sb.st_rdev = (dev_t)0;	/*	 * set the mode and PAX type according to the typeflag in the header	 */	switch(hd->typeflag) {	case FIFOTYPE:		arcn->type = PAX_FIF;		arcn->sb.st_mode |= S_IFIFO;		break;	case DIRTYPE:		arcn->type = PAX_DIR;		arcn->sb.st_mode |= S_IFDIR;		arcn->sb.st_nlink = 2;		/*		 * Some programs that create ustar archives append a '/'		 * to the pathname for directories. This clearly violates		 * ustar specs, but we will silently strip it off anyway.		 */		if (arcn->name[arcn->nlen - 1] == '/')			arcn->name[--arcn->nlen] = '\0';		break;	case BLKTYPE:	case CHRTYPE:		/*		 * this type requires the rdev field to be set.		 */		if (hd->typeflag == BLKTYPE) {			arcn->type = PAX_BLK;			arcn->sb.st_mode |= S_IFBLK;		} else {			arcn->type = PAX_CHR;			arcn->sb.st_mode |= S_IFCHR;		}		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);		arcn->sb.st_rdev = TODEV(devmajor, devminor);		break;	case SYMTYPE:	case LNKTYPE:		if (hd->typeflag == SYMTYPE) {			arcn->type = PAX_SLK;			arcn->sb.st_mode |= S_IFLNK;		} else {			arcn->type = PAX_HLK;			/*			 * so printing looks better			 */			arcn->sb.st_mode |= S_IFREG;			arcn->sb.st_nlink = 2;		}		/*		 * copy the link name		 */		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,			sizeof(hd->linkname));		arcn->ln_name[arcn->ln_nlen] = '\0';		break;	case CONTTYPE:	case AREGTYPE:	case REGTYPE:	default:		/*		 * these types have file data that follows. Set the skip and		 * pad fields.		 */		arcn->type = PAX_REG;		arcn->pad = TAR_PAD(arcn->sb.st_size);		arcn->skip = arcn->sb.st_size;		arcn->sb.st_mode |= S_IFREG;		break;	}	return(0);}/* * ustar_wr() *	write a ustar 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, we only use *	'\0' for the termination character (this is different than picky tar) *	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__intustar_wr(register ARCHD *arcn)#elseintustar_wr(arcn)	register ARCHD *arcn;#endif{	register HD_USTAR *hd;	register char *pt;	char hdblk[sizeof(HD_USTAR)];	/*	 * check for those file system types ustar cannot store	 */	if (arcn->type == PAX_SCK) {		warn(1, "Ustar cannot archive a socket %s", arcn->org_name);		return(1);	}	/*	 * check the length of the linkname	 */	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||	    (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){		warn(1, "Link name too long for ustar %s", arcn->ln_name);		return(1);	}	/*	 * split the path name into prefix and name fields (if needed). if	 * pt != arcn->name, the name has to be split	 */	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {		warn(1, "File name too long for ustar %s", arcn->name);		return(1);	}	hd = (HD_USTAR *)hdblk;	arcn->pad = 0L;	/*	 * split the name, or zero out the prefix	 */	if (pt != arcn->name) {		/*		 * name was split, pt points at the / where the split is to		 * occur, we remove the / and copy the first part to the prefix		 */		*pt = '\0';		zf_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));		*pt++ = '/';	} else		bzero(hd->prefix, sizeof(hd->prefix));	/*	 * copy the name part. this may be the whole path or the part after	 * the prefix	 */	zf_strncpy(hd->name, pt, sizeof(hd->name));	/* 	 * set the fields in the header that are type dependent	 */	switch(arcn->type) {	case PAX_DIR:		hd->typeflag = DIRTYPE;		bzero(hd->linkname, sizeof(hd->linkname));		bzero(hd->devmajor, sizeof(hd->devmajor));		bzero(hd->devminor, sizeof(hd->devminor));		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))			goto out;		break;	case PAX_CHR:	case PAX_BLK:		if (arcn->type == PAX_CHR)			hd->typeflag = CHRTYPE;		else			hd->typeflag = BLKTYPE;		bzero(hd->linkname, sizeof(hd->linkname));		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,		   sizeof(hd->devmajor), 3) ||		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,		   sizeof(hd->devminor), 3) ||		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))			goto out;		break;	case PAX_FIF:		hd->typeflag = FIFOTYPE;		bzero(hd->linkname, sizeof(hd->linkname));		bzero(hd->devmajor, sizeof(hd->devmajor));		bzero(hd->devminor, sizeof(hd->devminor));		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))			goto out;		break;	case PAX_SLK:	case PAX_HLK:	case PAX_HRG:		if (arcn->type == PAX_SLK)			hd->typeflag = SYMTYPE;		else			hd->typeflag = LNKTYPE;		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));		bzero(hd->devmajor, sizeof(hd->devmajor));		bzero(hd->devminor, sizeof(hd->devminor));		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))			goto out;		break;	case PAX_REG:	case PAX_CTG:	default:		/*		 * file data with this type, set the padding		 */		if (arcn->type == PAX_CTG)			hd->typeflag = CONTTYPE;		else			hd->typeflag = REGTYPE;		bzero(hd->linkname, sizeof(hd->linkname));		bzero(hd->devmajor, sizeof(hd->devmajor));		bzero(hd->devminor, sizeof(hd->devminor));		arcn->pad = TAR_PAD(arcn->sb.st_size);#		ifdef NET2_STAT		if (ul_oct((u_long)arcn->sb.st_size, hd->size,		    sizeof(hd->size), 3)) {#		else		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,		    sizeof(hd->size), 3)) {#		endif			warn(1,"File is too long for ustar %s",arcn->org_name);			return(1);		}		break;	}	zf_strncpy(hd->magic, TMAGIC, TMAGLEN);	zf_strncpy(hd->version, TVERSION, TVERSLEN);	/*	 * set the remaining fields. Some versions want all 16 bits of mode	 * we better humor them (they really do not meet spec though)....	 */	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))		goto out;	zf_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));	zf_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));	/*	 * calculate and store the checksum write the header to the archive	 * return 0 tells the caller to now write the file data, 1 says no data	 * needs to be written	 */	if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,	   sizeof(hd->chksum), 3))		goto out;	if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)		return(-1);	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)		return(-1);	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))		return(0);	return(1);    out:    	/*	 * header field is out of range	 */	warn(1, "Ustar header field is too small for %s", arcn->org_name);	return(1);}/* * name_split() *	see if the name has to be split for storage in a ustar header. We try *	to fit the entire name in the name field without splitting if we can. *	The split point is always at a / * Return *	character pointer to split point (always the / that is to be removed *	if the split is not needed, the points is set to the start of the file *	name (it would violate the spec to split there). A NULL is returned if *	the file name is too long */#if __STDC__static char *name_split(register char *name, register int len)#elsestatic char *name_split(name, len)	register char *name;	register int len;#endif{	register char *start;	/*	 * check to see if the file name is small enough to fit in the name	 * field. if so just return a pointer to the name.	 */	if (len <= TNMSZ)		return(name);	if (len > (TPFSZ + TNMSZ + 1))		return(NULL);	/*	 * we start looking at the biggest sized piece that fits in the name	 * field. We walk foward looking for a slash to split at. The idea is	 * to find the biggest piece to fit in the name field (or the smallest	 * prefix we can find) (the -1 is correct the biggest piece would	 * include the slash between the two parts that gets thrown away)	 */	start = name + len - TNMSZ - 1;	while ((*start != '\0') && (*start != '/'))		++start;	/*	 * if we hit the end of the string, this name cannot be split, so we	 * cannot store this file.	 */	if (*start == '\0')		return(NULL);	len = start - name;	/*	 * NOTE: /str where the length of str == TNMSZ can not be stored under	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and	 * the file would then expand on extract to //str. The len == 0 below	 * makes this special case follow the spec to the letter.	 */	if ((len > TPFSZ) || (len == 0))		return(NULL);	/*	 * ok have a split point, return it to the caller	 */	return(start);}

⌨️ 快捷键说明

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