xref: /titanic_44/usr/src/cmd/sendmail/libsm/fseek.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *      All rights reserved.
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993
5*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
8*7c478bd9Sstevel@tonic-gate  * Chris Torek.
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
11*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
12*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: fseek.c,v 1.46 2004/08/03 20:17:38 ca Exp $")
19*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
20*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
21*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
22*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
23*7c478bd9Sstevel@tonic-gate #include <errno.h>
24*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
25*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
26*7c478bd9Sstevel@tonic-gate #include <sm/signal.h>
27*7c478bd9Sstevel@tonic-gate #include <sm/io.h>
28*7c478bd9Sstevel@tonic-gate #include <sm/assert.h>
29*7c478bd9Sstevel@tonic-gate #include <sm/clock.h>
30*7c478bd9Sstevel@tonic-gate #include "local.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #define POS_ERR	(-(off_t)1)
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate static void	seekalrm __P((int));
35*7c478bd9Sstevel@tonic-gate static jmp_buf SeekTimeOut;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /*
38*7c478bd9Sstevel@tonic-gate **  SEEKALRM -- handler when timeout activated for sm_io_seek()
39*7c478bd9Sstevel@tonic-gate **
40*7c478bd9Sstevel@tonic-gate **  Returns flow of control to where setjmp(SeekTimeOut) was set.
41*7c478bd9Sstevel@tonic-gate **
42*7c478bd9Sstevel@tonic-gate **	Parameters:
43*7c478bd9Sstevel@tonic-gate **		sig -- unused
44*7c478bd9Sstevel@tonic-gate **
45*7c478bd9Sstevel@tonic-gate **	Returns:
46*7c478bd9Sstevel@tonic-gate **		does not return
47*7c478bd9Sstevel@tonic-gate **
48*7c478bd9Sstevel@tonic-gate **	Side Effects:
49*7c478bd9Sstevel@tonic-gate **		returns flow of control to setjmp(SeekTimeOut).
50*7c478bd9Sstevel@tonic-gate **
51*7c478bd9Sstevel@tonic-gate **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
52*7c478bd9Sstevel@tonic-gate **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
53*7c478bd9Sstevel@tonic-gate **		DOING.
54*7c478bd9Sstevel@tonic-gate */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
57*7c478bd9Sstevel@tonic-gate static void
58*7c478bd9Sstevel@tonic-gate seekalrm(sig)
59*7c478bd9Sstevel@tonic-gate 	int sig;
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	longjmp(SeekTimeOut, 1);
62*7c478bd9Sstevel@tonic-gate }
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate **  SM_IO_SEEK -- position the file pointer
66*7c478bd9Sstevel@tonic-gate **
67*7c478bd9Sstevel@tonic-gate **	Parameters:
68*7c478bd9Sstevel@tonic-gate **		fp -- the file pointer to be seek'd
69*7c478bd9Sstevel@tonic-gate **		timeout -- time to complete seek (milliseconds)
70*7c478bd9Sstevel@tonic-gate **		offset -- seek offset based on 'whence'
71*7c478bd9Sstevel@tonic-gate **		whence -- indicates where seek is relative from.
72*7c478bd9Sstevel@tonic-gate **			One of SM_IO_SEEK_{CUR,SET,END}.
73*7c478bd9Sstevel@tonic-gate **	Returns:
74*7c478bd9Sstevel@tonic-gate **		Failure: returns -1 (minus 1) and sets errno
75*7c478bd9Sstevel@tonic-gate **		Success: returns 0 (zero)
76*7c478bd9Sstevel@tonic-gate */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate int
79*7c478bd9Sstevel@tonic-gate sm_io_seek(fp, timeout, offset, whence)
80*7c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
81*7c478bd9Sstevel@tonic-gate 	int SM_NONVOLATILE timeout;
82*7c478bd9Sstevel@tonic-gate 	long SM_NONVOLATILE offset;
83*7c478bd9Sstevel@tonic-gate 	int SM_NONVOLATILE whence;
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate 	bool havepos;
86*7c478bd9Sstevel@tonic-gate 	off_t target, curoff;
87*7c478bd9Sstevel@tonic-gate 	size_t n;
88*7c478bd9Sstevel@tonic-gate 	struct stat st;
89*7c478bd9Sstevel@tonic-gate 	int ret;
90*7c478bd9Sstevel@tonic-gate 	SM_EVENT *evt = NULL;
91*7c478bd9Sstevel@tonic-gate 	register off_t (*seekfn) __P((SM_FILE_T *, off_t, int));
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(fp, SmFileMagic);
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	/* make sure stdio is set up */
96*7c478bd9Sstevel@tonic-gate 	if (!Sm_IO_DidInit)
97*7c478bd9Sstevel@tonic-gate 		sm_init();
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* Have to be able to seek. */
100*7c478bd9Sstevel@tonic-gate 	if ((seekfn = fp->f_seek) == NULL)
101*7c478bd9Sstevel@tonic-gate 	{
102*7c478bd9Sstevel@tonic-gate 		errno = ESPIPE;			/* historic practice */
103*7c478bd9Sstevel@tonic-gate 		return -1;
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_DEFAULT)
107*7c478bd9Sstevel@tonic-gate 		timeout = fp->f_timeout;
108*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)
109*7c478bd9Sstevel@tonic-gate 	{
110*7c478bd9Sstevel@tonic-gate 		/*
111*7c478bd9Sstevel@tonic-gate 		**  Filling the buffer will take time and we are wanted to
112*7c478bd9Sstevel@tonic-gate 		**  return immediately. So...
113*7c478bd9Sstevel@tonic-gate 		*/
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 		errno = EAGAIN;
116*7c478bd9Sstevel@tonic-gate 		return -1;
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate #define SM_SET_ALARM()						\
120*7c478bd9Sstevel@tonic-gate 	if (timeout != SM_TIME_FOREVER)				\
121*7c478bd9Sstevel@tonic-gate 	{							\
122*7c478bd9Sstevel@tonic-gate 		if (setjmp(SeekTimeOut) != 0)			\
123*7c478bd9Sstevel@tonic-gate 		{						\
124*7c478bd9Sstevel@tonic-gate 			errno = EAGAIN;				\
125*7c478bd9Sstevel@tonic-gate 			return -1;				\
126*7c478bd9Sstevel@tonic-gate 		}						\
127*7c478bd9Sstevel@tonic-gate 		evt = sm_seteventm(timeout, seekalrm, 0);	\
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	**  Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence'
132*7c478bd9Sstevel@tonic-gate 	**  argument. After this, whence is either SM_IO_SEEK_SET or
133*7c478bd9Sstevel@tonic-gate 	**  SM_IO_SEEK_END.
134*7c478bd9Sstevel@tonic-gate 	*/
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	switch (whence)
137*7c478bd9Sstevel@tonic-gate 	{
138*7c478bd9Sstevel@tonic-gate 	  case SM_IO_SEEK_CUR:
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		/*
141*7c478bd9Sstevel@tonic-gate 		**  In order to seek relative to the current stream offset,
142*7c478bd9Sstevel@tonic-gate 		**  we have to first find the current stream offset a la
143*7c478bd9Sstevel@tonic-gate 		**  ftell (see ftell for details).
144*7c478bd9Sstevel@tonic-gate 		*/
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 		/* may adjust seek offset on append stream */
147*7c478bd9Sstevel@tonic-gate 		sm_flush(fp, (int *) &timeout);
148*7c478bd9Sstevel@tonic-gate 		SM_SET_ALARM();
149*7c478bd9Sstevel@tonic-gate 		if (fp->f_flags & SMOFF)
150*7c478bd9Sstevel@tonic-gate 			curoff = fp->f_lseekoff;
151*7c478bd9Sstevel@tonic-gate 		else
152*7c478bd9Sstevel@tonic-gate 		{
153*7c478bd9Sstevel@tonic-gate 			curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
154*7c478bd9Sstevel@tonic-gate 			if (curoff == -1L)
155*7c478bd9Sstevel@tonic-gate 			{
156*7c478bd9Sstevel@tonic-gate 				ret = -1;
157*7c478bd9Sstevel@tonic-gate 				goto clean;
158*7c478bd9Sstevel@tonic-gate 			}
159*7c478bd9Sstevel@tonic-gate 		}
160*7c478bd9Sstevel@tonic-gate 		if (fp->f_flags & SMRD)
161*7c478bd9Sstevel@tonic-gate 		{
162*7c478bd9Sstevel@tonic-gate 			curoff -= fp->f_r;
163*7c478bd9Sstevel@tonic-gate 			if (HASUB(fp))
164*7c478bd9Sstevel@tonic-gate 				curoff -= fp->f_ur;
165*7c478bd9Sstevel@tonic-gate 		}
166*7c478bd9Sstevel@tonic-gate 		else if (fp->f_flags & SMWR && fp->f_p != NULL)
167*7c478bd9Sstevel@tonic-gate 			curoff += fp->f_p - fp->f_bf.smb_base;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		offset += curoff;
170*7c478bd9Sstevel@tonic-gate 		whence = SM_IO_SEEK_SET;
171*7c478bd9Sstevel@tonic-gate 		havepos = true;
172*7c478bd9Sstevel@tonic-gate 		break;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	  case SM_IO_SEEK_SET:
175*7c478bd9Sstevel@tonic-gate 	  case SM_IO_SEEK_END:
176*7c478bd9Sstevel@tonic-gate 		SM_SET_ALARM();
177*7c478bd9Sstevel@tonic-gate 		curoff = 0;		/* XXX just to keep gcc quiet */
178*7c478bd9Sstevel@tonic-gate 		havepos = false;
179*7c478bd9Sstevel@tonic-gate 		break;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	  default:
182*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
183*7c478bd9Sstevel@tonic-gate 		return -1;
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	/*
187*7c478bd9Sstevel@tonic-gate 	**  Can only optimise if:
188*7c478bd9Sstevel@tonic-gate 	**	reading (and not reading-and-writing);
189*7c478bd9Sstevel@tonic-gate 	**	not unbuffered; and
190*7c478bd9Sstevel@tonic-gate 	**	this is a `regular' Unix file (and hence seekfn==sm_stdseek).
191*7c478bd9Sstevel@tonic-gate 	**  We must check SMNBF first, because it is possible to have SMNBF
192*7c478bd9Sstevel@tonic-gate 	**  and SMSOPT both set.
193*7c478bd9Sstevel@tonic-gate 	*/
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (fp->f_bf.smb_base == NULL)
196*7c478bd9Sstevel@tonic-gate 		sm_makebuf(fp);
197*7c478bd9Sstevel@tonic-gate 	if (fp->f_flags & (SMWR | SMRW | SMNBF | SMNPT))
198*7c478bd9Sstevel@tonic-gate 		goto dumb;
199*7c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & SMOPT) == 0)
200*7c478bd9Sstevel@tonic-gate 	{
201*7c478bd9Sstevel@tonic-gate 		if (seekfn != sm_stdseek ||
202*7c478bd9Sstevel@tonic-gate 		    fp->f_file < 0 || fstat(fp->f_file, &st) ||
203*7c478bd9Sstevel@tonic-gate 		    (st.st_mode & S_IFMT) != S_IFREG)
204*7c478bd9Sstevel@tonic-gate 		{
205*7c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMNPT;
206*7c478bd9Sstevel@tonic-gate 			goto dumb;
207*7c478bd9Sstevel@tonic-gate 		}
208*7c478bd9Sstevel@tonic-gate 		fp->f_blksize = st.st_blksize;
209*7c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMOPT;
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	/*
213*7c478bd9Sstevel@tonic-gate 	**  We are reading; we can try to optimise.
214*7c478bd9Sstevel@tonic-gate 	**  Figure out where we are going and where we are now.
215*7c478bd9Sstevel@tonic-gate 	*/
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	if (whence == SM_IO_SEEK_SET)
218*7c478bd9Sstevel@tonic-gate 		target = offset;
219*7c478bd9Sstevel@tonic-gate 	else
220*7c478bd9Sstevel@tonic-gate 	{
221*7c478bd9Sstevel@tonic-gate 		if (fstat(fp->f_file, &st))
222*7c478bd9Sstevel@tonic-gate 			goto dumb;
223*7c478bd9Sstevel@tonic-gate 		target = st.st_size + offset;
224*7c478bd9Sstevel@tonic-gate 	}
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	if (!havepos)
227*7c478bd9Sstevel@tonic-gate 	{
228*7c478bd9Sstevel@tonic-gate 		if (fp->f_flags & SMOFF)
229*7c478bd9Sstevel@tonic-gate 			curoff = fp->f_lseekoff;
230*7c478bd9Sstevel@tonic-gate 		else
231*7c478bd9Sstevel@tonic-gate 		{
232*7c478bd9Sstevel@tonic-gate 			curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
233*7c478bd9Sstevel@tonic-gate 			if (curoff == POS_ERR)
234*7c478bd9Sstevel@tonic-gate 				goto dumb;
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 		curoff -= fp->f_r;
237*7c478bd9Sstevel@tonic-gate 		if (HASUB(fp))
238*7c478bd9Sstevel@tonic-gate 			curoff -= fp->f_ur;
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/*
242*7c478bd9Sstevel@tonic-gate 	**  Compute the number of bytes in the input buffer (pretending
243*7c478bd9Sstevel@tonic-gate 	**  that any ungetc() input has been discarded).  Adjust current
244*7c478bd9Sstevel@tonic-gate 	**  offset backwards by this count so that it represents the
245*7c478bd9Sstevel@tonic-gate 	**  file offset for the first byte in the current input buffer.
246*7c478bd9Sstevel@tonic-gate 	*/
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	if (HASUB(fp))
249*7c478bd9Sstevel@tonic-gate 	{
250*7c478bd9Sstevel@tonic-gate 		curoff += fp->f_r;	/* kill off ungetc */
251*7c478bd9Sstevel@tonic-gate 		n = fp->f_up - fp->f_bf.smb_base;
252*7c478bd9Sstevel@tonic-gate 		curoff -= n;
253*7c478bd9Sstevel@tonic-gate 		n += fp->f_ur;
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 	else
256*7c478bd9Sstevel@tonic-gate 	{
257*7c478bd9Sstevel@tonic-gate 		n = fp->f_p - fp->f_bf.smb_base;
258*7c478bd9Sstevel@tonic-gate 		curoff -= n;
259*7c478bd9Sstevel@tonic-gate 		n += fp->f_r;
260*7c478bd9Sstevel@tonic-gate 	}
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/*
263*7c478bd9Sstevel@tonic-gate 	**  If the target offset is within the current buffer,
264*7c478bd9Sstevel@tonic-gate 	**  simply adjust the pointers, clear SMFEOF, undo ungetc(),
265*7c478bd9Sstevel@tonic-gate 	**  and return.  (If the buffer was modified, we have to
266*7c478bd9Sstevel@tonic-gate 	**  skip this; see getln in fget.c.)
267*7c478bd9Sstevel@tonic-gate 	*/
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (target >= curoff && target < curoff + (off_t) n)
270*7c478bd9Sstevel@tonic-gate 	{
271*7c478bd9Sstevel@tonic-gate 		register int o = target - curoff;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		fp->f_p = fp->f_bf.smb_base + o;
274*7c478bd9Sstevel@tonic-gate 		fp->f_r = n - o;
275*7c478bd9Sstevel@tonic-gate 		if (HASUB(fp))
276*7c478bd9Sstevel@tonic-gate 			FREEUB(fp);
277*7c478bd9Sstevel@tonic-gate 		fp->f_flags &= ~SMFEOF;
278*7c478bd9Sstevel@tonic-gate 		ret = 0;
279*7c478bd9Sstevel@tonic-gate 		goto clean;
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	/*
283*7c478bd9Sstevel@tonic-gate 	**  The place we want to get to is not within the current buffer,
284*7c478bd9Sstevel@tonic-gate 	**  but we can still be kind to the kernel copyout mechanism.
285*7c478bd9Sstevel@tonic-gate 	**  By aligning the file offset to a block boundary, we can let
286*7c478bd9Sstevel@tonic-gate 	**  the kernel use the VM hardware to map pages instead of
287*7c478bd9Sstevel@tonic-gate 	**  copying bytes laboriously.  Using a block boundary also
288*7c478bd9Sstevel@tonic-gate 	**  ensures that we only read one block, rather than two.
289*7c478bd9Sstevel@tonic-gate 	*/
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	curoff = target & ~(fp->f_blksize - 1);
292*7c478bd9Sstevel@tonic-gate 	if ((*seekfn)(fp, curoff, SM_IO_SEEK_SET) == POS_ERR)
293*7c478bd9Sstevel@tonic-gate 		goto dumb;
294*7c478bd9Sstevel@tonic-gate 	fp->f_r = 0;
295*7c478bd9Sstevel@tonic-gate 	fp->f_p = fp->f_bf.smb_base;
296*7c478bd9Sstevel@tonic-gate 	if (HASUB(fp))
297*7c478bd9Sstevel@tonic-gate 		FREEUB(fp);
298*7c478bd9Sstevel@tonic-gate 	fp->f_flags &= ~SMFEOF;
299*7c478bd9Sstevel@tonic-gate 	n = target - curoff;
300*7c478bd9Sstevel@tonic-gate 	if (n)
301*7c478bd9Sstevel@tonic-gate 	{
302*7c478bd9Sstevel@tonic-gate 		/* Note: SM_TIME_FOREVER since fn timeout already set */
303*7c478bd9Sstevel@tonic-gate 		if (sm_refill(fp, SM_TIME_FOREVER) || fp->f_r < (int) n)
304*7c478bd9Sstevel@tonic-gate 			goto dumb;
305*7c478bd9Sstevel@tonic-gate 		fp->f_p += n;
306*7c478bd9Sstevel@tonic-gate 		fp->f_r -= n;
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	ret = 0;
310*7c478bd9Sstevel@tonic-gate clean:
311*7c478bd9Sstevel@tonic-gate 	/*  We're back. So undo our timeout and handler */
312*7c478bd9Sstevel@tonic-gate 	if (evt != NULL)
313*7c478bd9Sstevel@tonic-gate 		sm_clrevent(evt);
314*7c478bd9Sstevel@tonic-gate 	return ret;
315*7c478bd9Sstevel@tonic-gate dumb:
316*7c478bd9Sstevel@tonic-gate 	/*
317*7c478bd9Sstevel@tonic-gate 	**  We get here if we cannot optimise the seek ... just
318*7c478bd9Sstevel@tonic-gate 	**  do it.  Allow the seek function to change fp->f_bf.smb_base.
319*7c478bd9Sstevel@tonic-gate 	*/
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	/* Note: SM_TIME_FOREVER since fn timeout already set */
322*7c478bd9Sstevel@tonic-gate 	ret = SM_TIME_FOREVER;
323*7c478bd9Sstevel@tonic-gate 	if (sm_flush(fp, &ret) != 0 ||
324*7c478bd9Sstevel@tonic-gate 	    (*seekfn)(fp, (off_t) offset, whence) == POS_ERR)
325*7c478bd9Sstevel@tonic-gate 	{
326*7c478bd9Sstevel@tonic-gate 		ret = -1;
327*7c478bd9Sstevel@tonic-gate 		goto clean;
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	/* success: clear SMFEOF indicator and discard ungetc() data */
331*7c478bd9Sstevel@tonic-gate 	if (HASUB(fp))
332*7c478bd9Sstevel@tonic-gate 		FREEUB(fp);
333*7c478bd9Sstevel@tonic-gate 	fp->f_p = fp->f_bf.smb_base;
334*7c478bd9Sstevel@tonic-gate 	fp->f_r = 0;
335*7c478bd9Sstevel@tonic-gate 	fp->f_flags &= ~SMFEOF;
336*7c478bd9Sstevel@tonic-gate 	ret = 0;
337*7c478bd9Sstevel@tonic-gate 	goto clean;
338*7c478bd9Sstevel@tonic-gate }
339