13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
28 #ifndef _POSIX_C_SOURCE
29 #define _POSIX_C_SOURCE 199309L
30 #endif
31
32 #include "hb-private.hh"
33
34 #include "hb-object-private.hh"
35
36 #ifdef HAVE_SYS_MMAN_H
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif /* HAVE_UNISTD_H */
40 #include <sys/mman.h>
41 #endif /* HAVE_SYS_MMAN_H */
42
43 #include <stdio.h>
44 #include <errno.h>
45
46
47
48 #ifndef HB_DEBUG_BLOB
49 #define HB_DEBUG_BLOB (HB_DEBUG+0)
50 #endif
51
52
53 struct hb_blob_t {
54 hb_object_header_t header;
55 ASSERT_POD ();
56
57 bool immutable;
58
59 const char *data;
60 unsigned int length;
61 hb_memory_mode_t mode;
62
63 void *user_data;
64 hb_destroy_func_t destroy;
65 };
66
67
68 static bool _try_writable (hb_blob_t *blob);
69
70 static void
71 _hb_blob_destroy_user_data (hb_blob_t *blob)
72 {
73 if (blob->destroy) {
74 blob->destroy (blob->user_data);
75 blob->user_data = NULL;
76 blob->destroy = NULL;
77 }
78 }
79
80 /**
81 * hb_blob_create: (skip)
82 * @data: Pointer to blob data.
83 * @length: Length of @data in bytes.
84 * @mode: Memory mode for @data.
85 * @user_data: Data parameter to pass to @destroy.
86 * @destroy: Callback to call when @data is not needed anymore.
87 *
88 * Creates a new "blob" object wrapping @data. The @mode parameter is used
89 * to negotiate ownership and lifecycle of @data.
90 *
91 * Return value: New blob, or the empty blob if something failed or if @length is
92 * zero. Destroy with hb_blob_destroy().
93 *
94 * Since: 0.9.2
95 **/
96 hb_blob_t *
111 }
112
113 blob->data = data;
114 blob->length = length;
115 blob->mode = mode;
116
117 blob->user_data = user_data;
118 blob->destroy = destroy;
119
120 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
121 blob->mode = HB_MEMORY_MODE_READONLY;
122 if (!_try_writable (blob)) {
123 hb_blob_destroy (blob);
124 return hb_blob_get_empty ();
125 }
126 }
127
128 return blob;
129 }
130
131 /**
132 * hb_blob_create_sub_blob:
133 * @parent: Parent blob.
134 * @offset: Start offset of sub-blob within @parent, in bytes.
135 * @length: Length of sub-blob.
136 *
137 * Returns a blob that represents a range of bytes in @parent. The new
138 * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
139 * will never modify data in the parent blob. The parent data is not
140 * expected to be modified, and will result in undefined behavior if it
141 * is.
142 *
143 * Makes @parent immutable.
144 *
145 * Return value: New blob, or the empty blob if something failed or if
146 * @length is zero or @offset is beyond the end of @parent's data. Destroy
147 * with hb_blob_destroy().
148 *
149 * Since: 0.9.2
150 **/
151 hb_blob_t *
152 hb_blob_create_sub_blob (hb_blob_t *parent,
153 unsigned int offset,
154 unsigned int length)
155 {
156 hb_blob_t *blob;
157
158 if (!length || offset >= parent->length)
159 return hb_blob_get_empty ();
160
161 hb_blob_make_immutable (parent);
162
163 blob = hb_blob_create (parent->data + offset,
164 MIN (length, parent->length - offset),
165 HB_MEMORY_MODE_READONLY,
166 hb_blob_reference (parent),
167 (hb_destroy_func_t) hb_blob_destroy);
168
169 return blob;
170 }
171
172 /**
173 * hb_blob_get_empty:
174 *
175 * Returns the singleton empty blob.
176 *
177 * See TODO:link object types for more information.
178 *
179 * Return value: (transfer full): the empty blob.
180 *
181 * Since: 0.9.2
182 **/
183 hb_blob_t *
184 hb_blob_get_empty (void)
185 {
186 static const hb_blob_t _hb_blob_nil = {
187 HB_OBJECT_HEADER_STATIC,
188
189 true, /* immutable */
190
191 NULL, /* data */
192 0, /* length */
193 HB_MEMORY_MODE_READONLY, /* mode */
194
195 NULL, /* user_data */
196 NULL /* destroy */
197 };
198
199 return const_cast<hb_blob_t *> (&_hb_blob_nil);
200 }
201
202 /**
203 * hb_blob_reference: (skip)
204 * @blob: a blob.
205 *
206 * Increases the reference count on @blob.
207 *
208 * See TODO:link object types for more information.
209 *
210 * Return value: @blob.
211 *
212 * Since: 0.9.2
213 **/
214 hb_blob_t *
215 hb_blob_reference (hb_blob_t *blob)
216 {
356 * @length: (out): output length of the writable data.
357 *
358 * Tries to make blob data writable (possibly copying it) and
359 * return pointer to data.
360 *
361 * Fails if blob has been made immutable, or if memory allocation
362 * fails.
363 *
364 * Returns: (transfer none) (array length=length): Writable blob data,
365 * or %NULL if failed.
366 *
367 * Since: 0.9.2
368 **/
369 char *
370 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
371 {
372 if (!_try_writable (blob)) {
373 if (length)
374 *length = 0;
375
376 return NULL;
377 }
378
379 if (length)
380 *length = blob->length;
381
382 return const_cast<char *> (blob->data);
383 }
384
385
386 static hb_bool_t
387 _try_make_writable_inplace_unix (hb_blob_t *blob)
388 {
389 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
390 uintptr_t pagesize = -1, mask, length;
391 const char *addr;
392
393 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
394 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
395 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
396 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
|
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
28 #ifndef _POSIX_C_SOURCE
29 #define _POSIX_C_SOURCE 199309L
30 #endif
31
32 #include "hb-private.hh"
33 #include "hb-debug.hh"
34
35 #include "hb-object-private.hh"
36
37 #ifdef HAVE_SYS_MMAN_H
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif /* HAVE_UNISTD_H */
41 #include <sys/mman.h>
42 #endif /* HAVE_SYS_MMAN_H */
43
44 #include <stdio.h>
45 #include <errno.h>
46
47
48 struct hb_blob_t {
49 hb_object_header_t header;
50 ASSERT_POD ();
51
52 bool immutable;
53
54 const char *data;
55 unsigned int length;
56 hb_memory_mode_t mode;
57
58 void *user_data;
59 hb_destroy_func_t destroy;
60 };
61
62
63 static bool _try_writable (hb_blob_t *blob);
64
65 static void
66 _hb_blob_destroy_user_data (hb_blob_t *blob)
67 {
68 if (blob->destroy) {
69 blob->destroy (blob->user_data);
70 blob->user_data = nullptr;
71 blob->destroy = nullptr;
72 }
73 }
74
75 /**
76 * hb_blob_create: (skip)
77 * @data: Pointer to blob data.
78 * @length: Length of @data in bytes.
79 * @mode: Memory mode for @data.
80 * @user_data: Data parameter to pass to @destroy.
81 * @destroy: Callback to call when @data is not needed anymore.
82 *
83 * Creates a new "blob" object wrapping @data. The @mode parameter is used
84 * to negotiate ownership and lifecycle of @data.
85 *
86 * Return value: New blob, or the empty blob if something failed or if @length is
87 * zero. Destroy with hb_blob_destroy().
88 *
89 * Since: 0.9.2
90 **/
91 hb_blob_t *
106 }
107
108 blob->data = data;
109 blob->length = length;
110 blob->mode = mode;
111
112 blob->user_data = user_data;
113 blob->destroy = destroy;
114
115 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
116 blob->mode = HB_MEMORY_MODE_READONLY;
117 if (!_try_writable (blob)) {
118 hb_blob_destroy (blob);
119 return hb_blob_get_empty ();
120 }
121 }
122
123 return blob;
124 }
125
126 static void
127 _hb_blob_destroy (void *data)
128 {
129 hb_blob_destroy ((hb_blob_t *) data);
130 }
131
132 /**
133 * hb_blob_create_sub_blob:
134 * @parent: Parent blob.
135 * @offset: Start offset of sub-blob within @parent, in bytes.
136 * @length: Length of sub-blob.
137 *
138 * Returns a blob that represents a range of bytes in @parent. The new
139 * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
140 * will never modify data in the parent blob. The parent data is not
141 * expected to be modified, and will result in undefined behavior if it
142 * is.
143 *
144 * Makes @parent immutable.
145 *
146 * Return value: New blob, or the empty blob if something failed or if
147 * @length is zero or @offset is beyond the end of @parent's data. Destroy
148 * with hb_blob_destroy().
149 *
150 * Since: 0.9.2
151 **/
152 hb_blob_t *
153 hb_blob_create_sub_blob (hb_blob_t *parent,
154 unsigned int offset,
155 unsigned int length)
156 {
157 hb_blob_t *blob;
158
159 if (!length || offset >= parent->length)
160 return hb_blob_get_empty ();
161
162 hb_blob_make_immutable (parent);
163
164 blob = hb_blob_create (parent->data + offset,
165 MIN (length, parent->length - offset),
166 HB_MEMORY_MODE_READONLY,
167 hb_blob_reference (parent),
168 _hb_blob_destroy);
169
170 return blob;
171 }
172
173 /**
174 * hb_blob_get_empty:
175 *
176 * Returns the singleton empty blob.
177 *
178 * See TODO:link object types for more information.
179 *
180 * Return value: (transfer full): the empty blob.
181 *
182 * Since: 0.9.2
183 **/
184 hb_blob_t *
185 hb_blob_get_empty (void)
186 {
187 static const hb_blob_t _hb_blob_nil = {
188 HB_OBJECT_HEADER_STATIC,
189
190 true, /* immutable */
191
192 nullptr, /* data */
193 0, /* length */
194 HB_MEMORY_MODE_READONLY, /* mode */
195
196 nullptr, /* user_data */
197 nullptr /* destroy */
198 };
199
200 return const_cast<hb_blob_t *> (&_hb_blob_nil);
201 }
202
203 /**
204 * hb_blob_reference: (skip)
205 * @blob: a blob.
206 *
207 * Increases the reference count on @blob.
208 *
209 * See TODO:link object types for more information.
210 *
211 * Return value: @blob.
212 *
213 * Since: 0.9.2
214 **/
215 hb_blob_t *
216 hb_blob_reference (hb_blob_t *blob)
217 {
357 * @length: (out): output length of the writable data.
358 *
359 * Tries to make blob data writable (possibly copying it) and
360 * return pointer to data.
361 *
362 * Fails if blob has been made immutable, or if memory allocation
363 * fails.
364 *
365 * Returns: (transfer none) (array length=length): Writable blob data,
366 * or %NULL if failed.
367 *
368 * Since: 0.9.2
369 **/
370 char *
371 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
372 {
373 if (!_try_writable (blob)) {
374 if (length)
375 *length = 0;
376
377 return nullptr;
378 }
379
380 if (length)
381 *length = blob->length;
382
383 return const_cast<char *> (blob->data);
384 }
385
386
387 static hb_bool_t
388 _try_make_writable_inplace_unix (hb_blob_t *blob)
389 {
390 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
391 uintptr_t pagesize = -1, mask, length;
392 const char *addr;
393
394 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
395 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
396 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
397 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
|