1/*
2 * Copyright (c) 2000-2001, 2004 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: fpos.c,v 1.39 2005/06/14 23:07:20 ca Exp $")
19#include <errno.h>
20#include <setjmp.h>
21#include <sm/time.h>
22#include <sm/heap.h>
23#include <sm/signal.h>
24#include <sm/clock.h>
25#include <sm/io.h>
26#include <sm/assert.h>
27#include "local.h"
28
29static void	tellalrm __P((int));
30static jmp_buf TellTimeOut;
31
32/*
33**  TELLALRM -- handler when timeout activated for sm_io_tell()
34**
35**  Returns flow of control to where setjmp(TellTimeOut) was set.
36**
37**	Parameters:
38**		sig -- unused
39**
40**	Returns:
41**		does not return
42**
43**	Side Effects:
44**		returns flow of control to setjmp(TellTimeOut).
45**
46**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
47**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
48**		DOING.
49*/
50
51/* ARGSUSED0 */
52static void
53tellalrm(sig)
54	int sig;
55{
56	longjmp(TellTimeOut, 1);
57}
58
59/*
60**  SM_IO_TELL -- position the file pointer
61**
62**	Paramters:
63**		fp -- the file pointer to get repositioned
64**		timeout -- time to complete the tell (milliseconds)
65**
66**	Returns:
67**		Success -- the repositioned location.
68**		Failure -- -1 (minus 1) and sets errno
69*/
70
71long
72sm_io_tell(fp, timeout)
73	register SM_FILE_T *fp;
74	int SM_NONVOLATILE timeout;
75{
76	register off_t pos;
77	SM_EVENT *evt = NULL;
78
79	SM_REQUIRE_ISA(fp, SmFileMagic);
80	if (fp->f_seek == NULL)
81	{
82		errno = ESPIPE;			/* historic practice */
83		return -1L;
84	}
85
86	if (timeout == SM_TIME_DEFAULT)
87		timeout = fp->f_timeout;
88	if (timeout == SM_TIME_IMMEDIATE)
89	{
90		/*
91		**  Filling the buffer will take time and we are wanted to
92		**  return immediately. So...
93		*/
94
95		errno = EAGAIN;
96		return -1L;
97	}
98
99	/*
100	**  Find offset of underlying I/O object, then adjust byte position
101	**  may adjust seek offset on append stream
102	*/
103
104	(void) sm_flush(fp, (int *) &timeout);
105
106	/* This is where we start the timeout */
107	if (timeout != SM_TIME_FOREVER)
108	{
109		if (setjmp(TellTimeOut) != 0)
110		{
111			errno = EAGAIN;
112			return -1L;
113		}
114
115		evt = sm_seteventm(timeout, tellalrm, 0);
116	}
117
118	if (fp->f_flags & SMOFF)
119		pos = fp->f_lseekoff;
120	else
121	{
122		/* XXX only set the timeout here? */
123		pos = (*fp->f_seek)(fp, (off_t) 0, SM_IO_SEEK_CUR);
124		if (pos == -1L)
125			goto clean;
126	}
127	if (fp->f_flags & SMRD)
128	{
129		/*
130		**  Reading.  Any unread characters (including
131		**  those from ungetc) cause the position to be
132		**  smaller than that in the underlying object.
133		*/
134
135		pos -= fp->f_r;
136		if (HASUB(fp))
137			pos -= fp->f_ur;
138	}
139	else if (fp->f_flags & SMWR && fp->f_p != NULL)
140	{
141		/*
142		**  Writing.  Any buffered characters cause the
143		**  position to be greater than that in the
144		**  underlying object.
145		*/
146
147		pos += fp->f_p - fp->f_bf.smb_base;
148	}
149
150clean:
151	/*  We're back. So undo our timeout and handler */
152	if (evt != NULL)
153		sm_clrevent(evt);
154	return pos;
155}
156