static char rcsid[] = "$Header: efs_open.c,v 820.1 86/12/04 19:47:44 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984, 1985			*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Handle open requests for both the extended
 * filesystem driver and remote files.
 *
 * jam 840207-09-11-21-22-28-0427
 * smj 850813	Remove (enable) refs to NET_SUPER_USER.
 */

#include "../h/param.h"
#include "../h/dir.h"
#include "../h/file.h"
#include "../h/user.h"
#include "../vnet/vnet.h"
#include "../h/inode.h"
#include "../h/nami.h"

#include "../conn/conn.h"
#include "../rpc/rpc.h"
#include "../efs/efs.h"

struct efs_openCall {
	int		uid;		/* UID of caller */
	int		gid;		/* GID of caller */
	int		mode;		/* Mode file is opened with */
	int		flags; 		/* Passed through from open1() */
	int		cmask;		/* Creation mask of caller */
	/* NULL terminated file name follows this structure */
};

struct efs_openReturn {
	int		error;		/* Error number or 0 on success */
	u_long		rfd;		/* Remote file descriptor */
	long		offset;		/* Initial offset into the file */
};

dev_t	efs_dev = NODEV;

efs_open(dev, flags, mode)
   dev_t dev;
{
	register connection_t *conn;
	register struct efs_remoteFile *remote;
	register struct efs_openCall *params;
	register struct efs_openReturn *results;
	struct file *fp = getf(u.u_r.r_val1);
	int error;

	if (efs_dev == NODEV)
		efs_dev = dev;
	if (efs_initPath() == 0) {
		if (!suser())
			return(EACCES);
		/*
		 * Make sure no one confuses this open file
		 * with an open remote file.
		 */
		fp->f_remote = NULL;
		return(0);
	}
	if ((conn = efs_uhostLookup()) == NULL || conn->state != CONN_ACTIVE)
		return(EHOSTUNREACH);
	remote = efs_allocRemoteFile();
	if (remote == NULL)
		return(ENOLOCALFILE);
	remote->conn = conn;
	conn_link(conn);

	/*
	 * Systems running versions of conn lower
	 * than 0x0001 will choke on bulk data requests
	 * so we disable them here.
	 */
	if (conn->version < 0x0001)
		remote->nobulk = 1;

	params = efs_makePacket(open,EFS_PATHSIZE);
	params->uid = u.u_uid;
	params->gid = u.u_gid;
	params->mode = mode;
	params->flags = flags;
	params->cmask = u.u_cmask;
	efs_getPathname(efs_data(params));
	efs_incClient(opens);
	results = (struct efs_openReturn *)efs_call(conn,EFS_OPEN,params);
	if (results == NULL) {
		efs_freeRemoteFile(remote);
		return(u.u_error);
	}
	error = results->error;
	if (error)
		efs_freeRemoteFile(remote);
	else {
		remote->rfd = results->rfd;
		fp->f_offset = results->offset;
		fp->f_remote = remote;
	}
	rpc_freeResults(results);
	return(error);
}

caddr_t
efs_remoteOpen(clientConn, clientId, operation, params)
   connection_t *clientConn;
   u_long clientId;
   u_short operation;
   struct efs_openCall *params;
{
	register struct efs_openReturn *results;
	register struct efs_localFile *local;
	register struct file *fp;
	int mode;
	extern mbufchar();

	efs_incServer(opens);
	u.u_uid = u.u_ruid = params->uid;
	u.u_gid = u.u_rgid = params->gid;
	u.u_cmask = params->cmask;
	efs_checkNetsu();
	u.u_error = 0;
	results = efs_makeReturnPacket(params,open, 0);
	local = efs_allocLocalFile();
	if (local == NULL) {
		u.u_error = ENOLOCALFILE;
		goto out;
	}
	u.u_dirp = efs_data(params);
	mode = params->flags;

	copen(mode, params->mode, mbufchar, 1/*amserver*/);
	if (u.u_error)
		goto out;
	fp = getf(u.u_r.r_val1);
	u.u_ofile[u.u_r.r_val1] = NULL;

	/* BUG race before conn_link happens */
	conn_link(clientConn);
	local->conn = clientConn;
	local->fp = fp;
	results->rfd = local->rfd;
	results->offset = local->fp->f_offset;
out:
	if (local && u.u_error)
		efs_freeLocalFile(local);
	results->error = u.u_error;
	u.u_dirp = NULL;
	rpc_freeParams(params);
	return((caddr_t)results);
}
