2 * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
4 * $Id: seekFile.c,v 1.3 1998/12/02 13:27:53 simonm Exp $
6 * hSeek and hIsSeekable Runtime Support
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
16 #ifdef HAVE_SYS_STAT_H
20 /* Invoked by IO.hSeek only */
22 seekFile(ptr, whence, size, d)
28 IOFileObject* fo = (IOFileObject*)ptr;
35 case 0: whence=SEEK_SET; break;
36 case 1: whence=SEEK_CUR; break;
37 case 2: whence=SEEK_END; break;
38 default: whence=SEEK_SET; break; /* Should never happen, really */
42 * We need to snatch the offset out of an MP_INT. The bits are there sans sign,
43 * which we pick up from our size parameter. If abs(size) is greater than 1,
44 * this integer is just too big.
49 offset = -*(StgInt *) d;
55 offset = *(StgInt *) d;
58 ghc_errtype = ERR_INVALIDARGUMENT;
59 ghc_errstr = "offset out of range";
63 /* If we're doing a relative seek, see if we cannot deal
64 * with the request without flushing the buffer..
66 * Note: the wording in the report is vague here, but
67 * we only avoid flushing on *input* buffers and *not* output ones.
69 if ( whence == SEEK_CUR &&
70 (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) &&
71 (fo->bufRPtr + (int)offset) < fo->bufWPtr &&
72 (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */
73 fo->bufRPtr += (int)offset;
75 } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) {
76 /* We're seeking outside the input buffer,
77 record delta so that we can adjust the file position
78 reported from the underlying fd to get
79 at the real position we're at when we take into account
82 posn_delta = fo->bufWPtr - fo->bufRPtr; /* number of chars left in the buffer */
83 if (posn_delta < 0) posn_delta=0;
86 /* If we cannot seek within our current buffer, flush it. */
87 rc = flushBuffer(ptr);
88 if (rc < 0) return rc;
90 /* Try to find out the file type & size for a physical file */
91 while (fstat(fo->fd, &sb) < 0) {
99 if (S_ISREG(sb.st_mode)) {
100 /* Verify that we are not seeking beyond end-of-file */
108 while ((posn = lseek(fo->fd, 0, SEEK_CUR)) == -1) {
109 /* the possibility seems awfully remote */
110 if (errno != EINTR) {
118 offset -= posn_delta; /* adjust the offset to include the buffer delta */
121 posn = (off_t)sb.st_size + offset;
124 if (posn > sb.st_size) {
125 ghc_errtype = ERR_INVALIDARGUMENT;
126 ghc_errstr = "seek position beyond end of file";
129 } else if (S_ISFIFO(sb.st_mode)) {
130 ghc_errtype = ERR_UNSUPPORTEDOPERATION;
131 ghc_errstr = "can't seek on a pipe";
134 ghc_errtype = ERR_UNSUPPORTEDOPERATION;
135 ghc_errstr = "can't seek on a device";
138 while ( lseek(fo->fd, offset, whence) == -1) {
139 if (errno != EINTR) {
146 FILEOBJ_CLEAR_EOF(fo);
150 /* Invoked by IO.hSeek only */
152 seekFile_int64(ptr, whence, d)
157 IOFileObject* fo = (IOFileObject*)ptr;
164 case 0: whence=SEEK_SET; break;
165 case 1: whence=SEEK_CUR; break;
166 case 2: whence=SEEK_END; break;
167 default: whence=SEEK_SET; break; /* Should never happen, really */
170 /* If we're doing a relative seek, see if we cannot deal
171 * with the request without flushing the buffer..
173 * Note: the wording in the report is vague here, but
174 * we only avoid flushing on *input* buffers and *not* output ones.
176 if ( whence == SEEK_CUR &&
177 (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) &&
178 (fo->bufRPtr + (int)offset) < fo->bufWPtr &&
179 (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */
180 fo->bufRPtr += (int)offset;
182 } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) {
183 /* We're seeking outside the input buffer,
184 record delta so that we can adjust the file position
185 reported from the underlying fd to get
186 at the real position we're at when we take into account
189 posn_delta = fo->bufWPtr - fo->bufRPtr; /* number of chars left in the buffer */
190 if (posn_delta < 0) posn_delta=0;
193 /* If we cannot seek within our current buffer, flush it. */
194 rc = flushBuffer(ptr);
195 if (rc < 0) return rc;
197 /* Try to find out the file type & size for a physical file */
198 while (fstat(fo->fd, &sb) < 0) {
199 /* highly unlikely */
200 if (errno != EINTR) {
206 if (S_ISREG(sb.st_mode)) {
207 /* Verify that we are not seeking beyond end-of-file */
215 while ((posn = lseek(fo->fd, 0, SEEK_CUR)) == -1) {
216 /* the possibility seems awfully remote */
217 if (errno != EINTR) {
225 offset -= posn_delta; /* adjust the offset to include the buffer delta */
228 posn = (off_t)sb.st_size + offset;
231 if (posn > sb.st_size) {
232 ghc_errtype = ERR_INVALIDARGUMENT;
233 ghc_errstr = "seek position beyond end of file";
236 } else if (S_ISFIFO(sb.st_mode)) {
237 ghc_errtype = ERR_UNSUPPORTEDOPERATION;
238 ghc_errstr = "can't seek on a pipe";
241 ghc_errtype = ERR_UNSUPPORTEDOPERATION;
242 ghc_errstr = "can't seek on a device";
245 while ( lseek(fo->fd, offset, whence) == -1) {
246 if (errno != EINTR) {
253 FILEOBJ_CLEAR_EOF(fo);
261 IOFileObject* fo = (IOFileObject*)ptr;
264 /* Try to find out the file type */
265 while (fstat(fo->fd, &sb) < 0) {
266 /* highly unlikely */
267 if (errno != EINTR) {
273 /* Regular files are okay */
274 if (S_ISREG(sb.st_mode)) {
277 /* For now, everything else is not */