Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Hierarchical Data Format Release 5 (HDF5)
4 : * Authors: Denis Nadeau <denis.nadeau@gmail.com>
5 : * Sam Gillingham <gillingham.sam@gmail.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2008-2018, Even Rouault <even.rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : // This file contains the Virtual File Layer implementation that calls through
30 : // to the VSI functions and should be included by HDF5 based drivers that wish
31 : // to use the VFL for /vsi file system support.
32 :
33 : #ifndef HDF5VFL_H_INCLUDED_
34 : #define HDF5VFL_H_INCLUDED_
35 :
36 : #include "cpl_port.h"
37 :
38 : #include <algorithm>
39 : #include <mutex>
40 :
41 : #ifdef H5FD_FEAT_MEMMANAGE
42 : #define HDF5_1_13_OR_LATER
43 : #endif
44 :
45 : // HDF5 >= 1.13.2
46 : #ifdef H5FD_CLASS_VERSION
47 : #if H5FD_CLASS_VERSION != 1
48 : #error \
49 : "HDF5_vsil_g needs to be adapted to the new layout of H5FD_class_t. Look at ${hdf5_prefix}/include/H5FDdevelop.h"
50 : #endif
51 : #endif
52 :
53 : static std::mutex gMutex;
54 : static hid_t hFileDriver = -1;
55 :
56 : static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags, hid_t fapl_id,
57 : haddr_t maxaddr);
58 : static herr_t HDF5_vsil_close(H5FD_t *_file);
59 : static herr_t HDF5_vsil_query(const H5FD_t *_f1, unsigned long *flags);
60 : static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
61 : static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
62 : static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file, H5FD_mem_t type);
63 : static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
64 : haddr_t addr, size_t size, void *buf);
65 : static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
66 : haddr_t addr, size_t size, const void *buf);
67 : static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
68 :
69 : static hid_t HDF5VFLGetFileDriver();
70 : static void HDF5VFLUnloadFileDriver();
71 :
72 : #define MAXADDR (((haddr_t)1 << (8 * sizeof(haddr_t) - 1)) - 1)
73 :
74 : /* See https://support.hdfgroup.org/HDF5/doc/TechNotes/VFL.html */
75 : static const H5FD_class_t HDF5_vsil_g = {
76 : #ifdef H5FD_CLASS_VERSION
77 : H5FD_CLASS_VERSION,
78 : #endif
79 : #ifdef HDF5_1_13_OR_LATER
80 : /* value: 513 has been reserved with hdfgroup and is registered at:
81 : * https://portal.hdfgroup.org/pages/viewpage.action?pageId=74188097 */
82 : (H5FD_class_value_t)(513),
83 : #endif
84 : "vsil", /* name */
85 : MAXADDR, /* maxaddr */
86 : H5F_CLOSE_WEAK, /* fc_degree */
87 : nullptr, /* terminate */
88 : nullptr, /* sb_size */
89 : nullptr, /* sb_encode */
90 : nullptr, /* sb_decode */
91 : 0, /* fapl_size */
92 : nullptr, /* fapl_get */
93 : nullptr, /* fapl_copy */
94 : nullptr, /* fapl_free */
95 : 0, /* dxpl_size */
96 : nullptr, /* dxpl_copy */
97 : nullptr, /* dxpl_free */
98 : HDF5_vsil_open, /* open */
99 : HDF5_vsil_close, /* close */
100 : nullptr, /* cmp */
101 : HDF5_vsil_query, /* query */
102 : nullptr, /* get_type_map */
103 : nullptr, /* alloc */
104 : nullptr, /* free */
105 : HDF5_vsil_get_eoa, /* get_eoa */
106 : HDF5_vsil_set_eoa, /* set_eoa */
107 : HDF5_vsil_get_eof, /* get_eof */
108 : nullptr, /* get_handle */
109 : HDF5_vsil_read, /* read */
110 : HDF5_vsil_write, /* write */
111 : #if H5FD_CLASS_VERSION == 1
112 : nullptr, /* read_vector */
113 : nullptr, /* write_vector */
114 : nullptr, /* read_selection */
115 : nullptr, /* write_selection */
116 : #endif
117 : nullptr, /* flush */
118 : HDF5_vsil_truncate, /* truncate */
119 : nullptr, /* lock */
120 : nullptr, /* unlock */
121 : #ifdef HDF5_1_13_OR_LATER
122 : nullptr, /* del */
123 : nullptr, /* ctl */
124 : #endif
125 : H5FD_FLMAP_DICHOTOMY /* fl_map */
126 : };
127 :
128 : typedef struct HDF5_vsil_t
129 : {
130 : H5FD_t pub; /* must be first */
131 : VSILFILE *fp = nullptr;
132 : haddr_t eoa = 0;
133 : haddr_t eof = 0;
134 : } HDF5_vsil_t;
135 :
136 544 : static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags,
137 : hid_t /*fapl_id*/, haddr_t /*maxaddr*/)
138 : {
139 544 : const char *openFlags = "rb";
140 544 : if ((H5F_ACC_RDWR & flags))
141 174 : openFlags = "rb+";
142 544 : if ((H5F_ACC_TRUNC & flags) || (H5F_ACC_CREAT & flags))
143 121 : openFlags = "wb+";
144 :
145 544 : VSILFILE *fp = VSIFOpenL(name, openFlags);
146 544 : if (!fp)
147 : {
148 4 : return nullptr;
149 : }
150 540 : if ((H5F_ACC_TRUNC & flags))
151 : {
152 118 : VSIFTruncateL(fp, 0);
153 : }
154 :
155 540 : HDF5_vsil_t *fh = new HDF5_vsil_t;
156 540 : memset(&fh->pub, 0, sizeof(fh->pub));
157 540 : if (!fh)
158 : {
159 0 : VSIFCloseL(fp);
160 0 : return nullptr;
161 : }
162 540 : fh->fp = fp;
163 :
164 540 : VSIFSeekL(fh->fp, 0, SEEK_END);
165 540 : fh->eof = static_cast<haddr_t>(VSIFTellL(fh->fp));
166 :
167 540 : return reinterpret_cast<H5FD_t *>(fh);
168 : }
169 :
170 540 : static herr_t HDF5_vsil_close(H5FD_t *_file)
171 : {
172 540 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
173 540 : int ret = VSIFCloseL(fh->fp);
174 540 : delete fh;
175 540 : return ret;
176 : }
177 :
178 1889 : static herr_t HDF5_vsil_query(const H5FD_t *, unsigned long *flags /* out */)
179 : {
180 1889 : *flags = H5FD_FEAT_AGGREGATE_METADATA | H5FD_FEAT_ACCUMULATE_METADATA |
181 : H5FD_FEAT_DATA_SIEVE | H5FD_FEAT_AGGREGATE_SMALLDATA;
182 1889 : return 0;
183 : }
184 :
185 76118 : static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t /*type*/)
186 : {
187 76118 : const HDF5_vsil_t *fh = reinterpret_cast<const HDF5_vsil_t *>(_file);
188 76118 : return fh->eoa;
189 : }
190 :
191 3847 : static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t /*type*/,
192 : haddr_t addr)
193 : {
194 3847 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
195 3847 : fh->eoa = addr;
196 3847 : return 0;
197 : }
198 :
199 1806 : static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file, H5FD_mem_t /* type */
200 : )
201 : {
202 1806 : const HDF5_vsil_t *fh = reinterpret_cast<const HDF5_vsil_t *>(_file);
203 1806 : return fh->eof;
204 : }
205 :
206 24327 : static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t /* type */,
207 : hid_t /* dxpl_id */, haddr_t addr, size_t size,
208 : void *buf /*out*/)
209 : {
210 24327 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
211 24327 : VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
212 24327 : return VSIFReadL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
213 : }
214 :
215 4659 : static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t /* type */,
216 : hid_t /* dxpl_id */, haddr_t addr, size_t size,
217 : const void *buf /*out*/)
218 : {
219 4659 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
220 4659 : VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
221 4659 : int ret = VSIFWriteL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
222 4659 : fh->eof = std::max(fh->eof, static_cast<haddr_t>(VSIFTellL(fh->fp)));
223 4659 : return ret;
224 : }
225 :
226 902 : static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t /* dxpl_id*/,
227 : hbool_t /*closing*/)
228 : {
229 902 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
230 902 : if (fh->eoa != fh->eof)
231 : {
232 4 : if (VSIFTruncateL(fh->fp, fh->eoa) < 0)
233 : {
234 0 : return -1;
235 : }
236 4 : fh->eof = fh->eoa;
237 : }
238 902 : return 0;
239 : }
240 :
241 : /************************************************************************/
242 : /* HDF5VFLGetFileDriver() */
243 : /************************************************************************/
244 :
245 396 : static hid_t HDF5VFLGetFileDriver()
246 : {
247 396 : std::lock_guard<std::mutex> oLock(gMutex);
248 396 : if (hFileDriver < 0)
249 : {
250 4 : hFileDriver = H5FDregister(&HDF5_vsil_g);
251 : #if H5E_auto_t_vers == 2
252 : // also, don't print error messages from KEA driver.
253 : // (which uses H5E_auto_t_vers=2 - the default, hdf uses 1 for some
254 : // reason). These tend to be meaningless - ie no GCP's found etc. They
255 : // didn't seem to be shown when we didn't use the VFL layer
256 : // - maybe VFL turns them on?
257 1 : H5Eset_auto(H5E_DEFAULT, nullptr, nullptr);
258 : #endif
259 : }
260 792 : return hFileDriver;
261 : }
262 :
263 : /************************************************************************/
264 : /* HDF5VFLUnloadFileDriver() */
265 : /************************************************************************/
266 :
267 34 : static void HDF5VFLUnloadFileDriver()
268 : {
269 : {
270 68 : std::lock_guard<std::mutex> oLock(gMutex);
271 34 : if (hFileDriver >= 0)
272 : {
273 1 : H5FDunregister(hFileDriver);
274 1 : hFileDriver = -1;
275 : }
276 : }
277 34 : }
278 :
279 : #endif /* HDF5VFL_H_INCLUDED_ */
|