 /*
  * Khoros: $Id: SunVM.c,v 1.3 1992/03/20 23:38:57 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: SunVM.c,v 1.3 1992/03/20 23:38:57 dkhoros Exp $";
#endif

 /*
  * $Log: SunVM.c,v $
 * Revision 1.3  1992/03/20  23:38:57  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name: SunVM.c					<<<<
   >>>>								<<<<
   >>>>   description: Khoros Virtual memory drivers for Sun	<<<<
   >>>>								<<<<
   >>>>      routines: sunvm_tempnam				<<<<
   >>>>		       sunvm_open				<<<<
   >>>>		       sunvm_close				<<<<
   >>>>		       sunvm_read				<<<<
   >>>>		       sunvm_write				<<<<
   >>>>		       sunvm_lseek				<<<<
   >>>>		       sunvm_tell				<<<<
   >>>>		       sunvm_access				<<<<
   >>>>		       sunvm_unlink				<<<<
   >>>>		       sunvm_lock				<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


#ifdef KSUNVM

#include "internals.h"	
#include "SunVM.h"	



/**************************************************************
*
* MODULE NAME: sunvm_tempnam
*
*     PURPOSE: This function initializes a tempnam for a "sunvm"
*	       type transport.  Given a request with a filename of
*	       the following syntax:
*
*			"sunvm=XXXXXXXXXX"
*			     ...etc....
*
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 if an error occurs
*
* CALLED FROM:  internal routine called from ktempnam()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int sunvm_tempnam(identifier, template, result)

char *identifier;
char *template;
char *result;
{
	int	fid;
	char	*temp, filename[LENGTH];


	(void) strcpy(filename, template);
	if ((temp = vtempnam(filename)) == NULL)
	   return(-1);


	if ((fid = open(temp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) <= 0)
	{
	   perror("file_tempnam:  Unable to create temporary file....");
	   return(-1);
	}
	close(fid);

	if (identifier == NULL)
	   (void) sprintf(result, "sunvm=%s", temp);
	else
	   (void) sprintf(result,"%s=%s", identifier, temp);

	kfree(temp);
	return(0);
}


/**************************************************************
*
* MODULE NAME: sunvm_open
*
*     PURPOSE: This function opens a "sunvm" connection.  It is the
*	       internal driver to open a file, which is called by
*	       the user when they call kopen().  kopen() calls when
*	       it gets an open request with a filename of the following
*	       syntax:
*
*			"sunvm=XXXXXXXXX"
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 if an error occurs
*
* CALLED FROM:  internal routine called from kopen()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int sunvm_open(path, flags, mode, file)

char *path;
int  flags;
int  mode;
kfile *file;
{
	caddr_t	addr;
	struct  stat buf;
	int	size, fid, prot = 0;
	ResourceStruct *resources;


	/*
	 *  Get the size of the file
	 */
	if (stat(path, &buf) == -1)
	{
	   perror("sunvm_open:  Stat failure....");
	   return(-1);
	}
	size = buf.st_size;

	/*
	 *  Get memory map (mmap) protections from the open permission
	 *  flags...
	 */
	if (flags == O_RDONLY || flags & O_RDWR)
	{
	   prot |= PROT_READ;
	}
	if (flags & O_WRONLY || flags & O_RDWR)
	{
	   flags |= O_RDWR;
	   prot  |= (PROT_WRITE | PROT_READ);
	}

	/*
	 *  Open the file for the memory map (mmap) call.
	 */
	if ((fid = open(path, flags, mode)) < 0)
	{
	   perror("sunvm_open:  Open failure....");
	   return(-1);
	}

	/*
	 *  Attach to file the appropriate memory map space...
	 */
	if ((addr = mmap(0, size, prot, MAP_SHARED, fid, 0)) == (caddr_t) -1)
	{
	   perror("sunvm_open:  Memory Map (mmap) failure....");
	   return(-1);
	}

	if (!(resources = (ResourceStruct *) calloc(1, sizeof(ResourceStruct))))
	{
	   (void) fprintf(stderr,"sunvm_open:  Not enough memory....\n\n");
	   (void) fprintf(stderr,"  Unable to malloc (%d) bytes for the khoros \
Sun Virtual Memory structure.\n", sizeof(ResourceStruct));
	   return(-1);
	}

	resources->fid    = fid;
	resources->addr   = addr;
	resources->size   = size;
	resources->prot   = prot;
	resources->offset = 0;

	file->resources = (caddr_t) resources;
	return(0);
}



