1 /*
2 * Copyright 2013 MongoDB Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 #undef MONGOC_LOG_DOMAIN
19 #define MONGOC_LOG_DOMAIN "gridfs_file_page"
20
21 #include "mongoc-gridfs-file-page.h"
22 #include "mongoc-gridfs-file-page-private.h"
23
24 #include "mongoc-trace-private.h"
25
26
27 /** create a new page from a buffer
28 *
29 * The buffer should stick around for the life of the page
30 */
31 mongoc_gridfs_file_page_t *
_mongoc_gridfs_file_page_new(const uint8_t * data,uint32_t len,uint32_t chunk_size)32 _mongoc_gridfs_file_page_new (const uint8_t *data,
33 uint32_t len,
34 uint32_t chunk_size)
35 {
36 mongoc_gridfs_file_page_t *page;
37
38 ENTRY;
39
40 BSON_ASSERT (data);
41 BSON_ASSERT (len <= chunk_size);
42
43 page = (mongoc_gridfs_file_page_t *) bson_malloc0 (sizeof *page);
44
45 page->chunk_size = chunk_size;
46 page->read_buf = data;
47 page->len = len;
48
49 RETURN (page);
50 }
51
52
53 bool
_mongoc_gridfs_file_page_seek(mongoc_gridfs_file_page_t * page,uint32_t offset)54 _mongoc_gridfs_file_page_seek (mongoc_gridfs_file_page_t *page, uint32_t offset)
55 {
56 ENTRY;
57
58 BSON_ASSERT (page);
59
60 page->offset = offset;
61
62 RETURN (1);
63 }
64
65
66 int32_t
_mongoc_gridfs_file_page_read(mongoc_gridfs_file_page_t * page,void * dst,uint32_t len)67 _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page,
68 void *dst,
69 uint32_t len)
70 {
71 int bytes_read;
72 const uint8_t *src;
73
74 ENTRY;
75
76 BSON_ASSERT (page);
77 BSON_ASSERT (dst);
78
79 bytes_read = BSON_MIN (len, page->len - page->offset);
80
81 src = page->read_buf ? page->read_buf : page->buf;
82
83 memcpy (dst, src + page->offset, bytes_read);
84
85 page->offset += bytes_read;
86
87 RETURN (bytes_read);
88 }
89
90
91 /**
92 * _mongoc_gridfs_file_page_write:
93 *
94 * Write to a page.
95 *
96 * Writes are copy-on-write with regards to the buffer that was passed to the
97 * mongoc_gridfs_file_page_t during construction. In other words, the first
98 * write allocates a large enough buffer for file->chunk_size, which becomes
99 * authoritative from then on.
100 *
101 * A write of zero bytes will trigger the copy-on-write mechanism.
102 */
103 int32_t
_mongoc_gridfs_file_page_write(mongoc_gridfs_file_page_t * page,const void * src,uint32_t len)104 _mongoc_gridfs_file_page_write (mongoc_gridfs_file_page_t *page,
105 const void *src,
106 uint32_t len)
107 {
108 int bytes_written;
109
110 ENTRY;
111
112 BSON_ASSERT (page);
113 BSON_ASSERT (src);
114
115 bytes_written = BSON_MIN (len, page->chunk_size - page->offset);
116
117 if (!page->buf) {
118 page->buf = (uint8_t *) bson_malloc (page->chunk_size);
119 memcpy (
120 page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len));
121 }
122
123 /* Copy bytes and adjust the page position */
124 memcpy (page->buf + page->offset, src, bytes_written);
125 page->offset += bytes_written;
126 page->len = BSON_MAX (page->offset, page->len);
127
128 /* Don't use the old read buffer, which is no longer current */
129 page->read_buf = page->buf;
130
131 RETURN (bytes_written);
132 }
133
134
135 /**
136 * _mongoc_gridfs_file_page_memset0:
137 *
138 * Write zeros to a page, starting from the page's current position. Up to
139 * `len` bytes will be set to zero or until the page is full, whichever
140 * comes first.
141 *
142 * Like _mongoc_gridfs_file_page_write, operations are copy-on-write with
143 * regards to the page buffer.
144 *
145 * Returns:
146 * Number of bytes set.
147 */
148 uint32_t
_mongoc_gridfs_file_page_memset0(mongoc_gridfs_file_page_t * page,uint32_t len)149 _mongoc_gridfs_file_page_memset0 (mongoc_gridfs_file_page_t *page, uint32_t len)
150 {
151 uint32_t bytes_set;
152
153 ENTRY;
154
155 BSON_ASSERT (page);
156
157 bytes_set = BSON_MIN (page->chunk_size - page->offset, len);
158
159 if (!page->buf) {
160 page->buf = (uint8_t *) bson_malloc0 (page->chunk_size);
161 memcpy (
162 page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len));
163 }
164
165 /* Set bytes and adjust the page position */
166 memset (page->buf + page->offset, '\0', bytes_set);
167 page->offset += bytes_set;
168 page->len = BSON_MAX (page->offset, page->len);
169
170 /* Don't use the old read buffer, which is no longer current */
171 page->read_buf = page->buf;
172
173 RETURN (bytes_set);
174 }
175
176
177 const uint8_t *
_mongoc_gridfs_file_page_get_data(mongoc_gridfs_file_page_t * page)178 _mongoc_gridfs_file_page_get_data (mongoc_gridfs_file_page_t *page)
179 {
180 ENTRY;
181
182 BSON_ASSERT (page);
183
184 RETURN (page->buf ? page->buf : page->read_buf);
185 }
186
187
188 uint32_t
_mongoc_gridfs_file_page_get_len(mongoc_gridfs_file_page_t * page)189 _mongoc_gridfs_file_page_get_len (mongoc_gridfs_file_page_t *page)
190 {
191 ENTRY;
192
193 BSON_ASSERT (page);
194
195 RETURN (page->len);
196 }
197
198
199 uint32_t
_mongoc_gridfs_file_page_tell(mongoc_gridfs_file_page_t * page)200 _mongoc_gridfs_file_page_tell (mongoc_gridfs_file_page_t *page)
201 {
202 ENTRY;
203
204 BSON_ASSERT (page);
205
206 RETURN (page->offset);
207 }
208
209
210 bool
_mongoc_gridfs_file_page_is_dirty(mongoc_gridfs_file_page_t * page)211 _mongoc_gridfs_file_page_is_dirty (mongoc_gridfs_file_page_t *page)
212 {
213 ENTRY;
214
215 BSON_ASSERT (page);
216
217 RETURN (page->buf ? 1 : 0);
218 }
219
220
221 void
_mongoc_gridfs_file_page_destroy(mongoc_gridfs_file_page_t * page)222 _mongoc_gridfs_file_page_destroy (mongoc_gridfs_file_page_t *page)
223 {
224 ENTRY;
225
226 if (page->buf) {
227 bson_free (page->buf);
228 }
229
230 bson_free (page);
231
232 EXIT;
233 }
234