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