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