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