henesyinit from p9f47575dc5 years agoHistory
924 lines · 17.6 KB · C
RawDownload
/* * ar - portable (ascii) format version */#include <u.h>#include <libc.h>#include <bio.h>#include <ar.h> /* *	The algorithm uses up to 3 temp files.  The "pivot member" is the *	archive member specified by and a, b, or i option.  Temp file astart *	contains existing members up to and including the pivot member.  Temp *	file amiddle contains new files moved or inserted behind the pivot. *	Temp file aend, contains the existing members of the archive that follow *	the pivot member.  When all members have been processed, function *	'install' streams the temp files, in order back into the archive. */ typedef struct	Armember	/* Temp file entry - one per archive member */{	struct Armember	*next;	struct ar_hdr	hdr;	long		size;	long		date;	void		*member;} Armember; typedef	struct Arfile		/* Temp file control block - one per tempfile */{	int	paged;		/*set when some data paged to disk */	char	*fname;		/* paging file name */	int	fd;		/* paging file descriptor */	Armember *head;		/* head of member chain */	Armember *tail;		/* tail of member chain */} Arfile;		/* constants and flags */char	*man =		"mrxtdpq";char	*opt =		"uvnbailo";char	artemp[] =	"/tmp/vXXXXX";char	movtemp[] =	"/tmp/v1XXXXX";char	tailtemp[] =	"/tmp/v2XXXXX"; int	aflag;				/* command line flags */int	bflag;int	cflag;int	dflag;int	iflag;int	lflag;int	mflag;int	nflag;int	oflag;int	pflag;int	qflag;int	rflag;int	tflag;int	uflag;int	vflag;int	xflag; Arfile *astart, *amiddle, *aend;	/* Temp file control block pointers */	#define	ARNAMESIZE	sizeof(astart->tail->hdr.name) char	poname[ARNAMESIZE+1];		/* name of pivot member */char	*file;				/* current file or member being worked on */Biobuf	bout; void	arcopy(int, Arfile*, Armember*);int	arcreate(char*);void	arfree(Arfile*);void	arinsert(Arfile*, Armember*);char	*armalloc(int);void	armove(int, Arfile*, Armember*);void	arread(int, Armember*, int);void	arstream(int, Arfile*);int	arwrite(int, Armember*);int	bamatch(char*, char*);Armember *getdir(int);int	getspace(void);void	install(char*, Arfile*, Arfile*, Arfile*);void	longt(Armember*);int	match(int, char**);void	mesg(int, char*);Arfile	*newtempfile(char*);Armember *newmember(void);int	openar(char*, int, int);int	page(Arfile*);void	pmode(long);void	select(int*, long);void	setcom(void(*)(char*, int, char**));void	skip(int, long);void	trim(char*, char*, int);void	usage(void);void	wrerr(void); void	rcmd(char*, int, char**);		/* command processing */void	dcmd(char*, int, char**);void	xcmd(char*, int, char**);void	tcmd(char*, int, char**);void	pcmd(char*, int, char**);void	mcmd(char*, int, char**);void	qcmd(char*, int, char**);void	(*comfun)(char*, int, char**); voidmain(int argc, char *argv[]){	char *cp; 	Binit(&bout, 1, OWRITE);	if(argc < 3)		usage();	for (cp = argv[1]; *cp; cp++) {		switch(*cp) {		case 'a':	aflag = 1;	break;		case 'b':	bflag = 1;	break;		case 'c':	cflag = 1;	break;		case 'd':	setcom(dcmd);	break;		case 'i':	bflag = 1;	break;		case 'l':				strcpy(artemp, "vXXXXX");				strcpy(movtemp, "v1XXXXX");				strcpy(tailtemp, "v2XXXXX");				break;		case 'm':	setcom(mcmd);	break;		case 'n':	nflag = 1;	break;		case 'o':	oflag = 1;	break;		case 'p':	setcom(pcmd);	break;		case 'q':	setcom(qcmd);	break;		case 'r':	setcom(rcmd);	break;		case 't':	setcom(tcmd);	break;		case 'u':	uflag = 1;	break;		case 'v':	vflag = 1;	break;		case 'x':	setcom(xcmd);	break;		default:			fprint(2, "ar: bad option `%c'\n", *cp);			exits("error");		}	}	if (aflag && bflag) {		fprint(2, "ar: only one of 'a' and 'b' can be specified\n");		usage();	}	if(aflag || bflag) {		trim(argv[2], poname, sizeof(poname));		argv++;		argc--;		if(argc < 3)			usage();	}	if(comfun == 0) {		if(uflag == 0) {			fprint(2, "ar: one of [%s] must be specified\n", man);			usage();		}		setcom(rcmd);	}	cp = argv[2];	argc -= 3;	argv += 3;	(*comfun)(cp, argc, argv);	/* do the command */	cp = 0;	while (argc--) {		if (*argv) {			fprint(2, "ar: %s not found\n", *argv);			cp = "error";		}		argv++;	}	exits(cp);}/* *	select a command */voidsetcom(void (*fun)(char *, int, char**)){ 	if(comfun != 0) {		fprint(2, "ar: only one of [%s] allowed\n", man);		usage();	}	comfun = fun;}/* *	perform the 'r' and 'u' commands */voidrcmd(char *arname, int count, char **files){	int fd, fd2;	int i;	Arfile *ap;	Armember *bp;	Dir d; 	fd = openar(arname, ORDWR, 1);	astart = newtempfile(artemp);	ap = astart;	aend = 0;	while (fd > 0) {		bp = getdir(fd);		if (!bp)			break;		if (bamatch(file, poname)) {		/* check for pivot */			aend = newtempfile(tailtemp);			ap = aend;		}		if (count == 0 || match(count, files)) {			fd2 = open(file, OREAD);			if (fd2 < 0) {				if (count != 0)					fprint(2, "ar: cannot open %s\n", file);				arcopy(fd, ap, bp);			} else if (uflag) {				if (dirfstat(fd2, &d) < 0) {					fprint(2, "ar: cannot stat %s\n", file);					arcopy(fd, ap, bp);				} else if (d.mtime <= bp->date)					arcopy(fd, ap, bp);				else {					mesg('r', file);					skip(fd, bp->size);					armove(fd2, ap, bp);				}				close(fd2);			} else {				mesg('r', file);				skip(fd, bp->size);				armove(fd2, ap, bp);				close(fd2);			}		} else			arcopy(fd, ap, bp);	}	if(fd < 0) {		if(!cflag)			fprint(2, "ar: creating %s\n", arname);	} else		close(fd);		/* copy in remaining files named on command line */	for (i = 0; i < count; i++) {		file = files[i];		if(file == 0)			continue;		files[i] = 0;		fd2 = open(file, OREAD);		if (fd2 < 0)			fprint(2, "ar: %s cannot open\n", file);		else {			mesg('a', file);			armove(fd2, astart, newmember());			close(fd2);		}	}	install(arname, astart, 0, aend);}voiddcmd(char *arname, int count, char **files){	Armember *bp;	int fd;  	if (!count)		return;	fd = openar(arname, ORDWR, 0);	astart = newtempfile(artemp);	while (bp = getdir(fd)) {		if(match(count, files)) {			mesg('d', file);			skip(fd, bp->size);		} else			arcopy(fd, astart, bp);	}	install(arname, astart, 0, 0);} voidxcmd(char *arname, int count, char **files){	int fd, f, mode, i;	Armember *bp;	Dir d; 	fd = openar(arname, OREAD, 0);	i = 0;	while (bp = getdir(fd)) {		if(count == 0 || match(count, files)) {			mode = strtoul(bp->hdr.mode, 0, 8) & 0777;			f = create(file, OWRITE, mode);			if(f < 0) {				fprint(2, "ar: %s cannot create\n", file);				skip(fd, bp->size);			} else {				mesg('x', file);				arcopy(fd, 0, bp);				if (write(f, bp->member, bp->size) < 0)					wrerr();				if(oflag) {					if(dirfstat(f, &d) < 0)						perror(file);					else {						d.atime = bp->date;						d.mtime = bp->date;						if(dirwstat(file, &d) < 0)							perror(file);					}				}				free(bp->member);				close(f);			}			free(bp);			if (count && ++i >= count)				break;		} else {			skip(fd, bp->size);			free(bp);		}	}	close(fd);}voidpcmd(char *arname, int count, char **files){	int fd;	Armember *bp; 	fd = openar(arname, OREAD, 0);	while(bp = getdir(fd)) {		if(count == 0 || match(count, files)) {			if(vflag)				print("\n<%s>\n\n", file);			arcopy(fd, 0, bp);			if (write(1, bp->member, bp->size) < 0)				wrerr();		} else			skip(fd, bp->size);		free(bp);	}	close(fd);}voidmcmd(char *arname, int count, char **files){	int fd;	Arfile *ap;	Armember *bp; 	if (count == 0)		return;	fd = openar(arname, ORDWR, 0);	astart = newtempfile(artemp);	amiddle = newtempfile(movtemp);	aend = 0;	ap = astart;	while(bp = getdir(fd)) {		if (bamatch(file, poname)) {			aend = newtempfile(tailtemp);			ap = aend;		}		if(match(count, files)) {			mesg('m', file);			arcopy(fd, amiddle, bp);		} else			arcopy(fd, ap, bp);	}	close(fd);	if (poname[0] && aend == 0)		fprint(2, "ar: %s not found - files moved to end.\n", poname);	install(arname, astart, amiddle, aend);}voidtcmd(char *arname, int count, char **files){	int fd;	Armember *bp;	char name[ARNAMESIZE+1]; 	fd = openar(arname, OREAD, 0);	while(bp = getdir(fd)) {		if(count == 0 || match(count, files)) {			if(vflag)				longt(bp);			trim(file, name, sizeof(name));			Bprint(&bout, "%s\n", name);		}		skip(fd, bp->size);		free(bp);	}	close(fd);}voidqcmd(char *arname, int count, char **files){	int fd, fd2, i;	Armember *bp; 	if(aflag || bflag) {		fprint(2, "ar: abi not allowed with q\n");		exits("error");	}	fd = openar(arname, ORDWR, 1);	if (fd < 0) {		if(!cflag)			fprint(2, "ar: creating %s\n", arname);		fd = arcreate(arname);	}	/* leave note group behind when writing archive; i.e. sidestep interrupts */	rfork(RFNOTEG);	seek(fd, 0, 2);	bp = newmember();	for(i=0; i<count && files[i]; i++) {		file = files[i];		files[i] = 0;		fd2 = open(file, OREAD);		if(fd2 < 0)			fprint(2, "ar: %s cannot open\n", file);		else {			mesg('q', file);			armove(fd2, 0, bp);			if (!arwrite(fd, bp))				wrerr();			free(bp->member);			bp->member = 0;			close(fd2);		}	}	free(bp);	close(fd);}/* *	open an archive and validate its header */intopenar(char *arname, int mode, int errok){	int fd;	char mbuf[SARMAG]; 	fd = open(arname, mode);	if(fd >= 0){		if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {			fprint(2, "ar: %s not in archive format\n", arname);			exits("error");		}	}else if(!errok){		fprint(2, "ar: cannot open %s: %r\n", arname);		exits("error");	}	return fd;}/* *	create an archive and set its header */intarcreate(char *arname){	int fd; 	fd = create(arname, OWRITE, 0664);	if(fd < 0){		fprint(2, "ar: cannot create %s: %r\n", arname);		exits("error");	}	if(write(fd, ARMAG, SARMAG) != SARMAG)		wrerr();	return fd;}/* *		error handling */voidwrerr(void){	perror("ar: write error");	exits("error");} voidrderr(void){	perror("ar: read error");	exits("error");} voidphaseerr(int offset){	fprint(2, "ar: phase error at offset %d\n", offset);	exits("error");} voidusage(void){	fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man);	exits("error");}/*

Lines 1–500 of 924.