Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5Olink.c |
16 | | * |
17 | | * Purpose: Link messages |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | #define H5L_FRIEND /*suppress error about including H5Lpkg */ |
23 | | #include "H5Omodule.h" /* This source code file is part of the H5O module */ |
24 | | |
25 | | #include "H5private.h" /* Generic Functions */ |
26 | | #include "H5Eprivate.h" /* Error handling */ |
27 | | #include "H5FLprivate.h" /* Free lists */ |
28 | | #include "H5Iprivate.h" /* IDs */ |
29 | | #include "H5Lpkg.h" /* Links */ |
30 | | #include "H5MMprivate.h" /* Memory management */ |
31 | | #include "H5Opkg.h" /* Object headers */ |
32 | | |
33 | | /* PRIVATE PROTOTYPES */ |
34 | | static void *H5O__link_decode(H5F_t *f, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags, size_t p_size, |
35 | | const uint8_t *p); |
36 | | static herr_t H5O__link_encode(H5F_t *f, bool disable_shared, size_t H5_ATTR_UNUSED p_size, uint8_t *p, |
37 | | const void *_mesg); |
38 | | static void *H5O__link_copy(const void *_mesg, void *_dest); |
39 | | static size_t H5O__link_size(const H5F_t *f, bool disable_shared, const void *_mesg); |
40 | | static herr_t H5O__link_reset(void *_mesg); |
41 | | static herr_t H5O__link_free(void *_mesg); |
42 | | static herr_t H5O__link_pre_copy_file(H5F_t *file_src, const void *mesg_src, bool *deleted, |
43 | | const H5O_copy_t *cpy_info, void *udata); |
44 | | static void *H5O__link_copy_file(H5F_t *file_src, void *native_src, H5F_t *file_dst, bool *recompute_size, |
45 | | unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata); |
46 | | static herr_t H5O__link_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src, H5O_loc_t *dst_oloc, |
47 | | void *mesg_dst, unsigned *mesg_flags, H5O_copy_t *cpy_info); |
48 | | static herr_t H5O__link_debug(H5F_t *f, const void *_mesg, FILE *stream, int indent, int fwidth); |
49 | | |
50 | | /* This message derives from H5O message class */ |
51 | | const H5O_msg_class_t H5O_MSG_LINK[1] = {{ |
52 | | H5O_LINK_ID, /*message id number */ |
53 | | "link", /*message name for debugging */ |
54 | | sizeof(H5O_link_t), /*native message size */ |
55 | | 0, /* messages are shareable? */ |
56 | | H5O__link_decode, /*decode message */ |
57 | | H5O__link_encode, /*encode message */ |
58 | | H5O__link_copy, /*copy the native value */ |
59 | | H5O__link_size, /*size of symbol table entry */ |
60 | | H5O__link_reset, /* reset method */ |
61 | | H5O__link_free, /* free method */ |
62 | | H5O_link_delete, /* file delete method */ |
63 | | NULL, /* link method */ |
64 | | NULL, /*set share method */ |
65 | | NULL, /*can share method */ |
66 | | H5O__link_pre_copy_file, /* pre copy native value to file */ |
67 | | H5O__link_copy_file, /* copy native value to file */ |
68 | | H5O__link_post_copy_file, /* post copy native value to file */ |
69 | | NULL, /* get creation index */ |
70 | | NULL, /* set creation index */ |
71 | | H5O__link_debug /*debug the message */ |
72 | | }}; |
73 | | |
74 | | /* Current version of link information */ |
75 | 39 | #define H5O_LINK_VERSION 1 |
76 | | |
77 | | /* Flags for link flag encoding */ |
78 | 78 | #define H5O_LINK_NAME_SIZE 0x03 /* 2-bit field for size of name length */ |
79 | 78 | #define H5O_LINK_STORE_CORDER 0x04 /* Whether to store creation index */ |
80 | 78 | #define H5O_LINK_STORE_LINK_TYPE 0x08 /* Whether to store non-default link type */ |
81 | 78 | #define H5O_LINK_STORE_NAME_CSET 0x10 /* Whether to store non-default name character set */ |
82 | | #define H5O_LINK_ALL_FLAGS \ |
83 | 39 | (H5O_LINK_NAME_SIZE | H5O_LINK_STORE_CORDER | H5O_LINK_STORE_LINK_TYPE | H5O_LINK_STORE_NAME_CSET) |
84 | | |
85 | | /* Individual definitions of name size values */ |
86 | 0 | #define H5O_LINK_NAME_1 0x00 /* Use 1-byte value for name length */ |
87 | 0 | #define H5O_LINK_NAME_2 0x01 /* Use 2-byte value for name length */ |
88 | 0 | #define H5O_LINK_NAME_4 0x02 /* Use 4-byte value for name length */ |
89 | 0 | #define H5O_LINK_NAME_8 0x03 /* Use 8-byte value for name length */ |
90 | | |
91 | | /* Declare a free list to manage the H5O_link_t struct */ |
92 | | H5FL_DEFINE_STATIC(H5O_link_t); |
93 | | |
94 | | /*------------------------------------------------------------------------- |
95 | | * Function: H5O__link_decode |
96 | | * |
97 | | * Purpose: Decode a message and return a pointer to |
98 | | * a newly allocated one. |
99 | | * |
100 | | * Return: Success: Pointer to new message in native order |
101 | | * Failure: NULL |
102 | | *------------------------------------------------------------------------- |
103 | | */ |
104 | | static void * |
105 | | H5O__link_decode(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags, |
106 | | unsigned H5_ATTR_UNUSED *ioflags, size_t p_size, const uint8_t *p) |
107 | 39 | { |
108 | 39 | H5O_link_t *lnk = NULL; /* Pointer to link message */ |
109 | 39 | size_t len = 0; /* Length of a string in the message */ |
110 | 39 | unsigned char link_flags; /* Flags for encoding link info */ |
111 | 39 | const uint8_t *p_end = p + p_size - 1; /* End of the p buffer */ |
112 | 39 | void *ret_value = NULL; |
113 | | |
114 | 39 | FUNC_ENTER_PACKAGE |
115 | | |
116 | 39 | assert(f); |
117 | 39 | assert(p); |
118 | | |
119 | 39 | if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end)) |
120 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
121 | 39 | if (*p++ != H5O_LINK_VERSION) |
122 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message"); |
123 | | |
124 | | /* Allocate space for message */ |
125 | 39 | if (NULL == (lnk = H5FL_CALLOC(H5O_link_t))) |
126 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
127 | | |
128 | | /* Get the encoding flags for the link */ |
129 | 39 | if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end)) |
130 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
131 | 39 | link_flags = *p++; |
132 | 39 | if (link_flags & ~H5O_LINK_ALL_FLAGS) |
133 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message"); |
134 | | |
135 | | /* Check for non-default link type */ |
136 | 39 | if (link_flags & H5O_LINK_STORE_LINK_TYPE) { |
137 | | /* Get the type of the link */ |
138 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end)) |
139 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
140 | 0 | lnk->type = (H5L_type_t)*p++; |
141 | 0 | if (lnk->type < H5L_TYPE_HARD || lnk->type > H5L_TYPE_MAX) |
142 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad link type"); |
143 | 0 | } |
144 | 39 | else |
145 | 39 | lnk->type = H5L_TYPE_HARD; |
146 | | |
147 | | /* Get the link creation time from the file */ |
148 | 39 | if (link_flags & H5O_LINK_STORE_CORDER) { |
149 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 8, p_end)) |
150 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
151 | 0 | INT64DECODE(p, lnk->corder); |
152 | 0 | lnk->corder_valid = true; |
153 | 0 | } |
154 | 39 | else { |
155 | 39 | lnk->corder = 0; |
156 | 39 | lnk->corder_valid = false; |
157 | 39 | } |
158 | | |
159 | | /* Check for non-default name character set */ |
160 | 39 | if (link_flags & H5O_LINK_STORE_NAME_CSET) { |
161 | | /* Get the link name's character set */ |
162 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end)) |
163 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
164 | 0 | lnk->cset = (H5T_cset_t)*p++; |
165 | 0 | if (lnk->cset < H5T_CSET_ASCII || lnk->cset > H5T_CSET_UTF8) |
166 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad cset type"); |
167 | 0 | } |
168 | 39 | else |
169 | 39 | lnk->cset = H5T_CSET_ASCII; |
170 | | |
171 | | /* Get the length of the link's name */ |
172 | 39 | switch (link_flags & H5O_LINK_NAME_SIZE) { |
173 | 39 | case 0: /* 1 byte size */ |
174 | 39 | if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end)) |
175 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
176 | 39 | len = *p++; |
177 | 39 | break; |
178 | | |
179 | 0 | case 1: /* 2 byte size */ |
180 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end)) |
181 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
182 | 0 | UINT16DECODE(p, len); |
183 | 0 | break; |
184 | | |
185 | 0 | case 2: /* 4 byte size */ |
186 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 4, p_end)) |
187 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
188 | 0 | UINT32DECODE(p, len); |
189 | 0 | break; |
190 | | |
191 | 0 | case 3: /* 8 byte size */ |
192 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 8, p_end)) |
193 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
194 | 0 | UINT64DECODE(p, len); |
195 | 0 | break; |
196 | | |
197 | 0 | default: |
198 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no appropriate size for name length"); |
199 | 39 | } |
200 | 39 | if (len == 0) |
201 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid name length"); |
202 | | |
203 | | /* Get the link's name */ |
204 | 39 | if (H5_IS_BUFFER_OVERFLOW(p, len, p_end)) |
205 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
206 | 39 | if (NULL == (lnk->name = (char *)H5MM_malloc(len + 1))) |
207 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
208 | 39 | H5MM_memcpy(lnk->name, p, len); |
209 | 39 | lnk->name[len] = '\0'; |
210 | 39 | p += len; |
211 | | |
212 | | /* Get the appropriate information for each type of link */ |
213 | 39 | switch (lnk->type) { |
214 | 39 | case H5L_TYPE_HARD: |
215 | | /* Get the address of the object the link points to */ |
216 | 39 | if (H5_IS_BUFFER_OVERFLOW(p, H5F_sizeof_addr(f), p_end)) |
217 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
218 | 39 | H5F_addr_decode(f, &p, &(lnk->u.hard.addr)); |
219 | 39 | break; |
220 | | |
221 | 0 | case H5L_TYPE_SOFT: |
222 | | /* Get the link value */ |
223 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end)) |
224 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
225 | 0 | UINT16DECODE(p, len); |
226 | 0 | if (len == 0) |
227 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid link length"); |
228 | | |
229 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, len, p_end)) |
230 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
231 | 0 | if (NULL == (lnk->u.soft.name = (char *)H5MM_malloc((size_t)len + 1))) |
232 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
233 | 0 | H5MM_memcpy(lnk->u.soft.name, p, len); |
234 | 0 | lnk->u.soft.name[len] = '\0'; |
235 | 0 | p += len; |
236 | 0 | break; |
237 | | |
238 | | /* User-defined links */ |
239 | 0 | case H5L_TYPE_EXTERNAL: |
240 | 0 | case H5L_TYPE_ERROR: |
241 | 0 | case H5L_TYPE_MAX: |
242 | 0 | default: |
243 | 0 | if (lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX) |
244 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown link type"); |
245 | | |
246 | | /* A UD link. Get the user-supplied data */ |
247 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end)) |
248 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
249 | 0 | UINT16DECODE(p, len); |
250 | 0 | if (lnk->type == H5L_TYPE_EXTERNAL && len < 3) |
251 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "external link information length < 3"); |
252 | 0 | lnk->u.ud.size = len; |
253 | 0 | if (len > 0) { |
254 | 0 | if (H5_IS_BUFFER_OVERFLOW(p, len, p_end)) |
255 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
256 | 0 | if (NULL == (lnk->u.ud.udata = H5MM_malloc((size_t)len))) |
257 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
258 | 0 | H5MM_memcpy(lnk->u.ud.udata, p, len); |
259 | 0 | p += len; |
260 | 0 | } |
261 | 0 | else |
262 | 0 | lnk->u.ud.udata = NULL; |
263 | 39 | } |
264 | | |
265 | | /* Set return value */ |
266 | 39 | ret_value = lnk; |
267 | | |
268 | 39 | done: |
269 | 39 | if (!ret_value && lnk) { |
270 | 0 | H5MM_xfree(lnk->name); |
271 | 0 | if (lnk->type == H5L_TYPE_SOFT && lnk->u.soft.name != NULL) |
272 | 0 | H5MM_xfree(lnk->u.soft.name); |
273 | 0 | if (lnk->type >= H5L_TYPE_UD_MIN && lnk->u.ud.size > 0 && lnk->u.ud.udata != NULL) |
274 | 0 | H5MM_xfree(lnk->u.ud.udata); |
275 | 0 | H5FL_FREE(H5O_link_t, lnk); |
276 | 0 | } |
277 | | |
278 | 39 | FUNC_LEAVE_NOAPI(ret_value) |
279 | 39 | } /* end H5O__link_decode() */ |
280 | | |
281 | | /*------------------------------------------------------------------------- |
282 | | * Function: H5O__link_encode |
283 | | * |
284 | | * Purpose: Encodes a link message. |
285 | | * |
286 | | * Return: Non-negative on success/Negative on failure |
287 | | * |
288 | | *------------------------------------------------------------------------- |
289 | | */ |
290 | | static herr_t |
291 | | H5O__link_encode(H5F_t *f, bool H5_ATTR_UNUSED disable_shared, size_t H5_ATTR_UNUSED p_size, uint8_t *p, |
292 | | const void *_mesg) |
293 | 0 | { |
294 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_mesg; |
295 | 0 | uint64_t len; /* Length of a string in the message */ |
296 | 0 | unsigned char link_flags; /* Flags for encoding link info */ |
297 | |
|
298 | 0 | FUNC_ENTER_PACKAGE_NOERR |
299 | | |
300 | | /* check args */ |
301 | 0 | assert(f); |
302 | 0 | assert(p); |
303 | 0 | assert(lnk); |
304 | | |
305 | | /* Get length of link's name */ |
306 | 0 | len = (uint64_t)strlen(lnk->name); |
307 | 0 | assert(len > 0); |
308 | | |
309 | | /* encode */ |
310 | 0 | *p++ = H5O_LINK_VERSION; |
311 | | |
312 | | /* The encoding flags for the link */ |
313 | 0 | if (len > 4294967295) |
314 | 0 | link_flags = H5O_LINK_NAME_8; |
315 | 0 | else if (len > 65535) |
316 | 0 | link_flags = H5O_LINK_NAME_4; |
317 | 0 | else if (len > 255) |
318 | 0 | link_flags = H5O_LINK_NAME_2; |
319 | 0 | else |
320 | 0 | link_flags = H5O_LINK_NAME_1; |
321 | 0 | link_flags = (unsigned char)(link_flags | (lnk->corder_valid ? H5O_LINK_STORE_CORDER : 0)); |
322 | 0 | link_flags = (unsigned char)(link_flags | ((lnk->type != H5L_TYPE_HARD) ? H5O_LINK_STORE_LINK_TYPE : 0)); |
323 | 0 | link_flags = (unsigned char)(link_flags | ((lnk->cset != H5T_CSET_ASCII) ? H5O_LINK_STORE_NAME_CSET : 0)); |
324 | 0 | *p++ = link_flags; |
325 | | |
326 | | /* Store the type of a non-default link */ |
327 | 0 | if (link_flags & H5O_LINK_STORE_LINK_TYPE) |
328 | 0 | *p++ = (uint8_t)lnk->type; |
329 | | |
330 | | /* Store the link creation order in the file, if its valid */ |
331 | 0 | if (lnk->corder_valid) |
332 | 0 | INT64ENCODE(p, lnk->corder); |
333 | | |
334 | | /* Store a non-default link name character set */ |
335 | 0 | if (link_flags & H5O_LINK_STORE_NAME_CSET) |
336 | 0 | *p++ = (uint8_t)lnk->cset; |
337 | | |
338 | | /* Store the link name's length */ |
339 | 0 | switch (link_flags & H5O_LINK_NAME_SIZE) { |
340 | 0 | case 0: /* 1 byte size */ |
341 | 0 | *p++ = (uint8_t)len; |
342 | 0 | break; |
343 | | |
344 | 0 | case 1: /* 2 byte size */ |
345 | 0 | UINT16ENCODE(p, len); |
346 | 0 | break; |
347 | | |
348 | 0 | case 2: /* 4 byte size */ |
349 | 0 | UINT32ENCODE(p, len); |
350 | 0 | break; |
351 | | |
352 | 0 | case 3: /* 8 byte size */ |
353 | 0 | UINT64ENCODE(p, len); |
354 | 0 | break; |
355 | | |
356 | 0 | default: |
357 | 0 | assert(0 && "bad size for name"); |
358 | 0 | } /* end switch */ |
359 | | |
360 | | /* Store the link's name */ |
361 | 0 | H5MM_memcpy(p, lnk->name, (size_t)len); |
362 | 0 | p += len; |
363 | | |
364 | | /* Store the appropriate information for each type of link */ |
365 | 0 | switch (lnk->type) { |
366 | 0 | case H5L_TYPE_HARD: |
367 | | /* Store the address of the object the link points to */ |
368 | 0 | H5F_addr_encode(f, &p, lnk->u.hard.addr); |
369 | 0 | break; |
370 | | |
371 | 0 | case H5L_TYPE_SOFT: |
372 | | /* Store the link value */ |
373 | 0 | len = (uint16_t)strlen(lnk->u.soft.name); |
374 | 0 | assert(len > 0); |
375 | 0 | UINT16ENCODE(p, len); |
376 | 0 | H5MM_memcpy(p, lnk->u.soft.name, (size_t)len); |
377 | 0 | p += len; |
378 | 0 | break; |
379 | | |
380 | | /* User-defined links */ |
381 | 0 | case H5L_TYPE_EXTERNAL: |
382 | 0 | case H5L_TYPE_ERROR: |
383 | 0 | case H5L_TYPE_MAX: |
384 | 0 | default: |
385 | 0 | assert(lnk->type >= H5L_TYPE_UD_MIN && lnk->type <= H5L_TYPE_MAX); |
386 | | |
387 | | /* Store the user-supplied data, however long it is */ |
388 | 0 | len = (uint16_t)lnk->u.ud.size; |
389 | 0 | UINT16ENCODE(p, len); |
390 | 0 | if (len > 0) { |
391 | 0 | H5MM_memcpy(p, lnk->u.ud.udata, (size_t)len); |
392 | 0 | p += len; |
393 | 0 | } |
394 | 0 | break; |
395 | 0 | } /* end switch */ |
396 | | |
397 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
398 | 0 | } /* end H5O__link_encode() */ |
399 | | |
400 | | /*------------------------------------------------------------------------- |
401 | | * Function: H5O__link_copy |
402 | | * |
403 | | * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if |
404 | | * necessary. |
405 | | * |
406 | | * Return: Success: Ptr to _DEST |
407 | | * |
408 | | * Failure: NULL |
409 | | * |
410 | | *------------------------------------------------------------------------- |
411 | | */ |
412 | | static void * |
413 | | H5O__link_copy(const void *_mesg, void *_dest) |
414 | 0 | { |
415 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_mesg; |
416 | 0 | H5O_link_t *dest = (H5O_link_t *)_dest; |
417 | 0 | void *ret_value = NULL; /* Return value */ |
418 | |
|
419 | 0 | FUNC_ENTER_PACKAGE |
420 | | |
421 | | /* Check args */ |
422 | 0 | assert(lnk); |
423 | 0 | if (!dest && NULL == (dest = H5FL_MALLOC(H5O_link_t))) |
424 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
425 | | |
426 | | /* Copy static information */ |
427 | 0 | *dest = *lnk; |
428 | | |
429 | | /* Duplicate the link's name */ |
430 | 0 | assert(lnk->name); |
431 | 0 | if (NULL == (dest->name = H5MM_xstrdup(lnk->name))) |
432 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate link name"); |
433 | | |
434 | | /* Copy other information needed for different link types */ |
435 | 0 | if (lnk->type == H5L_TYPE_SOFT) { |
436 | 0 | if (NULL == (dest->u.soft.name = H5MM_xstrdup(lnk->u.soft.name))) |
437 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate soft link value"); |
438 | 0 | } /* end if */ |
439 | 0 | else if (lnk->type >= H5L_TYPE_UD_MIN) { |
440 | 0 | if (lnk->u.ud.size > 0) { |
441 | 0 | if (NULL == (dest->u.ud.udata = H5MM_malloc(lnk->u.ud.size))) |
442 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
443 | 0 | H5MM_memcpy(dest->u.ud.udata, lnk->u.ud.udata, lnk->u.ud.size); |
444 | 0 | } /* end if */ |
445 | 0 | } /* end if */ |
446 | | |
447 | | /* Set return value */ |
448 | 0 | ret_value = dest; |
449 | |
|
450 | 0 | done: |
451 | 0 | if (NULL == ret_value) |
452 | 0 | if (dest) { |
453 | 0 | if (dest->name && dest->name != lnk->name) |
454 | 0 | dest->name = (char *)H5MM_xfree(dest->name); |
455 | 0 | if (NULL == _dest) |
456 | 0 | dest = H5FL_FREE(H5O_link_t, dest); |
457 | 0 | } /* end if */ |
458 | |
|
459 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
460 | 0 | } /* end H5O__link_copy() */ |
461 | | |
462 | | /*------------------------------------------------------------------------- |
463 | | * Function: H5O__link_size |
464 | | * |
465 | | * Purpose: Returns the size of the raw message in bytes not counting |
466 | | * the message type or size fields, but only the data fields. |
467 | | * This function doesn't take into account alignment. |
468 | | * |
469 | | * Return: Success: Message data size in bytes without alignment. |
470 | | * |
471 | | * Failure: zero |
472 | | * |
473 | | *------------------------------------------------------------------------- |
474 | | */ |
475 | | static size_t |
476 | | H5O__link_size(const H5F_t *f, bool H5_ATTR_UNUSED disable_shared, const void *_mesg) |
477 | 0 | { |
478 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_mesg; |
479 | 0 | uint64_t name_len; /* Length of name */ |
480 | 0 | size_t name_size; /* Size of encoded name length */ |
481 | 0 | size_t ret_value = 0; /* Return value */ |
482 | |
|
483 | 0 | FUNC_ENTER_PACKAGE_NOERR |
484 | | |
485 | | /* Sanity check */ |
486 | 0 | HDcompile_assert(sizeof(uint64_t) >= sizeof(size_t)); |
487 | | |
488 | | /* Get name's length */ |
489 | 0 | name_len = (uint64_t)strlen(lnk->name); |
490 | | |
491 | | /* Determine correct value for name size bits */ |
492 | 0 | if (name_len > 4294967295) |
493 | 0 | name_size = 8; |
494 | 0 | else if (name_len > 65535) |
495 | 0 | name_size = 4; |
496 | 0 | else if (name_len > 255) |
497 | 0 | name_size = 2; |
498 | 0 | else |
499 | 0 | name_size = 1; |
500 | | |
501 | | /* Set return value */ |
502 | 0 | ret_value = 1 + /* Version */ |
503 | 0 | 1 + /* Link encoding flags */ |
504 | 0 | (lnk->type != H5L_TYPE_HARD ? (size_t)1 : 0) + /* Link type */ |
505 | 0 | (lnk->corder_valid ? 8 : 0) + /* Creation order */ |
506 | 0 | (lnk->cset != H5T_CSET_ASCII ? 1 : 0) + /* Character set */ |
507 | 0 | name_size + /* Name length */ |
508 | 0 | name_len; /* Name */ |
509 | | |
510 | | /* Add the appropriate length for each type of link */ |
511 | 0 | switch (lnk->type) { |
512 | 0 | case H5L_TYPE_HARD: |
513 | 0 | ret_value += H5F_SIZEOF_ADDR(f); |
514 | 0 | break; |
515 | | |
516 | 0 | case H5L_TYPE_SOFT: |
517 | 0 | ret_value += 2 + /* Link value length */ |
518 | 0 | strlen(lnk->u.soft.name); /* Link value */ |
519 | 0 | break; |
520 | | |
521 | 0 | case H5L_TYPE_ERROR: |
522 | 0 | case H5L_TYPE_EXTERNAL: |
523 | 0 | case H5L_TYPE_MAX: |
524 | 0 | default: /* Default is user-defined link type */ |
525 | 0 | assert(lnk->type >= H5L_TYPE_UD_MIN); |
526 | 0 | ret_value += 2 + /* User-defined data size */ |
527 | 0 | lnk->u.ud.size; /* User-defined data */ |
528 | 0 | break; |
529 | 0 | } /* end switch */ |
530 | | |
531 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
532 | 0 | } /* end H5O__link_size() */ |
533 | | |
534 | | /*------------------------------------------------------------------------- |
535 | | * Function: H5O__link_reset |
536 | | * |
537 | | * Purpose: Frees resources within a message, but doesn't free |
538 | | * the message itself. |
539 | | * |
540 | | * Return: Non-negative on success/Negative on failure |
541 | | * |
542 | | *------------------------------------------------------------------------- |
543 | | */ |
544 | | static herr_t |
545 | | H5O__link_reset(void *_mesg) |
546 | 407 | { |
547 | 407 | H5O_link_t *lnk = (H5O_link_t *)_mesg; |
548 | | |
549 | 407 | FUNC_ENTER_PACKAGE_NOERR |
550 | | |
551 | 407 | if (lnk) { |
552 | | /* Free information for link (but don't free link pointer) */ |
553 | 407 | if (lnk->type == H5L_TYPE_SOFT) |
554 | 0 | lnk->u.soft.name = (char *)H5MM_xfree(lnk->u.soft.name); |
555 | 407 | else if (lnk->type >= H5L_TYPE_UD_MIN) { |
556 | 0 | if (lnk->u.ud.size > 0) |
557 | 0 | lnk->u.ud.udata = H5MM_xfree(lnk->u.ud.udata); |
558 | 0 | } /* end if */ |
559 | 407 | lnk->name = (char *)H5MM_xfree(lnk->name); |
560 | 407 | } /* end if */ |
561 | | |
562 | 407 | FUNC_LEAVE_NOAPI(SUCCEED) |
563 | 407 | } /* end H5O__link_reset() */ |
564 | | |
565 | | /*------------------------------------------------------------------------- |
566 | | * Function: H5O__link_free |
567 | | * |
568 | | * Purpose: Frees the message contents and the message itself |
569 | | * |
570 | | * Return: Non-negative on success/Negative on failure |
571 | | * |
572 | | *------------------------------------------------------------------------- |
573 | | */ |
574 | | static herr_t |
575 | | H5O__link_free(void *_mesg) |
576 | 27 | { |
577 | 27 | H5O_link_t *lnk = (H5O_link_t *)_mesg; |
578 | | |
579 | 27 | FUNC_ENTER_PACKAGE_NOERR |
580 | | |
581 | 27 | assert(lnk); |
582 | | |
583 | 27 | lnk = H5FL_FREE(H5O_link_t, lnk); |
584 | | |
585 | 27 | FUNC_LEAVE_NOAPI(SUCCEED) |
586 | 27 | } /* end H5O__link_free() */ |
587 | | |
588 | | /*------------------------------------------------------------------------- |
589 | | * Function: H5O_link_delete |
590 | | * |
591 | | * Purpose: Free file space referenced by message |
592 | | * |
593 | | * Return: Non-negative on success/Negative on failure |
594 | | * |
595 | | *------------------------------------------------------------------------- |
596 | | */ |
597 | | herr_t |
598 | | H5O_link_delete(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, void *_mesg) |
599 | 0 | { |
600 | 0 | H5O_link_t *lnk = (H5O_link_t *)_mesg; |
601 | 0 | hid_t file_id = -1; /* ID for the file the link is located in (passed to user callback) */ |
602 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
603 | |
|
604 | 0 | FUNC_ENTER_NOAPI(FAIL) |
605 | | |
606 | | /* check args */ |
607 | 0 | assert(f); |
608 | 0 | assert(lnk); |
609 | | |
610 | | /* Check for adjusting the link count when the link is removed */ |
611 | | /* Adjust the reference count of the object when a hard link is removed */ |
612 | 0 | if (lnk->type == H5L_TYPE_HARD) { |
613 | 0 | H5O_loc_t oloc; |
614 | | |
615 | | /* Construct object location for object, in order to decrement it's ref count */ |
616 | 0 | H5O_loc_reset(&oloc); |
617 | 0 | oloc.file = f; |
618 | 0 | assert(H5_addr_defined(lnk->u.hard.addr)); |
619 | 0 | oloc.addr = lnk->u.hard.addr; |
620 | | |
621 | | /* Decrement the ref count for the object */ |
622 | 0 | if (H5O_link(&oloc, -1) < 0) |
623 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to decrement object link count"); |
624 | 0 | } /* end if */ |
625 | | /* Perform the "delete" callback when a user-defined link is removed */ |
626 | 0 | else if (lnk->type >= H5L_TYPE_UD_MIN) { |
627 | 0 | const H5L_class_t *link_class; /* User-defined link class */ |
628 | | |
629 | | /* Get the link class for this type of link. */ |
630 | 0 | if (NULL == (link_class = H5L_find_class(lnk->type))) |
631 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_NOTREGISTERED, FAIL, "link class not registered"); |
632 | | |
633 | | /* Check for delete callback */ |
634 | 0 | if (link_class->del_func) { |
635 | | /* Get a file ID for the file the link is in */ |
636 | 0 | if ((file_id = H5F_get_id(f)) < 0) |
637 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get file ID"); |
638 | | |
639 | | /* Prepare & restore library for user callback */ |
640 | 0 | H5_BEFORE_USER_CB(FAIL) |
641 | 0 | { |
642 | | /* Call user-defined link's 'delete' callback */ |
643 | 0 | ret_value = (link_class->del_func)(lnk->name, file_id, lnk->u.ud.udata, lnk->u.ud.size); |
644 | 0 | } |
645 | 0 | H5_AFTER_USER_CB(FAIL) |
646 | 0 | if (ret_value < 0) |
647 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "link deletion callback returned failure"); |
648 | 0 | } /* end if */ |
649 | 0 | } /* end if */ |
650 | | |
651 | 0 | done: |
652 | | /* Release the file ID */ |
653 | 0 | if (file_id > 0 && H5I_dec_ref(file_id) < 0) |
654 | 0 | HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "can't close file"); |
655 | |
|
656 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
657 | 0 | } /* end H5O_link_delete() */ |
658 | | |
659 | | /*------------------------------------------------------------------------- |
660 | | * Function: H5O__link_pre_copy_file |
661 | | * |
662 | | * Purpose: Perform any necessary actions before copying message between |
663 | | * files for link messages. |
664 | | * |
665 | | * Return: Success: Non-negative |
666 | | * |
667 | | * Failure: Negative |
668 | | * |
669 | | *------------------------------------------------------------------------- |
670 | | */ |
671 | | static herr_t |
672 | | H5O__link_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src, bool *deleted, |
673 | | const H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata) |
674 | 0 | { |
675 | 0 | FUNC_ENTER_PACKAGE_NOERR |
676 | | |
677 | | /* check args */ |
678 | 0 | assert(deleted); |
679 | 0 | assert(cpy_info); |
680 | | |
681 | | /* If we are performing a 'shallow hierarchy' copy, and this link won't |
682 | | * be included in the final group, indicate that it should be deleted |
683 | | * in the destination object header before performing any other actions |
684 | | * on it. |
685 | | */ |
686 | 0 | if (cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth) |
687 | 0 | *deleted = true; |
688 | |
|
689 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
690 | 0 | } /* end H5O__link_pre_copy_file() */ |
691 | | |
692 | | /*------------------------------------------------------------------------- |
693 | | * Function: H5O__link_copy_file |
694 | | * |
695 | | * Purpose: Copies a message from _MESG to _DEST in file |
696 | | * |
697 | | * Return: Success: Ptr to _DEST |
698 | | * |
699 | | * Failure: NULL |
700 | | * |
701 | | *------------------------------------------------------------------------- |
702 | | */ |
703 | | static void * |
704 | | H5O__link_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *native_src, H5F_t H5_ATTR_UNUSED *file_dst, |
705 | | bool H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags, |
706 | | H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata) |
707 | 0 | { |
708 | 0 | H5O_link_t *link_src = (H5O_link_t *)native_src; |
709 | 0 | void *ret_value = NULL; /* Return value */ |
710 | |
|
711 | 0 | FUNC_ENTER_PACKAGE |
712 | | |
713 | | /* check args */ |
714 | 0 | assert(link_src); |
715 | 0 | assert(cpy_info); |
716 | 0 | assert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth); |
717 | | |
718 | | /* Sanity check source link type */ |
719 | 0 | if (link_src->type > H5L_TYPE_SOFT && link_src->type < H5L_TYPE_UD_MIN) |
720 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "unrecognized built-in link type"); |
721 | | |
722 | | /* Allocate "blank" link for destination */ |
723 | | /* (values will be filled in during 'post copy' operation) */ |
724 | 0 | if (NULL == (ret_value = H5FL_CALLOC(H5O_link_t))) |
725 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
726 | | |
727 | 0 | done: |
728 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
729 | 0 | } /* H5O__link_copy_file() */ |
730 | | |
731 | | /*------------------------------------------------------------------------- |
732 | | * Function: H5O__link_post_copy_file |
733 | | * |
734 | | * Purpose: Finish copying a message from between files |
735 | | * |
736 | | * Return: Non-negative on success/Negative on failure |
737 | | * |
738 | | *------------------------------------------------------------------------- |
739 | | */ |
740 | | static herr_t |
741 | | H5O__link_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst, |
742 | | unsigned H5_ATTR_UNUSED *mesg_flags, H5O_copy_t *cpy_info) |
743 | 0 | { |
744 | 0 | const H5O_link_t *link_src = (const H5O_link_t *)mesg_src; |
745 | 0 | H5O_link_t *link_dst = (H5O_link_t *)mesg_dst; |
746 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
747 | |
|
748 | 0 | FUNC_ENTER_PACKAGE |
749 | | |
750 | | /* check args */ |
751 | 0 | assert(link_src); |
752 | 0 | assert(dst_oloc); |
753 | 0 | assert(H5_addr_defined(dst_oloc->addr)); |
754 | 0 | assert(dst_oloc->file); |
755 | 0 | assert(link_dst); |
756 | 0 | assert(cpy_info); |
757 | 0 | assert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth); |
758 | | |
759 | | /* Copy the link (and the object it points to) */ |
760 | 0 | if (H5L__link_copy_file(dst_oloc->file, link_src, src_oloc, link_dst, cpy_info) < 0) |
761 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy link"); |
762 | | |
763 | 0 | done: |
764 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
765 | 0 | } /* H5O__link_post_copy_file() */ |
766 | | |
767 | | /*------------------------------------------------------------------------- |
768 | | * Function: H5O__link_debug |
769 | | * |
770 | | * Purpose: Prints debugging info for a message. |
771 | | * |
772 | | * Return: Non-negative on success/Negative on failure |
773 | | * |
774 | | *------------------------------------------------------------------------- |
775 | | */ |
776 | | static herr_t |
777 | | H5O__link_debug(H5F_t H5_ATTR_UNUSED *f, const void *_mesg, FILE *stream, int indent, int fwidth) |
778 | 0 | { |
779 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_mesg; |
780 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
781 | |
|
782 | 0 | FUNC_ENTER_PACKAGE |
783 | | |
784 | | /* check args */ |
785 | 0 | assert(f); |
786 | 0 | assert(lnk); |
787 | 0 | assert(stream); |
788 | 0 | assert(indent >= 0); |
789 | 0 | assert(fwidth >= 0); |
790 | |
|
791 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Link Type:", |
792 | 0 | (lnk->type == H5L_TYPE_HARD |
793 | 0 | ? "Hard" |
794 | 0 | : (lnk->type == H5L_TYPE_SOFT |
795 | 0 | ? "Soft" |
796 | 0 | : (lnk->type == H5L_TYPE_EXTERNAL |
797 | 0 | ? "External" |
798 | 0 | : (lnk->type >= H5L_TYPE_UD_MIN ? "User-defined" : "Unknown"))))); |
799 | |
|
800 | 0 | if (lnk->corder_valid) |
801 | 0 | fprintf(stream, "%*s%-*s %" PRId64 "\n", indent, "", fwidth, "Creation Order:", lnk->corder); |
802 | |
|
803 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Link Name Character Set:", |
804 | 0 | (lnk->cset == H5T_CSET_ASCII ? "ASCII" : (lnk->cset == H5T_CSET_UTF8 ? "UTF-8" : "Unknown"))); |
805 | 0 | fprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth, "Link Name:", lnk->name); |
806 | | |
807 | | /* Display link-specific information */ |
808 | 0 | switch (lnk->type) { |
809 | 0 | case H5L_TYPE_HARD: |
810 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, |
811 | 0 | "Object address:", lnk->u.hard.addr); |
812 | 0 | break; |
813 | | |
814 | 0 | case H5L_TYPE_SOFT: |
815 | 0 | fprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth, "Link Value:", lnk->u.soft.name); |
816 | 0 | break; |
817 | | |
818 | 0 | case H5L_TYPE_ERROR: |
819 | 0 | case H5L_TYPE_EXTERNAL: |
820 | 0 | case H5L_TYPE_MAX: |
821 | 0 | default: |
822 | 0 | if (lnk->type >= H5L_TYPE_UD_MIN) { |
823 | 0 | if (lnk->type == H5L_TYPE_EXTERNAL) { |
824 | 0 | const char *objname = |
825 | 0 | (const char *)lnk->u.ud.udata + (strlen((const char *)lnk->u.ud.udata) + 1); |
826 | |
|
827 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, |
828 | 0 | "External File Name:", (const char *)lnk->u.ud.udata); |
829 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "External Object Name:", objname); |
830 | 0 | } /* end if */ |
831 | 0 | else { |
832 | 0 | fprintf(stream, "%*s%-*s %zu\n", indent, "", fwidth, |
833 | 0 | "User-Defined Link Size:", lnk->u.ud.size); |
834 | 0 | } /* end else */ |
835 | 0 | } /* end if */ |
836 | 0 | else |
837 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type"); |
838 | 0 | break; |
839 | 0 | } /* end switch */ |
840 | | |
841 | 0 | done: |
842 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
843 | 0 | } /* end H5O__link_debug() */ |