1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5
* Copyright (C) 2002-2004 Jody Goldberg (jody@gnome.org)
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of version 2.1 of the GNU Lesser General Public
9
* License as published by the Free Software Foundation.
11
* This program 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
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24
#include "gsf-input-memory.h"
25
#include "gsf-input-impl.h"
26
#include "gsf-impl-utils.h"
27
#include "gsf-utils.h"
28
#include "gsf-shared-memory.h"
31
#if defined(FREEBSD) || defined(__FreeBSD__)
32
/* We must keep the file open while pages are mapped. */
33
/* http://www.freebsd.org/cgi/query-pr.cgi?pr=48291 */
34
#define HAVE_BROKEN_MMAP
38
static GObjectClass *parent_class;
40
struct _GsfInputMemory {
42
GsfSharedMemory *shared;
43
#ifdef HAVE_BROKEN_MMAP
47
typedef GsfInputClass GsfInputMemoryClass;
50
* gsf_input_memory_new:
51
* @buf: The input bytes
52
* @length: The length of @buf
53
* @needs_free: Whether you want this memory to be free'd at object destruction
55
* Returns: A new #GsfInputMemory
58
gsf_input_memory_new (guint8 const *buf, gsf_off_t length, gboolean needs_free)
60
GsfInputMemory *mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
63
mem->shared = gsf_shared_memory_new ((void *)buf, length, needs_free);
64
gsf_input_set_size (GSF_INPUT (mem), length);
65
return GSF_INPUT (mem);
69
* gsf_input_memory_new_clone:
70
* @buf: The input bytes
71
* @length: The length of @buf
73
* Returns: A new #GsfInputMemory
76
gsf_input_memory_new_clone (guint8 const *buf, gsf_off_t length)
78
GsfInputMemory *mem = NULL;
79
guint8 * cpy = g_try_malloc (length * sizeof (guint8));
83
memcpy (cpy, buf, length);
84
mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
87
mem->shared = gsf_shared_memory_new ((void *)cpy, length, TRUE);
88
gsf_input_set_size (GSF_INPUT (mem), length);
89
return GSF_INPUT (mem);
93
gsf_input_memory_finalize (GObject *obj)
95
GsfInputMemory *mem = (GsfInputMemory *) (obj);
98
g_object_unref (G_OBJECT (mem->shared));
100
#ifdef HAVE_BROKEN_MMAP
105
parent_class->finalize (obj);
109
gsf_input_memory_dup (GsfInput *src_input, GError **err)
111
GsfInputMemory const *src = (GsfInputMemory *) (src_input);
112
GsfInputMemory *dst = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
117
dst->shared = src->shared;
118
g_object_ref (G_OBJECT (dst->shared));
120
#ifdef HAVE_BROKEN_MMAP
122
dst->fd = dup (src->fd);
125
return GSF_INPUT (dst);
128
static guint8 const *
129
gsf_input_memory_read (GsfInput *input, size_t num_bytes, guint8 *optional_buffer)
131
GsfInputMemory *mem = (GsfInputMemory *) (input);
132
guchar const *src = mem->shared->buf;
136
if (optional_buffer) {
137
memcpy (optional_buffer, src + input->cur_offset, num_bytes);
138
return optional_buffer;
140
return src + input->cur_offset;
144
gsf_input_memory_seek (G_GNUC_UNUSED GsfInput *input,
145
G_GNUC_UNUSED gsf_off_t offset,
146
G_GNUC_UNUSED GSeekType whence)
152
gsf_input_memory_init (GObject *obj)
154
GsfInputMemory *mem = (GsfInputMemory *) (obj);
156
#ifdef HAVE_BROKEN_MMAP
162
gsf_input_memory_class_init (GObjectClass *gobject_class)
164
GsfInputClass *input_class = GSF_INPUT_CLASS (gobject_class);
166
gobject_class->finalize = gsf_input_memory_finalize;
167
input_class->Dup = gsf_input_memory_dup;
168
input_class->Read = gsf_input_memory_read;
169
input_class->Seek = gsf_input_memory_seek;
171
parent_class = g_type_class_peek_parent (gobject_class);
174
GSF_CLASS (GsfInputMemory, gsf_input_memory,
175
gsf_input_memory_class_init, gsf_input_memory_init,
178
/***************************************************************************/
183
#include <sys/mman.h>
184
#include <sys/types.h>
185
#include <sys/stat.h>
190
#define PROT_READ 0x1
193
#if !defined(MAP_FAILED) || defined(__osf__)
194
/* Someone needs their head examined - BSD ? */
195
# define MAP_FAILED ((void *)-1)
200
* gsf_input_mmap_new:
201
* @filename: The file on disk that you want to mmap
202
* @err: A #GError, or optionally %null
204
* Returns: A new #GsfInputMemory
207
gsf_input_mmap_new (char const *filename, GError **err)
216
fd = open (filename, O_RDONLY);
217
if (fd < 0 || fstat (fd, &st) < 0) {
219
char *utf8name = gsf_filename_to_utf8 (filename, FALSE);
220
*err = g_error_new (gsf_input_error (), 0,
221
"%s: %s", utf8name, g_strerror (errno));
224
if (fd >= 0) close (fd);
228
if (!S_ISREG (st.st_mode)) {
230
char *utf8name = gsf_filename_to_utf8 (filename, FALSE);
231
*err = g_error_new (gsf_input_error (), 0,
232
"%s: Is not a regular file", utf8name);
239
size = (size_t) st.st_size;
240
if ((off_t) size != st.st_size) { /* Check for overflow */
242
char *utf8name = gsf_filename_to_utf8 (filename, FALSE);
243
*err = g_error_new (gsf_input_error (), 0,
245
"File too large to be memory mapped");
251
buf = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, (off_t) 0);
252
if (buf == MAP_FAILED) {
254
char *utf8name = gsf_filename_to_utf8 (filename, FALSE);
255
*err = g_error_new (gsf_input_error (), 0,
256
"%s: %s", utf8name, g_strerror (errno));
263
mem = g_object_new (GSF_INPUT_MEMORY_TYPE, NULL);
266
mem->shared = gsf_shared_memory_mmapped_new (buf, (gsf_off_t) size);
267
gsf_input_set_size (GSF_INPUT (mem), (gsf_off_t) size);
268
gsf_input_set_name (GSF_INPUT (mem), filename);
270
#ifdef HAVE_BROKEN_MMAP
276
return GSF_INPUT (mem);
279
#warning MMAP Unsupported
283
*err = g_error_new (gsf_input_error (), 0,