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

📄 rcsedit.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
 * If all goes well, discard any previously acquired locks, * and set frewrite to the FILE* descriptor of the lock file, * which will eventually turn into the new RCS file. */{	register char *tp;	register char const *sp, *RCSname, *x;	RILE *f;	size_t l;	int e, exists, fdesc, previouslock, r;	struct buf *dirt;	struct stat statbuf;	previouslock  =  frewrite != 0;	exists =#		if has_readlink			resolve_symlink(RCSbuf);#		else			    stat(RCSbuf->string, &statbuf) == 0  ?  1			:   errno==ENOENT ? 0 : -1;#		endif	if (exists < (mustread|previouslock))		/*		 * There's an unusual problem with the RCS file;		 * or the RCS file doesn't exist,		 * and we must read or we already have a lock elsewhere.		 */		return 0;	RCSname = RCSbuf->string;	sp = basename(RCSname);	l = sp - RCSname;	dirt = &dirtfname[previouslock];	bufscpy(dirt, RCSname);	tp = dirt->string + l;	x = rcssuffix(RCSname);#	if has_readlink	    if (!x) {		error("symbolic link to non RCS filename `%s'", RCSname);		errno = EINVAL;		return 0;	    }#	endif	if (*sp == *x) {		error("RCS filename `%s' incompatible with suffix `%s'", sp, x);		errno = EINVAL;		return 0;	}	/* Create a lock file whose name is a function of the RCS filename.  */	if (*x) {		/*		 * The suffix is nonempty.		 * The lock filename is the first char of of the suffix,		 * followed by the RCS filename with last char removed.  E.g.:		 *	foo,v	RCS filename with suffix ,v		 *	,foo,	lock filename		 */		*tp++ = *x;		while (*sp)			*tp++ = *sp++;		*--tp = 0;	} else {		/*		 * The suffix is empty.		 * The lock filename is the RCS filename		 * with last char replaced by '_'.		 */		while ((*tp++ = *sp++))			;		tp -= 2;		if (*tp == '_') {			error("RCS filename `%s' ends with `%c'", RCSname, *tp);			errno = EINVAL;			return 0;		}		*tp = '_';	}	sp = tp = dirt->string;	f = 0;	/*	* good news:	*	open(f, O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY) is atomic	*	according to Posix 1003.1-1990.	* bad news:	*	NFS ignores O_EXCL and doesn't comply with Posix 1003.1-1990.	* good news:	*	(O_TRUNC,READONLY) normally guarantees atomicity even with NFS.	* bad news:	*	If you're root, (O_TRUNC,READONLY) doesn't guarantee atomicity.	* good news:	*	Root-over-the-wire NFS access is rare for security reasons.	*	This bug has never been reported in practice with RCS.	* So we don't worry about this bug.	*	* An even rarer NFS bug can occur when clients retry requests.	* Suppose client A renames the lock file ",f," to "f,v"	* at about the same time that client B creates ",f,",	* and suppose A's first rename request is delayed, so A reissues it.	* The sequence of events might be:	*	A sends rename(",f,", "f,v")	*	B sends create(",f,")	*	A sends retry of rename(",f,", "f,v")	*	server receives, does, and acknowledges A's first rename()	*	A receives acknowledgment, and its RCS program exits	*	server receives, does, and acknowledges B's create()	*	server receives, does, and acknowledges A's retry of rename()	* This not only wrongly deletes B's lock, it removes the RCS file!	* Most NFS implementations have idempotency caches that usually prevent	* this scenario, but such caches are finite and can be overrun.	* This problem afflicts programs that use the traditional	* Unix method of using link() and unlink() to get and release locks,	* as well as RCS's method of using open() and rename().	* There is no easy workaround for either link-unlink or open-rename.	* Any new method based on lockf() seemingly would be incompatible with	* the old methods; besides, lockf() is notoriously buggy under NFS.	* Since this problem afflicts scads of Unix programs, but is so rare	* that nobody seems to be worried about it, we won't worry either.	*/#	define READONLY (S_IRUSR|S_IRGRP|S_IROTH)#	if !open_can_creat#		define create(f) creat(f, READONLY)#	else#		define create(f) open(f, O_BINARY|O_CREAT|O_EXCL|O_TRUNC|O_WRONLY, READONLY)#	endif	catchints();	ignoreints();	/*	 * Create a lock file for an RCS file.  This should be atomic, i.e.	 * if two processes try it simultaneously, at most one should succeed.	 */	seteid();	fdesc = create(sp);	e = errno;	setrid();	if (fdesc < 0) {		if (e == EACCES  &&  stat(tp,&statbuf) == 0)			/* The RCS file is busy.  */			e = EEXIST;	} else {		dirtfmaker[0] = effective;		e = ENOENT;		if (exists) {		    f = Iopen(RCSname, FOPEN_R, status);		    e = errno;		    if (f && previouslock) {			/* Discard the previous lock in favor of this one.  */			Ozclose(&frewrite);			seteid();			if ((r = un_link(newRCSfilename)) != 0)			    e = errno;			setrid();			if (r != 0)			    enfaterror(e, newRCSfilename);			bufscpy(&dirtfname[0], tp);		    }		}		if (!(frewrite = fdopen(fdesc, FOPEN_W))) {		    efaterror(newRCSfilename);		}	}	restoreints();	errno = e;	return f;}	voidkeepdirtemp(name)	char const *name;/* Do not unlink name, either because it's not there any more, * or because it has already been unlinked. */{	register int i;	for (i=DIRTEMPNAMES; 0<=--i; )		if (dirtfname[i].string == name) {			dirtfmaker[i] = notmade;			return;		}	faterror("keepdirtemp");}	char const *makedirtemp(name, n)	register char const *name;	int n;/* * Have maketemp() do all the work if name is null. * Otherwise, create a unique filename in name's dir using n and name * and store it into the dirtfname[n]. * Because of storage in tfnames, dirtempunlink() can unlink the file later. * Return a pointer to the filename created. */{	register char *tp, *np;	register size_t dl;	register struct buf *bn;	if (!name)		return maketemp(n);	dl = dirlen(name);	bn = &dirtfname[n];	bufalloc(bn,#		if has_mktemp			dl + 9#		else			strlen(name) + 3#		endif	);	bufscpy(bn, name);	np = tp = bn->string;	tp += dl;	*tp++ = '_';	*tp++ = '0'+n;	catchints();#	if has_mktemp		VOID strcpy(tp, "XXXXXX");		if (!mktemp(np) || !*np)		    faterror("can't make temporary file name `%.*s%c_%cXXXXXX'",			(int)dl, name, SLASH, '0'+n		    );#	else		/*		 * Posix 1003.1-1990 has no reliable way		 * to create a unique file in a named directory.		 * We fudge here.  If the working file name is abcde,		 * the temp filename is _Ncde where N is a digit.		 */		name += dl;		if (*name) name++;		if (*name) name++;		VOID strcpy(tp, name);#	endif	dirtfmaker[n] = real;	return np;}	voiddirtempunlink()/* Clean up makedirtemp() files.  May be invoked by signal handler. */{	register int i;	enum maker m;	for (i = DIRTEMPNAMES;  0 <= --i;  )	    if ((m = dirtfmaker[i]) != notmade) {		if (m == effective)		    seteid();		VOID un_link(dirtfname[i].string);		if (m == effective)		    setrid();		dirtfmaker[i] = notmade;	    }}	int#if has_prototypeschnamemod(FILE **fromp, char const *from, char const *to, mode_t mode)  /* The `#if has_prototypes' is needed because mode_t might promote to int.  */#else  chnamemod(fromp,from,to,mode) FILE **fromp; char const *from,*to; mode_t mode;#endif/* * Rename a file (with optional stream pointer *FROMP) from FROM to TO. * FROM already exists. * Change its mode to MODE, before renaming if possible. * If FROMP, close and clear *FROMP before renaming it. * Unlink TO if it already exists. * Return -1 on error (setting errno), 0 otherwise. */{#	if bad_a_rename		/*		 * This host is brain damaged.  A race condition is possible		 * while the lock file is temporarily writable.		 * There doesn't seem to be a workaround.		 */		mode_t mode_while_renaming = mode|S_IWUSR;#	else#		define mode_while_renaming mode#	endif	if (fromp) {#		if has_fchmod			if (fchmod(fileno(*fromp), mode_while_renaming) != 0)				return -1;#		endif		Ozclose(fromp);	}#	if has_fchmod	    else#	endif	    if (chmod(from, mode_while_renaming) != 0)		return -1;#	if !has_rename || bad_b_rename		VOID un_link(to);		/*		 * We need not check the result;		 * link() or rename() will catch it.		 * No harm is done if TO does not exist.		 * However, there's a short window of inconsistency		 * during which TO does not exist.		 */#	endif	return#	    if !has_rename		do_link(from,to) != 0  ?  -1  :  un_link(from)#	    else		    rename(from, to) != 0#		    if has_NFS			&& errno != ENOENT#		    endif		?  -1#		if bad_a_rename		:  mode != mode_while_renaming  ?  chmod(to, mode)#		endif		:  0#	    endif	;#	undef mode_while_renaming}	intfindlock(delete, target)	int delete;	struct hshentry **target;/* * Find the first lock held by caller and return a pointer * to the locked delta; also removes the lock if DELETE. * If one lock, put it into *TARGET. * Return 0 for no locks, 1 for one, 2 for two or more. */{	register struct lock *next, **trail, **found;	found = 0;	for (trail = &Locks;  (next = *trail);  trail = &next->nextlock)		if (strcmp(getcaller(), next->login)  ==  0) {			if (found) {				error("multiple revisions locked by %s; please specify one", getcaller());				return 2;			}			found = trail;		}	if (!found)		return 0;	next = *found;	*target = next->delta;	if (delete) {		next->delta->lockedby = nil;		*found = next->nextlock;	}	return 1;}	intaddlock(delta)	struct hshentry * delta;/* * Add a lock held by caller to DELTA and yield 1 if successful. * Print an error message and yield -1 if no lock is added because * DELTA is locked by somebody other than caller. * Return 0 if the caller already holds the lock. */{	register struct lock *next;	next=Locks;	for (next = Locks;  next;  next = next->nextlock)		if (cmpnum(delta->num, next->delta->num) == 0)			if (strcmp(getcaller(), next->login) == 0)				return 0;			else {				error("revision %s already locked by %s",				      delta->num, next->login				);				return -1;			}	next = ftalloc(struct lock);	delta->lockedby = next->login = getcaller();	next->delta = delta;	next->nextlock = Locks;	Locks = next;	return 1;}	intaddsymbol(num, name, rebind)	char const *num, *name;	int rebind;/* * Associate with revision NUM the new symbolic NAME. * If NAME already exists and REBIND is set, associate NAME with NUM; * otherwise, print an error message and return false; * Return true if successful. */{	register struct assoc *next;	for (next = Symbols;  next;  next = next->nextassoc)		if (strcmp(name, next->symbol)  ==  0)			if (rebind  ||  strcmp(next->num,num) == 0) {				next->num = num;				return true;			} else {				error("symbolic name %s already bound to %s",					name, next->num				);				return false;			}	next = ftalloc(struct assoc);	next->symbol = name;	next->num = num;	next->nextassoc = Symbols;	Symbols = next;	return true;}	char const *getcaller()/* Get the caller's login name.  */{#	if has_setuid		return getusername(euid()!=ruid());#	else		return getusername(false);#	endif}	intcheckaccesslist()/* * Return true if caller is the superuser, the owner of the * file, the access list is empty, or caller is on the access list. * Otherwise, print an error message and return false. */{	register struct access const *next;	if (!AccessList || myself(RCSstat.st_uid) || strcmp(getcaller(),"root")==0)		return true;	next = AccessList;	do {		if (strcmp(getcaller(), next->login)  ==  0)			return true;	} while ((next = next->nextaccess));	error("user %s not on the access list", getcaller());	return false;}	intdorewrite(lockflag, changed)	int lockflag, changed;/* * Do nothing if LOCKFLAG is zero. * Prepare to rewrite an RCS file if CHANGED is positive. * Stop rewriting if CHANGED is zero, because there won't be any changes. * Fail if CHANGED is negative. * Return true on success. */{	int r, e;	if (lockflag)		if (changed) {			if (changed < 0)				return false;			putadmin(frewrite);			puttree(Head, frewrite);			aprintf(frewrite, "\n\n%s%c", Kdesc, nextc);			foutptr = frewrite;		} else {			Ozclose(&frewrite);			seteid();			ignoreints();			r = un_link(newRCSfilename);			e = errno;			keepdirtemp(newRCSfilename);			restoreints();			setrid();			if (r != 0) {				enerror(e, RCSfilename);				return false;			}		}	return true;}	intdonerewrite(changed)	int changed;/* * Finish rewriting an RCS file if CHANGED is nonzero. * Return true on success. */{	int r, e;	if (changed && !nerror) {		if (finptr) {			fastcopy(finptr, frewrite);			Izclose(&finptr);		}		if (1 < RCSstat.st_nlink)			warn("breaking hard link to %s", RCSfilename);		seteid();		ignoreints();		r = chnamemod(&frewrite, newRCSfilename, RCSfilename,			RCSstat.st_mode & ~(S_IWUSR|S_IWGRP|S_IWOTH)		);		e = errno;		keepdirtemp(newRCSfilename);		restoreints();		setrid();		if (r != 0) {			enerror(e, RCSfilename);			error("saved in %s", newRCSfilename);			dirtempunlink();			return false;		}	}	return true;}	voidaflush(f)	FILE *f;{	if (fflush(f) != 0)		Oerror();}

⌨️ 快捷键说明

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