/**************************************************************
*
* MODULE NAME: sunvm_close
*
*     PURPOSE: This function closes a "sunvm".  It is the internal driver
*	       to close a data sunvm, which is called by the user
*	       when they call kclose().  kclose() calls the "sunvm" internal
*	       drivers by the nature of the transport, which is dictated
*	       by the initial kopen().
*
*
*       INPUT:  file - the kfile structure.
*
*      OUTPUT:  returns whether we were able to close the file
*
* CALLED FROM:  internal routine called from kclose()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int sunvm_close(file)

kfile *file;
{
	caddr_t	addr;
	int	fid, size;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call lseek() since "kfile" is just a regular file
	 */
	fid  = resources->fid;
	size = resources->size;
	addr = resources->addr;

	return(close(fid) |  munmap(addr, size));
}



/**************************************************************
*
* MODULE NAME: sunvm_read
*
*     PURPOSE: This function reads a "sunvm".  It is the internal driver
*	       to read data from a sunvm, which is called by the user
*	       when they call kread().  kread() calls the "sunvm" internal
*	       drivers by the nature of the transport, which is dictated
*	       by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		ptr    - the pointer to store the data into.
*		nbytes - the number of bytes to read.
*
*      OUTPUT:  returns the number of bytes read from the sunvm
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int sunvm_read(file, ptr, nbytes)

kfile *file;
char  *ptr;
int   nbytes;
{
	caddr_t addr;
	int	size, offset;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call bcopy() since "kfile" is just a regular 
	 *  memory pointer.
	 */
	addr   = resources->addr;
	size   = resources->size;
	offset = resources->offset;

	/*
	 *  Make sure that we aren't trying to read more bytes than we
	 *  currently have.  If so then try re-opening the file to see
	 *  if it's gotten bigger.
	 */
	if (offset+nbytes > size)
	{
	   sunvm_reopen(file, offset+nbytes);
	   addr   = resources->addr;
	   size   = resources->size;
	   offset = resources->offset;
	}

	if (offset+nbytes > size && offset != size)
	{
	   bcopy(addr+offset, ptr, size-offset);
	   nbytes = size-offset;
	}
	else if (offset != size)
	   bcopy(addr+offset, ptr, nbytes);
	else
	   return(EOF);

	resources->offset += nbytes;
	return(nbytes);
}



/**************************************************************
*
* MODULE NAME: sunvm_write
*
*     PURPOSE: This function writes to a "sunvm".  It is the internal driver
*	       to write data from the supplied data array to a sunvm, which
*	       is called by the user when they call kwrite().  kwrite() calls
*	       the "sunvm" internal drivers by the nature of the transport,
*	       which is dictated by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		ptr  - the pointer to write the data from.
*		nbytes - the number of bytes to read.
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int sunvm_write(file, ptr, nbytes)

kfile *file;
char  *ptr;
int   nbytes;
{
	caddr_t addr;
	int	fid, size, offset, num;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call bcopy() since "kfile" is just a regular 
	 *  memory pointer.
	 */
	addr   = resources->addr;
	size   = resources->size;
	offset = resources->offset;

	/*
	 *  Make sure that we aren't trying to read more bytes than we
	 *  currently have.  If so then try re-opening the file to see
	 *  if it's gotten bigger.
	 */
	if (offset+nbytes > size)
	{
	   fid = resources->fid;
	   num = (offset-nbytes) - size;
	   (void) write(fid, ptr+(nbytes-num), num);

	   sunvm_reopen(file, offset+nbytes);
	   addr   = resources->addr;
	   size   = resources->size;
	   offset = resources->offset;
	}

	if (offset+nbytes > size && offset != size)
	{
	   bcopy(ptr, addr+offset, size-offset);
	   nbytes = size-offset;
	}
	else if (offset != size)
	   bcopy(ptr, addr+offset, nbytes);
	else
	   return(EOF);

	resources->offset += nbytes;
	return(nbytes);
}



