#include <sys/mman.h>
#endif
+#include "glibconfig.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <io.h>
+
+#define fstat(a,b) _fstati64(a,b)
+#define stat _stati64
+
+#endif
#include "gconvert.h"
#include "gerror.h"
#include "gmessages.h"
#include "gstdio.h"
#include "gstrfuncs.h"
+#include "gatomic.h"
#include "glibintl.h"
#include "galias.h"
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+
#ifndef MAP_FAILED
#define MAP_FAILED ((void *) -1)
#endif
{
gsize length;
gchar *contents;
+ int ref_count;
+#ifdef G_OS_WIN32
+ HANDLE mapping;
+#endif
};
/**
* g_mapped_file_new:
* @filename: The path of the file to load, in the GLib filename encoding
- * @writable: wether the mapping should be writable
+ * @writable: whether the mapping should be writable
* @error: return location for a #GError, or %NULL
*
* Maps a file into memory. On UNIX, this is using the mmap() function.
* will not be modified, or if all modifications of the file are done
* atomically (e.g. using g_file_set_contents()).
*
- * Return value: a newly allocated #GMappedFile which must be freed
- * with g_mapped_file_free(), or %NULL if the mapping failed.
+ * Return value: a newly allocated #GMappedFile which must be unref'd
+ * with g_mapped_file_unref(), or %NULL if the mapping failed.
*
* Since: 2.8
*/
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (!error || *error == NULL, NULL);
- fd = g_open (filename, writable ? O_RDWR : O_RDONLY);
+ fd = g_open (filename, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
if (fd == -1)
{
int save_errno = errno;
return NULL;
}
- file = g_new0 (GMappedFile, 1);
+ file = g_slice_new0 (GMappedFile);
+ file->ref_count = 1;
if (fstat (fd, &st) == -1)
{
goto out;
}
+ if (st.st_size == 0)
+ {
+ file->length = 0;
+ file->contents = NULL;
+ close (fd);
+ return file;
+ }
+
file->contents = MAP_FAILED;
#ifdef HAVE_MMAP
+ if (st.st_size > G_MAXSIZE)
+ {
+ errno = EINVAL;
+ }
+ else
+ {
+ file->length = (gsize) st.st_size;
+ file->contents = (gchar *) mmap (NULL, file->length,
+ writable ? PROT_READ|PROT_WRITE : PROT_READ,
+ MAP_PRIVATE, fd, 0);
+ }
+#endif
+#ifdef G_OS_WIN32
file->length = st.st_size;
- file->contents = (gchar *) mmap (NULL, st.st_size,
- writable ? PROT_READ|PROT_WRITE : PROT_READ,
- MAP_PRIVATE, fd, 0);
+ file->mapping = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL,
+ writable ? PAGE_WRITECOPY : PAGE_READONLY,
+ 0, 0,
+ NULL);
+ if (file->mapping != NULL)
+ {
+ file->contents = MapViewOfFile (file->mapping,
+ writable ? FILE_MAP_COPY : FILE_MAP_READ,
+ 0, 0,
+ 0);
+ if (file->contents == NULL)
+ {
+ file->contents = MAP_FAILED;
+ CloseHandle (file->mapping);
+ file->mapping = NULL;
+ }
+ }
#endif
+
if (file->contents == MAP_FAILED)
{
out:
close (fd);
- g_free (file);
+ g_slice_free (GMappedFile, file);
return NULL;
}
* Note that the contents may not be zero-terminated,
* even if the #GMappedFile is backed by a text file.
*
- * Returns: the contents of @file.
+ * If the file is empty then %NULL is returned.
+ *
+ * Returns: the contents of @file, or %NULL.
*
* Since: 2.8
*/
* g_mapped_file_free:
* @file: a #GMappedFile
*
- * Unmaps the buffer of @file and frees it.
- *
- * For writable, shared mappings, the contents
- * will be written back to the file at this point.
+ * This call existed before #GMappedFile had refcounting and is currently
+ * exactly the same as g_mapped_file_unref().
*
* Since: 2.8
+ * Deprecated:2.22: Use g_mapped_file_unref() instead.
*/
void
g_mapped_file_free (GMappedFile *file)
{
+ g_mapped_file_unref (file);
+}
+
+/**
+ * g_mapped_file_ref:
+ * @file: a #GMappedFile
+ *
+ * Increments the reference count of @file by one. It is safe to call
+ * this function from any thread.
+ *
+ * Return value: the passed in #GMappedFile.
+ *
+ * Since: 2.22
+ **/
+GMappedFile *
+g_mapped_file_ref (GMappedFile *file)
+{
+ g_return_val_if_fail (file != NULL, NULL);
+ g_return_val_if_fail (file->ref_count > 0, file);
+
+ g_atomic_int_inc (&file->ref_count);
+
+ return file;
+}
+
+/**
+ * g_mapped_file_unref:
+ * @file: a #GMappedFile
+ *
+ * Decrements the reference count of @file by one. If the reference count
+ * drops to 0, unmaps the buffer of @file and frees it.
+ *
+ * It is safe to call this function from any thread.
+ *
+ * Since 2.22
+ **/
+void
+g_mapped_file_unref (GMappedFile *file)
+{
g_return_if_fail (file != NULL);
+ g_return_if_fail (file->ref_count > 0);
+ if (g_atomic_int_dec_and_test (&file->ref_count))
+ {
+ if (file->length)
+ {
#ifdef HAVE_MMAP
- munmap (file->contents, file->length);
+ munmap (file->contents, file->length);
#endif
-}
+#ifdef G_OS_WIN32
+ UnmapViewOfFile (file->contents);
+ CloseHandle (file->mapping);
+#endif
+ }
+ g_slice_free (GMappedFile, file);
+ }
+}
#define __G_MAPPED_FILE_C__
#include "galiasdef.c"