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.38 2004/08/03 20:17:38 ca Exp $") 19 #include <errno.h> 20 #include <setjmp.h> 21 #include <sys/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 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 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