16f76187a391dfc3149a331eba482cde7db440b6
[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.6 2001/03/01 12:25:33 rrt 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(StgForeignPtr ptr, StgInt whence, StgInt size, StgByteArray d)
23 {
24     IOFileObject* fo = (IOFileObject*)ptr;
25     struct Stat sb;
26     off_t offset;
27     int posn_delta =0;
28     int rc = 0;
29
30     switch (whence) {
31      case 0:  whence=SEEK_SET; break;
32      case 1:  whence=SEEK_CUR; break;
33      case 2:  whence=SEEK_END; break;
34      default: whence=SEEK_SET; /* Should never happen, really */
35     }
36
37     /*
38      * We need to snatch the offset out of an MP_INT.  The bits are there sans sign,
39      * which we pick up from our size parameter.  If abs(size) is greater than 1,
40      * this integer is just too big.
41      */
42
43     switch (size) {
44     case -1:
45         offset = -*(StgInt *) d;
46         break;
47     case 0:
48         offset = 0;
49         break;
50     case 1:
51         offset = *(StgInt *) d;
52         break;
53     default:
54         ghc_errtype = ERR_INVALIDARGUMENT;
55         ghc_errstr = "offset out of range";
56         return -1;
57     }
58
59     /* If we're doing a relative seek, see if we cannot deal 
60      * with the request without flushing the buffer..
61      *
62      * Note: the wording in the report is vague here, but 
63      * we only avoid flushing on *input* buffers and *not* output ones.
64      */
65     if ( whence == SEEK_CUR &&
66          (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) &&
67           (fo->bufRPtr + (int)offset) < fo->bufWPtr &&
68           (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */
69        fo->bufRPtr += (int)offset;
70        return 0;
71     } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) {
72          /* We're seeking outside the input buffer,
73             record delta so that we can adjust the file position
74             reported from the underlying fd to get
75             at the real position we're at when we take into account
76             buffering.
77          */
78         posn_delta = fo->bufWPtr - fo->bufRPtr;  /* number of chars left in the buffer */
79         if (posn_delta < 0) posn_delta=0;
80     }
81
82     /* If we cannot seek within our current buffer, flush it. */
83     rc = flushBuffer(ptr);
84     if (rc < 0) return rc;
85
86     /* Try to find out the file type */
87     while (Fstat(fo->fd, &sb) < 0) {
88         /* highly unlikely */
89         if (errno != EINTR) {
90             cvtErrno();
91             stdErrno();
92             return -1;
93         }
94     }
95     if (S_ISFIFO(sb.st_mode)) {
96         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
97         ghc_errstr = "can't seek on a pipe";
98         return -1;
99     }
100     while ( lseek(fo->fd, offset-posn_delta, whence) == -1) {
101         if (errno != EINTR) {
102             cvtErrno();
103             stdErrno();
104             return -1;
105         }
106     }
107     /* Clear EOF */
108     FILEOBJ_CLEAR_EOF(fo);
109     return 0;
110 }
111
112 /* Invoked by IO.hSeek only */
113 StgInt
114 seekFile_int64(StgForeignPtr ptr, StgInt whence, StgInt64 d)
115 {
116     IOFileObject* fo = (IOFileObject*)ptr;
117     struct Stat sb;
118     off_t offset = d;
119     int posn_delta =0;
120     int rc = 0;
121
122     switch (whence) {
123      case 0: whence=SEEK_SET; break;
124      case 1: whence=SEEK_CUR; break;
125      case 2: whence=SEEK_END; break;
126      default: whence=SEEK_SET; break; /* Should never happen, really */
127     }
128
129     /* If we're doing a relative seek, see if we cannot deal 
130      * with the request without flushing the buffer..
131      *
132      * Note: the wording in the report is vague here, but 
133      * we only avoid flushing on *input* buffers and *not* output ones.
134      */
135     if ( whence == SEEK_CUR &&
136          (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo) &&
137           (fo->bufRPtr + (int)offset) < fo->bufWPtr &&
138           (fo->bufRPtr + (int)offset) >= 0) ) { /* The input buffer case */
139        fo->bufRPtr += (int)offset;
140        return 0;
141     } else if ( whence == SEEK_CUR && (FILEOBJ_READABLE(fo) && !FILEOBJ_WRITEABLE(fo)) ) {
142          /* We're seeking outside the input buffer,
143             record delta so that we can adjust the file position
144             reported from the underlying fd to get
145             at the real position we're at when we take into account
146             buffering.
147          */
148         posn_delta = fo->bufWPtr - fo->bufRPtr;  /* number of chars left in the buffer */
149         if (posn_delta < 0) posn_delta=0;
150     }
151
152     /* If we cannot seek within our current buffer, flush it. */
153     rc = flushBuffer(ptr);
154     if (rc < 0) return rc;
155
156     /* Try to find out the file type & size for a physical file */
157     while (Fstat(fo->fd, &sb) < 0) {
158         /* highly unlikely */
159         if (errno != EINTR) {
160             cvtErrno();
161             stdErrno();
162             return -1;
163         }
164     }
165     if (S_ISFIFO(sb.st_mode)) {
166         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
167         ghc_errstr = "can't seek on a pipe";
168         return -1;
169     }
170     while ( lseek(fo->fd, offset-posn_delta, whence) == -1) {
171         if (errno != EINTR) {
172             cvtErrno();
173             stdErrno();
174             return -1;
175         }
176     }
177     /* Clear EOF */
178     FILEOBJ_CLEAR_EOF(fo);
179     return 0;
180 }
181
182 StgInt
183 seekFileP(StgForeignPtr ptr)
184 {
185     IOFileObject* fo = (IOFileObject*)ptr;
186     struct Stat sb;
187
188     /* Try to find out the file type */
189     while (Fstat(fo->fd, &sb) < 0) {
190         /* highly unlikely */
191         if (errno != EINTR) {
192             cvtErrno();
193             stdErrno();
194             return -1;
195         }
196     }
197     /* Pipes are not okay.. */
198     if (S_ISFIFO(sb.st_mode)) {
199         return 0;
200     } 
201     /* ..for now, everything else is */
202     else {
203         return 1;
204     }
205 }