[project @ 1998-04-10 10:54:14 by simonm]
[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.1 1998/04/10 10:54:49 simonm 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 StgInt
21 seekFile(StgAddr fp, StgInt whence, StgInt size, StgByteArray d)
22 {
23     struct stat sb;
24     long int offset;
25
26     /*
27      * We need to snatch the offset out of an MP_INT.  The bits are there sans sign,
28      * which we pick up from our size parameter.  If abs(size) is greater than 1,
29      * this integer is just too big.
30      */
31
32     switch (size) {
33     case -1:
34         offset = -*(StgInt *) d;
35         break;
36     case 0:
37         offset = 0;
38         break;
39     case 1:
40         offset = *(StgInt *) d;
41         break;
42     default:
43         ghc_errtype = ERR_INVALIDARGUMENT;
44         ghc_errstr = "offset out of range";
45         return -1;
46     }
47
48     /* Try to find out the file type & size for a physical file */
49     while (fstat(fileno((FILE *) fp), &sb) < 0) {
50         /* highly unlikely */
51         if (errno != EINTR) {
52             cvtErrno();
53             stdErrno();
54             return -1;
55         }
56     }
57     if (S_ISREG(sb.st_mode)) {
58         /* Verify that we are not seeking beyond end-of-file */
59         int posn;
60
61         switch (whence) {
62         case SEEK_SET:
63             posn = offset;
64             break;
65         case SEEK_CUR:
66             while ((posn = ftell((FILE *) fp)) == -1) {
67                 /* the possibility seems awfully remote */
68                 if (errno != EINTR) {
69                     cvtErrno();
70                     stdErrno();
71                     return -1;
72                 }
73             }
74             posn += offset;
75             break;
76         case SEEK_END:
77             posn = sb.st_size + offset;
78             break;
79         }
80         if (posn > sb.st_size) {
81             ghc_errtype = ERR_INVALIDARGUMENT;
82             ghc_errstr = "seek position beyond end of file";
83             return -1;
84         }
85     } else if (S_ISFIFO(sb.st_mode)) {
86         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
87         ghc_errstr = "can't seek on a pipe";
88         return -1;
89     } else {
90         ghc_errtype = ERR_UNSUPPORTEDOPERATION;
91         ghc_errstr = "can't seek on a device";
92         return -1;
93     }
94     while (fseek((FILE *) fp, offset, whence) != 0) {
95         if (errno != EINTR) {
96             cvtErrno();
97             stdErrno();
98             return -1;
99         }
100     }
101     return 0;
102 }
103
104 StgInt
105 seekFileP(StgAddr fp)
106 {
107     struct stat sb;
108
109     /* Try to find out the file type */
110     while (fstat(fileno((FILE *) fp), &sb) < 0) {
111         /* highly unlikely */
112         if (errno != EINTR) {
113             cvtErrno();
114             stdErrno();
115             return -1;
116         }
117     }
118     /* Regular files are okay */
119     if (S_ISREG(sb.st_mode)) {
120         return 1;
121     } 
122     /* For now, everything else is not */
123     else {
124         return 0;
125     }
126 }