1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
13 */
14
15#pragma ident	"%Z%%M%	%I%	%E% SMI"
16
17#include <sm/gen.h>
18SM_RCSID("@(#)$Id: makebuf.c,v 1.26 2001/10/31 16:04:08 ca Exp $")
19#include <stdlib.h>
20#include <unistd.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sm/io.h>
24#include <sm/heap.h>
25#include <sm/conf.h>
26#include "local.h"
27
28/*
29**  SM_MAKEBUF -- make a buffer for the file
30**
31**	Parameters:
32**		fp -- the file to be buffered
33**
34**	Returns:
35**		nothing
36**
37**	Allocate a file buffer, or switch to unbuffered I/O.
38**	By default tty devices default to line buffered.
39*/
40
41void
42sm_makebuf(fp)
43	register SM_FILE_T *fp;
44{
45	register void *p;
46	register int flags;
47	size_t size;
48	int couldbetty;
49
50	if (fp->f_flags & SMNBF)
51	{
52		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
53		fp->f_bf.smb_size = 1;
54		return;
55	}
56	flags = sm_whatbuf(fp, &size, &couldbetty);
57	if ((p = sm_malloc(size)) == NULL)
58	{
59		fp->f_flags |= SMNBF;
60		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
61		fp->f_bf.smb_size = 1;
62		return;
63	}
64	if (!Sm_IO_DidInit)
65		sm_init();
66	flags |= SMMBF;
67	fp->f_bf.smb_base = fp->f_p = p;
68	fp->f_bf.smb_size = size;
69	if (couldbetty && isatty(fp->f_file))
70		flags |= SMLBF;
71	fp->f_flags |= flags;
72}
73
74/*
75**  SM_WHATBUF -- determine proper buffer for a file (internal)
76**
77**  Plus it fills in 'bufsize' for recommended buffer size and
78**  fills in flag to indicate if 'fp' could be a tty (nothing
79**  to do with "betty" :-) ).
80**
81**	Parameters:
82**		fp -- file pointer to be buffered
83**		bufsize -- new buffer size (a return)
84**		couldbetty -- could be a tty (returns)
85**
86**	Returns:
87**		Success:
88**		on error:
89**			SMNPT -- not seek opimized
90**			SMOPT -- seek opimized
91*/
92
93int
94sm_whatbuf(fp, bufsize, couldbetty)
95	register SM_FILE_T *fp;
96	size_t *bufsize;
97	int *couldbetty;
98{
99	struct stat st;
100
101	if (fp->f_file < 0 || fstat(fp->f_file, &st) < 0)
102	{
103		*couldbetty = 0;
104		*bufsize = SM_IO_BUFSIZ;
105		return SMNPT;
106	}
107
108	/* could be a tty iff it is a character device */
109	*couldbetty = S_ISCHR(st.st_mode);
110	if (st.st_blksize == 0)
111	{
112		*bufsize = SM_IO_BUFSIZ;
113		return SMNPT;
114	}
115
116#if SM_IO_MAX_BUF_FILE > 0
117	if (S_ISREG(st.st_mode) && st.st_blksize > SM_IO_MAX_BUF_FILE)
118		st.st_blksize = SM_IO_MAX_BUF_FILE;
119#endif /* SM_IO_MAX_BUF_FILE > 0 */
120
121#if SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0
122	if (!S_ISREG(st.st_mode))
123	{
124# if SM_IO_MAX_BUF > 0
125		if (st.st_blksize > SM_IO_MAX_BUF)
126			st.st_blksize = SM_IO_MAX_BUF;
127#  if SM_IO_MIN_BUF > 0
128		else
129#  endif /* SM_IO_MIN_BUF > 0 */
130# endif /* SM_IO_MAX_BUF > 0 */
131# if SM_IO_MIN_BUF > 0
132		if (st.st_blksize < SM_IO_MIN_BUF)
133			st.st_blksize = SM_IO_MIN_BUF;
134# endif /* SM_IO_MIN_BUF > 0 */
135	}
136#endif /* SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 */
137
138	/*
139	**  Optimise fseek() only if it is a regular file.  (The test for
140	**  sm_std_seek is mainly paranoia.)  It is safe to set _blksize
141	**  unconditionally; it will only be used if SMOPT is also set.
142	*/
143
144	if ((fp->f_flags & SMSTR) == 0)
145	{
146		*bufsize = st.st_blksize;
147		fp->f_blksize = st.st_blksize;
148	}
149	else
150		*bufsize = SM_IO_BUFSIZ;
151	if ((st.st_mode & S_IFMT) == S_IFREG &&
152	    fp->f_seek == sm_stdseek)
153		return SMOPT;
154	else
155		return SMNPT;
156}
157