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