root/usr/src/cmd/bnu/cpmv.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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 (c) 1999 by Sun Microsystems, Inc.
 *      All rights reserved.
 */
/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */


#ident  "%Z%%M% %I%     %E% SMI"        /* from SVR4 bnu:cpmv.c 2.13 */

#include "uucp.h"

/*
 * copy f1 to f2 locally
 *      f1      -> source file name
 *      f2      -> destination file name
 * return:
 *      0       -> ok
 *      FAIL    -> failed
 */

static int
xcp(f1, f2)
char *f1, *f2;
{
        register int    fd1, fd2;
        register int    nr, nw;
        char buf[BUFSIZ];
        char *temp_p, temp[MAXFULLNAME];

        if ((fd1 = open(f1, O_RDONLY)) == -1)
                return (FAIL);

        if (DIRECTORY(f2)) {
                (void) strcat(f2, "/");
                (void) strcat(f2, BASENAME(f1, '/'));
        }
        DEBUG(4, "file name is %s\n", f2);

        (void) strcpy(temp, f2);
        if ((temp_p = strrchr(temp, '/')) == NULL)
            temp_p = temp;
        else
            temp_p++;
        (void) strcpy(temp_p, ".TM.XXXXXX");
        temp_p = temp;
        DEBUG(4, "temp name is %s\n", temp_p);

        if ((fd2 = mkstemp(temp_p)) == -1) {
                /* open of temp may fail if called from uidxcp() */
                /* in this case, try f2 since it is pre-created */
                temp_p = f2;
                if ((fd2 = open(temp_p, O_CREAT | O_TRUNC | O_WRONLY,
                    PUB_FILEMODE)) == -1) {
                        DEBUG(5, "open of file returned errno %d\n", errno);
                        (void) close(fd1);
                        return (FAIL);
                }
                DEBUG(4, "using file name directly.%s\n", "");
        }
        (void) chmod(temp_p, PUB_FILEMODE);

        /*      copy, looking for read or write failures */
        while ((nr = read(fd1, buf, sizeof (buf))) > 0 &&
                (nw = write(fd2, buf, nr)) == nr)
                ;

        close(fd1);
        close(fd2);

        if (nr != 0 || nw == -1) {
                (void) unlink(temp_p);
                return (FAIL);
        }
        if (temp_p != f2) {
            if (rename(temp_p, f2) != 0) {
                DEBUG(5, "rename failed: errno %d\n", errno);
                (void) unlink(temp_p);
                return (FAIL);
            }
        }
        return (0);
}


/*
 * move f1 to f2 locally
 * returns:
 *      0       -> ok
 *      FAIL    -> failed
 */

int
xmv(f1, f2)
register char *f1, *f2;
{
        register int do_unlink, ret;
        struct stat sbuf;

        if (stat(f2, &sbuf) == 0)
                do_unlink = ((sbuf.st_mode & S_IFMT) == S_IFREG);
        else
                do_unlink = 1;

        if (do_unlink)
                (void) unlink(f2);      /* i'm convinced this is the right */
                                        /* thing to do */
        if ((ret = link(f1, f2)) < 0) {
            /* copy file */
            ret = xcp(f1, f2);
        }

        if (ret == 0)
            (void) unlink(f1);
        return (ret);
}

/*
 * toCorrupt - move file to CORRUPTDIR
 * return - none
 */

void
toCorrupt(file)
char *file;
{
        char corrupt[MAXFULLNAME];

        (void) sprintf(corrupt, "%s/%s", CORRUPTDIR, BASENAME(file, '/'));
        (void) link(file, corrupt);
        ASSERT(unlink(file) == 0, Ct_UNLINK, file, errno);
}

/*
 * append f1 to f2
 *      f1      -> source FILE pointer
 *      f2      -> destination FILE pointer
 * return:
 *      SUCCESS -> ok
 *      FAIL    -> failed
 *
 * to avoid confusing mail, turn lines with just "." into "..".
 */
int
xfappend(fp1, fp2)
register FILE   *fp1, *fp2;
{
        char    buf[BUFSIZ];

        while (fgets(buf, sizeof (buf), fp1) != NULL) {
                if (buf[0] == '.' && buf[1] == '\n')
                        strcpy(buf, "..\n");
                fputs(buf, fp2);
        }

        return (ferror(fp1) || ferror(fp2) ? FAIL : SUCCESS);
}


/*
 * copy f1 to f2 locally under uid of uid argument
 *      f1      -> source file name
 *      f2      -> destination file name
 *      Uid and Euid are global
 * return:
 *      0       -> ok
 *      FAIL    -> failed
 * NOTES:
 *  for V7 systems, flip-flop between real and effective uid is
 *  not allowed, so fork must be done.  This code will not
 *  work correctly when realuid is root on System 5 because of
 *  a bug in setuid.
 */

int
uidxcp(f1, f2)
char *f1, *f2;
{
        int status;
        char full[MAXFULLNAME];

        (void) strcpy(full, f2);
        if (DIRECTORY(f2)) {
            (void) strcat(full, "/");
            (void) strcat(full, BASENAME(f1, '/'));
        }

        /* create full owned by uucp */
        (void) close(creat(full, PUB_FILEMODE));
        (void) chmod(full, PUB_FILEMODE);

        /* do file copy as read uid */
#ifndef V7
        (void) setuid(Uid);
        status = xcp(f1, full);
        (void) setuid(Euid);
        return (status);

#else /* V7 */

        if (vfork() == 0) {
            setuid(Uid);
            _exit(xcp(f1, full));
        }
        wait(&status);
        return (status);
#endif
}

/*
 * put file in public place
 * if successful, filename is modified
 * returns:
 *      0       -> success
 *      FAIL    -> failure
 */
int
putinpub(file, tmp, user)
char *file, *user, *tmp;
{
        int status;
        char fullname[MAXFULLNAME];

        (void) sprintf(fullname, "%s/%s/", Pubdir, user);
        if (mkdirs(fullname, PUBMASK) != 0) {
                /* cannot make directories */
                return (FAIL);
        }
        (void) strcat(fullname, BASENAME(file, '/'));
        status = xmv(tmp, fullname);
        if (status == 0) {
                (void) strcpy(file, fullname);
                (void) chmod(fullname, PUB_FILEMODE);
        }
        return (status);
}