/*
* Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#include "local.h"
/*
** SEEKALRM -- handler when timeout activated for sm_io_seek()
**
** Returns flow of control to where setjmp(SeekTimeOut) was set.
**
** Parameters:
** sig -- unused
**
** Returns:
** does not return
**
** Side Effects:
** returns flow of control to setjmp(SeekTimeOut).
**
** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
** DOING.
*/
/* ARGSUSED0 */
static void
int sig;
{
}
/*
** SM_IO_SEEK -- position the file pointer
**
** Parameters:
** fp -- the file pointer to be seek'd
** timeout -- time to complete seek (milliseconds)
** offset -- seek offset based on 'whence'
** whence -- indicates where seek is relative from.
** One of SM_IO_SEEK_{CUR,SET,END}.
** Returns:
** Failure: returns -1 (minus 1) and sets errno
** Success: returns 0 (zero)
*/
int
int SM_NONVOLATILE timeout;
long SM_NONVOLATILE offset;
int SM_NONVOLATILE whence;
{
bool havepos;
size_t n;
int ret;
/* make sure stdio is set up */
if (!Sm_IO_DidInit)
sm_init();
/* Have to be able to seek. */
{
return -1;
}
if (timeout == SM_TIME_DEFAULT)
if (timeout == SM_TIME_IMMEDIATE)
{
/*
** Filling the buffer will take time and we are wanted to
** return immediately. So...
*/
return -1;
}
#define SM_SET_ALARM() \
if (timeout != SM_TIME_FOREVER) \
{ \
if (setjmp(SeekTimeOut) != 0) \
{ \
return -1; \
} \
}
/*
** Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence'
** argument. After this, whence is either SM_IO_SEEK_SET or
** SM_IO_SEEK_END.
*/
switch (whence)
{
case SM_IO_SEEK_CUR:
/*
** In order to seek relative to the current stream offset,
** we have to first find the current stream offset a la
** ftell (see ftell for details).
*/
/* may adjust seek offset on append stream */
SM_SET_ALARM();
else
{
if (curoff == -1L)
{
ret = -1;
goto clean;
}
}
{
}
havepos = true;
break;
case SM_IO_SEEK_SET:
case SM_IO_SEEK_END:
SM_SET_ALARM();
curoff = 0; /* XXX just to keep gcc quiet */
havepos = false;
break;
default:
return -1;
}
/*
** Can only optimise if:
** reading (and not reading-and-writing);
** not unbuffered; and
** this is a `regular' Unix file (and hence seekfn==sm_stdseek).
** We must check SMNBF first, because it is possible to have SMNBF
** and SMSOPT both set.
*/
sm_makebuf(fp);
goto dumb;
{
if (seekfn != sm_stdseek ||
{
goto dumb;
}
}
/*
** We are reading; we can try to optimise.
** Figure out where we are going and where we are now.
*/
if (whence == SM_IO_SEEK_SET)
else
{
goto dumb;
}
if (!havepos)
{
else
{
goto dumb;
}
}
/*
** Compute the number of bytes in the input buffer (pretending
** that any ungetc() input has been discarded). Adjust current
** offset backwards by this count so that it represents the
** file offset for the first byte in the current input buffer.
*/
{
curoff -= n;
}
else
{
curoff -= n;
}
/*
** If the target offset is within the current buffer,
** simply adjust the pointers, clear SMFEOF, undo ungetc(),
** and return. (If the buffer was modified, we have to
** skip this; see getln in fget.c.)
*/
{
ret = 0;
goto clean;
}
/*
** The place we want to get to is not within the current buffer,
** but we can still be kind to the kernel copyout mechanism.
** By aligning the file offset to a block boundary, we can let
** the kernel use the VM hardware to map pages instead of
** copying bytes laboriously. Using a block boundary also
** ensures that we only read one block, rather than two.
*/
goto dumb;
if (n)
{
/* Note: SM_TIME_FOREVER since fn timeout already set */
goto dumb;
}
ret = 0;
/* We're back. So undo our timeout and handler */
return ret;
dumb:
/*
** We get here if we cannot optimise the seek ... just
** do it. Allow the seek function to change fp->f_bf.smb_base.
*/
/* Note: SM_TIME_FOREVER since fn timeout already set */
{
ret = -1;
goto clean;
}
/* success: clear SMFEOF indicator and discard ungetc() data */
ret = 0;
goto clean;
}