Tizen 2.1 base
[platform/upstream/glib2.0.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 #define fstat(a,b) _fstati64(a,b)
42 #define stat _stati64
43
44 #ifndef S_ISREG
45 #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
46 #endif
47
48 #endif
49
50 #include "gconvert.h"
51 #include "gerror.h"
52 #include "gfileutils.h"
53 #include "gmappedfile.h"
54 #include "gmem.h"
55 #include "gmessages.h"
56 #include "gstdio.h"
57 #include "gstrfuncs.h"
58 #include "gatomic.h"
59
60 #include "glibintl.h"
61
62
63 #ifndef _O_BINARY
64 #define _O_BINARY 0
65 #endif
66
67 #ifndef MAP_FAILED
68 #define MAP_FAILED ((void *) -1)
69 #endif
70
71 /**
72  * GMappedFile:
73  *
74  * The #GMappedFile represents a file mapping created with
75  * g_mapped_file_new(). It has only private members and should
76  * not be accessed directly.
77  */
78
79 struct _GMappedFile
80 {
81   gchar *contents;
82   gsize  length;
83   gpointer free_func;
84   int    ref_count;
85 #ifdef G_OS_WIN32
86   HANDLE mapping;
87 #endif
88 };
89
90 static void
91 g_mapped_file_destroy (GMappedFile *file)
92 {
93   if (file->length)
94     {
95 #ifdef HAVE_MMAP
96       munmap (file->contents, file->length);
97 #endif
98 #ifdef G_OS_WIN32
99       UnmapViewOfFile (file->contents);
100       CloseHandle (file->mapping);
101 #endif
102     }
103
104   g_slice_free (GMappedFile, file);
105 }
106
107 static GMappedFile*
108 mapped_file_new_from_fd (int           fd,
109                          gboolean      writable,
110                          const gchar  *filename,
111                          GError      **error)
112 {
113   GMappedFile *file;
114   struct stat st;
115
116   file = g_slice_new0 (GMappedFile);
117   file->ref_count = 1;
118   file->free_func = g_mapped_file_destroy;
119
120   if (fstat (fd, &st) == -1)
121     {
122       int save_errno = errno;
123       gchar *display_filename = filename ? g_filename_display_name (filename) : NULL;
124
125       g_set_error (error,
126                    G_FILE_ERROR,
127                    g_file_error_from_errno (save_errno),
128                    _("Failed to get attributes of file '%s%s%s%s': fstat() failed: %s"),
129                    display_filename ? display_filename : "fd",
130                    display_filename ? "' " : "",
131                    display_filename ? display_filename : "",
132                    display_filename ? "'" : "",
133                    g_strerror (save_errno));
134       g_free (display_filename);
135       goto out;
136     }
137
138   /* mmap() on size 0 will fail with EINVAL, so we avoid calling mmap()
139    * in that case -- but only if we have a regular file; we still want
140    * attempts to mmap a character device to fail, for example.
141    */
142   if (st.st_size == 0 && S_ISREG (st.st_mode))
143     {
144       file->length = 0;
145       file->contents = NULL;
146       return file;
147     }
148
149   file->contents = MAP_FAILED;
150
151 #ifdef HAVE_MMAP
152   if (st.st_size > G_MAXSIZE)
153     {
154       errno = EINVAL;
155     }
156   else
157     {      
158       file->length = (gsize) st.st_size;
159       file->contents = (gchar *) mmap (NULL,  file->length,
160                                        writable ? PROT_READ|PROT_WRITE : PROT_READ,
161                                        MAP_PRIVATE, fd, 0);
162     }
163 #endif
164 #ifdef G_OS_WIN32
165   file->length = st.st_size;
166   file->mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL,
167                                      writable ? PAGE_WRITECOPY : PAGE_READONLY,
168                                      0, 0,
169                                      NULL);
170   if (file->mapping != NULL)
171     {
172       file->contents = MapViewOfFile (file->mapping,
173                                       writable ? FILE_MAP_COPY : FILE_MAP_READ,
174                                       0, 0,
175                                       0);
176       if (file->contents == NULL)
177         {
178           file->contents = MAP_FAILED;
179           CloseHandle (file->mapping);
180           file->mapping = NULL;
181         }
182     }
183 #endif
184
185   
186   if (file->contents == MAP_FAILED)
187     {
188       int save_errno = errno;
189       gchar *display_filename = filename ? g_filename_display_name (filename) : NULL;
190
191       g_set_error (error,
192                    G_FILE_ERROR,
193                    g_file_error_from_errno (save_errno),
194                    _("Failed to map %s%s%s%s: mmap() failed: %s"),
195                    display_filename ? display_filename : "fd",
196                    display_filename ? "' " : "",
197                    display_filename ? display_filename : "",
198                    display_filename ? "'" : "",
199                    g_strerror (save_errno));
200       g_free (display_filename);
201       goto out;
202     }
203
204   return file;
205
206  out:
207   g_slice_free (GMappedFile, file);
208
209   return NULL;
210 }
211
212 /**
213  * g_mapped_file_new:
214  * @filename: The path of the file to load, in the GLib filename encoding
215  * @writable: whether the mapping should be writable
216  * @error: return location for a #GError, or %NULL
217  *
218  * Maps a file into memory. On UNIX, this is using the mmap() function.
219  *
220  * If @writable is %TRUE, the mapped buffer may be modified, otherwise
221  * it is an error to modify the mapped buffer. Modifications to the buffer
222  * are not visible to other processes mapping the same file, and are not
223  * written back to the file.
224  *
225  * Note that modifications of the underlying file might affect the contents
226  * of the #GMappedFile. Therefore, mapping should only be used if the file
227  * will not be modified, or if all modifications of the file are done
228  * atomically (e.g. using g_file_set_contents()).
229  *
230  * If @filename is the name of an empty, regular file, the function
231  * will successfully return an empty #GMappedFile. In other cases of
232  * size 0 (e.g. device files such as /dev/null), @error will be set
233  * to the #GFileError value #G_FILE_ERROR_INVAL.
234  *
235  * Return value: a newly allocated #GMappedFile which must be unref'd
236  *    with g_mapped_file_unref(), or %NULL if the mapping failed.
237  *
238  * Since: 2.8
239  */
240 GMappedFile *
241 g_mapped_file_new (const gchar  *filename,
242                    gboolean      writable,
243                    GError      **error)
244 {
245   GMappedFile *file;
246   int fd;
247
248   g_return_val_if_fail (filename != NULL, NULL);
249   g_return_val_if_fail (!error || *error == NULL, NULL);
250
251   fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
252   if (fd == -1)
253     {
254       int save_errno = errno;
255       gchar *display_filename = g_filename_display_name (filename);
256
257       g_set_error (error,
258                    G_FILE_ERROR,
259                    g_file_error_from_errno (save_errno),
260                    _("Failed to open file '%s': open() failed: %s"),
261                    display_filename,
262                    g_strerror (save_errno));
263       g_free (display_filename);
264       return NULL;
265     }
266
267   file = mapped_file_new_from_fd (fd, writable, filename, error);
268
269   close (fd);
270
271   return file;
272 }
273
274
275 /**
276  * g_mapped_file_new_from_fd:
277  * @fd: The file descriptor of the file to load
278  * @writable: whether the mapping should be writable
279  * @error: return location for a #GError, or %NULL
280  *
281  * Maps a file into memory. On UNIX, this is using the mmap() function.
282  *
283  * If @writable is %TRUE, the mapped buffer may be modified, otherwise
284  * it is an error to modify the mapped buffer. Modifications to the buffer
285  * are not visible to other processes mapping the same file, and are not
286  * written back to the file.
287  *
288  * Note that modifications of the underlying file might affect the contents
289  * of the #GMappedFile. Therefore, mapping should only be used if the file
290  * will not be modified, or if all modifications of the file are done
291  * atomically (e.g. using g_file_set_contents()).
292  *
293  * Return value: a newly allocated #GMappedFile which must be unref'd
294  *    with g_mapped_file_unref(), or %NULL if the mapping failed.
295  *
296  * Since: 2.32
297  */
298 GMappedFile *
299 g_mapped_file_new_from_fd (gint          fd,
300                            gboolean      writable,
301                            GError      **error)
302 {
303   return mapped_file_new_from_fd (fd, writable, NULL, error);
304 }
305
306 /**
307  * g_mapped_file_get_length:
308  * @file: a #GMappedFile
309  *
310  * Returns the length of the contents of a #GMappedFile.
311  *
312  * Returns: the length of the contents of @file.
313  *
314  * Since: 2.8
315  */
316 gsize
317 g_mapped_file_get_length (GMappedFile *file)
318 {
319   g_return_val_if_fail (file != NULL, 0);
320
321   return file->length;
322 }
323
324 /**
325  * g_mapped_file_get_contents:
326  * @file: a #GMappedFile
327  *
328  * Returns the contents of a #GMappedFile. 
329  *
330  * Note that the contents may not be zero-terminated,
331  * even if the #GMappedFile is backed by a text file.
332  *
333  * If the file is empty then %NULL is returned.
334  *
335  * Returns: the contents of @file, or %NULL.
336  *
337  * Since: 2.8
338  */
339 gchar *
340 g_mapped_file_get_contents (GMappedFile *file)
341 {
342   g_return_val_if_fail (file != NULL, NULL);
343
344   return file->contents;
345 }
346
347 /**
348  * g_mapped_file_free:
349  * @file: a #GMappedFile
350  *
351  * This call existed before #GMappedFile had refcounting and is currently
352  * exactly the same as g_mapped_file_unref().
353  *
354  * Since: 2.8
355  * Deprecated:2.22: Use g_mapped_file_unref() instead.
356  */
357 void
358 g_mapped_file_free (GMappedFile *file)
359 {
360   g_mapped_file_unref (file);
361 }
362
363 /**
364  * g_mapped_file_ref:
365  * @file: a #GMappedFile
366  *
367  * Increments the reference count of @file by one.  It is safe to call
368  * this function from any thread.
369  *
370  * Return value: the passed in #GMappedFile.
371  *
372  * Since: 2.22
373  **/
374 GMappedFile *
375 g_mapped_file_ref (GMappedFile *file)
376 {
377   g_return_val_if_fail (file != NULL, NULL);
378
379   g_atomic_int_inc (&file->ref_count);
380
381   return file;
382 }
383
384 /**
385  * g_mapped_file_unref:
386  * @file: a #GMappedFile
387  *
388  * Decrements the reference count of @file by one.  If the reference count
389  * drops to 0, unmaps the buffer of @file and frees it.
390  *
391  * It is safe to call this function from any thread.
392  *
393  * Since 2.22
394  **/
395 void
396 g_mapped_file_unref (GMappedFile *file)
397 {
398   g_return_if_fail (file != NULL);
399
400   if (g_atomic_int_dec_and_test (&file->ref_count))
401     g_mapped_file_destroy (file);
402 }