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>
18 SM_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
29 static void tellalrm __P((int));
30 static 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 */
52 static void
tellalrm(sig)53 tellalrm(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
71 long
sm_io_tell(fp,timeout)72 sm_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
150 clean:
151 /* We're back. So undo our timeout and handler */
152 if (evt != NULL)
153 sm_clrevent(evt);
154 return pos;
155 }
156