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 extern "C" int CPL_DLL GDALIsInGlobalDestructor(void);
42
43 #ifdef H5FD_FEAT_SUPPORTS_SWMR_IO
44 #define HDF5_1_10_OR_LATER
45 #endif
46
47 static std::mutex gMutex;
48 static hid_t hFileDriver = -1;
49
50 static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags, hid_t fapl_id,
51 haddr_t maxaddr);
52 static herr_t HDF5_vsil_close(H5FD_t *_file);
53 static herr_t HDF5_vsil_query(const H5FD_t *_f1, unsigned long *flags);
54 static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
55 static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
56 static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file
57 #ifdef HDF5_1_10_OR_LATER
58 , H5FD_mem_t type
59 #endif
60 );
61 static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
62 haddr_t addr, size_t size, void *buf);
63 static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
64 haddr_t addr, size_t size, const void *buf);
65 static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
66
67 static hid_t HDF5VFLGetFileDriver();
68 static void HDF5VFLUnloadFileDriver();
69
70 #define MAXADDR (((haddr_t)1<<(8*sizeof(haddr_t)-1))-1)
71
72 /* See https://support.hdfgroup.org/HDF5/doc/TechNotes/VFL.html */
73 static const H5FD_class_t HDF5_vsil_g = {
74 "vsil", /* name */
75 MAXADDR, /* maxaddr */
76 H5F_CLOSE_WEAK, /* fc_degree */
77 #ifdef HDF5_1_10_OR_LATER
78 nullptr, /* terminate */
79 #endif
80 nullptr, /* sb_size */
81 nullptr, /* sb_encode */
82 nullptr, /* sb_decode */
83 0, /* fapl_size */
84 nullptr, /* fapl_get */
85 nullptr, /* fapl_copy */
86 nullptr, /* fapl_free */
87 0, /* dxpl_size */
88 nullptr, /* dxpl_copy */
89 nullptr, /* dxpl_free */
90 HDF5_vsil_open, /* open */
91 HDF5_vsil_close, /* close */
92 nullptr, /* cmp */
93 HDF5_vsil_query, /* query */
94 nullptr, /* get_type_map */
95 nullptr, /* alloc */
96 nullptr, /* free */
97 HDF5_vsil_get_eoa, /* get_eoa */
98 HDF5_vsil_set_eoa, /* set_eoa */
99 HDF5_vsil_get_eof, /* get_eof */
100 nullptr, /* get_handle */
101 HDF5_vsil_read, /* read */
102 HDF5_vsil_write, /* write */
103 nullptr, /* flush */
104 HDF5_vsil_truncate, /* truncate */
105 nullptr, /* lock */
106 nullptr, /* unlock */
107 H5FD_FLMAP_DICHOTOMY /* fl_map */
108 };
109
110 typedef struct HDF5_vsil_t {
111 H5FD_t pub; /* must be first */
112 VSILFILE *fp = nullptr;
113 haddr_t eoa = 0;
114 haddr_t eof = 0;
115 } HDF5_vsil_t;
116
HDF5_vsil_open(const char * name,unsigned flags,hid_t,haddr_t)117 static H5FD_t *HDF5_vsil_open(const char *name, unsigned flags,
118 hid_t /*fapl_id*/, haddr_t /*maxaddr*/)
119 {
120 const char* openFlags = "rb";
121 if( (H5F_ACC_RDWR & flags) )
122 openFlags = "rb+";
123 if( (H5F_ACC_TRUNC & flags) || (H5F_ACC_CREAT & flags) )
124 openFlags = "wb+";
125
126 VSILFILE* fp = VSIFOpenL(name, openFlags);
127 if( !fp )
128 {
129 return nullptr;
130 }
131 if( (H5F_ACC_TRUNC & flags) )
132 {
133 VSIFTruncateL(fp, 0);
134 }
135
136 HDF5_vsil_t* fh = new HDF5_vsil_t;
137 memset(&fh->pub, 0, sizeof(fh->pub));
138 if( !fh )
139 {
140 VSIFCloseL(fp);
141 return nullptr;
142 }
143 fh->fp = fp;
144
145 VSIFSeekL(fh->fp, 0, SEEK_END);
146 fh->eof = static_cast<haddr_t>(VSIFTellL(fh->fp));
147
148 return reinterpret_cast<H5FD_t*>(fh);
149 }
150
HDF5_vsil_close(H5FD_t * _file)151 static herr_t HDF5_vsil_close(H5FD_t *_file)
152 {
153 HDF5_vsil_t* fh = reinterpret_cast<HDF5_vsil_t*>(_file);
154 int ret = VSIFCloseL(fh->fp);
155 delete fh;
156 return ret;
157 }
158
HDF5_vsil_query(const H5FD_t *,unsigned long * flags)159 static herr_t HDF5_vsil_query(const H5FD_t *, unsigned long *flags /* out */)
160 {
161 *flags = H5FD_FEAT_AGGREGATE_METADATA |
162 H5FD_FEAT_ACCUMULATE_METADATA |
163 H5FD_FEAT_DATA_SIEVE |
164 H5FD_FEAT_AGGREGATE_SMALLDATA;
165 return 0;
166 }
167
HDF5_vsil_get_eoa(const H5FD_t * _file,H5FD_mem_t)168 static haddr_t HDF5_vsil_get_eoa(const H5FD_t *_file, H5FD_mem_t /*type*/)
169 {
170 const HDF5_vsil_t* fh = reinterpret_cast<const HDF5_vsil_t*>(_file);
171 return fh->eoa;
172 }
173
HDF5_vsil_set_eoa(H5FD_t * _file,H5FD_mem_t,haddr_t addr)174 static herr_t HDF5_vsil_set_eoa(H5FD_t *_file, H5FD_mem_t /*type*/,
175 haddr_t addr)
176 {
177 HDF5_vsil_t* fh = reinterpret_cast<HDF5_vsil_t*>(_file);
178 fh->eoa = addr;
179 return 0;
180 }
181
HDF5_vsil_get_eof(const H5FD_t * _file,H5FD_mem_t)182 static haddr_t HDF5_vsil_get_eof(const H5FD_t *_file
183 #ifdef HDF5_1_10_OR_LATER
184 , H5FD_mem_t /* type */
185 #endif
186 )
187 {
188 const HDF5_vsil_t* fh = reinterpret_cast<const HDF5_vsil_t*>(_file);
189 return fh->eof;
190 }
191
HDF5_vsil_read(H5FD_t * _file,H5FD_mem_t,hid_t,haddr_t addr,size_t size,void * buf)192 static herr_t HDF5_vsil_read(H5FD_t *_file, H5FD_mem_t /* type */,
193 hid_t /* dxpl_id */,
194 haddr_t addr, size_t size, void *buf /*out*/)
195 {
196 HDF5_vsil_t* fh = reinterpret_cast<HDF5_vsil_t*>(_file);
197 VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
198 return VSIFReadL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
199 }
200
HDF5_vsil_write(H5FD_t * _file,H5FD_mem_t,hid_t,haddr_t addr,size_t size,const void * buf)201 static herr_t HDF5_vsil_write(H5FD_t *_file, H5FD_mem_t /* type */,
202 hid_t /* dxpl_id */,
203 haddr_t addr, size_t size,
204 const void *buf /*out*/)
205 {
206 HDF5_vsil_t* fh = reinterpret_cast<HDF5_vsil_t*>(_file);
207 VSIFSeekL(fh->fp, static_cast<vsi_l_offset>(addr), SEEK_SET);
208 int ret = VSIFWriteL(buf, size, 1, fh->fp) == 1 ? 0 : -1;
209 fh->eof = std::max(fh->eof, static_cast<haddr_t>(VSIFTellL(fh->fp)));
210 return ret;
211 }
212
HDF5_vsil_truncate(H5FD_t * _file,hid_t,hbool_t)213 static herr_t HDF5_vsil_truncate(H5FD_t *_file, hid_t /* dxpl_id*/,
214 hbool_t /*closing*/)
215 {
216 HDF5_vsil_t* fh = reinterpret_cast<HDF5_vsil_t*>(_file);
217 if(fh->eoa != fh->eof)
218 {
219 if( VSIFTruncateL(fh->fp, fh->eoa) < 0 )
220 {
221 return -1;
222 }
223 fh->eof = fh->eoa;
224 }
225 return 0;
226 }
227
228 /************************************************************************/
229 /* HDF5VFLGetFileDriver() */
230 /************************************************************************/
231
HDF5VFLGetFileDriver()232 static hid_t HDF5VFLGetFileDriver()
233 {
234 std::lock_guard<std::mutex> oLock(gMutex);
235 if( hFileDriver < 0 )
236 {
237 hFileDriver = H5FDregister(&HDF5_vsil_g);
238 #if H5E_auto_t_vers == 2
239 // also, don't print error messages from KEA driver.
240 // (which uses H5E_auto_t_vers=2 - the default, hdf uses 1 for some reason).
241 // These tend to be meaningless - ie no GCP's found etc.
242 // They didn't seem to be shown when we didn't use the VFL layer
243 // - maybe VFL turns them on?
244 H5Eset_auto(H5E_DEFAULT, nullptr, nullptr);
245 #endif
246 }
247 return hFileDriver;
248 }
249
250 /************************************************************************/
251 /* HDF5VFLUnloadFileDriver() */
252 /************************************************************************/
253
HDF5VFLUnloadFileDriver()254 static void HDF5VFLUnloadFileDriver()
255 {
256 if( !GDALIsInGlobalDestructor() )
257 {
258 std::lock_guard<std::mutex> oLock(gMutex);
259 if( hFileDriver >= 0 )
260 {
261 H5FDunregister(hFileDriver);
262 hFileDriver = -1;
263 }
264 }
265 }
266
267 #endif /* HDF5VFL_H_INCLUDED_ */
268