Add Windows version info resource.
[obnox/wireshark/wip.git] / wiretap / file_wrappers.c
1 /* file_wrappers.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 /*
28  * Do this now, to get close() defined, before we muck with the definition
29  * of HAVE_UNISTD_H.  See below for the full sad story of why we do that.
30  */
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34
35 /*
36  * OK, now this is tricky.
37  *
38  * At least on FreeBSD 3.2, "/usr/include/zlib.h" includes
39  * "/usr/include/zconf.h", which, if HAVE_UNISTD_H is defined,
40  * #defines "z_off_t" to be "off_t", and if HAVE_UNISTD_H is
41  * not defined, #defines "z_off_t" to be "long" if it's not
42  * already #defined.
43  *
44  * In 4.4-Lite-derived systems such as FreeBSD, "off_t" is
45  * "long long int", not "long int", so the definition of "z_off_t" -
46  * and therefore the types of the arguments to routines such as
47  * "gzseek()", as declared, with prototypes, in "zlib.h" - depends
48  * on whether HAVE_UNISTD_H is defined prior to including "zlib.h"!
49  *
50  * It's not defined in the FreeBSD 3.2 "zlib", so if we include "zlib.h"
51  * after defining HAVE_UNISTD_H, we get a misdeclaration of "gzseek()",
52  * and, if we're building with "zlib" support, anything that seeks
53  * on a file may not work.
54  *
55  * Other BSDs may have the same problem, if they haven't done something
56  * such as defining HAVE_UNISTD_H in "zconf.h".
57  *
58  * "config.h" defines HAVE_UNISTD_H, on all systems that have it, and all
59  * 4.4-Lite-derived BSDs have it.  Therefore, given that "zlib.h" is included
60  * by "file_wrappers.h", that means that unless we include "zlib.h" before
61  * we include "config.h", we get a misdeclaration of "gzseek()".
62  *
63  * Unfortunately, it's "config.h" that tells us whether we have "zlib"
64  * in the first place, so we don't know whether to include "zlib.h"
65  * until we include "config.h"....
66  *
67  * A similar problem appears to occur with "gztell()", at least on
68  * NetBSD.
69  *
70  * To add further complication, on recent versions, at least, of OpenBSD,
71  * the Makefile for zlib defines HAVE_UNISTD_H.
72  *
73  * So what we do is, on all OSes other than OpenBSD, *undefine* HAVE_UNISTD_H
74  * before including "wtap-int.h" (it handles including "zlib.h" if HAVE_ZLIB
75  * is defined, and it includes "wtap.h", which we include to get the
76  * WTAP_ERR_ZLIB values), and, if we have zlib, make "file_seek()" and
77  * "file_tell()" subroutines, so that the only calls to "gzseek()" and
78  * "gztell()" are in this file, which, by dint of the hackery described
79  * above, manages to correctly declare "gzseek()" and "gztell()".
80  *
81  * On OpenBSD, we forcibly *define* HAVE_UNISTD_H if it's not defined.
82  *
83  * Hopefully, the BSDs will, over time, remove the test for HAVE_UNISTD_H
84  * from "zconf.h", so that "gzseek()" and "gztell()" will be declared
85  * with the correct signature regardless of whether HAVE_UNISTD_H is
86  * defined, so that if they change the signature we don't have to worry
87  * about making sure it's defined or not defined.
88  *
89  * DO NOT, UNDER ANY CIRCUMSTANCES, REMOVE THE FOLLOWING LINES, OR MOVE
90  * THEM AFTER THE INCLUDE OF "wtap-int.h"!  Doing so will cause any program
91  * using Wiretap to read capture files to fail miserably on a FreeBSD
92  * 3.2 or 3.3 system - and possibly some other BSD systems - if zlib is
93  * installed.  If you *must* have HAVE_UNISTD_H defined before including
94  * "wtap-int.h", put "file_error()" into a file by itself, which can
95  * cheerfully include "wtap.h" and get "gzseek()" misdeclared, and include
96  * just "zlib.h" in this file - *after* undefining HAVE_UNISTD_H.
97  */
98 #ifdef __OpenBSD__
99 #ifndef HAVE_UNISTD_H
100 #define HAVE_UNISTD_H
101 #endif /* HAVE_UNISTD_H */
102 #else /* __OpenBSD__ */
103 #undef HAVE_UNISTD_H
104 #endif /* __OpenBSD__ */
105
106 #include <errno.h>
107 #include <stdio.h>
108 #ifdef HAVE_LIBZ
109 #ifdef HAVE_FCNTL_H
110 #include <fcntl.h>
111 #endif /* HAVE_FCNTL_H */
112 #include <string.h>
113 #endif /* HAVE_LIBZ */
114 #include "wtap-int.h"
115 #include "file_wrappers.h"
116 #include "file_util.h"
117
118
119 #ifdef HAVE_LIBZ
120
121 FILE_T
122 file_open(const char *path, const char *mode)
123 {
124         int fd;
125         FILE_T ft;
126         int oflag;
127
128         if (*mode == 'r') {
129                 if (strchr(mode + 1, '+') != NULL)
130                         oflag = O_RDWR;
131                 else
132                         oflag = O_RDONLY;
133         } else if (*mode == 'w') {
134                 if (strchr(mode + 1, '+') != NULL)
135                         oflag = O_RDWR|O_CREAT|O_TRUNC;
136                 else
137                         oflag = O_RDONLY|O_CREAT|O_TRUNC;
138         } else if (*mode == 'a') {
139                 if (strchr(mode + 1, '+') != NULL)
140                         oflag = O_RDWR|O_APPEND;
141                 else
142                         oflag = O_RDONLY|O_APPEND;
143         } else {
144                 errno = EINVAL;
145                 return NULL;
146         }
147 #ifdef _WIN32
148         if (strchr(mode + 1, 'b') != NULL)
149                 oflag |= O_BINARY;
150 #endif
151         /* open file and do correct filename conversions */
152         if ((fd = eth_open(path, oflag, 0666)) == -1)
153                 return NULL;
154
155         /* open zlib file handle */
156         ft = gzdopen(fd, mode);
157         if (ft == NULL) {
158                 eth_close(fd);
159                 return NULL;
160         }
161
162         return ft;
163 }
164
165 gint64
166 file_seek(void *stream, gint64 offset, int whence, int *err)
167 {
168         gint64 ret;
169
170         /* XXX - z_off_t is usually long, won't work >= 2GB! */
171         ret = (gint64) gzseek(stream, (z_off_t)offset, whence);
172         if (ret == -1) {
173                 /*
174                  * XXX - "gzseek()", as of zlib 1.1.4, doesn't set
175                  * "z_err" for the stream, so "gzerror()" could return
176                  * a bogus Z_OK.
177                  *
178                  * As this call failed, we know "gzerror()" shouldn't
179                  * return Z_OK; if it does, we assume that "errno" is
180                  * the real error.
181                  */
182                 *err = file_error(stream);
183                 if (*err == 0)
184                         *err = errno;
185         }
186         return ret;
187 }
188
189 gint64
190 file_tell(void *stream)
191 {
192         /* XXX - z_off_t is usually long, won't work >= 2GB! */
193         return (gint64)gztell(stream);
194 }
195
196 /*
197  * Routine to return a Wiretap error code (0 for no error, an errno
198  * for a file error, or a WTAP_ERR_ code for other errors) for an
199  * I/O stream.
200  */
201 int
202 file_error(void *fh)
203 {
204         int errnum;
205
206         gzerror(fh, &errnum);
207         switch (errnum) {
208
209         case Z_OK:              /* no error */
210                 return 0;
211
212         case Z_STREAM_END:      /* EOF - not an error */
213                 return 0;
214
215         case Z_ERRNO:           /* file I/O error */
216                 return errno;
217
218         default:
219                 return WTAP_ERR_ZLIB + errnum;
220         }
221 }
222
223 #else /* HAVE_LIBZ */
224
225 gint64
226 file_seek(void *stream, gint64 offset, int whence, int *err)
227 {
228         gint64 ret;
229 #ifdef _WIN32
230         gint64 pos;
231 #endif
232
233 #ifdef _WIN32
234         /* Win32 version using fsetpos/fgetpos */
235         /* XXX - using fsetpos/fgetpos this way is UNDOCUMENTED, but I don't see a any better way :-( */
236         /* _lseeki64(_fileno(stream)) doesn't work as this will mangle the internal FILE handling data */
237         switch(whence) {
238         case(SEEK_SET):
239             /* do nothing */
240             break;
241         case(SEEK_CUR):
242             /* adjust offset */
243             /* XXX - CURRENTLY UNTESTED!!! */
244             ret = fgetpos(stream, &pos);
245             if(ret != 0) {
246                 *err = errno;
247                 return ret;
248             }
249             offset += pos;
250             break;
251         case(SEEK_END):
252         default:
253             g_assert_not_reached();
254         }
255         ret = fsetpos(stream, &offset);
256         if(ret != 0) {
257                 *err = errno;
258         }
259         /* XXX - won't work >= 2GB! */
260         /*ret = (gint64) fseek(stream, (long) offset, whence);
261         if(ret == -1) {
262                 *err = errno;
263         }*/
264 #else
265         /* "basic" version using fseek */
266         /* XXX - won't work >= 2GB! */
267         ret = (gint64) fseek(stream, (long) offset, whence);
268         if (ret == -1)
269                 *err = file_error(stream);
270 #endif
271         /*g_warning("Seek %lld whence %u ret %lld size %u", offset, whence, ret, sizeof(fpos_t));*/
272         return ret;
273 }
274
275 gint64
276 file_tell(void *stream)
277 {
278 #ifdef _WIN32
279         /* Win32 version using _telli64 */
280         /* XXX - CURRENTLY UNTESTED!!! */
281         return _telli64(_fileno((FILE *)stream));
282 #else
283         /* "basic" version using ftell */
284         /* XXX - ftell returns a long - won't work >= 2GB! */
285         return (gint64) ftell(stream);
286 #endif
287 }
288
289 int
290 file_error(void *fh)
291 {
292         if (ferror((FILE *) fh))
293                 return errno;
294         else
295                 return 0;
296 }
297
298 #endif /* HAVE_LIBZ */