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
tellalrm(sig)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
sm_io_tell(fp,timeout)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