diff options
author | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
---|---|---|
committer | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
commit | 5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch) | |
tree | 0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/lib/libpkg/common/srchcfile.c | |
parent | 2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff) | |
download | illumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz |
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/lib/libpkg/common/srchcfile.c')
-rw-r--r-- | usr/src/lib/libpkg/common/srchcfile.c | 1278 |
1 files changed, 1278 insertions, 0 deletions
diff --git a/usr/src/lib/libpkg/common/srchcfile.c b/usr/src/lib/libpkg/common/srchcfile.c new file mode 100644 index 0000000000..dd24a855cd --- /dev/null +++ b/usr/src/lib/libpkg/common/srchcfile.c @@ -0,0 +1,1278 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + + +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <sys/types.h> +#include <libintl.h> +#include "pkglib.h" +#include "pkgstrct.h" +#include "pkglocale.h" +#include "pkglibmsgs.h" + +/* + * Forward declarations + */ + +static void findend(char **cp); +static int getend(char **cp); +static int getstr(char **cp, int n, char *str, int separator[]); + +/* from gpkgmap.c */ +int getnumvfp(char **cp, int base, long *d, long bad); +int getlnumvfp(char **cp, int base, fsblkcnt_t *d, long bad); + +/* + * Module globals + */ + +static char lpath[PATH_MAX]; /* for ept->path */ +static char mylocal[PATH_MAX]; /* for ept->ainfo.local */ +static int decisionTableInit = 0; + +/* + * These arrays must be indexable by an unsigned char. + */ + +static int ISPKGPATHSEP[UCHAR_MAX+1]; +static int ISWORDSEP[UCHAR_MAX+1]; +static int ISPKGNAMESEP[UCHAR_MAX+1]; + +/* + * Name: WRITEDATA + * Description: write out data to VFP_T given start and end pointers + * Arguments: VFP - (VFP_T *) - [RO, *RW] + * Contents file VFP to narrow search on + * FIRSTPOS - (char *) - [RO, *RO] + * Pointer to first byte to write out + * LASTPOS - (char *) - [RO, *RO] + * Pointer to last byte to write out + */ + +#define WRITEDATA(VFP, FIRSTPOS, LASTPOS) \ + { \ + ssize_t XXlenXX; \ + /* compute number of bytes skipped */ \ + XXlenXX = (ptrdiff_t)(LASTPOS) - (ptrdiff_t)(FIRSTPOS); \ + /* write the bytes out */ \ + vfpPutBytes((VFP), (FIRSTPOS), XXlenXX); \ + } + +/* + * Name: COPYPATH + * Description: copy path limiting size to destination capacity + * Arguments: DEST - (char []) - [RW] + * SRC - (char *) - [RO, *RO] + * Pointer to first byte of path to copy + * LEN - (int) - [RO] + * Number of bytes to copy + */ + +#define COPYPATH(DEST, SRC, LEN) \ + { \ + /* assure return path does not overflow */ \ + if ((LEN) > sizeof ((DEST))) { \ + (LEN) = sizeof ((DEST))-1; \ + } \ + /* copy return path to local storage */ \ + (void) memcpy((DEST), (SRC), (LEN)); \ + (DEST)[(LEN)] = '\0'; \ + } + +/* + * Name: narrowSearch + * Description: narrow the search location for a specified path + * The contents and package map files are always sorted by path. + * This function is given a target path to search for given the + * current location in a contents file. It is assured that the + * target path has not been searched for yet in the contents file + * so the current location in the contents file is guaranteed to + * be less than the location of the target path (if present). + * Given this employ a binary search to speed up the search for + * the path nearest to a specified target path. + * Arguments: a_vfp - (VFP_T *) - [RO, *RW] + * Contents file VFP to narrow search on + * a_path - (char *) - [RO, *RO] + * Pointer to path to search for + * a_pathLen - (size_t) - [RO] + * Length of string (a_path) + * Returns: char * - pointer to first byte of entry in contents file that + * is guaranteed to be the closest match to the specified + * a_path without being "greater than" the path. + * == (char *)NULL if no entry found + */ + +static char * +narrowSearch(VFP_T *a_vfp, char *a_path, size_t a_pathLen) +{ + char *phigh; + char *plow; + char *pmid; + int n; + size_t plen; + + /* if no path to compare, start at beginning */ + + if ((a_path == (char *)NULL) || (*a_path == '\0')) { + return ((char *)NULL); + } + + /* if the contents file is empty, resort to sequential search */ + + if (vfpGetBytesRemaining(a_vfp) <= 1) { + return ((char *)NULL); + } + + /* + * test against first path - if the path specified is less than the + * first path in the contents file, then the path can be inserted + * before the first entry in the contents file. + */ + + /* locate start of first line */ + + plow = vfpGetCurrCharPtr(a_vfp); + pmid = plow; + + /* if first path not absolute, resort to sequential search */ + + if (*pmid != '/') { + return ((char *)NULL); + } + + /* find end of path */ + + while (ISPKGPATHSEP[(int)*pmid] == 0) { + pmid++; + } + + /* determine length of path */ + + plen = (ptrdiff_t)pmid - (ptrdiff_t)plow; + + /* compare target path with current path */ + + n = strncmp(a_path, plow, plen); + if (n == 0) { + /* if lengths same exact match return position found */ + if (a_pathLen == plen) { + return (plow); + } + /* not exact match - a_path > pm */ + n = a_pathLen; + } + + /* return if target is less than or equal to first entry */ + + if (n <= 0) { + return (plow); + } + + /* + * test against last path - if the path specified is greater than the + * last path in the contents file, then the path can be appended after + * the last entry in the contents file. + */ + + /* locate start of last line */ + + plow = vfpGetCurrCharPtr(a_vfp); + pmid = vfpGetLastCharPtr(a_vfp); + + while ((pmid > plow) && (!((pmid[0] == '/') && (pmid[-1] == '\n')))) { + pmid--; + } + + /* if absolute path, do comparison */ + + if ((pmid > plow) && (*pmid == '/')) { + plow = pmid; + + /* find end of path */ + + while (ISPKGPATHSEP[(int)*pmid] == 0) { + pmid++; + } + + /* determine length of path */ + + plen = (ptrdiff_t)pmid - (ptrdiff_t)plow; + + /* compare target path with current path */ + + n = strncmp(a_path, plow, plen); + if (n == 0) { + /* if lengths same exact match return position found */ + if (a_pathLen == plen) { + return (plow); + } + /* not exact match - a_path > pm */ + n = a_pathLen; + } + + /* return if target is greater than or equal to entry */ + + if (n >= 0) { + return (plow); + } + } + /* + * firstPath < targetpath < lastPath: + * binary search looking for closest "less than" match + */ + + plow = vfpGetCurrCharPtr(a_vfp); + phigh = vfpGetLastCharPtr(a_vfp); + + for (;;) { + char *pm; + + /* determine number of bytes left in search area */ + + plen = (ptrdiff_t)phigh - (ptrdiff_t)plow; + + /* calculate mid point between current low and high points */ + + pmid = plow + (plen >> 1); + + /* backup and find first "\n/" -or- start of buffer */ + + while ((pmid > plow) && + (!((pmid[0] == '/') && (pmid[-1] == '\n')))) { + pmid--; + } + + /* return lowest line found if current line not past that */ + + if (pmid <= plow) { + return (plow); + } + + /* remember start of this line */ + + pm = pmid; + + /* find end of path */ + + while (ISPKGPATHSEP[(int)*pmid] == 0) { + pmid++; + } + + /* determine length of path */ + + plen = (ptrdiff_t)pmid - (ptrdiff_t)pm; + + /* compare target path with current path */ + + n = strncmp(a_path, pm, plen); + + if (n == 0) { + /* if lengths same exact match return position found */ + if (a_pathLen == plen) { + return (pm); + } + /* not exact match - a_path > pm */ + n = a_pathLen; + } + + + /* not exact match - determine which watermark to split */ + + if (n > 0) { /* a_path > pm */ + plow = pm; + } else { /* a_path < pm */ + phigh = pm; + } + } + /*NOTREACHED*/ +} + +/* + * Name: srchcfile + * Description: search contents file looking for closest match to entry, + * creating a new contents file if output contents file specified + * Arguments: ept - (struct cfent *) - [RO, *RW] + * - contents file entry, describing last item found + * path - (char *) - [RO, *RO] + * - path to search for in contents file + * - If path is "*", then the next entry is returned; + * the next entry always matches this path + * - If the path is (char *)NULL or "", then all remaining + * entries are processed and copied out to the + * file specified by cfTmpVFp + * cfVfp - (VFP_T *) - [RO, *RW] + * - VFP_T open on contents file to search + * cfTmpVfp - (VFP_T *) - [RO, *RW] + * - VFP_T open on temporary contents file to populate + * Returns: int + * < 0 - error occurred + * - Use getErrstr to retrieve character-string describing + * the reason for failure + * == 0 - no match found + * - specified path not in the contents file + * - all contents of cfVfp copied to cfTmpVfp + * - current character of cfVfp is at end of file + * == 1 - exact match found + * - specified path found in contents file + * - contents of cfVfp up to entry found copied to cfTmpVfp + * - current character of cfVfp is first character of + * entry found + * - this value is always returned if path is "*" and the + * next entry is returned - -1 is returned when no more + * entries are left to process + * == 2 - entry found which is GREATER than path specified + * - specified path would fit BEFORE entry found + * - contents of cfVfp up to entry found copied to cfTmpVfp + * - current character of cfVfp is first character of + * entry found + * Side Effects: + * - The ept structure supplied is filled in with a description of + * the item that caused the search to terminate, except in the + * case of '0' in which case the contents of 'ept' is undefined. + * - NOTE: the ept->path item points to a path that is statically + * allocated and will be overwritten on the next call. + * - NOTE: the ept->ainfo.local item points to a path that is + * statically allocated and will be overwritten on the next call. + */ + +int +srchcfile(struct cfent *ept, char *path, VFP_T *cfVfp, VFP_T *cfTmpVfp) +{ + char *cpath_start = (char *)NULL; + char *firstPos = vfpGetCurrCharPtr(cfVfp); + char *lastPos = NULL; + char *pos; + char classname[CLSSIZ+1]; + char pkgname[PKGSIZ+1]; + int anypath = 0; + int c; + int dataSkipped = 0; + int n; + int rdpath; + size_t cpath_len = 0; + size_t pathLength; + struct pinfo *lastpinfo; + struct pinfo *pinfo; + + /* + * this code does not use nested subroutines because execution time + * of this routine is especially critical to installation and upgrade + */ + + /* initialize local variables */ + + setErrstr(NULL); /* no error message currently cached */ + pathLength = (path == (char *)NULL ? 0 : strlen(path)); + lpath[0] = '\0'; + lpath[sizeof (lpath)-1] = '\0'; + + /* initialize ept structure values */ + + (void) strlcpy(ept->ainfo.group, BADGROUP, sizeof (ept->ainfo.group)); + (void) strlcpy(ept->ainfo.owner, BADOWNER, sizeof (ept->ainfo.owner)); + (void) strlcpy(ept->pkg_class, BADCLASS, sizeof (ept->pkg_class)); + ept->ainfo.local = (char *)NULL; + ept->ainfo.mode = BADMODE; + ept->cinfo.cksum = BADCONT; + ept->cinfo.modtime = BADCONT; + ept->cinfo.size = (fsblkcnt_t)BADCONT; + ept->ftype = BADFTYPE; + ept->npkgs = 0; + ept->path = (char *)NULL; + ept->pinfo = (struct pinfo *)NULL; + ept->pkg_class_idx = -1; + ept->volno = 0; + + /* + * populate decision tables that implement fast character checking; + * this is much faster than the equivalent strpbrk() call or a + * while() loop checking for the characters. It is only faster if + * there are at least 3 characters to scan for - when checking for + * one or two characters (such as '\n' or '\0') its faster to do + * a simple while() loop. + */ + + if (decisionTableInit == 0) { + /* + * any chars listed stop scan; + * scan stops on first byte found that is set to '1' below + */ + + /* + * Separators for path names, normal space and = + * for linked filenames + */ + bzero(ISPKGPATHSEP, sizeof (ISPKGPATHSEP)); + ISPKGPATHSEP['='] = 1; /* = */ + ISPKGPATHSEP[' '] = 1; /* space */ + ISPKGPATHSEP['\t'] = 1; /* horizontal-tab */ + ISPKGPATHSEP['\n'] = 1; /* new-line */ + ISPKGPATHSEP['\0'] = 1; /* NULL character */ + + /* + * Separators for normal words + */ + bzero(ISWORDSEP, sizeof (ISWORDSEP)); + ISWORDSEP[' '] = 1; + ISWORDSEP['\t'] = 1; + ISWORDSEP['\n'] = 1; + ISWORDSEP['\0'] = 1; + + /* + * Separators for list of packages, includes \\ for + * alternate ftype and : for classname + */ + bzero(ISPKGNAMESEP, sizeof (ISPKGNAMESEP)); + ISPKGNAMESEP[' '] = 1; + ISPKGNAMESEP['\t'] = 1; + ISPKGNAMESEP['\n'] = 1; + ISPKGNAMESEP[':'] = 1; + ISPKGNAMESEP['\\'] = 1; + ISPKGNAMESEP['\0'] = 1; + + decisionTableInit = 1; + } + + /* if no bytes in contents file, return 0 */ + + if (vfpGetBytesRemaining(cfVfp) <= 1) { + return (0); + } + + /* if the path to scan for is empty, act like no path was specified */ + + if ((path != (char *)NULL) && (*path == '\0')) { + path = (char *)NULL; + } + + /* + * if path to search for is "*", then we will return the first path + * we encounter as a match, otherwise we return an error + */ + + if ((path != (char *)NULL) && (path[0] != '/')) { + if (strcmp(path, "*") != 0) { + setErrstr(pkg_gt(ERR_ILLEGAL_SEARCH_PATH)); + return (-1); + } + anypath = 1; + } + + /* attempt to narrow down the search for the specified path */ + + if (anypath == 0) { + char *np; + + np = narrowSearch(cfVfp, path, pathLength); + if (np != (char *)NULL) { + dataSkipped = 1; + lastPos = np; + vfpSetCurrCharPtr(cfVfp, np); + } + } + + /* + * If the path to search for in the source contents file is NULL, then + * this is a request to scan to the end of the source contents file. If + * there is a temporary contents file to copy entries to, all that needs + * to be done is to copy the data remaining from the current location in + * the source contents file to the end of the temporary contents file. + * if there is no temporary contents file to copy to, then all that + * needs to be done is to seek to the end of the source contents file. + */ + + if ((anypath == 0) && (path == (char *)NULL)) { + if (cfTmpVfp != (VFP_T *)NULL) { + if (vfpGetBytesRemaining(cfVfp) > 0) { + WRITEDATA(cfTmpVfp, firstPos, + vfpGetLastCharPtr(cfVfp)+1); + } + *vfpGetLastCharPtr(cfTmpVfp) = '\0'; + } + vfpSeekToEnd(cfVfp); + return (0); + } + + /* + * ********************************************************************* + * main loop processing entries from the contents file looking for + * the specified path + * ********************************************************************* + */ + + for (;;) { + char *p; + + /* not reading old style entry */ + + rdpath = 0; + + /* determine first character of the next entry */ + + if (vfpGetBytesRemaining(cfVfp) <= 0) { + /* no bytes in contents file current char is NULL */ + + c = '\0'; + } else { + /* grab path from first entry */ + + c = vfpGetcNoInc(cfVfp); + } + + /* save current position in file */ + + pos = vfpGetCurrCharPtr(cfVfp); + + /* + * ============================================================= + * at the first character of the next entry in the contents file + * if not absolute path check for exceptions and old style entry + * --> if end of contents file write out skipped data and return + * --> if comment character skip to end of line and restart loop + * --> else process "old style entry: ftype class path" + * ============================================================= + */ + + if (c != '/') { + /* if NULL character then end of contents file found */ + + if (c == '\0') { + /* write out skipped data before returning */ + if (dataSkipped && + (cfTmpVfp != (VFP_T *)NULL)) { + WRITEDATA(cfTmpVfp, firstPos, lastPos); + *vfpGetLastCharPtr(cfTmpVfp) = '\0'; + } + + return (0); /* no more entries */ + } + + /* ignore lines that begin with #, : or a "space" */ + + if ((isspace(c) != 0) || (c == '#') || (c == ':')) { + /* line is a comment */ + findend(&vfpGetCurrCharPtr(cfVfp)); + continue; + } + + /* + * old style entry - format is: + * ftype class path + * set ept->ftype to the type + * set ept->class to the class + * set ept->path to point to lpath + * set cpath_start/cpath_len to point to the file name + * set rdpath to '1' to indicate old style entry parsed + */ + + while (isspace((c = vfpGetc(cfVfp)))) + ; + + switch (c) { + case '?': case 'f': case 'v': case 'e': case 'l': + case 's': case 'p': case 'c': case 'b': case 'd': + case 'x': + /* save ftype */ + ept->ftype = (char)c; + + /* save class */ + if (getstr(&vfpGetCurrCharPtr(cfVfp), CLSSIZ, + ept->pkg_class, ISWORDSEP)) { + setErrstr(ERR_CANNOT_READ_CLASS_TOKEN); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + + /* + * locate file name up to "=", set cpath_start + * and cpath_len to point to the file name + */ + cpath_start = vfpGetCurrCharPtr(cfVfp); + p = vfpGetCurrCharPtr(cfVfp); + + /* + * skip past all bytes until first '= \t\n\0': + */ + while (ISPKGPATHSEP[(int)*p] == 0) { + p++; + } + + cpath_len = vfpGetCurrPtrDelta(cfVfp, p); + + /* + * if the path is zero bytes, line is corrupted + */ + + if (cpath_len < 1) { + setErrstr(ERR_CANNOT_READ_PATHNAME_FLD); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + + vfpIncCurrPtrBy(cfVfp, cpath_len); + + /* set path to point to local path cache */ + ept->path = lpath; + + /* set flag indicating path already parsed */ + rdpath = 1; + break; + + case '\0': + /* end of line before new-line seen */ + vfpDecCurrPtr(cfVfp); + setErrstr(ERR_INCOMPLETE_ENTRY); + return (-1); + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* volume number seen */ + setErrstr(ERR_VOLUMENO_UNEXPECTED); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + + case 'i': + /* type i files are not cataloged */ + setErrstr(ERR_FTYPE_I_UNEXPECTED); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + + default: + /* unknown ftype */ + setErrstr(ERR_UNKNOWN_FTYPE); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } else { + /* + * current entry DOES start with absolute path + * set ept->path to point to lpath + * set cpath_start/cpath_len to point to the file name + */ + /* copy first token into path element of passed structure */ + + cpath_start = vfpGetCurrCharPtr(cfVfp); + + p = cpath_start; + + /* + * skip past all bytes until first from '= \t\n\0': + */ + + while (ISPKGPATHSEP[(int)*p] == 0) { + p++; + } + + cpath_len = vfpGetCurrPtrDelta(cfVfp, p); + + vfpIncCurrPtrBy(cfVfp, cpath_len); + + if (vfpGetcNoInc(cfVfp) == '\0') { + setErrstr(ERR_INCOMPLETE_ENTRY); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + + ept->path = lpath; + } + + /* + * ============================================================= + * if absolute path then the path is collected and we are at the + * first byte following the absolute path name; + * if not an absolute path then an old style entry, ept has been + * filled with the type and class and path name. + * determine if we have read the pathname which identifies + * the entry we are searching for + * ============================================================= + */ + + if (anypath != 0) { + n = 0; /* next entry is "equal to" */ + } else if (path == (char *)NULL) { + n = 1; /* next entry is "greater than" */ + } else { + n = strncmp(path, cpath_start, cpath_len); + if ((n == 0) && (cpath_len != pathLength)) { + n = cpath_len; + } + } + + /* get first character following the end of the path */ + + c = vfpGetc(cfVfp); + + /* + * if an exact match, always parse out the local path + */ + + if (n == 0) { + /* + * we want to return information about this path in + * the structure provided, so parse any local path + * and jump to code which parses rest of the input line + */ + if (c == '=') { + /* parse local path specification */ + if (getstr(&vfpGetCurrCharPtr(cfVfp), PATH_MAX, + mylocal, ISWORDSEP)) { + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_CANNOT_READ_LL_PATH); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + ept->ainfo.local = mylocal; + } + } + + /* + * if an exact match and processing a new style entry, read the + * remaining information from the new style entry - if this is + * an old style entry (rdpath != 0) then the existing info has + * already been processed as it exists before the pathname and + * not after like a new style entry + */ + + if (n == 0 && rdpath == 0) { + while (isspace((c = vfpGetc(cfVfp)))) + ; + + switch (c) { + case '?': case 'f': case 'v': case 'e': case 'l': + case 's': case 'p': case 'c': case 'b': case 'd': + case 'x': + /* save ftype */ + ept->ftype = (char)c; + + /* save class */ + if (getstr(&vfpGetCurrCharPtr(cfVfp), CLSSIZ, + ept->pkg_class, ISWORDSEP)) { + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_CANNOT_READ_CLASS_TOKEN); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + break; /* we already read the pathname */ + + case '\0': + /* end of line before new-line seen */ + vfpDecCurrPtr(cfVfp); + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_INCOMPLETE_ENTRY); + return (-1); + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_VOLUMENO_UNEXPECTED); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + + case 'i': + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_FTYPE_I_UNEXPECTED); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + + default: + /* unknown ftype */ + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_UNKNOWN_FTYPE); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } + + /* + * if an exact match all processing is completed; break out of + * the main processing loop and finish processing this entry + * prior to returning to the caller. + */ + + if (n == 0) { + break; + } + + /* + * this entry is not an exact match for the path being searched + * for - if this entry is GREATER THAN the path being searched + * for then finish processing and return GREATER THAN result + * to the caller so the entry for the path being searched for + * can be added to the contents file. + */ + + if (n < 0) { + /* + * the entry we want would fit BEFORE the one we just + * read, so we need to unread what we've read by + * seeking back to the start of this entry + */ + + vfpSetCurrCharPtr(cfVfp, pos); + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + /* write out any skipped data before returning */ + if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) { + WRITEDATA(cfTmpVfp, firstPos, lastPos); + } + + return (2); /* path would insert here */ + } + + /* + * This entry is "LESS THAN" the specified path to search for + * need to process the next entry from the contents file. First, + * if writing to new contents file, update new contents file if + * processing old style entry; otherwise, update skipped data + * information to remember current last byte of skipped data. + */ + + if (cfTmpVfp != (VFP_T *)NULL) { + char *px; + ssize_t len; + + if (rdpath != 0) { + /* modify record: write out any skipped data */ + if (dataSkipped) { + WRITEDATA(cfTmpVfp, firstPos, lastPos); + } + + /* + * copy what we've read and the rest of this + * line onto the specified output stream + */ + vfpPutBytes(cfTmpVfp, cpath_start, cpath_len); + vfpPutc(cfTmpVfp, c); + vfpPutc(cfTmpVfp, ept->ftype); + vfpPutc(cfTmpVfp, ' '); + vfpPuts(cfTmpVfp, ept->pkg_class); + + px = strchr(vfpGetCurrCharPtr(cfVfp), '\n'); + + if (px == (char *)NULL) { + len = vfpGetBytesRemaining(cfVfp); + vfpPutBytes(cfTmpVfp, + vfpGetCurrCharPtr(cfVfp), len); + vfpPutc(cfTmpVfp, '\n'); + vfpSeekToEnd(cfVfp); + } else { + len = vfpGetCurrPtrDelta(cfVfp, px); + vfpPutBytes(cfTmpVfp, + vfpGetCurrCharPtr(cfVfp), len); + vfpIncCurrPtrBy(cfVfp, len); + } + + /* reset skiped bytes if any data skipped */ + if (dataSkipped) { + dataSkipped = 0; + lastPos = (char *)NULL; + firstPos = vfpGetCurrCharPtr(cfVfp); + } + } else { + /* skip data */ + dataSkipped = 1; + + px = strchr(vfpGetCurrCharPtr(cfVfp), '\n'); + + if (px == (char *)NULL) { + vfpSeekToEnd(cfVfp); + } else { + len = vfpGetCurrPtrDelta(cfVfp, px)+1; + vfpIncCurrPtrBy(cfVfp, len); + } + lastPos = vfpGetCurrCharPtr(cfVfp); + } + } else { + /* + * since this isn't the entry we want, just read the + * stream until we find the end of this entry and + * then start this search loop again + */ + char *px; + + px = strchr(vfpGetCurrCharPtr(cfVfp), '\n'); + + if (px == (char *)NULL) { + vfpSeekToEnd(cfVfp); + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(pkg_gt(ERR_MISSING_NEWLINE)); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } else { + ssize_t len; + + len = vfpGetCurrPtrDelta(cfVfp, px)+1; + vfpIncCurrPtrBy(cfVfp, len); + } + } + } + + /* + * ********************************************************************* + * end of main loop processing entries from contents file + * the loop is broken out of when an exact match for the + * path being searched for has been found and the type is one of: + * - ?fvelspcbdx + * at this point parsing is at the first character past the full path + * name on an exact match for the path being looked for - parse the + * remainder of the entries information into the ept structure. + * ********************************************************************* + */ + + /* link/symbolic link must have link destination */ + + if (((ept->ftype == 's') || (ept->ftype == 'l')) && + (ept->ainfo.local == NULL)) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_NO_LINK_SOURCE_SPECIFIED); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + + /* character/block devices have major/minor device numbers */ + + if (((ept->ftype == 'c') || (ept->ftype == 'b'))) { + ept->ainfo.major = BADMAJOR; + ept->ainfo.minor = BADMINOR; + if (getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10, + (long *)&ept->ainfo.major, BADMAJOR) || + getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10, + (long *)&ept->ainfo.minor, BADMINOR)) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(pkg_gt(ERR_CANNOT_READ_MM_NUMS)); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } + + /* most types have mode, owner, group identification components */ + + if ((ept->ftype == 'd') || (ept->ftype == 'x') || (ept->ftype == 'c') || + (ept->ftype == 'b') || (ept->ftype == 'p') || + (ept->ftype == 'f') || (ept->ftype == 'v') || + (ept->ftype == 'e')) { + /* mode, owner, group should be here */ + if (getnumvfp(&vfpGetCurrCharPtr(cfVfp), 8, + (long *)&ept->ainfo.mode, BADMODE) || + getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (ept->ainfo.owner), + ept->ainfo.owner, ISWORDSEP) || + getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (ept->ainfo.group), + ept->ainfo.group, ISWORDSEP)) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_CANNOT_READ_MOG); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } + + /* i/f/v/e have size, checksum, modification time components */ + + if ((ept->ftype == 'i') || (ept->ftype == 'f') || + (ept->ftype == 'v') || (ept->ftype == 'e')) { + /* look for content description */ + if (getlnumvfp(&vfpGetCurrCharPtr(cfVfp), 10, + (fsblkcnt_t *)&ept->cinfo.size, BADCONT) || + getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10, + (long *)&ept->cinfo.cksum, BADCONT) || + getnumvfp(&vfpGetCurrCharPtr(cfVfp), 10, + (long *)&ept->cinfo.modtime, BADCONT)) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_CANNOT_READ_CONTENT_INFO); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } + + /* i files processing is completed - return 'exact match found' */ + + if (ept->ftype == 'i') { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + if (getend(&vfpGetCurrCharPtr(cfVfp))) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_EXTRA_TOKENS); + return (-1); + } + + /* write out any skipped data before returning */ + if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) { + WRITEDATA(cfTmpVfp, firstPos, lastPos); + } + + return (1); + } + + /* + * determine list of packages which reference this entry + */ + + lastpinfo = (struct pinfo *)NULL; + while ((c = getstr(&vfpGetCurrCharPtr(cfVfp), sizeof (pkgname), + pkgname, ISPKGNAMESEP)) <= 0) { + /* if c < 0 the string was too long to fix in the buffer */ + + if (c < 0) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_PACKAGE_NAME_TOO_LONG); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + + /* a package is present - create and populate pinfo structure */ + + pinfo = (struct pinfo *)calloc(1, sizeof (struct pinfo)); + if (!pinfo) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_NO_MEMORY); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + if (!lastpinfo) { + ept->pinfo = pinfo; /* first one */ + } else { + lastpinfo->next = pinfo; /* link list */ + } + lastpinfo = pinfo; + + if ((pkgname[0] == '-') || (pkgname[0] == '+') || + (pkgname[0] == '*') || (pkgname[0] == '~') || + (pkgname[0] == '!') || (pkgname[0] == '%')) { + pinfo->status = pkgname[0]; + (void) strlcpy(pinfo->pkg, pkgname+1, + sizeof (pinfo->pkg)); + } else { + (void) strlcpy(pinfo->pkg, pkgname, + sizeof (pinfo->pkg)); + } + + /* pkg/[:[ftype][:class] */ + c = (vfpGetc(cfVfp)); + if (c == '\\') { + /* get alternate ftype */ + pinfo->editflag++; + c = (vfpGetc(cfVfp)); + } + + if (c == ':') { + /* get special classname */ + (void) getstr(&vfpGetCurrCharPtr(cfVfp), + sizeof (classname), classname, ISWORDSEP); + (void) strlcpy(pinfo->aclass, classname, + sizeof (pinfo->aclass)); + c = (vfpGetc(cfVfp)); + } + ept->npkgs++; + + /* break out of while if at end of entry */ + + if ((c == '\n') || (c == '\0')) { + break; + } + + /* if package not separated by a space return an error */ + + if (!isspace(c)) { + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + setErrstr(ERR_BAD_ENTRY_END); + findend(&vfpGetCurrCharPtr(cfVfp)); + return (-1); + } + } + + /* + * parsing of the entry is complete + */ + + /* copy path found to 'lpath' */ + COPYPATH(lpath, cpath_start, cpath_len); + + /* write out any skipped data before returning */ + if (dataSkipped && (cfTmpVfp != (VFP_T *)NULL)) { + WRITEDATA(cfTmpVfp, firstPos, lastPos); + } + + /* if not at the end of the entry, make it so */ + + if ((c != '\n') && (c != '\0')) { + if (getend(&vfpGetCurrCharPtr(cfVfp)) && ept->pinfo) { + setErrstr(ERR_EXTRA_TOKENS); + return (-1); + } + } + + return (1); +} + +static int +getstr(char **cp, int n, char *str, int separator[]) +{ + int c; + char *p = *cp; + char *p1; + size_t len; + + if (*p == '\0') { + return (1); + } + + /* leading white space ignored */ + + while (((c = *p) != '\0') && (isspace(*p++))) + ; + if ((c == '\0') || (c == '\n')) { + p--; + *cp = p; + return (1); /* nothing there */ + } + + p--; + + /* compute length based on delimiter found or not */ + + p1 = p; + while (separator[(int)*p1] == 0) { + p1++; + } + + len = (ptrdiff_t)p1 - (ptrdiff_t)p; + + /* if string will fit in result buffer copy string and return success */ + + if (len < n) { + (void) memcpy(str, p, len); + str[len] = '\0'; + p += len; + *cp = p; + return (0); + } + + /* result buffer too small; copy partial string, return error */ + (void) memcpy(str, p, n-1); + str[n-1] = '\0'; + p += n; + *cp = p; + return (-1); +} + +static int +getend(char **cp) +{ + int n; + char *p = *cp; + + n = 0; + + /* if at end of buffer return no more characters left */ + + if (*p == '\0') { + return (0); + } + + while ((*p != '\0') && (*p != '\n')) { + if (n == 0) { + if (!isspace(*p)) { + n++; + } + } + p++; + } + + *cp = ++p; + return (n); +} + +static void +findend(char **cp) +{ + char *p1; + char *p = *cp; + + /* if at end of buffer return no more characters left */ + + if (*p == '\0') { + return; + } + + /* find the end of the line */ + + p1 = strchr(p, '\n'); + + if (p1 != (char *)NULL) { + *cp = ++p1; + return; + } + + *cp = strchr(p, '\0'); +} |