/**************************************************************
*
* MODULE NAME: sunvm_lseek
*
*     PURPOSE: This function is used to do a "lseek".  It is the internal
*	       driver to rewind to a specific point so that the data can be
*	       skipped or re-read.  This is called when the user calls
*	       klseek().  klseek() calls the "sunvm" internal drivers by the
*	       nature of the transport, which is dictated by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		offset - the offset in which to seek
*		whence - the control of how the offset will be applied
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int sunvm_lseek(file, offset, whence)

kfile *file;
int   offset;
int   whence;
{
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call lseek() since "kfile" is just a regular sunvm
	 */
	if (whence == SEEK_SET)
	   resources->offset = offset;
	else if (whence == SEEK_CUR)
	   resources->offset += offset;
	else if (whence == SEEK_END)
	   resources->offset = resources->size + offset;
	else
	{
	   errno = EINVAL;
	   perror("sunvm_lseek:  Invalid whence argument value....");
	   return(-1);
	}

	if (resources->offset > resources->size)
	{
	   /* not sure as of yet */
	}
	return(resources->offset);
}



/**************************************************************
*
* MODULE NAME: sunvm_tell
*
*     PURPOSE: This function is used to do a "lseek".  It is the internal
*	       driver to rewind to a specific point so that the data can be
*	       skipped or re-read.  This is called when the user calls
*	       ktell().  ktell() calls the "sunvm" internal drivers by the
*	       nature of the transport, which is dictated by the kopen().
*
*
*       INPUT:  file   - the kfile structure.
*		offset - the offset in which to seek
*		whence - the control of how the offset will be applied
*
*      OUTPUT:  returns the number of bytes written to the kfile
*
* CALLED FROM:  internal routine called from kread()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int sunvm_tell(file)

kfile *file;
{
	int	offset;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	/*
	 *  Simply call tell() since "kfile" is just a regular sunvm
	 */
	offset = resources->offset;
	return(offset);
}



/**************************************************************
*
* MODULE NAME: sunvm_access
*
*     PURPOSE: This function is used to do see if a file is accessable.
*	       This is called when the user calls kaccess().  kaccess()
*	       calls the "sunvm" internal drivers by the nature of the
*	       transport, which is dictated by the transport_identifier().
*
*
*       INPUT:  path     - the initial path.
*		filename - the filename that they wish to access
*		mode     - the access mode information
*
*      OUTPUT:  returns the result
*
* CALLED FROM:  internal routine called from kaccess()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int sunvm_access(path, filename, mode)

char *path;
char *filename;
int  mode;
{
	int	   status;


	/*
	 *  Simply call access() since "filename" is just a regular filename
	 */
	status = access(filename, mode);
	return(status);
}



/**************************************************************
*
* MODULE NAME: sunvm_unlink
*
*     PURPOSE: This function initializes a tempnam for a "sunvm"
*	       type transport.  Given a request with a filename of
*	       the following syntax:
*
*			"sunmvm=XXXXXXXXXX"
*
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 depending whether we
*		sucessfully created the template
*
* CALLED FROM:  internal routine called from kunlink()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int sunvm_unlink(identifier, filename)

char *identifier;
char *filename;
{
	int	status;


	status = unlink(filename);
	return(status);
}



/**************************************************************
*
* MODULE NAME: sunvm_lock
*
*     PURPOSE: This function locks a "sunvm" transport.  Given
*	       a request with a filename of the following syntax:
*
*			"sunvm=filename"
*
*       INPUT: 
*
*        
*      OUTPUT:  returns 0 or -1 depending whether we
*		sucessfully created the template
*
* CALLED FROM:  internal routine called from kflock()
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int sunvm_lock(file, operation)

kfile *file;
int   operation;
{
	int	status;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	status = flock(resources->fid, operation);
	return(status);
}



/*********************************************************************
*
*		Private Sun Virtual Mempory Routines
*
*********************************************************************/

sunvm_reopen(file, num_bytes)

kfile *file;
int   num_bytes;
{
	caddr_t addr;
	int	fid, size;
	ResourceStruct *resources = (ResourceStruct *) file->resources;


	if (resources->prot & PROT_READ)
	   fid = resources->fid;
	else
	{
	   if ((fid = open("/dev/zero", O_RDWR)) < 0)
	      fid = resources->fid;
	}

	/*
	 *  Attach to file the appropriate memory map space...
	 */
	size = ceil(((double) num_bytes)/DefaultPageSize)*DefaultPageSize;
	if ((addr = mmap(resources->addr, num_bytes, resources->prot,
			 MAP_SHARED, fid, size)) == (caddr_t) -1)
	{
	   perror("sunvm_reopen:  Memory Map (mmap) failure....");
	   return;
	}
	resources->addr = addr;
	resources->size = size;
}

#endif  /* KSUNVM */
/* don`t add after the endif */
