/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"@(#)files.c	1.15	98/08/05 SMI"	/* SVr4.0 1.4.1.6	*/

#include "lpsched.h"

static char time_buf[50];

/**
 ** chfiles() - CHANGE OWNERSHIP OF FILES, RETURN TOTAL SIZE
 **/

off_t chfiles ( char * * list, uid_t uid, gid_t gid )	/* funcdef */
{
    size_t	total;
    struct stat	stbuf;
    char	*file;
    
    total = 0;

    while(file = *list++)
    {
	if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)) ||
	    STRNEQU(Lp_Tmp, file, strlen(Lp_Tmp)))
	{
	    /*
	     * Once this routine (chfiles) is called for a request,
	     * any temporary files are ``ours'', i.e. they are on our
	     * machine. A user running on an RFS-connected remote machine
	     * can't necessarily know our machine name, so can't put
	     * the files where they belong (Lp_Tmp/machine). But now we
	     * can. Of course, this is all done with mirrors, as Lp_Temp
	     * and Lp_Tmp/local-machine are symbolicly linked. So we just
	     * change the name. This saves on wear and tear later.
	     */
	    if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)))
	    {
		char *newfile = makepath(Lp_Tmp, Local_System,
				file + strlen(Lp_Temp) + 1, NULL);

		Free(file);
		list[-1] = file = newfile;
	    }
	    
	    (void) Chmod(file, 0600);
	    (void) Chown(file, uid, gid);
	}

	if (Stat(file, &stbuf) == -1)
	    return(-1);

	switch (stbuf.st_mode & S_IFMT) {
	case 0:
	case S_IFREG:
	    break;

	case S_IFIFO:
	    if (!isadmin(uid))
		return(-1);
	    /*
	     * If any of the files is a FIFO, the size indicator
	     * becomes meaningless. On the other hand, returning
	     * a total of zero causes the request to be rejected,
	     * so we return something > 0.
	     */
	    stbuf.st_size = 1;
	    break;

	case S_IFDIR:
	case S_IFCHR:
	case S_IFBLK:
	default:
	    return(-1);
	}

	total += stbuf.st_size;
    }
    return(total);
}

/**
 ** rmfiles() - DELETE/LOG FILES FOR DEFUNCT REQUEST
 **/

void rmfiles ( RSTATUS * rp, int log_it )	/* funcdef */
{
    char	**file	= rp->request->file_list;
    char	*path;
    char	num[STRSIZE(MOST_FILES) + 1];
    static int	fd	= -1;
    int		reqfd;
    int		count	= 0;


    if (rp->req_file) {
	    char *p, *q;

	   /*
	    * The secure request file is removed first to prevent
	    * reloading should the system crash while in rmfiles().
	    */
	    path = makepath(Lp_Requests, rp->req_file, (char *)0);
	    (void) Unlink(path);
	    Free(path);

	    /*
	     * Copy the request file to the log file, if asked,
	     * or simply remove it.
	     */
#if	defined(TEMP_OR_TMP)
	    path = makepath(Lp_Temp, rp->req_file, (char *)0);
#else
	    path = makepath(Lp_Tmp, rp->req_file, (char *)0);
#endif
	    if (log_it && rp->secure && rp->secure->req_id) {
		if (fd == -1)
		    fd = open_locked(Lp_ReqLog, "a", MODE_NOREAD);
		if ((fd  >= 0) && (reqfd = Open(path, O_RDONLY, 0)) != -1) {
		    register int	n;
		    char		buf[BUFSIZ];

		    cftime(time_buf, NULL, &(rp->secure->date));
		    fdprintf(fd, "= %s, uid %d, gid %d, size %ld, %s\n",
			rp->secure->req_id, rp->secure->uid, rp->secure->gid,
			rp->secure->size, time_buf);
		    if (rp->slow)
			fdprintf(fd, "x %s\n", rp->slow);
		    if (rp->fast)
			fdprintf(fd, "y %s\n", rp->fast);
		    if (rp->printer && rp->printer->printer->name)
			fdprintf(fd, "z %s\n", rp->printer->printer->name);
		    while ((n = Read(reqfd, buf, BUFSIZ)) > 0)
			write (fd, buf, n);
		    Close (reqfd);
		}
	    }
	    (void)Unlink (path);		/* remove request file */
	    Free (path);

	    p = strdup(rp->req_file);		/* remove host/id file */
	    if (q = strrchr(p, '-')) {
		    *q = NULL;
		    path = makepath(Lp_Tmp, p, NULL);
		    (void) Unlink(path);
		    Free(path);
	    }
	    Free(p);
    }

    if (file)					/* remove file in filelist */
	while(*file)
	{
		/*
		 * The copies of user files.
		 */
		if (STRNEQU(Lp_Temp, *file, strlen(Lp_Temp)) ||
		    STRNEQU(Lp_Tmp, *file, strlen(Lp_Tmp)))
		    (void) Unlink(*file);
		count++;
		file++;
	}

    if (rp->secure && rp->secure->req_id) {
	char *p;
	p = getreqno(rp->secure->req_id);

	/*
	 * The filtered files. We can't rely on just the RS_FILTERED
	 * flag, since the request may have been cancelled while
	 * filtering. On the other hand, just checking "rp->slow"
	 * doesn't mean that the files exist, because the request
	 * may have been canceled BEFORE filtering started. Oh well.
	 */
	if (rp->slow)
	    while(count > 0)
	    {
		sprintf(num, "%d", count--);
		path = makestr(Lp_Tmp, "/",  rp->secure->system, "/F", p, "-",
			num, (char *)0);
		Unlink(path);
		Free(path);
	    }

	/*
	 * The notify/error file.
	 */
	path = makepath(Lp_Temp, p, (char *)0);
	(void) Unlink(path);
	Free(path);
    }
}

