Update zoneinfo database.
[dragonfly/netmp.git] / contrib / sendmail / libsm / fseek.c
blob6985e0d1dca7a473c2e63d26d1be03321c0f6989
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.
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
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.
15 #include <sm/gen.h>
16 SM_RCSID("@(#)$Id: fseek.c,v 1.45 2001/09/11 04:04:48 gshapiro Exp $")
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <setjmp.h>
23 #include <sys/time.h>
24 #include <sm/signal.h>
25 #include <sm/io.h>
26 #include <sm/assert.h>
27 #include <sm/clock.h>
28 #include "local.h"
30 #define POS_ERR (-(off_t)1)
32 static jmp_buf SeekTimeOut;
35 ** SEEKALRM -- handler when timeout activated for sm_io_seek()
37 ** Returns flow of control to where setjmp(SeekTimeOut) was set.
39 ** Parameters:
40 ** sig -- unused
42 ** Returns:
43 ** does not return
45 ** Side Effects:
46 ** returns flow of control to setjmp(SeekTimeOut).
48 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
49 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
50 ** DOING.
53 /* ARGSUSED0 */
54 static void
55 seekalrm(sig)
56 int sig;
58 longjmp(SeekTimeOut, 1);
62 ** SM_IO_SEEK -- position the file pointer
64 ** Parameters:
65 ** fp -- the file pointer to be seek'd
66 ** timeout -- time to complete seek (milliseconds)
67 ** offset -- seek offset based on 'whence'
68 ** whence -- indicates where seek is relative from.
69 ** One of SM_IO_SEEK_{CUR,SET,END}.
70 ** Returns:
71 ** Failure: returns -1 (minus 1) and sets errno
72 ** Success: returns 0 (zero)
75 int
76 sm_io_seek(fp, timeout, offset, whence)
77 register SM_FILE_T *fp;
78 int SM_NONVOLATILE timeout;
79 long SM_NONVOLATILE offset;
80 int SM_NONVOLATILE whence;
82 bool havepos;
83 off_t target, curoff;
84 size_t n;
85 struct stat st;
86 int ret;
87 SM_EVENT *evt = NULL;
88 register off_t (*seekfn) __P((SM_FILE_T *, off_t, int));
90 SM_REQUIRE_ISA(fp, SmFileMagic);
92 /* make sure stdio is set up */
93 if (!Sm_IO_DidInit)
94 sm_init();
96 /* Have to be able to seek. */
97 if ((seekfn = fp->f_seek) == NULL)
99 errno = ESPIPE; /* historic practice */
100 return -1;
103 if (timeout == SM_TIME_DEFAULT)
104 timeout = fp->f_timeout;
105 if (timeout == SM_TIME_IMMEDIATE)
108 ** Filling the buffer will take time and we are wanted to
109 ** return immediately. So...
112 errno = EAGAIN;
113 return -1;
116 #define SM_SET_ALARM() \
117 if (timeout != SM_TIME_FOREVER) \
119 if (setjmp(SeekTimeOut) != 0) \
121 errno = EAGAIN; \
122 return -1; \
124 evt = sm_seteventm(timeout, seekalrm, 0); \
128 ** Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence'
129 ** argument. After this, whence is either SM_IO_SEEK_SET or
130 ** SM_IO_SEEK_END.
133 switch (whence)
135 case SM_IO_SEEK_CUR:
138 ** In order to seek relative to the current stream offset,
139 ** we have to first find the current stream offset a la
140 ** ftell (see ftell for details).
143 /* may adjust seek offset on append stream */
144 sm_flush(fp, (int *) &timeout);
145 SM_SET_ALARM();
146 if (fp->f_flags & SMOFF)
147 curoff = fp->f_lseekoff;
148 else
150 curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
151 if (curoff == -1L)
153 ret = -1;
154 goto clean;
157 if (fp->f_flags & SMRD)
159 curoff -= fp->f_r;
160 if (HASUB(fp))
161 curoff -= fp->f_ur;
163 else if (fp->f_flags & SMWR && fp->f_p != NULL)
164 curoff += fp->f_p - fp->f_bf.smb_base;
166 offset += curoff;
167 whence = SM_IO_SEEK_SET;
168 havepos = true;
169 break;
171 case SM_IO_SEEK_SET:
172 case SM_IO_SEEK_END:
173 SM_SET_ALARM();
174 curoff = 0; /* XXX just to keep gcc quiet */
175 havepos = false;
176 break;
178 default:
179 errno = EINVAL;
180 return -1;
184 ** Can only optimise if:
185 ** reading (and not reading-and-writing);
186 ** not unbuffered; and
187 ** this is a `regular' Unix file (and hence seekfn==sm_stdseek).
188 ** We must check SMNBF first, because it is possible to have SMNBF
189 ** and SMSOPT both set.
192 if (fp->f_bf.smb_base == NULL)
193 sm_makebuf(fp);
194 if (fp->f_flags & (SMWR | SMRW | SMNBF | SMNPT))
195 goto dumb;
196 if ((fp->f_flags & SMOPT) == 0)
198 if (seekfn != sm_stdseek ||
199 fp->f_file < 0 || fstat(fp->f_file, &st) ||
200 (st.st_mode & S_IFMT) != S_IFREG)
202 fp->f_flags |= SMNPT;
203 goto dumb;
205 fp->f_blksize = st.st_blksize;
206 fp->f_flags |= SMOPT;
210 ** We are reading; we can try to optimise.
211 ** Figure out where we are going and where we are now.
214 if (whence == SM_IO_SEEK_SET)
215 target = offset;
216 else
218 if (fstat(fp->f_file, &st))
219 goto dumb;
220 target = st.st_size + offset;
223 if (!havepos)
225 if (fp->f_flags & SMOFF)
226 curoff = fp->f_lseekoff;
227 else
229 curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
230 if (curoff == POS_ERR)
231 goto dumb;
233 curoff -= fp->f_r;
234 if (HASUB(fp))
235 curoff -= fp->f_ur;
239 ** Compute the number of bytes in the input buffer (pretending
240 ** that any ungetc() input has been discarded). Adjust current
241 ** offset backwards by this count so that it represents the
242 ** file offset for the first byte in the current input buffer.
245 if (HASUB(fp))
247 curoff += fp->f_r; /* kill off ungetc */
248 n = fp->f_up - fp->f_bf.smb_base;
249 curoff -= n;
250 n += fp->f_ur;
252 else
254 n = fp->f_p - fp->f_bf.smb_base;
255 curoff -= n;
256 n += fp->f_r;
260 ** If the target offset is within the current buffer,
261 ** simply adjust the pointers, clear SMFEOF, undo ungetc(),
262 ** and return. (If the buffer was modified, we have to
263 ** skip this; see getln in fget.c.)
266 if (target >= curoff && target < curoff + (off_t) n)
268 register int o = target - curoff;
270 fp->f_p = fp->f_bf.smb_base + o;
271 fp->f_r = n - o;
272 if (HASUB(fp))
273 FREEUB(fp);
274 fp->f_flags &= ~SMFEOF;
275 ret = 0;
276 goto clean;
280 ** The place we want to get to is not within the current buffer,
281 ** but we can still be kind to the kernel copyout mechanism.
282 ** By aligning the file offset to a block boundary, we can let
283 ** the kernel use the VM hardware to map pages instead of
284 ** copying bytes laboriously. Using a block boundary also
285 ** ensures that we only read one block, rather than two.
288 curoff = target & ~(fp->f_blksize - 1);
289 if ((*seekfn)(fp, curoff, SM_IO_SEEK_SET) == POS_ERR)
290 goto dumb;
291 fp->f_r = 0;
292 fp->f_p = fp->f_bf.smb_base;
293 if (HASUB(fp))
294 FREEUB(fp);
295 fp->f_flags &= ~SMFEOF;
296 n = target - curoff;
297 if (n)
299 /* Note: SM_TIME_FOREVER since fn timeout already set */
300 if (sm_refill(fp, SM_TIME_FOREVER) || fp->f_r < (int) n)
301 goto dumb;
302 fp->f_p += n;
303 fp->f_r -= n;
306 ret = 0;
307 clean:
308 /* We're back. So undo our timeout and handler */
309 if (evt != NULL)
310 sm_clrevent(evt);
311 return ret;
312 dumb:
314 ** We get here if we cannot optimise the seek ... just
315 ** do it. Allow the seek function to change fp->f_bf.smb_base.
318 /* Note: SM_TIME_FOREVER since fn timeout already set */
319 ret = SM_TIME_FOREVER;
320 if (sm_flush(fp, &ret) != 0 ||
321 (*seekfn)(fp, (off_t) offset, whence) == POS_ERR)
323 ret = -1;
324 goto clean;
327 /* success: clear SMFEOF indicator and discard ungetc() data */
328 if (HASUB(fp))
329 FREEUB(fp);
330 fp->f_p = fp->f_bf.smb_base;
331 fp->f_r = 0;
332 fp->f_flags &= ~SMFEOF;
333 ret = 0;
334 goto clean;