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 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 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