/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Module: vfpops.c
* Synopsis: Implements virtual file protocol operations
* Description:
*
* This module implements the "Virtual File protocol" operations. These
* operations are intended to provide very fast access to file data,
* allowing a file to be accessed in very efficient ways with extremely
* low-cpu intensive operations. If possible file data is mapped directly
* into memory allowing the data to be accessed directly. If the data
* cannot be mapped directly into memory, memory will be allocated and
* the file data read directly into memory. If that fails currently the
* file data is not accessible. Other methods of making the file could
* be implemented in the future (e.g. stdio if all else fails).
*
* In general any code that uses stdio to access a file can be changed
* to use the various "vfp" operations to access a file, with a resulting
* increase in performance and decrease in cpu time required to access
* the file contents.
*
* Public Methods:
*
* vfpCheckpointFile - Create new VFP that checkpoints existing VFP
* vfpCheckpointOpen - open file, allocate storage, return pointer to VFP_T
* vfpClose - close file associated with vfp
* vfpDecCurrPtr - decrement current character pointer
* vfpGetBytesRemaining - get number of bytes remaining to read
* vfpGetCurrCharPtr - get pointer to current character
* vfpGetCurrPtrDelta - get number of bytes between current and specified char
* vfpGetFirstCharPtr - get pointer to first character
* vfpGetLastCharPtr - get pointer to last character
* vfpGetModifiedLen - get highest modified byte (length) contained in vfp
* vfpGetPath - get the path associated with the vfp
* vfpGetc - get current character and increment to next
* vfpGetcNoInc - get current character - do not increment
* vfpGets - get a string from the vfp into a fixed size buffer
* vfpIncCurrPtr - increment current character pointer
* vfpIncCurrPtrBy - increment current pointer by specified delta
* vfpOpen - open file on vfp
* vfpPutBytes - put fixed number of bytes to current character and increment
* vfpPutFormat - put format one arg to current character and increment
* vfpPutInteger - put integer to current character and increment
* vfpPutLong - put long to current character and increment
* vfpPutc - put current character and increment to next
* vfpPuts - put string to current character and increment
* vfpRewind - rewind file to first byte
* vfpSeekToEnd - seek to end of file
* vfpSetCurrCharPtr - set pointer to current character
* vfpSetFlags - set flags that affect file access
* vfpSetSize - set size of file (for writing)
* vfpTruncate - truncate file
* vfpWriteToFile - write data contained in vfp to specified file
*/
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <libintl.h>
#include "pkglib.h"
#include "pkgstrct.h"
#include "pkglocale.h"
/*
* These are internal flags that occupy the high order byte of the VFPFLAGS_T
* flags element of the vfp. These flags may only occupy the high order order
* 16 bits of the 32-bit unsigned vfp "flags" object.
*/
/* path name given to "anonymous" (string) vfp */
/* minimum size file to mmap (64mb) */
/*
* *****************************************************************************
* global external (public) functions
* *****************************************************************************
*/
/*
* Name: vfpOpen
* Description: Open file on vfp, allocate storage, return pointer to VFP_T
* Arguments: VFP_T **r_vfp - pointer to pointer to VFP_T
* char *a_path - path of file to open and associate with this VFP.
* - if the path is (char *)NULL then no file is associated
* with this VFP - this is a way to create a fixed length
* string that can be manipulated with the VFP operators.
* Before the VFP can be used "vfpSetSize" must be called
* to set the size of the string buffer.
* char *a_mode - fopen mode to open the file with
* VFPFLAGS_T a_flags - one or more flags to control the operation:
* - VFP_NONE - no special flags
* - VFP_NEEDNOW - file data needed in memory now
* - VFP_SEQUENTIAL - memory will be sequentially accessed
* - VFP_RANDOM - memory will be randomly accessed
* - VFP_NOMMAP - do not use mmap to access file
* - VFP_NOMALLOC - do not use malloc to buffer file
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
* Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
* which can be used with the various vfp functions.
* errno -- contains system error number if return is != 0
*/
int
{
int lerrno;
/* allocate pre-zeroed vfp object */
return (-1);
}
/* create "string" vfp if no path specified */
/*
* no path specified - no open file associated with vfp
* The vfp is initialized to all zeros - initialize just those
* values that need to be non-zero.
*/
return (0);
}
/*
* path specified - associate open file with vfp;
* return an error if no path or mode specified
*/
return (-1);
}
/* return an error if an empty path or mode specified */
return (-1);
}
/* open the file */
return (-1);
}
/* Get the file size */
return (-1);
}
/*
* Obtain access to existing file contents:
* -> plan a: map contents file into memory
* -> plan b: on failure just read into large buffer
*/
/* attempt to mmap file if mmap is allowed */
/*
* if file is a regular file, and if mmap allowed,
* and (malloc not forbidden or size is > minumum size to mmap)
*/
char *p;
/* set size to current size of file */
/*
* compute proper size for mapping for the file contents;
* add in one extra page so falling off end when file size is
* exactly modulo page size does not cause a page fault to
* guarantee that the end of the file contents will always
* contain a '\0' null character.
*/
/*
* mmap allowed: mmap file into memory
* first allocate space on top of which the mapping can be done;
* this way we can guarantee that if the mapping happens to be
* an exact multiple of a page size, that there will be at least
* one byte past the end of the mapping that can be accessed and
* that is guaranteed to be zero.
*/
/* allocate backing space */
if (p == (char *)NULL) {
} else {
/* guarantee first byte after end of data is zero */
/* map file on top of the backing space */
/* if mmap succeeded set mmap used flag in vfp */
}
}
}
/* if map failed (or not allowed) attempt malloc (if allowed) */
/* mmap failed - plan b: read directly into memory */
/*
* compute proper size for allocating storage for file contents;
* add in one extra page so falling off end when file size is
* exactly modulo page size does not cause a page fault to
* guarantee that the end of the file contents will always
* contain a '\0' null character.
*/
/* allocate buffer to hold file data */
return (-1);
}
/* read the file into the buffer */
if (lerrno == 0) {
}
return (-1);
}
/* assure last byte+1 is null character */
}
/* set malloc used flag in vfp */
}
/* if no starting address all read methods failed */
/* no mmap() - no read() - cannot allocate memory */
return (-1);
}
/*
* initialize vfp contents
*/
/* _vfpCurr -> next byte to read */
/* _vfpEnd -> last data byte */
/* _vfpHighWater -> last byte written */
/* _vfpFile -> associated FILE* object */
/* set flags as appropriate */
/* retain path name */
if (*a_mode == 'w') {
}
if (*a_mode == 'r') {
}
/* set return vfp pointer */
/* All OK */
return (0);
}
/*
* Name: vfpClose
* Description: Close an open vfp, causing any modified data to be written out
* to the file associated with the vfp.
* Arguments: VFP_T **r_vfp - pointer to pointer to VFP_T returned by vfpOpen
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
* Side Effects: r_vfp is set to (VFP_T)NULL
*/
int
{
int ret;
int lerrno;
/* return error if NULL VFP_T** provided */
return (-1);
}
/* localize access to VFP_T */
/* return successful if NULL VFP_T* provided */
return (0);
}
/* reset return VFP_T* handle */
/*
* if closing a file that is open for writing, commit all data if the
* backing memory is volatile and if there is a file open to write
* the data to.
*/
/* determine number of bytes to write */
/* if modified bytes present commit data to the file */
if (len > 0) {
}
}
}
/* unmap the file mapping */
/* free the backing allocation */
}
/* free up path */
/* close the file */
ret = 0;
}
/* deallocate the vfp itself */
/* if the fclose() failed, return error and errno */
if (ret != 0) {
return (-1);
}
return (0);
}
/*
* Name: vfpSetFlags
* Description: Modify operation of VFP according to flags specified
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to set flags
* VFPFLAGS_T a_flags - one or more flags to control the operation:
* - VFP_NEEDNOW - file data needed in memory now
* - VFP_SEQUENTIAL - file data sequentially accessed
* - VFP_RANDOM - file data randomly accessed
* Any other flags specified are silently ignored.
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
*/
int
{
/* return if no vfp specified */
return (0);
}
/* if file data mapped into memory, apply vm flags */
/* mmap succeeded: properly advise vm system */
if (a_flags & VFP_NEEDNOW) {
/* advise vm system data is needed now */
}
if (a_flags & VFP_SEQUENTIAL) {
/* advise vm system data access is sequential */
}
if (a_flags & VFP_RANDOM) {
/* advise vm system data access is random */
}
}
return (0);
}
/*
* Name: vfpRewind
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to rewind
* Returns: void
* Operation is always successful
*/
void
{
/* return if no vfp specified */
return;
}
/* set high water mark of last modified data */
}
/* reset next character pointer to start of file data */
}
/*
* Name: vfpSetSize
* Description: Set size of in-memory image associated with VFP
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to set
* size_t a_size - number of bytes to associatge with VFP
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
* Side Effects:
* Currently only a file that is in malloc()ed memory can
* have its in-memory size changed.
* An error is returned If the file is mapped into memory.
* A file cannot be decreased in size - if the specified
* size is less than the current size, the operation is
* successful but no change in file size occurs.
* If no file is associated with the VFP (no "name" was
* given to vfpOpen) the first call to vfpSetSize allocates
* the initial size of the file data - effectively calling
* "malloc" to allocate the initial memory for the file data.
* Once an initial allocation has been made, subsequent calls
* to vfpSetSize are effectively a "realloc" of the existing
* file data.
* All existing file data is preserved.
*/
int
{
char *np;
/* return if no vfp specified */
return (0);
}
/* if malloc not used don't know how to set size right now */
return (-1);
}
/* adjust size to reflect extra page of data maintained */
a_size += getpagesize();
/* if size is not larger than current nothing to do */
return (0);
}
/* remember new size */
/* allocate/reallocate memory as appropriate */
return (-1);
}
} else {
return (-1);
}
np[0] = '\0';
}
/* make sure last allocated byte is a null */
/*
* adjust all pointers to account for buffer address change
*/
/* _vfpCurr -> next byte to read */
/* _vfpHighWater -> last byte written */
/* _vfpEnd -> last data byte */
/* _vfpStart -> first data byte */
return (0);
}
/*
* Name: vfpTruncate
* Description: Truncate data associated with VFP
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to truncate
* Returns: void
* Operation is always successful.
* Side Effects:
* In memory data associated with file is believed to be empty.
* Actual memory associated with file is not affected.
* If a file is associated with the VFP, it is truncated.
*/
void
{
/* return if no vfp specified */
return;
}
/*
* reset all pointers so that no data is associated with file
*/
/* current byte is start of data area */
/* last byte written is start of data area */
/* current character is NULL */
/* if file associated with VFP, truncate actual file */
}
}
/*
* Name: vfpWriteToFile
* Description: Write data associated with VFP to specified file
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to write
* char *a_path - path of file to write file data to
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
*/
int
{
int fd;
int lerrno = 0;
/* return if no vfp specified */
return (-1);
}
/* on buffer overflow generate error */
return (-1);
}
/* open file to write data to */
if (fd < 0) {
return (-1);
}
/* determine number of bytes to write */
/*
* if there is data associated with the file, write it out;
* if an error occurs, close the file and return failure.
*/
if (len > 0) {
/* error comitting data - return failure */
return (-1);
}
}
/* close the file */
/* data committed to backing store - clear the modified flag */
(void) vfpClearModified(a_vfp);
/* return success */
return (0);
}
/*
* Name: vfpCheckpointFile
* Description: Create new VFP that checkpoints existing VFP, can be used by
* subsequent call to vfpCheckpointOpen to open a file using the
* existing in-memory cache of the contents of the file
* Arguments: VFP_T **r_cpVfp - pointer to pointer to VFP_T to be filled in
* with "checkpointed file" VFP (backing store)
* VFP_T **a_vfp - pointer to pointer to VFP_T returned by vfpOpen
* representing the VFP to checkpoint
* char *a_path - path to file that is the backing store for the
* in-memory data represented by a_vfp - used to verify
* that the data in memory is not out of date with respect
* to the backing store when vfpCheckpointOpen is called
* == (char *)NULL - use path associated with a_vfp
* that is, the backing store file in use
* Returns: int == 0 - operation was successful
* - r_destVfp contains a pointer to a new VFP that
* may be used in a subsequent call to
* vfpCheckpointOpen
* - the VFP referenced by *a_vfp is free()ed and
* must no longer be referenced
* != 0 - operation failed, errno contains reason
* - the VFP referenced by *a_vfp is not affected;
* the caller may continue to use it
* Notes: If the data of a VFP to checkpoint is mmap()ed then this method
* returns failure - only malloc()ed data VFPs can be
* checkpointed.
*/
int
{
/* return error if NULL VFP_T** to checkpoint provided */
return (-1);
}
/* reset return checkpoint VFP pointer */
/* return error if no VFP to checkpoint specified */
return (-1);
}
/* localize reference to a_vfp */
/* return error if no VFP to checkpoint specified */
return (-1);
}
/* on buffer overflow generate error */
return (-1);
}
/* no checkpointing is possible if the existing VFP is mmap()ed */
return (-1);
}
/* if no path specified, grab it from the VFP to checkpoint */
}
/* backing store required: if VFP is "string" then this is an error */
return (-1);
}
/* Get the VFP to checkpoint (backing store) file size */
return (-1);
}
/* allocate storage for checkpointed VFP (to return) */
return (-1);
}
/*
* close any file that is on the VFP to checkpoint (backing store);
* subsequent processes can modify the backing store data, and
* then when vfpCheckpointOpen is called, either the in-memory
* cached data will be used (if backing store unmodified) or else
* the in-memory data is released and the backing store is used.
*/
}
/* free any path associated with VFP to checkpoint (backing store) */
}
/* copy contents of VFP to checkpoint to checkpointed VFP */
/* free contents of VFP to checkpoint */
/* reset pointer to VFP that has been free'd */
/* remember path associated with the checkpointed VFP (backing store) */
/* save tokens that identify the backing store for the in-memory data */
/* pass checkpointed VFP to caller */
/* success! */
return (0);
}
/*
* Name: vfpCheckpointOpen
* Description: Open file on vfp, allocate storage, return pointer to VFP_T
* a checkpointed VFP is passed in, and the in memory contents of
* the VFP are not out of date with respect to the backing store
* file, use the existing in-memory contents - otherwise, discard
* the in-memory contents and reopen and reread the file.
* Arguments: VFP_T **a_cpVfp - pointer to pointer to VFP_T that represents
* checkpointed VFP to use to open the file IF the contents
* of the backing store are identical to the in-memory data
* VFP_T **r_vfp - pointer to pointer to VFP_T to open file on
* char *a_path - path of file to open and associate with this VFP.
* - if the path is (char *)NULL then no file is associated
* with this VFP - this is a way to create a fixed length
* string that can be manipulated with the VFP operators.
* Before the VFP can be used "vfpSetSize" must be called
* to set the size of the string buffer.
* char *a_mode - fopen mode to open the file with
* VFPFLAGS_T a_flags - one or more flags to control the operation:
* - VFP_NONE - no special flags
* - VFP_NEEDNOW - file data needed in memory now
* - VFP_SEQUENTIAL - memory will be sequentially accessed
* - VFP_RANDOM - memory will be randomly accessed
* - VFP_NOMMAP - do not use mmap to access file
* - VFP_NOMALLOC - do not use malloc to buffer file
* Returns: int == 0 - operation was successful
* != 0 - operation failed, errno contains reason
* Side Effects: r_vfp -- filled in with a pointer to a newly allocated vfp
* which can be used with the various VFP functions.
* a_cpVfp -- contents reset to zero if used to open the file
* errno -- contains system error number if return is != 0
*/
int
{
/*
* if no source VFP, or source VFP empty,
* or no backing store, just open file
*/
}
/* localize access to checkpointed VFP_T (*a_cpVfp) */
/* if no path specified, grab it from the checkpointed VFP */
}
/* return error if no path specified and no path in checkpointed VFP */
return (-1);
}
/* if no backing store path, then just open file */
}
/*
* if backing store tokens do not match checkpointed VFP,
* the backing store has been updated since the VFP was checkpointed;
* release the in-memory data, and open and read the backing store
*/
}
/*
* backing store has not been updated since the VFP was checkpointed;
* use the in-memory data without re-reading the backing store; open the
* backing store file (if no file already open on the checkpointed VFP)
* so there is an open file associated with the in-memory data
*/
int lerrno;
return (-1);
}
}
/* allocate new VFP object to return as open VFP */
}
/* copy cached checkpointed VFP to new VFP to return */
/*
* initialize VFP to return contents
*/
/* FILE -> file opened on the VFPs backing store */
/* release any existing path associated with the VFP */
}
/* path associated with the backing store for this VFP */
/*
* data pointers associated with in memory copy of backing store
* (such as _vfpHighWater, _vfpEnd, _vfpStart, etc.)
* do not need to be modified because we are using the same backing
* store as was checkpointed in cpVfp that is pointed to by vfp.
*/
/* _vfpCurr -> next byte to read */
/* free checkpointed VFP as it is now open on "vfp" */
/* reset callers -> checkpointed VFP */
/* set return VFP pointer */
/* success! */
return (0);
}
/*
* Name: vfpClearModified
* Description: Clear the "data is modified" indication from the VFP
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to clear
* the "data is modified" indication
* Returns: int - previous setting of "data is modified" indication
* == 0 - "data is modified" was NOT previously set
* != 0 - "data is modified" WAS previously set
*/
int
{
/* save current flags settings */
/* clear "data is modified" flag */
/* return previous "data is modified" flag setting */
return ((flags & _VFP_MODIFIED) != 0);
}
/*
* Name: vfpSetModified
* Description: Set the "data is modified" indication from the VFP
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to set
* the "data is modified" indication
* Returns: int - previous setting of "data is modified" indication
* == 0 - "data is modified" was NOT previously set
* != 0 - "data is modified" WAS previously set
*/
int
{
/* save current flags settings */
/* set "data is modified" flag */
/* return previous "data is modified" flag setting */
return ((flags & _VFP_MODIFIED) != 0);
}
/*
* Name: vfpGetModified
* Description: Get the "data is modified" indication from the VFP
* Arguments: VFP_T *a_vfp - VFP_T pointer associated with file to get
* the "data is modified" indication
* Returns: int - current setting of "data is modified" indication
* == 0 - "data is modified" is NOT set
* != 0 - "data is modified" IS set
*/
int
{
/* return current "data is modified" flag setting */
}
/*
* Name: vfpSafeWrite
* Description: write data to open file safely
* Arguments: a_fildes - file descriptor to write data to
* a_buf - pointer to buffer containing data to write
* a_nbyte - number of bytes to write to open file
* Returns: int
* < 0 - error, errno set
* >= 0 - success
* NOTE: unlike write(2), vfpSafeWrite() handles partial writes, and will
* ----- restart the write() until all bytes are written, or an error occurs.
*/
{
ssize_t r;
for (;;) {
/* write bytes to file */
/* return error on failure of write() */
if (r < 0) {
/* EAGAIN: try again */
continue;
}
/* EINTR: interrupted - try again */
continue;
}
return (r);
}
/* return total bytes written on success */
if (r >= a_nbyte) {
return (bytes);
}
/* partial write, adjust pointers, call write again */
}
}
/*
* Name: vfpSafePwrite
* Description: write data to open file safely
* Arguments: a_fildes - file descriptor to write data to
* a_buf - pointer to buffer containing data to write
* a_nbyte - number of bytes to write to open file
* a_offset - offset into open file to write the first byte to
* Returns: int
* < 0 - error, errno set
* >= 0 - success
* NOTE: unlike pwrite(2), vfpSafePwrite() handles partial writes, and will
* ----- restart the pwrite() until all bytes are written, or an error occurs.
*/
{
ssize_t r;
for (;;) {
/* write bytes to file */
/* return error on failure of write() */
if (r < 0) {
/* EAGAIN: try again */
continue;
}
/* EINTR: interrupted - try again */
continue;
}
return (r);
}
/* return total bytes written on success */
if (r >= a_nbyte) {
return (bytes);
}
/* partial write, adjust pointers, call write again */
}
}