xref: /titanic_44/usr/src/lib/libpkg/common/vfpops.c (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * CDDL HEADER START
3*5c51f124SMoriah Waterland  *
4*5c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
5*5c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
6*5c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
7*5c51f124SMoriah Waterland  *
8*5c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
10*5c51f124SMoriah Waterland  * See the License for the specific language governing permissions
11*5c51f124SMoriah Waterland  * and limitations under the License.
12*5c51f124SMoriah Waterland  *
13*5c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
14*5c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
16*5c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
17*5c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5c51f124SMoriah Waterland  *
19*5c51f124SMoriah Waterland  * CDDL HEADER END
20*5c51f124SMoriah Waterland  */
21*5c51f124SMoriah Waterland 
22*5c51f124SMoriah Waterland /*
23*5c51f124SMoriah Waterland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*5c51f124SMoriah Waterland  * Use is subject to license terms.
25*5c51f124SMoriah Waterland  */
26*5c51f124SMoriah Waterland 
27*5c51f124SMoriah Waterland 
28*5c51f124SMoriah Waterland 
29*5c51f124SMoriah Waterland /*
30*5c51f124SMoriah Waterland  * Module:	vfpops.c
31*5c51f124SMoriah Waterland  * Synopsis:	Implements virtual file protocol operations
32*5c51f124SMoriah Waterland  * Description:
33*5c51f124SMoriah Waterland  *
34*5c51f124SMoriah Waterland  * This module implements the "Virtual File protocol" operations. These
35*5c51f124SMoriah Waterland  * operations are intended to provide very fast access to file data,
36*5c51f124SMoriah Waterland  * allowing a file to be accessed in very efficient ways with extremely
37*5c51f124SMoriah Waterland  * low-cpu intensive operations. If possible file data is mapped directly
38*5c51f124SMoriah Waterland  * into memory allowing the data to be accessed directly. If the data
39*5c51f124SMoriah Waterland  * cannot be mapped directly into memory, memory will be allocated and
40*5c51f124SMoriah Waterland  * the file data read directly into memory. If that fails currently the
41*5c51f124SMoriah Waterland  * file data is not accessible. Other methods of making the file could
42*5c51f124SMoriah Waterland  * be implemented in the future (e.g. stdio if all else fails).
43*5c51f124SMoriah Waterland  *
44*5c51f124SMoriah Waterland  * In general any code that uses stdio to access a file can be changed
45*5c51f124SMoriah Waterland  * to use the various "vfp" operations to access a file, with a resulting
46*5c51f124SMoriah Waterland  * increase in performance and decrease in cpu time required to access
47*5c51f124SMoriah Waterland  * the file contents.
48*5c51f124SMoriah Waterland  *
49*5c51f124SMoriah Waterland  * Public Methods:
50*5c51f124SMoriah Waterland  *
51*5c51f124SMoriah Waterland  *   vfpCheckpointFile - Create new VFP that checkpoints existing VFP
52*5c51f124SMoriah Waterland  *   vfpCheckpointOpen - open file, allocate storage, return pointer to VFP_T
53*5c51f124SMoriah Waterland  *   vfpClose - close file associated with vfp
54*5c51f124SMoriah Waterland  *   vfpDecCurrPtr - decrement current character pointer
55*5c51f124SMoriah Waterland  *   vfpGetBytesRemaining - get number of bytes remaining to read
56*5c51f124SMoriah Waterland  *   vfpGetCurrCharPtr - get pointer to current character
57*5c51f124SMoriah Waterland  *   vfpGetCurrPtrDelta - get number of bytes between current and specified char
58*5c51f124SMoriah Waterland  *   vfpGetFirstCharPtr - get pointer to first character
59*5c51f124SMoriah Waterland  *   vfpGetLastCharPtr - get pointer to last character
60*5c51f124SMoriah Waterland  *   vfpGetModifiedLen - get highest modified byte (length) contained in vfp
61*5c51f124SMoriah Waterland  *   vfpGetPath - get the path associated with the vfp
62*5c51f124SMoriah Waterland  *   vfpGetc - get current character and increment to next
63*5c51f124SMoriah Waterland  *   vfpGetcNoInc - get current character - do not increment
64*5c51f124SMoriah Waterland  *   vfpGets - get a string from the vfp into a fixed size buffer
65*5c51f124SMoriah Waterland  *   vfpIncCurrPtr - increment current character pointer
66*5c51f124SMoriah Waterland  *   vfpIncCurrPtrBy - increment current pointer by specified delta
67*5c51f124SMoriah Waterland  *   vfpOpen - open file on vfp
68*5c51f124SMoriah Waterland  *   vfpPutBytes - put fixed number of bytes to current character and increment
69*5c51f124SMoriah Waterland  *   vfpPutFormat - put format one arg to current character and increment
70*5c51f124SMoriah Waterland  *   vfpPutInteger - put integer to current character and increment
71*5c51f124SMoriah Waterland  *   vfpPutLong - put long to current character and increment
72*5c51f124SMoriah Waterland  *   vfpPutc - put current character and increment to next
73*5c51f124SMoriah Waterland  *   vfpPuts - put string to current character and increment
74*5c51f124SMoriah Waterland  *   vfpRewind - rewind file to first byte
75*5c51f124SMoriah Waterland  *   vfpSeekToEnd - seek to end of file
76*5c51f124SMoriah Waterland  *   vfpSetCurrCharPtr - set pointer to current character
77*5c51f124SMoriah Waterland  *   vfpSetFlags - set flags that affect file access
78*5c51f124SMoriah Waterland  *   vfpSetSize - set size of file (for writing)
79*5c51f124SMoriah Waterland  *   vfpTruncate - truncate file
80*5c51f124SMoriah Waterland  *   vfpWriteToFile - write data contained in vfp to specified file
81*5c51f124SMoriah Waterland  */
82*5c51f124SMoriah Waterland 
83*5c51f124SMoriah Waterland #include <stdio.h>
84*5c51f124SMoriah Waterland #include <limits.h>
85*5c51f124SMoriah Waterland #include <stdlib.h>
86*5c51f124SMoriah Waterland #include <string.h>
87*5c51f124SMoriah Waterland #include <strings.h>
88*5c51f124SMoriah Waterland #include <unistd.h>
89*5c51f124SMoriah Waterland #include <ctype.h>
90*5c51f124SMoriah Waterland #include <fcntl.h>
91*5c51f124SMoriah Waterland #include <sys/types.h>
92*5c51f124SMoriah Waterland #include <sys/stat.h>
93*5c51f124SMoriah Waterland #include <sys/mman.h>
94*5c51f124SMoriah Waterland #include <errno.h>
95*5c51f124SMoriah Waterland #include <libintl.h>
96*5c51f124SMoriah Waterland #include "pkglib.h"
97*5c51f124SMoriah Waterland #include "pkgstrct.h"
98*5c51f124SMoriah Waterland #include "pkglocale.h"
99*5c51f124SMoriah Waterland 
100*5c51f124SMoriah Waterland /*
101*5c51f124SMoriah Waterland  * These are internal flags that occupy the high order byte of the VFPFLAGS_T
102*5c51f124SMoriah Waterland  * flags element of the vfp. These flags may only occupy the high order order
103*5c51f124SMoriah Waterland  * 16 bits of the 32-bit unsigned vfp "flags" object.
104*5c51f124SMoriah Waterland  */
105*5c51f124SMoriah Waterland 
106*5c51f124SMoriah Waterland #define	_VFP_MMAP	0x00010000	/* mmap used */
107*5c51f124SMoriah Waterland #define	_VFP_MALLOC	0x00020000	/* malloc used */
108*5c51f124SMoriah Waterland #define	_VFP_WRITE	0x00040000	/* file opened for write */
109*5c51f124SMoriah Waterland #define	_VFP_READ	0x00080000	/* file opened for reading */
110*5c51f124SMoriah Waterland #define	_VFP_MODIFIED	0x00100000	/* contents are marked modified */
111*5c51f124SMoriah Waterland 
112*5c51f124SMoriah Waterland /* path name given to "anonymous" (string) vfp */
113*5c51f124SMoriah Waterland 
114*5c51f124SMoriah Waterland #define	VFP_ANONYMOUS_PATH	"<<string>>"
115*5c51f124SMoriah Waterland 
116*5c51f124SMoriah Waterland /* minimum size file to mmap (64mb) */
117*5c51f124SMoriah Waterland 
118*5c51f124SMoriah Waterland #define	MIN_MMAP_SIZE	(64*1024)
119*5c51f124SMoriah Waterland 
120*5c51f124SMoriah Waterland /*
121*5c51f124SMoriah Waterland  * *****************************************************************************
122*5c51f124SMoriah Waterland  * global external (public) functions
123*5c51f124SMoriah Waterland  * *****************************************************************************
124*5c51f124SMoriah Waterland  */
125*5c51f124SMoriah Waterland 
126*5c51f124SMoriah Waterland /*
127*5c51f124SMoriah Waterland  * Name:	vfpOpen
128*5c51f124SMoriah Waterland  * Description:	Open file on vfp, allocate storage, return pointer to VFP_T
129*5c51f124SMoriah Waterland  *		that can be used to access/modify file contents.
130*5c51f124SMoriah Waterland  * Arguments:	VFP_T **r_vfp - pointer to pointer to VFP_T
131*5c51f124SMoriah Waterland  *		char *a_path - path of file to open and associate with this VFP.
132*5c51f124SMoriah Waterland  *			- if the path is (char *)NULL then no file is associated
133*5c51f124SMoriah Waterland  *			  with this VFP - this is a way to create a fixed length
134*5c51f124SMoriah Waterland  *			  string that can be manipulated with the VFP operators.
135*5c51f124SMoriah Waterland  *			  Before the VFP can be used "vfpSetSize" must be called
136*5c51f124SMoriah Waterland  *			  to set the size of the string buffer.
137*5c51f124SMoriah Waterland  *		char *a_mode - fopen mode to open the file with
138*5c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
139*5c51f124SMoriah Waterland  *			- VFP_NONE - no special flags
140*5c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
141*5c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - memory will be sequentially accessed
142*5c51f124SMoriah Waterland  *			- VFP_RANDOM - memory will be randomly accessed
143*5c51f124SMoriah Waterland  *			- VFP_NOMMAP - do not use mmap to access file
144*5c51f124SMoriah Waterland  *			- VFP_NOMALLOC - do not use malloc to buffer file
145*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
146*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
147*5c51f124SMoriah Waterland  * Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
148*5c51f124SMoriah Waterland  *			which can be used with the various vfp functions.
149*5c51f124SMoriah Waterland  *		errno -- contains system error number if return is != 0
150*5c51f124SMoriah Waterland  */
151*5c51f124SMoriah Waterland 
152*5c51f124SMoriah Waterland int
153*5c51f124SMoriah Waterland vfpOpen(VFP_T **r_vfp, char *a_path, char *a_mode, VFPFLAGS_T a_flags)
154*5c51f124SMoriah Waterland {
155*5c51f124SMoriah Waterland 	FILE		*fp = (FILE *)NULL;
156*5c51f124SMoriah Waterland 	VFP_T		*vfp;
157*5c51f124SMoriah Waterland 	int		lerrno;
158*5c51f124SMoriah Waterland 	struct stat	statbuf;
159*5c51f124SMoriah Waterland 	int		pagesize = getpagesize();
160*5c51f124SMoriah Waterland 
161*5c51f124SMoriah Waterland 	/* reset return VFP/FILE pointers */
162*5c51f124SMoriah Waterland 
163*5c51f124SMoriah Waterland 	(*r_vfp) = (VFP_T *)NULL;
164*5c51f124SMoriah Waterland 
165*5c51f124SMoriah Waterland 	/* allocate pre-zeroed vfp object */
166*5c51f124SMoriah Waterland 
167*5c51f124SMoriah Waterland 	vfp = (VFP_T *)calloc(sizeof (VFP_T), 1);
168*5c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
169*5c51f124SMoriah Waterland 		return (-1);
170*5c51f124SMoriah Waterland 	}
171*5c51f124SMoriah Waterland 
172*5c51f124SMoriah Waterland 	/* create "string" vfp if no path specified */
173*5c51f124SMoriah Waterland 
174*5c51f124SMoriah Waterland 	if (a_path == (char *)NULL) {
175*5c51f124SMoriah Waterland 		/*
176*5c51f124SMoriah Waterland 		 * no path specified - no open file associated with vfp
177*5c51f124SMoriah Waterland 		 * The vfp is initialized to all zeros - initialize just those
178*5c51f124SMoriah Waterland 		 * values that need to be non-zero.
179*5c51f124SMoriah Waterland 		 */
180*5c51f124SMoriah Waterland 
181*5c51f124SMoriah Waterland 		vfp->_vfpFlags = _VFP_MALLOC;
182*5c51f124SMoriah Waterland 		vfp->_vfpPath = strdup(VFP_ANONYMOUS_PATH);
183*5c51f124SMoriah Waterland 		(*r_vfp) = vfp;
184*5c51f124SMoriah Waterland 		return (0);
185*5c51f124SMoriah Waterland 	}
186*5c51f124SMoriah Waterland 
187*5c51f124SMoriah Waterland 	/*
188*5c51f124SMoriah Waterland 	 * path specified - associate open file with vfp;
189*5c51f124SMoriah Waterland 	 * return an error if no path or mode specified
190*5c51f124SMoriah Waterland 	 */
191*5c51f124SMoriah Waterland 
192*5c51f124SMoriah Waterland 	if (a_mode == (char *)NULL) {
193*5c51f124SMoriah Waterland 		errno = EFAULT;		/* Bad address */
194*5c51f124SMoriah Waterland 		(void) free(vfp);
195*5c51f124SMoriah Waterland 		return (-1);
196*5c51f124SMoriah Waterland 	}
197*5c51f124SMoriah Waterland 
198*5c51f124SMoriah Waterland 	/* return an error if an empty path or mode specified */
199*5c51f124SMoriah Waterland 
200*5c51f124SMoriah Waterland 	if ((*a_path == '\0') || (*a_mode == '\0')) {
201*5c51f124SMoriah Waterland 		errno = EINVAL;		/* Invalid argument */
202*5c51f124SMoriah Waterland 		(void) free(vfp);
203*5c51f124SMoriah Waterland 		return (-1);
204*5c51f124SMoriah Waterland 	}
205*5c51f124SMoriah Waterland 
206*5c51f124SMoriah Waterland 	/* open the file */
207*5c51f124SMoriah Waterland 
208*5c51f124SMoriah Waterland 	fp = fopen(a_path, a_mode);
209*5c51f124SMoriah Waterland 	if (fp == (FILE *)NULL) {
210*5c51f124SMoriah Waterland 		lerrno = errno;
211*5c51f124SMoriah Waterland 		(void) free(vfp);
212*5c51f124SMoriah Waterland 		errno = lerrno;
213*5c51f124SMoriah Waterland 		return (-1);
214*5c51f124SMoriah Waterland 	}
215*5c51f124SMoriah Waterland 
216*5c51f124SMoriah Waterland 	/* Get the file size */
217*5c51f124SMoriah Waterland 
218*5c51f124SMoriah Waterland 	if (fstat(fileno(fp), &statbuf) != 0) {
219*5c51f124SMoriah Waterland 		lerrno = errno;
220*5c51f124SMoriah Waterland 		(void) fclose(fp);
221*5c51f124SMoriah Waterland 		(void) free(vfp);
222*5c51f124SMoriah Waterland 		errno = lerrno;
223*5c51f124SMoriah Waterland 		return (-1);
224*5c51f124SMoriah Waterland 	}
225*5c51f124SMoriah Waterland 
226*5c51f124SMoriah Waterland 	/*
227*5c51f124SMoriah Waterland 	 * Obtain access to existing file contents:
228*5c51f124SMoriah Waterland 	 *  -> plan a: map contents file into memory
229*5c51f124SMoriah Waterland 	 *  -> plan b: on failure just read into large buffer
230*5c51f124SMoriah Waterland 	 */
231*5c51f124SMoriah Waterland 
232*5c51f124SMoriah Waterland 	/* attempt to mmap file if mmap is allowed */
233*5c51f124SMoriah Waterland 
234*5c51f124SMoriah Waterland 	vfp->_vfpStart = MAP_FAILED;	/* assume map failed if not allowed */
235*5c51f124SMoriah Waterland 
236*5c51f124SMoriah Waterland 	/*
237*5c51f124SMoriah Waterland 	 * if file is a regular file, and if mmap allowed,
238*5c51f124SMoriah Waterland 	 * and (malloc not forbidden or size is > minumum size to mmap)
239*5c51f124SMoriah Waterland 	 */
240*5c51f124SMoriah Waterland 
241*5c51f124SMoriah Waterland 	if ((S_ISREG(statbuf.st_mode)) && (!(a_flags & VFP_NOMMAP)) &&
242*5c51f124SMoriah Waterland 		((a_flags & VFP_NOMALLOC) || statbuf.st_size > MIN_MMAP_SIZE)) {
243*5c51f124SMoriah Waterland 		char *p;
244*5c51f124SMoriah Waterland 		/* set size to current size of file */
245*5c51f124SMoriah Waterland 
246*5c51f124SMoriah Waterland 		vfp->_vfpMapSize = statbuf.st_size;
247*5c51f124SMoriah Waterland 
248*5c51f124SMoriah Waterland 		/*
249*5c51f124SMoriah Waterland 		 * compute proper size for mapping for the file contents;
250*5c51f124SMoriah Waterland 		 * add in one extra page so falling off end when file size is
251*5c51f124SMoriah Waterland 		 * exactly modulo page size does not cause a page fault to
252*5c51f124SMoriah Waterland 		 * guarantee that the end of the file contents will always
253*5c51f124SMoriah Waterland 		 * contain a '\0' null character.
254*5c51f124SMoriah Waterland 		 */
255*5c51f124SMoriah Waterland 
256*5c51f124SMoriah Waterland 		vfp->_vfpSize = (statbuf.st_size + pagesize +
257*5c51f124SMoriah Waterland 				(pagesize-(statbuf.st_size % pagesize)));
258*5c51f124SMoriah Waterland 
259*5c51f124SMoriah Waterland 		/*
260*5c51f124SMoriah Waterland 		 * mmap allowed: mmap file into memory
261*5c51f124SMoriah Waterland 		 * first allocate space on top of which the mapping can be done;
262*5c51f124SMoriah Waterland 		 * this way we can guarantee that if the mapping happens to be
263*5c51f124SMoriah Waterland 		 * an exact multiple of a page size, that there will be at least
264*5c51f124SMoriah Waterland 		 * one byte past the end of the mapping that can be accessed and
265*5c51f124SMoriah Waterland 		 * that is guaranteed to be zero.
266*5c51f124SMoriah Waterland 		 */
267*5c51f124SMoriah Waterland 
268*5c51f124SMoriah Waterland 		/* allocate backing space */
269*5c51f124SMoriah Waterland 
270*5c51f124SMoriah Waterland 		p = (char *)memalign(pagesize, vfp->_vfpSize);
271*5c51f124SMoriah Waterland 		if (p == (char *)NULL) {
272*5c51f124SMoriah Waterland 			vfp->_vfpStart = MAP_FAILED;
273*5c51f124SMoriah Waterland 		} else {
274*5c51f124SMoriah Waterland 			/* guarantee first byte after end of data is zero */
275*5c51f124SMoriah Waterland 
276*5c51f124SMoriah Waterland 			p[vfp->_vfpMapSize] = '\0';
277*5c51f124SMoriah Waterland 
278*5c51f124SMoriah Waterland 			/* map file on top of the backing space */
279*5c51f124SMoriah Waterland 
280*5c51f124SMoriah Waterland 			vfp->_vfpStart = mmap(p, vfp->_vfpMapSize, PROT_READ,
281*5c51f124SMoriah Waterland 				MAP_PRIVATE|MAP_FIXED, fileno(fp), (off_t)0);
282*5c51f124SMoriah Waterland 
283*5c51f124SMoriah Waterland 			/* if mmap succeeded set mmap used flag in vfp */
284*5c51f124SMoriah Waterland 
285*5c51f124SMoriah Waterland 			if (vfp->_vfpStart != MAP_FAILED) {
286*5c51f124SMoriah Waterland 				vfp->_vfpFlags |= _VFP_MMAP;
287*5c51f124SMoriah Waterland 			}
288*5c51f124SMoriah Waterland 		}
289*5c51f124SMoriah Waterland 	}
290*5c51f124SMoriah Waterland 
291*5c51f124SMoriah Waterland 	/* if map failed (or not allowed) attempt malloc (if allowed) */
292*5c51f124SMoriah Waterland 
293*5c51f124SMoriah Waterland 	if ((vfp->_vfpStart == MAP_FAILED) && (!(a_flags & VFP_NOMALLOC))) {
294*5c51f124SMoriah Waterland 		/* mmap failed - plan b: read directly into memory */
295*5c51f124SMoriah Waterland 		ssize_t	rlen;
296*5c51f124SMoriah Waterland 
297*5c51f124SMoriah Waterland 		/*
298*5c51f124SMoriah Waterland 		 * compute proper size for allocating storage for file contents;
299*5c51f124SMoriah Waterland 		 * add in one extra page so falling off end when file size is
300*5c51f124SMoriah Waterland 		 * exactly modulo page size does not cause a page fault to
301*5c51f124SMoriah Waterland 		 * guarantee that the end of the file contents will always
302*5c51f124SMoriah Waterland 		 * contain a '\0' null character.
303*5c51f124SMoriah Waterland 		 */
304*5c51f124SMoriah Waterland 
305*5c51f124SMoriah Waterland 		vfp->_vfpSize = statbuf.st_size+pagesize;
306*5c51f124SMoriah Waterland 
307*5c51f124SMoriah Waterland 		/* allocate buffer to hold file data */
308*5c51f124SMoriah Waterland 
309*5c51f124SMoriah Waterland 		vfp->_vfpStart = memalign((size_t)pagesize, vfp->_vfpSize);
310*5c51f124SMoriah Waterland 		if (vfp->_vfpStart == (char *)NULL) {
311*5c51f124SMoriah Waterland 			lerrno = errno;
312*5c51f124SMoriah Waterland 			(void) fclose(fp);
313*5c51f124SMoriah Waterland 			(void) free(vfp);
314*5c51f124SMoriah Waterland 			errno = lerrno;
315*5c51f124SMoriah Waterland 			return (-1);
316*5c51f124SMoriah Waterland 		}
317*5c51f124SMoriah Waterland 
318*5c51f124SMoriah Waterland 		/* read the file into the buffer */
319*5c51f124SMoriah Waterland 
320*5c51f124SMoriah Waterland 		if (statbuf.st_size != 0) {
321*5c51f124SMoriah Waterland 			rlen = read(fileno(fp), vfp->_vfpStart,
322*5c51f124SMoriah Waterland 							statbuf.st_size);
323*5c51f124SMoriah Waterland 			if (rlen != statbuf.st_size) {
324*5c51f124SMoriah Waterland 				lerrno = errno;
325*5c51f124SMoriah Waterland 				if (lerrno == 0) {
326*5c51f124SMoriah Waterland 					lerrno = EIO;
327*5c51f124SMoriah Waterland 				}
328*5c51f124SMoriah Waterland 				(void) free(vfp->_vfpStart);
329*5c51f124SMoriah Waterland 				(void) fclose(fp);
330*5c51f124SMoriah Waterland 				(void) free(vfp);
331*5c51f124SMoriah Waterland 				errno = lerrno;
332*5c51f124SMoriah Waterland 				return (-1);
333*5c51f124SMoriah Waterland 			}
334*5c51f124SMoriah Waterland 
335*5c51f124SMoriah Waterland 			/* assure last byte+1 is null character */
336*5c51f124SMoriah Waterland 
337*5c51f124SMoriah Waterland 			((char *)vfp->_vfpStart)[statbuf.st_size] = '\0';
338*5c51f124SMoriah Waterland 		}
339*5c51f124SMoriah Waterland 
340*5c51f124SMoriah Waterland 		/* set malloc used flag in vfp */
341*5c51f124SMoriah Waterland 
342*5c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_MALLOC;
343*5c51f124SMoriah Waterland 	}
344*5c51f124SMoriah Waterland 
345*5c51f124SMoriah Waterland 	/* if no starting address all read methods failed */
346*5c51f124SMoriah Waterland 
347*5c51f124SMoriah Waterland 	if (vfp->_vfpStart == MAP_FAILED) {
348*5c51f124SMoriah Waterland 		/* no mmap() - no read() - cannot allocate memory */
349*5c51f124SMoriah Waterland 		(void) fclose(fp);
350*5c51f124SMoriah Waterland 		(void) free(vfp);
351*5c51f124SMoriah Waterland 		errno = ENOMEM;
352*5c51f124SMoriah Waterland 		return (-1);
353*5c51f124SMoriah Waterland 	}
354*5c51f124SMoriah Waterland 
355*5c51f124SMoriah Waterland 	/*
356*5c51f124SMoriah Waterland 	 * initialize vfp contents
357*5c51f124SMoriah Waterland 	 */
358*5c51f124SMoriah Waterland 
359*5c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
360*5c51f124SMoriah Waterland 	vfp->_vfpCurr = (char *)vfp->_vfpStart;
361*5c51f124SMoriah Waterland 
362*5c51f124SMoriah Waterland 	/* _vfpEnd -> last data byte */
363*5c51f124SMoriah Waterland 	vfp->_vfpEnd = (((char *)vfp->_vfpStart) + statbuf.st_size)-1;
364*5c51f124SMoriah Waterland 
365*5c51f124SMoriah Waterland 	/* _vfpHighWater -> last byte written */
366*5c51f124SMoriah Waterland 	vfp->_vfpHighWater = (char *)vfp->_vfpEnd;
367*5c51f124SMoriah Waterland 
368*5c51f124SMoriah Waterland 	/* _vfpFile -> associated FILE* object */
369*5c51f124SMoriah Waterland 	vfp->_vfpFile = fp;
370*5c51f124SMoriah Waterland 
371*5c51f124SMoriah Waterland 	/* set flags as appropriate */
372*5c51f124SMoriah Waterland 
373*5c51f124SMoriah Waterland 	(void) vfpSetFlags(vfp, a_flags);
374*5c51f124SMoriah Waterland 
375*5c51f124SMoriah Waterland 	/* retain path name */
376*5c51f124SMoriah Waterland 
377*5c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path ? a_path : "");
378*5c51f124SMoriah Waterland 
379*5c51f124SMoriah Waterland 	/* set read/write flags */
380*5c51f124SMoriah Waterland 
381*5c51f124SMoriah Waterland 	if (*a_mode == 'w') {
382*5c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_WRITE;
383*5c51f124SMoriah Waterland 	}
384*5c51f124SMoriah Waterland 
385*5c51f124SMoriah Waterland 	if (*a_mode == 'r') {
386*5c51f124SMoriah Waterland 		vfp->_vfpFlags |= _VFP_READ;
387*5c51f124SMoriah Waterland 	}
388*5c51f124SMoriah Waterland 
389*5c51f124SMoriah Waterland 	/* set return vfp pointer */
390*5c51f124SMoriah Waterland 
391*5c51f124SMoriah Waterland 	(*r_vfp) = vfp;
392*5c51f124SMoriah Waterland 
393*5c51f124SMoriah Waterland 	/* All OK */
394*5c51f124SMoriah Waterland 
395*5c51f124SMoriah Waterland 	return (0);
396*5c51f124SMoriah Waterland }
397*5c51f124SMoriah Waterland 
398*5c51f124SMoriah Waterland /*
399*5c51f124SMoriah Waterland  * Name:	vfpClose
400*5c51f124SMoriah Waterland  * Description:	Close an open vfp, causing any modified data to be written out
401*5c51f124SMoriah Waterland  *		to the file associated with the vfp.
402*5c51f124SMoriah Waterland  * Arguments:	VFP_T **r_vfp - pointer to pointer to VFP_T returned by vfpOpen
403*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
404*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
405*5c51f124SMoriah Waterland  * Side Effects: r_vfp is set to (VFP_T)NULL
406*5c51f124SMoriah Waterland  */
407*5c51f124SMoriah Waterland 
408*5c51f124SMoriah Waterland int
409*5c51f124SMoriah Waterland vfpClose(VFP_T **r_vfp)
410*5c51f124SMoriah Waterland {
411*5c51f124SMoriah Waterland 	int	ret;
412*5c51f124SMoriah Waterland 	int	lerrno;
413*5c51f124SMoriah Waterland 	VFP_T	*vfp;
414*5c51f124SMoriah Waterland 
415*5c51f124SMoriah Waterland 	/* return error if NULL VFP_T** provided */
416*5c51f124SMoriah Waterland 
417*5c51f124SMoriah Waterland 	if (r_vfp == (VFP_T **)NULL) {
418*5c51f124SMoriah Waterland 		errno = EFAULT;
419*5c51f124SMoriah Waterland 		return (-1);
420*5c51f124SMoriah Waterland 	}
421*5c51f124SMoriah Waterland 
422*5c51f124SMoriah Waterland 	/* localize access to VFP_T */
423*5c51f124SMoriah Waterland 
424*5c51f124SMoriah Waterland 	vfp = *r_vfp;
425*5c51f124SMoriah Waterland 
426*5c51f124SMoriah Waterland 	/* return successful if NULL VFP_T* provided */
427*5c51f124SMoriah Waterland 
428*5c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
429*5c51f124SMoriah Waterland 		return (0);
430*5c51f124SMoriah Waterland 	}
431*5c51f124SMoriah Waterland 
432*5c51f124SMoriah Waterland 	/* reset return VFP_T* handle */
433*5c51f124SMoriah Waterland 
434*5c51f124SMoriah Waterland 	*r_vfp = (VFP_T *)NULL;
435*5c51f124SMoriah Waterland 
436*5c51f124SMoriah Waterland 	/*
437*5c51f124SMoriah Waterland 	 * if closing a file that is open for writing, commit all data if the
438*5c51f124SMoriah Waterland 	 * backing memory is volatile and if there is a file open to write
439*5c51f124SMoriah Waterland 	 * the data to.
440*5c51f124SMoriah Waterland 	 */
441*5c51f124SMoriah Waterland 
442*5c51f124SMoriah Waterland 	if (vfp->_vfpFlags & _VFP_WRITE) {
443*5c51f124SMoriah Waterland 		if ((vfp->_vfpFlags & _VFP_MALLOC) &&
444*5c51f124SMoriah Waterland 				(vfp->_vfpFile != (FILE *)NULL)) {
445*5c51f124SMoriah Waterland 			size_t	len;
446*5c51f124SMoriah Waterland 
447*5c51f124SMoriah Waterland 			/* determine number of bytes to write */
448*5c51f124SMoriah Waterland 			len = vfpGetModifiedLen(vfp);
449*5c51f124SMoriah Waterland 
450*5c51f124SMoriah Waterland 			/* if modified bytes present commit data to the file */
451*5c51f124SMoriah Waterland 			if (len > 0) {
452*5c51f124SMoriah Waterland 				(void) vfpSafePwrite(fileno(vfp->_vfpFile),
453*5c51f124SMoriah Waterland 						vfp->_vfpStart, len, (off_t)0);
454*5c51f124SMoriah Waterland 			}
455*5c51f124SMoriah Waterland 		}
456*5c51f124SMoriah Waterland 	}
457*5c51f124SMoriah Waterland 
458*5c51f124SMoriah Waterland 	/* deallocate any allocated storage/mappings/etc */
459*5c51f124SMoriah Waterland 
460*5c51f124SMoriah Waterland 	if (vfp->_vfpFlags & _VFP_MALLOC) {
461*5c51f124SMoriah Waterland 		(void) free(vfp->_vfpStart);
462*5c51f124SMoriah Waterland 	} else if (vfp->_vfpFlags & _VFP_MMAP) {
463*5c51f124SMoriah Waterland 		/* unmap the file mapping */
464*5c51f124SMoriah Waterland 
465*5c51f124SMoriah Waterland 		(void) munmap(vfp->_vfpStart, vfp->_vfpMapSize);
466*5c51f124SMoriah Waterland 
467*5c51f124SMoriah Waterland 		/* free the backing allocation */
468*5c51f124SMoriah Waterland 
469*5c51f124SMoriah Waterland 		(void) free(vfp->_vfpStart);
470*5c51f124SMoriah Waterland 	}
471*5c51f124SMoriah Waterland 
472*5c51f124SMoriah Waterland 	/* free up path */
473*5c51f124SMoriah Waterland 
474*5c51f124SMoriah Waterland 	(void) free(vfp->_vfpPath);
475*5c51f124SMoriah Waterland 
476*5c51f124SMoriah Waterland 	/* close the file */
477*5c51f124SMoriah Waterland 
478*5c51f124SMoriah Waterland 	ret = 0;
479*5c51f124SMoriah Waterland 	if (vfp->_vfpFile != (FILE *)NULL) {
480*5c51f124SMoriah Waterland 		ret = fclose(vfp->_vfpFile);
481*5c51f124SMoriah Waterland 		lerrno = errno;
482*5c51f124SMoriah Waterland 	}
483*5c51f124SMoriah Waterland 
484*5c51f124SMoriah Waterland 	/* deallocate the vfp itself */
485*5c51f124SMoriah Waterland 
486*5c51f124SMoriah Waterland 	(void) free(vfp);
487*5c51f124SMoriah Waterland 
488*5c51f124SMoriah Waterland 	/* if the fclose() failed, return error and errno */
489*5c51f124SMoriah Waterland 
490*5c51f124SMoriah Waterland 	if (ret != 0) {
491*5c51f124SMoriah Waterland 		errno = lerrno;
492*5c51f124SMoriah Waterland 		return (-1);
493*5c51f124SMoriah Waterland 	}
494*5c51f124SMoriah Waterland 
495*5c51f124SMoriah Waterland 	return (0);
496*5c51f124SMoriah Waterland }
497*5c51f124SMoriah Waterland 
498*5c51f124SMoriah Waterland /*
499*5c51f124SMoriah Waterland  * Name:	vfpSetFlags
500*5c51f124SMoriah Waterland  * Description:	Modify operation of VFP according to flags specified
501*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set flags
502*5c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
503*5c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
504*5c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - file data sequentially accessed
505*5c51f124SMoriah Waterland  *			- VFP_RANDOM - file data randomly accessed
506*5c51f124SMoriah Waterland  *			Any other flags specified are silently ignored.
507*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
508*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
509*5c51f124SMoriah Waterland  */
510*5c51f124SMoriah Waterland 
511*5c51f124SMoriah Waterland int
512*5c51f124SMoriah Waterland vfpSetFlags(VFP_T *a_vfp, VFPFLAGS_T a_flags)
513*5c51f124SMoriah Waterland {
514*5c51f124SMoriah Waterland 	/* return if no vfp specified */
515*5c51f124SMoriah Waterland 
516*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
517*5c51f124SMoriah Waterland 		return (0);
518*5c51f124SMoriah Waterland 	}
519*5c51f124SMoriah Waterland 
520*5c51f124SMoriah Waterland 	/* if file data mapped into memory, apply vm flags */
521*5c51f124SMoriah Waterland 
522*5c51f124SMoriah Waterland 	if ((a_vfp->_vfpSize != 0) && (a_vfp->_vfpFlags & _VFP_MMAP)) {
523*5c51f124SMoriah Waterland 		/* mmap succeeded: properly advise vm system */
524*5c51f124SMoriah Waterland 
525*5c51f124SMoriah Waterland 		if (a_flags & VFP_NEEDNOW) {
526*5c51f124SMoriah Waterland 			/* advise vm system data is needed now */
527*5c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpMapSize,
528*5c51f124SMoriah Waterland 							MADV_WILLNEED);
529*5c51f124SMoriah Waterland 		}
530*5c51f124SMoriah Waterland 		if (a_flags & VFP_SEQUENTIAL) {
531*5c51f124SMoriah Waterland 			/* advise vm system data access is sequential */
532*5c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpSize,
533*5c51f124SMoriah Waterland 							MADV_SEQUENTIAL);
534*5c51f124SMoriah Waterland 		}
535*5c51f124SMoriah Waterland 		if (a_flags & VFP_RANDOM) {
536*5c51f124SMoriah Waterland 			/* advise vm system data access is random */
537*5c51f124SMoriah Waterland 			(void) madvise(a_vfp->_vfpStart, a_vfp->_vfpSize,
538*5c51f124SMoriah Waterland 							MADV_RANDOM);
539*5c51f124SMoriah Waterland 		}
540*5c51f124SMoriah Waterland 	}
541*5c51f124SMoriah Waterland 
542*5c51f124SMoriah Waterland 	return (0);
543*5c51f124SMoriah Waterland }
544*5c51f124SMoriah Waterland 
545*5c51f124SMoriah Waterland /*
546*5c51f124SMoriah Waterland  * Name:	vfpRewind
547*5c51f124SMoriah Waterland  * Description:	Reset default pointer for next read/write to start of file data
548*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to rewind
549*5c51f124SMoriah Waterland  * Returns:	void
550*5c51f124SMoriah Waterland  *			Operation is always successful
551*5c51f124SMoriah Waterland  */
552*5c51f124SMoriah Waterland 
553*5c51f124SMoriah Waterland void
554*5c51f124SMoriah Waterland vfpRewind(VFP_T *a_vfp)
555*5c51f124SMoriah Waterland {
556*5c51f124SMoriah Waterland 	/* return if no vfp specified */
557*5c51f124SMoriah Waterland 
558*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
559*5c51f124SMoriah Waterland 		return;
560*5c51f124SMoriah Waterland 	}
561*5c51f124SMoriah Waterland 
562*5c51f124SMoriah Waterland 	/* set high water mark of last modified data */
563*5c51f124SMoriah Waterland 
564*5c51f124SMoriah Waterland 	if (a_vfp->_vfpCurr > a_vfp->_vfpHighWater) {
565*5c51f124SMoriah Waterland 		a_vfp->_vfpHighWater = a_vfp->_vfpCurr;
566*5c51f124SMoriah Waterland 	}
567*5c51f124SMoriah Waterland 
568*5c51f124SMoriah Waterland 	/* reset next character pointer to start of file data */
569*5c51f124SMoriah Waterland 
570*5c51f124SMoriah Waterland 	a_vfp->_vfpCurr = a_vfp->_vfpStart;
571*5c51f124SMoriah Waterland }
572*5c51f124SMoriah Waterland 
573*5c51f124SMoriah Waterland /*
574*5c51f124SMoriah Waterland  * Name:	vfpSetSize
575*5c51f124SMoriah Waterland  * Description:	Set size of in-memory image associated with VFP
576*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set
577*5c51f124SMoriah Waterland  *		size_t a_size - number of bytes to associatge with VFP
578*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
579*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
580*5c51f124SMoriah Waterland  * Side Effects:
581*5c51f124SMoriah Waterland  *		Currently only a file that is in malloc()ed memory can
582*5c51f124SMoriah Waterland  *		have its in-memory size changed.
583*5c51f124SMoriah Waterland  *		An error is returned If the file is mapped into memory.
584*5c51f124SMoriah Waterland  *		A file cannot be decreased in size - if the specified
585*5c51f124SMoriah Waterland  *		size is less than the current size, the operation is
586*5c51f124SMoriah Waterland  *		successful but no change in file size occurs.
587*5c51f124SMoriah Waterland  *		If no file is associated with the VFP (no "name" was
588*5c51f124SMoriah Waterland  *		given to vfpOpen) the first call to vfpSetSize allocates
589*5c51f124SMoriah Waterland  *		the initial size of the file data - effectively calling
590*5c51f124SMoriah Waterland  *		"malloc" to allocate the initial memory for the file data.
591*5c51f124SMoriah Waterland  *		Once an initial allocation has been made, subsequent calls
592*5c51f124SMoriah Waterland  *		to vfpSetSize are effectively a "realloc" of the existing
593*5c51f124SMoriah Waterland  *		file data.
594*5c51f124SMoriah Waterland  *		All existing file data is preserved.
595*5c51f124SMoriah Waterland  */
596*5c51f124SMoriah Waterland 
597*5c51f124SMoriah Waterland int
598*5c51f124SMoriah Waterland vfpSetSize(VFP_T *a_vfp, size_t a_size)
599*5c51f124SMoriah Waterland {
600*5c51f124SMoriah Waterland 	char	*np;
601*5c51f124SMoriah Waterland 	size_t	curSize;
602*5c51f124SMoriah Waterland 
603*5c51f124SMoriah Waterland 	/* return if no vfp specified */
604*5c51f124SMoriah Waterland 
605*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
606*5c51f124SMoriah Waterland 		return (0);
607*5c51f124SMoriah Waterland 	}
608*5c51f124SMoriah Waterland 
609*5c51f124SMoriah Waterland 	/* if malloc not used don't know how to set size right now */
610*5c51f124SMoriah Waterland 
611*5c51f124SMoriah Waterland 	if (!(a_vfp->_vfpFlags & _VFP_MALLOC)) {
612*5c51f124SMoriah Waterland 		return (-1);
613*5c51f124SMoriah Waterland 	}
614*5c51f124SMoriah Waterland 
615*5c51f124SMoriah Waterland 	/* adjust size to reflect extra page of data maintained */
616*5c51f124SMoriah Waterland 
617*5c51f124SMoriah Waterland 	a_size += getpagesize();
618*5c51f124SMoriah Waterland 
619*5c51f124SMoriah Waterland 	/* if size is not larger than current nothing to do */
620*5c51f124SMoriah Waterland 
621*5c51f124SMoriah Waterland 	if (a_size <= a_vfp->_vfpSize) {
622*5c51f124SMoriah Waterland 		return (0);
623*5c51f124SMoriah Waterland 	}
624*5c51f124SMoriah Waterland 
625*5c51f124SMoriah Waterland 	/* remember new size */
626*5c51f124SMoriah Waterland 
627*5c51f124SMoriah Waterland 	curSize = a_vfp->_vfpSize;
628*5c51f124SMoriah Waterland 	a_vfp->_vfpSize = a_size;
629*5c51f124SMoriah Waterland 
630*5c51f124SMoriah Waterland 	/* allocate/reallocate memory as appropriate */
631*5c51f124SMoriah Waterland 
632*5c51f124SMoriah Waterland 	if (a_vfp->_vfpStart != (char *)NULL) {
633*5c51f124SMoriah Waterland 		np = (char *)realloc(a_vfp->_vfpStart, a_vfp->_vfpSize+1);
634*5c51f124SMoriah Waterland 		if (np == (char *)NULL) {
635*5c51f124SMoriah Waterland 			return (-1);
636*5c51f124SMoriah Waterland 		}
637*5c51f124SMoriah Waterland 		np[curSize-1] = '\0';
638*5c51f124SMoriah Waterland 	} else {
639*5c51f124SMoriah Waterland 		np = (char *)malloc(a_vfp->_vfpSize+1);
640*5c51f124SMoriah Waterland 		if (np == (char *)NULL) {
641*5c51f124SMoriah Waterland 			return (-1);
642*5c51f124SMoriah Waterland 		}
643*5c51f124SMoriah Waterland 		np[0] = '\0';
644*5c51f124SMoriah Waterland 	}
645*5c51f124SMoriah Waterland 
646*5c51f124SMoriah Waterland 	/* make sure last allocated byte is a null */
647*5c51f124SMoriah Waterland 
648*5c51f124SMoriah Waterland 	np[a_vfp->_vfpSize] = '\0';
649*5c51f124SMoriah Waterland 
650*5c51f124SMoriah Waterland 	/*
651*5c51f124SMoriah Waterland 	 * adjust all pointers to account for buffer address change
652*5c51f124SMoriah Waterland 	 */
653*5c51f124SMoriah Waterland 
654*5c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
655*5c51f124SMoriah Waterland 	a_vfp->_vfpCurr = (char *)(((ptrdiff_t)a_vfp->_vfpCurr -
656*5c51f124SMoriah Waterland 					(ptrdiff_t)a_vfp->_vfpStart) + np);
657*5c51f124SMoriah Waterland 
658*5c51f124SMoriah Waterland 	/* _vfpHighWater -> last byte written */
659*5c51f124SMoriah Waterland 	a_vfp->_vfpHighWater = (char *)(((ptrdiff_t)a_vfp->_vfpHighWater -
660*5c51f124SMoriah Waterland 					(ptrdiff_t)a_vfp->_vfpStart) + np);
661*5c51f124SMoriah Waterland 
662*5c51f124SMoriah Waterland 	/* _vfpEnd -> last data byte */
663*5c51f124SMoriah Waterland 	a_vfp->_vfpEnd = (np + a_vfp->_vfpSize)-1;
664*5c51f124SMoriah Waterland 
665*5c51f124SMoriah Waterland 	/* _vfpStart -> first data byte */
666*5c51f124SMoriah Waterland 	a_vfp->_vfpStart = np;
667*5c51f124SMoriah Waterland 
668*5c51f124SMoriah Waterland 	return (0);
669*5c51f124SMoriah Waterland }
670*5c51f124SMoriah Waterland 
671*5c51f124SMoriah Waterland /*
672*5c51f124SMoriah Waterland  * Name:	vfpTruncate
673*5c51f124SMoriah Waterland  * Description:	Truncate data associated with VFP
674*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to truncate
675*5c51f124SMoriah Waterland  * Returns:	void
676*5c51f124SMoriah Waterland  *			Operation is always successful.
677*5c51f124SMoriah Waterland  * Side Effects:
678*5c51f124SMoriah Waterland  *		In memory data associated with file is believed to be empty.
679*5c51f124SMoriah Waterland  *		Actual memory associated with file is not affected.
680*5c51f124SMoriah Waterland  *		If a file is associated with the VFP, it is truncated.
681*5c51f124SMoriah Waterland  */
682*5c51f124SMoriah Waterland 
683*5c51f124SMoriah Waterland void
684*5c51f124SMoriah Waterland vfpTruncate(VFP_T *a_vfp)
685*5c51f124SMoriah Waterland {
686*5c51f124SMoriah Waterland 	/* return if no vfp specified */
687*5c51f124SMoriah Waterland 
688*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
689*5c51f124SMoriah Waterland 		return;
690*5c51f124SMoriah Waterland 	}
691*5c51f124SMoriah Waterland 
692*5c51f124SMoriah Waterland 	/*
693*5c51f124SMoriah Waterland 	 * reset all pointers so that no data is associated with file
694*5c51f124SMoriah Waterland 	 */
695*5c51f124SMoriah Waterland 
696*5c51f124SMoriah Waterland 	/* current byte is start of data area */
697*5c51f124SMoriah Waterland 
698*5c51f124SMoriah Waterland 	a_vfp->_vfpCurr = a_vfp->_vfpStart;
699*5c51f124SMoriah Waterland 
700*5c51f124SMoriah Waterland 	/* last byte written is start of data area */
701*5c51f124SMoriah Waterland 
702*5c51f124SMoriah Waterland 	a_vfp->_vfpHighWater = a_vfp->_vfpStart;
703*5c51f124SMoriah Waterland 
704*5c51f124SMoriah Waterland 	/* current character is NULL */
705*5c51f124SMoriah Waterland 
706*5c51f124SMoriah Waterland 	*a_vfp->_vfpCurr = '\0';
707*5c51f124SMoriah Waterland 
708*5c51f124SMoriah Waterland 	/* if file associated with VFP, truncate actual file */
709*5c51f124SMoriah Waterland 
710*5c51f124SMoriah Waterland 	if (a_vfp->_vfpFile != (FILE *)NULL) {
711*5c51f124SMoriah Waterland 		(void) ftruncate(fileno(a_vfp->_vfpFile), 0);
712*5c51f124SMoriah Waterland 	}
713*5c51f124SMoriah Waterland }
714*5c51f124SMoriah Waterland 
715*5c51f124SMoriah Waterland /*
716*5c51f124SMoriah Waterland  * Name:	vfpWriteToFile
717*5c51f124SMoriah Waterland  * Description:	Write data associated with VFP to specified file
718*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to write
719*5c51f124SMoriah Waterland  *		char *a_path - path of file to write file data to
720*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
721*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
722*5c51f124SMoriah Waterland  */
723*5c51f124SMoriah Waterland 
724*5c51f124SMoriah Waterland int
725*5c51f124SMoriah Waterland vfpWriteToFile(VFP_T *a_vfp, char *a_path)
726*5c51f124SMoriah Waterland {
727*5c51f124SMoriah Waterland 	int	fd;
728*5c51f124SMoriah Waterland 	int	lerrno = 0;
729*5c51f124SMoriah Waterland 	size_t	len;
730*5c51f124SMoriah Waterland 	ssize_t	result = 0;
731*5c51f124SMoriah Waterland 
732*5c51f124SMoriah Waterland 	/* return if no vfp specified */
733*5c51f124SMoriah Waterland 
734*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T *)NULL) {
735*5c51f124SMoriah Waterland 		errno = EFAULT;
736*5c51f124SMoriah Waterland 		return (-1);
737*5c51f124SMoriah Waterland 	}
738*5c51f124SMoriah Waterland 
739*5c51f124SMoriah Waterland 	/* on buffer overflow generate error */
740*5c51f124SMoriah Waterland 
741*5c51f124SMoriah Waterland 	if ((a_vfp->_vfpOverflow != 0) || (vfpGetBytesAvailable(a_vfp) < 1)) {
742*5c51f124SMoriah Waterland 		errno = EFBIG;
743*5c51f124SMoriah Waterland 		return (-1);
744*5c51f124SMoriah Waterland 	}
745*5c51f124SMoriah Waterland 
746*5c51f124SMoriah Waterland 	/* open file to write data to */
747*5c51f124SMoriah Waterland 
748*5c51f124SMoriah Waterland 	fd = open(a_path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
749*5c51f124SMoriah Waterland 	if (fd < 0) {
750*5c51f124SMoriah Waterland 		return (-1);
751*5c51f124SMoriah Waterland 	}
752*5c51f124SMoriah Waterland 
753*5c51f124SMoriah Waterland 	/* determine number of bytes to write */
754*5c51f124SMoriah Waterland 
755*5c51f124SMoriah Waterland 	len = vfpGetModifiedLen(a_vfp);
756*5c51f124SMoriah Waterland 
757*5c51f124SMoriah Waterland 	/*
758*5c51f124SMoriah Waterland 	 * if there is data associated with the file, write it out;
759*5c51f124SMoriah Waterland 	 * if an error occurs, close the file and return failure.
760*5c51f124SMoriah Waterland 	 */
761*5c51f124SMoriah Waterland 
762*5c51f124SMoriah Waterland 	if (len > 0) {
763*5c51f124SMoriah Waterland 		result = vfpSafeWrite(fd, a_vfp->_vfpStart, len);
764*5c51f124SMoriah Waterland 		if (result != len) {
765*5c51f124SMoriah Waterland 			/* error comitting data - return failure */
766*5c51f124SMoriah Waterland 			lerrno = errno;
767*5c51f124SMoriah Waterland 			(void) close(fd);
768*5c51f124SMoriah Waterland 			errno = lerrno;
769*5c51f124SMoriah Waterland 			return (-1);
770*5c51f124SMoriah Waterland 		}
771*5c51f124SMoriah Waterland 	}
772*5c51f124SMoriah Waterland 
773*5c51f124SMoriah Waterland 	/* close the file */
774*5c51f124SMoriah Waterland 
775*5c51f124SMoriah Waterland 	(void) close(fd);
776*5c51f124SMoriah Waterland 
777*5c51f124SMoriah Waterland 	/* data committed to backing store - clear the modified flag */
778*5c51f124SMoriah Waterland 
779*5c51f124SMoriah Waterland 	(void) vfpClearModified(a_vfp);
780*5c51f124SMoriah Waterland 
781*5c51f124SMoriah Waterland 	/* return success */
782*5c51f124SMoriah Waterland 
783*5c51f124SMoriah Waterland 	return (0);
784*5c51f124SMoriah Waterland }
785*5c51f124SMoriah Waterland 
786*5c51f124SMoriah Waterland /*
787*5c51f124SMoriah Waterland  * Name:	vfpCheckpointFile
788*5c51f124SMoriah Waterland  * Description:	Create new VFP that checkpoints existing VFP, can be used by
789*5c51f124SMoriah Waterland  *		subsequent call to vfpCheckpointOpen to open a file using the
790*5c51f124SMoriah Waterland  *		existing in-memory cache of the contents of the file
791*5c51f124SMoriah Waterland  * Arguments:	VFP_T **r_cpVfp - pointer to pointer to VFP_T to be filled in
792*5c51f124SMoriah Waterland  *			with "checkpointed file" VFP (backing store)
793*5c51f124SMoriah Waterland  *		VFP_T **a_vfp - pointer to pointer to VFP_T returned by vfpOpen
794*5c51f124SMoriah Waterland  *			representing the VFP to checkpoint
795*5c51f124SMoriah Waterland  *		char *a_path - path to file that is the backing store for the
796*5c51f124SMoriah Waterland  *			in-memory data represented by a_vfp - used to verify
797*5c51f124SMoriah Waterland  *			that the data in memory is not out of date with respect
798*5c51f124SMoriah Waterland  *			to the backing store when vfpCheckpointOpen is called
799*5c51f124SMoriah Waterland  *			== (char *)NULL - use path associated with a_vfp
800*5c51f124SMoriah Waterland  *				that is, the backing store file in use
801*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
802*5c51f124SMoriah Waterland  *				- r_destVfp contains a pointer to a new VFP that
803*5c51f124SMoriah Waterland  *					may be used in a subsequent call to
804*5c51f124SMoriah Waterland  *					vfpCheckpointOpen
805*5c51f124SMoriah Waterland  *				- the VFP referenced by *a_vfp is free()ed and
806*5c51f124SMoriah Waterland  *					must no longer be referenced
807*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
808*5c51f124SMoriah Waterland  *				- the VFP referenced by *a_vfp is not affected;
809*5c51f124SMoriah Waterland  *					the caller may continue to use it
810*5c51f124SMoriah Waterland  * Notes:	If the data of a VFP to checkpoint is mmap()ed then this method
811*5c51f124SMoriah Waterland  *			returns failure - only malloc()ed data VFPs can be
812*5c51f124SMoriah Waterland  *			checkpointed.
813*5c51f124SMoriah Waterland  */
814*5c51f124SMoriah Waterland 
815*5c51f124SMoriah Waterland int
816*5c51f124SMoriah Waterland vfpCheckpointFile(VFP_T **r_cpVfp, VFP_T **a_vfp, char *a_path)
817*5c51f124SMoriah Waterland {
818*5c51f124SMoriah Waterland 	VFP_T		*vfp;		/* newly allocated checkpointed VFP */
819*5c51f124SMoriah Waterland 	VFP_T		*avfp;		/* local -> to a_vfp */
820*5c51f124SMoriah Waterland 	struct stat	statbuf;	/* stat(2) info for backing store */
821*5c51f124SMoriah Waterland 
822*5c51f124SMoriah Waterland 	/* return error if NULL VFP_T** to checkpoint provided */
823*5c51f124SMoriah Waterland 
824*5c51f124SMoriah Waterland 	if (r_cpVfp == (VFP_T **)NULL) {
825*5c51f124SMoriah Waterland 		errno = EFAULT;
826*5c51f124SMoriah Waterland 		return (-1);
827*5c51f124SMoriah Waterland 	}
828*5c51f124SMoriah Waterland 
829*5c51f124SMoriah Waterland 	/* reset return checkpoint VFP pointer */
830*5c51f124SMoriah Waterland 
831*5c51f124SMoriah Waterland 	(*r_cpVfp) = (VFP_T *)NULL;
832*5c51f124SMoriah Waterland 
833*5c51f124SMoriah Waterland 	/* return error if no VFP to checkpoint specified */
834*5c51f124SMoriah Waterland 
835*5c51f124SMoriah Waterland 	if (a_vfp == (VFP_T **)NULL) {
836*5c51f124SMoriah Waterland 		errno = EFAULT;
837*5c51f124SMoriah Waterland 		return (-1);
838*5c51f124SMoriah Waterland 	}
839*5c51f124SMoriah Waterland 
840*5c51f124SMoriah Waterland 	/* localize reference to a_vfp */
841*5c51f124SMoriah Waterland 
842*5c51f124SMoriah Waterland 	avfp = *a_vfp;
843*5c51f124SMoriah Waterland 
844*5c51f124SMoriah Waterland 	/* return error if no VFP to checkpoint specified */
845*5c51f124SMoriah Waterland 
846*5c51f124SMoriah Waterland 	if (avfp == (VFP_T *)NULL) {
847*5c51f124SMoriah Waterland 		errno = EFAULT;
848*5c51f124SMoriah Waterland 		return (-1);
849*5c51f124SMoriah Waterland 	}
850*5c51f124SMoriah Waterland 
851*5c51f124SMoriah Waterland 	/* on buffer overflow generate error */
852*5c51f124SMoriah Waterland 
853*5c51f124SMoriah Waterland 	if ((avfp->_vfpOverflow != 0) || (vfpGetBytesAvailable(avfp) < 1)) {
854*5c51f124SMoriah Waterland 		errno = EFBIG;
855*5c51f124SMoriah Waterland 		return (-1);
856*5c51f124SMoriah Waterland 	}
857*5c51f124SMoriah Waterland 
858*5c51f124SMoriah Waterland 	/* no checkpointing is possible if the existing VFP is mmap()ed */
859*5c51f124SMoriah Waterland 
860*5c51f124SMoriah Waterland 	if (avfp->_vfpFlags & _VFP_MMAP) {
861*5c51f124SMoriah Waterland 		errno = EIO;
862*5c51f124SMoriah Waterland 		return (-1);
863*5c51f124SMoriah Waterland 	}
864*5c51f124SMoriah Waterland 
865*5c51f124SMoriah Waterland 	/* if no path specified, grab it from the VFP to checkpoint */
866*5c51f124SMoriah Waterland 
867*5c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) || (*a_path == '\0')) {
868*5c51f124SMoriah Waterland 		a_path = avfp->_vfpPath;
869*5c51f124SMoriah Waterland 	}
870*5c51f124SMoriah Waterland 
871*5c51f124SMoriah Waterland 	/* backing store required: if VFP is "string" then this is an error */
872*5c51f124SMoriah Waterland 
873*5c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) ||
874*5c51f124SMoriah Waterland 				strcmp(a_path, VFP_ANONYMOUS_PATH) == 0) {
875*5c51f124SMoriah Waterland 		errno = EINVAL;
876*5c51f124SMoriah Waterland 		return (-1);
877*5c51f124SMoriah Waterland 	}
878*5c51f124SMoriah Waterland 
879*5c51f124SMoriah Waterland 	/* Get the VFP to checkpoint (backing store) file size */
880*5c51f124SMoriah Waterland 
881*5c51f124SMoriah Waterland 	if (stat(a_path, &statbuf) != 0) {
882*5c51f124SMoriah Waterland 		return (-1);
883*5c51f124SMoriah Waterland 	}
884*5c51f124SMoriah Waterland 
885*5c51f124SMoriah Waterland 	/* allocate storage for checkpointed VFP (to return) */
886*5c51f124SMoriah Waterland 
887*5c51f124SMoriah Waterland 	vfp = (VFP_T *)malloc(sizeof (VFP_T));
888*5c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
889*5c51f124SMoriah Waterland 		return (-1);
890*5c51f124SMoriah Waterland 	}
891*5c51f124SMoriah Waterland 
892*5c51f124SMoriah Waterland 	/*
893*5c51f124SMoriah Waterland 	 * close any file that is on the VFP to checkpoint (backing store);
894*5c51f124SMoriah Waterland 	 * subsequent processes can modify the backing store data, and
895*5c51f124SMoriah Waterland 	 * then when vfpCheckpointOpen is called, either the in-memory
896*5c51f124SMoriah Waterland 	 * cached data will be used (if backing store unmodified) or else
897*5c51f124SMoriah Waterland 	 * the in-memory data is released and the backing store is used.
898*5c51f124SMoriah Waterland 	 */
899*5c51f124SMoriah Waterland 
900*5c51f124SMoriah Waterland 	if (avfp->_vfpFile != (FILE *)NULL) {
901*5c51f124SMoriah Waterland 		(void) fclose(avfp->_vfpFile);
902*5c51f124SMoriah Waterland 		avfp->_vfpFile = (FILE *)NULL;
903*5c51f124SMoriah Waterland 	}
904*5c51f124SMoriah Waterland 
905*5c51f124SMoriah Waterland 	/* free any path associated with VFP to checkpoint (backing store) */
906*5c51f124SMoriah Waterland 
907*5c51f124SMoriah Waterland 	if (avfp->_vfpPath != (char *)NULL) {
908*5c51f124SMoriah Waterland 		(void) free(avfp->_vfpPath);
909*5c51f124SMoriah Waterland 		avfp->_vfpPath = (char *)NULL;
910*5c51f124SMoriah Waterland 	}
911*5c51f124SMoriah Waterland 
912*5c51f124SMoriah Waterland 	/* copy contents of VFP to checkpoint to checkpointed VFP */
913*5c51f124SMoriah Waterland 
914*5c51f124SMoriah Waterland 	memcpy(vfp, avfp, sizeof (VFP_T));
915*5c51f124SMoriah Waterland 
916*5c51f124SMoriah Waterland 	/* free contents of VFP to checkpoint */
917*5c51f124SMoriah Waterland 
918*5c51f124SMoriah Waterland 	(void) free(avfp);
919*5c51f124SMoriah Waterland 
920*5c51f124SMoriah Waterland 	/* reset pointer to VFP that has been free'd */
921*5c51f124SMoriah Waterland 
922*5c51f124SMoriah Waterland 	*a_vfp = (VFP_T *)NULL;
923*5c51f124SMoriah Waterland 
924*5c51f124SMoriah Waterland 	/* remember path associated with the checkpointed VFP (backing store) */
925*5c51f124SMoriah Waterland 
926*5c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path);
927*5c51f124SMoriah Waterland 
928*5c51f124SMoriah Waterland 	/* save tokens that identify the backing store for the in-memory data */
929*5c51f124SMoriah Waterland 
930*5c51f124SMoriah Waterland 	vfp->_vfpCkDev = statbuf.st_dev;	/* devid holding st_ino inode */
931*5c51f124SMoriah Waterland 	vfp->_vfpCkIno = statbuf.st_ino;	/* backing store inode */
932*5c51f124SMoriah Waterland 	vfp->_vfpCkMtime = statbuf.st_mtime;	/* last data modification */
933*5c51f124SMoriah Waterland 	vfp->_vfpCkSize = statbuf.st_size;	/* backing store size (bytes) */
934*5c51f124SMoriah Waterland 	vfp->_vfpCkStBlocks = statbuf.st_blocks; /* blocks allocated to file */
935*5c51f124SMoriah Waterland 
936*5c51f124SMoriah Waterland 	/* pass checkpointed VFP to caller */
937*5c51f124SMoriah Waterland 
938*5c51f124SMoriah Waterland 	(*r_cpVfp) = vfp;
939*5c51f124SMoriah Waterland 
940*5c51f124SMoriah Waterland 	/* success! */
941*5c51f124SMoriah Waterland 
942*5c51f124SMoriah Waterland 	return (0);
943*5c51f124SMoriah Waterland }
944*5c51f124SMoriah Waterland 
945*5c51f124SMoriah Waterland /*
946*5c51f124SMoriah Waterland  * Name:	vfpCheckpointOpen
947*5c51f124SMoriah Waterland  * Description:	Open file on vfp, allocate storage, return pointer to VFP_T
948*5c51f124SMoriah Waterland  *		that can be used to access/modify file contents. If a VFP_T to
949*5c51f124SMoriah Waterland  *		a checkpointed VFP is passed in, and the in memory contents of
950*5c51f124SMoriah Waterland  *		the VFP are not out of date with respect to the backing store
951*5c51f124SMoriah Waterland  *		file, use the existing in-memory contents - otherwise, discard
952*5c51f124SMoriah Waterland  *		the in-memory contents and reopen and reread the file.
953*5c51f124SMoriah Waterland  * Arguments:	VFP_T **a_cpVfp - pointer to pointer to VFP_T that represents
954*5c51f124SMoriah Waterland  *			checkpointed VFP to use to open the file IF the contents
955*5c51f124SMoriah Waterland  *			of the backing store are identical to the in-memory data
956*5c51f124SMoriah Waterland  *		VFP_T **r_vfp - pointer to pointer to VFP_T to open file on
957*5c51f124SMoriah Waterland  *		char *a_path - path of file to open and associate with this VFP.
958*5c51f124SMoriah Waterland  *			- if the path is (char *)NULL then no file is associated
959*5c51f124SMoriah Waterland  *			  with this VFP - this is a way to create a fixed length
960*5c51f124SMoriah Waterland  *			  string that can be manipulated with the VFP operators.
961*5c51f124SMoriah Waterland  *			  Before the VFP can be used "vfpSetSize" must be called
962*5c51f124SMoriah Waterland  *			  to set the size of the string buffer.
963*5c51f124SMoriah Waterland  *		char *a_mode - fopen mode to open the file with
964*5c51f124SMoriah Waterland  *		VFPFLAGS_T a_flags - one or more flags to control the operation:
965*5c51f124SMoriah Waterland  *			- VFP_NONE - no special flags
966*5c51f124SMoriah Waterland  *			- VFP_NEEDNOW - file data needed in memory now
967*5c51f124SMoriah Waterland  *			- VFP_SEQUENTIAL - memory will be sequentially accessed
968*5c51f124SMoriah Waterland  *			- VFP_RANDOM - memory will be randomly accessed
969*5c51f124SMoriah Waterland  *			- VFP_NOMMAP - do not use mmap to access file
970*5c51f124SMoriah Waterland  *			- VFP_NOMALLOC - do not use malloc to buffer file
971*5c51f124SMoriah Waterland  * Returns:	int	== 0 - operation was successful
972*5c51f124SMoriah Waterland  *			!= 0 - operation failed, errno contains reason
973*5c51f124SMoriah Waterland  * Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
974*5c51f124SMoriah Waterland  *			which can be used with the various VFP functions.
975*5c51f124SMoriah Waterland  *		a_cpVfp -- contents reset to zero if used to open the file
976*5c51f124SMoriah Waterland  *		errno -- contains system error number if return is != 0
977*5c51f124SMoriah Waterland  */
978*5c51f124SMoriah Waterland 
979*5c51f124SMoriah Waterland int
980*5c51f124SMoriah Waterland vfpCheckpointOpen(VFP_T **a_cpVfp, VFP_T **r_vfp, char *a_path,
981*5c51f124SMoriah Waterland 	char *a_mode, VFPFLAGS_T a_flags)
982*5c51f124SMoriah Waterland {
983*5c51f124SMoriah Waterland 	FILE		*fp;	/* backing store */
984*5c51f124SMoriah Waterland 	VFP_T		*cpVfp;	/* local -> to a_cpVfp checkpointed VFP */
985*5c51f124SMoriah Waterland 	VFP_T		*vfp;	/* new VFP open on checkpointed backing store */
986*5c51f124SMoriah Waterland 	struct stat	statbuf; /* stat(2) info on backing store */
987*5c51f124SMoriah Waterland 
988*5c51f124SMoriah Waterland 	/*
989*5c51f124SMoriah Waterland 	 * if no source VFP, or source VFP empty,
990*5c51f124SMoriah Waterland 	 * or no backing store, just open file
991*5c51f124SMoriah Waterland 	 */
992*5c51f124SMoriah Waterland 
993*5c51f124SMoriah Waterland 	if ((a_cpVfp == (VFP_T **)NULL) || (*a_cpVfp == (VFP_T *)NULL) ||
994*5c51f124SMoriah Waterland 		((*a_cpVfp)->_vfpStart == (char *)NULL)) {
995*5c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
996*5c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
997*5c51f124SMoriah Waterland 	}
998*5c51f124SMoriah Waterland 
999*5c51f124SMoriah Waterland 	/* localize access to checkpointed VFP_T (*a_cpVfp) */
1000*5c51f124SMoriah Waterland 
1001*5c51f124SMoriah Waterland 	cpVfp = *a_cpVfp;
1002*5c51f124SMoriah Waterland 
1003*5c51f124SMoriah Waterland 	/* if no path specified, grab it from the checkpointed VFP */
1004*5c51f124SMoriah Waterland 
1005*5c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) || (*a_path == '\0')) {
1006*5c51f124SMoriah Waterland 		a_path = cpVfp->_vfpPath;
1007*5c51f124SMoriah Waterland 	}
1008*5c51f124SMoriah Waterland 
1009*5c51f124SMoriah Waterland 	/* return error if no path specified and no path in checkpointed VFP */
1010*5c51f124SMoriah Waterland 
1011*5c51f124SMoriah Waterland 	if ((a_path == (char *)NULL) && (*a_path == '\0')) {
1012*5c51f124SMoriah Waterland 		errno = EINVAL;
1013*5c51f124SMoriah Waterland 		return (-1);
1014*5c51f124SMoriah Waterland 	}
1015*5c51f124SMoriah Waterland 
1016*5c51f124SMoriah Waterland 	/* if no backing store path, then just open file */
1017*5c51f124SMoriah Waterland 
1018*5c51f124SMoriah Waterland 	if (stat(a_path, &statbuf) != 0) {
1019*5c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
1020*5c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
1021*5c51f124SMoriah Waterland 	}
1022*5c51f124SMoriah Waterland 
1023*5c51f124SMoriah Waterland 	/*
1024*5c51f124SMoriah Waterland 	 * if backing store tokens do not match checkpointed VFP,
1025*5c51f124SMoriah Waterland 	 * the backing store has been updated since the VFP was checkpointed;
1026*5c51f124SMoriah Waterland 	 * release the in-memory data, and open and read the backing store
1027*5c51f124SMoriah Waterland 	 */
1028*5c51f124SMoriah Waterland 
1029*5c51f124SMoriah Waterland 	if ((statbuf.st_size != cpVfp->_vfpCkSize) ||
1030*5c51f124SMoriah Waterland 		(statbuf.st_mtime != cpVfp->_vfpCkMtime) ||
1031*5c51f124SMoriah Waterland 		(statbuf.st_blocks != cpVfp->_vfpCkStBlocks) ||
1032*5c51f124SMoriah Waterland 		(statbuf.st_ino != cpVfp->_vfpCkIno) ||
1033*5c51f124SMoriah Waterland 		(statbuf.st_dev != cpVfp->_vfpCkDev)) {
1034*5c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
1035*5c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
1036*5c51f124SMoriah Waterland 	}
1037*5c51f124SMoriah Waterland 
1038*5c51f124SMoriah Waterland 	/*
1039*5c51f124SMoriah Waterland 	 * backing store has not been updated since the VFP was checkpointed;
1040*5c51f124SMoriah Waterland 	 * use the in-memory data without re-reading the backing store; open the
1041*5c51f124SMoriah Waterland 	 * backing store file (if no file already open on the checkpointed VFP)
1042*5c51f124SMoriah Waterland 	 * so there is an open file associated with the in-memory data
1043*5c51f124SMoriah Waterland 	 */
1044*5c51f124SMoriah Waterland 
1045*5c51f124SMoriah Waterland 	fp = cpVfp->_vfpFile;
1046*5c51f124SMoriah Waterland 	if (fp == (FILE *)NULL) {
1047*5c51f124SMoriah Waterland 		fp = fopen(a_path, a_mode);
1048*5c51f124SMoriah Waterland 		if (fp == (FILE *)NULL) {
1049*5c51f124SMoriah Waterland 			int	lerrno;
1050*5c51f124SMoriah Waterland 
1051*5c51f124SMoriah Waterland 			lerrno = errno;
1052*5c51f124SMoriah Waterland 			(void) vfpClose(a_cpVfp);
1053*5c51f124SMoriah Waterland 			errno = lerrno;
1054*5c51f124SMoriah Waterland 			return (-1);
1055*5c51f124SMoriah Waterland 		}
1056*5c51f124SMoriah Waterland 	}
1057*5c51f124SMoriah Waterland 
1058*5c51f124SMoriah Waterland 	/* allocate new VFP object to return as open VFP */
1059*5c51f124SMoriah Waterland 
1060*5c51f124SMoriah Waterland 	vfp = (VFP_T *)malloc(sizeof (VFP_T));
1061*5c51f124SMoriah Waterland 	if (vfp == (VFP_T *)NULL) {
1062*5c51f124SMoriah Waterland 		(void) vfpClose(a_cpVfp);
1063*5c51f124SMoriah Waterland 		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
1064*5c51f124SMoriah Waterland 	}
1065*5c51f124SMoriah Waterland 
1066*5c51f124SMoriah Waterland 	/* copy cached checkpointed VFP to new VFP to return */
1067*5c51f124SMoriah Waterland 
1068*5c51f124SMoriah Waterland 	(void) memcpy(vfp, cpVfp, sizeof (VFP_T));
1069*5c51f124SMoriah Waterland 
1070*5c51f124SMoriah Waterland 	/*
1071*5c51f124SMoriah Waterland 	 * initialize VFP to return contents
1072*5c51f124SMoriah Waterland 	 */
1073*5c51f124SMoriah Waterland 
1074*5c51f124SMoriah Waterland 	/* FILE -> file opened on the VFPs backing store */
1075*5c51f124SMoriah Waterland 
1076*5c51f124SMoriah Waterland 	vfp->_vfpFile = fp;
1077*5c51f124SMoriah Waterland 
1078*5c51f124SMoriah Waterland 	/* release any existing path associated with the VFP */
1079*5c51f124SMoriah Waterland 
1080*5c51f124SMoriah Waterland 	if (vfp->_vfpPath != (char *)NULL) {
1081*5c51f124SMoriah Waterland 		(void) free(vfp->_vfpPath);
1082*5c51f124SMoriah Waterland 	}
1083*5c51f124SMoriah Waterland 
1084*5c51f124SMoriah Waterland 	/* path associated with the backing store for this VFP */
1085*5c51f124SMoriah Waterland 
1086*5c51f124SMoriah Waterland 	vfp->_vfpPath = strdup(a_path);
1087*5c51f124SMoriah Waterland 
1088*5c51f124SMoriah Waterland 	/*
1089*5c51f124SMoriah Waterland 	 * data pointers associated with in memory copy of backing store
1090*5c51f124SMoriah Waterland 	 * (such as _vfpHighWater, _vfpEnd, _vfpStart, etc.)
1091*5c51f124SMoriah Waterland 	 * do not need to be modified because we are using the same backing
1092*5c51f124SMoriah Waterland 	 * store as was checkpointed in cpVfp that is pointed to by vfp.
1093*5c51f124SMoriah Waterland 	 */
1094*5c51f124SMoriah Waterland 
1095*5c51f124SMoriah Waterland 	/* _vfpCurr -> next byte to read */
1096*5c51f124SMoriah Waterland 	vfp->_vfpCurr = (char *)vfp->_vfpStart;
1097*5c51f124SMoriah Waterland 
1098*5c51f124SMoriah Waterland 	/* free checkpointed VFP as it is now open on "vfp" */
1099*5c51f124SMoriah Waterland 
1100*5c51f124SMoriah Waterland 	(void) free(cpVfp);
1101*5c51f124SMoriah Waterland 
1102*5c51f124SMoriah Waterland 	/* reset callers -> checkpointed VFP */
1103*5c51f124SMoriah Waterland 
1104*5c51f124SMoriah Waterland 	(*a_cpVfp) = (VFP_T *)NULL;
1105*5c51f124SMoriah Waterland 
1106*5c51f124SMoriah Waterland 	/* set return VFP pointer */
1107*5c51f124SMoriah Waterland 
1108*5c51f124SMoriah Waterland 	(*r_vfp) = vfp;
1109*5c51f124SMoriah Waterland 
1110*5c51f124SMoriah Waterland 	/* success! */
1111*5c51f124SMoriah Waterland 
1112*5c51f124SMoriah Waterland 	return (0);
1113*5c51f124SMoriah Waterland }
1114*5c51f124SMoriah Waterland 
1115*5c51f124SMoriah Waterland /*
1116*5c51f124SMoriah Waterland  * Name:	vfpClearModified
1117*5c51f124SMoriah Waterland  * Description:	Clear the "data is modified" indication from the VFP
1118*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to clear
1119*5c51f124SMoriah Waterland  *			the "data is modified" indication
1120*5c51f124SMoriah Waterland  * Returns:	int	- previous setting of "data is modified" indication
1121*5c51f124SMoriah Waterland  *			== 0 - "data is modified" was NOT previously set
1122*5c51f124SMoriah Waterland  *			!= 0 - "data is modified" WAS previously set
1123*5c51f124SMoriah Waterland  */
1124*5c51f124SMoriah Waterland 
1125*5c51f124SMoriah Waterland int
1126*5c51f124SMoriah Waterland vfpClearModified(VFP_T *a_vfp)
1127*5c51f124SMoriah Waterland {
1128*5c51f124SMoriah Waterland 	VFPFLAGS_T	flags;
1129*5c51f124SMoriah Waterland 
1130*5c51f124SMoriah Waterland 	/* save current flags settings */
1131*5c51f124SMoriah Waterland 
1132*5c51f124SMoriah Waterland 	flags = a_vfp->_vfpFlags;
1133*5c51f124SMoriah Waterland 
1134*5c51f124SMoriah Waterland 	/* clear "data is modified" flag */
1135*5c51f124SMoriah Waterland 
1136*5c51f124SMoriah Waterland 	a_vfp->_vfpFlags &= (~_VFP_MODIFIED);
1137*5c51f124SMoriah Waterland 
1138*5c51f124SMoriah Waterland 	/* return previous "data is modified" flag setting */
1139*5c51f124SMoriah Waterland 
1140*5c51f124SMoriah Waterland 	return ((flags & _VFP_MODIFIED) != 0);
1141*5c51f124SMoriah Waterland }
1142*5c51f124SMoriah Waterland 
1143*5c51f124SMoriah Waterland /*
1144*5c51f124SMoriah Waterland  * Name:	vfpSetModified
1145*5c51f124SMoriah Waterland  * Description:	Set the "data is modified" indication from the VFP
1146*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to set
1147*5c51f124SMoriah Waterland  *			the "data is modified" indication
1148*5c51f124SMoriah Waterland  * Returns:	int	- previous setting of "data is modified" indication
1149*5c51f124SMoriah Waterland  *			== 0 - "data is modified" was NOT previously set
1150*5c51f124SMoriah Waterland  *			!= 0 - "data is modified" WAS previously set
1151*5c51f124SMoriah Waterland  */
1152*5c51f124SMoriah Waterland 
1153*5c51f124SMoriah Waterland int
1154*5c51f124SMoriah Waterland vfpSetModified(VFP_T *a_vfp)
1155*5c51f124SMoriah Waterland {
1156*5c51f124SMoriah Waterland 	VFPFLAGS_T	flags;
1157*5c51f124SMoriah Waterland 
1158*5c51f124SMoriah Waterland 	/* save current flags settings */
1159*5c51f124SMoriah Waterland 
1160*5c51f124SMoriah Waterland 	flags = a_vfp->_vfpFlags;
1161*5c51f124SMoriah Waterland 
1162*5c51f124SMoriah Waterland 	/* set "data is modified" flag */
1163*5c51f124SMoriah Waterland 
1164*5c51f124SMoriah Waterland 	a_vfp->_vfpFlags |= _VFP_MODIFIED;
1165*5c51f124SMoriah Waterland 
1166*5c51f124SMoriah Waterland 	/* return previous "data is modified" flag setting */
1167*5c51f124SMoriah Waterland 
1168*5c51f124SMoriah Waterland 	return ((flags & _VFP_MODIFIED) != 0);
1169*5c51f124SMoriah Waterland }
1170*5c51f124SMoriah Waterland 
1171*5c51f124SMoriah Waterland /*
1172*5c51f124SMoriah Waterland  * Name:	vfpGetModified
1173*5c51f124SMoriah Waterland  * Description:	Get the "data is modified" indication from the VFP
1174*5c51f124SMoriah Waterland  * Arguments:	VFP_T *a_vfp - VFP_T pointer associated with file to get
1175*5c51f124SMoriah Waterland  *			the "data is modified" indication
1176*5c51f124SMoriah Waterland  * Returns:	int	- current setting of "data is modified" indication
1177*5c51f124SMoriah Waterland  *			== 0 - "data is modified" is NOT set
1178*5c51f124SMoriah Waterland  *			!= 0 - "data is modified" IS set
1179*5c51f124SMoriah Waterland  */
1180*5c51f124SMoriah Waterland 
1181*5c51f124SMoriah Waterland int
1182*5c51f124SMoriah Waterland vfpGetModified(VFP_T *a_vfp)
1183*5c51f124SMoriah Waterland {
1184*5c51f124SMoriah Waterland 	/* return current "data is modified" flag setting */
1185*5c51f124SMoriah Waterland 
1186*5c51f124SMoriah Waterland 	return ((a_vfp->_vfpFlags & _VFP_MODIFIED) != 0);
1187*5c51f124SMoriah Waterland }
1188*5c51f124SMoriah Waterland 
1189*5c51f124SMoriah Waterland /*
1190*5c51f124SMoriah Waterland  * Name:	vfpSafeWrite
1191*5c51f124SMoriah Waterland  * Description:	write data to open file safely
1192*5c51f124SMoriah Waterland  * Arguments:	a_fildes - file descriptor to write data to
1193*5c51f124SMoriah Waterland  *		a_buf - pointer to buffer containing data to write
1194*5c51f124SMoriah Waterland  *		a_nbyte - number of bytes to write to open file
1195*5c51f124SMoriah Waterland  * Returns:	int
1196*5c51f124SMoriah Waterland  *		< 0 - error, errno set
1197*5c51f124SMoriah Waterland  *		>= 0 - success
1198*5c51f124SMoriah Waterland  * NOTE: unlike write(2), vfpSafeWrite() handles partial writes, and will
1199*5c51f124SMoriah Waterland  * ----- restart the write() until all bytes are written, or an error occurs.
1200*5c51f124SMoriah Waterland  */
1201*5c51f124SMoriah Waterland 
1202*5c51f124SMoriah Waterland ssize_t
1203*5c51f124SMoriah Waterland vfpSafeWrite(int a_fildes, void *a_buf, size_t a_nbyte)
1204*5c51f124SMoriah Waterland {
1205*5c51f124SMoriah Waterland 	ssize_t	r;
1206*5c51f124SMoriah Waterland 	size_t	bytes = a_nbyte;
1207*5c51f124SMoriah Waterland 
1208*5c51f124SMoriah Waterland 	for (;;) {
1209*5c51f124SMoriah Waterland 		/* write bytes to file */
1210*5c51f124SMoriah Waterland 		r = write(a_fildes, a_buf, a_nbyte);
1211*5c51f124SMoriah Waterland 
1212*5c51f124SMoriah Waterland 		/* return error on failure of write() */
1213*5c51f124SMoriah Waterland 		if (r < 0) {
1214*5c51f124SMoriah Waterland 			/* EAGAIN: try again */
1215*5c51f124SMoriah Waterland 			if (errno == EAGAIN) {
1216*5c51f124SMoriah Waterland 				continue;
1217*5c51f124SMoriah Waterland 			}
1218*5c51f124SMoriah Waterland 			/* EINTR: interrupted - try again */
1219*5c51f124SMoriah Waterland 			if (errno == EINTR) {
1220*5c51f124SMoriah Waterland 				continue;
1221*5c51f124SMoriah Waterland 			}
1222*5c51f124SMoriah Waterland 			return (r);
1223*5c51f124SMoriah Waterland 		}
1224*5c51f124SMoriah Waterland 
1225*5c51f124SMoriah Waterland 		/* return total bytes written on success */
1226*5c51f124SMoriah Waterland 		if (r >= a_nbyte) {
1227*5c51f124SMoriah Waterland 			return (bytes);
1228*5c51f124SMoriah Waterland 		}
1229*5c51f124SMoriah Waterland 
1230*5c51f124SMoriah Waterland 		/* partial write, adjust pointers, call write again */
1231*5c51f124SMoriah Waterland 		a_buf = (void *)((ptrdiff_t)a_buf + (ptrdiff_t)r);
1232*5c51f124SMoriah Waterland 		a_nbyte -= (size_t)r;
1233*5c51f124SMoriah Waterland 	}
1234*5c51f124SMoriah Waterland }
1235*5c51f124SMoriah Waterland 
1236*5c51f124SMoriah Waterland /*
1237*5c51f124SMoriah Waterland  * Name:	vfpSafePwrite
1238*5c51f124SMoriah Waterland  * Description:	write data to open file safely
1239*5c51f124SMoriah Waterland  * Arguments:	a_fildes - file descriptor to write data to
1240*5c51f124SMoriah Waterland  *		a_buf - pointer to buffer containing data to write
1241*5c51f124SMoriah Waterland  *		a_nbyte - number of bytes to write to open file
1242*5c51f124SMoriah Waterland  *		a_offset - offset into open file to write the first byte to
1243*5c51f124SMoriah Waterland  * Returns:	int
1244*5c51f124SMoriah Waterland  *		< 0 - error, errno set
1245*5c51f124SMoriah Waterland  *		>= 0 - success
1246*5c51f124SMoriah Waterland  * NOTE: unlike pwrite(2), vfpSafePwrite() handles partial writes, and will
1247*5c51f124SMoriah Waterland  * ----- restart the pwrite() until all bytes are written, or an error occurs.
1248*5c51f124SMoriah Waterland  */
1249*5c51f124SMoriah Waterland 
1250*5c51f124SMoriah Waterland ssize_t
1251*5c51f124SMoriah Waterland vfpSafePwrite(int a_fildes, void *a_buf, size_t a_nbyte, off_t a_offset)
1252*5c51f124SMoriah Waterland {
1253*5c51f124SMoriah Waterland 	ssize_t	r;
1254*5c51f124SMoriah Waterland 	size_t	bytes = a_nbyte;
1255*5c51f124SMoriah Waterland 
1256*5c51f124SMoriah Waterland 	for (;;) {
1257*5c51f124SMoriah Waterland 		/* write bytes to file */
1258*5c51f124SMoriah Waterland 		r = pwrite(a_fildes, a_buf, a_nbyte, a_offset);
1259*5c51f124SMoriah Waterland 
1260*5c51f124SMoriah Waterland 		/* return error on failure of write() */
1261*5c51f124SMoriah Waterland 		if (r < 0) {
1262*5c51f124SMoriah Waterland 			/* EAGAIN: try again */
1263*5c51f124SMoriah Waterland 			if (errno == EAGAIN) {
1264*5c51f124SMoriah Waterland 				continue;
1265*5c51f124SMoriah Waterland 			}
1266*5c51f124SMoriah Waterland 			/* EINTR: interrupted - try again */
1267*5c51f124SMoriah Waterland 			if (errno == EINTR) {
1268*5c51f124SMoriah Waterland 				continue;
1269*5c51f124SMoriah Waterland 			}
1270*5c51f124SMoriah Waterland 			return (r);
1271*5c51f124SMoriah Waterland 		}
1272*5c51f124SMoriah Waterland 
1273*5c51f124SMoriah Waterland 		/* return total bytes written on success */
1274*5c51f124SMoriah Waterland 		if (r >= a_nbyte) {
1275*5c51f124SMoriah Waterland 			return (bytes);
1276*5c51f124SMoriah Waterland 		}
1277*5c51f124SMoriah Waterland 
1278*5c51f124SMoriah Waterland 		/* partial write, adjust pointers, call write again */
1279*5c51f124SMoriah Waterland 		a_buf = (void *)((ptrdiff_t)a_buf + (ptrdiff_t)r);
1280*5c51f124SMoriah Waterland 		a_nbyte -= (size_t)r;
1281*5c51f124SMoriah Waterland 		a_offset += (off_t)r;
1282*5c51f124SMoriah Waterland 	}
1283*5c51f124SMoriah Waterland }
1284