prot_share.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 524 行

C
524
字号
# ifndef lintstatic char *sccsid = "@(#)prot_share.c	4.1	(ULTRIX)	7/2/90";# endif not lint/**************************************************************** *								* *  Licensed to Digital Equipment Corporation, Maynard, MA	* *		Copyright 1985 Sun Microsystems, Inc.		* *			All rights reserved.			* *								* ****************************************************************//**//* *	Modification history: *	~~~~~~~~~~~~~~~~~~~~ * *	revision			comments *	--------	----------------------------------------------- * *	01-Jun-89	Fred Glover *			New from nfssrc 4.0 * *	 *//* * prot_share.c consists of subroutines that implement the * DOS-compatible file sharing services for PC-NFS */#include <stdio.h>#include <sys/file.h>#include "prot_lock.h"#include "priv_prot.h"extern int debug;extern int report_sharing_conflicts;extern int grace_period;extern char *xmalloc();extern void xfree();extern bool_t obj_cmp();char *malloc();bool_t compatible();#define SH_HASH	29/* * File sharing records are organized as follows: * *                     fh (file handle) *                      | *                      v *                    hash() *                      | *                      +-------------+ *                                    | *                                    v *               +-+-+-+-+-+-+-+-+-+-+-+-+-+ *     fh_to_sx[]| | | | | | | | | | |*| | | *               +-+-+-+-+-+-+-+-+-+-+|+-+-+ *                                    | *      +-----------------------------+ *      | *      +-->  +---+   +---+   +---+   +---+ *   sx       |FWD--->|FWD--->|FWD--->| 0 |   (head of chains for files *            +---+   +---+   +---+   +---+    whose handle hash to the *            | 0 |<---BCK|<---BCK|<---BCK|    same value) *            +---+   +---+   +---+   +---+ *            |sxp|   |sxp|   |sxp|   |sxp| *            +---+   +-|-+   +---+   +---+ *                      | *      +---------------+ *      | *      +-->  +---+   +---+   +---+   +---+ *   sxx      |FWD--->|FWD--->|FWD--->| 0 |   (multiple shared access to *            +---+   +---+   +---+   +---+    the same file) *            | 0 |<---BCK|<---BCK|<---BCK| *            +---+   +---+   +---+   +---+ *            | s |   | s |   | s |   | s |	 (share: the structure *            | h |   | h |   | h |   | h |	  passed	in the RPC) *            | a |   | a |   | a |   | a | *            | r |   | r |   | r |   | r | *            | e |   | e |   | e |   | e | *            +---+   +---+   +---+   +---+ */struct	sxx {	struct sxx	*fwd;	struct sxx	*bck;	nlm_share	sh;};struct sx {	struct sx	*fwd;	struct sx	*bck;	struct sxx	*sxxp;};struct sx *fh_to_sx[SH_HASH];struct sxx *new_sxx();/* *	There are three entry points into the prot_share *	subsystem: * *	init_nlm_share *		called at the beginning of time to set up the hash table * *	proc_nlm_share *		called out of nlm_prog() in prot_main.c to process a *		a SHARE or UNSHARE request * *	destroy_client_shares *		called whenever a client has been declared dead by the *		status monitor. We throw away all sharing records *		for the client */void *init_nlm_share(){	int i;	if (debug)		printf("init_nlm_share\n");	for (i = 0; i < SH_HASH; i++)		fh_to_sx[i] = NULL;}/* * The following is the rough flow for proc_nlm_share: * *	hv = hash(fh) *	sxh = fh_to_sx[hv]; *	if (sxh!=NULL) { *		scan the chain looking for sxh->sxxp.sh.fh==fh *	} *	if (sxh==NULL) { *		SHARE: allocate new sx and sxx and chain to fh_to_sx[hv] *		UNSHARE: give up *	} *	sxxh = sxh->sxxp *	scan the chain looking for (sxxh->sh.caller_mame==caller_name && *		sxxh->sh.oh == oh) [i.e. the matching share structure] *	if (sxxh!=NULL) { *		SHARE: return {SUCCESS} [assume repeat request] *		UNSHARE: release *sxxh, which may free sxh, which may lead *		        to the fh_to_sx entry being reset *	} *	[there is no existing entry] *	UNSHARE: give up *	SHARE: scan chain starting at sxxxh->sxxp to see if the sharing *		is legal. If not, fail. Otherwise allocate new *		sxx, initialize it and add it to the list. *		Return {SUCCESS} */	void *proc_nlm_share(Rqstp, Transp)	struct svc_req *Rqstp;	SVCXPRT *Transp;{	nlm_shareargs *req;	struct	sx	*sxh;	struct	sxx	*sxxh;	int	hv;	enum nlm_stats	result;	bool_t	SHARE_REQ;	register char *c;	register int i;/* * Remember what kind of request this was */	SHARE_REQ = (Rqstp->rq_proc == NLM_SHARE);#define UNSHARE_REQ (!SHARE_REQ)/* * Allocate space for arguments and decode them */	req = (nlm_shareargs *)xmalloc(sizeof(nlm_shareargs));	if (!svc_getargs(Transp, xdr_nlm_shareargs, req)) {		free_sreq(req);		svcerr_decode(Transp);		return;	}	if (debug) {		printf("proc_nlm_share: %s from %s\n",			SHARE_REQ?"share":"unshare",			req->share.caller_name);		printf("oh="); pr_fh(&req->share.oh);		printf("\nfh="); pr_fh(&req->share.fh);		printf("\n");		if (SHARE_REQ)			printf("share: mode=%d, access=%d\n",				req->share.mode, req->share.access);	}/* * We only allow reclaims during the grace period */	if (grace_period > 0 && !(req->reclaim)) {		result = nlm_denied_grace_period;		goto common_exit;	}/* * Compute the hash index and get the start of the sxx chain */	hv = 0;	for (i = req->share.fh.n_len, c = req->share.fh.n_bytes; --i;)		hv += *c++;	hv %= SH_HASH;	sxh = fh_to_sx[hv];/* *	If sxh != NULL, scan down looking for the fh we are dealing with */	while (sxh != NULL) {		if (obj_cmp(&req->share.fh, &sxh->sxxp->sh.fh))			break;		sxh = sxh->fwd;	}/* * If sxh is null, we're not currently holding a sharing state for * this file. If it's a SHARE request, allocate new sx & sxx structures */	if (sxh == NULL) {		if (SHARE_REQ) {			if (debug)				printf("...null sxh - new file\n");			sxh = (struct sx *)malloc(sizeof(struct sx));			sxh->bck = NULL;			sxh->fwd = fh_to_sx[hv];			fh_to_sx[hv] = sxh;			sxh->sxxp = new_sxx(&req->share);		}		result = nlm_granted; /* either way.... */		goto common_exit;	}/* * If sxh is non-null, we have sharing state for this file. * Let's try and find an sx which corresponds exactly to this * request. */	if (debug)		printf("...sxh @0x%x\n", sxh);	sxxh = sxh->sxxp;	while (sxxh != NULL) {		if (!strcmp(sxxh->sh.caller_name, req->share.caller_name) &&			obj_cmp(&sxxh->sh.oh, &req->share.oh))			break;		sxxh = sxxh->fwd;	}/* * If sxxh is non-null, we have found an entry corresponding to * the request. For SHARE, we just reply "nlm_granted" -- presumably * this is an artefact of UDP-based RPC's. For UNSHARE, we must * throw away the sxx, and maybe the sx. */	if (sxxh != NULL) {		if (debug)printf("...matching sxx @0x%x\n", sxxh);		if (UNSHARE_REQ) {/* * Routine list manipulation follows.... */			if (sxxh->bck == NULL)				sxh->sxxp = sxxh->fwd;			else				sxxh->bck->fwd = sxxh->fwd;			if (sxxh->fwd != NULL)				sxxh->fwd->bck = sxxh->bck;			free_sxx(sxxh);/* * Check to see if we need to eliminate the sxx as well */			if (sxh->sxxp == NULL) {				if (sxh->bck == NULL)					fh_to_sx[hv] = sxh->fwd;				else					sxh->bck->fwd = sxh->fwd;				if (sxh->fwd != NULL)					sxh->fwd->bck = sxh->bck;				free((char *)sxh);			}					}		result = nlm_granted; /* for SHARE or UNSHARE */		goto common_exit;	}/* * We've now established that there's no existing sx corresponding * to this request. For UNSHARE, we just give "ok".... For * SHARE we've got to validate this sharing request. If it's o.k. * we build a new sx and add it to the list. [Current thinking * is that there's no special ordering here, so we can just stick it * on the front.] */	if (SHARE_REQ) {		if (!compatible(sxh->sxxp, &req->share)) {			if (debug)				printf("...not compatible\n");			result = nlm_denied;			goto common_exit;		}		sxxh = new_sxx(&req->share);		if (debug)printf("...compatible. new sxx @0x%x\n", sxxh);		sxh->sxxp->bck = sxxh;		sxxh->fwd = sxh->sxxp;		sxh->sxxp = sxxh;	}	result = nlm_granted;	/* SHARE/UNSHARE. Now we fall through to... *//* *	Common exit - issue reply with appropriate result code, * free request structure and quit */common_exit:	share_reply(Transp, req, result);	free_sreq(req);}/* * The following is the rough flow for destroy_client_shares: * *	for (hv = 0; hv < SH_HASH; hv++){ *	sxh = fh_to_sx[hv]; *	while (sxh!=NULL) { *		sxxh = sxh->sxxp *		while (sxxh != NULL) { *			if (!strcmp(sxxh->sh.caller_name,client)) *				blow away the entry (may longjump out of loops) *			sxxh=sxxh->fwd *		} *		sxh=sxh->fwd; *	} */	void *destroy_client_shares(client)	char *client;{	struct	sx	*sxh;	struct	sx	*next_sx;	struct	sxx	*sxxh;	struct	sxx	*next_sxx;	int	hv;	if (debug)		printf("destroy_client_shares for %s\n", client);	for (hv = 0; hv < SH_HASH; hv++) {		sxh = fh_to_sx[hv];/* *	If sxxh != NULL, scan down looking for the fh we are dealing with */		while (sxh != NULL) {			sxxh = sxh->sxxp;			next_sx = sxh->fwd;			while (sxxh != NULL) {				next_sxx = sxxh->fwd;				if (!strcmp(sxxh->sh.caller_name, client)) {/* * Blow this one away.... */					if (debug)						printf("... zap sxx @0x%x\n", sxxh);					if (sxxh->bck == NULL)						sxh->sxxp = sxxh->fwd;					else						sxxh->bck->fwd = sxxh->fwd;					if (sxxh->fwd != NULL)						sxxh->fwd->bck = sxxh->bck;					free_sxx(sxxh);/* * Check to see if we need to eliminate the sxx as well */					if (sxh->sxxp == NULL) {					if (debug)						printf("...  &  sx @0x%x\n", sxh);						if (sxh->bck == NULL)							fh_to_sx[hv] = sxh->fwd;						else							sxh->bck->fwd = sxh->fwd;						if (sxh->fwd != NULL)							sxh->fwd->bck = sxh->bck;						free((char *)sxh);						goto	skip_to_next_sx;					}							}	/* ... of "if (strcmp..." */				sxxh = next_sxx;			} /* of "while (sxxh..." */skip_to_next_sx:			sxh = next_sx;		} /* ... of "while (sxh..." */	} /* ... of	"for (hv... " */}/* *	------ Support routines ----- */share_reply(T,req,rc)	SVCXPRT *T;	nlm_shareargs *req;	enum	nlm_stats rc;{	nlm_shareres res;	res.cookie.n_len = req->cookie.n_len;	res.cookie.n_bytes = req->cookie.n_bytes;	res.stat = rc;	if (!(svc_sendreply(T, xdr_nlm_shareres, &res)))		svcerr_systemerr(T);}		free_sxx(s)	struct sxx *s;{	xfree(&s->sh.caller_name);  	xfree(&s->sh.fh.n_bytes);	xfree(&s->sh.oh.n_bytes);	bzero((char *) s, sizeof (*s));	free((char * ) s);}free_sreq(r)	nlm_shareargs *r;{	if (r) {		xfree(&r->cookie.n_bytes);		xfree(&r->share.caller_name);		xfree(&r->share.fh.n_bytes);		xfree(&r->share.oh.n_bytes);		bzero((char *) r, sizeof (*r));		free((char *) r);	}}/* *	Allocate a new sxx structure based on that in the RPC. We make use * of the fact that the caller-name, fh and oh are dynamically * allocated, and that we won't need them in the original copy after * this point in time, so we just copy the pointers and lengths and * set the pointers to NULL (xfree will check them in free_sreq) */struct sxx *new_sxx(s)	nlm_share *s;{	struct sxx *new;	new = (struct sxx *)malloc(sizeof(struct sxx));	new->fwd = NULL;	new->bck = NULL;	new->sh.caller_name = s->caller_name;	s->caller_name = NULL;	new->sh.fh.n_len = s->fh.n_len;	new->sh.fh.n_bytes = s->fh.n_bytes;	s->fh.n_bytes = NULL;	new->sh.oh.n_len = s->oh.n_len;	new->sh.oh.n_bytes = s->oh.n_bytes;	s->oh.n_bytes = NULL;	new->sh.mode = s->mode;	new->sh.access = s->access;	return(new);}/* * compatible - the guts of the whole thing. Takes a pointer to * the first sx structure in the list and one to the share structure * in the RPC. Returns TRUE if the SHARE is compatible with the * existing state. * * The checking relies on the bit encoding for fsh_mode and * fsh_access (see nlm_prot.h). Specifically, * if any existing access ANDed with the requested mode is non-zero, OR * if any existing mode ANDed with the requested access is non-zero, * we deny the SHARE. */bool_tcompatible(ss,s)	struct sxx *ss;	nlm_share *s;{	while (ss != NULL) {		if (((int)ss->sh.mode & (int)s->access) ||				((int)ss->sh.access & (int)s->mode)) {			if (report_sharing_conflicts)				printf("\nFile sharing request from %s (mode %d, access %d) conflicts\nwith sharing for %s (mode %d, access %d)\n",				s->caller_name, s->mode, s->access,				ss->sh.caller_name, ss->sh.mode, ss->sh.access);			return(FALSE);		}		ss = ss->fwd;	}	return(TRUE);}

⌨️ 快捷键说明

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