Define fstat() for msvc build
[platform/upstream/glib.git] / glib / gmappedfile.c
1 /* GLIB - Library of useful routines for C programming
2  * gmappedfile.c: Simplified wrapper around the mmap() function.
3  *
4  * Copyright 2005 Matthias Clasen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include <errno.h>
25 #include <sys/types.h> 
26 #include <sys/stat.h> 
27 #include <fcntl.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_MMAP
32 #include <sys/mman.h>
33 #endif
34
35 #include "glibconfig.h"
36
37 #ifdef G_OS_WIN32
38 #include <windows.h>
39 #include <io.h>
40
41 #ifdef _MSC_VER
42 #define fstat(a,b) _fstat(a,b)
43 #endif
44
45 #endif
46
47 #include "gconvert.h"
48 #include "gerror.h"
49 #include "gfileutils.h"
50 #include "gmappedfile.h"
51 #include "gmem.h"
52 #include "gmessages.h"
53 #include "gstdio.h"
54 #include "gstrfuncs.h"
55
56 #include "glibintl.h"
57
58 #include "galias.h"
59
60 #ifndef _O_BINARY
61 #define _O_BINARY 0
62 #endif
63
64 #ifndef MAP_FAILED
65 #define MAP_FAILED ((void *) -1)
66 #endif
67
68 struct _GMappedFile 
69 {
70   gsize  length;
71   gchar *contents;
72 #ifdef G_OS_WIN32
73   HANDLE mapping;
74 #endif
75 };
76
77 /**
78  * g_mapped_file_new:
79  * @filename: The path of the file to load, in the GLib filename encoding
80  * @writable: whether the mapping should be writable
81  * @error: return location for a #GError, or %NULL
82  *
83  * Maps a file into memory. On UNIX, this is using the mmap() function.
84  *
85  * If @writable is %TRUE, the mapped buffer may be modified, otherwise
86  * it is an error to modify the mapped buffer. Modifications to the buffer 
87  * are not visible to other processes mapping the same file, and are not 
88  * written back to the file.
89  *
90  * Note that modifications of the underlying file might affect the contents
91  * of the #GMappedFile. Therefore, mapping should only be used if the file 
92  * will not be modified, or if all modifications of the file are done
93  * atomically (e.g. using g_file_set_contents()). 
94  *
95  * Return value: a newly allocated #GMappedFile which must be freed
96  *    with g_mapped_file_free(), or %NULL if the mapping failed. 
97  *
98  * Since: 2.8
99  */
100 GMappedFile *
101 g_mapped_file_new (const gchar  *filename,
102                    gboolean      writable,
103                    GError      **error)
104 {
105   GMappedFile *file;
106   int fd;
107   struct stat st;
108
109   g_return_val_if_fail (filename != NULL, NULL);
110   g_return_val_if_fail (!error || *error == NULL, NULL);
111
112   fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
113   if (fd == -1)
114     {
115       int save_errno = errno;
116       gchar *display_filename = g_filename_display_name (filename);
117       
118       g_set_error (error,
119                    G_FILE_ERROR,
120                    g_file_error_from_errno (save_errno),
121                    _("Failed to open file '%s': open() failed: %s"),
122                    display_filename, 
123                    g_strerror (save_errno));
124       g_free (display_filename);
125       return NULL;
126     }
127
128   file = g_new0 (GMappedFile, 1);
129
130   if (fstat (fd, &st) == -1)
131     {
132       int save_errno = errno;
133       gchar *display_filename = g_filename_display_name (filename);
134
135       g_set_error (error,
136                    G_FILE_ERROR,
137                    g_file_error_from_errno (save_errno),
138                    _("Failed to get attributes of file '%s': fstat() failed: %s"),
139                    display_filename, 
140                    g_strerror (save_errno));
141       g_free (display_filename);
142       goto out;
143     }
144
145   if (st.st_size == 0)
146     {
147       file->length = 0;
148       file->contents = "";
149       close (fd);
150       return file;
151     }
152
153   file->contents = MAP_FAILED;
154
155 #ifdef HAVE_MMAP
156   if (st.st_size > G_MAXSIZE)
157     {
158       errno = EINVAL;
159     }
160   else
161     {      
162       file->length = (gsize) st.st_size;
163       file->contents = (gchar *) mmap (NULL,  file->length,
164                                        writable ? PROT_READ|PROT_WRITE : PROT_READ,
165                                        MAP_PRIVATE, fd, 0);
166     }
167 #endif
168 #ifdef G_OS_WIN32
169   file->length = st.st_size;
170   file->mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL,
171                                      writable ? PAGE_WRITECOPY : PAGE_READONLY,
172                                      0, 0,
173                                      NULL);
174   if (file->mapping != NULL)
175     {
176       file->contents = MapViewOfFile (file->mapping,
177                                       writable ? FILE_MAP_COPY : FILE_MAP_READ,
178                                       0, 0,
179                                       0);
180       if (file->contents == NULL)
181         {
182           file->contents = MAP_FAILED;
183           CloseHandle (file->mapping);
184           file->mapping = NULL;
185         }
186     }
187 #endif
188
189   
190   if (file->contents == MAP_FAILED)
191     {
192       int save_errno = errno;
193       gchar *display_filename = g_filename_display_name (filename);
194       
195       g_set_error (error,
196                    G_FILE_ERROR,
197                    g_file_error_from_errno (save_errno),
198                    _("Failed to map file '%s': mmap() failed: %s"),
199                    display_filename,
200                    g_strerror (save_errno));
201       g_free (display_filename);
202       goto out;
203     }
204
205   close (fd);
206   return file;
207
208  out:
209   close (fd);
210   g_free (file);
211
212   return NULL;
213 }
214
215 /**
216  * g_mapped_file_get_length:
217  * @file: a #GMappedFile
218  *
219  * Returns the length of the contents of a #GMappedFile.
220  *
221  * Returns: the length of the contents of @file.
222  *
223  * Since: 2.8
224  */
225 gsize
226 g_mapped_file_get_length (GMappedFile *file)
227 {
228   g_return_val_if_fail (file != NULL, 0);
229
230   return file->length;
231 }
232
233 /**
234  * g_mapped_file_get_contents:
235  * @file: a #GMappedFile
236  *
237  * Returns the contents of a #GMappedFile. 
238  *
239  * Note that the contents may not be zero-terminated,
240  * even if the #GMappedFile is backed by a text file.
241  *
242  * Returns: the contents of @file.
243  *
244  * Since: 2.8
245  */
246 gchar *
247 g_mapped_file_get_contents (GMappedFile *file)
248 {
249   g_return_val_if_fail (file != NULL, NULL);
250
251   return file->contents;
252 }
253
254 /**
255  * g_mapped_file_free:
256  * @file: a #GMappedFile
257  *
258  * Unmaps the buffer of @file and frees it. 
259  *
260  * Since: 2.8
261  */
262 void
263 g_mapped_file_free (GMappedFile *file)
264 {
265   g_return_if_fail (file != NULL);
266
267   if (file->length)
268   {
269 #ifdef HAVE_MMAP
270     munmap (file->contents, file->length);
271 #endif
272 #ifdef G_OS_WIN32
273     UnmapViewOfFile (file->contents);
274     CloseHandle (file->mapping);
275 #endif
276   }
277
278   g_free (file);
279 }
280
281
282 #define __G_MAPPED_FILE_C__
283 #include "galiasdef.c"