root/usr/src/lib/libpkg/common/putcfile.c
/*
 * 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 <string.h>
#include <limits.h>
#include <sys/types.h>
#include "pkgstrct.h"
#include "pkglib.h"

/*
 * Name:        putcfile
 * Description: Write contents file entry to specified FILE
 * Arguments:   struct cfent a_ept - data for contents file entry
 *              FILE *a_fp - FP of file to write contents file entry to
 * Notes:       This is identical to putcvfpfile() but this function takes a
 *              stdio FILE* file to write to instead of a VFP_T file. It is
 *              MUCH slower than putcvfpfile().
 */

int
putcfile(struct cfent *a_ept, FILE *a_fp)
{
        struct pinfo *pinfo;

        if (a_ept->ftype == 'i') {
                return (0); /* no ifiles stored in contents DB */
        }

        if (a_ept->path == NULL) {
                return (-1);    /* no path name - no entry to write */
        }

        if (fputs(a_ept->path, a_fp) == EOF) {
                return (-1);
        }

        if (a_ept->ainfo.local) {
                if (putc('=', a_fp) == EOF) {
                        return (-1);
                }
                if (fputs(a_ept->ainfo.local, a_fp) == EOF)
                        return (-1);
        }

        if (a_ept->volno) {
                if (fprintf(a_fp, " %d", a_ept->volno) < 0) {
                        return (-1);
                }
        }

        if (putc(' ', a_fp) == EOF) {
                return (-1);
        }

        if (putc(a_ept->ftype, a_fp) == EOF) {
                return (-1);
        }

        if (putc(' ', a_fp) == EOF) {
                return (-1);
        }

        if (fputs(a_ept->pkg_class, a_fp) == EOF) {
                return (-1);
        }

        if ((a_ept->ftype == 'c') || (a_ept->ftype == 'b')) {
                if (a_ept->ainfo.major == BADMAJOR) {
                        if (putc(' ', a_fp) == EOF) {
                                return (-1);
                        }

                        if (putc('?', a_fp) == EOF) {
                                return (-1);
                        }
                } else {
                        if (fprintf(a_fp, " %ld", a_ept->ainfo.major) < 0)
                                return (-1);
                }

                if (a_ept->ainfo.minor == BADMINOR) {
                        if (putc(' ', a_fp) == EOF) {
                                return (-1);
                        }

                        if (putc('?', a_fp) == EOF) {
                                return (-1);
                        }
                } else {
                        if (fprintf(a_fp, " %ld", a_ept->ainfo.minor) < 0)
                                return (-1);
                }
        }

        if ((a_ept->ftype == 'd') || (a_ept->ftype == 'x') ||
                (a_ept->ftype == 'c') || (a_ept->ftype == 'b') ||
                (a_ept->ftype == 'p') || (a_ept->ftype == 'f') ||
                (a_ept->ftype == 'v') || (a_ept->ftype == 'e')) {
                if (fprintf(a_fp,
                        ((a_ept->ainfo.mode == BADMODE) ? " ?" : " %04o"),
                        a_ept->ainfo.mode) < 0)
                        return (-1);

                if (putc(' ', a_fp) == EOF) {
                        return (-1);
                }

                if (fputs(a_ept->ainfo.owner, a_fp) == EOF) {
                        return (-1);
                }

                if (putc(' ', a_fp) == EOF) {
                        return (-1);
                }

                if (fputs(a_ept->ainfo.group, a_fp) == EOF) {
                        return (-1);
                }
        }

        if ((a_ept->ftype == 'f') || (a_ept->ftype == 'v') ||
                (a_ept->ftype == 'e')) {
                if (fprintf(a_fp,
                        ((a_ept->cinfo.size == BADCONT) ? " ?" : " %llu"),
                        a_ept->cinfo.size) < 0)
                        return (-1);

                if (fprintf(a_fp,
                        ((a_ept->cinfo.cksum == BADCONT) ? " ?" : " %ld"),
                        a_ept->cinfo.cksum) < 0)
                        return (-1);

                if (fprintf(a_fp,
                    ((a_ept->cinfo.modtime == BADCONT) ? " ?" : " %ld"),
                    a_ept->cinfo.modtime) < 0)
                        return (-1);
        }

        pinfo = a_ept->pinfo;
        while (pinfo) {
                if (putc(' ', a_fp) == EOF) {
                        return (-1);
                }

                if (pinfo->status) {
                        if (fputc(pinfo->status, a_fp) == EOF) {
                                return (-1);
                        }
                }

                if (fputs(pinfo->pkg, a_fp) == EOF) {
                        return (-1);
                }

                if (pinfo->editflag) {
                        if (putc('\\', a_fp) == EOF) {
                                return (-1);
                        }
                }

                if (pinfo->aclass[0]) {
                        if (putc(':', a_fp) == EOF) {
                                return (-1);
                        }
                        if (fputs(pinfo->aclass, a_fp) == EOF) {
                                return (-1);
                        }
                }
                pinfo = pinfo->next;
        }

        if (putc('\n', a_fp) == EOF) {
                return (-1);
        }
        return (0);
}

/*
 * Name:        putcvfpfile
 * Description: Write contents file entry to specified VFP
 * Arguments:   struct cfent a_ept - data for contents file entry
 *              VFP_T *a_vfp - VFP of file to write contents file entry to
 * Notes:       This is identical to putcfile() but this function takes a
 *              VFP_T file to write to instead of a stdio FILE file. It is
 *              MUCH faster tha putcfile().
 */

