1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1990, 1993 5*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 8*7c478bd9Sstevel@tonic-gate * Chris Torek. 9*7c478bd9Sstevel@tonic-gate * 10*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 11*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 12*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: fseek.c,v 1.46 2004/08/03 20:17:38 ca Exp $") 19*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 20*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 21*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 22*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 23*7c478bd9Sstevel@tonic-gate #include <errno.h> 24*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 25*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 26*7c478bd9Sstevel@tonic-gate #include <sm/signal.h> 27*7c478bd9Sstevel@tonic-gate #include <sm/io.h> 28*7c478bd9Sstevel@tonic-gate #include <sm/assert.h> 29*7c478bd9Sstevel@tonic-gate #include <sm/clock.h> 30*7c478bd9Sstevel@tonic-gate #include "local.h" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #define POS_ERR (-(off_t)1) 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate static void seekalrm __P((int)); 35*7c478bd9Sstevel@tonic-gate static jmp_buf SeekTimeOut; 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /* 38*7c478bd9Sstevel@tonic-gate ** SEEKALRM -- handler when timeout activated for sm_io_seek() 39*7c478bd9Sstevel@tonic-gate ** 40*7c478bd9Sstevel@tonic-gate ** Returns flow of control to where setjmp(SeekTimeOut) was set. 41*7c478bd9Sstevel@tonic-gate ** 42*7c478bd9Sstevel@tonic-gate ** Parameters: 43*7c478bd9Sstevel@tonic-gate ** sig -- unused 44*7c478bd9Sstevel@tonic-gate ** 45*7c478bd9Sstevel@tonic-gate ** Returns: 46*7c478bd9Sstevel@tonic-gate ** does not return 47*7c478bd9Sstevel@tonic-gate ** 48*7c478bd9Sstevel@tonic-gate ** Side Effects: 49*7c478bd9Sstevel@tonic-gate ** returns flow of control to setjmp(SeekTimeOut). 50*7c478bd9Sstevel@tonic-gate ** 51*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 52*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 53*7c478bd9Sstevel@tonic-gate ** DOING. 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 57*7c478bd9Sstevel@tonic-gate static void 58*7c478bd9Sstevel@tonic-gate seekalrm(sig) 59*7c478bd9Sstevel@tonic-gate int sig; 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate longjmp(SeekTimeOut, 1); 62*7c478bd9Sstevel@tonic-gate } 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate ** SM_IO_SEEK -- position the file pointer 66*7c478bd9Sstevel@tonic-gate ** 67*7c478bd9Sstevel@tonic-gate ** Parameters: 68*7c478bd9Sstevel@tonic-gate ** fp -- the file pointer to be seek'd 69*7c478bd9Sstevel@tonic-gate ** timeout -- time to complete seek (milliseconds) 70*7c478bd9Sstevel@tonic-gate ** offset -- seek offset based on 'whence' 71*7c478bd9Sstevel@tonic-gate ** whence -- indicates where seek is relative from. 72*7c478bd9Sstevel@tonic-gate ** One of SM_IO_SEEK_{CUR,SET,END}. 73*7c478bd9Sstevel@tonic-gate ** Returns: 74*7c478bd9Sstevel@tonic-gate ** Failure: returns -1 (minus 1) and sets errno 75*7c478bd9Sstevel@tonic-gate ** Success: returns 0 (zero) 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate int 79*7c478bd9Sstevel@tonic-gate sm_io_seek(fp, timeout, offset, whence) 80*7c478bd9Sstevel@tonic-gate register SM_FILE_T *fp; 81*7c478bd9Sstevel@tonic-gate int SM_NONVOLATILE timeout; 82*7c478bd9Sstevel@tonic-gate long SM_NONVOLATILE offset; 83*7c478bd9Sstevel@tonic-gate int SM_NONVOLATILE whence; 84*7c478bd9Sstevel@tonic-gate { 85*7c478bd9Sstevel@tonic-gate bool havepos; 86*7c478bd9Sstevel@tonic-gate off_t target, curoff; 87*7c478bd9Sstevel@tonic-gate size_t n; 88*7c478bd9Sstevel@tonic-gate struct stat st; 89*7c478bd9Sstevel@tonic-gate int ret; 90*7c478bd9Sstevel@tonic-gate SM_EVENT *evt = NULL; 91*7c478bd9Sstevel@tonic-gate register off_t (*seekfn) __P((SM_FILE_T *, off_t, int)); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp, SmFileMagic); 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* make sure stdio is set up */ 96*7c478bd9Sstevel@tonic-gate if (!Sm_IO_DidInit) 97*7c478bd9Sstevel@tonic-gate sm_init(); 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* Have to be able to seek. */ 100*7c478bd9Sstevel@tonic-gate if ((seekfn = fp->f_seek) == NULL) 101*7c478bd9Sstevel@tonic-gate { 102*7c478bd9Sstevel@tonic-gate errno = ESPIPE; /* historic practice */ 103*7c478bd9Sstevel@tonic-gate return -1; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_DEFAULT) 107*7c478bd9Sstevel@tonic-gate timeout = fp->f_timeout; 108*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_IMMEDIATE) 109*7c478bd9Sstevel@tonic-gate { 110*7c478bd9Sstevel@tonic-gate /* 111*7c478bd9Sstevel@tonic-gate ** Filling the buffer will take time and we are wanted to 112*7c478bd9Sstevel@tonic-gate ** return immediately. So... 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 116*7c478bd9Sstevel@tonic-gate return -1; 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate #define SM_SET_ALARM() \ 120*7c478bd9Sstevel@tonic-gate if (timeout != SM_TIME_FOREVER) \ 121*7c478bd9Sstevel@tonic-gate { \ 122*7c478bd9Sstevel@tonic-gate if (setjmp(SeekTimeOut) != 0) \ 123*7c478bd9Sstevel@tonic-gate { \ 124*7c478bd9Sstevel@tonic-gate errno = EAGAIN; \ 125*7c478bd9Sstevel@tonic-gate return -1; \ 126*7c478bd9Sstevel@tonic-gate } \ 127*7c478bd9Sstevel@tonic-gate evt = sm_seteventm(timeout, seekalrm, 0); \ 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate ** Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence' 132*7c478bd9Sstevel@tonic-gate ** argument. After this, whence is either SM_IO_SEEK_SET or 133*7c478bd9Sstevel@tonic-gate ** SM_IO_SEEK_END. 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate switch (whence) 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate case SM_IO_SEEK_CUR: 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate ** In order to seek relative to the current stream offset, 142*7c478bd9Sstevel@tonic-gate ** we have to first find the current stream offset a la 143*7c478bd9Sstevel@tonic-gate ** ftell (see ftell for details). 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* may adjust seek offset on append stream */ 147*7c478bd9Sstevel@tonic-gate sm_flush(fp, (int *) &timeout); 148*7c478bd9Sstevel@tonic-gate SM_SET_ALARM(); 149*7c478bd9Sstevel@tonic-gate if (fp->f_flags & SMOFF) 150*7c478bd9Sstevel@tonic-gate curoff = fp->f_lseekoff; 151*7c478bd9Sstevel@tonic-gate else 152*7c478bd9Sstevel@tonic-gate { 153*7c478bd9Sstevel@tonic-gate curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR); 154*7c478bd9Sstevel@tonic-gate if (curoff == -1L) 155*7c478bd9Sstevel@tonic-gate { 156*7c478bd9Sstevel@tonic-gate ret = -1; 157*7c478bd9Sstevel@tonic-gate goto clean; 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate if (fp->f_flags & SMRD) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate curoff -= fp->f_r; 163*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 164*7c478bd9Sstevel@tonic-gate curoff -= fp->f_ur; 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate else if (fp->f_flags & SMWR && fp->f_p != NULL) 167*7c478bd9Sstevel@tonic-gate curoff += fp->f_p - fp->f_bf.smb_base; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate offset += curoff; 170*7c478bd9Sstevel@tonic-gate whence = SM_IO_SEEK_SET; 171*7c478bd9Sstevel@tonic-gate havepos = true; 172*7c478bd9Sstevel@tonic-gate break; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate case SM_IO_SEEK_SET: 175*7c478bd9Sstevel@tonic-gate case SM_IO_SEEK_END: 176*7c478bd9Sstevel@tonic-gate SM_SET_ALARM(); 177*7c478bd9Sstevel@tonic-gate curoff = 0; /* XXX just to keep gcc quiet */ 178*7c478bd9Sstevel@tonic-gate havepos = false; 179*7c478bd9Sstevel@tonic-gate break; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate default: 182*7c478bd9Sstevel@tonic-gate errno = EINVAL; 183*7c478bd9Sstevel@tonic-gate return -1; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate ** Can only optimise if: 188*7c478bd9Sstevel@tonic-gate ** reading (and not reading-and-writing); 189*7c478bd9Sstevel@tonic-gate ** not unbuffered; and 190*7c478bd9Sstevel@tonic-gate ** this is a `regular' Unix file (and hence seekfn==sm_stdseek). 191*7c478bd9Sstevel@tonic-gate ** We must check SMNBF first, because it is possible to have SMNBF 192*7c478bd9Sstevel@tonic-gate ** and SMSOPT both set. 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate if (fp->f_bf.smb_base == NULL) 196*7c478bd9Sstevel@tonic-gate sm_makebuf(fp); 197*7c478bd9Sstevel@tonic-gate if (fp->f_flags & (SMWR | SMRW | SMNBF | SMNPT)) 198*7c478bd9Sstevel@tonic-gate goto dumb; 199*7c478bd9Sstevel@tonic-gate if ((fp->f_flags & SMOPT) == 0) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate if (seekfn != sm_stdseek || 202*7c478bd9Sstevel@tonic-gate fp->f_file < 0 || fstat(fp->f_file, &st) || 203*7c478bd9Sstevel@tonic-gate (st.st_mode & S_IFMT) != S_IFREG) 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate fp->f_flags |= SMNPT; 206*7c478bd9Sstevel@tonic-gate goto dumb; 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate fp->f_blksize = st.st_blksize; 209*7c478bd9Sstevel@tonic-gate fp->f_flags |= SMOPT; 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate ** We are reading; we can try to optimise. 214*7c478bd9Sstevel@tonic-gate ** Figure out where we are going and where we are now. 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (whence == SM_IO_SEEK_SET) 218*7c478bd9Sstevel@tonic-gate target = offset; 219*7c478bd9Sstevel@tonic-gate else 220*7c478bd9Sstevel@tonic-gate { 221*7c478bd9Sstevel@tonic-gate if (fstat(fp->f_file, &st)) 222*7c478bd9Sstevel@tonic-gate goto dumb; 223*7c478bd9Sstevel@tonic-gate target = st.st_size + offset; 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate if (!havepos) 227*7c478bd9Sstevel@tonic-gate { 228*7c478bd9Sstevel@tonic-gate if (fp->f_flags & SMOFF) 229*7c478bd9Sstevel@tonic-gate curoff = fp->f_lseekoff; 230*7c478bd9Sstevel@tonic-gate else 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR); 233*7c478bd9Sstevel@tonic-gate if (curoff == POS_ERR) 234*7c478bd9Sstevel@tonic-gate goto dumb; 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate curoff -= fp->f_r; 237*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 238*7c478bd9Sstevel@tonic-gate curoff -= fp->f_ur; 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate ** Compute the number of bytes in the input buffer (pretending 243*7c478bd9Sstevel@tonic-gate ** that any ungetc() input has been discarded). Adjust current 244*7c478bd9Sstevel@tonic-gate ** offset backwards by this count so that it represents the 245*7c478bd9Sstevel@tonic-gate ** file offset for the first byte in the current input buffer. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 249*7c478bd9Sstevel@tonic-gate { 250*7c478bd9Sstevel@tonic-gate curoff += fp->f_r; /* kill off ungetc */ 251*7c478bd9Sstevel@tonic-gate n = fp->f_up - fp->f_bf.smb_base; 252*7c478bd9Sstevel@tonic-gate curoff -= n; 253*7c478bd9Sstevel@tonic-gate n += fp->f_ur; 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate else 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate n = fp->f_p - fp->f_bf.smb_base; 258*7c478bd9Sstevel@tonic-gate curoff -= n; 259*7c478bd9Sstevel@tonic-gate n += fp->f_r; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate ** If the target offset is within the current buffer, 264*7c478bd9Sstevel@tonic-gate ** simply adjust the pointers, clear SMFEOF, undo ungetc(), 265*7c478bd9Sstevel@tonic-gate ** and return. (If the buffer was modified, we have to 266*7c478bd9Sstevel@tonic-gate ** skip this; see getln in fget.c.) 267*7c478bd9Sstevel@tonic-gate */ 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate if (target >= curoff && target < curoff + (off_t) n) 270*7c478bd9Sstevel@tonic-gate { 271*7c478bd9Sstevel@tonic-gate register int o = target - curoff; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate fp->f_p = fp->f_bf.smb_base + o; 274*7c478bd9Sstevel@tonic-gate fp->f_r = n - o; 275*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 276*7c478bd9Sstevel@tonic-gate FREEUB(fp); 277*7c478bd9Sstevel@tonic-gate fp->f_flags &= ~SMFEOF; 278*7c478bd9Sstevel@tonic-gate ret = 0; 279*7c478bd9Sstevel@tonic-gate goto clean; 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate ** The place we want to get to is not within the current buffer, 284*7c478bd9Sstevel@tonic-gate ** but we can still be kind to the kernel copyout mechanism. 285*7c478bd9Sstevel@tonic-gate ** By aligning the file offset to a block boundary, we can let 286*7c478bd9Sstevel@tonic-gate ** the kernel use the VM hardware to map pages instead of 287*7c478bd9Sstevel@tonic-gate ** copying bytes laboriously. Using a block boundary also 288*7c478bd9Sstevel@tonic-gate ** ensures that we only read one block, rather than two. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate curoff = target & ~(fp->f_blksize - 1); 292*7c478bd9Sstevel@tonic-gate if ((*seekfn)(fp, curoff, SM_IO_SEEK_SET) == POS_ERR) 293*7c478bd9Sstevel@tonic-gate goto dumb; 294*7c478bd9Sstevel@tonic-gate fp->f_r = 0; 295*7c478bd9Sstevel@tonic-gate fp->f_p = fp->f_bf.smb_base; 296*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 297*7c478bd9Sstevel@tonic-gate FREEUB(fp); 298*7c478bd9Sstevel@tonic-gate fp->f_flags &= ~SMFEOF; 299*7c478bd9Sstevel@tonic-gate n = target - curoff; 300*7c478bd9Sstevel@tonic-gate if (n) 301*7c478bd9Sstevel@tonic-gate { 302*7c478bd9Sstevel@tonic-gate /* Note: SM_TIME_FOREVER since fn timeout already set */ 303*7c478bd9Sstevel@tonic-gate if (sm_refill(fp, SM_TIME_FOREVER) || fp->f_r < (int) n) 304*7c478bd9Sstevel@tonic-gate goto dumb; 305*7c478bd9Sstevel@tonic-gate fp->f_p += n; 306*7c478bd9Sstevel@tonic-gate fp->f_r -= n; 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate ret = 0; 310*7c478bd9Sstevel@tonic-gate clean: 311*7c478bd9Sstevel@tonic-gate /* We're back. So undo our timeout and handler */ 312*7c478bd9Sstevel@tonic-gate if (evt != NULL) 313*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); 314*7c478bd9Sstevel@tonic-gate return ret; 315*7c478bd9Sstevel@tonic-gate dumb: 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate ** We get here if we cannot optimise the seek ... just 318*7c478bd9Sstevel@tonic-gate ** do it. Allow the seek function to change fp->f_bf.smb_base. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* Note: SM_TIME_FOREVER since fn timeout already set */ 322*7c478bd9Sstevel@tonic-gate ret = SM_TIME_FOREVER; 323*7c478bd9Sstevel@tonic-gate if (sm_flush(fp, &ret) != 0 || 324*7c478bd9Sstevel@tonic-gate (*seekfn)(fp, (off_t) offset, whence) == POS_ERR) 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate ret = -1; 327*7c478bd9Sstevel@tonic-gate goto clean; 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* success: clear SMFEOF indicator and discard ungetc() data */ 331*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 332*7c478bd9Sstevel@tonic-gate FREEUB(fp); 333*7c478bd9Sstevel@tonic-gate fp->f_p = fp->f_bf.smb_base; 334*7c478bd9Sstevel@tonic-gate fp->f_r = 0; 335*7c478bd9Sstevel@tonic-gate fp->f_flags &= ~SMFEOF; 336*7c478bd9Sstevel@tonic-gate ret = 0; 337*7c478bd9Sstevel@tonic-gate goto clean; 338*7c478bd9Sstevel@tonic-gate } 339