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

📄 tarsets.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
字号:
/*	tarsets.c - *		write media image production scripts. * * *			Copyright (c) 1985, 1988 by *		Digital Equipment Corporation, Maynard, MA *			All rights reserved. *								 *	This software is furnished under a license and may be used and *	copied  only  in accordance with the terms of such license and *	with the  inclusion  of  the  above  copyright  notice.   This *	software  or  any  other copies thereof may not be provided or *	otherwise made available to any other person.  No title to and *	ownership of the software is hereby transferred.		 *								 *	The information in this software is subject to change  without *	notice  and should not be construed as a commitment by Digital *	Equipment Corporation.					 *								 *	Digital assumes no responsibility for the use  or  reliability *	of its software on equipment which is not supplied by Digital. **//************************************************************************ * *	Modification History: * *	000	afd	1984 *	001	ccb	1-JUN-1988 *		Re-Implemented to clean up several structural problems *		that made for difficult maintenance. *		No functional change. * *************************************************************************/#ifndef lintstatic	char *sccsid = "@(#)tarsets.c	4.1	(ULTRIX)	7/2/90";#endif lint#include <sys/param.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/errno.h>#include <stdio.h>/*	externs - *		errno - standard *		sys_errlist - standard*/extern	errno;extern	*sys_errlist[];/*	constants - * *	BLKSIZ - size of a tar block. *	DIR - inventory char for IFDIR files *	FACLEN - maximum size of subset names *	HLINK - inventory char for hard links *	I_OVERSIZED - inventory flags file oversized flag. *	I_USED - inventory flags node used mask *	PCKSIZ - number of BLKSIZ blocks that fit a package *	PERFILECHRS - number of chars/file overhead in script. *	REG - inventory char for IFREG files *	SLINK - inventory char for IFLNK files *	TARPAD - tar overhead per file *	TARSIZ - tar blocking factor for tar's -b switch *	TOP - constant value at top recursion level *	TS_DIRTY - Volume in use mask *	TS_OVERSIZED - Oversized volume encountered mask *	TS_VOLREADY - Volume ready mask*/#define	BLKSIZ		512#define	DIR		'd'#define	FACLEN		16#define	HLINK		'l'#define	I_OVERSIZED	0x0002#define	I_USED		0x0001#define	PCKSIZ		350#define	PERFILECHRS	4#define	REG		'f'#define	SLINK		's'#define	TARPAD		1#define	TARSIZ		20#define	TOP		0#define	TS_DIRTY	0x0001#define	TS_OVERSIZED	0x0002#define	TS_VOLREADY	0x0004/*	macros - * *	BYTOBL - *		args: a number of bytes *		does: xlate file bytes to size of file in tar image * *	ISOPEN - *		args: a volume descriptor *		does: resolves to true if TS_VOLREADY is set * *	USAGE - *		args: none *		does: generate a usage message*/#define	BYTOBL(S)	( ( (S) + BLKSIZ ) / BLKSIZ + TARPAD)#define	ISOPEN(V)	( (V)->v_flags & TS_VOLREADY )#define	Usage()		fprintf(stderr,"%s: Usage: %s master-dir\n",prog, prog);#define	reg		register/*	TYPEDEFS*/typedef struct INV	/* record for list of distribution files */{	struct INV	*i_next;		/* link to next file record */	char		i_path[MAXPATHLEN];	/* file name */	struct INV	*i_hpl;			/* ptr to hard links */	int		i_flags;		/* node flags */	unsigned	i_chrs;			/* size of the file name */	unsigned	i_blks;			/* # blocks in file */	unsigned	i_tchrs;		/* # chrs for inode */	unsigned	i_tblks;		/* # blocks for inode */} INV;typedef struct vip	/* Volume Info Pack */{	unsigned	v_num;		/* volume number */	unsigned	v_chrs;		/* number of chars written to file */	unsigned	v_blks;		/* number of disk blocks allocated */	unsigned	v_flags;	/* flags word */} VIP;/*	SUBR TYPE DEFINITIONS*/char	*emalloc();		/* error checking malloc */INV	*ReadInput();		/* Found Below *//*	GLOBAL DATA*/char		buf[BUFSIZ];		/* scratch buffer */char		subset[FACLEN];		/* global storage for subset name */char		*prog;			/* global prog name for err strings */char		mntpath[MAXPATHLEN];	/* mount path of build */struct stat	stb;			/* global stat buffer */int		debug = 0;		/* debug flag, default 0 */FILE		*dbfp;			/* debug output FILE pointer */char		*debugfile = "ts.dbg";	/* debug output file name *//*	Main() - *		main type stuff * *	args:	standard *	does:	parse command line. *		enable debugging if required and it's possible *		freopen stdout to an error file. *		call ReadInput() to internalize INV records comming *			on stdin *		call WriteScript() to handle backpacking *		call OverSized() to handle records bigger than a *			breadbox *		call TsEndVol() to close out any trailing records. *		exit. *	return:	0 on success, 1 on failure. *	fails:	on bad calling syntax, prints usage message.*/main (argc,argv)int argc;char *argv[];{	INV	*DataList;	/* main list */	VIP	v;		/* Vol Descriptor */	prog = argv[0];	/* save program name */	/* decode args */	switch( argc )	{	case 3:		/* perhaps debug */		if( strcmp("-d", argv[1] ) )			goto error;		++debug;		++argv;	case 2:		/* no debug */		if( !debug && !strcmp(argv[1], "-d") )			goto error;		strcpy(mntpath,argv[1]);		break;	default:	error:		Usage();		exit(1);	}	if( debug )	/* open debug output file */	{		if( (dbfp = fopen(debugfile, "w")) != NULL )			fprintf(stderr, "Debugging On, file %s\n", debugfile);		else		{			/* can't open debug file.			 *  print warning and turn off debugging.			*/			fprintf(stderr,				"%s: Unable to open %s (%s)\nDebug Off.\n",				prog, debugfile, sys_errlist[errno] );			debug = 0;		}	}	/* bind stderr to an error file	*/	fprintf(stderr, "Stderr is redirected to diagnostics file `stderr'\n");	freopen("stderr", "a", stderr);	bzero( (char *) &v, sizeof(VIP) );	DataList = ReadInput();	WriteScript(DataList, &v, TOP);	OverSized(DataList, &v);	TsEndVol(&v);	exit(0);}/*	ReadInput() - *		build internal representation of the inventory *		being fed thru stdin. * *	args:	none *	does:	reads records from stdin. each record representing *		a file or link is scribbled into an INV structure and *		placed in a linked list. *	return:	a pointer to the head of the list.*/INV *ReadInput(){	reg INV	*p;	/* pointer to main list */	reg INV	*q;	/* pointer to working record */	char	linkto[MAXPATHLEN];	/* linkto name, current record */	off_t	size;			/* file size, current record */	char	type;			/* file type, current record */	int	lncnt;			/* input line counter */	for( p = q = (INV *) 0, lncnt = 1; gets(buf) != NULL; ++lncnt )	{		if(!q)		{			/* time to get a new node */			q = (INV *) emalloc(sizeof(INV));			bzero( (char *) q, sizeof(INV) );		}		if( sscanf(buf,"%*s%d%*d%*hd%*hd%*ho%*s%*s%1s%s%s%s",			&size, &type, q->i_path, linkto, subset ) != 5 )		{			fprintf(stderr,				"%s: Invalid Record on line %d: %s",				lncnt, buf );		}		/* DIR == directory */		if( type == DIR )			continue;		q->i_chrs = strlen(q->i_path) + PERFILECHRS;		if( type == HLINK && strcmp(linkto, "none") )		{			/* Hard Link, not first instance of this			 *  inode encountered. Set up it's INV			 *  and call to have it linked into the			 *  the list under it's inode-group.			*/			q->i_blks = TARPAD;			AddHardLink(q,p,linkto);		}		else		{			/* real file, fill node and link */			q->i_tchrs = q->i_chrs;			q->i_blks = q->i_tblks = BYTOBL(size);			q->i_next = p;			p = q;		}		q = NULL;	}	return(p);}/*	AddHardLink() - *		add hard link node to list * *	given:	pointer to unreferenced node. *		pointer to top node. *		pointer to linkto string. *	does:	associate the node with it's inode group. *		update inode lead blk, chr counters *	return:	Pointer to the parent of the inode group.*/AddHardLink(n,l,s)reg INV *n, *l;reg char *s;{	/* find node in l to which n should be linked */	for(; l != (INV *) 0; l = l->i_next)	{		if(!strcmp(l->i_path, s))		{			/* got it, link into inode group... */			n->i_hpl = l->i_hpl;			l->i_hpl = n;			/* ... and update parent counters */			l->i_tchrs += n->i_chrs;			l->i_tblks += n->i_blks;			return;		}	}	fprintf(stderr, "%s: %s -> %s link reference unresolved.\n",		prog, n->i_path, s);	exit(1);}/*	WriteScript() - *		write the output script. * *	given:	a pointer to the current head of the inv list. *		pointer to a volume descriptor. *	does:	arbitrates the output of tar commands such that no *		command would overflow a single diskette. *		and so that no command line in the resulting script *		exceeds NCARGS *	return:	no explicit return value. * *	NOTE:	recursion.*/WriteScript(p,v,level)reg INV *p;VIP *v;int level;{	if( debug )	{		fprintf(dbfp,			"%s: Entering WriteScript(%8x,%8x,%d)\n",			prog, p, v, level);	}	while( p != (INV *) 0 )	/* Loop to end of linked list */	{		if( debug )		{			 fprintf(dbfp, "%s: Node %s\n", prog, p->i_path);		}		if( p->i_flags & I_USED )		{			if( debug )			{				fprintf(dbfp,"%s: In Use Node %s\n",					prog, p->i_path);			}			/* this node already assigned to a volume */			p = p->i_next;			continue;		}		if( p->i_tblks > PCKSIZ )		{			/* oversized file.			 *  print error message, set oversized flag			 *  on the volume descriptor, go on to next volume.			*/			fprintf(stderr, "Warning: file %s is %d blocks",				p->i_path, p->i_tblks);			fprintf(stderr, "\ttoo large for diskette\n\n");			if( debug )			{				fprintf(dbfp, "%s: Oversized Node %s\n",					prog, p->i_path);			}			v->v_flags |= TS_OVERSIZED;			p->i_flags |= (I_OVERSIZED|I_USED);			p = p->i_next;			continue;		}		/* Determine if current file fits 		 *  in current volume, check is made against		 *  the file and all of it's hard link overhead		 *  as well as the number of characters that		 *  will be required to print it		*/		if( (v->v_blks + p->i_tblks) > PCKSIZ ||			(v->v_chrs + p->i_tchrs) >= NCARGS )		{			/* It doesn't. Recur to pick one that			 *  fits.			*/			if( debug )			{				fprintf(dbfp,					"%s: Node doesn't fit, will recur\n",					prog );			}			WriteScript( p->i_next, v, level+1 );			/* Return from recursion:			 *  if level is !0, pop.			*/			if( level )			{				if( debug )				{					fprintf(dbfp,						"%s: return level %d\n",						prog, level);				}				return(0);			}			/* Level 0 return:			 *  Volume assumed full to capacity, close.			*/			TsEndVol(v);		}		else		{			/* file fits, Write it. */			if( debug )			{				fprintf(dbfp, "%s: Node fit, volume %d\n",					prog, v->v_num);			}			Output(p,v);			p = p->i_next;		}	}	if( debug )	{		fprintf(dbfp,"%s: return level %d\n", prog, level);	}}/*	OverSized() - *		write diskette records that are bigger than a *		single diskette. * *	args:	pointer to a list of INVs. *		pointer to the current volume structure. * *	does:	Create single volume for all files larger than one diskette. * *	return:	Nothing*/OverSized(p,v)INV *p;register VIP *v;{	if( v->v_flags & TS_OVERSIZED )	{		if( v->v_flags & (TS_VOLREADY|TS_DIRTY) )			TsNewVol(v);		fprintf(stderr, "Writing Oversized File Volume...\n");		for( ;p != (INV *) 0; p = p->i_next)		{			if( p->i_flags & I_OVERSIZED )				Output(p,v);		}	}}/*	Output() - *		print pathname from node. * *	given:	pointer to a node. *		pointer to a volume info pack *	does:	print a line for the script containing line *		line continuation and the node->path. *		track down all hard links to this node and *		do likewise for them. track tar padding *		for the hard link records. *	return:	number of blocks consumed by files and links for which *		output records were created.*/Output(p, v)reg INV *p;reg VIP *v;{	if( debug )	{		fprintf( dbfp, "%s: Entering Output()\n", prog);	}	if( !(v->v_flags & TS_VOLREADY) )		TsNewVol(v);	/* add all blocks and chars for this file into	 *  the volume descriptor	*/	v->v_blks += p->i_tblks;	v->v_chrs += p->i_tchrs;	/* mark to volume as DIRTY	*/	v->v_flags |= TS_DIRTY;	/* print the parent path and mark as used.	*/	printf( " \\\n'%s'", p->i_path );	p->i_flags |= I_USED;	/* loop thru and print paths for each member of	 *  the inode group	*/	for(p = p->i_hpl; p != (INV *) 0; p = p->i_hpl)		printf( " \\\n'%s'", p->i_path);	if( debug )	{		fprintf( dbfp, "%s: Output() returning\n", prog );	}}/*	TsNewVol() - *		start new volume. * *	args:	a pointer to a volume descriptor. *	does:	closes any pending open volume. *		writes tar command header. *		resets blocks and character count. *		arranges for volume file to be output.*/TsNewVol(v)reg VIP *v;{	static char	volbuf[10];	static char	*cmdfmt = "tar cpobf %d ${TO}/%s%d \\\n%s\\\n -C %s";	TsEndVol(v);	/* close open volume */	++(v->v_num);	/* increment volnum */	/* calulate block requirement for Volume file,	 *  placed in volume when the volume record is	 *  first opened	*/	sprintf(volbuf,"Volume%d",v->v_num);	stat(volbuf,&stb);	v->v_blks = (stb.st_size + BLKSIZ ) / BLKSIZ + TARPAD;	/* write beginning of tar command */	sprintf( buf, cmdfmt, TARSIZ, subset, v->v_num, volbuf, mntpath);	fputs( buf, stdout );	/* account for chars just written + trailing newline	 *  needed in TsEndVol()	*/	v->v_chrs = strlen(buf) + 1;	/* mark volume ready */	v->v_flags |= TS_VOLREADY;}/*	TsEndVol() - *		close out a volume segment on the output script. * *	Given:	a pointer to a volume descriptor *	Does:	Verifies that there the volume record is writable. *		Writes block sizes for volume to stderr. *		Writes a newline to the output, clears TS_VOLREADY *			in the descriptor flags. *	Return:	Unused*/TsEndVol(v)reg VIP *v;{	if( debug )	{		fprintf(dbfp, "%s: TsEndVol()\n", prog);	}	if( v->v_flags & TS_VOLREADY )	{		/* write status record to stderr		*/		fprintf(stderr, "%d Blocks, %d Chars on Volume %s%d\n",			v->v_blks, v->v_chrs, subset, v->v_num);		fputs("\n", stdout);		v->v_flags &= ~TS_VOLREADY;		v->v_blks = v->v_chrs = 0;	}}

⌨️ 快捷键说明

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