fpos.c revision 302408
1281466Sandrew/*
2281466Sandrew * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers.
3281466Sandrew *      All rights reserved.
4281466Sandrew * Copyright (c) 1990, 1993
5281466Sandrew *	The Regents of the University of California.  All rights reserved.
6281466Sandrew *
7281466Sandrew * This code is derived from software contributed to Berkeley by
8281466Sandrew * Chris Torek.
9281466Sandrew *
10281466Sandrew * By using this file, you agree to the terms and conditions set
11281466Sandrew * forth in the LICENSE file which can be found at the top level of
12281466Sandrew * the sendmail distribution.
13281466Sandrew */
14281466Sandrew
15281466Sandrew#include <sm/gen.h>
16281466SandrewSM_RCSID("@(#)$Id: fpos.c,v 1.40 2013-11-22 20:51:42 ca Exp $")
17281466Sandrew#include <errno.h>
18281466Sandrew#include <setjmp.h>
19281466Sandrew#include <sm/time.h>
20281466Sandrew#include <sm/heap.h>
21281466Sandrew#include <sm/signal.h>
22281466Sandrew#include <sm/clock.h>
23281466Sandrew#include <sm/io.h>
24281466Sandrew#include <sm/assert.h>
25281466Sandrew#include "local.h"
26281466Sandrew
27281466Sandrewstatic void	tellalrm __P((int));
28281466Sandrewstatic jmp_buf TellTimeOut;
29281466Sandrew
30281466Sandrew/*
31281466Sandrew**  TELLALRM -- handler when timeout activated for sm_io_tell()
32281466Sandrew**
33281466Sandrew**  Returns flow of control to where setjmp(TellTimeOut) was set.
34281466Sandrew**
35281466Sandrew**	Parameters:
36281466Sandrew**		sig -- unused
37281466Sandrew**
38281466Sandrew**	Returns:
39281466Sandrew**		does not return
40281466Sandrew**
41281466Sandrew**	Side Effects:
42281466Sandrew**		returns flow of control to setjmp(TellTimeOut).
43281466Sandrew**
44281466Sandrew**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
45281466Sandrew**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
46281466Sandrew**		DOING.
47281466Sandrew*/
48281466Sandrew
49281466Sandrew/* ARGSUSED0 */
50281466Sandrewstatic void
51281466Sandrewtellalrm(sig)
52281466Sandrew	int sig;
53281466Sandrew{
54281466Sandrew	longjmp(TellTimeOut, 1);
55281466Sandrew}
56281466Sandrew
57281466Sandrew/*
58281466Sandrew**  SM_IO_TELL -- position the file pointer
59281466Sandrew**
60281466Sandrew**	Paramters:
61281466Sandrew**		fp -- the file pointer to get repositioned
62281466Sandrew**		timeout -- time to complete the tell (milliseconds)
63281466Sandrew**
64281466Sandrew**	Returns:
65281466Sandrew**		Success -- the repositioned location.
66281466Sandrew**		Failure -- -1 (minus 1) and sets errno
67281466Sandrew*/
68281466Sandrew
69281466Sandrewlong
70281466Sandrewsm_io_tell(fp, timeout)
71281466Sandrew	register SM_FILE_T *fp;
72281466Sandrew	int SM_NONVOLATILE timeout;
73281466Sandrew{
74281466Sandrew	register off_t pos;
75281466Sandrew	SM_EVENT *evt = NULL;
76281466Sandrew
77281466Sandrew	SM_REQUIRE_ISA(fp, SmFileMagic);
78281466Sandrew	if (fp->f_seek == NULL)
79281466Sandrew	{
80281466Sandrew		errno = ESPIPE;			/* historic practice */
81281466Sandrew		return -1L;
82281466Sandrew	}
83281466Sandrew
84281466Sandrew	if (timeout == SM_TIME_DEFAULT)
85281466Sandrew		timeout = fp->f_timeout;
86281466Sandrew	if (timeout == SM_TIME_IMMEDIATE)
87281466Sandrew	{
88281466Sandrew		/*
89281466Sandrew		**  Filling the buffer will take time and we are wanted to
90281466Sandrew		**  return immediately. So...
91281466Sandrew		*/
92281466Sandrew
93281466Sandrew		errno = EAGAIN;
94281466Sandrew		return -1L;
95281466Sandrew	}
96281466Sandrew
97281466Sandrew	/*
98281466Sandrew	**  Find offset of underlying I/O object, then adjust byte position
99281466Sandrew	**  may adjust seek offset on append stream
100281466Sandrew	*/
101281466Sandrew
102281466Sandrew	(void) sm_flush(fp, (int *) &timeout);
103281466Sandrew
104281466Sandrew	/* This is where we start the timeout */
105283363Sandrew	if (timeout != SM_TIME_FOREVER)
106283363Sandrew	{
107283363Sandrew		if (setjmp(TellTimeOut) != 0)
108283363Sandrew		{
109283363Sandrew			errno = EAGAIN;
110283363Sandrew			return -1L;
111283363Sandrew		}
112283363Sandrew
113283363Sandrew		evt = sm_seteventm(timeout, tellalrm, 0);
114283363Sandrew	}
115283363Sandrew
116283363Sandrew	if (fp->f_flags & SMOFF)
117283363Sandrew		pos = fp->f_lseekoff;
118283363Sandrew	else
119283363Sandrew	{
120283363Sandrew		/* XXX only set the timeout here? */
121283363Sandrew		pos = (*fp->f_seek)(fp, (off_t) 0, SM_IO_SEEK_CUR);
122283363Sandrew		if (pos == -1L)
123281466Sandrew			goto clean;
124281466Sandrew	}
125281466Sandrew	if (fp->f_flags & SMRD)
126281466Sandrew	{
127281466Sandrew		/*
128281466Sandrew		**  Reading.  Any unread characters (including
129281466Sandrew		**  those from ungetc) cause the position to be
130281466Sandrew		**  smaller than that in the underlying object.
131281466Sandrew		*/
132281466Sandrew
133281466Sandrew		pos -= fp->f_r;
134281466Sandrew		if (HASUB(fp))
135281466Sandrew			pos -= fp->f_ur;
136281466Sandrew	}
137281466Sandrew	else if (fp->f_flags & SMWR && fp->f_p != NULL)
138281466Sandrew	{
139281466Sandrew		/*
140281466Sandrew		**  Writing.  Any buffered characters cause the
141281466Sandrew		**  position to be greater than that in the
142281466Sandrew		**  underlying object.
143281466Sandrew		*/
144281466Sandrew
145281466Sandrew		pos += fp->f_p - fp->f_bf.smb_base;
146281466Sandrew	}
147281466Sandrew
148281466Sandrewclean:
149281466Sandrew	/*  We're back. So undo our timeout and handler */
150281466Sandrew	if (evt != NULL)
151281466Sandrew		sm_clrevent(evt);
152281466Sandrew	return pos;
153281466Sandrew}
154281466Sandrew