[project @ 1999-09-19 19:25:24 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / seekFile.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: seekFile.c,v 1.4 1999/09/19 19:25:24 sof Exp $
5  *
6  * hSeek and hIsSeekable Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 /* Invoked by IO.hSeek only */
21 StgInt
22 seekFile(ptr, whence, size, d)
23 StgForeignPtr ptr;
24 StgInt whence;
25 StgInt size;
26 StgByteArray d;
27 {
28     IOFileObject* fo = (IOFileObject*)ptr;
29     struct stat sb;
30     off_t offset;
31     int posn_delta =0;
32     int rc = 0;
33
34     switch (whence) {
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; /* Should never happen, really */
39     }
40
41     /*
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.
45      */
46
47     switch (size) {
48     case -1:
49         offset = -*(StgInt *) d;
50         break;
51     case 0:
52         offset = 0;
53         break;
54     case 1:
55         offset = *(StgInt *) d;
56         break;
57     default:
58         ghc_errtype = ERR_INVALIDARGUMENT;
59         ghc_errstr = "offset out of range";
60         return -1;
61     }
62
63     /* If we're doing a relative seek, see if we cannot deal 
64      * with the request without flushing the buffer..
65      *
66      * Note: the wording in the report is vague here, but 
67      * we only avoid flushing on *input* buffers and *not* output ones.
68      */
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;
74        return 0;
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
80             buffering.
81          */
82         posn_delta = fo->bufWPtr - fo->bufRPtr;  /* number of chars left in the buffer */
83         if (posn_delta < 0) posn_delta=0;
84     }
85
86     /* If we cannot seek within our current buffer, flush it. */
87     rc = flushBuffer(ptr);
88     if (rc < 0) return rc;
89
90     /* Try to find out the file type */
91     while (fstat(fo->fd, &sb) < 0) {
92         /* highly unlikely */
93         if (errno != EINTR) {
94             cvtErrno();
95             stdErrno();
96             return -1;
97         }
98     }
99     if (S_ISFIFO(sb.st_mode)) {
100         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
101         ghc_errstr = "can't seek on a pipe";
102         return -1;
103     }
104     while ( lseek(fo->fd, offset, whence) == -1) {
105         if (errno != EINTR) {
106             cvtErrno();
107             stdErrno();
108             return -1;
109         }
110     }
111     /* Clear EOF */
112     FILEOBJ_CLEAR_EOF(fo);
113     return 0;
114 }
115
116 /* Invoked by IO.hSeek only */
117 StgInt
118 seekFile_int64(ptr, whence, d)
119 StgForeignPtr ptr;
120 StgInt whence;
121 StgInt64 d;
122 {
123     IOFileObject* fo = (IOFileObject*)ptr;
124     struct stat sb;
125     off_t offset = d;
126     int posn_delta =0;
127     int rc = 0;
128
129     switch (whence) {
130      case 0: whence=SEEK_SET; break;
131      case 1: whence=SEEK_CUR; break;
132      case 2: whence=SEEK_END; break;
133      default: whence=SEEK_SET; break; /* Should never happen, really */
134     }
135
136     /* If we're doing a relative seek, see if we cannot deal 
137      * with the request without flushing the buffer..
138      *
139      * Note: the wording in the report is vague here, but 
140      * we only avoid flushing on *input* buffers and *not* output ones.
141      */
142     if ( whence == SEEK_CUR &&
143          (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) &&
144           (fo->bufRPtr + (int)offset) < fo->bufWPtr &&
145           (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */
146        fo->bufRPtr += (int)offset;
147        return 0;
148     } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) {
149          /* We're seeking outside the input buffer,
150             record delta so that we can adjust the file position
151             reported from the underlying fd to get
152             at the real position we're at when we take into account
153             buffering.
154          */
155         posn_delta = fo->bufWPtr - fo->bufRPtr;  /* number of chars left in the buffer */
156         if (posn_delta < 0) posn_delta=0;
157     }
158
159     /* If we cannot seek within our current buffer, flush it. */
160     rc = flushBuffer(ptr);
161     if (rc < 0) return rc;
162
163     /* Try to find out the file type & size for a physical file */
164     while (fstat(fo->fd, &sb) < 0) {
165         /* highly unlikely */
166         if (errno != EINTR) {
167             cvtErrno();
168             stdErrno();
169             return -1;
170         }
171     }
172     if (S_ISFIFO(sb.st_mode)) {
173         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
174         ghc_errstr = "can't seek on a pipe";
175         return -1;
176     }
177     while ( lseek(fo->fd, offset, whence) == -1) {
178         if (errno != EINTR) {
179             cvtErrno();
180             stdErrno();
181             return -1;
182         }
183     }
184     /* Clear EOF */
185     FILEOBJ_CLEAR_EOF(fo);
186     return 0;
187 }
188
189 StgInt
190 seekFileP(ptr)
191 StgForeignPtr ptr;
192 {
193     IOFileObject* fo = (IOFileObject*)ptr;
194     struct stat sb;
195
196     /* Try to find out the file type */
197     while (fstat(fo->fd, &sb) < 0) {
198         /* highly unlikely */
199         if (errno != EINTR) {
200             cvtErrno();
201             stdErrno();
202             return -1;
203         }
204     }
205     /* Pipes are not okay.. */
206     if (S_ISFIFO(sb.st_mode)) {
207         return 0;
208     } 
209     /* ..for now, everything else is */
210     else {
211         return 1;
212     }
213 }