xref: /freebsd/contrib/sendmail/libsm/fpos.c (revision 2f02600abfddfc4e9f20dd384a2e729b451e16bd)
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>
16 SM_RCSID("@(#)$Id: fpos.c,v 1.39 2005/06/14 23:07:20 ca Exp $")
17 #include <errno.h>
18 #include <setjmp.h>
19 #include <sm/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 
27 static void	tellalrm __P((int));
28 static 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 */
50 static void
51 tellalrm(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 
69 long
70 sm_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 
148 clean:
149 	/*  We're back. So undo our timeout and handler */
150 	if (evt != NULL)
151 		sm_clrevent(evt);
152 	return pos;
153 }
154