190792Sgshapiro/*
2261363Sgshapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro * Copyright (c) 1990, 1993
590792Sgshapiro *	The Regents of the University of California.  All rights reserved.
690792Sgshapiro *
790792Sgshapiro * This code is derived from software contributed to Berkeley by
890792Sgshapiro * Chris Torek.
990792Sgshapiro *
1090792Sgshapiro * By using this file, you agree to the terms and conditions set
1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1290792Sgshapiro * the sendmail distribution.
1390792Sgshapiro */
1490792Sgshapiro
1590792Sgshapiro#include <sm/gen.h>
16266692SgshapiroSM_RCSID("@(#)$Id: makebuf.c,v 1.27 2013-11-22 20:51:43 ca Exp $")
1790792Sgshapiro#include <stdlib.h>
1890792Sgshapiro#include <unistd.h>
1990792Sgshapiro#include <sys/types.h>
2090792Sgshapiro#include <sys/stat.h>
2190792Sgshapiro#include <sm/io.h>
2290792Sgshapiro#include <sm/heap.h>
2390792Sgshapiro#include <sm/conf.h>
2490792Sgshapiro#include "local.h"
2590792Sgshapiro
2690792Sgshapiro/*
2790792Sgshapiro**  SM_MAKEBUF -- make a buffer for the file
2890792Sgshapiro**
2990792Sgshapiro**	Parameters:
3090792Sgshapiro**		fp -- the file to be buffered
3190792Sgshapiro**
3290792Sgshapiro**	Returns:
3390792Sgshapiro**		nothing
3490792Sgshapiro**
3590792Sgshapiro**	Allocate a file buffer, or switch to unbuffered I/O.
3690792Sgshapiro**	By default tty devices default to line buffered.
3790792Sgshapiro*/
3890792Sgshapiro
3990792Sgshapirovoid
4090792Sgshapirosm_makebuf(fp)
4190792Sgshapiro	register SM_FILE_T *fp;
4290792Sgshapiro{
4390792Sgshapiro	register void *p;
4490792Sgshapiro	register int flags;
4590792Sgshapiro	size_t size;
4690792Sgshapiro	int couldbetty;
4790792Sgshapiro
4890792Sgshapiro	if (fp->f_flags & SMNBF)
4990792Sgshapiro	{
5090792Sgshapiro		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
5190792Sgshapiro		fp->f_bf.smb_size = 1;
5290792Sgshapiro		return;
5390792Sgshapiro	}
5490792Sgshapiro	flags = sm_whatbuf(fp, &size, &couldbetty);
5590792Sgshapiro	if ((p = sm_malloc(size)) == NULL)
5690792Sgshapiro	{
5790792Sgshapiro		fp->f_flags |= SMNBF;
5890792Sgshapiro		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
5990792Sgshapiro		fp->f_bf.smb_size = 1;
6090792Sgshapiro		return;
6190792Sgshapiro	}
6290792Sgshapiro	if (!Sm_IO_DidInit)
6390792Sgshapiro		sm_init();
6490792Sgshapiro	flags |= SMMBF;
6590792Sgshapiro	fp->f_bf.smb_base = fp->f_p = p;
6690792Sgshapiro	fp->f_bf.smb_size = size;
6790792Sgshapiro	if (couldbetty && isatty(fp->f_file))
6890792Sgshapiro		flags |= SMLBF;
6990792Sgshapiro	fp->f_flags |= flags;
7090792Sgshapiro}
7190792Sgshapiro
7290792Sgshapiro/*
7390792Sgshapiro**  SM_WHATBUF -- determine proper buffer for a file (internal)
7490792Sgshapiro**
7590792Sgshapiro**  Plus it fills in 'bufsize' for recommended buffer size and
7690792Sgshapiro**  fills in flag to indicate if 'fp' could be a tty (nothing
7790792Sgshapiro**  to do with "betty" :-) ).
7890792Sgshapiro**
7990792Sgshapiro**	Parameters:
8090792Sgshapiro**		fp -- file pointer to be buffered
8190792Sgshapiro**		bufsize -- new buffer size (a return)
8290792Sgshapiro**		couldbetty -- could be a tty (returns)
8390792Sgshapiro**
8490792Sgshapiro**	Returns:
8590792Sgshapiro**		Success:
8690792Sgshapiro**		on error:
8790792Sgshapiro**			SMNPT -- not seek opimized
8890792Sgshapiro**			SMOPT -- seek opimized
8990792Sgshapiro*/
9090792Sgshapiro
9190792Sgshapiroint
9290792Sgshapirosm_whatbuf(fp, bufsize, couldbetty)
9390792Sgshapiro	register SM_FILE_T *fp;
9490792Sgshapiro	size_t *bufsize;
9590792Sgshapiro	int *couldbetty;
9690792Sgshapiro{
9790792Sgshapiro	struct stat st;
9890792Sgshapiro
9990792Sgshapiro	if (fp->f_file < 0 || fstat(fp->f_file, &st) < 0)
10090792Sgshapiro	{
10190792Sgshapiro		*couldbetty = 0;
10290792Sgshapiro		*bufsize = SM_IO_BUFSIZ;
10390792Sgshapiro		return SMNPT;
10490792Sgshapiro	}
10590792Sgshapiro
10690792Sgshapiro	/* could be a tty iff it is a character device */
10790792Sgshapiro	*couldbetty = S_ISCHR(st.st_mode);
10890792Sgshapiro	if (st.st_blksize == 0)
10990792Sgshapiro	{
11090792Sgshapiro		*bufsize = SM_IO_BUFSIZ;
11190792Sgshapiro		return SMNPT;
11290792Sgshapiro	}
11390792Sgshapiro
11490792Sgshapiro#if SM_IO_MAX_BUF_FILE > 0
11590792Sgshapiro	if (S_ISREG(st.st_mode) && st.st_blksize > SM_IO_MAX_BUF_FILE)
11690792Sgshapiro		st.st_blksize = SM_IO_MAX_BUF_FILE;
11790792Sgshapiro#endif /* SM_IO_MAX_BUF_FILE > 0 */
11890792Sgshapiro
11990792Sgshapiro#if SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0
12090792Sgshapiro	if (!S_ISREG(st.st_mode))
12190792Sgshapiro	{
12290792Sgshapiro# if SM_IO_MAX_BUF > 0
12390792Sgshapiro		if (st.st_blksize > SM_IO_MAX_BUF)
12490792Sgshapiro			st.st_blksize = SM_IO_MAX_BUF;
12590792Sgshapiro#  if SM_IO_MIN_BUF > 0
12690792Sgshapiro		else
12790792Sgshapiro#  endif /* SM_IO_MIN_BUF > 0 */
12890792Sgshapiro# endif /* SM_IO_MAX_BUF > 0 */
12990792Sgshapiro# if SM_IO_MIN_BUF > 0
13090792Sgshapiro		if (st.st_blksize < SM_IO_MIN_BUF)
13190792Sgshapiro			st.st_blksize = SM_IO_MIN_BUF;
13290792Sgshapiro# endif /* SM_IO_MIN_BUF > 0 */
13390792Sgshapiro	}
13490792Sgshapiro#endif /* SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 */
13590792Sgshapiro
13690792Sgshapiro	/*
13790792Sgshapiro	**  Optimise fseek() only if it is a regular file.  (The test for
13890792Sgshapiro	**  sm_std_seek is mainly paranoia.)  It is safe to set _blksize
13990792Sgshapiro	**  unconditionally; it will only be used if SMOPT is also set.
14090792Sgshapiro	*/
14190792Sgshapiro
14290792Sgshapiro	if ((fp->f_flags & SMSTR) == 0)
14390792Sgshapiro	{
14490792Sgshapiro		*bufsize = st.st_blksize;
14590792Sgshapiro		fp->f_blksize = st.st_blksize;
14690792Sgshapiro	}
14790792Sgshapiro	else
14890792Sgshapiro		*bufsize = SM_IO_BUFSIZ;
14990792Sgshapiro	if ((st.st_mode & S_IFMT) == S_IFREG &&
15090792Sgshapiro	    fp->f_seek == sm_stdseek)
15190792Sgshapiro		return SMOPT;
15290792Sgshapiro	else
15390792Sgshapiro		return SMNPT;
15490792Sgshapiro}
155