% % (c) The GRASP/AQUA Project, Glasgow University, 1994 % \subsection[seekFile.lc]{hSeek and hIsSeekable Runtime Support} \begin{code} #include "rtsdefs.h" #include "stgio.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif StgInt seekFile(fp, whence, size, d) StgAddr fp; StgInt whence; StgInt size; StgByteArray d; { struct stat sb; long int offset; /* * We need to snatch the offset out of an MP_INT. The bits are there sans sign, * which we pick up from our size parameter. If abs(size) is greater than 1, * this integer is just too big. */ switch (size) { case -1: offset = -*(StgInt *) d; break; case 0: offset = 0; break; case 1: offset = *(StgInt *) d; break; default: ghc_errtype = ERR_INVALIDARGUMENT; ghc_errstr = "offset out of range"; return -1; } /* Try to find out the file type & size for a physical file */ while (fstat(fileno((FILE *) fp), &sb) < 0) { /* highly unlikely */ if (errno != EINTR) { cvtErrno(); stdErrno(); 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 (posn > sb.st_size) { ghc_errtype = ERR_INVALIDARGUMENT; ghc_errstr = "seek position beyond end of file"; return -1; } } else 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) { if (errno != EINTR) { cvtErrno(); stdErrno(); return -1; } } return 0; } StgInt seekFileP(fp) StgAddr fp; { struct stat sb; /* Try to find out the file type */ while (fstat(fileno((FILE *) fp), &sb) < 0) { /* highly unlikely */ if (errno != EINTR) { cvtErrno(); stdErrno(); return -1; } } /* Regular files are okay */ if (S_ISREG(sb.st_mode)) { return 1; } /* For now, everything else is not */ else { return 0; } } \end{code}