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 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : // This file contains the Virtual File Layer implementation that calls through
14 : // to the VSI functions and should be included by HDF5 based drivers that wish
15 : // to use the VFL for /vsi file system support.
16 :
17 : #ifndef HDF5VFL_H_INCLUDED_
18 : #define HDF5VFL_H_INCLUDED_
19 :
20 : #include "cpl_port.h"
21 :
22 : #include <algorithm>
23 : #include <mutex>
24 :
25 : #ifdef H5FD_FEAT_MEMMANAGE
26 : #define HDF5_1_13_OR_LATER
27 : #endif
28 :
29 : // HDF5 >= 1.13.2
30 : #ifdef H5FD_CLASS_VERSION
31 : #if H5FD_CLASS_VERSION != 1
32 : #error \
33 : "HDF5_vsil_g needs to be adapted to the new layout of H5FD_class_t. Look at ${hdf5_prefix}/include/H5FDdevelop.h"
34 : #endif
35 : #endif
36 :
37 : static std::mutex gMutex;
38 : static hid_t hFileDriver = -1;
39 :
40 : static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags, hid_t fapl_id,
41 : haddr_t maxaddr);
42 : static herr_t HDF5_vsil_close(H5FD_t *_file);
43 : static herr_t HDF5_vsil_query(const H5FD_t *_f1, unsigned long *flags);
44 : static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
45 : static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
46 : static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file, H5FD_mem_t type);
47 : static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
48 : haddr_t addr, size_t size, void *buf);
49 : static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
50 : haddr_t addr, size_t size, const void *buf);
51 : static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
52 :
53 : static hid_t HDF5VFLGetFileDriver();
54 : static void HDF5VFLUnloadFileDriver();
55 :
56 : #define MAXADDR (((haddr_t)1 << (8 * sizeof(haddr_t) - 1)) - 1)
57 :
58 : /* See https://support.hdfgroup.org/HDF5/doc/TechNotes/VFL.html */
59 : static const H5FD_class_t HDF5_vsil_g = {
60 : #ifdef H5FD_CLASS_VERSION
61 : H5FD_CLASS_VERSION,
62 : #endif
63 : #ifdef HDF5_1_13_OR_LATER
64 : /* value: 513 has been reserved with hdfgroup and is registered at:
65 : * https://portal.hdfgroup.org/pages/viewpage.action?pageId=74188097 */
66 : (H5FD_class_value_t)(513),
67 : #endif
68 : "vsil", /* name */
69 : MAXADDR, /* maxaddr */
70 : H5F_CLOSE_WEAK, /* fc_degree */
71 : nullptr, /* terminate */
72 : nullptr, /* sb_size */
73 : nullptr, /* sb_encode */
74 : nullptr, /* sb_decode */
75 : 0, /* fapl_size */
76 : nullptr, /* fapl_get */
77 : nullptr, /* fapl_copy */
78 : nullptr, /* fapl_free */
79 : 0, /* dxpl_size */
80 : nullptr, /* dxpl_copy */
81 : nullptr, /* dxpl_free */
82 : HDF5_vsil_open, /* open */
83 : HDF5_vsil_close, /* close */
84 : nullptr, /* cmp */
85 : HDF5_vsil_query, /* query */
86 : nullptr, /* get_type_map */
87 : nullptr, /* alloc */
88 : nullptr, /* free */
89 : HDF5_vsil_get_eoa, /* get_eoa */
90 : HDF5_vsil_set_eoa, /* set_eoa */
91 : HDF5_vsil_get_eof, /* get_eof */
92 : nullptr, /* get_handle */
93 : HDF5_vsil_read, /* read */
94 : HDF5_vsil_write, /* write */
95 : #if H5FD_CLASS_VERSION == 1
96 : nullptr, /* read_vector */
97 : nullptr, /* write_vector */
98 : nullptr, /* read_selection */
99 : nullptr, /* write_selection */
100 : #endif
101 : nullptr, /* flush */
102 : HDF5_vsil_truncate, /* truncate */
103 : nullptr, /* lock */
104 : nullptr, /* unlock */
105 : #ifdef HDF5_1_13_OR_LATER
106 : nullptr, /* del */
107 : nullptr, /* ctl */
108 : #endif
109 : H5FD_FLMAP_DICHOTOMY /* fl_map */
110 : };
111 :
112 : typedef struct HDF5_vsil_t
113 : {
114 : H5FD_t pub; /* must be first */
115 : VSILFILE *fp = nullptr;
116 : haddr_t eoa = 0;
117 : haddr_t eof = 0;
118 : } HDF5_vsil_t;
119 :
120 561 : static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags,
121 : hid_t /*fapl_id*/, haddr_t /*maxaddr*/)
122 : {
123 561 : const char *openFlags = "rb";
124 561 : if ((H5F_ACC_RDWR & flags))
125 174 : openFlags = "rb+";
126 561 : if ((H5F_ACC_TRUNC & flags) || (H5F_ACC_CREAT & flags))
127 121 : openFlags = "wb+";
128 :
129 561 : VSILFILE *fp = VSIFOpenL(name, openFlags);
130 561 : if (!fp)
131 : {
132 4 : return nullptr;
133 : }
134 557 : if ((H5F_ACC_TRUNC & flags))
135 : {
136 118 : VSIFTruncateL(fp, 0);
137 : }
138 :
139 557 : HDF5_vsil_t *fh = new HDF5_vsil_t;
140 557 : memset(&fh->pub, 0, sizeof(fh->pub));
141 557 : if (!fh)
142 : {
143 0 : VSIFCloseL(fp);
144 0 : return nullptr;
145 : }
146 557 : fh->fp = fp;
147 :
148 557 : VSIFSeekL(fh->fp, 0, SEEK_END);
149 557 : fh->eof = static_cast<haddr_t>(VSIFTellL(fh->fp));
150 :
151 557 : return reinterpret_cast<H5FD_t *>(fh);
152 : }
153 :
154 557 : static herr_t HDF5_vsil_close(H5FD_t *_file)
155 : {
156 557 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
157 557 : int ret = VSIFCloseL(fh->fp);
158 557 : delete fh;
159 557 : return ret;
160 : }
161 :
162 1923 : static herr_t HDF5_vsil_query(const H5FD_t *, unsigned long *flags /* out */)
163 : {
164 1923 : *flags = H5FD_FEAT_AGGREGATE_METADATA | H5FD_FEAT_ACCUMULATE_METADATA |
165 : H5FD_FEAT_DATA_SIEVE | H5FD_FEAT_AGGREGATE_SMALLDATA;
166 1923 : return 0;
167 : }
168 :
169 76992 : static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t /*type*/)
170 : {
171 76992 : const HDF5_vsil_t *fh = reinterpret_cast<const HDF5_vsil_t *>(_file);
172 76992 : return fh->eoa;
173 : }
174 :
175 3923 : static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t /*type*/,
176 : haddr_t addr)
177 : {
178 3923 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
179 3923 : fh->eoa = addr;
180 3923 : return 0;
181 : }
182 :
183 1874 : static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file, H5FD_mem_t /* type */
184 : )
185 : {
186 1874 : const HDF5_vsil_t *fh = reinterpret_cast<const HDF5_vsil_t *>(_file);
187 1874 : return fh->eof;
188 : }
189 :
190 24788 : static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t /* type */,
191 : hid_t /* dxpl_id */, haddr_t addr, size_t size,
192 : void *buf /*out*/)
193 : {
194 24788 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
195 24788 : VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
196 24788 : return VSIFReadL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
197 : }
198 :
199 4659 : static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t /* type */,
200 : hid_t /* dxpl_id */, haddr_t addr, size_t size,
201 : const void *buf /*out*/)
202 : {
203 4659 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
204 4659 : VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
205 4659 : int ret = VSIFWriteL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
206 4659 : fh->eof = std::max(fh->eof, static_cast<haddr_t>(VSIFTellL(fh->fp)));
207 4659 : return ret;
208 : }
209 :
210 902 : static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t /* dxpl_id*/,
211 : hbool_t /*closing*/)
212 : {
213 902 : HDF5_vsil_t *fh = reinterpret_cast<HDF5_vsil_t *>(_file);
214 902 : if (fh->eoa != fh->eof)
215 : {
216 4 : if (VSIFTruncateL(fh->fp, fh->eoa) < 0)
217 : {
218 0 : return -1;
219 : }
220 4 : fh->eof = fh->eoa;
221 : }
222 902 : return 0;
223 : }
224 :
225 : /************************************************************************/
226 : /* HDF5VFLGetFileDriver() */
227 : /************************************************************************/
228 :
229 413 : static hid_t HDF5VFLGetFileDriver()
230 : {
231 413 : std::lock_guard<std::mutex> oLock(gMutex);
232 413 : if (hFileDriver < 0)
233 : {
234 4 : hFileDriver = H5FDregister(&HDF5_vsil_g);
235 : #if H5E_auto_t_vers == 2
236 : // also, don't print error messages from KEA driver.
237 : // (which uses H5E_auto_t_vers=2 - the default, hdf uses 1 for some
238 : // reason). These tend to be meaningless - ie no GCP's found etc. They
239 : // didn't seem to be shown when we didn't use the VFL layer
240 : // - maybe VFL turns them on?
241 1 : H5Eset_auto(H5E_DEFAULT, nullptr, nullptr);
242 : #endif
243 : }
244 826 : return hFileDriver;
245 : }
246 :
247 : /************************************************************************/
248 : /* HDF5VFLUnloadFileDriver() */
249 : /************************************************************************/
250 :
251 41 : static void HDF5VFLUnloadFileDriver()
252 : {
253 : {
254 82 : std::lock_guard<std::mutex> oLock(gMutex);
255 41 : if (hFileDriver >= 0)
256 : {
257 1 : H5FDunregister(hFileDriver);
258 1 : hFileDriver = -1;
259 : }
260 : }
261 41 : }
262 :
263 : #endif /* HDF5VFL_H_INCLUDED_ */
|