X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Flib%2Fstd%2Fcbits%2FseekFile.c;h=91934844cc1f638992330b1fe60878035672177c;hb=b458760b18ca7d3e1e913eefbf8478eac34afb99;hp=2946fe2e630203151a3ee821d592b09c73e0828e;hpb=3f9b5688990aa7c1170c8d995df69087b43dabeb;p=ghc-hetmet.git diff --git a/ghc/lib/std/cbits/seekFile.c b/ghc/lib/std/cbits/seekFile.c index 2946fe2..9193484 100644 --- a/ghc/lib/std/cbits/seekFile.c +++ b/ghc/lib/std/cbits/seekFile.c @@ -1,7 +1,7 @@ /* * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998 * - * $Id: seekFile.c,v 1.1 1998/04/10 10:54:49 simonm Exp $ + * $Id: seekFile.c,v 1.5 2000/01/17 12:30:07 simonmar Exp $ * * hSeek and hIsSeekable Runtime Support */ @@ -17,11 +17,22 @@ #include #endif +/* Invoked by IO.hSeek only */ StgInt -seekFile(StgAddr fp, StgInt whence, StgInt size, StgByteArray d) +seekFile(StgForeignPtr ptr, StgInt whence, StgInt size, StgByteArray d) { + IOFileObject* fo = (IOFileObject*)ptr; struct stat sb; - long int offset; + off_t offset; + int posn_delta =0; + int rc = 0; + + switch (whence) { + case 0: whence=SEEK_SET; break; + case 1: whence=SEEK_CUR; break; + case 2: whence=SEEK_END; break; + default: whence=SEEK_SET; /* Should never happen, really */ + } /* * We need to snatch the offset out of an MP_INT. The bits are there sans sign, @@ -45,8 +56,35 @@ seekFile(StgAddr fp, StgInt whence, StgInt size, StgByteArray d) return -1; } - /* Try to find out the file type & size for a physical file */ - while (fstat(fileno((FILE *) fp), &sb) < 0) { + /* If we're doing a relative seek, see if we cannot deal + * with the request without flushing the buffer.. + * + * Note: the wording in the report is vague here, but + * we only avoid flushing on *input* buffers and *not* output ones. + */ + if ( whence == SEEK_CUR && + (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) && + (fo->bufRPtr + (int)offset) < fo->bufWPtr && + (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */ + fo->bufRPtr += (int)offset; + return 0; + } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) { + /* We're seeking outside the input buffer, + record delta so that we can adjust the file position + reported from the underlying fd to get + at the real position we're at when we take into account + buffering. + */ + posn_delta = fo->bufWPtr - fo->bufRPtr; /* number of chars left in the buffer */ + if (posn_delta < 0) posn_delta=0; + } + + /* If we cannot seek within our current buffer, flush it. */ + rc = flushBuffer(ptr); + if (rc < 0) return rc; + + /* Try to find out the file type */ + while (fstat(fo->fd, &sb) < 0) { /* highly unlikely */ if (errno != EINTR) { cvtErrno(); @@ -54,60 +92,101 @@ seekFile(StgAddr fp, StgInt whence, StgInt size, StgByteArray d) return -1; } } - if (S_ISREG(sb.st_mode)) { - /* Verify that we are not seeking beyond end-of-file */ - int posn; - - switch (whence) { - case SEEK_SET: - posn = offset; - break; - case SEEK_CUR: - while ((posn = ftell((FILE *) fp)) == -1) { - /* the possibility seems awfully remote */ - if (errno != EINTR) { - cvtErrno(); - stdErrno(); - return -1; - } - } - posn += offset; - break; - case SEEK_END: - posn = sb.st_size + offset; - break; + if (S_ISFIFO(sb.st_mode)) { + ghc_errtype = ERR_UNSUPPORTEDOPERATION; + ghc_errstr = "can't seek on a pipe"; + return -1; + } + while ( lseek(fo->fd, offset-posn_delta, whence) == -1) { + if (errno != EINTR) { + cvtErrno(); + stdErrno(); + return -1; } - if (posn > sb.st_size) { - ghc_errtype = ERR_INVALIDARGUMENT; - ghc_errstr = "seek position beyond end of file"; + } + /* Clear EOF */ + FILEOBJ_CLEAR_EOF(fo); + return 0; +} + +/* Invoked by IO.hSeek only */ +StgInt +seekFile_int64(StgForeignPtr ptr, StgInt whence, StgInt64 d) +{ + IOFileObject* fo = (IOFileObject*)ptr; + struct stat sb; + off_t offset = d; + int posn_delta =0; + int rc = 0; + + switch (whence) { + case 0: whence=SEEK_SET; break; + case 1: whence=SEEK_CUR; break; + case 2: whence=SEEK_END; break; + default: whence=SEEK_SET; break; /* Should never happen, really */ + } + + /* If we're doing a relative seek, see if we cannot deal + * with the request without flushing the buffer.. + * + * Note: the wording in the report is vague here, but + * we only avoid flushing on *input* buffers and *not* output ones. + */ + if ( whence == SEEK_CUR && + (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) && + (fo->bufRPtr + (int)offset) < fo->bufWPtr && + (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */ + fo->bufRPtr += (int)offset; + return 0; + } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) { + /* We're seeking outside the input buffer, + record delta so that we can adjust the file position + reported from the underlying fd to get + at the real position we're at when we take into account + buffering. + */ + posn_delta = fo->bufWPtr - fo->bufRPtr; /* number of chars left in the buffer */ + if (posn_delta < 0) posn_delta=0; + } + + /* If we cannot seek within our current buffer, flush it. */ + rc = flushBuffer(ptr); + if (rc < 0) return rc; + + /* Try to find out the file type & size for a physical file */ + while (fstat(fo->fd, &sb) < 0) { + /* highly unlikely */ + if (errno != EINTR) { + cvtErrno(); + stdErrno(); return -1; } - } else if (S_ISFIFO(sb.st_mode)) { + } + if (S_ISFIFO(sb.st_mode)) { ghc_errtype = ERR_UNSUPPORTEDOPERATION; ghc_errstr = "can't seek on a pipe"; return -1; - } else { - ghc_errtype = ERR_UNSUPPORTEDOPERATION; - ghc_errstr = "can't seek on a device"; - return -1; } - while (fseek((FILE *) fp, offset, whence) != 0) { + while ( lseek(fo->fd, offset-posn_delta, whence) == -1) { if (errno != EINTR) { cvtErrno(); stdErrno(); return -1; } } + /* Clear EOF */ + FILEOBJ_CLEAR_EOF(fo); return 0; } StgInt -seekFileP(StgAddr fp) +seekFileP(StgForeignPtr ptr) { + IOFileObject* fo = (IOFileObject*)ptr; struct stat sb; /* Try to find out the file type */ - while (fstat(fileno((FILE *) fp), &sb) < 0) { + while (fstat(fo->fd, &sb) < 0) { /* highly unlikely */ if (errno != EINTR) { cvtErrno(); @@ -115,12 +194,12 @@ seekFileP(StgAddr fp) return -1; } } - /* Regular files are okay */ - if (S_ISREG(sb.st_mode)) { - return 1; + /* Pipes are not okay.. */ + if (S_ISFIFO(sb.st_mode)) { + return 0; } - /* For now, everything else is not */ + /* ..for now, everything else is */ else { - return 0; + return 1; } }