1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF. The full HDF copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /* $Id$ */
15
16 /*
17 FILE
18 hfiledd.c - DD & DD block management routines.
19
20 REMARKS
21 These routines provide all the management for the DD list, both on disk
22 and in memory. The DD list is read in from disk (or created in memory
23 for a new file) here and the tag tree and all the DD modifying functions
24 are in this module. DO NOT MODIFY THE DD BLOCKS FROM OUTSIDE THIS FILE!
25
26 DESIGN
27 The DD blocks are stored in memory in a very similar way to the way they
28 are stored in the file: in a doubly-linked list of DD blocks with each
29 block having a pointer to the array of DDs in it (in the file). There
30 are additional memory structures which are indexed into the DD list which
31 are designed for faster access to certain manipulations of the DD list.
32 The tag_tree is a tbbt of the tags contained within the file. Each
33 node of the tag_tree has a link to a bit-vector for keeping track of the
34 refs used for that tag and a link to a dynamic array pointers into the
35 DD list for each ref # used.
36
37 BUGS/LIMITATIONS
38
39 EXPORTED ROUTINES
40 User-level functions:
41 Hdupdd - Duplicate a data descriptor
42 Hnumber - Count number of occurrances of tag/ref in file
43 Hnewref - Returns a ref that is unique in the file
44 Htagnewref - Returns a ref that is unique in the file for a given tag
45 Hfind - Locate the next object of a search in an HDF file
46 Hdeldd - Delete a data descriptor
47
48 Developer-level routines
49 HDcheck_tagref - Checks to see if tag/ref is in DD list i.e. created already
50 HDreuse_tagref - reuse a data descriptor preserving tag/refw(assumes DD exists)
51
52 Tag/ref functions:
53 HTPcreate - Create (& attach to) a tag/ref pair (inserts into DD list also)
54 HTPselect - Attach to an existing DD in the DD list
55 HTPendaccess- End access to an attached DD in the DD list
56 HTPdelete - Mark a tag/ref pair as free (marks space as free in DD list)
57 (ends access to the tag/ref also)
58 HTPupdate - Change the offset and/or length of a data object
59 HTPinquire - Get the DD information for a DD (i.e. tag/ref/offset/length)
60 HTPis_special- Check if a DD id is associated with a special tag
61 DD list functions:
62 HTPstart - Initialize the DD list from disk (creates the DD list in memory)
63 HTPinit - Create a new DD list (creates the DD list in memory)
64 HTPsync - Flush the DD list to disk (syncronizes with disk)
65 HTPend - Close the DD list to disk (syncronizes with disk too)
66 LOCAL ROUTINES
67 HTIfind_dd - find a specific DD in the file
68 HTInew_dd_block - create a new (empty) DD block
69 HTIupdate_dd - update a DD on disk
70 HTIcount_dd - counts the dd's of a certain type in file
71 HTIregister_tag_ref - insert a ref into the tag tree for a file
72 HTIunregister_tag_ref - remove a ref from the tag tree for a file
73
74 OLD ROUTINES
75 HIlookup_dd - find the dd record for an element
76 HIflush_dds - flush changed DD blocks to file
77 HIinit_file_dds - Initialize DD blocks for a new file
78 HIfill_file_rec - read in all of the DDs
79 HIadd_hash_dd - add a dd to the hash table
80 HIdel_hash_dd - remove a dd from the hash table
81 HIfind_dd - find the dd record for an element
82 HIcount_dd - counts the dd's of a certain type in file
83 HInew_dd_block - create a new (empty) DD block
84 HIupdate_dd - write an updated dd to the file
85 HIregister_tag_ref - mark a ref as used for a tag
86 HIunregister_tag_ref - mark a ref as un-used for a tag
87
88 AUTHOR
89 Quincey Koziol
90
91 MODIFICATION HISTORY
92 12/20/95 - Starting writing specs & coding prototype
93 */
94
95 #include "hdf.h"
96 #include "hfile.h"
97
98 /* Private routines */
99 static intn HTIfind_dd(filerec_t * file_rec, uint16 look_tag, uint16 look_ref,
100 dd_t ** pdd, intn direction);
101
102 static intn HTInew_dd_block(filerec_t * file_rec);
103
104 static intn HTIupdate_dd(filerec_t * file_rec, dd_t * dd);
105
106 static intn HTIcount_dd(filerec_t * file_rec, uint16 cnt_tag, uint16 cnt_ref,
107 uintn *all_cnt, uintn *real_cnt);
108
109 static intn HTIregister_tag_ref(filerec_t * file_rec, dd_t *dd);
110
111 static intn HTIunregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr);
112
113 /* Local definitions */
114 /* The initial size of a ref dynarray */
115 #define REF_DYNARRAY_START 64
116 /* The increment of a ref dynarray */
117 #define REF_DYNARRAY_INCR 256
118 /* macros to encode and decode a DD */
119 #define DDENCODE(p, tag,ref,offset,length) \
120 {UINT16ENCODE(p, tag); \
121 UINT16ENCODE(p, ref); \
122 INT32ENCODE(p, offset); \
123 INT32ENCODE(p, length); \
124 }
125 #define DDDECODE(p, tag,ref,offset,length) \
126 {UINT16DECODE(p, tag); \
127 UINT16DECODE(p, ref); \
128 INT32DECODE(p, offset); \
129 INT32DECODE(p, length); \
130 }
131
132
133 /******************************************************************************
134 NAME
135 HTPstart - Initialize the DD list in memory
136
137 DESCRIPTION
138 Reads the DD blocks from disk and creates the in-memory structures for
139 handling them. This routine should only be called once for a given
140 file and HTPend should be called when finished with the DD list (i.e.
141 when the file is being closed).
142
143 RETURNS
144 Returns SUCCEED if successful and FAIL otherwise
145
146 *******************************************************************************/
HTPstart(filerec_t * file_rec)147 intn HTPstart(filerec_t *file_rec /* IN: File record to store info in */
148 )
149 {
150 CONSTR(FUNC, "HTPstart"); /* for HERROR */
151 uint8 *tbuf=NULL; /* temporary buffer */
152 uintn tbuf_size=0; /* temporary buffer size */
153 int32 end_off = 0; /* offset of the end of the file */
154 intn ret_value = SUCCEED;
155
156 HEclear();
157 /* Alloc start of linked list of ddblocks. */
158 file_rec->ddhead = (ddblock_t *) HDmalloc(sizeof(ddblock_t));
159 if (file_rec->ddhead == (ddblock_t *) NULL)
160 HGOTO_ERROR(DFE_NOSPACE, FAIL);
161
162 /* Keep the filerec_t pointer around for each ddblock */
163 file_rec->ddhead->frec=file_rec;
164
165 /* Only one elt in linked list so head is also last. */
166 file_rec->ddlast = file_rec->ddhead;
167 file_rec->ddlast->next = (ddblock_t *) NULL;
168 file_rec->ddlast->prev = (ddblock_t *) NULL;
169
170 /* The first ddblock always starts after the magic number.
171 Set it up so that we start reading from there. */
172 file_rec->ddlast->myoffset = MAGICLEN; /* set offset of block in file */
173 file_rec->ddlast->dirty = 0; /* block does not need to be flushed */
174
175 /* Initialize the tag tree */
176 file_rec->tag_tree = tbbtdmake(tagcompare, sizeof(uint16), TBBT_FAST_UINT16_COMPARE);
177
178 /* Initialize the DD atom group (trying 256 hash currently, feel free to change */
179 if(HAinit_group(DDGROUP,256)==FAIL)
180 HGOTO_ERROR(DFE_INTERNAL, FAIL);
181
182 /* Read in the dd's one at a time and determine the max ref in the file
183 at the same time. */
184 file_rec->maxref = 0;
185 for (;;)
186 {
187 ddblock_t *ddcurr; /* ptr to the current DD block */
188 dd_t *curr_dd_ptr; /* pointer to the current DD being read in */
189 uint8 ddhead[NDDS_SZ+OFFSET_SZ]; /* storage for the DD header */
190 uint8 *p; /* Temporary buffer pointer. */
191 intn ndds; /* number of DDs in a block */
192 intn i; /* Temporary integer */
193
194 /* Get a short-cut for the current DD block being read-in */
195 ddcurr=file_rec->ddlast;
196
197 /* Go to the beginning of the DD block */
198 if (HPseek(file_rec, ddcurr->myoffset) == FAIL)
199 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
200
201 /* Read in the start of this dd block.
202 Read data consists of ndds (number of dd's in this block) and
203 offset (offset to the next ddblock). */
204 if (HP_read(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
205 HGOTO_ERROR(DFE_READERROR, FAIL);
206
207 /* Decode the numbers. */
208 p = &ddhead[0];
209 INT16DECODE(p, ddcurr->ndds);
210 ndds = (intn)ddcurr->ndds;
211 if (ndds <= 0) /* validity check */
212 HGOTO_ERROR(DFE_CORRUPT, FAIL);
213 INT32DECODE(p, ddcurr->nextoffset);
214
215 /* check if the DD block is the last thing in the file */
216 /* (Unlikely, but possible (I think)) */
217 if (ddcurr->myoffset + (NDDS_SZ + OFFSET_SZ) + (ndds * DD_SZ) > end_off)
218 end_off = ddcurr->myoffset + (NDDS_SZ + OFFSET_SZ) + (ndds * DD_SZ);
219
220 /* Now that we know how many dd's are in this block,
221 alloc memory for the records. */
222 ddcurr->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
223 if (ddcurr->ddlist==(dd_t *)NULL)
224 HGOTO_ERROR(DFE_NOSPACE, FAIL);
225
226 /* Allocate memory for the temporary buffer also */
227 if(tbuf==NULL || ((uintn)ndds*DD_SZ)>tbuf_size)
228 {
229 if (tbuf!=(uint8 *)NULL)
230 HDfree(tbuf);
231 tbuf_size=(uintn)ndds*DD_SZ;
232 tbuf=(uint8 *)HDmalloc(tbuf_size);
233 if (tbuf==(uint8 *)NULL)
234 HGOTO_ERROR(DFE_NOSPACE, FAIL);
235 } /* end if */
236
237 /* Index of current dd in ddlist of this ddblock is 0. */
238 curr_dd_ptr=ddcurr->ddlist;
239
240 /* Read in a chunk of dd's from the file. */
241 if (HP_read(file_rec, tbuf, ndds * DD_SZ) == FAIL)
242 HGOTO_ERROR(DFE_READERROR, FAIL);
243
244 /* decode the dd's */
245 p = tbuf;
246 for (i = 0; i < ndds; i++, curr_dd_ptr++)
247 {
248 DDDECODE(p, curr_dd_ptr->tag, curr_dd_ptr->ref,
249 curr_dd_ptr->offset, curr_dd_ptr->length);
250 curr_dd_ptr->blk=ddcurr;
251
252 /* check if maximum ref # exceeded */
253 if (file_rec->maxref < curr_dd_ptr->ref)
254 file_rec->maxref = curr_dd_ptr->ref;
255
256 /* check if the data element is the last thing in the file */
257 if ((curr_dd_ptr->offset + curr_dd_ptr->length) > end_off)
258 end_off = curr_dd_ptr->offset + curr_dd_ptr->length;
259
260 /* Add to the tag info tree */
261 if(curr_dd_ptr->tag!=DFTAG_NULL)
262 if(HTIregister_tag_ref(file_rec,curr_dd_ptr)==FAIL)
263 HGOTO_ERROR(DFE_INTERNAL, FAIL);
264 }
265
266 if (ddcurr->nextoffset != 0)
267 { /* More ddblocks in the file */
268 ddblock_t *ddnew; /* ptr to the new DD block */
269
270 /* extend the linked list */
271 ddcurr->next = ddnew = (ddblock_t *) HDmalloc((uint32) sizeof(ddblock_t));
272 if (ddnew == (ddblock_t *) NULL)
273 HGOTO_ERROR(DFE_NOSPACE, FAIL);
274
275 ddnew->prev = ddcurr;
276 ddnew->next = (ddblock_t *) NULL;
277 ddnew->ddlist = (dd_t *) NULL;
278 ddnew->myoffset = ddcurr->nextoffset;
279 ddnew->dirty= FALSE;
280 file_rec->ddlast = ddnew;
281
282 /* Keep the filerec_t pointer around for each ddblock */
283 ddnew->frec=file_rec;
284 } /* end if */
285 else
286 break;
287 } /* end for */
288
289 /* Update the DFTAG_NULL pointers */
290 file_rec->ddnull=NULL;
291 file_rec->ddnull_idx=(-1);
292
293 /* Update the end of the file from the DD's we have read in */
294 file_rec->f_end_off = end_off;
295
296 done:
297 if(ret_value == FAIL)
298 { /* Error condition cleanup */
299
300 } /* end if */
301
302 /* Normal function cleanup */
303 if(tbuf!=NULL)
304 HDfree(tbuf);
305
306 return ret_value;
307 } /* end HTPstart() */
308
309 /******************************************************************************
310 NAME
311 HTPinit - Create a new DD list in memory
312
313 DESCRIPTION
314 Creates a new DD list in memory for a newly created file. This routine
315 should only be called once for a given file and HTPend should be called
316 when finished with the DD list (i.e. when the file is being closed).
317
318 RETURNS
319 Returns SUCCEED if successful and FAIL otherwise
320
321 *******************************************************************************/
HTPinit(filerec_t * file_rec,int16 ndds)322 intn HTPinit(filerec_t *file_rec, /* IN: File record to store info in */
323 int16 ndds /* IN: # of DDs to store in each block */
324 )
325 {
326 CONSTR(FUNC, "HTPinit"); /* for HERROR */
327 ddblock_t *block; /* dd block to intialize */
328 uint8 ddhead[NDDS_SZ+OFFSET_SZ]; /* storage for the DD header */
329 uint8 *tbuf=NULL; /* temporary buffer */
330 uint8 *p; /* temp buffer ptr */
331 dd_t *list; /* list of dd */
332 intn ret_value = SUCCEED;
333
334 HEclear();
335 if (file_rec == NULL || ndds<0) /* valid arguments */
336 HGOTO_ERROR(DFE_ARGS, FAIL);
337
338 /* 'reasonablize' the value of ndds. 0 means use default */
339 if (0 == ndds)
340 ndds = DEF_NDDS;
341 else if (ndds < MIN_NDDS)
342 ndds = MIN_NDDS;
343
344 /* allocate the dd block in memory and initialize it */
345 file_rec->ddhead = (ddblock_t *) HDmalloc(sizeof(ddblock_t));
346 if (file_rec->ddhead == (ddblock_t *) NULL)
347 HGOTO_ERROR(DFE_NOSPACE, FAIL);
348 block = file_rec->ddlast = file_rec->ddhead;
349 block->prev = (ddblock_t *) NULL;
350 block->ndds = ndds;
351 block->next = (ddblock_t *) NULL;
352 block->nextoffset = 0;
353 block->myoffset = MAGICLEN;
354 block->dirty = FALSE;
355
356 /* Keep the filerec_t pointer around for each ddblock */
357 block->frec=file_rec;
358
359 /* write first dd block header to file */
360 p = &ddhead[0];
361 INT16ENCODE(p, block->ndds);
362 INT32ENCODE(p, (int32) 0);
363 if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
364 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
365
366 /* allocate and initialize dd list */
367 list = block->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
368 if (list == (dd_t *) NULL)
369 HGOTO_ERROR(DFE_NOSPACE, FAIL);
370
371 /* Fill the first memory DD block with NIL dd's */
372 list[0].tag = DFTAG_NULL;
373 list[0].ref = DFREF_NONE;
374 list[0].length = INVALID_LENGTH;
375 list[0].offset = INVALID_OFFSET;
376 list[0].blk = block;
377 HDmemfill(&list[1],&list[0],sizeof(dd_t),(uint32)(ndds-1));
378
379 tbuf=(uint8 *)HDmalloc(ndds*DD_SZ);
380 if (tbuf == NULL) /* check for DD list */
381 HGOTO_ERROR(DFE_NOSPACE, FAIL);
382
383 /* Fill the first disk DD block with NIL dd's */
384 p = tbuf;
385 DDENCODE(p, (uint16) DFTAG_NULL, (uint16) DFREF_NONE,
386 (int32) INVALID_LENGTH, (int32) INVALID_OFFSET);
387 HDmemfill(p,tbuf,DD_SZ,(uint32)(ndds-1));
388
389 /* Write the NIL dd's out into the DD block on disk */
390 if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
391 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
392
393 /* Update the DFTAG_NULL pointers */
394 file_rec->ddnull=block;
395 file_rec->ddnull_idx=(-1);
396
397 /* set the end of the file currently to the end of the first DD block */
398 file_rec->f_end_off = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (block->ndds * DD_SZ);
399
400 /* no dd's yet, so maximum ref is 0 */
401 file_rec->maxref = 0;
402
403 /* Initialize the tag tree */
404 file_rec->tag_tree = tbbtdmake(tagcompare, sizeof(uint16), TBBT_FAST_UINT16_COMPARE);
405
406 /* Initialize the DD atom group (trying 256 hash currently, feel free to change */
407 if(HAinit_group(DDGROUP,256)==FAIL)
408 HGOTO_ERROR(DFE_INTERNAL, FAIL);
409
410 done:
411 if(ret_value == FAIL)
412 { /* Error condition cleanup */
413
414 } /* end if */
415
416 /* Normal function cleanup */
417 HDfree(tbuf);
418
419 return ret_value;
420 } /* end HTPinit() */
421
422 /******************************************************************************
423 NAME
424 HTPsync - Flush the DD list in memory
425
426 DESCRIPTION
427 Syncronizes the in-memory copy of the DD list with the copy on disk by
428 writing out the DD blocks which have changed to disk.
429
430 RETURNS
431 Returns SUCCEED if successful and FAIL otherwise
432
433 *******************************************************************************/
HTPsync(filerec_t * file_rec)434 intn HTPsync(filerec_t *file_rec /* IN: File record to store info in */
435 )
436 {
437 CONSTR(FUNC, "HTPsync"); /* for HERROR */
438 ddblock_t *block; /* dd block to intialize */
439 uint8 ddhead[NDDS_SZ+OFFSET_SZ]; /* storage for the DD header */
440 uint8 *tbuf=NULL; /* temporary buffer */
441 uintn tbuf_size=0; /* temporary buffer size */
442 uint8 *p; /* temp buffer ptr */
443 dd_t *list; /* list of dd */
444 int16 ndds; /* # of DDs per block */
445 intn i; /* temp ints */
446 intn ret_value = SUCCEED;
447
448 HEclear();
449 block = file_rec->ddhead;
450 if (block == NULL) /* check for DD list */
451 HGOTO_ERROR(DFE_BADDDLIST, FAIL);
452
453 while (block != NULL)
454 { /* check all the blocks for flushing */
455 if (block->dirty == TRUE)
456 { /* flush this block? */
457 if (HPseek(file_rec, block->myoffset) == FAIL)
458 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
459
460 /* write dd block header to file */
461 p = ddhead;
462 INT16ENCODE(p, block->ndds);
463 INT32ENCODE(p, block->nextoffset);
464 if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
465 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
466
467 /* n is the maximum number of dd's in tbuf */
468 ndds = block->ndds;
469 /* Allocate memory for the temporary buffer also */
470 if(tbuf==NULL || ((uintn)ndds*DD_SZ)>tbuf_size)
471 {
472 if (tbuf!=(uint8 *)NULL)
473 HDfree(tbuf);
474 tbuf_size=(uintn)ndds*DD_SZ;
475 tbuf=(uint8 *)HDmalloc(tbuf_size);
476 if (tbuf==(uint8 *)NULL)
477 HGOTO_ERROR(DFE_NOSPACE, FAIL);
478 } /* end if */
479
480 /* write dd list to file */
481 list = &block->ddlist[0]; /* start at the first DD, go from there */
482 p = tbuf;
483 for (i = 0; i < ndds; i++, list++)
484 DDENCODE(p, list->tag, list->ref, list->offset, list->length);
485
486 if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
487 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
488
489 block->dirty = FALSE; /* block has been flushed */
490 } /* end if */
491 block = block->next; /* advance to next block for file */
492 } /* end while */
493
494 done:
495 if(ret_value == FAIL)
496 { /* Error condition cleanup */
497
498 } /* end if */
499
500 /* Normal function cleanup */
501 if (tbuf!=(uint8 *)NULL)
502 HDfree(tbuf);
503
504 return ret_value;
505 } /* end HTPsync() */
506
507 /******************************************************************************
508 NAME
509 HTPend - Terminate the DD list in memory
510
511 DESCRIPTION
512 Terminates access to the DD list in memory, writing the DD blocks out to
513 the disk (if they've changed). After this routine is called, no further
514 access to tag/refs (or essentially any other HDF objects) can be performed
515 on the file.
516
517 RETURNS
518 Returns SUCCEED if successful and FAIL otherwise
519
520 *******************************************************************************/
HTPend(filerec_t * file_rec)521 intn HTPend(filerec_t *file_rec /* IN: File record to store info in */
522 )
523 {
524 CONSTR(FUNC, "HTPend"); /* for HERROR */
525 ddblock_t *bl, *next; /* current ddblock and next ddblock pointers.
526 for freeing ddblock linked list */
527 intn ret_value = SUCCEED;
528
529 HEclear();
530 if(HTPsync(file_rec)==FAIL)
531 HGOTO_ERROR(DFE_INTERNAL, FAIL);
532
533 for (bl = file_rec->ddhead; bl!=NULL; bl = next)
534 {
535 next = bl->next;
536 if (bl->ddlist)
537 HDfree((VOIDP) bl->ddlist);
538 HDfree((VOIDP) bl);
539 }
540
541 /* Chuck the tag info tree too */
542 tbbtdfree(file_rec->tag_tree,tagdestroynode,NULL);
543
544 /* Shutdown the DD atom group */
545 if(HAdestroy_group(DDGROUP)==FAIL)
546 HGOTO_ERROR(DFE_INTERNAL, FAIL);
547
548 file_rec->ddhead = (ddblock_t *) NULL;
549
550 done:
551 if(ret_value == FAIL)
552 { /* Error condition cleanup */
553
554 } /* end if */
555
556 /* Normal function cleanup */
557
558 return ret_value;
559 } /* end HTPend() */
560
561 /******************************************************************************
562 NAME
563 HTPcreate - Create (and attach to) a tag/ref pair
564
565 DESCRIPTION
566 Creates a new tag/ref pair in memory and inserts the tag/ref pair into the
567 DD list to be written out to disk. This routine returns a DD id which can
568 be used in the other tag/ref routines to modify the DD.
569
570 RETURNS
571 Returns DD id if successful and FAIL otherwise
572
573 *******************************************************************************/
HTPcreate(filerec_t * file_rec,uint16 tag,uint16 ref)574 atom_t HTPcreate(filerec_t *file_rec, /* IN: File record to store info in */
575 uint16 tag, /* IN: Tag to create */
576 uint16 ref /* IN: ref to create */
577 )
578 {
579 CONSTR(FUNC, "HTPcreate"); /* for HERROR */
580 dd_t *dd_ptr=NULL; /* ptr to dd created */
581 atom_t ret_value=SUCCEED;
582
583 HEclear();
584 if(file_rec==NULL || (tag==DFTAG_NULL || tag==DFTAG_WILDCARD) ||
585 ref==DFREF_WILDCARD)
586 HGOTO_ERROR(DFE_ARGS, FAIL);
587
588 if(HTIfind_dd(file_rec,(uint16)DFTAG_NULL,(uint16)DFTAG_WILDCARD,
589 &dd_ptr,DF_FORWARD)==FAIL)
590 {
591 if (HTInew_dd_block(file_rec) == FAIL)
592 {
593 HGOTO_ERROR(DFE_NOFREEDD, FAIL);
594 } /* end if */
595 else
596 dd_ptr=&file_rec->ddlast->ddlist[0];
597 } /* end if */
598
599 /* Insert DD information into the DD list in memory */
600 dd_ptr->tag=tag;
601 dd_ptr->ref=ref;
602 /* the following assures object defintion in DD list
603 without data written for object. */
604 dd_ptr->offset=INVALID_OFFSET;
605 dd_ptr->length=INVALID_LENGTH;
606
607 /* dd_ptr->blk should already be correctly set */
608
609 /* Update the disk, etc. */
610 if(HTIupdate_dd(file_rec,dd_ptr)==FAIL)
611 HGOTO_ERROR(DFE_INTERNAL, FAIL);
612
613 /* Mark off the ref # as 'used' in the tag tree & add to dynarray of refs */
614 if(HTIregister_tag_ref(file_rec,dd_ptr)==FAIL)
615 HGOTO_ERROR(DFE_INTERNAL, FAIL);
616
617 /* Get the atom to return */
618 if((ret_value=HAregister_atom(DDGROUP,dd_ptr))==FAIL)
619 HGOTO_ERROR(DFE_INTERNAL, FAIL);
620
621 done:
622 if(ret_value == FAIL)
623 { /* Error condition cleanup */
624
625 } /* end if */
626
627 /* Normal function cleanup */
628
629 return ret_value;
630 } /* HTPcreate() */
631
632 /******************************************************************************
633 NAME
634 HTPselect - Attach to an existing tag/ref pair
635
636 DESCRIPTION
637 Attaches to an existing tag/ref pair. This routine returns a DD id which
638 can be used in the other tag/ref routines to modify the DD.
639
640 RETURNS
641 Returns DD id if successful and FAIL otherwise
642
643 *******************************************************************************/
HTPselect(filerec_t * file_rec,uint16 tag,uint16 ref)644 atom_t HTPselect(filerec_t *file_rec, /* IN: File record to store info in */
645 uint16 tag, /* IN: Tag to select */
646 uint16 ref /* IN: ref to select */
647 )
648 {
649 CONSTR(FUNC, "HTPselect"); /* for HERROR */
650 dd_t *dd_ptr; /* ptr to the DD info for the tag/ref */
651 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
652 tag_info *tinfo_ptr; /* pointer to the info for a tag */
653 uint16 base_tag=BASETAG(tag); /* corresponding base tag (if the tag is special) */
654 atom_t ret_value=SUCCEED;
655
656 HEclear();
657 if(file_rec==NULL || (tag==DFTAG_NULL || tag==DFTAG_WILDCARD) ||
658 ref==DFREF_WILDCARD)
659 HGOTO_ERROR(DFE_ARGS, FAIL);
660
661 /* Try to find the regular tag in the tag info tree */
662 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
663 HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
664
665 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
666 if((dd_ptr=DAget_elem(tinfo_ptr->d,(intn)ref))==NULL)
667 HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
668
669 /* Get the atom to return */
670 if((ret_value=HAregister_atom(DDGROUP,dd_ptr))==FAIL)
671 HGOTO_ERROR(DFE_INTERNAL, FAIL);
672
673 done:
674 if(ret_value == FAIL)
675 { /* Error condition cleanup */
676
677 } /* end if */
678
679 /* Normal function cleanup */
680
681 return ret_value;
682 } /* HTPselect() */
683
684 /******************************************************************************
685 NAME
686 HTPendaccess - End access to an existing tag/ref pair
687
688 DESCRIPTION
689 Ends access to an existing tag/ref pair. Any further access to the tag/ref
690 pair may result in incorrect information being recorded about the DD in
691 memory or on disk.
692
693 RETURNS
694 Returns SUCCEED if successful and FAIL otherwise
695
696 *******************************************************************************/
HTPendaccess(atom_t ddid)697 intn HTPendaccess(atom_t ddid /* IN: DD id to end access to */
698 )
699 {
700 #ifdef LATER
701 CONSTR(FUNC, "HTPendaccess"); /* for HERROR */
702 #endif /* LATER */
703 int32 ret_value=SUCCEED;
704
705 /* Chuck the atom */
706 if(HAremove_atom(ddid)==NULL)
707 HGOTO_DONE(FAIL);
708
709 done:
710 if(ret_value == FAIL)
711 { /* Error condition cleanup */
712
713 } /* end if */
714
715 /* Normal function cleanup */
716
717 return ret_value;
718 } /* HTPendaccess() */
719
720 /******************************************************************************
721 NAME
722 HTPdelete - Delete an existing tag/ref pair
723
724 DESCRIPTION
725 Deletes a tag/ref from the file. Also ends access to the tag/ref pair.
726 Any further access to the tag/ref pair may result in incorrect information
727 being recorded about the DD in memory or on disk.
728
729 RETURNS
730 Returns SUCCEED if successful and FAIL otherwise
731
732 *******************************************************************************/
HTPdelete(atom_t ddid)733 intn HTPdelete(atom_t ddid /* IN: DD id to delete */
734 )
735 {
736 CONSTR(FUNC, "HTPdelete"); /* for HERROR */
737 dd_t *dd_ptr; /* ptr to the DD info for the tag/ref */
738 filerec_t * file_rec;
739 int32 ret_value=SUCCEED;
740
741 HEclear();
742 /* Retrieve the atom's object, so we can delete the tag/ref */
743 if((dd_ptr=HAatom_object(ddid))==NULL)
744 HGOTO_ERROR(DFE_INTERNAL, FAIL);
745
746 /* Grab this information, because the global dd_info will be deleted in HTIunregister_tag_ref */
747 file_rec=dd_ptr->blk->frec;
748
749 /* Since we don't know where we are, reset the DFTAG_NULL pointers */
750 file_rec->ddnull=NULL;
751 file_rec->ddnull_idx=(-1);
752
753 if (HPfreediskblock(file_rec,dd_ptr->offset,dd_ptr->length) == FAIL)
754 HGOTO_ERROR(DFE_INTERNAL, FAIL);
755
756 /* Update the disk, etc. */
757 if(HTIupdate_dd(file_rec,dd_ptr)==FAIL)
758 HGOTO_ERROR(DFE_INTERNAL, FAIL);
759
760 /* Remove the ref # as 'used' in the tag tree & delete from dynarray of refs */
761 if(HTIunregister_tag_ref(file_rec,dd_ptr)==FAIL)
762 HGOTO_ERROR(DFE_INTERNAL, FAIL);
763
764 /* Destroy everything */
765 if(HAremove_atom(ddid)==NULL)
766 HGOTO_ERROR(DFE_INTERNAL, FAIL);
767
768 done:
769 if(ret_value == FAIL)
770 { /* Error condition cleanup */
771
772 } /* end if */
773
774 /* Normal function cleanup */
775
776 return ret_value;
777 } /* HTPdelete() */
778
779 /******************************************************************************
780 NAME
781 HTPupdate - Change the offset or length of an existing tag/ref pair
782
783 DESCRIPTION
784 Updates a tag/ref in the file, allowing the length and/or offset to be
785 modified.
786
787 Note: a value of '-2' for both 'length' and 'offset' are used to indicate
788 that the length or offset (respectively) is unchanged and should
789 remain the same. Kind of ugly but works for now.
790
791 RETURNS
792 Returns SUCCEED if successful and FAIL otherwise
793
794 *******************************************************************************/
HTPupdate(atom_t ddid,int32 new_off,int32 new_len)795 intn HTPupdate(atom_t ddid, /* IN: DD id to update */
796 int32 new_off, /* IN: new offset for DD */
797 int32 new_len /* IN: new length for DD */
798 )
799 {
800 CONSTR(FUNC, "HTPupdate"); /* for HERROR */
801 dd_t *dd_ptr = NULL; /* ptr to the DD info for the tag/ref */
802 int32 dont_change = -2; /* initialize to '-2' */
803 int32 ret_value = SUCCEED;
804
805 HEclear();
806 /* Retrieve the atom's object, so we can update the DD */
807 if((dd_ptr=HAatom_object(ddid))==NULL)
808 HGOTO_ERROR(DFE_INTERNAL, FAIL);
809
810 /* Update the tag/ref in memory */
811 if(new_len != dont_change)
812 dd_ptr->length=new_len;
813 if(new_off != dont_change)
814 dd_ptr->offset=new_off;
815
816 /* Update the disk, etc. */
817 if(HTIupdate_dd(dd_ptr->blk->frec,dd_ptr)==FAIL)
818 HGOTO_ERROR(DFE_INTERNAL, FAIL);
819
820 done:
821 if(ret_value == FAIL)
822 { /* Error condition cleanup */
823
824 } /* end if */
825
826 /* Normal function cleanup */
827
828 return ret_value;
829 } /* HTPupdate() */
830
831 /******************************************************************************
832 NAME
833 HTPinquire - Get the DD information for a DD (i.e. tag/ref/offset/length)
834
835 DESCRIPTION
836 Get the DD information for a DD id from the DD block. Passing NULL for
837 any parameter does not try to update that parameter.
838
839 RETURNS
840 Returns SUCCEED if successful and FAIL otherwise
841
842 *******************************************************************************/
HTPinquire(atom_t ddid,uint16 * tag,uint16 * ref,int32 * off,int32 * len)843 intn HTPinquire(atom_t ddid, /* IN: DD id to inquire about */
844 uint16 *tag, /* IN: tag of DD */
845 uint16 *ref, /* IN: ref of DD */
846 int32 *off, /* IN: offset of DD */
847 int32 *len /* IN: length of DD */
848 )
849 {
850 CONSTR(FUNC, "HTPinquire"); /* for HERROR */
851 dd_t *dd_ptr; /* ptr to the DD info for the tag/ref */
852 intn ret_value=SUCCEED;
853
854 HEclear();
855 /* Retrieve the atom's object, so we can update the DD */
856 if((dd_ptr=HAatom_object(ddid))==NULL)
857 HGOTO_ERROR(DFE_ARGS, FAIL);
858
859 /* Get the information requested */
860 if(tag!=NULL)
861 *tag=dd_ptr->tag;
862 if(ref!=NULL)
863 *ref=dd_ptr->ref;
864 if(off!=NULL)
865 *off=dd_ptr->offset;
866 if(len!=NULL)
867 *len=dd_ptr->length;
868
869 done:
870 if(ret_value == FAIL)
871 { /* Error condition cleanup */
872
873 } /* end if */
874
875 /* Normal function cleanup */
876
877 return ret_value;
878 } /* HTPinquire() */
879
880 /******************************************************************************
881 NAME
882 HTPis_special - Check if a DD id is associated with a special tag
883
884 DESCRIPTION
885 Checks if the tag for the DD id is a special tag.
886
887 RETURNS
888 Returns TRUE(1)/FALSE(0)
889
890 *******************************************************************************/
HTPis_special(atom_t ddid)891 intn HTPis_special(atom_t ddid /* IN: DD id to inquire about */
892 )
893 {
894 CONSTR(FUNC, "HTPis_special"); /* for HERROR */
895 dd_t *dd_ptr; /* ptr to the DD info for the tag/ref */
896 int32 ret_value=FAIL;
897
898 HEclear();
899 /* Retrieve the atom's object, so we can update the DD */
900 if((dd_ptr=HAatom_object(ddid))==NULL)
901 HGOTO_ERROR(DFE_ARGS, FALSE);
902
903 /* Get the information requested */
904 if(SPECIALTAG(dd_ptr->tag))
905 ret_value=TRUE;
906 else
907 ret_value=FALSE;
908
909 done:
910 if(ret_value == FALSE)
911 { /* Error condition cleanup */
912
913 } /* end if */
914
915 /* Normal function cleanup */
916
917 return ret_value;
918 } /* HTPis_special() */
919
920 /******************************************************************************
921 NAME
922 Hdupdd - Duplicate a data descriptor
923
924 DESCRIPTION
925 Duplicates a data descriptor so that the new tag/ref points to the
926 same data element pointed to by the old tag/ref. Return FAIL if
927 the given tag/ref are already in use.
928
929 RETURNS
930 returns SUCCEED (0) if successful, FAIL (-1) otherwise
931
932 *******************************************************************************/
Hdupdd(int32 file_id,uint16 tag,uint16 ref,uint16 old_tag,uint16 old_ref)933 intn Hdupdd(int32 file_id, /* IN: File ID the tag/refs are in */
934 uint16 tag, /* IN: Tag of new tag/ref */
935 uint16 ref, /* IN: Ref of new tag/ref */
936 uint16 old_tag, /* IN: Tag of old tag/ref */
937 uint16 old_ref /* IN: Ref of old tag/ref */
938 )
939 {
940 CONSTR(FUNC, "Hdupdd"); /* for HERROR */
941 filerec_t *file_rec; /* file record */
942 atom_t old_dd; /* The DD id for the old DD */
943 atom_t new_dd; /* The DD id for the new DD */
944 int32 old_len; /* The length of the old DD */
945 int32 old_off; /* The offset of the old DD */
946 intn ret_value=SUCCEED;
947
948 /* clear error stack and check validity of file id */
949 HEclear();
950 file_rec = HAatom_object(file_id);
951 if (BADFREC(file_rec))
952 HGOTO_ERROR(DFE_ARGS, FAIL);
953
954 /* Attach to the old DD in the file */
955 if((old_dd=HTPselect(file_rec,old_tag,old_ref))==FAIL)
956 HGOTO_ERROR(DFE_NOMATCH, FAIL);
957
958 /* Create the new DD in the file */
959 if((new_dd=HTPcreate(file_rec,tag,ref))==FAIL)
960 HGOTO_ERROR(DFE_DUPDD, FAIL);
961
962 /* Retrieve the old offset & length */
963 if(HTPinquire(old_dd,NULL,NULL,&old_off,&old_len)==FAIL)
964 HGOTO_ERROR(DFE_INTERNAL, FAIL);
965
966 /* Set the new DD's offset & length to the same as the old DD */
967 if(HTPupdate(new_dd,old_off,old_len)==FAIL)
968 HGOTO_ERROR(DFE_INTERNAL, FAIL);
969
970 /* End access to the old & new DDs */
971 if(HTPendaccess(old_dd)==FAIL)
972 HGOTO_ERROR(DFE_INTERNAL, FAIL);
973 if(HTPendaccess(new_dd)==FAIL)
974 HGOTO_ERROR(DFE_INTERNAL, FAIL);
975
976 done:
977 if(ret_value == FAIL)
978 { /* Error condition cleanup */
979
980 } /* end if */
981
982 /* Normal function cleanup */
983 return ret_value;
984 } /* Hdupdd() */
985
986 /******************************************************************************
987 NAME
988 Hnumber - Determine the number of objects of a given type
989
990 DESCRIPTION
991 Determine how many objects of the given tag are in the file.
992 tag may be set to DFTAG_WILDCARD to get back the total number
993 of objects in the file.
994
995 Note, a return value of zero is not a fail condition.
996
997 RETURNS
998 the number of objects of type 'tag' else FAIL
999
1000 *******************************************************************************/
Hnumber(int32 file_id,uint16 tag)1001 int32 Hnumber(int32 file_id, /* IN: File ID the tag/refs are in */
1002 uint16 tag /* IN: Tag to count */
1003 )
1004 {
1005 CONSTR(FUNC, "Hnumber");
1006 uintn all_cnt;
1007 uintn real_cnt;
1008 filerec_t *file_rec; /* file record */
1009 int32 ret_value=SUCCEED;
1010
1011 /* convert file id to file record */
1012 file_rec = HAatom_object(file_id);
1013
1014 HEclear();
1015 if (BADFREC(file_rec))
1016 HGOTO_ERROR(DFE_ARGS, FAIL);
1017
1018 /* Go count the items with that tag */
1019 if (HTIcount_dd(file_rec, tag, DFREF_WILDCARD, &all_cnt, &real_cnt) == FAIL)
1020 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1021
1022 ret_value = (int32) real_cnt;
1023
1024 done:
1025 if(ret_value == FAIL)
1026 { /* Error condition cleanup */
1027
1028 } /* end if */
1029
1030 /* Normal function cleanup */
1031 return ret_value;
1032 } /* Hnumber() */
1033
1034 /******************************************************************************
1035 NAME
1036 Hnewref - Returns a ref that is guaranteed to be unique in the file
1037
1038 DESCRIPTION
1039 Returns a ref number that can be used with any tag to produce a
1040 unique tag/ref. Successive calls to Hnewref will generate a
1041 strictly increasing sequence until the highest possible ref had been
1042 returned, then Hnewref will return unused ref's starting from 1.
1043
1044 RETURNS
1045 returns the ref number, 0 otherwise
1046
1047 *******************************************************************************/
1048 uint16
Hnewref(int32 file_id)1049 Hnewref(int32 file_id /* IN: File ID the tag/refs are in */)
1050 {
1051 CONSTR(FUNC, "Hnewref");
1052 filerec_t *file_rec; /* file record */
1053 uint16 ref; /* the new ref */
1054 uint16 ret_value = DFREF_NONE;
1055 uint32 i_ref; /* index for FOR loop */
1056
1057 /* clear error stack and check validity of file record id */
1058 HEclear();
1059 file_rec = HAatom_object(file_id);
1060 if (BADFREC(file_rec))
1061 HGOTO_ERROR(DFE_ARGS, 0);
1062
1063 /* if maxref of this file is still below the maximum,
1064 just return next number */
1065 if (file_rec->maxref < MAX_REF)
1066 ret_value = ++(file_rec->maxref);
1067 else
1068 { /* otherwise, search for an empty ref */
1069 /* incredibly slow but unlikely situation */
1070 /* This could possibly get replaced with some sort of bit-vector manipulation -QAK */
1071 for (i_ref = 1; i_ref <= (uint32)MAX_REF; i_ref++)
1072 {
1073 dd_t *dd_ptr=NULL;
1074 ref = (uint16)i_ref;
1075 if (HTIfind_dd(file_rec, (uint16) DFTAG_WILDCARD, ref, &dd_ptr, DF_FORWARD) == FAIL)
1076 {
1077 ret_value = ref; /* set return value to ref found */
1078 break; /* break out of loop */
1079 } /* end if */
1080 } /* end for */
1081 } /* end else */
1082
1083 done:
1084 if(ret_value == DFREF_NONE)
1085 { /* Error condition cleanup */
1086
1087 } /* end if */
1088
1089 /* Normal function cleanup */
1090 return ret_value;
1091 } /* Hnewref() */
1092
1093 /******************************************************************************
1094 NAME
1095 Htagnewref - returns a ref that is unique in the file for a given tag
1096
1097 DESCRIPTION
1098 Returns a ref number that can be used with any tag to produce a
1099 unique tag/ref. Successive calls to Hnewref will generate a
1100 strictly increasing sequence until the highest possible ref had been
1101 returned, then Hnewref will return unused ref's starting from 1.
1102
1103 RETURNS
1104 returns the ref number, 0 otherwise
1105
1106 *******************************************************************************/
1107 uint16
Htagnewref(int32 file_id,uint16 tag)1108 Htagnewref(int32 file_id,/* IN: File ID the tag/refs are in */
1109 uint16 tag /* IN: Tag to search for a new ref for */)
1110 {
1111 CONSTR(FUNC, "Htagnewref");
1112 filerec_t *file_rec; /* file record */
1113 tag_info *tinfo_ptr; /* pointer to the info for a tag */
1114 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
1115 uint16 base_tag = BASETAG(tag); /* corresponding base tag (if the tag is special) */
1116 uint16 ret_value = DFREF_NONE;
1117
1118 /* clear error stack and check validity of file record id */
1119 HEclear();
1120 file_rec = HAatom_object(file_id);
1121 if (BADFREC(file_rec))
1122 HGOTO_ERROR(DFE_ARGS, 0);
1123
1124 if((tip_ptr = (tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1125 ret_value = 1; /* The first available ref */
1126 else
1127 { /* found an existing tag */
1128 tinfo_ptr = *tip_ptr; /* get the pointer to the tag info */
1129 if((ret_value = (uint16)bv_find(tinfo_ptr->b,-1,BV_FALSE)) == (uint16)FAIL)
1130 HGOTO_ERROR(DFE_BVFIND, 0);
1131 } /* end else */
1132
1133 done:
1134 if(ret_value == 0)
1135 { /* Error condition cleanup */
1136
1137 } /* end if */
1138
1139 /* Normal function cleanup */
1140 return ret_value;
1141 } /* Htagnewref() */
1142
1143 /******************************************************************************
1144 NAME
1145 Hfind - locate the next object of a search in an HDF file
1146
1147 DESCRIPTION
1148 Searches for the `next' DD that fits the search tag/ref. Wildcards
1149 apply. If origin is DF_FORWARD, search from current position forwards
1150 in the file, otherwise DF_BACKWARD searches backward from the current
1151 position in the file. If *find_tag and *find_ref are both set to
1152 0, this indicates the beginning of a search, and the search will
1153 start from the beginning of the file if the direction is DF_FORWARD
1154 and from the and of the file if the direction is DF_BACKWARD.
1155
1156 RETURNS
1157 returns SUCCEED (0) if successful and FAIL (-1) otherwise
1158
1159 *******************************************************************************/
Hfind(int32 file_id,uint16 search_tag,uint16 search_ref,uint16 * find_tag,uint16 * find_ref,int32 * find_offset,int32 * find_length,intn direction)1160 intn Hfind(int32 file_id, /* IN: file ID to search in */
1161 uint16 search_tag, /* IN: the tag to search for (can be DFTAG_WILDCARD) */
1162 uint16 search_ref, /* IN: ref to search for (can be DFREF_WILDCARD) */
1163 uint16 *find_tag, /* IN: if (*find_tag==0) and (*find_ref==0) then start search */
1164 /* OUT: tag matching the search tag */
1165 uint16 *find_ref, /* IN: if (*find_tag==0) and (*find_ref==0) then start search */
1166 /* OUT: ref matching the search ref */
1167 int32 *find_offset, /* OUT: offset of the data element found */
1168 int32 *find_length, /* OUT: length of the data element found */
1169 intn direction /* IN: Direction to search in: */
1170 /* DF_FORWARD searches forward from the current location */
1171 /* DF_BACKWARD searches backward from the current location */
1172 )
1173 {
1174 CONSTR(FUNC, "Hfind"); /* for HERROR */
1175 filerec_t *file_rec; /* file record */
1176 dd_t *dd_ptr; /* ptr to current ddlist searched */
1177 intn ret_value = SUCCEED;
1178
1179 /* clear error stack and check validity of the access id */
1180 HEclear();
1181 if (file_id == FAIL || /* search_ref > MAX_REF || */ find_tag == NULL
1182 || find_ref == NULL || find_offset == NULL || find_length == NULL
1183 || (direction != DF_FORWARD && direction != DF_BACKWARD))
1184 HGOTO_ERROR(DFE_ARGS, FAIL);
1185
1186 file_rec = HAatom_object(file_id);
1187 if (BADFREC(file_rec))
1188 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1189
1190 dd_ptr = NULL;
1191 if (*find_ref != 0 || *find_tag != 0)
1192 { /* continue a search */
1193 /* get the block and index of the last tag/ref found, to continue */
1194 if (HTIfind_dd(file_rec, *find_tag, *find_ref, &dd_ptr, direction) == FAIL)
1195 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1196 } /* end else */
1197
1198 /* Go get the next match in the given direction */
1199 if (HTIfind_dd(file_rec, search_tag, search_ref, &dd_ptr, direction) == FAIL)
1200 HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1201
1202 *find_tag = dd_ptr->tag;
1203 *find_ref = dd_ptr->ref;
1204 *find_offset = dd_ptr->offset;
1205 *find_length = dd_ptr->length;
1206
1207 done:
1208 if(ret_value == FAIL)
1209 { /* Error condition cleanup */
1210
1211 } /* end if */
1212
1213 /* Normal function cleanup */
1214 return ret_value;
1215 } /* end Hfind() */
1216
1217 /******************************************************************************
1218 NAME
1219 HDcheck_tagref - Checks to see if tag/ref is in DD list i.e. created already
1220
1221 DESCRIPTION
1222 Routine checks to see if tag/ref exists in the DD list i.e. has
1223 been created.
1224
1225 RETURNS
1226 0-> tag/ref does not exist
1227 1-> tag/ref exists
1228 -1-> function failed
1229
1230 *******************************************************************************/
1231 intn
HDcheck_tagref(int32 file_id,uint16 tag,uint16 ref)1232 HDcheck_tagref(int32 file_id, /* IN: id of file */
1233 uint16 tag, /* IN: Tag to check */
1234 uint16 ref /* IN: ref to check */)
1235 {
1236 CONSTR(FUNC, "HDcheck_tagref"); /* for HERROR */
1237 filerec_t *file_rec = NULL; /* file record */
1238 dd_t *dd_ptr = NULL; /* ptr to the DD info for the tag/ref */
1239 tag_info **tip_ptr = NULL; /* ptr to the ptr to the info for a tag */
1240 tag_info *tinfo_ptr = NULL; /* pointer to the info for a tag */
1241 uint16 base_tag; /* corresponding base tag (if the tag is special) */
1242 intn ret_value = 1; /* default tag/ref exists */
1243
1244 /* clear error stack */
1245 HEclear();
1246
1247 /* check args */
1248 file_rec = HAatom_object(file_id);
1249 if(file_rec == NULL
1250 || (tag == DFTAG_NULL || tag==DFTAG_WILDCARD)
1251 || ref == DFREF_WILDCARD)
1252 HGOTO_ERROR(DFE_ARGS, -1);
1253
1254 base_tag = BASETAG(tag);
1255
1256 /* Try to find the regular tag in the tag info tree */
1257 if((tip_ptr = (tag_info **)tbbtdfind(file_rec->tag_tree,
1258 (VOIDP)&base_tag,NULL)) == NULL)
1259 HGOTO_DONE(0); /* Not an error, we just didn't find the object */
1260
1261 tinfo_ptr = *tip_ptr; /* get the pointer to the tag info */
1262 if((dd_ptr = DAget_elem(tinfo_ptr->d,(intn)ref)) == NULL)
1263 HGOTO_DONE(0); /* Not an error, we just didn't find the object */
1264
1265 /* found if we reach here*/
1266 ret_value = 1;
1267
1268 done:
1269 if(ret_value == -1)
1270 { /* Error condition cleanup */
1271
1272 } /* end if */
1273
1274 /* Normal function cleanup */
1275
1276 return ret_value;
1277 } /* HDcheck_tagref() */
1278
1279 /************************************************************************
1280 NAME
1281 HDreuse_tagref -- reuse a data descriptor preserving tag/ref(assumes DD exists)
1282
1283 DESCRIPTION
1284 Reuses the data descriptor of tag/ref in the dd list of the file.
1285 The tag/ref must already exist in the DD list.
1286 This routine is unsafe and may leave a file in a condition that is
1287 not usable by some routines. Use with care. Not valid for
1288 special elments right now. Used for allowing the data to change
1289 and move somewhere else in the file for non-special elements.
1290 Must be carefully if apply to higher-level objects like GR's and SDS
1291 that are comprised of other objects.
1292 Usefull when re-writing simple elements whose size changes while
1293 preserving the original tag/ref of the element since other elements
1294 might refer to this element by tag/ref e.g. in a Vgroup.
1295
1296 NOTE: this routine is similiar to Hdeldd() but with a different name
1297
1298 RETURNS
1299 returns SUCCEED (0) if successful, FAIL (-1) otherwise
1300 ************************************************************************/
1301 intn
HDreuse_tagref(int32 file_id,uint16 tag,uint16 ref)1302 HDreuse_tagref(int32 file_id, /* IN: id of file */
1303 uint16 tag, /* IN: tag of data descriptor to reuse */
1304 uint16 ref /* IN: ref of data descriptor to reuse */ )
1305 {
1306 CONSTR(FUNC, "HDreusedd"); /* for HERROR */
1307 filerec_t *file_rec = NULL; /* file record */
1308 atom_t ddid; /* ID for the DD */
1309 intn ret_value = SUCCEED;
1310
1311 /* clear error stack and check validity of file record id */
1312 HEclear();
1313
1314 file_rec = HAatom_object(file_id);
1315 if (BADFREC(file_rec) || tag == DFTAG_WILDCARD || ref == DFREF_WILDCARD)
1316 HGOTO_ERROR(DFE_ARGS, FAIL);
1317
1318 /* look for the dd to reuse */
1319 if ((ddid = HTPselect(file_rec, tag, ref)) == FAIL)
1320 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1321
1322 /* could reuse space in file by calling HPfreediskblock() routine
1323 but it does nothing for now. For later. */
1324 /* if (HPfreediskblock(file_rec,dd_ptr->offset,dd_ptr->length) == FAIL)
1325 HGOTO_ERROR(DFE_INTERNAL, FAIL); */
1326
1327 /* reuse the dd by setting the offset and length to
1328 INVALID_OFFSET and INVALID_LENGTH*/
1329 if (HTPupdate(ddid,INVALID_OFFSET, INVALID_LENGTH) == FAIL)
1330 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1331
1332 /* We leave the ref # as 'used' in the tag tree and
1333 dont' delete from dynarray of refs. */
1334
1335 /* Remove DD from atom group since it should get re-created in Hstartaccess().
1336 This could be handled better if Hstartaccess() was revamped
1337 to not create new access records for existing tag/ref pairs
1338 as well as revamping a few other routines. */
1339 if(HAremove_atom(ddid)==NULL)
1340 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1341
1342 done:
1343 if(ret_value == FAIL)
1344 { /* Error condition cleanup */
1345
1346 } /* end if */
1347
1348 /* Normal function cleanup */
1349 return ret_value;
1350 } /* end HDreuse_tagref */
1351
1352 /*--------------------------------------------------------------------------
1353 NAME
1354 Hdeldd -- delete a data descriptor
1355 USAGE
1356 intn Hdeldd(file_id, tag, ref)
1357 int32 file_id; IN: id of file
1358 int16 tag; IN: tag of data descriptor to delete
1359 int16 ref; IN: ref of data descriptor to delete
1360 RETURNS
1361 returns SUCCEED (0) if successful, FAIL (-1) otherwise
1362 DESCRIPTION
1363 Deletes a data descriptor of tag/ref from the dd list of the file.
1364 This routine is unsafe and may leave a file in a condition that is
1365 not usable by some routines. Use with care.
1366 For example, if this element is contained in a Vgroup, that group
1367 will *NOT* get updated to reflect that this element has been deleted.
1368
1369 --------------------------------------------------------------------------*/
Hdeldd(int32 file_id,uint16 tag,uint16 ref)1370 intn Hdeldd(int32 file_id, uint16 tag, uint16 ref)
1371 {
1372 CONSTR(FUNC, "Hdeldd"); /* for HERROR */
1373 filerec_t *file_rec; /* file record */
1374 atom_t ddid; /* ID for the DD */
1375 intn ret_value = SUCCEED;
1376
1377 /* clear error stack and check validity of file record id */
1378 HEclear();
1379 file_rec = HAatom_object(file_id);
1380 if (BADFREC(file_rec) || tag == DFTAG_WILDCARD || ref == DFREF_WILDCARD)
1381 HGOTO_ERROR(DFE_ARGS, FAIL);
1382
1383 /* look for the dd to delete */
1384 if ((ddid=HTPselect(file_rec, tag, ref)) == FAIL)
1385 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1386
1387 /* delete the dd */
1388 if (HTPdelete(ddid) == FAIL)
1389 HGOTO_ERROR(DFE_CANTDELDD, FAIL);
1390
1391 done:
1392 if(ret_value == FAIL)
1393 { /* Error condition cleanup */
1394
1395 } /* end if */
1396
1397 /* Normal function cleanup */
1398 return ret_value;
1399 } /* end Hdeldd */
1400
1401 #ifdef DEBUGGING
1402 /*--------------------------------------------------------------------------
1403 NAME
1404 HTPdump_dds -- Dump out the dd information for a file
1405 USAGE
1406 intn HTPdump_dds(file_id)
1407 int32 file_id; IN: file ID of HDF file to dump
1408 FILE *fout; IN: file stream to output to
1409 RETURNS
1410 returns SUCCEED (0) if successful and FAIL (-1) if failed.
1411 DESCRIPTION
1412 Prints out all the information (that you could _ever_ want to know) about
1413 the dd blocks and dd list for a file.
1414
1415 --------------------------------------------------------------------------*/
HTPdump_dds(int32 file_id,FILE * fout)1416 intn HTPdump_dds(int32 file_id, FILE *fout)
1417 {
1418 CONSTR(FUNC, "HTPdump_dds");
1419 filerec_t *file_rec; /* file record */
1420 int ret_value = SUCCEED;
1421
1422 /* clear error stack and check validity of file record id */
1423 HEclear();
1424 file_rec = HAatom_object(file_id);
1425 if (BADFREC(file_rec))
1426 HGOTO_ERROR(DFE_ARGS, FAIL);
1427
1428 /* Print out each DD block */
1429 {
1430 ddblock_t *block=file_rec->ddhead; /* dd block currently dumping */
1431 intn blk_count=0; /* Count of the number of blocks we've dumped */
1432 intn i; /* local counting variable */
1433
1434 while(block!=NULL)
1435 {
1436 dd_t *curr_dd; /* current dd to dump */
1437
1438 fprintf(fout,"DD block %d\n",blk_count);
1439 fprintf(fout,"# of DDs: %d, next block offset=%ld\n",(int)block->ndds,(long)block->nextoffset);
1440 fprintf(fout,"DD block offset: %ld, dirty?=%d\n",(long)block->myoffset,(int)block->dirty);
1441 for(i=0, curr_dd=block->ddlist; i<block->ndds; i++,curr_dd++)
1442 fprintf(fout,"%5d: tag/ref=(%5u/%5u), offset=%7ld, length=%7ld\n",(int)i,(unsigned)curr_dd->tag,(unsigned)curr_dd->ref,(long)curr_dd->offset,(long)curr_dd->length);
1443 blk_count++;
1444 block=block->next;
1445 } /* end while */
1446 } /* End of ddblock dumping code */
1447
1448 /* Dump the tag tree */
1449 {
1450 VOIDP *t;
1451
1452 if (NULL != (t = (VOIDP *) tbbtfirst((TBBT_NODE *) * (file_rec->tag_tree))))
1453 { /* found at least one node in the tree */
1454 tag_info *tinfo_ptr; /* pointer to the info for a tag */
1455
1456 do
1457 { /* dump each node */
1458 intn size; /* # of elements in the array */
1459 intn i; /* local counting variable */
1460
1461 tinfo_ptr = (tag_info *) * t; /* get actual pointer to the tag info */
1462 fprintf(fout,"Tag: %u\n",tinfo_ptr->tag);
1463
1464 /* Dump the ref # dynarray */
1465 if((size=DAsize_array(tinfo_ptr->d))!=FAIL)
1466 {
1467 VOIDP elem;
1468
1469 fprintf(fout,"dynarray size=%d\n",size);
1470 for(i=0; i<size; i++)
1471 {
1472 elem=DAget_elem(tinfo_ptr->d,i);
1473 if(elem!=NULL)
1474 fprintf(fout,"dynarray[%d]=%p\n",i,elem);
1475 } /* end for */
1476 } /* end if */
1477
1478 /* Dump the ref # bit-vector */
1479 if((size=bv_size(tinfo_ptr->b))!=FAIL)
1480 {
1481 intn bit;
1482
1483 fprintf(fout,"bitvector size=%d\n",size);
1484 fprintf(fout,"bits set:");
1485 for(i=0; i<size; i++)
1486 {
1487 bit=bv_get(tinfo_ptr->b,i);
1488 if(bit!=BV_FALSE)
1489 fprintf(fout,"%5d",i);
1490 } /* end for */
1491 fprintf(fout,"\n");
1492 } /* end if */
1493
1494 /* Get the next tag node */
1495 t = (VOIDP *) tbbtnext((TBBT_NODE *) t);
1496 } while(t!=NULL);
1497 }
1498 else
1499 fprintf(fout,"No nodes in tag tree\n");
1500 } /* End of tag node dumping */
1501
1502 done:
1503 if(ret_value == FAIL)
1504 { /* Error condition cleanup */
1505
1506 } /* end if */
1507
1508 /* Normal function cleanup */
1509
1510 return ret_value;
1511 } /* HTPdump_dds */
1512 #endif /* DEBUGGING */
1513
1514
1515
1516 /* Private, static, internal routines. Do not call from outside this module */
1517
1518 /*--------------------------------------------------------------------------
1519 NAME
1520 HTInew_dd_block -- create a new (empty) DD block
1521 USAGE
1522 intn HTInew_dd_block(file_rec)
1523
1524 filerec_t * file_rec; IN: file record
1525 RETURNS
1526 returns SUCCEED (0) if successful and FAIL (-1) if failed.
1527 DESCRIPTION
1528 Create a new DDblock in the file. Update the previously last DDblock so
1529 that its offset points to the newly created one.
1530
1531 --------------------------------------------------------------------------*/
HTInew_dd_block(filerec_t * file_rec)1532 static intn HTInew_dd_block(filerec_t * file_rec)
1533 {
1534 CONSTR(FUNC, "HTInew_dd_block"); /* for HERROR */
1535 int32 nextoffset; /* offset of new ddblock */
1536 uint8 ddhead[NDDS_SZ+OFFSET_SZ]; /* storage for the DD header */
1537 int32 offset; /* offset to the offset of new ddblock */
1538 ddblock_t *block; /* Block the DD is located in */
1539 dd_t *list; /* dd list array of new dd block */
1540 uint8 *p; /* Temporary buffer pointer. */
1541 intn ndds; /* number of ndds in new DD block */
1542 intn ret_value = SUCCEED;
1543
1544 HEclear();
1545 /* check integrity of file record */
1546 if (file_rec->ddhead==NULL || file_rec->ddlast==NULL)
1547 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1548
1549 /* allocate new dd block record and fill in data */
1550 if ((block = (ddblock_t *) HDmalloc(sizeof(ddblock_t))) == NULL)
1551 HGOTO_ERROR(DFE_NOSPACE, FAIL);
1552 block->ndds = (int16)(ndds = (intn)file_rec->ddhead->ndds); /* snarf from first block */
1553 block->next = (ddblock_t *) NULL;
1554 block->nextoffset = 0;
1555
1556 /* Keep the filerec_t pointer around for each ddblock */
1557 block->frec=file_rec;
1558
1559 /* get room for the new DD block in the file */
1560 if ((nextoffset = HPgetdiskblock(file_rec, NDDS_SZ + OFFSET_SZ + (ndds * DD_SZ), TRUE)) == FAIL)
1561 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1562 block->myoffset = nextoffset; /* set offset of new block */
1563 block->dirty = (uintn)file_rec->cache; /* if we're caching, wait to write DD block */
1564
1565 if (file_rec->cache) /* if we are caching, wait to update previous DD block */
1566 file_rec->dirty |= DDLIST_DIRTY; /* indicate file needs to be flushed */
1567 else
1568 {
1569 p = ddhead;
1570 INT16ENCODE(p, block->ndds);
1571 INT32ENCODE(p, (int32) 0);
1572 if (HP_write(file_rec, ddhead, NDDS_SZ + OFFSET_SZ) == FAIL)
1573 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1574 } /* end else */
1575
1576 /* set up the dd list of this dd block and put it in the file
1577 after the dd block header */
1578 list = block->ddlist = (dd_t *) HDmalloc((uint32) ndds * sizeof(dd_t));
1579 if (list == (dd_t *) NULL)
1580 HGOTO_ERROR(DFE_NOSPACE, FAIL);
1581
1582 /* Fill the block with NIL tags */
1583 list[0].tag = DFTAG_NULL;
1584 list[0].ref = DFREF_NONE;
1585 list[0].length = INVALID_LENGTH;
1586 list[0].offset = INVALID_OFFSET;
1587 list[0].blk = block;
1588 HDmemfill(&list[1],&list[0],sizeof(dd_t),(uint32)ndds-1);
1589
1590 if (file_rec->cache!=0)
1591 { /* if we are caching, wait to update previous DD block */
1592 uint8 *tbuf; /* temporary buffer */
1593
1594 tbuf=(uint8 *)HDmalloc(ndds*DD_SZ);
1595 if(tbuf==(uint8 *)NULL)
1596 HGOTO_ERROR(DFE_NOSPACE, FAIL);
1597
1598 p = tbuf;
1599 DDENCODE(p, (uint16) DFTAG_NULL, (uint16) DFREF_NONE,
1600 (int32) INVALID_LENGTH, (int32) INVALID_OFFSET);
1601 HDmemfill(p,tbuf,DD_SZ,(uint32)(ndds-1));
1602
1603 if (HP_write(file_rec, tbuf, ndds * DD_SZ) == FAIL)
1604 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1605
1606 HDfree(tbuf);
1607 } /* end if */
1608
1609 /* update previously last ddblock to point to this new dd block */
1610 file_rec->ddlast->nextoffset = nextoffset;
1611 block->prev = file_rec->ddlast;
1612 file_rec->ddlast->next = block;
1613 if (file_rec->cache)
1614 { /* if we are caching, wait to update previous DD block */
1615 file_rec->dirty |= DDLIST_DIRTY; /* indicate file needs to be flushed */
1616 file_rec->ddlast->dirty = TRUE; /* indicate this block needs to be flushed */
1617 } /* end if */
1618 else
1619 {
1620 if (file_rec->ddhead == file_rec->ddlast)
1621 offset = MAGICLEN + NDDS_SZ;
1622 else
1623 offset = file_rec->ddlast->prev->nextoffset + NDDS_SZ;
1624 p = ddhead;
1625 INT32ENCODE(p, nextoffset);
1626 if (HPseek(file_rec, offset) == FAIL)
1627 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1628 if (HP_write(file_rec, ddhead, OFFSET_SZ) == FAIL)
1629 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1630 } /* end else */
1631
1632 /* update file record */
1633 file_rec->ddlast = block;
1634
1635 /* set the end of the file to the end of the current DD block */
1636 file_rec->f_end_off = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (block->ndds * DD_SZ);
1637
1638 done:
1639 if(ret_value == FAIL)
1640 { /* Error condition cleanup */
1641
1642 } /* end if */
1643
1644 /* Normal function cleanup */
1645
1646 return ret_value;
1647 } /* HTInew_dd_block */
1648
1649 /*--------------------------------------------------------------------------
1650 NAME
1651 HTIfind_dd -- find a specific DD in the file
1652 USAGE
1653 int HTIfind_dd(file_rec, tag, ref, dd_ptr, direction)
1654 filerec_t * file_rec; IN: file record to search
1655 uint16 tag; IN: tag of element to find
1656 uint16 ref; IN: ref of element to find
1657 dd_t ** pdd; OUT: pointer to the DD in memory
1658 intn direction; IN: direction to search
1659 (DF_FORWARD / DF_BACKWARD)
1660 RETURNS
1661 returns SUCCEED (0) if successful and FAIL (-1) if failed.
1662 DESCRIPTION
1663 Find the dd with tag and ref, by returning the block where the dd resides
1664 and the index of the dd in the ddblock ddlist.
1665
1666 --------------------------------------------------------------------------*/
HTIfind_dd(filerec_t * file_rec,uint16 look_tag,uint16 look_ref,dd_t ** pdd,intn direction)1667 static intn HTIfind_dd(filerec_t * file_rec, uint16 look_tag, uint16 look_ref,
1668 dd_t ** pdd, intn direction)
1669 {
1670 #ifdef LATER
1671 CONSTR(FUNC, "HTIfind_dd"); /* for HERROR */
1672 #endif /* LATER */
1673 intn idx; /* index into ddlist of current dd searched */
1674 ddblock_t *block; /* ptr to current ddblock searched */
1675 dd_t *list; /* ptr to current ddlist searched */
1676 uint16 special_tag; /* corresponding special tag */
1677 intn ret_value = SUCCEED;
1678
1679 HEclear();
1680 /* Create the special version of the tag to search for also */
1681 special_tag = MKSPECIALTAG(look_tag);
1682
1683 if(look_tag!=DFTAG_WILDCARD && look_ref!=DFTAG_WILDCARD)
1684 { /* easy to optimize case, looking for a specific tag/ref pair */
1685 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
1686 tag_info *tinfo_ptr; /* pointer to the info for a tag */
1687 dd_t *dd_ptr; /* ptr to the DD info for a tag/ref */
1688 uint16 base_tag=BASETAG(look_tag); /* corresponding base tag (if the tag is special) */
1689
1690 /* Try to find the regular tag in the tag info tree */
1691 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1692 HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1693
1694 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
1695 if((dd_ptr=DAget_elem(tinfo_ptr->d,(intn)look_ref))==NULL)
1696 HGOTO_DONE(FAIL); /* Not an error, we just didn't find the object */
1697
1698 *pdd=dd_ptr;
1699 HGOTO_DONE(SUCCEED);
1700 } /* end if */
1701 else
1702 { /* handle wildcards, etc. */
1703 if (direction == DF_FORWARD)
1704 { /* search forward through the DD list */
1705 if(*pdd==NULL)
1706 {
1707 block=file_rec->ddhead;
1708 idx=0;
1709 } /* end if */
1710 else
1711 {
1712 block=(*pdd)->blk;
1713 idx=((*pdd)-&block->ddlist[0])+1;
1714 } /* end else */
1715 if(look_tag==DFTAG_WILDCARD && look_ref==DFREF_WILDCARD)
1716 { /* Both tag & ref are wildcards */
1717 for (; block; block = block->next)
1718 {
1719 list = &block->ddlist[idx];
1720 for (; idx < block->ndds; idx++, list++)
1721 {
1722 /* skip the empty dd's */
1723 if (list->tag == DFTAG_NULL)
1724 continue;
1725
1726 /* we have a match !! (anything matches! :-) */
1727 *pdd=list;
1728 HGOTO_DONE(SUCCEED);
1729 } /* end for */
1730
1731 /* start from beginning of the next dd list */
1732 idx = 0;
1733 } /* end for */
1734 } /* end if */
1735 else if(look_tag==DFTAG_NULL && look_ref==DFTAG_WILDCARD)
1736 { /* special case for quick lookup of empty DD's */
1737 if(file_rec->ddnull==NULL)
1738 block=file_rec->ddhead;
1739 else
1740 block=file_rec->ddnull;
1741 if(file_rec->ddnull_idx<0)
1742 idx=0;
1743 else
1744 idx=file_rec->ddnull_idx+1;
1745
1746 for (; block; block = block->next)
1747 {
1748 list = &block->ddlist[idx];
1749 for (; idx < block->ndds; idx++, list++)
1750 {
1751 /* skip the empty dd's */
1752 if (list->tag == DFTAG_NULL)
1753 {
1754 /* we have a match !! */
1755 *pdd=list;
1756
1757 /* Update the DFTAG_NULL pointers */
1758 file_rec->ddnull=block;
1759 file_rec->ddnull_idx=idx;
1760
1761 HGOTO_DONE(SUCCEED);
1762 } /* end if */
1763 } /* end for */
1764
1765 /* start from beginning of the next dd list */
1766 idx = 0;
1767 } /* end for */
1768 } /* end if */
1769 else if(look_tag==DFTAG_WILDCARD)
1770 { /* tag is wildcard */
1771 for (; block; block = block->next)
1772 {
1773 list = &block->ddlist[idx];
1774 for (; idx < block->ndds; idx++, list++)
1775 {
1776 /* skip the empty dd's */
1777 if (list->tag == DFTAG_NULL)
1778 continue;
1779
1780 if (list->ref == look_ref)
1781 {
1782 /* we have a match !! */
1783 *pdd=list;
1784 HGOTO_DONE(SUCCEED);
1785 } /* end if */
1786 } /* end for */
1787
1788 /* start from beginning of the next dd list */
1789 idx = 0;
1790 } /* end for */
1791 } /* end if */
1792 else if(look_ref==DFREF_WILDCARD)
1793 { /* ref is wildcard */
1794 #ifndef OLD_WAY
1795 if(special_tag==DFTAG_NULL)
1796 {
1797 /* Change this to lookup the next used ref # in the bitvector or dynarray -QAK */
1798 for (; block; block = block->next)
1799 {
1800 list = &block->ddlist[idx];
1801 for (; idx < block->ndds; idx++, list++)
1802 {
1803 /* skip the empty dd's */
1804 if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1805 continue;
1806
1807 if (list->tag == look_tag)
1808 {
1809 /* we have a match !! */
1810 *pdd=list;
1811 HGOTO_DONE(SUCCEED);
1812 } /* end if */
1813 } /* end for */
1814
1815 /* start from beginning of the next dd list */
1816 idx = 0;
1817 } /* end for */
1818 } /* end if */
1819 else
1820 {
1821 for (; block; block = block->next)
1822 {
1823 list = &block->ddlist[idx];
1824 for (; idx < block->ndds; idx++, list++)
1825 {
1826 /* skip the empty dd's */
1827 if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1828 continue;
1829
1830 if (list->tag == look_tag || list->tag == special_tag)
1831 {
1832 /* we have a match !! */
1833 *pdd=list;
1834 HGOTO_DONE(SUCCEED);
1835 } /* end if */
1836 } /* end for */
1837
1838 /* start from beginning of the next dd list */
1839 idx = 0;
1840 } /* end for */
1841 } /* end else */
1842 #else /* OLD_WAY */
1843 /* Hmm, not working yet?... -QAK */
1844 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
1845 tag_info *tinfo_ptr; /* pointer to the info for a tag */
1846 dd_t *dd_ptr; /* ptr to the DD info for a tag/ref */
1847 uint16 base_tag=BASETAG(look_tag); /* corresponding base tag (if the tag is special) */
1848 int32 last_ref; /* the last ref # found */
1849 uint16 found_ref; /* next ref # found */
1850
1851 /* Try to find the regular tag in the tag info tree */
1852 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
1853 HGOTO_ERROR(DFE_BADTAG, FAIL);
1854
1855 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
1856 if(*pdd==NULL) /* check if we are searching from the beginning */
1857 last_ref=-1;
1858 else
1859 last_ref=block->ddlist[idx].ref;
1860 if((found_ref=bv_find(tinfo_ptr->b,last_ref,1))==(uint16)FAIL)
1861 HGOTO_ERROR(DFE_BVFIND, FAIL);
1862
1863 if((dd_ptr=DAget_elem(tinfo_ptr->d,found_ref))==NULL)
1864 HGOTO_ERROR(DFE_BADREF, FAIL);
1865
1866 *pdd=dd_ptr;
1867 HGOTO_DONE(SUCCEED);
1868 #endif /* OLD_WAY */
1869 } /* end if */
1870 else
1871 { /* Both tag & ref are not wildcards */
1872 for (; block; block = block->next)
1873 {
1874 list = &block->ddlist[idx];
1875 for (; idx < block->ndds; idx++, list++)
1876 {
1877 /* skip the empty dd's */
1878 if (list->tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1879 continue;
1880
1881 if ((list->tag == look_tag
1882 || (special_tag != DFTAG_NULL && list->tag == special_tag))
1883 && list->ref == look_ref)
1884 {
1885 /* we have a match !! */
1886 *pdd=list;
1887 HGOTO_DONE(SUCCEED);
1888 } /* end if */
1889 } /* end for */
1890
1891 /* start from beginning of the next dd list */
1892 idx = 0;
1893 } /* end for */
1894 } /* end else */
1895 } /* end if */
1896 else if (direction == DF_BACKWARD)
1897 { /* search backward through the DD list */
1898 if(*pdd==NULL)
1899 {
1900 block=file_rec->ddlast;
1901 idx=block->ndds-1;
1902 } /* end if */
1903 else
1904 {
1905 block=(*pdd)->blk;
1906 idx=((*pdd)-&block->ddlist[0])-1;
1907 } /* end else */
1908 for (; block;)
1909 {
1910 list = block->ddlist;
1911 for (; idx >= 0; idx--)
1912 {
1913 /* skip the empty dd's */
1914 if (list[idx].tag == DFTAG_NULL && look_tag != DFTAG_NULL)
1915 continue;
1916
1917 if (((look_tag == DFTAG_WILDCARD || list[idx].tag == look_tag)
1918 || (special_tag != DFTAG_NULL && list[idx].tag == special_tag))
1919 && (look_ref == DFREF_WILDCARD || list[idx].ref == look_ref))
1920 {
1921
1922 /* we have a match !! */
1923 *pdd=&list[idx];
1924 HGOTO_DONE(SUCCEED);
1925 } /* end if */
1926 } /* end for */
1927
1928 /* start from beginning of the next dd list */
1929 block = block->prev;
1930 if (block != NULL)
1931 idx = block->ndds - 1;
1932 } /* end for */
1933 } /* end if */
1934 } /* end else */
1935
1936 /* If we get here, we've failed */
1937 ret_value=FAIL;
1938
1939 done:
1940 if(ret_value == FAIL)
1941 { /* Error condition cleanup */
1942
1943 } /* end if */
1944
1945 /* Normal function cleanup */
1946
1947 return ret_value;
1948 } /* HTIfind_dd */
1949
1950 /*--------------------------------------------------------------------------
1951 NAME
1952 HTIupdate_dd -- update a DD on disk
1953 USAGE
1954 int HTIupdate_dd(file_rec, dd_ptr)
1955 filerec_t *file_rec; IN: id of file
1956 dd_t *dd_ptr; IN: pointer to dd to update
1957 RETURNS
1958 returns SUCCEED (0) if successful and FAIL (-1) if failed.
1959 DESCRIPTION
1960 Takes appropriate action to note that a DD in a DD block has changed
1961
1962 --------------------------------------------------------------------------*/
HTIupdate_dd(filerec_t * file_rec,dd_t * dd_ptr)1963 static intn HTIupdate_dd(filerec_t * file_rec, dd_t * dd_ptr)
1964 {
1965 CONSTR(FUNC, "HTIupdate_dd"); /* for HERROR */
1966 ddblock_t *block; /* DD block the dd is in */
1967 int32 idx; /* index of the DD in the DD block */
1968 intn ret_value = SUCCEED;
1969
1970 HEclear();
1971 block=dd_ptr->blk;
1972 idx=dd_ptr-&block->ddlist[0];
1973 if (file_rec->cache)
1974 { /* if caching is on, postpone update until later */
1975 file_rec->dirty |= DDLIST_DIRTY;
1976 block->dirty = TRUE;
1977 } /* end if */
1978 else
1979 {
1980 int32 offset; /* offset of updated dd in file */
1981 uint8 tbuf[DD_SZ]; /* storage for the DD */
1982 uint8 *p; /* temp buffer ptr */
1983
1984 /* look for offset of updated dd block in the file */
1985 offset = block->myoffset + (NDDS_SZ + OFFSET_SZ) + (idx * DD_SZ);
1986
1987 /* write in the updated dd */
1988 if (HPseek(file_rec, offset) == FAIL)
1989 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1990
1991 p = tbuf;
1992 DDENCODE(p, dd_ptr->tag, dd_ptr->ref, dd_ptr->offset, dd_ptr->length);
1993 if (HP_write(file_rec, tbuf, DD_SZ) == FAIL)
1994 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1995 } /* end else */
1996
1997 /* check whether to incr. offset of end of file */
1998 /* not certain whether this is actually necessary, but better safe than */
1999 /* sorry later... -QAK */
2000 if ((dd_ptr->offset != INVALID_OFFSET && dd_ptr->length != INVALID_LENGTH) &&
2001 ( dd_ptr->offset + dd_ptr->length) > file_rec->f_end_off)
2002 file_rec->f_end_off = dd_ptr->offset + dd_ptr->length;
2003
2004 done:
2005 if(ret_value == FAIL)
2006 { /* Error condition cleanup */
2007
2008 } /* end if */
2009
2010 /* Normal function cleanup */
2011
2012 return ret_value;
2013 } /* HTIupdate_dd */
2014
2015 /* ----------------------------- HTIcount_dd ------------------------------ */
2016 /*
2017 NAME
2018 HTIcount_dd -- counts the dd's of a certain type in file
2019 USAGE
2020 intn HTIcount_dd(file_rec, tag, ref, all_cnt, real_cnt)
2021 filerec_t * file_rec; IN: file record to search
2022 uint16 tag; IN: tag of element to find
2023 (can be DFTAG_WILDCARD)
2024 uint16 ref; IN: ref of element to find
2025 (can be DFREF_WILDCARD)
2026 uintn *all_cnt; OUT: Count of all the tag/ref pairs
2027 found, including DFTAG_NULL and
2028 DFTAG_FREE
2029 uintn *real_cnt; OUT: Count of all the tag/ref pairs
2030 found, excluding DFTAG_NULL and
2031 DFTAG_FREE
2032 RETURNS
2033 SUCCEED / FAIL
2034 DESCRIPTION
2035 Counts the number of tag/ref pairs in a file.
2036
2037 This routine keeps track of and returns to the user the number
2038 of all tag/refs and the number of "real" tag/refs found.
2039 "Real" tag/refs are any except DFTAG_NULL & DFTAG_FREE.
2040
2041 This routine always counts the total tag/refs in the file, no
2042 provision is made for partial searches.
2043
2044 ---------------------------------------------------------------------------*/
HTIcount_dd(filerec_t * file_rec,uint16 cnt_tag,uint16 cnt_ref,uintn * all_cnt,uintn * real_cnt)2045 static intn HTIcount_dd(filerec_t * file_rec, uint16 cnt_tag, uint16 cnt_ref,
2046 uintn *all_cnt, uintn *real_cnt)
2047 {
2048 uintn t_all_cnt = 0; /* count of all tag/refs found */
2049 uintn t_real_cnt = 0; /* count of all tag/refs except NULL & FREE */
2050 intn idx; /* index into ddlist of current dd searched */
2051 ddblock_t *block; /* ptr to current ddblock searched */
2052 dd_t *dd_ptr; /* ptr to current ddlist searched */
2053 uint16 special_tag; /* corresponding special tag */
2054
2055 HEclear();
2056 /* search for special version also */
2057 special_tag = MKSPECIALTAG(cnt_tag);
2058
2059 /* Change these algorithms to take advantage of the dynamic arrays for tags -QAK */
2060 switch(cnt_tag)
2061 {
2062 case DFTAG_WILDCARD:
2063 for (block = file_rec->ddhead; block != NULL; block = block->next)
2064 {
2065 t_all_cnt += (uintn)block->ndds;
2066
2067 dd_ptr = block->ddlist;
2068 for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2069 {
2070 /* skip the empty dd's */
2071 if (dd_ptr->tag == DFTAG_NULL || dd_ptr->tag == DFTAG_FREE)
2072 continue;
2073
2074 if ((cnt_ref == DFREF_WILDCARD || dd_ptr->ref == cnt_ref))
2075 t_real_cnt++;
2076 } /* end for */
2077 } /* end for */
2078 break;
2079
2080 case DFTAG_NULL:
2081 case DFTAG_FREE:
2082 for (block = file_rec->ddhead; block != NULL; block = block->next)
2083 {
2084 t_all_cnt += (uintn)block->ndds;
2085
2086 dd_ptr = block->ddlist;
2087 for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2088 if ((dd_ptr->tag == cnt_tag
2089 || (special_tag != DFTAG_NULL && dd_ptr->tag == special_tag))
2090 && (cnt_ref == DFREF_WILDCARD || dd_ptr->ref == cnt_ref))
2091 t_real_cnt++;
2092 } /* end for */
2093 break;
2094
2095 default:
2096 if(special_tag==DFTAG_NULL)
2097 {
2098 for (block = file_rec->ddhead; block != NULL; block = block->next)
2099 {
2100 t_all_cnt += (uintn)block->ndds;
2101
2102 dd_ptr = block->ddlist;
2103 for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2104 if (dd_ptr->tag == cnt_tag
2105 && (dd_ptr->ref == cnt_ref || cnt_ref == DFREF_WILDCARD))
2106 t_real_cnt++;
2107 } /* end for */
2108 } /* end if */
2109 else
2110 {
2111 if(cnt_ref==DFREF_WILDCARD)
2112 {
2113 for (block = file_rec->ddhead; block != NULL; block = block->next)
2114 {
2115 t_all_cnt += (uintn)block->ndds;
2116
2117 idx=0;
2118 dd_ptr = block->ddlist;
2119 if(block->ndds%2 == 1)
2120 if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2121 {
2122 t_real_cnt++;
2123 idx++;
2124 dd_ptr++;
2125 } /* end if */
2126 for (; idx < block->ndds; idx++, dd_ptr++)
2127 {
2128 if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2129 t_real_cnt++;
2130 idx++;
2131 dd_ptr++;
2132 if (dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2133 t_real_cnt++;
2134 } /* end for */
2135 } /* end for */
2136 } /* end if */
2137 else
2138 {
2139 for (block = file_rec->ddhead; block != NULL; block = block->next)
2140 {
2141 t_all_cnt += (uintn)block->ndds;
2142
2143 dd_ptr = block->ddlist;
2144 for (idx = 0; idx < block->ndds; idx++, dd_ptr++)
2145 if ((dd_ptr->tag == cnt_tag || dd_ptr->tag == special_tag)
2146 && dd_ptr->ref == cnt_ref)
2147 t_real_cnt++;
2148 } /* end for */
2149 } /* end else */
2150 } /* end else */
2151 break;
2152 } /* end switch */
2153
2154 *all_cnt = t_all_cnt;
2155 *real_cnt = t_real_cnt;
2156 return (SUCCEED);
2157 } /* HTIcount_dd */
2158
2159 /*--------------------------------------------------------------------------
2160 NAME
2161 HTIregister_tag_ref -- mark a ref # as used for a tag
2162 USAGE
2163 intn HTIregister_tag_ref(file_rec, dd_ptr)
2164 filerec_t * file_rec; IN: file record
2165 dd_t * dd_ptr; IN: pointer to the dd the tag/ref is in
2166 RETURNS
2167 returns SUCCEED (0) if successful and FAIL (-1) if failed.
2168 DESCRIPTION
2169 Marks a ref # as used for a given tag.
2170
2171 --------------------------------------------------------------------------*/
2172 static intn
HTIregister_tag_ref(filerec_t * file_rec,dd_t * dd_ptr)2173 HTIregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr)
2174 {
2175 CONSTR(FUNC, "HTIregister_tag_ref");
2176 tag_info *tinfo_ptr; /* pointer to the info for a tag */
2177 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
2178 uint16 base_tag=BASETAG(dd_ptr->tag); /* the base tag for the tag tree */
2179 int ret_value = SUCCEED;
2180
2181 HEclear();
2182 /* Add to the tag info tree */
2183 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
2184 { /* a new tag was found */
2185 if((tinfo_ptr=(tag_info *)HDcalloc(1,sizeof(tag_info)))==NULL)
2186 HGOTO_ERROR(DFE_NOSPACE, FAIL);
2187 tinfo_ptr->tag=base_tag;
2188
2189 /* Insert the tag node into the tree */
2190 tbbtdins(file_rec->tag_tree, (VOIDP) tinfo_ptr, NULL);
2191
2192 /* Take care of the bit-vector */
2193 if((tinfo_ptr->b=bv_new(-1,BV_EXTENDABLE))==NULL)
2194 HGOTO_ERROR(DFE_BVNEW, FAIL);
2195 /* Set the 0'th bit in the bit-vector (cannot be stored in HDF files) */
2196 /* Yes, this is a kludge due to ref # zero not being used -QAK */
2197 if(bv_set(tinfo_ptr->b,0,BV_TRUE)==FAIL)
2198 HGOTO_ERROR(DFE_BVSET, FAIL);
2199
2200 /* Take care of the dynarray */
2201 if((tinfo_ptr->d=DAcreate_array(REF_DYNARRAY_START,REF_DYNARRAY_INCR))==NULL)
2202 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2203 } /* end if */
2204 else
2205 { /* found an existing tag */
2206 intn ref_bit; /* bit of the ref # in the tag info */
2207
2208 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
2209 if((ref_bit=bv_get(tinfo_ptr->b,(intn)dd_ptr->ref))==FAIL)
2210 HGOTO_ERROR(DFE_BVGET, FAIL);
2211 if(ref_bit==BV_TRUE)
2212 HGOTO_ERROR(DFE_DUPDD, FAIL);
2213 } /* end else */
2214
2215 /* Set the bit in the bit-vector */
2216 if(bv_set(tinfo_ptr->b,(intn)dd_ptr->ref,BV_TRUE)==FAIL)
2217 HGOTO_ERROR(DFE_BVSET, FAIL);
2218
2219 /* Insert the DD info into the dynarray for later use */
2220 if(DAset_elem(tinfo_ptr->d,(intn)dd_ptr->ref,(VOIDP)dd_ptr)==FAIL)
2221 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2222
2223 done:
2224 if(ret_value == FAIL)
2225 { /* Error condition cleanup */
2226
2227 if(tinfo_ptr->d!=NULL)
2228 DAdestroy_array(tinfo_ptr->d,0);
2229 } /* end if */
2230
2231 /* Normal function cleanup */
2232
2233 return ret_value;
2234 } /* HTIregister_tag_ref */
2235
2236 /*--------------------------------------------------------------------------
2237 NAME
2238 HTIunregister_tag_ref -- mark a ref # as free for a tag
2239 USAGE
2240 intn HTIunregister_tag_ref(file_rec, tag, ref)
2241 filerec_t * file_rec; IN: file record
2242 dd_t *dd_ptr; IN: DD of the tag/ref to unregister
2243 RETURNS
2244 returns SUCCEED (0) if successful and FAIL (-1) if failed.
2245 DESCRIPTION
2246 Marks a ref # as free for a given tag.
2247
2248 --------------------------------------------------------------------------*/
HTIunregister_tag_ref(filerec_t * file_rec,dd_t * dd_ptr)2249 static intn HTIunregister_tag_ref(filerec_t * file_rec, dd_t *dd_ptr)
2250 {
2251 CONSTR(FUNC, "HTIunregister_tag_ref");
2252 tag_info *tinfo_ptr; /* pointer to the info for a tag */
2253 tag_info **tip_ptr; /* ptr to the ptr to the info for a tag */
2254 uint16 base_tag=BASETAG(dd_ptr->tag); /* the base tag for the tag tree */
2255 int ret_value = SUCCEED;
2256
2257 HEclear();
2258 /* Add to the tag info tree */
2259 if((tip_ptr=(tag_info **)tbbtdfind(file_rec->tag_tree,(VOIDP)&base_tag,NULL))==NULL)
2260 {
2261 HGOTO_ERROR(DFE_BADTAG, FAIL);
2262 } /* end if */
2263 else
2264 { /* found an existing tag */
2265 intn ref_bit; /* bit of the ref # in the tag info */
2266
2267 tinfo_ptr=*tip_ptr; /* get the pointer to the tag info */
2268 if((ref_bit=bv_get(tinfo_ptr->b,(intn)dd_ptr->ref))==FAIL)
2269 HGOTO_ERROR(DFE_BVGET, FAIL);
2270 if(ref_bit==BV_FALSE)
2271 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2272 if(bv_set(tinfo_ptr->b,(intn)dd_ptr->ref,BV_FALSE)==FAIL)
2273 HGOTO_ERROR(DFE_BVSET, FAIL);
2274
2275 /* Delete the DD info from the tag tree */
2276 if(DAdel_elem(tinfo_ptr->d,(intn)dd_ptr->ref)==NULL)
2277 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2278
2279 /* Delete the tag/ref from the file */
2280 dd_ptr->tag=DFTAG_NULL;
2281 } /* end else */
2282
2283 done:
2284 if(ret_value == FAIL)
2285 { /* Error condition cleanup */
2286
2287 } /* end if */
2288
2289 /* Normal function cleanup */
2290
2291 return ret_value;
2292 } /* HTIunregister_tag_ref */
2293
2294 /* ---------------------------- tagcompare ------------------------- */
2295 /*
2296 Compares two tag B-tree keys for equality. Similar to memcmp.
2297
2298 *** Only called by B-tree routines, should _not_ be called externally ***
2299 */
2300 intn
tagcompare(VOIDP k1,VOIDP k2,intn cmparg)2301 tagcompare(VOIDP k1, VOIDP k2, intn cmparg)
2302 {
2303 intn ret_value;
2304 /* shut compiler up */
2305 cmparg = cmparg;
2306
2307 ret_value = ((intn) ((*(uint16 *) k1) - (*(uint16 *) k2))); /* valid for integer keys */
2308
2309 return ret_value;
2310 } /* tagcompare */
2311
2312 /* ---------------------------- tagdestroynode ------------------------- */
2313 /*
2314 Frees tag B-Tree nodes
2315
2316 *** Only called by B-tree routines, should _not_ be called externally ***
2317 */
2318 VOID
tagdestroynode(VOIDP n)2319 tagdestroynode(VOIDP n)
2320 {
2321 tag_info *t=(tag_info *)n;
2322
2323 if(t->b!=NULL)
2324 bv_delete(t->b);
2325 if(t->d!=NULL)
2326 DAdestroy_array(t->d,0);
2327 HDfree((VOIDP) n);
2328 } /* tagdestroynode */
2329
2330