#include "args.h"
/*
 * Copyright (c) 1986, 2014 by The Trustees of Columbia University in
 * the City of New York.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  + Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  + Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 *  + Neither the name of Columbia University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 */

#include "args.h"
#include "config.h"
#include "osfiles.h"
#include "compat.h"

const char *progname;
int locked = 0;
char lockname[MAXPATHLEN];

extern int sys_read ARGS((int fd_, char *buf_, int count_));
extern int sys_write ARGS((int fd_, const char *buf_, int count_));

static void fatal ARGS((const char *s1, const char *s2));
static void done ARGS((int n));


int
#if HAVE_STDC
main (int argc, char **argv)
#else /* K&R style */
main (argc, argv)
int argc;
char *argv[];
#endif /* HAVE_STDC */
{
    char *from, *to, *cp;
    char destdir[MAXPATHLEN];
    struct stat st;
    int c, ifd, ofd;
    time_t mtime;

    if (argc != 3) {
	fprintf (stderr, "usage: %s source-file destination-file\n", argv[0]);
	exit (1);
    }

    progname = (cp = rindex (argv[0], '/')) ? cp + 1 : argv[0];

    from = argv[1];
    to = argv[2];

    if ((cp = rindex (to, '/'), cp)) {
	strcpy (destdir, to);
	destdir[cp - to] = 0;
    }
    else
	strcpy (destdir, ".");

    if (access (from, R_OK) != 0)
	fatal ("cannot access", from);

    if (access (to, F_OK) == 0) {
	fprintf (stderr, "%s: will not overwrite %s\n", progname, to);
	exit (1);
    }

    if (access (destdir, W_OK|X_OK) != 0)
	fatal ("cannot write", destdir);

#ifdef MAIL_USE_FLOCK
    if ((ifd = open (from, O_RDONLY)) < 0)
	fatal ("cannot open", to);

    if (flock (ifd, LOCK_EX|LOCK_NB) != 0)
	fatal ("cannot lock", from);
#else
    sprintf (lockname, "%s.lock", from);
    if (creat (lockname, 0) < 0)
	fatal ("cannot lock", from);
    locked = 1;
    if ((ifd = open (from, O_RDONLY)) < 0)
	fatal ("cannot open", to);
#endif

    if (stat (from, &st) < 0)
	fatal ("cannot stat", from);
    mtime = st.st_mtime;

    if ((ofd = open (to, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0)
	fatal ("cannot open", to);

    for (;;) {
	char buf[BUFSIZ];
	c = read (ifd, buf, sizeof buf);
	if (c == 0)
	    break;
	if (c < 0)
	    fatal ("error reading", from);
	if (write (ofd, buf, c) < c)
	    fatal ("error writing", to);
    }

    if (close (ofd) < 0)
	fatal ("error closing", to);

    if (stat (from, &st) < 0)
	fatal ("cannot stat", from);

    if (st.st_mtime != mtime)
	fprintf (stderr, "%s: %s changed!\n", progname, from);

    /*
     * Try to unlink the source file.  If that
     * fails, just truncate it.
     */
    if (unlink (from) < 0) {
	if (stat (from, F_OK) == 0)
	    if ((c = creat (from, 0660)) < 0)
		fatal ("cannot truncate", from);
	    else
		(void) close (c);
    }
    done (0);
    return (0);  /*NOTREACHED*/	/* keep optimizers and lint happy */
}

static void
#if HAVE_STDC
fatal (const char *s1, const char *s2)
#else /* K&R style */
fatal (s1, s2)
const char *s1, *s2;
#endif /* HAVE_STDC */
{
    if (s2) {
	int saved_errno = errno;
	fprintf (stderr, "%s: %s ", progname, s1);
	errno = saved_errno;
	perror (s2);
    }
    else
	fprintf (stderr, "%s: %s\n", progname, s1);
    done (1);
}

static void
#if HAVE_STDC
done (int n)
#else /* K&R style */
done (n)
int n;
#endif /* HAVE_STDC */
{
#ifndef MAIL_USE_FLOCK
    if (locked)
	unlink (lockname);
#endif
    exit (n);
}
