glib/libglib/src/gmappedfile.c
branchRCL_3
changeset 57 2efc27d87e1c
parent 0 e4d67989cc36
equal deleted inserted replaced
56:acd3cd4aaceb 57:2efc27d87e1c
       
     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  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Lesser General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Lesser General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Lesser General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 
       
    25 #include <errno.h>
       
    26 #include <sys/types.h> 
       
    27 #include <sys/stat.h> 
       
    28 #include <fcntl.h>
       
    29 #ifdef HAVE_UNISTD_H
       
    30 #include <unistd.h>
       
    31 #endif
       
    32 #ifdef HAVE_MMAP
       
    33 #include <sys/mman.h>
       
    34 #endif
       
    35 
       
    36 #include "glibconfig.h"
       
    37 
       
    38 #ifdef G_OS_WIN32
       
    39 #include <windows.h>
       
    40 #include <io.h>
       
    41 #endif
       
    42 
       
    43 #include "gconvert.h"
       
    44 #include "gerror.h"
       
    45 #include "gfileutils.h"
       
    46 #include "gmappedfile.h"
       
    47 #include "gmem.h"
       
    48 #include "gmessages.h"
       
    49 #include "gstdio.h"
       
    50 #include "gstrfuncs.h"
       
    51 
       
    52 #include "glibintl.h"
       
    53 
       
    54 #include "galias.h"
       
    55 
       
    56 #ifdef __SYMBIAN32__
       
    57 #include "glib.h"
       
    58 #endif /* __SYMBIAN32__ */
       
    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: wether 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 EXPORT_C 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   file = g_new0 (GMappedFile, 1);
       
   128 
       
   129   if (fstat (fd, &st) == -1)
       
   130     {
       
   131       int save_errno = errno;
       
   132       gchar *display_filename = g_filename_display_name (filename);
       
   133 
       
   134       g_set_error (error,
       
   135                    G_FILE_ERROR,
       
   136                    g_file_error_from_errno (save_errno),
       
   137                    _("Failed to get attributes of file '%s': fstat() failed: %s"),
       
   138                    display_filename, 
       
   139 		   g_strerror (save_errno));
       
   140       g_free (display_filename);
       
   141       goto out;
       
   142     }
       
   143 
       
   144   if (st.st_size == 0)
       
   145     {
       
   146       file->length = 0;
       
   147       file->contents = "";
       
   148       close (fd);
       
   149       return file;
       
   150     }
       
   151 
       
   152   file->contents = MAP_FAILED;
       
   153 
       
   154 #ifdef HAVE_MMAP
       
   155   if (st.st_size > G_MAXSIZE)
       
   156     {
       
   157       errno = EINVAL;
       
   158     }
       
   159   else
       
   160     {      
       
   161       file->length = (gsize) st.st_size;
       
   162       file->contents = (gchar *) mmap (NULL,  file->length,
       
   163 				       writable ? PROT_READ|PROT_WRITE : PROT_READ,
       
   164 				       MAP_PRIVATE, fd, 0);
       
   165     }
       
   166 #endif
       
   167 #ifdef G_OS_WIN32
       
   168   file->length = st.st_size;
       
   169   file->mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL,
       
   170 				     writable ? PAGE_WRITECOPY : PAGE_READONLY,
       
   171 				     0, 0,
       
   172 				     NULL);
       
   173   if (file->mapping != NULL)
       
   174     {
       
   175       file->contents = MapViewOfFile (file->mapping,
       
   176 				      writable ? FILE_MAP_COPY : FILE_MAP_READ,
       
   177 				      0, 0,
       
   178 				      0);
       
   179       if (file->contents == NULL)
       
   180 	{
       
   181 	  file->contents = MAP_FAILED;
       
   182 	  CloseHandle (file->mapping);
       
   183 	  file->mapping = NULL;
       
   184 	}
       
   185     }
       
   186 #endif
       
   187 
       
   188   
       
   189   if (file->contents == MAP_FAILED)
       
   190     {
       
   191       int save_errno = errno;
       
   192       gchar *display_filename = g_filename_display_name (filename);
       
   193       
       
   194       g_set_error (error,
       
   195 		   G_FILE_ERROR,
       
   196 		   g_file_error_from_errno (save_errno),
       
   197 		   _("Failed to map file '%s': mmap() failed: %s"),
       
   198 		   display_filename,
       
   199 		   g_strerror (save_errno));
       
   200       g_free (display_filename);
       
   201       goto out;
       
   202     }
       
   203 
       
   204   close (fd);
       
   205   return file;
       
   206 
       
   207  out:
       
   208   close (fd);
       
   209   g_free (file);
       
   210 
       
   211   return NULL;
       
   212 }
       
   213 
       
   214 /**
       
   215  * g_mapped_file_get_length:
       
   216  * @file: a #GMappedFile
       
   217  *
       
   218  * Returns the length of the contents of a #GMappedFile.
       
   219  *
       
   220  * Returns: the length of the contents of @file.
       
   221  *
       
   222  * Since: 2.8
       
   223  */
       
   224 EXPORT_C gsize
       
   225 g_mapped_file_get_length (GMappedFile *file)
       
   226 {
       
   227   g_return_val_if_fail (file != NULL, 0);
       
   228 
       
   229   return file->length;
       
   230 }
       
   231 
       
   232 /**
       
   233  * g_mapped_file_get_contents:
       
   234  * @file: a #GMappedFile
       
   235  *
       
   236  * Returns the contents of a #GMappedFile. 
       
   237  *
       
   238  * Note that the contents may not be zero-terminated,
       
   239  * even if the #GMappedFile is backed by a text file.
       
   240  *
       
   241  * Returns: the contents of @file.
       
   242  *
       
   243  * Since: 2.8
       
   244  */
       
   245 EXPORT_C gchar *
       
   246 g_mapped_file_get_contents (GMappedFile *file)
       
   247 {
       
   248   g_return_val_if_fail (file != NULL, NULL);
       
   249 
       
   250   return file->contents;
       
   251 }
       
   252 
       
   253 /**
       
   254  * g_mapped_file_free:
       
   255  * @file: a #GMappedFile
       
   256  *
       
   257  * Unmaps the buffer of @file and frees it. 
       
   258  *
       
   259  * Since: 2.8
       
   260  */
       
   261 EXPORT_C void
       
   262 g_mapped_file_free (GMappedFile *file)
       
   263 {
       
   264   g_return_if_fail (file != NULL);
       
   265 
       
   266   if (file->length)
       
   267   {
       
   268 #ifdef HAVE_MMAP
       
   269     munmap (file->contents, file->length);
       
   270 #endif
       
   271 #ifdef G_OS_WIN32
       
   272     UnmapViewOfFile (file->contents);
       
   273     CloseHandle (file->mapping);
       
   274 #endif
       
   275   }
       
   276 
       
   277   g_free (file);
       
   278 }
       
   279 
       
   280 
       
   281 #define __G_MAPPED_FILE_C__
       
   282 #include "galiasdef.c"