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 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 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 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 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 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 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 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 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 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 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 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 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 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 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