xref: /titanic_51/usr/src/lib/libpkg/common/vfpops.c (revision 4656d4747c8743290bfbe910c64cd75eb4e4af8d)
15c51f124SMoriah Waterland /*
25c51f124SMoriah Waterland  * CDDL HEADER START
35c51f124SMoriah Waterland  *
45c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
55c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
65c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
75c51f124SMoriah Waterland  *
85c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
105c51f124SMoriah Waterland  * See the License for the specific language governing permissions
115c51f124SMoriah Waterland  * and limitations under the License.
125c51f124SMoriah Waterland  *
135c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
145c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
165c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
175c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
185c51f124SMoriah Waterland  *
195c51f124SMoriah Waterland  * CDDL HEADER END
205c51f124SMoriah Waterland  */
215c51f124SMoriah Waterland 
225c51f124SMoriah Waterland /*
235c51f124SMoriah Waterland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245c51f124SMoriah Waterland  * Use is subject to license terms.
255c51f124SMoriah Waterland  */
265c51f124SMoriah Waterland 
275c51f124SMoriah Waterland 
285c51f124SMoriah Waterland 
295c51f124SMoriah Waterland /*
305c51f124SMoriah Waterland  * Module:	vfpops.c
315c51f124SMoriah Waterland  * Synopsis:	Implements virtual file protocol operations
325c51f124SMoriah Waterland  * Description:
335c51f124SMoriah Waterland  *
345c51f124SMoriah Waterland  * This module implements the "Virtual File protocol" operations. These
355c51f124SMoriah Waterland  * operations are intended to provide very fast access to file data,
365c51f124SMoriah Waterland  * allowing a file to be accessed in very efficient ways with extremely
375c51f124SMoriah Waterland  * low-cpu intensive operations. If possible file data is mapped directly
385c51f124SMoriah Waterland  * into memory allowing the data to be accessed directly. If the data
395c51f124SMoriah Waterland  * cannot be mapped directly into memory, memory will be allocated and
405c51f124SMoriah Waterland  * the file data read directly into memory. If that fails currently the
415c51f124SMoriah Waterland  * file data is not accessible. Other methods of making the file could
425c51f124SMoriah Waterland  * be implemented in the future (e.g. stdio if all else fails).
435c51f124SMoriah Waterland  *
445c51f124SMoriah Waterland  * In general any code that uses stdio to access a file can be changed
455c51f124SMoriah Waterland  * to use the various "vfp" operations to access a file, with a resulting
465c51f124SMoriah Waterland  * increase in performance and decrease in cpu time required to access
475c51f124SMoriah Waterland  * the file contents.
485c51f124SMoriah Waterland  *
495c51f124SMoriah Waterland  * Public Methods:
505c51f124SMoriah Waterland  *
515c51f124SMoriah Waterland  *   vfpCheckpointFile - Create new VFP that checkpoints existing VFP
525c51f124SMoriah Waterland  *   vfpCheckpointOpen - open file, allocate storage, return pointer to VFP_T
535c51f124SMoriah Waterland  *   vfpClose - close file associated with vfp
545c51f124SMoriah Waterland  *   vfpDecCurrPtr - decrement current character pointer
555c51f124SMoriah Waterland  *   vfpGetBytesRemaining - get number of bytes remaining to read
565c51f124SMoriah Waterland  *   vfpGetCurrCharPtr - get pointer to current character
575c51f124SMoriah Waterland  *   vfpGetCurrPtrDelta - get number of bytes between current and specified char
585c51f124SMoriah Waterland  *   vfpGetFirstCharPtr - get pointer to first character
595c51f124SMoriah Waterland  *   vfpGetLastCharPtr - get pointer to last character
605c51f124SMoriah Waterland  *   vfpGetModifiedLen - get highest modified byte (length) contained in vfp
615c51f124SMoriah Waterland  *   vfpGetPath - get the path associated with the vfp
625c51f124SMoriah Waterland  *   vfpGetc - get current character and increment to next
635c51f124SMoriah Waterland  *   vfpGetcNoInc - get current character - do not increment
645c51f124SMoriah Waterland  *   vfpGets - get a string from the vfp into a fixed size buffer
655c51f124SMoriah Waterland  *   vfpIncCurrPtr - increment current character pointer
665c51f124SMoriah Waterland  *   vfpIncCurrPtrBy - increment current pointer by specified delta
675c51f124SMoriah Waterland  *   vfpOpen - open file on vfp
685c51f124SMoriah Waterland  *   vfpPutBytes - put fixed number of bytes to current character and increment
695c51f124SMoriah Waterland  *   vfpPutFormat - put format one arg to current character and increment
705c51f124SMoriah Waterland  *   vfpPutInteger - put integer to current character and increment
715c51f124SMoriah Waterland  *   vfpPutLong - put long to current character and increment
725c51f124SMoriah Waterland  *   vfpPutc - put current character and increment to next
735c51f124SMoriah Waterland  *   vfpPuts - put string to current character and increment
745c51f124SMoriah Waterland  *   vfpRewind - rewind file to first byte
755c51f124SMoriah Waterland  *   vfpSeekToEnd - seek to end of file
765c51f124SMoriah Waterland  *   vfpSetCurrCharPtr - set pointer to current character
775c51f124SMoriah Waterland  *   vfpSetFlags - set flags that affect file access
785c51f124SMoriah Waterland  *   vfpSetSize - set size of file (for writing)
795c51f124SMoriah Waterland  *   vfpTruncate - truncate file
805c51f124SMoriah Waterland  *   vfpWriteToFile - write data contained in vfp to specified file
815c51f124SMoriah Waterland  */
825c51f124SMoriah Waterland 
835c51f124SMoriah Waterland #include <stdio.h>
845c51f124SMoriah Waterland #include <limits.h>
855c51f124SMoriah Waterland #include <stdlib.h>
865c51f124SMoriah Waterland #include <string.h>
875c51f124SMoriah Waterland #include <strings.h>
885c51f124SMoriah Waterland #include <unistd.h>
895c51f124SMoriah Waterland #include <ctype.h>
905c51f124SMoriah Waterland #include <fcntl.h>
915c51f124SMoriah Waterland #include <sys/types.h>
925c51f124SMoriah Waterland #include <sys/stat.h>
935c51f124SMoriah Waterland #include <sys/mman.h>
945c51f124SMoriah Waterland #include <errno.h>
955c51f124SMoriah Waterland #include <libintl.h>
965c51f124SMoriah Waterland #include "pkglib.h"
975c51f124SMoriah Waterland #include "pkgstrct.h"
985c51f124SMoriah Waterland #include "pkglocale.h"
995c51f124SMoriah Waterland 
1005c51f124SMoriah Waterland /*
1015c51f124SMoriah Waterland  * These are internal flags that occupy the high order byte of the VFPFLAGS_T
1025c51f124SMoriah Waterland  * flags element of the vfp. These flags may only occupy the high order order
1035c51f124SMoriah Waterland  * 16 bits of the 32-bit unsigned vfp "flags" object.
1045c51f124SMoriah Waterland  */
1055c51f124SMoriah Waterland 
1065c51f124SMoriah Waterland #define	_VFP_MMAP	0x00010000	/* mmap used */
1075c51f124SMoriah Waterland #define	_VFP_MALLOC	0x00020000	/* malloc used */
1085c51f124SMoriah Waterland #define	_VFP_WRITE	0x00040000	/* file opened for write */
1095c51f124SMoriah Waterland #define	_VFP_READ	0x00080000	/* file opened for reading */
1105c51f124SMoriah Waterland #define	_VFP_MODIFIED	0x00100000	/* contents are marked modified */
1115c51f124SMoriah Waterland 
1125c51f124SMoriah Waterland /* path name given to "anonymous" (string) vfp */
1135c51f124SMoriah Waterland 
1145c51f124SMoriah Waterland #define	VFP_ANONYMOUS_PATH	"<<string>>"
1155c51f124SMoriah Waterland 
1165c51f124SMoriah Waterland /* minimum size file to mmap (64mb) */
1175c51f124SMoriah Waterland 
1185c51f124SMoriah Waterland #define	MIN_MMAP_SIZE	(64*1024)
1195c51f124SMoriah Waterland 
1205c51f124SMoriah Waterland /*
1215c51f124SMoriah Waterland  * *****************************************************************************
1225c51f124SMoriah Waterland  * global external (public) functions
1235c51f124SMoriah Waterland  * *****************************************************************************
1245c51f124SMoriah Waterland  */
1255c51f124SMoriah Waterland 
1265c51f124SMoriah Waterland /*
1275c51f124SMoriah Waterland  * Name:	vfpOpen
1285c51f124SMoriah Waterland  * Description:	Open file on vfp, allocate storage, return pointer to VFP_T
1295c51f124SMoriah Waterland  *		that can be used to access/modify file contents.
1305c51f124SMoriah Waterland  * Arguments:	VFP_T **r_vfp - pointer to pointer to VFP_T
1315c51f124SMoriah Waterland  *		char *a_path - path of file to open and associate with this VFP.
1325c51f124SMoriah Waterland  *			- if the path is (char *)NULL then no file is associated
1335c51f124SMoriah Waterland  *			  with this VFP - this is a way to create a fixed length
1345c51f124SMoriah Waterland  *			  string that can be manipulated with the VFP operators.
1355c51f124SMoriah Waterland  *			  Before the VFP can be used "vfpSetSize" must be called
1365c51f124SMoriah Waterland  *			  to set the size of the string buffer.
1375c51f124SMoriah Waterland  *		char *a_mode - fopen mode to open the file with
1385c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
1395c51f124SMoriah Waterland  *			- VFP_NONE - no special flags
1405c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
1415c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - memory will be sequentially accessed
1425c51f124SMoriah Waterland  *			- VFP_RANDOM - memory will be randomly accessed
1435c51f124SMoriah Waterland  *			- VFP_NOMMAP - do not use mmap to access file
1445c51f124SMoriah Waterland  *			- VFP_NOMALLOC - do not use malloc to buffer file
1455c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
1465c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
1475c51f124SMoriah Waterland  * Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
1485c51f124SMoriah Waterland  *			which can be used with the various vfp functions.
1495c51f124SMoriah Waterland  *		errno -- contains system error number if return is != 0
1505c51f124SMoriah Waterland  */
1515c51f124SMoriah Waterland 
1525c51f124SMoriah Waterland int
1535c51f124SMoriah Waterland vfpOpen(VFP_T **r_vfp, char *a_path, char *a_mode, VFPFLAGS_T a_flags)
1545c51f124SMoriah Waterland {
1555c51f124SMoriah Waterland 	FILE		*fp = (FILE *)NULL;
1565c51f124SMoriah Waterland 	VFP_T		*vfp;
1575c51f124SMoriah Waterland 	int		lerrno;
1585c51f124SMoriah Waterland 	struct stat	statbuf;
1595c51f124SMoriah Waterland 	int		pagesize = getpagesize();
1605c51f124SMoriah Waterland 
1615c51f124SMoriah Waterland 	/* reset return VFP/FILE pointers */
1625c51f124SMoriah Waterland 
1635c51f124SMoriah Waterland 	(*r_vfp) = (VFP_T *)NULL;
1645c51f124SMoriah Waterland 
1655c51f124SMoriah Waterland 	/* allocate pre-zeroed vfp object */
1665c51f124SMoriah Waterland 
1675c51f124SMoriah Waterland 	vfp = (VFP_T *)calloc(sizeof (VFP_T), 1);
1685c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
1695c51f124SMoriah Waterland 		return (-1);
1705c51f124SMoriah Waterland 	}
1715c51f124SMoriah Waterland 
1725c51f124SMoriah Waterland 	/* create "string" vfp if no path specified */
1735c51f124SMoriah Waterland 
1745c51f124SMoriah Waterland 	if (a_path == (char *)NULL) {
1755c51f124SMoriah Waterland 		/*
1765c51f124SMoriah Waterland 		 * no path specified - no open file associated with vfp
1775c51f124SMoriah Waterland 		 * The vfp is initialized to all zeros - initialize just those
1785c51f124SMoriah Waterland 		 * values that need to be non-zero.
1795c51f124SMoriah Waterland 		 */
1805c51f124SMoriah Waterland 
1815c51f124SMoriah Waterland 		vfp->_vfpFlags = _VFP_MALLOC;
1825c51f124SMoriah Waterland 		vfp->_vfpPath = strdup(VFP_ANONYMOUS_PATH);
1835c51f124SMoriah Waterland 		(*r_vfp) = vfp;
1845c51f124SMoriah Waterland 		return (0);
1855c51f124SMoriah Waterland 	}
1865c51f124SMoriah Waterland 
1875c51f124SMoriah Waterland 	/*
1885c51f124SMoriah Waterland 	 * path specified - associate open file with vfp;
1895c51f124SMoriah Waterland 	 * return an error if no path or mode specified
1905c51f124SMoriah Waterland 	 */
1915c51f124SMoriah Waterland 
1925c51f124SMoriah Waterland 	if (a_mode == (char *)NULL) {
1935c51f124SMoriah Waterland 		errno = EFAULT;		/* Bad address */
1945c51f124SMoriah Waterland 		(void) free(vfp);
1955c51f124SMoriah Waterland 		return (-1);
1965c51f124SMoriah Waterland 	}
1975c51f124SMoriah Waterland 
1985c51f124SMoriah Waterland 	/* return an error if an empty path or mode specified */
1995c51f124SMoriah Waterland 
2005c51f124SMoriah Waterland 	if ((*a_path == '\0') || (*a_mode == '\0')) {
2015c51f124SMoriah Waterland 		errno = EINVAL;		/* Invalid argument */
2025c51f124SMoriah Waterland 		(void) free(vfp);
2035c51f124SMoriah Waterland 		return (-1);
2045c51f124SMoriah Waterland 	}
2055c51f124SMoriah Waterland 
2065c51f124SMoriah Waterland 	/* open the file */
2075c51f124SMoriah Waterland 
2085c51f124SMoriah Waterland 	fp = fopen(a_path, a_mode);
2095c51f124SMoriah Waterland 	if (fp == (FILE *)NULL) {
2105c51f124SMoriah Waterland 		lerrno = errno;
2115c51f124SMoriah Waterland 		(void) free(vfp);
2125c51f124SMoriah Waterland 		errno = lerrno;
2135c51f124SMoriah Waterland 		return (-1);
2145c51f124SMoriah Waterland 	}
2155c51f124SMoriah Waterland 
2165c51f124SMoriah Waterland 	/* Get the file size */
2175c51f124SMoriah Waterland 
2185c51f124SMoriah Waterland 	if (fstat(fileno(fp), &statbuf) != 0) {
2195c51f124SMoriah Waterland 		lerrno = errno;
2205c51f124SMoriah Waterland 		(void) fclose(fp);
2215c51f124SMoriah Waterland 		(void) free(vfp);
2225c51f124SMoriah Waterland 		errno = lerrno;
2235c51f124SMoriah Waterland 		return (-1);
2245c51f124SMoriah Waterland 	}
2255c51f124SMoriah Waterland 
2265c51f124SMoriah Waterland 	/*
2275c51f124SMoriah Waterland 	 * Obtain access to existing file contents:
2285c51f124SMoriah Waterland 	 *  -> plan a: map contents file into memory
2295c51f124SMoriah Waterland 	 *  -> plan b: on failure just read into large buffer
2305c51f124SMoriah Waterland 	 */
2315c51f124SMoriah Waterland 
2325c51f124SMoriah Waterland 	/* attempt to mmap file if mmap is allowed */
2335c51f124SMoriah Waterland 
2345c51f124SMoriah Waterland 	vfp->_vfpStart = MAP_FAILED;	/* assume map failed if not allowed */
2355c51f124SMoriah Waterland 
2365c51f124SMoriah Waterland 	/*
2375c51f124SMoriah Waterland 	 * if file is a regular file, and if mmap allowed,
2385c51f124SMoriah Waterland 	 * and (malloc not forbidden or size is > minumum size to mmap)
2395c51f124SMoriah Waterland 	 */
2405c51f124SMoriah Waterland 
2415c51f124SMoriah Waterland 	if ((S_ISREG(statbuf.st_mode)) && (!(a_flags & VFP_NOMMAP)) &&
2425c51f124SMoriah Waterland 		((a_flags & VFP_NOMALLOC) || statbuf.st_size > MIN_MMAP_SIZE)) {
2435c51f124SMoriah Waterland 		char *p;
2445c51f124SMoriah Waterland 		/* set size to current size of file */
2455c51f124SMoriah Waterland 
2465c51f124SMoriah Waterland 		vfp->_vfpMapSize = statbuf.st_size;
2475c51f124SMoriah Waterland 
2485c51f124SMoriah Waterland 		/*
2495c51f124SMoriah Waterland 		 * compute proper size for mapping for the file contents;
2505c51f124SMoriah Waterland 		 * add in one extra page so falling off end when file size is
2515c51f124SMoriah Waterland 		 * exactly modulo page size does not cause a page fault to
2525c51f124SMoriah Waterland 		 * guarantee that the end of the file contents will always
2535c51f124SMoriah Waterland 		 * contain a '\0' null character.
2545c51f124SMoriah Waterland 		 */
2555c51f124SMoriah Waterland 
2565c51f124SMoriah Waterland 		vfp->_vfpSize = (statbuf.st_size + pagesize +
2575c51f124SMoriah Waterland 				(pagesize-(statbuf.st_size % pagesize)));
2585c51f124SMoriah Waterland 
2595c51f124SMoriah Waterland 		/*
2605c51f124SMoriah Waterland 		 * mmap allowed: mmap file into memory
2615c51f124SMoriah Waterland 		 * first allocate space on top of which the mapping can be done;
2625c51f124SMoriah Waterland 		 * this way we can guarantee that if the mapping happens to be
2635c51f124SMoriah Waterland 		 * an exact multiple of a page size, that there will be at least
2645c51f124SMoriah Waterland 		 * one byte past the end of the mapping that can be accessed and
2655c51f124SMoriah Waterland 		 * that is guaranteed to be zero.
2665c51f124SMoriah Waterland 		 */
2675c51f124SMoriah Waterland 
2685c51f124SMoriah Waterland 		/* allocate backing space */
2695c51f124SMoriah Waterland 
2705c51f124SMoriah Waterland 		p = (char *)memalign(pagesize, vfp->_vfpSize);
2715c51f124SMoriah Waterland 		if (p == (char *)NULL) {
2725c51f124SMoriah Waterland 			vfp->_vfpStart = MAP_FAILED;
2735c51f124SMoriah Waterland 		} else {
2745c51f124SMoriah Waterland 			/* guarantee first byte after end of data is zero */
2755c51f124SMoriah Waterland 
2765c51f124SMoriah Waterland 			p[vfp->_vfpMapSize] = '\0';
2775c51f124SMoriah Waterland 
2785c51f124SMoriah Waterland 			/* map file on top of the backing space */
2795c51f124SMoriah Waterland 
2805c51f124SMoriah Waterland 			vfp->_vfpStart = mmap(p, vfp->_vfpMapSize, PROT_READ,
2815c51f124SMoriah Waterland 				MAP_PRIVATE|MAP_FIXED, fileno(fp), (off_t)0);
2825c51f124SMoriah Waterland 
2835c51f124SMoriah Waterland 			/* if mmap succeeded set mmap used flag in vfp */
2845c51f124SMoriah Waterland 
2855c51f124SMoriah Waterland 			if (vfp->_vfpStart != MAP_FAILED) {
2865c51f124SMoriah Waterland 				vfp->_vfpFlags |= _VFP_MMAP;
2875c51f124SMoriah Waterland 			}
2885c51f124SMoriah Waterland 		}
2895c51f124SMoriah Waterland 	}
2905c51f124SMoriah Waterland 
2915c51f124SMoriah Waterland 	/* if map failed (or not allowed) attempt malloc (if allowed) */
2925c51f124SMoriah Waterland 
2935c51f124SMoriah Waterland 	if ((vfp->_vfpStart == MAP_FAILED) && (!(a_flags & VFP_NOMALLOC))) {
2945c51f124SMoriah Waterland 		/* mmap failed - plan b: read directly into memory */
2955c51f124SMoriah Waterland 		ssize_t	rlen;
2965c51f124SMoriah Waterland 
2975c51f124SMoriah Waterland 		/*
2985c51f124SMoriah Waterland 		 * compute proper size for allocating storage for file contents;
2995c51f124SMoriah Waterland 		 * add in one extra page so falling off end when file size is
3005c51f124SMoriah Waterland 		 * exactly modulo page size does not cause a page fault to
3015c51f124SMoriah Waterland 		 * guarantee that the end of the file contents will always
3025c51f124SMoriah Waterland 		 * contain a '\0' null character.
3035c51f124SMoriah Waterland 		 */
3045c51f124SMoriah Waterland 
3055c51f124SMoriah Waterland 		vfp->_vfpSize = statbuf.st_size+pagesize;
3065c51f124SMoriah Waterland 
3075c51f124SMoriah Waterland 		/* allocate buffer to hold file data */
3085c51f124SMoriah Waterland 
3095c51f124SMoriah Waterland 		vfp->_vfpStart = memalign((size_t)pagesize, vfp->_vfpSize);
3105c51f124SMoriah Waterland 		if (vfp->_vfpStart == (char *)NULL) {
3115c51f124SMoriah Waterland 			lerrno = errno;
3125c51f124SMoriah Waterland 			(void) fclose(fp);
3135c51f124SMoriah Waterland 			(void) free(vfp);
3145c51f124SMoriah Waterland 			errno = lerrno;
3155c51f124SMoriah Waterland 			return (-1);
3165c51f124SMoriah Waterland 		}
3175c51f124SMoriah Waterland 
3185c51f124SMoriah Waterland 		/* read the file into the buffer */
3195c51f124SMoriah Waterland 
3205c51f124SMoriah Waterland 		if (statbuf.st_size != 0) {
3215c51f124SMoriah Waterland 			rlen = read(fileno(fp), vfp->_vfpStart,
3225c51f124SMoriah Waterland 							statbuf.st_size);
3235c51f124SMoriah Waterland 			if (rlen != statbuf.st_size) {
3245c51f124SMoriah Waterland 				lerrno = errno;
3255c51f124SMoriah Waterland 				if (lerrno == 0) {
3265c51f124SMoriah Waterland 					lerrno = EIO;
3275c51f124SMoriah Waterland 				}
3285c51f124SMoriah Waterland 				(void) free(vfp->_vfpStart);
3295c51f124SMoriah Waterland 				(void) fclose(fp);
3305c51f124SMoriah Waterland 				(void) free(vfp);
3315c51f124SMoriah Waterland 				errno = lerrno;
3325c51f124SMoriah Waterland 				return (-1);
3335c51f124SMoriah Waterland 			}
3345c51f124SMoriah Waterland 
3355c51f124SMoriah Waterland 			/* assure last byte+1 is null character */
3365c51f124SMoriah Waterland 
3375c51f124SMoriah Waterland 			((char *)vfp->_vfpStart)[statbuf.st_size] = '\0';
3385c51f124SMoriah Waterland 		}
3395c51f124SMoriah Waterland 
3405c51f124SMoriah Waterland 		/* set malloc used flag in vfp */
3415c51f124SMoriah Waterland 
3425c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_MALLOC;
3435c51f124SMoriah Waterland 	}
3445c51f124SMoriah Waterland 
3455c51f124SMoriah Waterland 	/* if no starting address all read methods failed */
3465c51f124SMoriah Waterland 
3475c51f124SMoriah Waterland 	if (vfp->_vfpStart == MAP_FAILED) {
3485c51f124SMoriah Waterland 		/* no mmap() - no read() - cannot allocate memory */
3495c51f124SMoriah Waterland 		(void) fclose(fp);
3505c51f124SMoriah Waterland 		(void) free(vfp);
3515c51f124SMoriah Waterland 		errno = ENOMEM;
3525c51f124SMoriah Waterland 		return (-1);
3535c51f124SMoriah Waterland 	}
3545c51f124SMoriah Waterland 
3555c51f124SMoriah Waterland 	/*
3565c51f124SMoriah Waterland 	 * initialize vfp contents
3575c51f124SMoriah Waterland 	 */
3585c51f124SMoriah Waterland 
3595c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
3605c51f124SMoriah Waterland 	vfp->_vfpCurr = (char *)vfp->_vfpStart;
3615c51f124SMoriah Waterland 
3625c51f124SMoriah Waterland 	/* _vfpEnd -> last data byte */
3635c51f124SMoriah Waterland 	vfp->_vfpEnd = (((char *)vfp->_vfpStart) + statbuf.st_size)-1;
3645c51f124SMoriah Waterland 
3655c51f124SMoriah Waterland 	/* _vfpHighWater -> last byte written */
3665c51f124SMoriah Waterland 	vfp->_vfpHighWater = (char *)vfp->_vfpEnd;
3675c51f124SMoriah Waterland 
3685c51f124SMoriah Waterland 	/* _vfpFile -> associated FILE* object */
3695c51f124SMoriah Waterland 	vfp->_vfpFile = fp;
3705c51f124SMoriah Waterland 
3715c51f124SMoriah Waterland 	/* set flags as appropriate */
3725c51f124SMoriah Waterland 
3735c51f124SMoriah Waterland 	(void) vfpSetFlags(vfp, a_flags);
3745c51f124SMoriah Waterland 
3755c51f124SMoriah Waterland 	/* retain path name */
3765c51f124SMoriah Waterland 
3775c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path ? a_path : "");
3785c51f124SMoriah Waterland 
3795c51f124SMoriah Waterland 	/* set read/write flags */
3805c51f124SMoriah Waterland 
3815c51f124SMoriah Waterland 	if (*a_mode == 'w') {
3825c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_WRITE;
3835c51f124SMoriah Waterland 	}
3845c51f124SMoriah Waterland 
3855c51f124SMoriah Waterland 	if (*a_mode == 'r') {
3865c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_READ;
3875c51f124SMoriah Waterland 	}
3885c51f124SMoriah Waterland 
3895c51f124SMoriah Waterland 	/* set return vfp pointer */
3905c51f124SMoriah Waterland 
3915c51f124SMoriah Waterland 	(*r_vfp) = vfp;
3925c51f124SMoriah Waterland 
3935c51f124SMoriah Waterland 	/* All OK */
3945c51f124SMoriah Waterland 
3955c51f124SMoriah Waterland 	return (0);
3965c51f124SMoriah Waterland }
3975c51f124SMoriah Waterland 
3985c51f124SMoriah Waterland /*
3995c51f124SMoriah Waterland  * Name:	vfpClose
4005c51f124SMoriah Waterland  * Description:	Close an open vfp, causing any modified data to be written out
4015c51f124SMoriah Waterland  *		to the file associated with the vfp.
4025c51f124SMoriah Waterland  * Arguments:	VFP_T **r_vfp - pointer to pointer to VFP_T returned by vfpOpen
4035c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
4045c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
4055c51f124SMoriah Waterland  * Side Effects: r_vfp is set to (VFP_T)NULL
4065c51f124SMoriah Waterland  */
4075c51f124SMoriah Waterland 
4085c51f124SMoriah Waterland int
4095c51f124SMoriah Waterland vfpClose(VFP_T **r_vfp)
4105c51f124SMoriah Waterland {
4115c51f124SMoriah Waterland 	int	ret;
4125c51f124SMoriah Waterland 	int	lerrno;
4135c51f124SMoriah Waterland 	VFP_T	*vfp;
4145c51f124SMoriah Waterland 
4155c51f124SMoriah Waterland 	/* return error if NULL VFP_T** provided */
4165c51f124SMoriah Waterland 
4175c51f124SMoriah Waterland 	if (r_vfp == (VFP_T **)NULL) {
4185c51f124SMoriah Waterland 		errno = EFAULT;
4195c51f124SMoriah Waterland 		return (-1);
4205c51f124SMoriah Waterland 	}
4215c51f124SMoriah Waterland 
4225c51f124SMoriah Waterland 	/* localize access to VFP_T */
4235c51f124SMoriah Waterland 
4245c51f124SMoriah Waterland 	vfp = *r_vfp;
4255c51f124SMoriah Waterland 
4265c51f124SMoriah Waterland 	/* return successful if NULL VFP_T* provided */
4275c51f124SMoriah Waterland 
4285c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
4295c51f124SMoriah Waterland 		return (0);
4305c51f124SMoriah Waterland 	}
4315c51f124SMoriah Waterland 
4325c51f124SMoriah Waterland 	/* reset return VFP_T* handle */
4335c51f124SMoriah Waterland 
4345c51f124SMoriah Waterland 	*r_vfp = (VFP_T *)NULL;
4355c51f124SMoriah Waterland 
4365c51f124SMoriah Waterland 	/*
4375c51f124SMoriah Waterland 	 * if closing a file that is open for writing, commit all data if the
4385c51f124SMoriah Waterland 	 * backing memory is volatile and if there is a file open to write
4395c51f124SMoriah Waterland 	 * the data to.
4405c51f124SMoriah Waterland 	 */
4415c51f124SMoriah Waterland 
4425c51f124SMoriah Waterland 	if (vfp->_vfpFlags & _VFP_WRITE) {
4435c51f124SMoriah Waterland 		if ((vfp->_vfpFlags & _VFP_MALLOC) &&
4445c51f124SMoriah Waterland 				(vfp->_vfpFile != (FILE *)NULL)) {
4455c51f124SMoriah Waterland 			size_t	len;
4465c51f124SMoriah Waterland 
4475c51f124SMoriah Waterland 			/* determine number of bytes to write */
4485c51f124SMoriah Waterland 			len = vfpGetModifiedLen(vfp);
4495c51f124SMoriah Waterland 
4505c51f124SMoriah Waterland 			/* if modified bytes present commit data to the file */
4515c51f124SMoriah Waterland 			if (len > 0) {
4525c51f124SMoriah Waterland 				(void) vfpSafePwrite(fileno(vfp->_vfpFile),
4535c51f124SMoriah Waterland 						vfp->_vfpStart, len, (off_t)0);
4545c51f124SMoriah Waterland 			}
4555c51f124SMoriah Waterland 		}
4565c51f124SMoriah Waterland 	}
4575c51f124SMoriah Waterland 
4585c51f124SMoriah Waterland 	/* deallocate any allocated storage/mappings/etc */
4595c51f124SMoriah Waterland 
4605c51f124SMoriah Waterland 	if (vfp->_vfpFlags & _VFP_MALLOC) {
4615c51f124SMoriah Waterland 		(void) free(vfp->_vfpStart);
4625c51f124SMoriah Waterland 	} else if (vfp->_vfpFlags & _VFP_MMAP) {
4635c51f124SMoriah Waterland 		/* unmap the file mapping */
4645c51f124SMoriah Waterland 
4655c51f124SMoriah Waterland 		(void) munmap(vfp->_vfpStart, vfp->_vfpMapSize);
4665c51f124SMoriah Waterland 
4675c51f124SMoriah Waterland 		/* free the backing allocation */
4685c51f124SMoriah Waterland 
4695c51f124SMoriah Waterland 		(void) free(vfp->_vfpStart);
4705c51f124SMoriah Waterland 	}
4715c51f124SMoriah Waterland 
4725c51f124SMoriah Waterland 	/* free up path */
4735c51f124SMoriah Waterland 
4745c51f124SMoriah Waterland 	(void) free(vfp->_vfpPath);
4755c51f124SMoriah Waterland 
4765c51f124SMoriah Waterland 	/* close the file */
4775c51f124SMoriah Waterland 
4785c51f124SMoriah Waterland 	ret = 0;
4795c51f124SMoriah Waterland 	if (vfp->_vfpFile != (FILE *)NULL) {
4805c51f124SMoriah Waterland 		ret = fclose(vfp->_vfpFile);
4815c51f124SMoriah Waterland 		lerrno = errno;
4825c51f124SMoriah Waterland 	}
4835c51f124SMoriah Waterland 
4845c51f124SMoriah Waterland 	/* deallocate the vfp itself */
4855c51f124SMoriah Waterland 
4865c51f124SMoriah Waterland 	(void) free(vfp);
4875c51f124SMoriah Waterland 
4885c51f124SMoriah Waterland 	/* if the fclose() failed, return error and errno */
4895c51f124SMoriah Waterland 
4905c51f124SMoriah Waterland 	if (ret != 0) {
4915c51f124SMoriah Waterland 		errno = lerrno;
4925c51f124SMoriah Waterland 		return (-1);
4935c51f124SMoriah Waterland 	}
4945c51f124SMoriah Waterland 
4955c51f124SMoriah Waterland 	return (0);
4965c51f124SMoriah Waterland }
4975c51f124SMoriah Waterland 
4985c51f124SMoriah Waterland /*
4995c51f124SMoriah Waterland  * Name:	vfpSetFlags
5005c51f124SMoriah Waterland  * Description:	Modify operation of VFP according to flags specified
5015c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set flags
5025c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
5035c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
5045c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - file data sequentially accessed
5055c51f124SMoriah Waterland  *			- VFP_RANDOM - file data randomly accessed
5065c51f124SMoriah Waterland  *			Any other flags specified are silently ignored.
5075c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
5085c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
5095c51f124SMoriah Waterland  */
5105c51f124SMoriah Waterland 
5115c51f124SMoriah Waterland int
5125c51f124SMoriah Waterland vfpSetFlags(VFP_T *a_vfp, VFPFLAGS_T a_flags)
5135c51f124SMoriah Waterland {
5145c51f124SMoriah Waterland 	/* return if no vfp specified */
5155c51f124SMoriah Waterland 
5165c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
5175c51f124SMoriah Waterland 		return (0);
5185c51f124SMoriah Waterland 	}
5195c51f124SMoriah Waterland 
5205c51f124SMoriah Waterland 	/* if file data mapped into memory, apply vm flags */
5215c51f124SMoriah Waterland 
5225c51f124SMoriah Waterland 	if ((a_vfp->_vfpSize != 0) && (a_vfp->_vfpFlags & _VFP_MMAP)) {
5235c51f124SMoriah Waterland 		/* mmap succeeded: properly advise vm system */
5245c51f124SMoriah Waterland 
5255c51f124SMoriah Waterland 		if (a_flags & VFP_NEEDNOW) {
5265c51f124SMoriah Waterland 			/* advise vm system data is needed now */
5275c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpMapSize,
5285c51f124SMoriah Waterland 							MADV_WILLNEED);
5295c51f124SMoriah Waterland 		}
5305c51f124SMoriah Waterland 		if (a_flags & VFP_SEQUENTIAL) {
5315c51f124SMoriah Waterland 			/* advise vm system data access is sequential */
5325c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpSize,
5335c51f124SMoriah Waterland 							MADV_SEQUENTIAL);
5345c51f124SMoriah Waterland 		}
5355c51f124SMoriah Waterland 		if (a_flags & VFP_RANDOM) {
5365c51f124SMoriah Waterland 			/* advise vm system data access is random */
5375c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpSize,
5385c51f124SMoriah Waterland 							MADV_RANDOM);
5395c51f124SMoriah Waterland 		}
5405c51f124SMoriah Waterland 	}
5415c51f124SMoriah Waterland 
5425c51f124SMoriah Waterland 	return (0);
5435c51f124SMoriah Waterland }
5445c51f124SMoriah Waterland 
5455c51f124SMoriah Waterland /*
5465c51f124SMoriah Waterland  * Name:	vfpRewind
5475c51f124SMoriah Waterland  * Description:	Reset default pointer for next read/write to start of file data
5485c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to rewind
5495c51f124SMoriah Waterland  * Returns:	void
5505c51f124SMoriah Waterland  *			Operation is always successful
5515c51f124SMoriah Waterland  */
5525c51f124SMoriah Waterland 
5535c51f124SMoriah Waterland void
5545c51f124SMoriah Waterland vfpRewind(VFP_T *a_vfp)
5555c51f124SMoriah Waterland {
5565c51f124SMoriah Waterland 	/* return if no vfp specified */
5575c51f124SMoriah Waterland 
5585c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
5595c51f124SMoriah Waterland 		return;
5605c51f124SMoriah Waterland 	}
5615c51f124SMoriah Waterland 
5625c51f124SMoriah Waterland 	/* set high water mark of last modified data */
5635c51f124SMoriah Waterland 
5645c51f124SMoriah Waterland 	if (a_vfp->_vfpCurr > a_vfp->_vfpHighWater) {
5655c51f124SMoriah Waterland 		a_vfp->_vfpHighWater = a_vfp->_vfpCurr;
5665c51f124SMoriah Waterland 	}
5675c51f124SMoriah Waterland 
5685c51f124SMoriah Waterland 	/* reset next character pointer to start of file data */
5695c51f124SMoriah Waterland 
5705c51f124SMoriah Waterland 	a_vfp->_vfpCurr = a_vfp->_vfpStart;
5715c51f124SMoriah Waterland }
5725c51f124SMoriah Waterland 
5735c51f124SMoriah Waterland /*
5745c51f124SMoriah Waterland  * Name:	vfpSetSize
5755c51f124SMoriah Waterland  * Description:	Set size of in-memory image associated with VFP
5765c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set
5775c51f124SMoriah Waterland  *		size_t a_size - number of bytes to associatge with VFP
5785c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
5795c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
5805c51f124SMoriah Waterland  * Side Effects:
5815c51f124SMoriah Waterland  *		Currently only a file that is in malloc()ed memory can
5825c51f124SMoriah Waterland  *		have its in-memory size changed.
5835c51f124SMoriah Waterland  *		An error is returned If the file is mapped into memory.
5845c51f124SMoriah Waterland  *		A file cannot be decreased in size - if the specified
5855c51f124SMoriah Waterland  *		size is less than the current size, the operation is
5865c51f124SMoriah Waterland  *		successful but no change in file size occurs.
5875c51f124SMoriah Waterland  *		If no file is associated with the VFP (no "name" was
5885c51f124SMoriah Waterland  *		given to vfpOpen) the first call to vfpSetSize allocates
5895c51f124SMoriah Waterland  *		the initial size of the file data - effectively calling
5905c51f124SMoriah Waterland  *		"malloc" to allocate the initial memory for the file data.
5915c51f124SMoriah Waterland  *		Once an initial allocation has been made, subsequent calls
5925c51f124SMoriah Waterland  *		to vfpSetSize are effectively a "realloc" of the existing
5935c51f124SMoriah Waterland  *		file data.
5945c51f124SMoriah Waterland  *		All existing file data is preserved.
5955c51f124SMoriah Waterland  */
5965c51f124SMoriah Waterland 
5975c51f124SMoriah Waterland int
5985c51f124SMoriah Waterland vfpSetSize(VFP_T *a_vfp, size_t a_size)
5995c51f124SMoriah Waterland {
6005c51f124SMoriah Waterland 	char	*np;
6015c51f124SMoriah Waterland 	size_t	curSize;
6025c51f124SMoriah Waterland 
6035c51f124SMoriah Waterland 	/* return if no vfp specified */
6045c51f124SMoriah Waterland 
6055c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
6065c51f124SMoriah Waterland 		return (0);
6075c51f124SMoriah Waterland 	}
6085c51f124SMoriah Waterland 
6095c51f124SMoriah Waterland 	/* if malloc not used don't know how to set size right now */
6105c51f124SMoriah Waterland 
6115c51f124SMoriah Waterland 	if (!(a_vfp->_vfpFlags & _VFP_MALLOC)) {
6125c51f124SMoriah Waterland 		return (-1);
6135c51f124SMoriah Waterland 	}
6145c51f124SMoriah Waterland 
6155c51f124SMoriah Waterland 	/* adjust size to reflect extra page of data maintained */
6165c51f124SMoriah Waterland 
6175c51f124SMoriah Waterland 	a_size += getpagesize();
6185c51f124SMoriah Waterland 
6195c51f124SMoriah Waterland 	/* if size is not larger than current nothing to do */
6205c51f124SMoriah Waterland 
6215c51f124SMoriah Waterland 	if (a_size <= a_vfp->_vfpSize) {
6225c51f124SMoriah Waterland 		return (0);
6235c51f124SMoriah Waterland 	}
6245c51f124SMoriah Waterland 
6255c51f124SMoriah Waterland 	/* remember new size */
6265c51f124SMoriah Waterland 
6275c51f124SMoriah Waterland 	curSize = a_vfp->_vfpSize;
6285c51f124SMoriah Waterland 	a_vfp->_vfpSize = a_size;
6295c51f124SMoriah Waterland 
6305c51f124SMoriah Waterland 	/* allocate/reallocate memory as appropriate */
6315c51f124SMoriah Waterland 
6325c51f124SMoriah Waterland 	if (a_vfp->_vfpStart != (char *)NULL) {
6335c51f124SMoriah Waterland 		np = (char *)realloc(a_vfp->_vfpStart, a_vfp->_vfpSize+1);
6345c51f124SMoriah Waterland 		if (np == (char *)NULL) {
6355c51f124SMoriah Waterland 			return (-1);
6365c51f124SMoriah Waterland 		}
6375c51f124SMoriah Waterland 		np[curSize-1] = '\0';
6385c51f124SMoriah Waterland 	} else {
6395c51f124SMoriah Waterland 		np = (char *)malloc(a_vfp->_vfpSize+1);
6405c51f124SMoriah Waterland 		if (np == (char *)NULL) {
6415c51f124SMoriah Waterland 			return (-1);
6425c51f124SMoriah Waterland 		}
6435c51f124SMoriah Waterland 		np[0] = '\0';
6445c51f124SMoriah Waterland 	}
6455c51f124SMoriah Waterland 
6465c51f124SMoriah Waterland 	/* make sure last allocated byte is a null */
6475c51f124SMoriah Waterland 
6485c51f124SMoriah Waterland 	np[a_vfp->_vfpSize] = '\0';
6495c51f124SMoriah Waterland 
6505c51f124SMoriah Waterland 	/*
6515c51f124SMoriah Waterland 	 * adjust all pointers to account for buffer address change
6525c51f124SMoriah Waterland 	 */
6535c51f124SMoriah Waterland 
6545c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
6555c51f124SMoriah Waterland 	a_vfp->_vfpCurr = (char *)(((ptrdiff_t)a_vfp->_vfpCurr -
6565c51f124SMoriah Waterland 					(ptrdiff_t)a_vfp->_vfpStart) + np);
6575c51f124SMoriah Waterland 
6585c51f124SMoriah Waterland 	/* _vfpHighWater -> last byte written */
6595c51f124SMoriah Waterland 	a_vfp->_vfpHighWater = (char *)(((ptrdiff_t)a_vfp->_vfpHighWater -
6605c51f124SMoriah Waterland 					(ptrdiff_t)a_vfp->_vfpStart) + np);
6615c51f124SMoriah Waterland 
6625c51f124SMoriah Waterland 	/* _vfpEnd -> last data byte */
6635c51f124SMoriah Waterland 	a_vfp->_vfpEnd = (np + a_vfp->_vfpSize)-1;
6645c51f124SMoriah Waterland 
6655c51f124SMoriah Waterland 	/* _vfpStart -> first data byte */
6665c51f124SMoriah Waterland 	a_vfp->_vfpStart = np;
6675c51f124SMoriah Waterland 
6685c51f124SMoriah Waterland 	return (0);
6695c51f124SMoriah Waterland }
6705c51f124SMoriah Waterland 
6715c51f124SMoriah Waterland /*
6725c51f124SMoriah Waterland  * Name:	vfpTruncate
6735c51f124SMoriah Waterland  * Description:	Truncate data associated with VFP
6745c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to truncate
6755c51f124SMoriah Waterland  * Returns:	void
6765c51f124SMoriah Waterland  *			Operation is always successful.
6775c51f124SMoriah Waterland  * Side Effects:
6785c51f124SMoriah Waterland  *		In memory data associated with file is believed to be empty.
6795c51f124SMoriah Waterland  *		Actual memory associated with file is not affected.
6805c51f124SMoriah Waterland  *		If a file is associated with the VFP, it is truncated.
6815c51f124SMoriah Waterland  */
6825c51f124SMoriah Waterland 
6835c51f124SMoriah Waterland void
6845c51f124SMoriah Waterland vfpTruncate(VFP_T *a_vfp)
6855c51f124SMoriah Waterland {
6865c51f124SMoriah Waterland 	/* return if no vfp specified */
6875c51f124SMoriah Waterland 
6885c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
6895c51f124SMoriah Waterland 		return;
6905c51f124SMoriah Waterland 	}
6915c51f124SMoriah Waterland 
6925c51f124SMoriah Waterland 	/*
6935c51f124SMoriah Waterland 	 * reset all pointers so that no data is associated with file
6945c51f124SMoriah Waterland 	 */
6955c51f124SMoriah Waterland 
6965c51f124SMoriah Waterland 	/* current byte is start of data area */
6975c51f124SMoriah Waterland 
6985c51f124SMoriah Waterland 	a_vfp->_vfpCurr = a_vfp->_vfpStart;
6995c51f124SMoriah Waterland 
7005c51f124SMoriah Waterland 	/* last byte written is start of data area */
7015c51f124SMoriah Waterland 
7025c51f124SMoriah Waterland 	a_vfp->_vfpHighWater = a_vfp->_vfpStart;
7035c51f124SMoriah Waterland 
7045c51f124SMoriah Waterland 	/* current character is NULL */
7055c51f124SMoriah Waterland 
7065c51f124SMoriah Waterland 	*a_vfp->_vfpCurr = '\0';
7075c51f124SMoriah Waterland 
7085c51f124SMoriah Waterland 	/* if file associated with VFP, truncate actual file */
7095c51f124SMoriah Waterland 
7105c51f124SMoriah Waterland 	if (a_vfp->_vfpFile != (FILE *)NULL) {
7115c51f124SMoriah Waterland 		(void) ftruncate(fileno(a_vfp->_vfpFile), 0);
7125c51f124SMoriah Waterland 	}
7135c51f124SMoriah Waterland }
7145c51f124SMoriah Waterland 
7155c51f124SMoriah Waterland /*
7165c51f124SMoriah Waterland  * Name:	vfpWriteToFile
7175c51f124SMoriah Waterland  * Description:	Write data associated with VFP to specified file
7185c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to write
7195c51f124SMoriah Waterland  *		char *a_path - path of file to write file data to
7205c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
7215c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
7225c51f124SMoriah Waterland  */
7235c51f124SMoriah Waterland 
7245c51f124SMoriah Waterland int
7255c51f124SMoriah Waterland vfpWriteToFile(VFP_T *a_vfp, char *a_path)
7265c51f124SMoriah Waterland {
7275c51f124SMoriah Waterland 	int	fd;
7285c51f124SMoriah Waterland 	int	lerrno = 0;
7295c51f124SMoriah Waterland 	size_t	len;
7305c51f124SMoriah Waterland 	ssize_t	result = 0;
7315c51f124SMoriah Waterland 
7325c51f124SMoriah Waterland 	/* return if no vfp specified */
7335c51f124SMoriah Waterland 
7345c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
7355c51f124SMoriah Waterland 		errno = EFAULT;
7365c51f124SMoriah Waterland 		return (-1);
7375c51f124SMoriah Waterland 	}
7385c51f124SMoriah Waterland 
7395c51f124SMoriah Waterland 	/* on buffer overflow generate error */
7405c51f124SMoriah Waterland 
7415c51f124SMoriah Waterland 	if ((a_vfp->_vfpOverflow != 0) || (vfpGetBytesAvailable(a_vfp) < 1)) {
7425c51f124SMoriah Waterland 		errno = EFBIG;
7435c51f124SMoriah Waterland 		return (-1);
7445c51f124SMoriah Waterland 	}
7455c51f124SMoriah Waterland 
7465c51f124SMoriah Waterland 	/* open file to write data to */
7475c51f124SMoriah Waterland 
7485c51f124SMoriah Waterland 	fd = open(a_path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
7495c51f124SMoriah Waterland 	if (fd < 0) {
7505c51f124SMoriah Waterland 		return (-1);
7515c51f124SMoriah Waterland 	}
7525c51f124SMoriah Waterland 
7535c51f124SMoriah Waterland 	/* determine number of bytes to write */
7545c51f124SMoriah Waterland 
7555c51f124SMoriah Waterland 	len = vfpGetModifiedLen(a_vfp);
7565c51f124SMoriah Waterland 
7575c51f124SMoriah Waterland 	/*
7585c51f124SMoriah Waterland 	 * if there is data associated with the file, write it out;
7595c51f124SMoriah Waterland 	 * if an error occurs, close the file and return failure.
7605c51f124SMoriah Waterland 	 */
7615c51f124SMoriah Waterland 
7625c51f124SMoriah Waterland 	if (len > 0) {
7635c51f124SMoriah Waterland 		result = vfpSafeWrite(fd, a_vfp->_vfpStart, len);
7645c51f124SMoriah Waterland 		if (result != len) {
7655c51f124SMoriah Waterland 			/* error comitting data - return failure */
7665c51f124SMoriah Waterland 			lerrno = errno;
7675c51f124SMoriah Waterland 			(void) close(fd);
7685c51f124SMoriah Waterland 			errno = lerrno;
7695c51f124SMoriah Waterland 			return (-1);
7705c51f124SMoriah Waterland 		}
7715c51f124SMoriah Waterland 	}
7725c51f124SMoriah Waterland 
7735c51f124SMoriah Waterland 	/* close the file */
7745c51f124SMoriah Waterland 
7755c51f124SMoriah Waterland 	(void) close(fd);
7765c51f124SMoriah Waterland 
7775c51f124SMoriah Waterland 	/* data committed to backing store - clear the modified flag */
7785c51f124SMoriah Waterland 
7795c51f124SMoriah Waterland 	(void) vfpClearModified(a_vfp);
7805c51f124SMoriah Waterland 
7815c51f124SMoriah Waterland 	/* return success */
7825c51f124SMoriah Waterland 
7835c51f124SMoriah Waterland 	return (0);
7845c51f124SMoriah Waterland }
7855c51f124SMoriah Waterland 
7865c51f124SMoriah Waterland /*
7875c51f124SMoriah Waterland  * Name:	vfpCheckpointFile
7885c51f124SMoriah Waterland  * Description:	Create new VFP that checkpoints existing VFP, can be used by
7895c51f124SMoriah Waterland  *		subsequent call to vfpCheckpointOpen to open a file using the
7905c51f124SMoriah Waterland  *		existing in-memory cache of the contents of the file
7915c51f124SMoriah Waterland  * Arguments:	VFP_T **r_cpVfp - pointer to pointer to VFP_T to be filled in
7925c51f124SMoriah Waterland  *			with "checkpointed file" VFP (backing store)
7935c51f124SMoriah Waterland  *		VFP_T **a_vfp - pointer to pointer to VFP_T returned by vfpOpen
7945c51f124SMoriah Waterland  *			representing the VFP to checkpoint
7955c51f124SMoriah Waterland  *		char *a_path - path to file that is the backing store for the
7965c51f124SMoriah Waterland  *			in-memory data represented by a_vfp - used to verify
7975c51f124SMoriah Waterland  *			that the data in memory is not out of date with respect
7985c51f124SMoriah Waterland  *			to the backing store when vfpCheckpointOpen is called
7995c51f124SMoriah Waterland  *			== (char *)NULL - use path associated with a_vfp
8005c51f124SMoriah Waterland  *				that is, the backing store file in use
8015c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
8025c51f124SMoriah Waterland  *				- r_destVfp contains a pointer to a new VFP that
8035c51f124SMoriah Waterland  *					may be used in a subsequent call to
8045c51f124SMoriah Waterland  *					vfpCheckpointOpen
8055c51f124SMoriah Waterland  *				- the VFP referenced by *a_vfp is free()ed and
8065c51f124SMoriah Waterland  *					must no longer be referenced
8075c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
8085c51f124SMoriah Waterland  *				- the VFP referenced by *a_vfp is not affected;
8095c51f124SMoriah Waterland  *					the caller may continue to use it
8105c51f124SMoriah Waterland  * Notes:	If the data of a VFP to checkpoint is mmap()ed then this method
8115c51f124SMoriah Waterland  *			returns failure - only malloc()ed data VFPs can be
8125c51f124SMoriah Waterland  *			checkpointed.
8135c51f124SMoriah Waterland  */
8145c51f124SMoriah Waterland 
8155c51f124SMoriah Waterland int
8165c51f124SMoriah Waterland vfpCheckpointFile(VFP_T **r_cpVfp, VFP_T **a_vfp, char *a_path)
8175c51f124SMoriah Waterland {
8185c51f124SMoriah Waterland 	VFP_T		*vfp;		/* newly allocated checkpointed VFP */
8195c51f124SMoriah Waterland 	VFP_T		*avfp;		/* local -> to a_vfp */
8205c51f124SMoriah Waterland 	struct stat	statbuf;	/* stat(2) info for backing store */
8215c51f124SMoriah Waterland 
8225c51f124SMoriah Waterland 	/* return error if NULL VFP_T** to checkpoint provided */
8235c51f124SMoriah Waterland 
8245c51f124SMoriah Waterland 	if (r_cpVfp == (VFP_T **)NULL) {
8255c51f124SMoriah Waterland 		errno = EFAULT;
8265c51f124SMoriah Waterland 		return (-1);
8275c51f124SMoriah Waterland 	}
8285c51f124SMoriah Waterland 
8295c51f124SMoriah Waterland 	/* reset return checkpoint VFP pointer */
8305c51f124SMoriah Waterland 
8315c51f124SMoriah Waterland 	(*r_cpVfp) = (VFP_T *)NULL;
8325c51f124SMoriah Waterland 
8335c51f124SMoriah Waterland 	/* return error if no VFP to checkpoint specified */
8345c51f124SMoriah Waterland 
8355c51f124SMoriah Waterland 	if (a_vfp == (VFP_T **)NULL) {
8365c51f124SMoriah Waterland 		errno = EFAULT;
8375c51f124SMoriah Waterland 		return (-1);
8385c51f124SMoriah Waterland 	}
8395c51f124SMoriah Waterland 
8405c51f124SMoriah Waterland 	/* localize reference to a_vfp */
8415c51f124SMoriah Waterland 
8425c51f124SMoriah Waterland 	avfp = *a_vfp;
8435c51f124SMoriah Waterland 
8445c51f124SMoriah Waterland 	/* return error if no VFP to checkpoint specified */
8455c51f124SMoriah Waterland 
8465c51f124SMoriah Waterland 	if (avfp == (VFP_T *)NULL) {
8475c51f124SMoriah Waterland 		errno = EFAULT;
8485c51f124SMoriah Waterland 		return (-1);
8495c51f124SMoriah Waterland 	}
8505c51f124SMoriah Waterland 
8515c51f124SMoriah Waterland 	/* on buffer overflow generate error */
8525c51f124SMoriah Waterland 
8535c51f124SMoriah Waterland 	if ((avfp->_vfpOverflow != 0) || (vfpGetBytesAvailable(avfp) < 1)) {
8545c51f124SMoriah Waterland 		errno = EFBIG;
8555c51f124SMoriah Waterland 		return (-1);
8565c51f124SMoriah Waterland 	}
8575c51f124SMoriah Waterland 
8585c51f124SMoriah Waterland 	/* no checkpointing is possible if the existing VFP is mmap()ed */
8595c51f124SMoriah Waterland 
8605c51f124SMoriah Waterland 	if (avfp->_vfpFlags & _VFP_MMAP) {
8615c51f124SMoriah Waterland 		errno = EIO;
8625c51f124SMoriah Waterland 		return (-1);
8635c51f124SMoriah Waterland 	}
8645c51f124SMoriah Waterland 
8655c51f124SMoriah Waterland 	/* if no path specified, grab it from the VFP to checkpoint */
8665c51f124SMoriah Waterland 
8675c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) || (*a_path == '\0')) {
8685c51f124SMoriah Waterland 		a_path = avfp->_vfpPath;
8695c51f124SMoriah Waterland 	}
8705c51f124SMoriah Waterland 
8715c51f124SMoriah Waterland 	/* backing store required: if VFP is "string" then this is an error */
8725c51f124SMoriah Waterland 
8735c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) ||
8745c51f124SMoriah Waterland 				strcmp(a_path, VFP_ANONYMOUS_PATH) == 0) {
8755c51f124SMoriah Waterland 		errno = EINVAL;
8765c51f124SMoriah Waterland 		return (-1);
8775c51f124SMoriah Waterland 	}
8785c51f124SMoriah Waterland 
8795c51f124SMoriah Waterland 	/* Get the VFP to checkpoint (backing store) file size */
8805c51f124SMoriah Waterland 
8815c51f124SMoriah Waterland 	if (stat(a_path, &statbuf) != 0) {
8825c51f124SMoriah Waterland 		return (-1);
8835c51f124SMoriah Waterland 	}
8845c51f124SMoriah Waterland 
8855c51f124SMoriah Waterland 	/* allocate storage for checkpointed VFP (to return) */
8865c51f124SMoriah Waterland 
8875c51f124SMoriah Waterland 	vfp = (VFP_T *)malloc(sizeof (VFP_T));
8885c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
8895c51f124SMoriah Waterland 		return (-1);
8905c51f124SMoriah Waterland 	}
8915c51f124SMoriah Waterland 
8925c51f124SMoriah Waterland 	/*
8935c51f124SMoriah Waterland 	 * close any file that is on the VFP to checkpoint (backing store);
8945c51f124SMoriah Waterland 	 * subsequent processes can modify the backing store data, and
8955c51f124SMoriah Waterland 	 * then when vfpCheckpointOpen is called, either the in-memory
8965c51f124SMoriah Waterland 	 * cached data will be used (if backing store unmodified) or else
8975c51f124SMoriah Waterland 	 * the in-memory data is released and the backing store is used.
8985c51f124SMoriah Waterland 	 */
8995c51f124SMoriah Waterland 
9005c51f124SMoriah Waterland 	if (avfp->_vfpFile != (FILE *)NULL) {
9015c51f124SMoriah Waterland 		(void) fclose(avfp->_vfpFile);
9025c51f124SMoriah Waterland 		avfp->_vfpFile = (FILE *)NULL;
9035c51f124SMoriah Waterland 	}
9045c51f124SMoriah Waterland 
9055c51f124SMoriah Waterland 	/* free any path associated with VFP to checkpoint (backing store) */
9065c51f124SMoriah Waterland 
9075c51f124SMoriah Waterland 	if (avfp->_vfpPath != (char *)NULL) {
9085c51f124SMoriah Waterland 		(void) free(avfp->_vfpPath);
9095c51f124SMoriah Waterland 		avfp->_vfpPath = (char *)NULL;
9105c51f124SMoriah Waterland 	}
9115c51f124SMoriah Waterland 
9125c51f124SMoriah Waterland 	/* copy contents of VFP to checkpoint to checkpointed VFP */
9135c51f124SMoriah Waterland 
914*4656d474SGarrett D'Amore 	(void) memcpy(vfp, avfp, sizeof (VFP_T));
9155c51f124SMoriah Waterland 
9165c51f124SMoriah Waterland 	/* free contents of VFP to checkpoint */
9175c51f124SMoriah Waterland 
9185c51f124SMoriah Waterland 	(void) free(avfp);
9195c51f124SMoriah Waterland 
9205c51f124SMoriah Waterland 	/* reset pointer to VFP that has been free'd */
9215c51f124SMoriah Waterland 
9225c51f124SMoriah Waterland 	*a_vfp = (VFP_T *)NULL;
9235c51f124SMoriah Waterland 
9245c51f124SMoriah Waterland 	/* remember path associated with the checkpointed VFP (backing store) */
9255c51f124SMoriah Waterland 
9265c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path);
9275c51f124SMoriah Waterland 
9285c51f124SMoriah Waterland 	/* save tokens that identify the backing store for the in-memory data */
9295c51f124SMoriah Waterland 
9305c51f124SMoriah Waterland 	vfp->_vfpCkDev = statbuf.st_dev;	/* devid holding st_ino inode */
9315c51f124SMoriah Waterland 	vfp->_vfpCkIno = statbuf.st_ino;	/* backing store inode */
9325c51f124SMoriah Waterland 	vfp->_vfpCkMtime = statbuf.st_mtime;	/* last data modification */
9335c51f124SMoriah Waterland 	vfp->_vfpCkSize = statbuf.st_size;	/* backing store size (bytes) */
9345c51f124SMoriah Waterland 	vfp->_vfpCkStBlocks = statbuf.st_blocks; /* blocks allocated to file */
9355c51f124SMoriah Waterland 
9365c51f124SMoriah Waterland 	/* pass checkpointed VFP to caller */
9375c51f124SMoriah Waterland 
9385c51f124SMoriah Waterland 	(*r_cpVfp) = vfp;
9395c51f124SMoriah Waterland 
9405c51f124SMoriah Waterland 	/* success! */
9415c51f124SMoriah Waterland 
9425c51f124SMoriah Waterland 	return (0);
9435c51f124SMoriah Waterland }
9445c51f124SMoriah Waterland 
9455c51f124SMoriah Waterland /*
9465c51f124SMoriah Waterland  * Name:	vfpCheckpointOpen
9475c51f124SMoriah Waterland  * Description:	Open file on vfp, allocate storage, return pointer to VFP_T
9485c51f124SMoriah Waterland  *		that can be used to access/modify file contents. If a VFP_T to
9495c51f124SMoriah Waterland  *		a checkpointed VFP is passed in, and the in memory contents of
9505c51f124SMoriah Waterland  *		the VFP are not out of date with respect to the backing store
9515c51f124SMoriah Waterland  *		file, use the existing in-memory contents - otherwise, discard
9525c51f124SMoriah Waterland  *		the in-memory contents and reopen and reread the file.
9535c51f124SMoriah Waterland  * Arguments:	VFP_T **a_cpVfp - pointer to pointer to VFP_T that represents
9545c51f124SMoriah Waterland  *			checkpointed VFP to use to open the file IF the contents
9555c51f124SMoriah Waterland  *			of the backing store are identical to the in-memory data
9565c51f124SMoriah Waterland  *		VFP_T **r_vfp - pointer to pointer to VFP_T to open file on
9575c51f124SMoriah Waterland  *		char *a_path - path of file to open and associate with this VFP.
9585c51f124SMoriah Waterland  *			- if the path is (char *)NULL then no file is associated
9595c51f124SMoriah Waterland  *			  with this VFP - this is a way to create a fixed length
9605c51f124SMoriah Waterland  *			  string that can be manipulated with the VFP operators.
9615c51f124SMoriah Waterland  *			  Before the VFP can be used "vfpSetSize" must be called
9625c51f124SMoriah Waterland  *			  to set the size of the string buffer.
9635c51f124SMoriah Waterland  *		char *a_mode - fopen mode to open the file with
9645c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
9655c51f124SMoriah Waterland  *			- VFP_NONE - no special flags
9665c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
9675c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - memory will be sequentially accessed
9685c51f124SMoriah Waterland  *			- VFP_RANDOM - memory will be randomly accessed
9695c51f124SMoriah Waterland  *			- VFP_NOMMAP - do not use mmap to access file
9705c51f124SMoriah Waterland  *			- VFP_NOMALLOC - do not use malloc to buffer file
9715c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
9725c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
9735c51f124SMoriah Waterland  * Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
9745c51f124SMoriah Waterland  *			which can be used with the various VFP functions.
9755c51f124SMoriah Waterland  *		a_cpVfp -- contents reset to zero if used to open the file
9765c51f124SMoriah Waterland  *		errno -- contains system error number if return is != 0
9775c51f124SMoriah Waterland  */
9785c51f124SMoriah Waterland 
9795c51f124SMoriah Waterland int
9805c51f124SMoriah Waterland vfpCheckpointOpen(VFP_T **a_cpVfp, VFP_T **r_vfp, char *a_path,
9815c51f124SMoriah Waterland 	char *a_mode, VFPFLAGS_T a_flags)
9825c51f124SMoriah Waterland {
9835c51f124SMoriah Waterland 	FILE		*fp;	/* backing store */
9845c51f124SMoriah Waterland 	VFP_T		*cpVfp;	/* local -> to a_cpVfp checkpointed VFP */
9855c51f124SMoriah Waterland 	VFP_T		*vfp;	/* new VFP open on checkpointed backing store */
9865c51f124SMoriah Waterland 	struct stat	statbuf; /* stat(2) info on backing store */
9875c51f124SMoriah Waterland 
9885c51f124SMoriah Waterland 	/*
9895c51f124SMoriah Waterland 	 * if no source VFP, or source VFP empty,
9905c51f124SMoriah Waterland 	 * or no backing store, just open file
9915c51f124SMoriah Waterland 	 */
9925c51f124SMoriah Waterland 
9935c51f124SMoriah Waterland 	if ((a_cpVfp == (VFP_T **)NULL) || (*a_cpVfp == (VFP_T *)NULL) ||
9945c51f124SMoriah Waterland 		((*a_cpVfp)->_vfpStart == (char *)NULL)) {
9955c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
9965c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
9975c51f124SMoriah Waterland 	}
9985c51f124SMoriah Waterland 
9995c51f124SMoriah Waterland 	/* localize access to checkpointed VFP_T (*a_cpVfp) */
10005c51f124SMoriah Waterland 
10015c51f124SMoriah Waterland 	cpVfp = *a_cpVfp;
10025c51f124SMoriah Waterland 
10035c51f124SMoriah Waterland 	/* if no path specified, grab it from the checkpointed VFP */
10045c51f124SMoriah Waterland 
10055c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) || (*a_path == '\0')) {
10065c51f124SMoriah Waterland 		a_path = cpVfp->_vfpPath;
10075c51f124SMoriah Waterland 	}
10085c51f124SMoriah Waterland 
10095c51f124SMoriah Waterland 	/* return error if no path specified and no path in checkpointed VFP */
10105c51f124SMoriah Waterland 
10115c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) && (*a_path == '\0')) {
10125c51f124SMoriah Waterland 		errno = EINVAL;
10135c51f124SMoriah Waterland 		return (-1);
10145c51f124SMoriah Waterland 	}
10155c51f124SMoriah Waterland 
10165c51f124SMoriah Waterland 	/* if no backing store path, then just open file */
10175c51f124SMoriah Waterland 
10185c51f124SMoriah Waterland 	if (stat(a_path, &statbuf) != 0) {
10195c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
10205c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
10215c51f124SMoriah Waterland 	}
10225c51f124SMoriah Waterland 
10235c51f124SMoriah Waterland 	/*
10245c51f124SMoriah Waterland 	 * if backing store tokens do not match checkpointed VFP,
10255c51f124SMoriah Waterland 	 * the backing store has been updated since the VFP was checkpointed;
10265c51f124SMoriah Waterland 	 * release the in-memory data, and open and read the backing store
10275c51f124SMoriah Waterland 	 */
10285c51f124SMoriah Waterland 
10295c51f124SMoriah Waterland 	if ((statbuf.st_size != cpVfp->_vfpCkSize) ||
10305c51f124SMoriah Waterland 		(statbuf.st_mtime != cpVfp->_vfpCkMtime) ||
10315c51f124SMoriah Waterland 		(statbuf.st_blocks != cpVfp->_vfpCkStBlocks) ||
10325c51f124SMoriah Waterland 		(statbuf.st_ino != cpVfp->_vfpCkIno) ||
10335c51f124SMoriah Waterland 		(statbuf.st_dev != cpVfp->_vfpCkDev)) {
10345c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
10355c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
10365c51f124SMoriah Waterland 	}
10375c51f124SMoriah Waterland 
10385c51f124SMoriah Waterland 	/*
10395c51f124SMoriah Waterland 	 * backing store has not been updated since the VFP was checkpointed;
10405c51f124SMoriah Waterland 	 * use the in-memory data without re-reading the backing store; open the
10415c51f124SMoriah Waterland 	 * backing store file (if no file already open on the checkpointed VFP)
10425c51f124SMoriah Waterland 	 * so there is an open file associated with the in-memory data
10435c51f124SMoriah Waterland 	 */
10445c51f124SMoriah Waterland 
10455c51f124SMoriah Waterland 	fp = cpVfp->_vfpFile;
10465c51f124SMoriah Waterland 	if (fp == (FILE *)NULL) {
10475c51f124SMoriah Waterland 		fp = fopen(a_path, a_mode);
10485c51f124SMoriah Waterland 		if (fp == (FILE *)NULL) {
10495c51f124SMoriah Waterland 			int	lerrno;
10505c51f124SMoriah Waterland 
10515c51f124SMoriah Waterland 			lerrno = errno;
10525c51f124SMoriah Waterland 			(void) vfpClose(a_cpVfp);
10535c51f124SMoriah Waterland 			errno = lerrno;
10545c51f124SMoriah Waterland 			return (-1);
10555c51f124SMoriah Waterland 		}
10565c51f124SMoriah Waterland 	}
10575c51f124SMoriah Waterland 
10585c51f124SMoriah Waterland 	/* allocate new VFP object to return as open VFP */
10595c51f124SMoriah Waterland 
10605c51f124SMoriah Waterland 	vfp = (VFP_T *)malloc(sizeof (VFP_T));
10615c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
10625c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
10635c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
10645c51f124SMoriah Waterland 	}
10655c51f124SMoriah Waterland 
10665c51f124SMoriah Waterland 	/* copy cached checkpointed VFP to new VFP to return */
10675c51f124SMoriah Waterland 
10685c51f124SMoriah Waterland 	(void) memcpy(vfp, cpVfp, sizeof (VFP_T));
10695c51f124SMoriah Waterland 
10705c51f124SMoriah Waterland 	/*
10715c51f124SMoriah Waterland 	 * initialize VFP to return contents
10725c51f124SMoriah Waterland 	 */
10735c51f124SMoriah Waterland 
10745c51f124SMoriah Waterland 	/* FILE -> file opened on the VFPs backing store */
10755c51f124SMoriah Waterland 
10765c51f124SMoriah Waterland 	vfp->_vfpFile = fp;
10775c51f124SMoriah Waterland 
10785c51f124SMoriah Waterland 	/* release any existing path associated with the VFP */
10795c51f124SMoriah Waterland 
10805c51f124SMoriah Waterland 	if (vfp->_vfpPath != (char *)NULL) {
10815c51f124SMoriah Waterland 		(void) free(vfp->_vfpPath);
10825c51f124SMoriah Waterland 	}
10835c51f124SMoriah Waterland 
10845c51f124SMoriah Waterland 	/* path associated with the backing store for this VFP */
10855c51f124SMoriah Waterland 
10865c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path);
10875c51f124SMoriah Waterland 
10885c51f124SMoriah Waterland 	/*
10895c51f124SMoriah Waterland 	 * data pointers associated with in memory copy of backing store
10905c51f124SMoriah Waterland 	 * (such as _vfpHighWater, _vfpEnd, _vfpStart, etc.)
10915c51f124SMoriah Waterland 	 * do not need to be modified because we are using the same backing
10925c51f124SMoriah Waterland 	 * store as was checkpointed in cpVfp that is pointed to by vfp.
10935c51f124SMoriah Waterland 	 */
10945c51f124SMoriah Waterland 
10955c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
10965c51f124SMoriah Waterland 	vfp->_vfpCurr = (char *)vfp->_vfpStart;
10975c51f124SMoriah Waterland 
10985c51f124SMoriah Waterland 	/* free checkpointed VFP as it is now open on "vfp" */
10995c51f124SMoriah Waterland 
11005c51f124SMoriah Waterland 	(void) free(cpVfp);
11015c51f124SMoriah Waterland 
11025c51f124SMoriah Waterland 	/* reset callers -> checkpointed VFP */
11035c51f124SMoriah Waterland 
11045c51f124SMoriah Waterland 	(*a_cpVfp) = (VFP_T *)NULL;
11055c51f124SMoriah Waterland 
11065c51f124SMoriah Waterland 	/* set return VFP pointer */
11075c51f124SMoriah Waterland 
11085c51f124SMoriah Waterland 	(*r_vfp) = vfp;
11095c51f124SMoriah Waterland 
11105c51f124SMoriah Waterland 	/* success! */
11115c51f124SMoriah Waterland 
11125c51f124SMoriah Waterland 	return (0);
11135c51f124SMoriah Waterland }
11145c51f124SMoriah Waterland 
11155c51f124SMoriah Waterland /*
11165c51f124SMoriah Waterland  * Name:	vfpClearModified
11175c51f124SMoriah Waterland  * Description:	Clear the "data is modified" indication from the VFP
11185c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to clear
11195c51f124SMoriah Waterland  *			the "data is modified" indication
11205c51f124SMoriah Waterland  * Returns:	int	- previous setting of "data is modified" indication
11215c51f124SMoriah Waterland  *			== 0 - "data is modified" was NOT previously set
11225c51f124SMoriah Waterland  *			!= 0 - "data is modified" WAS previously set
11235c51f124SMoriah Waterland  */
11245c51f124SMoriah Waterland 
11255c51f124SMoriah Waterland int
11265c51f124SMoriah Waterland vfpClearModified(VFP_T *a_vfp)
11275c51f124SMoriah Waterland {
11285c51f124SMoriah Waterland 	VFPFLAGS_T	flags;
11295c51f124SMoriah Waterland 
11305c51f124SMoriah Waterland 	/* save current flags settings */
11315c51f124SMoriah Waterland 
11325c51f124SMoriah Waterland 	flags = a_vfp->_vfpFlags;
11335c51f124SMoriah Waterland 
11345c51f124SMoriah Waterland 	/* clear "data is modified" flag */
11355c51f124SMoriah Waterland 
11365c51f124SMoriah Waterland 	a_vfp->_vfpFlags &= (~_VFP_MODIFIED);
11375c51f124SMoriah Waterland 
11385c51f124SMoriah Waterland 	/* return previous "data is modified" flag setting */
11395c51f124SMoriah Waterland 
11405c51f124SMoriah Waterland 	return ((flags & _VFP_MODIFIED) != 0);
11415c51f124SMoriah Waterland }
11425c51f124SMoriah Waterland 
11435c51f124SMoriah Waterland /*
11445c51f124SMoriah Waterland  * Name:	vfpSetModified
11455c51f124SMoriah Waterland  * Description:	Set the "data is modified" indication from the VFP
11465c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set
11475c51f124SMoriah Waterland  *			the "data is modified" indication
11485c51f124SMoriah Waterland  * Returns:	int	- previous setting of "data is modified" indication
11495c51f124SMoriah Waterland  *			== 0 - "data is modified" was NOT previously set
11505c51f124SMoriah Waterland  *			!= 0 - "data is modified" WAS previously set
11515c51f124SMoriah Waterland  */
11525c51f124SMoriah Waterland 
11535c51f124SMoriah Waterland int
11545c51f124SMoriah Waterland vfpSetModified(VFP_T *a_vfp)
11555c51f124SMoriah Waterland {
11565c51f124SMoriah Waterland 	VFPFLAGS_T	flags;
11575c51f124SMoriah Waterland 
11585c51f124SMoriah Waterland 	/* save current flags settings */
11595c51f124SMoriah Waterland 
11605c51f124SMoriah Waterland 	flags = a_vfp->_vfpFlags;
11615c51f124SMoriah Waterland 
11625c51f124SMoriah Waterland 	/* set "data is modified" flag */
11635c51f124SMoriah Waterland 
11645c51f124SMoriah Waterland 	a_vfp->_vfpFlags |= _VFP_MODIFIED;
11655c51f124SMoriah Waterland 
11665c51f124SMoriah Waterland 	/* return previous "data is modified" flag setting */
11675c51f124SMoriah Waterland 
11685c51f124SMoriah Waterland 	return ((flags & _VFP_MODIFIED) != 0);
11695c51f124SMoriah Waterland }
11705c51f124SMoriah Waterland 
11715c51f124SMoriah Waterland /*
11725c51f124SMoriah Waterland  * Name:	vfpGetModified
11735c51f124SMoriah Waterland  * Description:	Get the "data is modified" indication from the VFP
11745c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to get
11755c51f124SMoriah Waterland  *			the "data is modified" indication
11765c51f124SMoriah Waterland  * Returns:	int	- current setting of "data is modified" indication
11775c51f124SMoriah Waterland  *			== 0 - "data is modified" is NOT set
11785c51f124SMoriah Waterland  *			!= 0 - "data is modified" IS set
11795c51f124SMoriah Waterland  */
11805c51f124SMoriah Waterland 
11815c51f124SMoriah Waterland int
11825c51f124SMoriah Waterland vfpGetModified(VFP_T *a_vfp)
11835c51f124SMoriah Waterland {
11845c51f124SMoriah Waterland 	/* return current "data is modified" flag setting */
11855c51f124SMoriah Waterland 
11865c51f124SMoriah Waterland 	return ((a_vfp->_vfpFlags & _VFP_MODIFIED) != 0);
11875c51f124SMoriah Waterland }
11885c51f124SMoriah Waterland 
11895c51f124SMoriah Waterland /*
11905c51f124SMoriah Waterland  * Name:	vfpSafeWrite
11915c51f124SMoriah Waterland  * Description:	write data to open file safely
11925c51f124SMoriah Waterland  * Arguments:	a_fildes - file descriptor to write data to
11935c51f124SMoriah Waterland  *		a_buf - pointer to buffer containing data to write
11945c51f124SMoriah Waterland  *		a_nbyte - number of bytes to write to open file
11955c51f124SMoriah Waterland  * Returns:	int
11965c51f124SMoriah Waterland  *		< 0 - error, errno set
11975c51f124SMoriah Waterland  *		>= 0 - success
11985c51f124SMoriah Waterland  * NOTE: unlike write(2), vfpSafeWrite() handles partial writes, and will
11995c51f124SMoriah Waterland  * ----- restart the write() until all bytes are written, or an error occurs.
12005c51f124SMoriah Waterland  */
12015c51f124SMoriah Waterland 
12025c51f124SMoriah Waterland ssize_t
12035c51f124SMoriah Waterland vfpSafeWrite(int a_fildes, void *a_buf, size_t a_nbyte)
12045c51f124SMoriah Waterland {
12055c51f124SMoriah Waterland 	ssize_t	r;
12065c51f124SMoriah Waterland 	size_t	bytes = a_nbyte;
12075c51f124SMoriah Waterland 
12085c51f124SMoriah Waterland 	for (;;) {
12095c51f124SMoriah Waterland 		/* write bytes to file */
12105c51f124SMoriah Waterland 		r = write(a_fildes, a_buf, a_nbyte);
12115c51f124SMoriah Waterland 
12125c51f124SMoriah Waterland 		/* return error on failure of write() */
12135c51f124SMoriah Waterland 		if (r < 0) {
12145c51f124SMoriah Waterland 			/* EAGAIN: try again */
12155c51f124SMoriah Waterland 			if (errno == EAGAIN) {
12165c51f124SMoriah Waterland 				continue;
12175c51f124SMoriah Waterland 			}
12185c51f124SMoriah Waterland 			/* EINTR: interrupted - try again */
12195c51f124SMoriah Waterland 			if (errno == EINTR) {
12205c51f124SMoriah Waterland 				continue;
12215c51f124SMoriah Waterland 			}
12225c51f124SMoriah Waterland 			return (r);
12235c51f124SMoriah Waterland 		}
12245c51f124SMoriah Waterland 
12255c51f124SMoriah Waterland 		/* return total bytes written on success */
12265c51f124SMoriah Waterland 		if (r >= a_nbyte) {
12275c51f124SMoriah Waterland 			return (bytes);
12285c51f124SMoriah Waterland 		}
12295c51f124SMoriah Waterland 
12305c51f124SMoriah Waterland 		/* partial write, adjust pointers, call write again */
12315c51f124SMoriah Waterland 		a_buf = (void *)((ptrdiff_t)a_buf + (ptrdiff_t)r);
12325c51f124SMoriah Waterland 		a_nbyte -= (size_t)r;
12335c51f124SMoriah Waterland 	}
12345c51f124SMoriah Waterland }
12355c51f124SMoriah Waterland 
12365c51f124SMoriah Waterland /*
12375c51f124SMoriah Waterland  * Name:	vfpSafePwrite
12385c51f124SMoriah Waterland  * Description:	write data to open file safely
12395c51f124SMoriah Waterland  * Arguments:	a_fildes - file descriptor to write data to
12405c51f124SMoriah Waterland  *		a_buf - pointer to buffer containing data to write
12415c51f124SMoriah Waterland  *		a_nbyte - number of bytes to write to open file
12425c51f124SMoriah Waterland  *		a_offset - offset into open file to write the first byte to
12435c51f124SMoriah Waterland  * Returns:	int
12445c51f124SMoriah Waterland  *		< 0 - error, errno set
12455c51f124SMoriah Waterland  *		>= 0 - success
12465c51f124SMoriah Waterland  * NOTE: unlike pwrite(2), vfpSafePwrite() handles partial writes, and will
12475c51f124SMoriah Waterland  * ----- restart the pwrite() until all bytes are written, or an error occurs.
12485c51f124SMoriah Waterland  */
12495c51f124SMoriah Waterland 
12505c51f124SMoriah Waterland ssize_t
12515c51f124SMoriah Waterland vfpSafePwrite(int a_fildes, void *a_buf, size_t a_nbyte, off_t a_offset)
12525c51f124SMoriah Waterland {
12535c51f124SMoriah Waterland 	ssize_t	r;
12545c51f124SMoriah Waterland 	size_t	bytes = a_nbyte;
12555c51f124SMoriah Waterland 
12565c51f124SMoriah Waterland 	for (;;) {
12575c51f124SMoriah Waterland 		/* write bytes to file */
12585c51f124SMoriah Waterland 		r = pwrite(a_fildes, a_buf, a_nbyte, a_offset);
12595c51f124SMoriah Waterland 
12605c51f124SMoriah Waterland 		/* return error on failure of write() */
12615c51f124SMoriah Waterland 		if (r < 0) {
12625c51f124SMoriah Waterland 			/* EAGAIN: try again */
12635c51f124SMoriah Waterland 			if (errno == EAGAIN) {
12645c51f124SMoriah Waterland 				continue;
12655c51f124SMoriah Waterland 			}
12665c51f124SMoriah Waterland 			/* EINTR: interrupted - try again */
12675c51f124SMoriah Waterland 			if (errno == EINTR) {
12685c51f124SMoriah Waterland 				continue;
12695c51f124SMoriah Waterland 			}
12705c51f124SMoriah Waterland 			return (r);
12715c51f124SMoriah Waterland 		}
12725c51f124SMoriah Waterland 
12735c51f124SMoriah Waterland 		/* return total bytes written on success */
12745c51f124SMoriah Waterland 		if (r >= a_nbyte) {
12755c51f124SMoriah Waterland 			return (bytes);
12765c51f124SMoriah Waterland 		}
12775c51f124SMoriah Waterland 
12785c51f124SMoriah Waterland 		/* partial write, adjust pointers, call write again */
12795c51f124SMoriah Waterland 		a_buf = (void *)((ptrdiff_t)a_buf + (ptrdiff_t)r);
12805c51f124SMoriah Waterland 		a_nbyte -= (size_t)r;
12815c51f124SMoriah Waterland 		a_offset += (off_t)r;
12825c51f124SMoriah Waterland 	}
12835c51f124SMoriah Waterland }
1284