int
putcvfpfile(struct cfent *a_ept, VFP_T *a_vfp)
{
        struct pinfo *pinfo;

        /* contents file does not maintain any 'i' file entries */

        if (a_ept->ftype == 'i') {
                return (0);
        }

        /* cannot create an entry if it has no file name */

        if (a_ept->path == NULL) {
                return (-1);
        }

        /*
         * Format of contents file line could be one of:
         * /file=./dir/file s class SUNWxxx
         * /file=../dir/file l class SUNWxxx
         * /dir d class mode owner group SUNWxxx SUNWyyy
         * /devices/name c class major minor mode owner group SUNWxxx
         * /file f class mode owner group size cksum modtime SUNWxxx
         * /file x class mode owner group SUNWppro
         * /file v class mode owner group size cksum modtime SUNWxxx
         * /file e class mode owner group size cksum modtime SUNWxxx
         * The package name could be prefixed by one of the following
         * status indicators: +-*!%@#~
         */

        /*
         * Adding an entry to the specified VFP.  During normal processing the
         * contents file is copied to a temporary contents file and entries are
         * added as appropriate.  When this processing is completed, a decision
         * is made on whether or not to overwrite the real contents file with
         * the contents of the temporary contents file.  If the temporary
         * contents file is just a copy of the real contents file then there is
         * no need to overwrite the real contents file with the contents of the
         * temporary contents file.  This decision is made in part on whether
         * or not any new or modified entries have been added to the temporary
         * contents file.  Set the "data is modified" indication associated
         * with this VFP so that the real contents file is overwritten when
         * processing is done.
         */

        (void) vfpSetModified(a_vfp);

        /* write initial path [all entries] */

        vfpPuts(a_vfp, a_ept->path);

        /* if link, write out '=' portion */

        if (a_ept->ainfo.local) {
                vfpPutc(a_vfp, '=');
                vfpPuts(a_vfp, a_ept->ainfo.local);
        }

        /* if volume, write it out */

        if (a_ept->volno) {
                vfpPutc(a_vfp, ' ');
                vfpPutInteger(a_vfp, a_ept->volno);
        }

        /* write out <space><entry type><space>class> */

        vfpPutc(a_vfp, ' ');
        vfpPutc(a_vfp, a_ept->ftype);
        vfpPutc(a_vfp, ' ');
        vfpPuts(a_vfp, a_ept->pkg_class);

        /* if char/block device, write out major/minor numbers */

        if ((a_ept->ftype == 'c') || (a_ept->ftype == 'b')) {
                /* major device number */
                if (a_ept->ainfo.major == BADMAJOR) {
                        vfpPutc(a_vfp, ' ');
                        vfpPutc(a_vfp, '?');
                } else {
                        vfpPutc(a_vfp, ' ');
                        vfpPutInteger(a_vfp, a_ept->ainfo.major);
                }

                /* minor device number */
                if (a_ept->ainfo.minor == BADMINOR) {
                        vfpPutc(a_vfp, ' ');
                        vfpPutc(a_vfp, '?');
                } else {
                        vfpPutc(a_vfp, ' ');
                        vfpPutInteger(a_vfp, a_ept->ainfo.minor);
                }
        }

        /* if dxcbpfve, write out mode, owner, group */

        if ((a_ept->ftype == 'd') || (a_ept->ftype == 'x') ||
                (a_ept->ftype == 'c') || (a_ept->ftype == 'b') ||
                (a_ept->ftype == 'p') || (a_ept->ftype == 'f') ||
                (a_ept->ftype == 'v') || (a_ept->ftype == 'e')) {

                /* mode */
                vfpPutFormat(a_vfp,
                        ((a_ept->ainfo.mode == BADMODE) ? " ?" : " %04o"),
                        a_ept->ainfo.mode);

                /* owner */
                vfpPutc(a_vfp, ' ');
                vfpPuts(a_vfp, a_ept->ainfo.owner);

                /* group */
                vfpPutc(a_vfp, ' ');
                vfpPuts(a_vfp, a_ept->ainfo.group);
        }
        /* if f/v/e, write out size, cksum, modtime */

        if ((a_ept->ftype == 'f') || (a_ept->ftype == 'v') ||
                (a_ept->ftype == 'e')) {
                /* size */
                vfpPutFormat(a_vfp,
                        ((a_ept->cinfo.size == BADCONT) ? " ?" : " %llu"),
                        a_ept->cinfo.size);

                /* cksum */
                vfpPutFormat(a_vfp,
                        ((a_ept->cinfo.cksum == BADCONT) ? " ?" : " %ld"),
                        a_ept->cinfo.cksum);

                /* modtime */
                vfpPutFormat(a_vfp,
                        ((a_ept->cinfo.modtime == BADCONT) ? " ?" : " %ld"),
                        a_ept->cinfo.modtime);
        }

        /* write out list of all packages referencing this entry */

        pinfo = a_ept->pinfo;
        while (pinfo) {
                vfpPutc(a_vfp, ' ');
                if (pinfo->status) {
                        vfpPutc(a_vfp, pinfo->status);
                }

                vfpPuts(a_vfp, pinfo->pkg);

                if (pinfo->editflag) {
                        vfpPutc(a_vfp, '\\');
                }

                if (pinfo->aclass[0]) {
                        vfpPutc(a_vfp, ':');
                        vfpPuts(a_vfp, pinfo->aclass);
                }
                pinfo = pinfo->next;
        }

        vfpPutc(a_vfp, '\n');
        return (0);
}