/**
 ** _alloc_req_id(void) - ALLOCATE NEXT REQUEST ID
 **/

#define	SEQF_DEF_START	1
#define	SEQF_DEF_END	59999
#define	SEQF_DEF_INCR	1
#define	SEQF		".SEQF"


long
_alloc_req_id ( void )
{
	static short		started	= 0;

	static int		fd;

	static long		start;
	static long		end;
	static long		incr;
	static long		curr;
	static long		wrap;

	static char		fmt[
				STRSIZE(BIGGEST_REQID_S)/* start   */
			      + 1			/* :       */
			      + STRSIZE(BIGGEST_REQID_S)/* end     */
			      + 1			/* :       */
			      + STRSIZE(BIGGEST_REQID_S)/* incr    */
			      + 1			/* :       */
			      + 4			/* %ld\n   */
			      + 1			/* (nul)   */
				];

	char 			buf[256];
	int len;

	long			ret;


	if (!started) {
		sprintf(buf, "%s/%s", Lp_Temp, SEQF);
		if (((fd = open_locked(buf, "r+", 0644)) < 0) &&
		    ((fd = open_locked(buf, "w", 0644)) < 0))
			fail ("Can't open file %s (%s).\n", buf, PERROR);

		lseek(fd, 0, SEEK_SET);

		read(fd, buf, sizeof (buf));
		if (sscanf(buf, "%ld:%ld:%ld:%ld\n", &start, &end, &incr, &curr) != 4) {
			start = SEQF_DEF_START;
			end = SEQF_DEF_END;
			curr = start;
			incr = SEQF_DEF_INCR;
		}

		if (start < 0)
			start = SEQF_DEF_START;
		if (end > SEQF_DEF_END)
			end = SEQF_DEF_END;
		if (curr < start || curr > end)
			curr = start;

		sprintf (fmt, "%ld:%ld:%ld:%%ld\n", start, end, incr);
		started = 1;
	}

	wrap = curr;
	do {	
		ret = curr;
		if ((curr += incr) > end)
	    	curr = start;

	} while ( wrap != curr && ((RSTATUS *)request_by_id_num(ret)) ) ; 

	/* write the new id file */
	lseek(fd, 0, SEEK_SET);
	len = sprintf(buf, fmt, curr);
	write(fd, buf, len);
	ftruncate(fd, len);

	if (curr == wrap) {
		note("alloc_req_id(): out of ids\n");
		errno = EEXIST;
		return(SEQF_DEF_START-1);
	} else
		return (ret);
}

/**
 ** _alloc_file() - ALLOCATE FILES FOR A REQUEST
 **/

char *
_alloc_files (
	int			num,
	char *			prefix,
	uid_t			uid,
	gid_t			gid,
	char *			host
)
{
	static char		base[
				1			/* F       */
			      + STRSIZE(BIGGEST_REQID_S)/* req-id  */
			      + 1			/* -       */
			      + STRSIZE(MOST_FILES_S)	/* file-no */
			      + 1			/* (nul)   */
				];

	char *			file;
	char *			cp;

	int			fd;
	int			plus;


	if (num > BIGGEST_REQID)
		return (0);

	if (!prefix) {
		int id;

		if ((id = _alloc_req_id()) < SEQF_DEF_START )
			return(NULL); /* Out of request IDs (errno = EEXIST) */
		sprintf (base, "%d-%d", id, MOST_FILES);
		plus = 0;
	} else {
		if (strlen(prefix) > (size_t) 6)
			return (0);
		sprintf (base, "F%s-%d", prefix, MOST_FILES);
		plus = 1;
	}

	if (host != NULL)
		file = makepath(Lp_Tmp, host, base, (char *)0);
	else
		file = makepath(Lp_Temp, base, (char *)0);
        
	cp = strrchr(file, '-') + 1;
	while (num--) {
		sprintf (cp, "%d", num + plus);
		if ((fd = Open(file, O_CREAT|O_TRUNC, 0600)) == -1) {
			Free (file);
			return (0);
		} else {
			Close (fd);
			Chown (file, uid, gid);
		}
	}

	Free (file);

	if ((cp = strrchr(base, '-')))
		*cp = 0;

	return (base);
}
