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 /*LINTLIBRARY */
17 /*+
18 FILE
19 hfile.c
20 HDF low level file I/O routines
21
22 H-Level Limits
23 ==============
24 o MAX_ACC access records open at a single time (#define in hfile.h)
25 o int16 total tags (fixed)
26 o int32 max length and offset of an element in an HDF file (fixed)
27
28 Routine prefix conventions
29 ==========================
30 HP: private, external
31 HI: private, static
32 HD: not-private, external (i.e. usable by non-developers)
33
34 "A" will be used to indicate that a routine is for parallel I/O.
35
36 Prefixes now have potentially three parts: (1) the interface, (2) optional
37 "A" to indicate parallel, and (3) scope:
38
39 <prefix> :== <interface>|<interface><scope>|<interface>A<scope>
40 <interface> :== H|HL|HX|SD|DFSD|DFAN|DFR8|...
41 <scope> :== D|P|I
42
43 Examples: HAP => H interface, parallel, private external
44 HAD => H interface, parallel, non-private external
45 HI => H interface, private static
46
47 EXPORTED ROUTINES
48 Hopen -- open or create a HDF file
49 Hclose -- close HDF file
50 Hstartread -- locate and position a read access elt on a tag/ref
51 Hnextread -- locate and position a read access elt on next tag/ref.
52 Hexist -- locate an object in an HDF file
53 Hinquire -- inquire stats of an access elt
54 Hstartwrite -- set up a WRITE access elt for a write
55 Happendable -- attempt make a dataset appendable
56 Hseek -- position an access element to an offset in data element
57 Hread -- read the next segment from data element
58 Hwrite -- write next data segment to data element
59 HDgetc -- read a byte from data element
60 HDputc -- write a byte to data element
61 Hendaccess -- to dispose of an access element
62 Hgetelement -- read in a data element
63 Hputelement -- writes a data element
64 Hlength -- returns length of a data element
65 Hoffset -- get offset of data element in the file
66 Hishdf -- tells if a file is an HDF file
67 Htrunc -- truncate a dataset to a length
68 Hsync -- sync file with memory
69 Hcache -- set low-level caching for a file
70 HDvalidfid -- check if a file ID is valid
71 HDerr -- Closes a file and return FAIL.
72 Hsetacceesstype -- set the I/O access type (serial, parallel, ...)
73 of a data element
74 Hgetlibversion -- return version info on current HDF library
75 Hgetfileversion -- return version info on HDF file
76 HPgetdiskblock -- Get the offset of a free block in the file.
77 HPfreediskblock -- Release a block in a file to be re-used.
78 HDread_drec -- reads a description record
79 HDcheck_empty -- determines if an element has been written with data
80 HDget_special_info -- get information about a special element
81 HDset_special_info -- reset information about a special element
82 HDspecial_type -- return the special type if the given element is special
83
84 File Memory Pool routines
85 -------------------------
86 Hmpset -- set pagesize and maximum number of pages to cache on next open/create
87 Hmpget -- get last pagesize and max number of pages cached for open/create
88
89 Special Tag routines
90 -------------------
91 HDmake_special_tag --
92 HDis_special_tag --
93 HDbaset_tag --
94
95 Macintosh specific Routines(unbuffered C I/O stubs on top of Mac toolbox)
96 --------------------------
97 mopen --
98 mclose --
99 mread --
100 mwrite --
101 mlsekk --
102
103 LOCAL ROUTINES
104 HIextend_file -- extend file to current length
105 HIget_function_table -- create special function table
106 HIgetspinfo -- return special info
107 HIunlock -- unlock a previously locked file record
108 HIget_filerec_node -- locate a filerec for a new file
109 HIrelease_filerec_node -- release a filerec
110 HIvalid_magic -- verify the magic number in a file
111 HIget_access_rec -- allocate a new access record
112 HIupdate_version -- determine whether new version tag should be written
113 HIread_version -- reads a version tag from a file
114 + */
115
116 #define HMASTER
117 #include "hdf.h"
118 #undef HMASTER
119 #define HFILE_MASTER
120 #include "hfile.h"
121 #include <errno.h>
122 #include "glist.h" /* for double-linked lists, stacks and queues */
123
124 /*--------------------- Locally defined Globals -----------------------------*/
125
126 /* The default state of the file DD caching */
127 PRIVATE intn default_cache = TRUE;
128
129 /* Whether we've installed the library termination function yet for this interface */
130 PRIVATE intn library_terminate = FALSE;
131 #ifdef OLD_WAY
132 PRIVATE list_head_t *cleanup_list = NULL;
133 #else
134 PRIVATE Generic_list *cleanup_list = NULL;
135 #endif
136
137 /* Whether to install the atexit routine */
138 PRIVATE intn install_atexit = TRUE;
139
140 /*--------------------- Externally defined Globals --------------------------*/
141 /* Function tables declarations. These function tables contain pointers
142 to functions that help access each type of special element. */
143
144 /* Functions for accessing the linked block special
145 data element. For definition of the linked block, see hblocks.c. */
146 extern funclist_t linked_funcs;
147
148 /* Functions for accessing external data elements, or data
149 elements that are in some other files. For definition of the external
150 data element, see hextelt.c. */
151 extern funclist_t ext_funcs;
152
153 /* Functions for accessing compressed data elements.
154 For definition of the compressed data element, see hcomp.c. */
155 extern funclist_t comp_funcs;
156
157 /* Functions for accessing chunked data elements.
158 For definition of the chunked data element, see hchunk.c. */
159 #include "hchunks.h"
160
161 /* Functions for accessing buffered data elements.
162 For definition of the buffered data element, see hbuffer.c. */
163 extern funclist_t buf_funcs;
164
165 /* Functions for accessing compressed raster data elements.
166 For definition of the compressed raster data element, see hcompri.c. */
167 extern funclist_t cr_funcs;
168
169 /* Table of these function tables for accessing special elements. The first
170 member of each record is the speical code for that type of data element. */
171 functab_t functab[] =
172 {
173 {SPECIAL_LINKED, &linked_funcs},
174 {SPECIAL_EXT, &ext_funcs},
175 {SPECIAL_COMP, &comp_funcs},
176 {SPECIAL_CHUNKED, &chunked_funcs},
177 #ifdef LATER
178 {SPECIAL_VLINKED, &vlnk_funcs},
179 #endif /* LATER */
180 {SPECIAL_BUFFERED, &buf_funcs},
181 {SPECIAL_COMPRAS, &cr_funcs},
182 {0, NULL} /* terminating record; add new record */
183 /* before this line */
184 };
185
186 /*
187 ** Declaration of private functions.
188 */
189 PRIVATE intn HIunlock
190 (filerec_t *file_rec);
191
192 PRIVATE filerec_t *HIget_filerec_node
193 (const char *path);
194
195 PRIVATE intn HIrelease_filerec_node
196 (filerec_t *file_rec);
197
198 PRIVATE intn HIvalid_magic
199 (hdf_file_t file);
200
201 PRIVATE intn HIextend_file
202 (filerec_t * file_rec);
203
204 PRIVATE funclist_t *HIget_function_table
205 (accrec_t * access_rec);
206
207 PRIVATE intn HIupdate_version
208 (int32);
209
210 PRIVATE intn HIread_version
211 (int32);
212
213 PRIVATE intn HIcheckfileversion
214 (int32 file_id);
215
216 PRIVATE intn HIsync
217 (filerec_t *file_rec);
218
219 PRIVATE intn HIstart(void);
220
221 /* #define TESTING */
222
223 /*--------------------------------------------------------------------------
224 NAME
225 Hopen -- Opens a HDF file.
226 USAGE
227 int32 Hopen(path, access, ndds)
228 char *path; IN: Name of file to be opened.
229 int access; IN: DFACC_READ, DFACC_WRITE, DFACC_CREATE
230 or any bitwise-or of the above.
231 int16 ndds; IN: Number of dds in a block if this
232 file needs to be created.
233 RETURNS
234 On success returns file id, on failure returns -1.
235 DESCRIPTION
236 Opens an HDF file. Returns the the file ID on success, or -1
237 on failure.
238
239 Access equals DFACC_CREATE means discard existing file and
240 create new file. If access is a bitwise-or of DFACC_CREATE
241 and anything else, the file is only created if it does not
242 exist. DFACC_WRITE set in access also means that if the file
243 does not exist, it is created. DFACC_READ is assumed to be
244 implied even if it is not set. DFACC_CREATE implies
245 DFACC_WRITE.
246
247 If the file is already opened and access is DFACC_CREATE:
248 error DFE_ALROPEN.
249 If the file is already opened, the requested access contains
250 DFACC_WRITE, and previous open does not allow write: attempt
251 to reopen the file with write permission.
252
253 On successful exit,
254 * file_rec members are filled in correctly.
255 * file is opened with the relevant permission.
256 * information about dd's are set up in memory.
257 For new file, in addition,
258 * the file headers and initial information are set up properly.
259
260 --------------------------------------------------------------------------*/
261 int32
Hopen(const char * path,intn acc_mode,int16 ndds)262 Hopen(const char *path, intn acc_mode, int16 ndds)
263 {
264 CONSTR(FUNC, "Hopen"); /* For HERROR */
265 filerec_t *file_rec=NULL;/* File record */
266 int vtag = 0; /* write version tag? */
267 int32 fid=FAIL; /* File ID */
268 int32 ret_value = SUCCEED;
269
270 /* Clear errors and check args and all the boring stuff. */
271 HEclear();
272 if (!path || ((acc_mode & DFACC_ALL) != acc_mode))
273 HGOTO_ERROR(DFE_ARGS, FAIL);
274
275 /* Perform global, one-time initialization */
276 if (library_terminate == FALSE)
277 if(HIstart()==FAIL)
278 HGOTO_ERROR(DFE_CANTINIT, FAIL);
279
280 /* Get a space to put the file information.
281 * HIget_filerec_node() also copies path into the record. */
282 if ((file_rec = HIget_filerec_node(path))== NULL)
283 HGOTO_ERROR(DFE_TOOMANY, FAIL); /* The slots are full. */
284
285 if (file_rec->refcount)
286 { /* File is already opened, check that permission is okay. */
287 /* If this request is to create a new file and file is still
288 * in use, return error. */
289 if (acc_mode == DFACC_CREATE)
290 HGOTO_ERROR(DFE_ALROPEN, FAIL);
291
292 if ((acc_mode & DFACC_WRITE) && !(file_rec->access & DFACC_WRITE))
293 {
294 /* If the request includes writing, and if original open does not
295 provide for write, then try to reopen file for writing.
296 This cannot be done on OS (such as the SXOS) where only one
297 open is allowed per file at any time. */
298 #ifndef NO_MULTI_OPEN
299 hdf_file_t f;
300
301 /* Sync. the file before throwing away the old file handle */
302 if(HIsync(file_rec)==FAIL)
303 HGOTO_ERROR(DFE_INTERNAL, FAIL);
304
305 f = (hdf_file_t)HI_OPEN(file_rec->path, acc_mode);
306 if (OPENERR(f))
307 HGOTO_ERROR(DFE_DENIED, FAIL);
308
309 /* Replace file_rec->file with new file pointer and
310 close old one. */
311 if (HI_CLOSE(file_rec->file) == FAIL)
312 {
313 HI_CLOSE(f);
314 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
315 }
316 file_rec->file = f;
317 file_rec->f_cur_off=0;
318 file_rec->last_op=H4_OP_UNKNOWN;
319 #else /* NO_MULTI_OPEN */
320 HGOTO_ERROR(DFE_DENIED, FAIL);
321 #endif /* NO_MULTI_OPEN */
322 }
323
324 /* There is now one more open to this file. */
325 file_rec->refcount++;
326 }
327 else
328 {
329 /* Flag to see if file is new and needs to be set up. */
330 intn new_file = FALSE;
331
332 /* Open the file, fill in the blanks and all the good stuff. */
333 if (acc_mode != DFACC_CREATE)
334 { /* try to open existing file */
335 file_rec->file = (hdf_file_t)HI_OPEN(file_rec->path, acc_mode);
336 if (OPENERR(file_rec->file))
337 {
338 if (acc_mode & DFACC_WRITE)
339 {
340 /* Seems like the file is not there, try to create it. */
341 new_file = TRUE;
342 }
343 else
344 HGOTO_ERROR(DFE_BADOPEN, FAIL);
345 }
346 else
347 {
348 #ifdef STDIO_BUF
349 /* Testing stdio buffered i/o */
350 if (HDsetvbuf(file_rec->file, my_stdio_buf, _IOFBF, MY_STDIO_BUF_SIZE) != 0)
351 HGOTO_ERROR(DFE_BADOPEN, FAIL);
352 #endif /* STDIO_BUF */
353 /* Open existing file successfully. */
354 file_rec->access = acc_mode | DFACC_READ;
355
356 /* Check to see if file is a HDF file. */
357 if (!HIvalid_magic(file_rec->file))
358 {
359 HI_CLOSE(file_rec->file);
360 HGOTO_ERROR(DFE_NOTDFFILE, FAIL);
361 }
362
363 file_rec->f_cur_off=0;
364 file_rec->last_op=H4_OP_UNKNOWN;
365 /* Read in all the relevant data descriptor records. */
366 if (HTPstart(file_rec) == FAIL)
367 {
368 HI_CLOSE(file_rec->file);
369 HGOTO_ERROR(DFE_BADOPEN, FAIL);
370 }
371 }
372 }
373 /* do *not* use else here */
374 if (acc_mode == DFACC_CREATE || new_file)
375 { /* create the file */
376 /* make user we get a version tag */
377 vtag = 1;
378
379 file_rec->file = (hdf_file_t)HI_CREATE(file_rec->path);
380 if (OPENERR(file_rec->file))
381 {
382 /* check if the failure was due to "too many open files" */
383 if(errno == EMFILE)
384 {
385 HGOTO_ERROR(DFE_TOOMANY, FAIL);
386 }
387 else
388 HGOTO_ERROR(DFE_BADOPEN, FAIL);
389 }
390
391 file_rec->f_cur_off=0;
392 file_rec->last_op=H4_OP_UNKNOWN;
393 #ifdef STDIO_BUF
394 /* Testing stdio buffered i/o */
395 if (HDsetvbuf(file_rec->file, my_stdio_buf, _IOFBF, MY_STDIO_BUF_SIZE) != 0)
396 HGOTO_ERROR(DFE_BADOPEN, FAIL);
397 #endif /* STDIO_BUF */
398 /* set up the newly created (and empty) file with
399 the magic cookie and initial data descriptor records */
400 if (HP_write(file_rec, HDFMAGIC, MAGICLEN) == FAIL)
401 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
402
403 if (HI_FLUSH(file_rec->file) == FAIL) /* flush the cookie */
404 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
405
406 if (HTPinit(file_rec, ndds) == FAIL)
407 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
408
409 file_rec->maxref = 0;
410 file_rec->access = new_file ? acc_mode | DFACC_READ : DFACC_ALL;
411 }
412 file_rec->refcount = 1;
413 file_rec->attach = 0;
414
415 /* currently, default is caching OFF */
416 file_rec->cache = default_cache;
417 file_rec->dirty = 0; /* mark all dirty flags off to start */
418 } /* end else */
419
420 file_rec->version_set = FALSE;
421
422 if((fid=HAregister_atom(FIDGROUP,file_rec))==FAIL)
423 HGOTO_ERROR(DFE_INTERNAL, FAIL);
424
425 /* version tags */
426 if (vtag == 1)
427 {
428 if(HIupdate_version(fid)==FAIL)
429 HGOTO_ERROR(DFE_INTERNAL, FAIL);
430 } /* end if */
431 else
432 {
433 HIread_version(fid); /* ignore return code in case the file doesn't have a version */
434 } /* end else */
435
436 ret_value=fid;
437
438 done:
439 if(ret_value == FAIL)
440 { /* Error condition cleanup */
441 if(fid!=FAIL)
442 HAremove_atom(fid);
443
444 /* Chuck the file record we've built */
445 if(file_rec!=NULL && file_rec->refcount==0)
446 HIrelease_filerec_node(file_rec);
447 } /* end if */
448
449 /* Normal function cleanup */
450 return ret_value;
451 } /* Hopen */
452
453 /*--------------------------------------------------------------------------
454 NAME
455 Hclose -- close HDF file
456 USAGE
457 intn Hclose(id)
458 int id; IN: the file id to be closed
459 RETURNS
460 returns SUCCEED (0) if successful and FAIL (-1) if failed.
461 DESCRIPTION
462 closes an HDF file given the file id. Id is first validated. If
463 there are still access objects attached to the file, an error is
464 returned and the file is not closed.
465
466 --------------------------------------------------------------------------*/
467 intn
Hclose(int32 file_id)468 Hclose(int32 file_id)
469 {
470 CONSTR(FUNC, "Hclose"); /* for HERROR */
471 filerec_t *file_rec; /* file record pointer */
472 intn ret_value = SUCCEED;
473
474 /* Clear errors and check args and all the boring stuff. */
475 HEclear();
476
477 /* convert file id to file rec and check for validity */
478 file_rec = HAatom_object(file_id);
479 if (BADFREC(file_rec))
480 HGOTO_ERROR(DFE_ARGS, FAIL);
481
482 /* version tags */
483 if ((file_rec->refcount > 0) && (file_rec->version.modified == 1))
484 HIupdate_version(file_id);
485
486 /* decrease the reference count */
487 if (--file_rec->refcount == 0)
488 {
489 /* if file reference count is zero but there are still attached
490 access elts, reject this close. */
491 if (file_rec->attach > 0)
492 {
493 file_rec->refcount++;
494 HEreport("There are still %d active aids attached", file_rec->attach);
495 HGOTO_ERROR(DFE_OPENAID, FAIL);
496 } /* end if */
497
498 /* before closing file, check whether to flush file info */
499 if(HIsync(file_rec)==FAIL)
500 HGOTO_ERROR(DFE_INTERNAL, FAIL);
501
502 /* otherwise, nothing should still be using this file, close it */
503 /* ignore any close error */
504 HI_CLOSE(file_rec->file);
505
506 if(HTPend(file_rec)==FAIL)
507 HGOTO_ERROR(DFE_INTERNAL, FAIL);
508
509 if(HIrelease_filerec_node(file_rec))
510 HGOTO_ERROR(DFE_INTERNAL, FAIL);
511 } /* end if */
512
513 if(HAremove_atom(file_id)==NULL)
514 HGOTO_ERROR(DFE_INTERNAL, FAIL);
515
516 done:
517 if(ret_value == FAIL)
518 { /* Error condition cleanup */
519
520 } /* end if */
521
522 /* Normal function cleanup */
523 return ret_value;
524 } /* Hclose */
525
526 /*--------------------------------------------------------------------------
527 NAME
528 Hexist -- locate an object in an HDF file
529 USAGE
530 intn Hexist(file_id ,search_tag, search_ref)
531 int32 file_id; IN: file ID to search in
532 uint16 search_tag; IN: the tag to search for
533 (can be DFTAG_WILDCARD)
534 uint16 search_ref; IN: ref to search for
535 (can be DFREF_WILDCARD)
536 RETURNS
537 returns SUCCEED (0) if successful and FAIL (-1) otherwise
538 DESCRIPTION
539 Simple interface to Hfind which just determines if a given
540 tag/ref pair exists in a file. Wildcards apply.
541 GLOBAL VARIABLES
542 COMMENTS, BUGS, ASSUMPTIONS
543 Hfind() does all validity checking, this is just a _very_
544 simple wrapper around it.
545 EXAMPLES
546 REVISION LOG
547 --------------------------------------------------------------------------*/
548 intn
Hexist(int32 file_id,uint16 search_tag,uint16 search_ref)549 Hexist(int32 file_id, uint16 search_tag, uint16 search_ref)
550 {
551 #ifdef LATER
552 CONSTR(FUNC, "Hexist"); /* for HERROR */
553 #endif
554 uint16 find_tag = 0, find_ref = 0;
555 int32 find_offset, find_length;
556 intn ret_value;
557
558 ret_value = (Hfind(file_id, search_tag, search_ref, &find_tag, &find_ref,
559 &find_offset, &find_length, DF_FORWARD));
560 return ret_value;
561 } /* end Hexist() */
562
563 /*--------------------------------------------------------------------------
564 NAME
565 Hinquire -- inquire stats of an access elt
566 USAGE
567 intn Hinquire(access_id, pfile_id, ptag, pref, plength,
568 poffset, pposn, paccess, pspecial)
569 int access_id; IN: id of an access elt
570 int32 *pfile_id; OUT: file id
571 uint16 *ptag; OUT: tag of the element pointed to
572 uint16 *pref; OUT: ref of the element pointed to
573 int32 *plength; OUT: length of the element pointed to
574 int32 *poffset; OUT: offset of elt in the file
575 int32 *pposn; OUT: position pointed to within the data elt
576 int16 *paccess; OUT: the access type of this access elt
577 int16 *pspecial; OUT: special code
578 RETURNS
579 returns SUCCEED (0) if the access elt points to some data element,
580 otherwise FAIL (-1)
581 DESCRIPTION
582 Inquire statistics of the data element pointed to by access elt and
583 the access elt. The access type is set if the access_id is valid even
584 if FAIL is returned. If access_id is not valid then access is set to
585 zero (0). If statistic is not needed, pass NULL for the appropriate
586 value.
587
588 --------------------------------------------------------------------------*/
589 intn
Hinquire(int32 access_id,int32 * pfile_id,uint16 * ptag,uint16 * pref,int32 * plength,int32 * poffset,int32 * pposn,int16 * paccess,int16 * pspecial)590 Hinquire(int32 access_id, int32 *pfile_id, uint16 *ptag, uint16 *pref,
591 int32 *plength, int32 *poffset, int32 *pposn, int16 *paccess,
592 int16 *pspecial)
593 {
594 CONSTR(FUNC, "Hinquire"); /* for HERROR */
595 accrec_t *access_rec; /* access record */
596 intn ret_value = SUCCEED;
597
598 /* clear error stack and check validity of access id */
599 HEclear();
600 access_rec = HAatom_object(access_id);
601 if (access_rec == (accrec_t *) NULL)
602 HGOTO_ERROR(DFE_ARGS, FAIL);
603
604 /* if special elt, let special functions handle it */
605 if (access_rec->special)
606 {
607 ret_value = (int) (*access_rec->special_func->inquire) (access_rec, pfile_id,
608 ptag, pref, plength, poffset, pposn, paccess, pspecial);
609 goto done;
610 }
611 if (pfile_id != NULL)
612 *pfile_id = access_rec->file_id;
613 /* Get the relevant DD information */
614 if (HTPinquire(access_rec->ddid,ptag,pref,poffset,plength)==FAIL)
615 HGOTO_ERROR(DFE_INTERNAL, FAIL);
616 if (pposn != NULL)
617 *pposn = access_rec->posn;
618 if (paccess != NULL)
619 *paccess = (int16) access_rec->access;
620 if (pspecial != NULL)
621 *pspecial = 0;
622
623 done:
624 if(ret_value == FAIL)
625 { /* Error condition cleanup */
626
627 } /* end if */
628
629 /* Normal function cleanup */
630 return ret_value;
631 } /* end Hinquire */
632
633
634 /* ----------------------------- Hfidinquire ----------------------------- */
635 /*
636 ** NAME
637 ** Hfidinquire --- Inquire about a file ID
638 ** USAGE
639 ** int Hfidinquire(file_id)
640 ** int32 file_id; IN: handle of file
641 ** char *path; OUT: path of file
642 ** int32 mode; OUT: mode file is opened with
643 ** RETURNS
644 ** returns SUCCEED (0) if successful and FAIL (-1) if failed.
645 ** DESCRIPTION
646 ** GLOBAL VARIABLES
647 ** COMMENTS, BUGS, ASSUMPTIONS
648 --------------------------------------------------------------------------*/
649 intn
Hfidinquire(int32 file_id,char ** fname,intn * faccess,intn * attach)650 Hfidinquire(int32 file_id, char **fname, intn *faccess, intn *attach)
651 {
652 CONSTR(FUNC, "Hfidinquire"); /* for HERROR */
653 filerec_t *file_rec;
654 intn ret_value = SUCCEED;
655
656 HEclear();
657
658 file_rec = HAatom_object(file_id);
659 if (BADFREC(file_rec))
660 HGOTO_ERROR(DFE_BADACC, FAIL);
661
662 *fname = file_rec->path;
663 *faccess = file_rec->access;
664 *attach = file_rec->attach;
665
666 done:
667 if(ret_value == FAIL)
668 { /* Error condition cleanup */
669
670 } /* end if */
671
672 /* Normal function cleanup */
673 return ret_value;
674 } /* Hfidinquire */
675
676 /*--------------------------------------------------------------------------
677
678 NAME
679 Hstartread -- locate and position a read access elt on a tag/ref
680 USAGE
681 int32 Hstartread(fileid, tag, ref)
682 int fileid; IN: id of file to attach access element to
683 int tag; IN: tag to search for
684 int ref; IN: ref to search for
685 RETURNS
686 returns id of access element if successful, otherwise FAIL (-1)
687 DESCRIPTION
688 Searches the DD's for a particular tag/ref combination. The
689 searching starts from the head of the DD list. Wildcards can be
690 used for tag or ref (DFTAG_WILDCARD, DFREF_WILDCARD) and they match
691 any values. If the search is successful, the access elt is
692 positioned to the start of that tag/ref, otherwise it is an error.
693 An access element is created and attached to the file.
694
695 --------------------------------------------------------------------------*/
696 int32
Hstartread(int32 file_id,uint16 tag,uint16 ref)697 Hstartread(int32 file_id, uint16 tag, uint16 ref)
698 {
699 CONSTR(FUNC, "Hstartread"); /* for HERROR */
700 int32 ret; /* AID to return */
701 int32 ret_value = SUCCEED;
702
703 /* clear error stack */
704 HEclear();
705
706 /* Call Hstartaccess with the modified base tag */
707 if ((ret = Hstartaccess(file_id, BASETAG(tag), ref, DFACC_READ)) == FAIL)
708 HGOTO_ERROR(DFE_BADAID, FAIL);
709
710 ret_value = ret;
711
712 done:
713 if(ret_value == FAIL)
714 { /* Error condition cleanup */
715
716 } /* end if */
717
718 /* Normal function cleanup */
719 return ret_value;
720 } /* Hstartread() */
721
722 /*--------------------------------------------------------------------------
723 NAME
724 Hnextread -- locate and position a read access elt on tag/ref.
725 USAGE
726 intn Hnextread(access_id, tag, ref, origin)
727 int32 access_id; IN: id of a READ access elt
728 uint16 tag; IN: the tag to search for
729 uint16 ref; IN: ref to search for
730 int origin; IN: from where to start searching
731 RETURNS
732 returns SUCCEED (0) if successful and FAIL (-1) otherwise
733 DESCRIPTION
734 Searches for the `next' DD that fits the tag/ref. Wildcards
735 apply. If origin is DF_START, search from start of DD list,
736 if origin is DF_CURRENT, search from current position, otherwise
737 origin should be DF_END which searches from end of file.
738 If the search is successful, then the access elt
739 is positioned at the start of that tag/ref, otherwise, it is not
740 modified.
741 COMMENTS, BUGS, ASSUMPTIONS
742 DF_END _not_ supported yet!
743
744 --------------------------------------------------------------------------*/
745 intn
Hnextread(int32 access_id,uint16 tag,uint16 ref,intn origin)746 Hnextread(int32 access_id, uint16 tag, uint16 ref, intn origin)
747 {
748 CONSTR(FUNC, "Hnextread"); /* for HERROR */
749 filerec_t *file_rec; /* file record */
750 accrec_t *access_rec; /* access record */
751 uint16 new_tag=0, new_ref=0; /* new tag & ref to access */
752 int32 new_off, new_len; /* offset & length of new tag & ref */
753 intn ret_value = SUCCEED;
754
755 /* clear error stack and check validity of the access id */
756 HEclear();
757 access_rec = HAatom_object(access_id);
758 if (access_rec == (accrec_t *) NULL || !(access_rec->access & DFACC_READ)
759 || (origin != DF_START && origin != DF_CURRENT)) /* DF_END is NOT supported yet !!!! */
760 HGOTO_ERROR(DFE_ARGS, FAIL);
761
762 file_rec = HAatom_object(access_rec->file_id);
763 if (BADFREC(file_rec))
764 HGOTO_ERROR(DFE_INTERNAL, FAIL);
765
766 /*
767 * if access record used to point to an external element we
768 * need to close the file before moving on
769 */
770 if (access_rec->special)
771 {
772 switch(access_rec->special)
773 {
774 case SPECIAL_LINKED:
775 if (HLPcloseAID(access_rec) == FAIL)
776 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
777 break;
778
779 case SPECIAL_EXT:
780 if (HXPcloseAID(access_rec) == FAIL)
781 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
782 break;
783
784 case SPECIAL_COMP:
785 if (HCPcloseAID(access_rec) == FAIL)
786 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
787 break;
788
789 case SPECIAL_CHUNKED:
790 if (HMCPcloseAID(access_rec) == FAIL)
791 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
792 break;
793
794 case SPECIAL_BUFFERED:
795 if (HBPcloseAID(access_rec) == FAIL)
796 HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
797 break;
798
799 default: /* do nothing for other cases currently */
800 break;
801 } /* end switch */
802 }
803
804 if (origin == DF_START)
805 { /* set up variables to start searching from beginning of file */
806 new_tag=0;
807 new_ref=0;
808 }
809 else
810 { /* origin == CURRENT */
811 /* set up variables to start searching from the current position */
812 /* Get the old tag & ref */
813 if(HTPinquire(access_rec->ddid,&new_tag,&new_ref,NULL,NULL)==FAIL)
814 HGOTO_ERROR(DFE_INTERNAL, FAIL);
815 }
816
817 /* go look for the dd */
818 if(Hfind(access_rec->file_id,tag,ref,&new_tag,&new_ref,&new_off,&new_len,DF_FORWARD)==FAIL)
819 HGOTO_ERROR(DFE_INTERNAL, FAIL);
820
821 /* Let go of the previous DD id */
822 if (HTPendaccess(access_rec->ddid) == FAIL)
823 HGOTO_ERROR(DFE_CANTFLUSH, FAIL);
824
825 /* found, so update the access record */
826 if((access_rec->ddid=HTPselect(file_rec,new_tag,new_ref))==FAIL)
827 HGOTO_ERROR(DFE_INTERNAL, FAIL);
828 access_rec->appendable = FALSE; /* start data as non-appendable */
829 if (new_len == INVALID_OFFSET && new_off == INVALID_LENGTH)
830 access_rec->new_elem = TRUE;
831 else
832 access_rec->new_elem = FALSE;
833
834 /* If special element act upon it accordingly */
835 if (HTPis_special(access_rec->ddid))
836 {
837 int32 spec_aid;
838
839 /* special element, call special function to handle */
840 if((access_rec->special_func = HIget_function_table(access_rec))==NULL)
841 HGOTO_ERROR(DFE_INTERNAL, FAIL);
842
843 /* decrement "attach" to the file_rec */
844 HIunlock(file_rec);
845 if ((spec_aid=(*access_rec->special_func->stread) (access_rec)) != FAIL)
846 {
847 HAremove_atom(spec_aid); /* This is a gross hack! -QAK */
848 HGOTO_DONE(SUCCEED);
849 } /* end if */
850 else
851 {
852 HGOTO_DONE(FAIL);
853 } /* end if */
854 }
855
856 access_rec->special = 0;
857 access_rec->posn = 0;
858
859 done:
860 if(ret_value == FAIL)
861 { /* Error condition cleanup */
862
863 } /* end if */
864
865 /* Normal function cleanup */
866 return ret_value;
867 } /* end Hnextread() */
868
869 /*--------------------------------------------------------------------------
870 NAME
871 Hstartwrite -- set up a WRITE access elt for a write
872 USAGE
873 int32 Hstartwrite(fileid, tag, ref, len)
874 int fileid; IN: id of file to write to
875 int tag; IN: tag to write to
876 int ref; IN: ref to write to
877 long length; IN: the length of the data element
878 RETURNS
879 returns id of access element if successful and FAIL otherwise
880 DESCRIPTION
881 Set up a WRITE access elt to write out a data element. The DD list
882 of the file is searched first. If the tag/ref is found, it is
883 NOT replaced - the seek position is presumably at 0.
884 If it does not exist, it is created.
885
886 --------------------------------------------------------------------------*/
887 int32
Hstartwrite(int32 file_id,uint16 tag,uint16 ref,int32 length)888 Hstartwrite(int32 file_id, uint16 tag, uint16 ref, int32 length)
889 {
890 CONSTR(FUNC, "Hstartwrite"); /* for HERROR */
891 accrec_t *access_rec; /* access record */
892 int32 ret; /* AID to return */
893 int32 ret_value = SUCCEED;
894
895 /* clear error stack */
896 HEclear();
897
898 /* Call Hstartaccess with the modified base tag */
899 if ((ret = Hstartaccess(file_id, BASETAG(tag), ref, DFACC_RDWR)) == FAIL)
900 HGOTO_ERROR(DFE_BADAID, FAIL);
901
902 access_rec = HAatom_object(ret);
903
904 /* if new element set the length */
905 if (access_rec->new_elem
906 && (Hsetlength(ret, length) == FAIL))
907 {
908 Hendaccess(ret);
909 HGOTO_ERROR(DFE_BADLEN, FAIL);
910 } /* end if */
911
912 ret_value = ret;
913
914 done:
915 if(ret_value == FAIL)
916 { /* Error condition cleanup */
917
918 } /* end if */
919
920 /* Normal function cleanup */
921 return ret_value;
922 } /* end Hstartwrite */
923
924 /*--------------------------------------------------------------------------
925 NAME
926 Hstartaccess -- set up a access elt for either reading or writing
927 USAGE
928 int32 Hstartaccess(fileid, tag, ref, flags)
929 int32 fileid; IN: id of file to read/write to
930 uint16 tag; IN: tag to read/write to
931 uint16 ref; IN: ref to read/write to
932 uint32 flags; IN: access flags for the data element
933 RETURNS
934 returns id of access element if successful and FAIL otherwise
935 DESCRIPTION
936 Start access to data element for read or write access. The DD list
937 of the file is searched first. If the tag/ref is found, it is
938 NOT replaced - the seek position is presumably at 0.
939 If it does not exist, it is created.
940
941 --------------------------------------------------------------------------*/
942 int32
Hstartaccess(int32 file_id,uint16 tag,uint16 ref,uint32 flags)943 Hstartaccess(int32 file_id, uint16 tag, uint16 ref, uint32 flags)
944 {
945 CONSTR(FUNC, "Hstartaccess"); /* for HERROR */
946 intn ddnew = FALSE; /* is the dd a new one? */
947 filerec_t *file_rec=NULL; /* file record */
948 accrec_t *access_rec=NULL; /* access record */
949 uint16 new_tag=0, new_ref=0; /* new tag & ref to access */
950 int32 new_off, new_len; /* offset & length of new tag & ref */
951 int32 ret_value = SUCCEED;
952
953 /* clear error stack and check validity of file id */
954 HEclear();
955
956 file_rec = HAatom_object(file_id);
957 if (BADFREC(file_rec))
958 HGOTO_ERROR(DFE_ARGS, FAIL);
959
960 /* If writing, can we write to this file? */
961 if ((flags & DFACC_WRITE) && !(file_rec->access & DFACC_WRITE))
962 HGOTO_ERROR(DFE_DENIED, FAIL);
963
964 /* get empty slot in access records */
965 access_rec = HIget_access_rec();
966 if (access_rec == NULL)
967 HGOTO_ERROR(DFE_TOOMANY, FAIL);
968
969 /* set up access record to look for the dd */
970 access_rec->file_id = file_id;
971 if (flags & DFACC_APPENDABLE)
972 access_rec->appendable = TRUE; /* start data as appendable */
973 else
974 access_rec->appendable = FALSE; /* start data as non-appendable */
975
976 /* set the default values for block size and number of blocks for use in */
977 /* linked-block creation/conversion; they can be changed by the user via */
978 /* VSsetblocksize and VSsetnumblocks - BMR (bug #267 - June 2001) */
979 access_rec->block_size = HDF_APPENDABLE_BLOCK_LEN;
980 access_rec->num_blocks = HDF_APPENDABLE_BLOCK_NUM;
981
982 access_rec->special_info = NULL; /* reset */
983
984 /* if the DFACC_CURRENT flag is set, start searching for the tag/ref from */
985 /* the current location in the DD list */
986 if (flags & DFACC_CURRENT
987 || Hfind(access_rec->file_id,tag,ref,&new_tag,&new_ref,
988 &new_off,&new_len,DF_FORWARD)==FAIL)
989 { /* not in DD list */
990 new_tag=tag;
991 new_ref=ref;
992 new_off=INVALID_OFFSET;
993 new_len=INVALID_LENGTH;
994 }
995
996 /* get DD id for tag/ref if in DD list using 'new_tag' and 'new_ref' */
997 if ((access_rec->ddid = HTPselect(file_rec, new_tag, new_ref)) == FAIL)
998 { /* not in DD list */
999 /* can't create data elements with only read access */
1000 if (!(flags & DFACC_WRITE))
1001 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1002
1003 /* dd not found, so have to create new element */
1004 if((access_rec->ddid = HTPcreate(file_rec,new_tag,new_ref))==FAIL)
1005 HGOTO_ERROR(DFE_NOFREEDD, FAIL);
1006
1007 ddnew = TRUE; /* mark as new element */
1008 }
1009 else /* tag/ref already exists in DD list. */
1010 { /* need to update the access_rec block and idx */
1011
1012 /* If the tag we were looking up is special, and we aren't looking */
1013 /* for the actual special element information, then use special */
1014 /* element access to the data... -QAK */
1015 if (!SPECIALTAG(tag) && HTPis_special(access_rec->ddid)==TRUE)
1016 { /* found, if this elt is special, let special function handle it */
1017
1018 /* get special function table for element */
1019 access_rec->special_func = HIget_function_table(access_rec);
1020 if (access_rec->special_func==NULL)
1021 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1022
1023 /* call appropriate special startread/startwrite fcn */
1024 if (!(flags & DFACC_WRITE))
1025 ret_value = (*access_rec->special_func->stread) (access_rec);
1026 else
1027 ret_value = (*access_rec->special_func->stwrite) (access_rec);
1028
1029 goto done; /* we are done since the special fcn should take
1030 of everthing. */
1031
1032 } /* end if special */
1033 } /* end else tag/ref exists */
1034
1035 /* Need to check if the "new" element was written to the file without */
1036 /* it's length being set. If that was the case, the offset and length */
1037 /* will be marked as invalid, and therefore we should mark it as "new" */
1038 /* again when the element is re-opened -QAK */
1039 if (!ddnew && new_off == INVALID_OFFSET && new_len == INVALID_LENGTH)
1040 ddnew = TRUE; /* mark as new element */
1041
1042 /* update the access record, and the file record */
1043 access_rec->posn = 0;
1044 access_rec->access = flags; /* keep the access flags around */
1045 access_rec->file_id = file_id;
1046 access_rec->special = 0; /* not special */
1047 access_rec->new_elem = ddnew; /* set the flag indicating whether
1048 this elt is new */
1049 file_rec->attach++; /* increment number of elts attached to file */
1050
1051 /* check current maximum ref for file and update if necessary */
1052 if (new_ref > file_rec->maxref)
1053 file_rec->maxref = new_ref;
1054
1055 /*
1056 * If this is the first time we are writting to this file
1057 * update the version tags as needed */
1058 if (!file_rec->version_set)
1059 HIcheckfileversion(file_id);
1060
1061 ret_value = HAregister_atom(AIDGROUP,access_rec);
1062
1063 done:
1064 if(ret_value == FAIL)
1065 { /* Error condition cleanup */
1066 if(access_rec!=NULL)
1067 HIrelease_accrec_node(access_rec);
1068
1069 } /* end if */
1070
1071 /* Normal function cleanup */
1072 return ret_value;
1073 } /* end Hstartaccess */
1074
1075 /*--------------------------------------------------------------------------
1076 NAME
1077 Hsetlength -- set the length of a new HDF element
1078 USAGE
1079 intn Hsetlength(aid, length)
1080 int32 aid; IN: id of element to set the length of
1081 int32 length; IN: the length of the element
1082 RETURNS
1083 SUCCEED/FAIL
1084 DESCRIPTION
1085 Sets the length of a new data element. This function is only valid
1086 when called after Hstartaccess on a new data element and before
1087 any data is written to that element.
1088
1089 --------------------------------------------------------------------------*/
1090 intn
Hsetlength(int32 aid,int32 length)1091 Hsetlength(int32 aid, int32 length)
1092 {
1093 CONSTR(FUNC, "Hsetlength"); /* for HERROR */
1094 accrec_t *access_rec; /* access record */
1095 filerec_t *file_rec; /* file record */
1096 int32 offset; /* offset of this data element in file */
1097 intn ret_value = SUCCEED;
1098
1099 /* clear error stack and check validity of file id */
1100 HEclear();
1101
1102 if ((access_rec = HAatom_object(aid)) == NULL) /* get the access_rec pointer */
1103 HGOTO_ERROR(DFE_ARGS, FAIL);
1104
1105 /* Check whether we are allowed to change the length */
1106 if (access_rec->new_elem != TRUE)
1107 HGOTO_ERROR(DFE_ARGS, FAIL);
1108
1109 file_rec = HAatom_object(access_rec->file_id);
1110 if (BADFREC(file_rec))
1111 HGOTO_ERROR(DFE_ARGS, FAIL);
1112
1113 /* place the data element at the end of the file and record its offset */
1114 if ((offset = HPgetdiskblock(file_rec, length, FALSE)) == FAIL)
1115 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1116
1117 /* fill in dd record updating the offset and length of the element */
1118 if(HTPupdate(access_rec->ddid,offset,length)==FAIL)
1119 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1120
1121 /* turn off the "new" flag now that we have a length and offset */
1122 access_rec->new_elem = FALSE;
1123
1124 done:
1125 if(ret_value == FAIL)
1126 { /* Error condition cleanup */
1127
1128 } /* end if */
1129
1130 /* Normal function cleanup */
1131 return ret_value;
1132 } /* end Hsetlength */
1133
1134 /*--------------------------------------------------------------------------
1135 NAME
1136 Happendable -- Allow a data set to be appended to without the
1137 use of linked blocks
1138 USAGE
1139 intn Happendable(aid)
1140 int32 aid; IN: aid of the dataset to make appendable
1141 RETURNS
1142 returns 0 if dataset is allowed to be appendable, FAIL otherwise
1143 DESCRIPTION
1144 If a dataset is at the end of a file, allow Hwrite()s to write
1145 past the end of a file. Allows expanding datasets without the use
1146 of linked blocks.
1147
1148 --------------------------------------------------------------------------*/
1149 intn
Happendable(int32 aid)1150 Happendable(int32 aid)
1151 {
1152 CONSTR(FUNC, "Happendable"); /* for HERROR */
1153 accrec_t *access_rec; /* access record */
1154 intn ret_value = SUCCEED;
1155
1156 /* clear error stack and check validity of file id */
1157 HEclear();
1158 if ((access_rec = HAatom_object(aid)) == NULL) /* get the access_rec pointer */
1159 HGOTO_ERROR(DFE_ARGS, FAIL);
1160
1161 /* just indicate that the data should be appendable, and only convert */
1162 /* it when actually asked to modify the data */
1163 access_rec->appendable = TRUE;
1164
1165 done:
1166 if(ret_value == FAIL)
1167 { /* Error condition cleanup */
1168
1169 } /* end if */
1170
1171 /* Normal function cleanup */
1172 return ret_value;
1173 } /* end Happendable */
1174
1175 /*--------------------------------------------------------------------------
1176 NAME
1177 HPisappendable -- Check whether a data set can be appended to without the
1178 use of linked blocks
1179 USAGE
1180 intn HPisappendable(aid)
1181 int32 aid; IN: aid of the dataset to check appendable
1182 RETURNS
1183 returns SUCCEED if dataset is allowed to be appendable, FAIL otherwise
1184 DESCRIPTION
1185 If a dataset is at the end of a file, allow Hwrite()s to write
1186 past the end of a file. Allows expanding datasets without the use
1187 of linked blocks.
1188
1189 --------------------------------------------------------------------------*/
1190 intn
HPisappendable(int32 aid)1191 HPisappendable(int32 aid)
1192 {
1193 CONSTR(FUNC, "HPisappendable"); /* for HERROR */
1194 accrec_t *access_rec; /* access record */
1195 filerec_t *file_rec; /* file record */
1196 int32 data_len; /* length of the data we are checking */
1197 int32 data_off; /* offset of the data we are checking */
1198 intn ret_value = SUCCEED;
1199
1200 /* clear error stack and check validity of file id */
1201 HEclear();
1202 if ((access_rec = HAatom_object(aid)) == NULL) /* get the access_rec pointer */
1203 HGOTO_ERROR(DFE_ARGS, FAIL);
1204
1205 file_rec = HAatom_object(access_rec->file_id);
1206 if (BADFREC(file_rec))
1207 HGOTO_ERROR(DFE_ARGS, FAIL);
1208
1209 /* get the offset and length of the dataset */
1210 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_len,&data_off)==FAIL)
1211 HGOTO_ERROR(DFE_ARGS, FAIL);
1212
1213 /* dataset at end? */
1214 if (data_len + data_off == file_rec->f_end_off)
1215 ret_value = SUCCEED;
1216 else
1217 ret_value = FAIL;
1218
1219 done:
1220 if(ret_value == FAIL)
1221 { /* Error condition cleanup */
1222
1223 } /* end if */
1224
1225 /* Normal function cleanup */
1226 return ret_value;
1227 } /* end HPisappendable */
1228
1229 /*--------------------------------------------------------------------------
1230
1231 NAME
1232 Hseek -- position an access element to an offset in data element
1233 USAGE
1234 intn Hseek(access_id, offset, origin)
1235 int32 access_id; IN: id of access element
1236 long offset; IN: offset to seek to
1237 int origin; IN: position to seek from by offset, 0: from
1238 beginning; 1: current position; 2: end of
1239 data element
1240 RETURNS
1241 returns FAIL (-1) if fail, SUCCEED (0) otherwise.
1242 DESCRIPTION
1243 Sets the position of an access element in a data element so that the
1244 next Hread or Hwrite will start from that position. origin
1245 determines the position from which the offset should be added. This
1246 routine fails if the access elt is not associated with any data
1247 element and if the seeked position is outside of the data element.
1248
1249 --------------------------------------------------------------------------*/
1250 intn
Hseek(int32 access_id,int32 offset,intn origin)1251 Hseek(int32 access_id, int32 offset, intn origin)
1252 {
1253 CONSTR(FUNC, "Hseek"); /* for HERROR */
1254 accrec_t *access_rec; /* access record */
1255 intn old_offset = offset; /* save for later potential use */
1256 filerec_t *file_rec; /* file record */
1257 int32 data_len; /* length of the data we are checking */
1258 int32 data_off; /* offset of the data we are checking */
1259 intn ret_value = SUCCEED;
1260
1261 /* clear error stack and check validity of this access id */
1262 HEclear();
1263
1264 access_rec = HAatom_object(access_id);
1265 if (access_rec == (accrec_t *) NULL
1266 || (origin != DF_START && origin != DF_CURRENT && origin != DF_END))
1267 HGOTO_ERROR(DFE_ARGS, FAIL);
1268
1269 /* if special elt, use special function */
1270 if (access_rec->special)
1271 { /* yes, call special seek fucntion with proper args */
1272 ret_value = (intn) (*access_rec->special_func->seek) (access_rec, offset, origin);
1273 goto done;
1274 }
1275
1276 /* Get the data's offset & length */
1277 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_off,&data_len)==FAIL)
1278 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1279
1280 /* calculate real offset based on the origin */
1281 if (origin == DF_CURRENT)
1282 offset += access_rec->posn;
1283 if (origin == DF_END)
1284 offset += data_len;
1285
1286 /* If we aren't moving the access records position, bypass the next bit of code */
1287 /* This allows seeking to offset zero in not-yet-existent data elements -QAK */
1288 if(offset==access_rec->posn)
1289 HGOTO_DONE(SUCCEED);
1290
1291 /* Check the range */
1292 if (offset < 0 || (!access_rec->appendable && offset > data_len))
1293 {
1294 HEreport("Tried to seek to %d (object length: %d)", offset, data_len);
1295 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1296 }
1297
1298 /* check if element is appendable and writing past current element length */
1299 if (access_rec->appendable && offset >= data_len)
1300 { /* yes */
1301 file_rec = HAatom_object(access_rec->file_id);
1302
1303 /* check if we are at end of file */
1304 if (data_len + data_off != file_rec->f_end_off)
1305 { /* nope, so try to convert element into linked-block element */
1306 if (HLconvert(access_id, access_rec->block_size, access_rec->num_blocks) == FAIL)
1307 {
1308 access_rec->appendable = FALSE;
1309 HEreport("Tried to seek to %d (object length: %d)", offset, data_len);
1310 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1311 } /* end if */
1312 else
1313 /* successfully converted the element into a linked block */
1314 /* now loop back and actually seek to the correct position */
1315 {
1316 if (Hseek(access_id, old_offset, origin) == FAIL)
1317 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1318 } /* end else */
1319 } /* end if */
1320 } /* end if */
1321
1322 /* set the new position */
1323 access_rec->posn = offset;
1324
1325 done:
1326 if(ret_value == FAIL)
1327 { /* Error condition cleanup */
1328
1329 } /* end if */
1330
1331 /* Normal function cleanup */
1332 return ret_value;
1333 } /* Hseek() */
1334
1335 /*--------------------------------------------------------------------------
1336
1337 NAME
1338 Htell -- report position of an access element in a data element
1339 USAGE
1340 int32 Htell(access_id)
1341 int32 access_id; IN: id of access element
1342 RETURNS
1343 returns FAIL (-1) on error, offset in data element otherwise
1344 DESCRIPTION
1345 Reports the offset in bytes of an AID in a data element. Analogous to
1346 ftell().
1347
1348 --------------------------------------------------------------------------*/
1349 int32
Htell(int32 access_id)1350 Htell(int32 access_id)
1351 {
1352 CONSTR(FUNC, "Htell"); /* for HERROR */
1353 accrec_t *access_rec; /* access record */
1354 int32 ret_value = SUCCEED;
1355
1356 /* clear error stack and check validity of this access id */
1357 HEclear();
1358
1359 access_rec = HAatom_object(access_id);
1360 if (access_rec == (accrec_t *) NULL)
1361 HGOTO_ERROR(DFE_ARGS, FAIL);
1362
1363 /* return the offset in the AID */
1364 ret_value = (int32)access_rec->posn;
1365
1366 done:
1367 if(ret_value == FAIL)
1368 { /* Error condition cleanup */
1369
1370 } /* end if */
1371
1372 /* Normal function cleanup */
1373 return ret_value;
1374 } /* Htell() */
1375
1376 /*--------------------------------------------------------------------------
1377 NAME
1378 Hread -- read the next segment from data element
1379 USAGE
1380 int32 Hread(access_id, length, data)
1381 int32 access_id; IN: id of READ access element
1382 int32 length; IN: length of segment to read in
1383 char *data; OUT: pointer to data array to read to
1384 RETURNS
1385 returns length of segment actually read in if successful and FAIL
1386 (-1) otherwise
1387 DESCRIPTION
1388 Read in the next segment in the data element pointed to by the
1389 access elt. If length is zero or larger than the remaining bytes
1390 of the object, read until the end of the object.
1391
1392 --------------------------------------------------------------------------*/
1393 int32
Hread(int32 access_id,int32 length,void * data)1394 Hread(int32 access_id, int32 length, void * data)
1395 {
1396 CONSTR(FUNC, "Hread"); /* for HERROR */
1397 filerec_t *file_rec; /* file record */
1398 accrec_t *access_rec; /* access record */
1399 int32 data_len; /* length of the data we are checking */
1400 int32 data_off; /* offset of the data we are checking */
1401 int32 ret_value = SUCCEED;
1402
1403 /* clear error stack and check validity of access id */
1404 HEclear();
1405 access_rec = HAatom_object(access_id);
1406 if (access_rec == (accrec_t *) NULL || data == NULL)
1407 HGOTO_ERROR(DFE_ARGS, FAIL);
1408
1409 /* Don't allow reading of "new" elements */
1410 if (access_rec->new_elem == TRUE)
1411 HGOTO_ERROR(DFE_READERROR, FAIL);
1412
1413 /* special elt, so call special function */
1414 if (access_rec->special)
1415 { /* yes, call special read function with proper args */
1416 ret_value = (*access_rec->special_func->read) (access_rec, length, data);
1417 goto done; /* we are done */
1418 }
1419
1420 /* check validity of file record */
1421 file_rec = HAatom_object(access_rec->file_id);
1422 if (BADFREC(file_rec))
1423 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1424
1425 /* get the dd of this data elt */
1426 if (length < 0)
1427 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1428
1429 /* Get the data's offset & length */
1430 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_off,&data_len)==FAIL)
1431 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1432
1433 /* seek to position to start reading and read in data */
1434 if (HPseek(file_rec, access_rec->posn + data_off) == FAIL)
1435 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1436
1437 /* length == 0 means to read to end of element, */
1438 /* if read length exceeds length of elt, read till end of elt */
1439 if (length == 0 || length + access_rec->posn > data_len)
1440 length = data_len - access_rec->posn;
1441
1442 /* read in data */
1443 if (HP_read(file_rec, data, length) == FAIL)
1444 HGOTO_ERROR(DFE_READERROR, FAIL);
1445
1446 /* move the position of the access record */
1447 access_rec->posn += length;
1448
1449 ret_value = length;
1450
1451 done:
1452 if(ret_value == FAIL)
1453 { /* Error condition cleanup */
1454
1455 } /* end if */
1456
1457 /* Normal function cleanup */
1458 return ret_value;
1459 } /* Hread */
1460
1461 /*--------------------------------------------------------------------------
1462 NAME
1463 Hwrite -- write next data segment to data element
1464 USAGE
1465 int32 Hwrite(access_id, len, data)
1466 int32 access_id; IN: id of WRITE access element
1467 int32 len; IN: length of segment to write
1468 const char *data; IN: pointer to data to write
1469 RETURNS
1470 returns length of segment successfully written, FAIL (-1) otherwise
1471 DESCRIPTION
1472 Write the data to data element where the last write or Hseek()
1473 stopped. If the space reserved is less than the length to write,
1474 then only as much as can fit is written. It is the responsibility
1475 of the user to insure that no two access elements are writing to the
1476 same data element. It is possible to interlace writes to more than
1477 one data elements in the same file though.
1478 Calling with length == 0 is an error.
1479
1480 --------------------------------------------------------------------------*/
1481 int32
Hwrite(int32 access_id,int32 length,const void * data)1482 Hwrite(int32 access_id, int32 length, const void * data)
1483 {
1484 CONSTR(FUNC, "Hwrite"); /* for HERROR */
1485 filerec_t *file_rec; /* file record */
1486 accrec_t *access_rec; /* access record */
1487 int32 data_len; /* length of the data we are checking */
1488 int32 data_off; /* offset of the data we are checking */
1489 int32 ret_value = SUCCEED;
1490
1491 /* clear error stack and check validity of access id */
1492 HEclear();
1493 access_rec = HAatom_object(access_id);
1494 if (access_rec == (accrec_t *) NULL
1495 || !(access_rec->access & DFACC_WRITE)
1496 || data == NULL)
1497 HGOTO_ERROR(DFE_ARGS, FAIL);
1498
1499
1500 /* if special elt, call special write function */
1501 if (access_rec->special)
1502 {
1503 ret_value = (*access_rec->special_func->write) (access_rec, length, data);
1504 goto done; /* we are done */
1505 } /* end special */
1506
1507 /* check validity of file record and get dd ptr */
1508 file_rec = HAatom_object(access_rec->file_id);
1509 if (BADFREC(file_rec))
1510 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1511
1512 /* check for a "new" element and make it appendable if so.
1513 Does this mean every element is by default appendable? */
1514 if (access_rec->new_elem == TRUE)
1515 {
1516 Hsetlength(access_id, length); /* make the initial chunk of data */
1517 access_rec->appendable = TRUE; /* make it appendable */
1518 } /* end if */
1519
1520
1521 /* get the offset and length of the element. This should have
1522 been set by Hstartwrite(). */
1523 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_off,&data_len)==FAIL)
1524 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1525
1526 /* check validity of length and write data.
1527 NOTE: it is an error to attempt write past the end of the elt */
1528 if (length <= 0
1529 || (!access_rec->appendable && length + access_rec->posn > data_len))
1530 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1531
1532 /* check if element is appendable and write length exceeds current
1533 data element length */
1534 if (access_rec->appendable && length + access_rec->posn > data_len)
1535 { /* yes */
1536
1537 /* is data element at end of file?
1538 hmm. not sure about this condition. */
1539 if (data_len + data_off != file_rec->f_end_off)
1540 { /* nope, not at end of file. Try to promote to
1541 linked-block element. */
1542 if (HLconvert(access_id, access_rec->block_size, access_rec->num_blocks) == FAIL)
1543 {
1544 access_rec->appendable = FALSE;
1545 HGOTO_ERROR(DFE_BADSEEK, FAIL);
1546 } /* end if */
1547 /* successfully converted the element into a linked block */
1548 /* now loop back and actually write the data out */
1549 if ((ret_value = Hwrite(access_id, length, data)) == FAIL)
1550 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1551 goto done; /* we're finished, wrap things up */
1552 } /* end if */
1553
1554 /* Update the DD with the new length. Note argument of '-2' for
1555 the offset parameter means not to change the offset in the DD. */
1556 if(HTPupdate(access_rec->ddid,-2,access_rec->posn+length)==FAIL)
1557 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1558 } /* end if */
1559
1560 /* seek and write data */
1561 if (HPseek(file_rec, access_rec->posn + data_off) == FAIL)
1562 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1563
1564 if (HP_write(file_rec, data, length) == FAIL)
1565 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1566
1567 /* update end of file pointer? */
1568 if (file_rec->f_cur_off > file_rec->f_end_off)
1569 file_rec->f_end_off = file_rec->f_cur_off;
1570
1571 /* update position of access in elt */
1572 access_rec->posn += length;
1573
1574 ret_value = length;
1575
1576 done:
1577 if(ret_value == FAIL)
1578 { /* Error condition cleanup */
1579
1580 } /* end if */
1581
1582 /* Normal function cleanup */
1583 return ret_value;
1584 } /* end Hwrite */
1585
1586 /*--------------------------------------------------------------------------
1587 NAME
1588 HDgetc -- read a byte from data element
1589 USAGE
1590 intn HDgetc(access_id)
1591 int access_id; IN: id of READ access element
1592
1593 RETURNS
1594 returns byte read in from data if successful and FAIL
1595 (-1) otherwise
1596
1597 DESCRIPTION
1598 Calls Hread() to read a single byte and reports errors.
1599
1600 --------------------------------------------------------------------------*/
1601 intn
HDgetc(int32 access_id)1602 HDgetc(int32 access_id)
1603 {
1604 CONSTR(FUNC, "HDgetc"); /* for HERROR */
1605 uint8 c=(uint8)FAIL; /* character read in */
1606 intn ret_value = SUCCEED;
1607
1608 if (Hread(access_id, 1, &c) == FAIL)
1609 HGOTO_ERROR(DFE_READERROR, FAIL);
1610
1611 ret_value = (intn)c;
1612
1613 done:
1614 if(ret_value == FAIL)
1615 { /* Error condition cleanup */
1616
1617 } /* end if */
1618
1619 /* Normal function cleanup */
1620
1621 return ret_value;
1622 } /* HDgetc */
1623
1624 /*--------------------------------------------------------------------------
1625 NAME
1626
1627 USAGE
1628 intn HDputc(c,access_id)
1629 uint8 c; IN: byte to write out
1630 int32 access_id; IN: id of WRITE access element
1631
1632 RETURNS
1633 returns byte written out to data if successful and FAIL
1634 (-1) otherwise
1635
1636 DESCRIPTION
1637 Calls Hwrite() to write a single byte and reports errors.
1638
1639 --------------------------------------------------------------------------*/
1640 intn
HDputc(uint8 c,int32 access_id)1641 HDputc(uint8 c, int32 access_id)
1642 {
1643 CONSTR(FUNC, "HDputc"); /* for HERROR */
1644 intn ret_value = SUCCEED;
1645
1646 if (Hwrite(access_id, 1, &c) == FAIL)
1647 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1648
1649 ret_value = (intn)c;
1650
1651 done:
1652 if(ret_value == FAIL)
1653 { /* Error condition cleanup */
1654
1655 } /* end if */
1656
1657 /* Normal function cleanup */
1658
1659 return ret_value;
1660 } /* HDputc */
1661
1662 /*--------------------------------------------------------------------------
1663 NAME
1664 Hendaccess -- to dispose of an access element
1665 USAGE
1666 intn Hendaccess(access_id)
1667 int32 access_id; IN: id of access element to dispose of
1668 RETURNS
1669 returns SUCCEED (0) if successful, FAIL (-1) otherwise
1670 DESCRIPTION
1671 Used to dispose of an access element. If access elements are not
1672 disposed it will eventually become impossible to allocate new
1673 ones and close the file.
1674
1675 If there are active aids Hclose will *NOT* close the file. This
1676 is a very common problem when developing new code.
1677
1678 --------------------------------------------------------------------------*/
1679 intn
Hendaccess(int32 access_id)1680 Hendaccess(int32 access_id)
1681 {
1682 CONSTR(FUNC, "Hendaccess"); /* for HERROR */
1683 filerec_t *file_rec; /* file record */
1684 accrec_t *access_rec=NULL;/* access record */
1685 intn ret_value = SUCCEED;
1686
1687 /* clear error stack and check validity of access id */
1688 HEclear();
1689 if ((access_rec = HAremove_atom(access_id))==NULL)
1690 HGOTO_ERROR(DFE_ARGS, FAIL);
1691
1692 /* if special elt, call special function */
1693 if (access_rec->special)
1694 {
1695 ret_value = (*access_rec->special_func->endaccess) (access_rec);
1696 goto done;
1697 } /* end if */
1698
1699 /* check validity of file record */
1700 file_rec = HAatom_object(access_rec->file_id);
1701 if (BADFREC(file_rec))
1702 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1703
1704 /* update file and access records */
1705 if (HTPendaccess(access_rec->ddid) == FAIL)
1706 HGOTO_ERROR(DFE_CANTFLUSH, FAIL);
1707
1708 file_rec->attach--;
1709 #ifdef OLD_WAY
1710 if(HAremove_atom(access_id)==NULL)
1711 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1712 #endif /* OLD_WAY */
1713 HIrelease_accrec_node(access_rec);
1714
1715 done:
1716 if(ret_value == FAIL)
1717 { /* Error condition cleanup */
1718 if(access_rec!=NULL)
1719 HIrelease_accrec_node(access_rec);
1720 } /* end if */
1721
1722 /* Normal function cleanup */
1723 return ret_value;
1724 } /* Hendaccess */
1725
1726 /*--------------------------------------------------------------------------
1727 NAME
1728 Hgetelement -- read in a data element
1729 USAGE
1730 int32 Hgetelement(file_id, tag, ref, data)
1731 int32 file_id; IN: id of the file to read from
1732 int16 tag; IN: tag of data element to read
1733 int16 ref; IN: ref of data element to read
1734 char *data; OUT: buffer to read into
1735 RETURNS
1736 returns number of bytes read if successful, FAIL (-1)
1737 otherwise
1738 DESCRIPTION
1739 Read in a data element from a HDF file and puts it into buffer
1740 pointed to by data. The space allocated for buffer is assumed to
1741 be large enough.
1742
1743 --------------------------------------------------------------------------*/
1744 int32
Hgetelement(int32 file_id,uint16 tag,uint16 ref,uint8 * data)1745 Hgetelement(int32 file_id, uint16 tag, uint16 ref, uint8 *data)
1746 {
1747 CONSTR(FUNC, "Hgetelement"); /* for HERROR */
1748 int32 access_id=FAIL; /* access record id */
1749 int32 length; /* length of this elt */
1750 int32 ret_value = SUCCEED;
1751
1752 /* clear error stack */
1753 HEclear();
1754
1755 /* get the access record, get the length of the elt, read in data,
1756 and dispose of access record */
1757 if (( access_id = Hstartread(file_id, tag, ref))== FAIL)
1758 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1759
1760 if ((length = Hread(access_id, (int32) 0, data)) == FAIL)
1761 HGOTO_ERROR(DFE_READERROR, FAIL);
1762
1763 if(Hendaccess(access_id)==FAIL)
1764 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1765
1766 ret_value = length;
1767
1768 done:
1769 if(ret_value == FAIL)
1770 { /* Error condition cleanup */
1771 if(access_id!=FAIL)
1772 Hendaccess(access_id);
1773 } /* end if */
1774
1775 /* Normal function cleanup */
1776 return ret_value;
1777 } /* Hgetelement() */
1778
1779 /*--------------------------------------------------------------------------
1780 NAME
1781 Hputelement -- writes a data element
1782 USAGE
1783 int Hputelement(fileid, tag, ref, data, length)
1784 int32 fileid; IN: id of file
1785 int16 tag; IN: tag of data element to put
1786 int16 ref; IN: ref of data element to put
1787 char *data; IN: pointer to buffer
1788 int32 length; IN: length of data
1789 RETURNS
1790 returns length of bytes written if successful and FAIL (-1)
1791 otherwise
1792 DESCRIPTION
1793 Writes a data element or replaces an existing data element
1794 in an HDF file. Uses Hwrite and its associated routines.
1795
1796 --------------------------------------------------------------------------*/
1797 int32
Hputelement(int32 file_id,uint16 tag,uint16 ref,const uint8 * data,int32 length)1798 Hputelement(int32 file_id, uint16 tag, uint16 ref, const uint8 *data,
1799 int32 length)
1800 {
1801 CONSTR(FUNC, "Hputelement"); /* for HERROR */
1802 int32 access_id=FAIL; /* access record id */
1803 int32 ret_value = SUCCEED;
1804
1805 /* clear error stack */
1806 HEclear();
1807
1808 /* get access record, write out data and dispose of access record */
1809 if (( access_id = Hstartwrite(file_id, (uint16) tag, (uint16) ref, length))== FAIL)
1810 HGOTO_ERROR(DFE_NOMATCH, FAIL);
1811
1812 if ((ret_value = Hwrite(access_id, length, data)) == FAIL)
1813 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1814
1815 if(Hendaccess(access_id)==FAIL)
1816 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1817
1818 done:
1819 if(ret_value == FAIL)
1820 { /* Error condition cleanup */
1821 if(access_id!=FAIL)
1822 Hendaccess(access_id);
1823 } /* end if */
1824
1825 /* Normal function cleanup */
1826 return ret_value;
1827 } /* end Hputelement() */
1828
1829 /*--------------------------------------------------------------------------
1830 NAME
1831 Hlength -- returns length of a data element
1832 USAGE
1833 int32 Hlength(fileid, tag, ref)
1834 int fileid; IN: id of file
1835 int tag; IN: tag of data element
1836 int ref; IN: ref of data element
1837 RETURNS
1838 return the length of a data element or FAIL if there is a problem.
1839 DESCRIPTION
1840 returns length of data element if it is present in the file.
1841 Return FAIL (-1) if it is not in the file or an error occurs.
1842
1843 The current implementation is probably less efficient than it
1844 could be. However, because of special elements the code is much
1845 cleaner this way.
1846
1847 --------------------------------------------------------------------------*/
1848 int32
Hlength(int32 file_id,uint16 tag,uint16 ref)1849 Hlength(int32 file_id, uint16 tag, uint16 ref)
1850 {
1851 #ifdef FASTER_BUT_DOESNT_WORK
1852 CONSTR(FUNC, "Hlength"); /* for HERROR */
1853 filerec_t *file_rec; /* file record */
1854 ddblock_t *block; /* DDB containing DD of element */
1855 int32 idx; /* index into DDB i.e. DD of element */
1856 int32 ret_value = SUCCEED;
1857
1858 /* clear error stack */
1859 HEclear();
1860
1861 file_rec = HAatom_object(file_id);
1862 if (BADFREC(file_rec))
1863 HGOTO_ERROR(DFE_ARGS, FAIL);
1864
1865 block = file_rec->ddhead;
1866 idx = -1;
1867 if (HIlookup_dd(file_rec, tag, ref, &block, &idx) == FAIL)
1868 HGOTO_ERROR(DFE_INTERNAL, FAIL);
1869
1870 ret_value = block->ddlist[idx].length;
1871
1872 done:
1873 if(ret_value == FAIL)
1874 { /* Error condition cleanup */
1875
1876 } /* end if */
1877
1878 /* Normal function cleanup */
1879 return ret_value;
1880 #else /* FASTER_BUT_DOESNT_WORK */
1881 CONSTR(FUNC, "Hlength"); /* for HERROR */
1882 int32 access_id; /* access record id */
1883 int32 length=FAIL; /* length of elt inquired */
1884 int32 ret_value = SUCCEED;
1885
1886 /* clear error stack */
1887 HEclear();
1888
1889 /* get access record, inquire about lebngth and then dispose of
1890 access record */
1891 access_id = Hstartread(file_id, tag, ref);
1892 if (access_id == FAIL)
1893 HGOTO_ERROR(DFE_ARGS, FAIL);
1894
1895 if ((ret_value = HQuerylength(access_id, &length)) == FAIL)
1896 HERROR(DFE_INTERNAL);
1897
1898 if(Hendaccess(access_id)==FAIL)
1899 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1900
1901 ret_value = length;
1902
1903 done:
1904 if(ret_value == FAIL)
1905 { /* Error condition cleanup */
1906
1907 } /* end if */
1908
1909 /* Normal function cleanup */
1910 return ret_value;
1911 #endif /* FASTER_BUT_DOESNT_WORK */
1912 } /* end Hlength */
1913
1914 /*--------------------------------------------------------------------------
1915 NAME
1916 Hoffset -- get offset of data element in the file
1917 USAGE
1918 int32 Hoffset(fileid, tag, ref)
1919 int32 fileid; IN: id of file
1920 uint16 tag; IN: tag of data element
1921 uint16 ref; IN: ref of data element
1922 RETURNS
1923 returns offset of data element if it is present in the
1924 file or FAIL (-1) if it is not.
1925
1926 DESCRIPTION
1927 This should be used for debugging purposes only since
1928 the user should not have to know the actual offset of
1929 a data element in a file.
1930
1931 Like Hlength(). This could be sped up by not going through
1932 Hstartread() but because of special elements it is easier
1933 this way
1934
1935 --------------------------------------------------------------------------*/
1936 int32
Hoffset(int32 file_id,uint16 tag,uint16 ref)1937 Hoffset(int32 file_id, uint16 tag, uint16 ref)
1938 {
1939 CONSTR(FUNC, "Hoffset"); /* for HERROR */
1940 int32 access_id; /* access record id */
1941 int32 offset=FAIL; /* offset of elt inquired */
1942 int32 ret_value = SUCCEED;
1943
1944 /* clear error stack */
1945 HEclear();
1946
1947 /* get access record, inquire offset, and dispose of access record */
1948 access_id = Hstartread(file_id, tag, ref);
1949 if (access_id == FAIL)
1950 HGOTO_ERROR(DFE_ARGS, FAIL);
1951
1952 if ((ret_value = HQueryoffset(access_id, &offset)) == FAIL)
1953 HERROR(DFE_INTERNAL);
1954
1955 if(Hendaccess(access_id)==FAIL)
1956 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1957
1958 ret_value = offset;
1959
1960 done:
1961 if(ret_value == FAIL)
1962 { /* Error condition cleanup */
1963
1964 } /* end if */
1965
1966 /* Normal function cleanup */
1967 return ret_value;
1968 } /* Hoffset */
1969
1970 /*--------------------------------------------------------------------------
1971 NAME
1972 Hishdf -- tells if a file is an HDF file
1973 USAGE
1974 intn Hishdf(path)
1975 const char *path; IN: name of file
1976 RETURNS
1977 returns TRUE (non-zero) if file is HDF, FALSE (0) otherwise
1978 DESCRIPTION
1979 This user level routine can be used to determine if a file
1980 with a given name is an HDF file. Note, just because a file
1981 is not an HDF file does not imply that all HDF library
1982 functions can not work on it.
1983
1984 --------------------------------------------------------------------------*/
1985 intn
Hishdf(const char * filename)1986 Hishdf(const char *filename)
1987 {
1988 #ifdef LATER
1989 CONSTR(FUNC, "Hishdf");
1990 #endif /* LATER */
1991
1992 intn ret;
1993 hdf_file_t fp;
1994 intn ret_value = TRUE;
1995
1996 /* Search for a matching slot in the already open files. */
1997 if(HAsearch_atom(FIDGROUP,HPcompare_filerec_path,filename)!=NULL)
1998 HGOTO_DONE(TRUE);
1999
2000 fp = (hdf_file_t)HI_OPEN(filename, DFACC_READ);
2001 if (OPENERR(fp))
2002 {
2003 ret_value = FALSE;
2004 }
2005 else
2006 {
2007 ret = HIvalid_magic(fp);
2008 HI_CLOSE(fp);
2009 ret_value = (int) ret;
2010 }
2011
2012 done:
2013 if(ret_value == FALSE)
2014 { /* Error condition cleanup */
2015
2016 } /* end if */
2017
2018 /* Normal function cleanup */
2019 return ret_value;
2020 } /* Hishdf */
2021
2022 /*--------------------------------------------------------------------------
2023 NAME
2024 Htrunc -- truncate a data element to a length
2025 USAGE
2026 int32 Htrunc(aid, len)
2027 int32 aid; IN: id of file
2028 int32 len; IN: length at which to truncate data element
2029 RETURNS
2030 return the length of a data element
2031 DESCRIPTION
2032 truncates a data element in the file. Return
2033 FAIL (-1) if it is not in the file or an error occurs.
2034
2035 --------------------------------------------------------------------------*/
2036 int32
Htrunc(int32 aid,int32 trunc_len)2037 Htrunc(int32 aid, int32 trunc_len)
2038 {
2039 CONSTR(FUNC, "Htrunc"); /* for HERROR */
2040 accrec_t *access_rec; /* access record */
2041 int32 data_len; /* length of the data we are checking */
2042 int32 data_off; /* offset of the data we are checking */
2043 int32 ret_value = SUCCEED;
2044
2045 /* clear error stack and check validity of access id */
2046 HEclear();
2047 access_rec = HAatom_object(aid);
2048 if (access_rec == (accrec_t *) NULL || !(access_rec->access & DFACC_WRITE))
2049 HGOTO_ERROR(DFE_ARGS, FAIL);
2050
2051 /* Dunno about truncating special elements... -QAK */
2052 #ifdef DONT_KNOW
2053 /* if special elt, call special function */
2054 if (access_rec->special)
2055 {
2056 ret_value = (*access_rec->special_func->write) (access_rec, length, data);
2057 goto done;
2058 }
2059 #endif
2060
2061 /* get the offset and length of the dataset */
2062 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_off,&data_len)==FAIL)
2063 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2064
2065 /* check for actually being able to truncate the data */
2066 if (data_len > trunc_len)
2067 {
2068 /* set the new length of the dataset.
2069 Note value of '-2' for the offset paramter means not to update
2070 the offset in the DD.*/
2071 if(HTPupdate(access_rec->ddid,-2,trunc_len)==FAIL)
2072 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2073 if (access_rec->posn > trunc_len) /* move the seek position back */
2074 access_rec->posn = trunc_len;
2075 ret_value = trunc_len;
2076 } /* end if */
2077 else
2078 HGOTO_ERROR(DFE_BADLEN, FAIL);
2079
2080 done:
2081 if(ret_value == FAIL)
2082 { /* Error condition cleanup */
2083
2084 } /* end if */
2085
2086 /* Normal function cleanup */
2087 return ret_value;
2088 } /* end Htrunc() */
2089
2090 /*--------------------------------------------------------------------------
2091 NAME
2092 HIsync -- sync file with memory
2093 USAGE
2094 intn HIsync(file_rec)
2095 filerec_t *file_rec; IN: file record of file
2096 RETURNS
2097 returns SUCCEED (0) if sucessful, FAIL (-1) otherwise
2098 DESCRIPTION
2099 HIsync() performs the actual sync'ing of the file in memory & on disk.
2100 NOTE
2101
2102 --------------------------------------------------------------------------*/
2103 PRIVATE intn
HIsync(filerec_t * file_rec)2104 HIsync(filerec_t *file_rec)
2105 {
2106 CONSTR(FUNC, "HIsync"); /* for HERROR */
2107 intn ret_value = SUCCEED;
2108
2109 /* check whether to flush the file info */
2110 if (file_rec->cache && file_rec->dirty)
2111 {
2112 /* flush DD blocks if necessary */
2113 if (file_rec->dirty & DDLIST_DIRTY)
2114 if (HTPsync(file_rec) == FAIL)
2115 HGOTO_ERROR(DFE_CANTFLUSH, FAIL);
2116
2117 /* extend the end of the file if necessary */
2118 if (file_rec->dirty & FILE_END_DIRTY)
2119 if (HIextend_file(file_rec) == FAIL)
2120 HGOTO_ERROR(DFE_CANTFLUSH, FAIL);
2121 file_rec->dirty = 0; /* file doesn't need to be flushed now */
2122 } /* end if */
2123
2124 done:
2125 if(ret_value == FAIL)
2126 { /* Error condition cleanup */
2127
2128 } /* end if */
2129
2130 /* Normal function cleanup */
2131
2132 return ret_value;
2133 } /* HIsync */
2134
2135 /*--------------------------------------------------------------------------
2136 NAME
2137 Hsync -- sync file with memory
2138 USAGE
2139 intn Hsync(file_id)
2140 int32 file_id; IN: id of file
2141 RETURNS
2142 returns SUCCEED (0) if sucessful, FAIL (-1) otherwise
2143 DESCRIPTION
2144 Currently, the on-disk and in-memory representations are always
2145 the same. Thus there is no real use for Hsync(). In the future,
2146 things may be buffered before being written out at which time
2147 Hsync() will be useful to sync up the on-disk representation.
2148 NOTE
2149 First tests of caching DD's until close.
2150
2151 --------------------------------------------------------------------------*/
2152 intn
Hsync(int32 file_id)2153 Hsync(int32 file_id)
2154 {
2155 CONSTR(FUNC, "Hsync"); /* for HERROR */
2156 filerec_t *file_rec; /* file record */
2157 intn ret_value = SUCCEED;
2158
2159 /* check validity of file record and get dd ptr */
2160 file_rec = HAatom_object(file_id);
2161 if (BADFREC(file_rec))
2162 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2163
2164 /* check whether to flush the file info */
2165 if(HIsync(file_rec)==FAIL)
2166 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2167
2168 done:
2169 if(ret_value == FAIL)
2170 { /* Error condition cleanup */
2171
2172 } /* end if */
2173
2174 /* Normal function cleanup */
2175 return ret_value;
2176 } /* Hsync */
2177
2178 /*--------------------------------------------------------------------------
2179 NAME
2180 Hcache -- set low-level caching for a file
2181 USAGE
2182 intn Hcache(file_id,cache_on)
2183 int32 file_id; IN: id of file
2184 intn cache_on; IN: whether to cache or not
2185 RETURNS
2186 returns SUCCEED (0) if sucessful, FAIL (-1) otherwise
2187 DESCRIPTION
2188 Set/reset the caching in an HDF file.
2189 If file_id is set to CACHE_ALL_FILES, then the value of cache_on is
2190 used to modify the default caching state.
2191 --------------------------------------------------------------------------*/
2192 intn
Hcache(int32 file_id,intn cache_on)2193 Hcache(int32 file_id, intn cache_on)
2194 {
2195 CONSTR(FUNC, "Hcache"); /* for HERROR */
2196 filerec_t *file_rec; /* file record */
2197 intn ret_value = SUCCEED;
2198
2199 if (file_id == CACHE_ALL_FILES)/* check whether to modify the default cache */
2200 { /* set the default caching for all further files Hopen'ed */
2201 default_cache = (cache_on != 0 ? TRUE : FALSE);
2202 } /* end if */
2203 else
2204 {
2205 /* check validity of file record and get dd ptr */
2206 file_rec = HAatom_object(file_id);
2207 if (BADFREC(file_rec))
2208 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2209
2210 /* check whether to flush the file info */
2211 if (cache_on == FALSE && file_rec->cache)
2212 {
2213 if(HIsync(file_rec)==FAIL)
2214 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2215 } /* end if */
2216 file_rec->cache = (cache_on != 0 ? TRUE : FALSE);
2217 } /* end else */
2218
2219 done:
2220 if(ret_value == FAIL)
2221 { /* Error condition cleanup */
2222
2223 } /* end if */
2224
2225 /* Normal function cleanup */
2226 return ret_value;
2227 } /* Hcache */
2228
2229 /*--------------------------------------------------------------------------
2230 NAME
2231 HDvalidfid -- check if a file ID is valid
2232 USAGE
2233 int HDvalidfid(file_id)
2234 int32 file_id; IN: id of file
2235 RETURNS
2236 returns TRUE if valid ID else FALSE
2237 DESCRIPTION
2238 Determine whether a given int32 is a valid HDF file ID or not
2239
2240 --------------------------------------------------------------------------*/
2241 intn
HDvalidfid(int32 file_id)2242 HDvalidfid(int32 file_id)
2243 {
2244 filerec_t *file_rec;
2245 intn ret_value = TRUE;
2246
2247 /* convert file id to file rec and check for validity */
2248 file_rec = HAatom_object(file_id);
2249 if (BADFREC(file_rec))
2250 ret_value = FALSE;
2251
2252 return ret_value;
2253 } /* HDvalidfid */
2254
2255 /*--------------------------------------------------------------------------
2256 HDerr -- Closes a file and return FAIL.
2257 Replacement for DFIerr in HDF3.1 and before
2258 --------------------------------------------------------------------------*/
2259 int
HDerr(int32 file_id)2260 HDerr(int32 file_id)
2261 {
2262 Hclose(file_id);
2263 return FAIL;
2264 }
2265
2266 /*--------------------------------------------------------------------------
2267 NAME
2268 Hsetacceesstype -- set the I/O access type (serial, parallel, ...)
2269 of a data element
2270 USAGE
2271 intn Hsetacceesstype(access_id, accesstype)
2272 int32 access_id; IN: id of access element
2273 uintn accesstype; IN: I/O access type
2274 RETURNS
2275 returns FAIL (-1) if fail, SUCCEED (0) otherwise.
2276 DESCRIPTION
2277 Set the type of I/O for accessing the data element to
2278 accesstype.
2279
2280 --------------------------------------------------------------------------*/
2281 intn
Hsetaccesstype(int32 access_id,uintn accesstype)2282 Hsetaccesstype(int32 access_id, uintn accesstype)
2283 {
2284 CONSTR(FUNC, "Hsetaccesstype"); /* for HERROR */
2285 accrec_t *access_rec; /* access record */
2286 intn ret_value = SUCCEED;
2287
2288 /* clear error stack and check validity of this access id */
2289 HEclear();
2290
2291 access_rec = HAatom_object(access_id);
2292 if (access_rec == (accrec_t *) NULL)
2293 HGOTO_ERROR(DFE_ARGS, FAIL);
2294 if (accesstype != DFACC_DEFAULT && accesstype != DFACC_SERIAL &&
2295 accesstype != DFACC_PARALLEL)
2296 HGOTO_ERROR(DFE_ARGS, FAIL);
2297
2298 if (accesstype == access_rec->access_type)
2299 goto done;
2300
2301 /* kludge mode on */
2302 if (accesstype != DFACC_PARALLEL) /* go to PARALLEL only */
2303 {
2304 ret_value = FAIL;
2305 goto done;
2306 }
2307 /* if special elt, call special function */
2308 if (access_rec->special)
2309 ret_value = HXPsetaccesstype(access_rec);
2310
2311 done:
2312 if(ret_value == FAIL)
2313 { /* Error condition cleanup */
2314
2315 } /* end if */
2316
2317 /* Normal function cleanup */
2318 return ret_value;
2319 } /* Hsetacceesstype() */
2320
2321 /*--------------------------------------------------------------------------
2322 NAME
2323 HDdont_atexit
2324 PURPOSE
2325 Indicates to the library that an 'atexit()' routine is _not_ to be installed
2326 USAGE
2327 intn HDdont_atexit(void)
2328 RETURNS
2329 Returns SUCCEED/FAIL
2330 DESCRIPTION
2331 This routine indicates to the library that an 'atexit()' cleanip routine
2332 should not be installed. The major (only?) purpose for this is in
2333 situations where the library is dynamically linked into an application and
2334 is un-linked from the application before 'exit()' gets callled. In those
2335 situations, a routine installed with 'atexit()' would jump to a routine
2336 which was no longer in memory, causing errors.
2337 In order to be effective, this routine _must_ be called before any other
2338 HDF function calls, and must be called each time the library is loaded/
2339 linked into the application. (the first time and after it's been un-loaded)
2340 GLOBAL VARIABLES
2341 COMMENTS, BUGS, ASSUMPTIONS
2342 If this routine is used, certain memory buffers will not be de-allocated,
2343 although in theory a user could call HPend on their own...
2344 EXAMPLES
2345 REVISION LOG
2346 --------------------------------------------------------------------------*/
HDdont_atexit(void)2347 intn HDdont_atexit(void)
2348 {
2349 #ifdef LATER
2350 CONSTR(FUNC, "HDdont_atexit"); /* for HERROR */
2351 #endif /* LATER */
2352 intn ret_value = SUCCEED;
2353
2354 if(install_atexit == TRUE)
2355 install_atexit=FALSE;
2356
2357 #ifdef LATER
2358 done:
2359 if(ret_value == FAIL)
2360 { /* Error condition cleanup */
2361
2362 } /* end if */
2363 #endif /* LATER */
2364
2365 /* Normal function cleanup */
2366 return(ret_value);
2367 } /* end HDdont_atexit() */
2368
2369 /*==========================================================================
2370
2371 Internal Routines
2372
2373 ==========================================================================*/
2374
2375 /*--------------------------------------------------------------------------
2376 NAME
2377 HIstart
2378 PURPOSE
2379 Global and H-level initialization routine
2380 USAGE
2381 intn HIstart()
2382 RETURNS
2383 Returns SUCCEED/FAIL
2384 DESCRIPTION
2385 Register the global shut-down routine (HPend) for call with atexit
2386 GLOBAL VARIABLES
2387 COMMENTS, BUGS, ASSUMPTIONS
2388 EXAMPLES
2389 REVISION LOG
2390 --------------------------------------------------------------------------*/
HIstart(void)2391 PRIVATE intn HIstart(void)
2392 {
2393 CONSTR(FUNC, "HIstart"); /* for HERROR */
2394 intn ret_value = SUCCEED;
2395
2396 /* Don't call this routine again... */
2397 library_terminate = TRUE;
2398
2399 /* Install atexit() library cleanup routine */
2400 if(install_atexit==TRUE)
2401 if (HDatexit(&HPend) != 0)
2402 HGOTO_ERROR(DFE_CANTINIT, FAIL);
2403
2404 /* Create the file ID and access ID groups */
2405 if(HAinit_group(FIDGROUP,64)==FAIL)
2406 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2407 if(HAinit_group(AIDGROUP,256)==FAIL)
2408 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2409
2410 #ifdef OLD_WAY
2411 if((cleanup_list=HULcreate_list(NULL))==NULL)
2412 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2413 #else
2414 if(cleanup_list == NULL)
2415 {
2416 /* allocate list to hold terminateion fcns */
2417 if ((cleanup_list = HDmalloc(sizeof(Generic_list))) == NULL)
2418 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2419
2420 /* initialize list */
2421 if (HDGLinitialize_list(cleanup_list) == FAIL)
2422 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2423 }
2424 #endif
2425
2426 done:
2427 if(ret_value == FAIL)
2428 { /* Error condition cleanup */
2429
2430 } /* end if */
2431
2432 /* Normal function cleanup */
2433 return(ret_value);
2434 } /* end HIstart() */
2435
2436 /*--------------------------------------------------------------------------
2437 NAME
2438 HPregister_term_func
2439 PURPOSE
2440 Registers a termination function in the list of routines to call during
2441 atexit() termination.
2442 USAGE
2443 intn HPregister_term_func(term_func)
2444 intn (*term_func)(); IN: function to call during axexit()
2445 RETURNS
2446 Returns SUCCEED/FAIL
2447 DESCRIPTION
2448 Adds routines to the linked-list of routines to call when terminating the
2449 library.
2450 GLOBAL VARIABLES
2451 COMMENTS, BUGS, ASSUMPTIONS
2452 Should only ever be called by the "atexit" function, or real power-users.
2453 EXAMPLES
2454 REVISION LOG
2455 --------------------------------------------------------------------------*/
HPregister_term_func(hdf_termfunc_t term_func)2456 intn HPregister_term_func(hdf_termfunc_t term_func)
2457 {
2458 CONSTR(FUNC, "HPregister_term_func"); /* for HERROR */
2459 intn ret_value = SUCCEED;
2460 if(library_terminate == FALSE)
2461 if(HIstart()==FAIL)
2462 HGOTO_ERROR(DFE_CANTINIT, FAIL);
2463
2464 #ifdef OLD_WAY
2465 if(HULadd_node(cleanup_list,(void *)term_func)==FAIL)
2466 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2467 #else
2468 if(HDGLadd_to_list(*cleanup_list,(void *)term_func)==FAIL)
2469 HGOTO_ERROR(DFE_INTERNAL, FAIL);
2470 #endif
2471
2472 done:
2473 if(ret_value == FAIL)
2474 { /* Error condition cleanup */
2475
2476 } /* end if */
2477
2478 /* Normal function cleanup */
2479 return(ret_value);
2480 } /* end HPregister_term_func() */
2481
2482 /*--------------------------------------------------------------------------
2483 NAME
2484 HPend
2485 PURPOSE
2486 Terminate various static buffers and shutdown the library.
2487 USAGE
2488 intn HPend()
2489 RETURNS
2490 Returns SUCCEED/FAIL
2491 DESCRIPTION
2492 Walk through the shutdown routines for the various interfaces and
2493 terminate them all.
2494 GLOBAL VARIABLES
2495 COMMENTS, BUGS, ASSUMPTIONS
2496 Should only ever be called by the "atexit" function, or real power-users.
2497 EXAMPLES
2498 REVISION LOG
2499 --------------------------------------------------------------------------*/
HPend(void)2500 void HPend(void)
2501 {
2502 #ifdef LATER
2503 CONSTR(FUNC, "HPend"); /* for HERROR */
2504 #endif /* LATER */
2505 hdf_termfunc_t term_func; /* pointer to a termination routine for an interface */
2506
2507 /* Shutdown the file ID atom group */
2508 HAdestroy_group(FIDGROUP);
2509
2510 /* Shutdown the access ID atom group */
2511 HAdestroy_group(AIDGROUP);
2512
2513 if((term_func=(hdf_termfunc_t)HDGLfirst_in_list(*cleanup_list))!=NULL)
2514 {
2515 do {
2516 (*term_func)();
2517 } while((term_func=(hdf_termfunc_t)HDGLnext_in_list(*cleanup_list))!=NULL);
2518 } /* end if */
2519
2520 /* can't issue errors if you're free'ing the error stack. */
2521 HDGLdestroy_list(cleanup_list); /* clear the list of interface cleanup routines */
2522 /* free allocated list struct */
2523 HDfree(cleanup_list);
2524 /* re-initialize */
2525 cleanup_list = NULL;
2526
2527
2528 HPbitshutdown();
2529 HXPshutdown();
2530 Hshutdown();
2531 HEshutdown();
2532 HAshutdown();
2533 #ifdef OLD_WAY
2534 HULshutdown();
2535 #endif
2536 tbbt_shutdown();
2537 } /* end HPend() */
2538
2539 /*--------------------------------------------------------------------------
2540 NAME
2541 HIextend_file -- extend file to current length
2542 USAGE
2543 int HIextend_file(file_rec)
2544 filerec_t * file_rec IN: pointer to file structure to extend
2545 RETURNS
2546 SUCCEED / FAIL
2547 DESCRIPTION
2548 The routine extends an HDF file to be the length on the f_end_off
2549 member of the file_rec. This is mainly written as a function so that
2550 the functionality is localized.
2551 --------------------------------------------------------------------------*/
2552 PRIVATE intn
HIextend_file(filerec_t * file_rec)2553 HIextend_file(filerec_t * file_rec)
2554 {
2555 CONSTR(FUNC, "HIextend_file"); /* for HERROR */
2556 uint8 temp = 0;
2557 intn ret_value = SUCCEED;
2558
2559 if (HPseek(file_rec, file_rec->f_end_off) == FAIL)
2560 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
2561 if (HP_write(file_rec, &temp, 1) == FAIL)
2562 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
2563
2564 done:
2565 if(ret_value == FAIL)
2566 { /* Error condition cleanup */
2567
2568 } /* end if */
2569
2570 /* Normal function cleanup */
2571
2572 return ret_value;
2573 } /* HIextend_file */
2574
2575 /*--------------------------------------------------------------------------
2576 NAME
2577 HIget_function_table -- create special function table
2578 USAGE
2579 int HIget_func_table(access_rec, FUNC)
2580 accrec_t * access_rec; IN: access record we are working on
2581 char * FUNC; IN: function we are working for
2582 RETURNS
2583 NULL no matter what (seems odd....)
2584 DESCRIPTION
2585 Set up the table of special functions for a given special element
2586
2587 --------------------------------------------------------------------------*/
2588 PRIVATE funclist_t *
HIget_function_table(accrec_t * access_rec)2589 HIget_function_table(accrec_t * access_rec)
2590 {
2591 CONSTR(FUNC, "HIget_function_table"); /* for HERROR */
2592 filerec_t *file_rec; /* file record */
2593 int16 spec_code;
2594 uint8 lbuf[4]; /* temporary buffer */
2595 uint8 *p; /* tmp buf ptr */
2596 int32 data_off; /* offset of the data we are checking */
2597 int i; /* loop index */
2598 funclist_t *ret_value = NULL; /* FAIL */
2599
2600 /* read in the special code in the special elt */
2601 file_rec = HAatom_object(access_rec->file_id);
2602
2603 /* get the offset and length of the dataset */
2604 if(HTPinquire(access_rec->ddid,NULL,NULL,&data_off,NULL)==FAIL)
2605 HGOTO_ERROR(DFE_INTERNAL, NULL);
2606
2607 if (HPseek(file_rec, data_off) == FAIL)
2608 HGOTO_ERROR(DFE_SEEKERROR, NULL);
2609 if (HP_read(file_rec, lbuf, (int)2) == FAIL)
2610 HGOTO_ERROR(DFE_READERROR, NULL);
2611
2612 /* using special code, look up function table in associative table */
2613 p = &lbuf[0];
2614 INT16DECODE(p, spec_code);
2615 access_rec->special=(intn)spec_code;
2616 for (i = 0; functab[i].key != 0; i++)
2617 {
2618 if (access_rec->special == functab[i].key)
2619 {
2620 ret_value = functab[i].tab;
2621 break; /* break out of loop */
2622 }
2623 }
2624
2625 done:
2626 if(ret_value == NULL)
2627 { /* Error condition cleanup */
2628
2629 } /* end if */
2630
2631 /* Normal function cleanup */
2632
2633 return ret_value;
2634 } /* HIget_function_table */
2635
2636 /*--------------------------------------------------------------------------
2637 NAME
2638 HIgetspinfo -- return special info
2639 USAGE
2640 int HIgetspinfo(access_rec, tag, ref)
2641 accrec_t * access_rec; IN: access record we are working on
2642 int16 tag; IN: tag to look for
2643 int16 ref; IN: ref to look for
2644 RETURNS
2645 special_info field or NULL if not found
2646 DESCRIPTION
2647 given the tag and ref of a given element return the special
2648 info field of the access element.
2649
2650 Basically, this function checks if any other AIDs in the file
2651 have read in the special information for this object. If so,
2652 this special information will be reused. Otherwise, the
2653 special element handling code needs to read in the information
2654 from disk
2655 GLOBALS
2656 Reads from the global access_records
2657
2658 --------------------------------------------------------------------------*/
2659 void *
HIgetspinfo(accrec_t * access_rec)2660 HIgetspinfo(accrec_t * access_rec)
2661 {
2662 #ifdef LATER
2663 CONSTR(FUNC, "HIgetspinfo"); /* for HERROR */
2664 #endif /* LATER */
2665 void * ret_value = NULL; /* FAIL */
2666
2667 if((ret_value=HAsearch_atom(AIDGROUP,HPcompare_accrec_tagref,access_rec))!=NULL)
2668 HGOTO_DONE(((accrec_t *)ret_value)->special_info);
2669
2670 done:
2671 if(ret_value == NULL)
2672 { /* Error condition cleanup */
2673
2674 } /* end if */
2675
2676 /* Normal function cleanup */
2677
2678 return ret_value;
2679 } /* HIgetspinfo */
2680
2681 /*--------------------------------------------------------------------------
2682 HIunlock -- unlock a previously locked file record
2683 --------------------------------------------------------------------------*/
2684 PRIVATE int
HIunlock(filerec_t * file_rec)2685 HIunlock(filerec_t *file_rec)
2686 {
2687 #ifdef LATER
2688 CONSTR(FUNC, "HIunlock"); /* for HERROR */
2689 int ret_value = SUCCEED;
2690 #endif /* LATER */
2691
2692 /* unlock the file record */
2693 file_rec->attach--;
2694
2695 #ifdef LATER
2696 done:
2697 if(ret_value == FAIL)
2698 { /* Error condition cleanup */
2699
2700 } /* end if */
2701
2702 /* Normal function cleanup */
2703
2704 return ret_value;
2705 #endif /* LATER */
2706 return(SUCCEED);
2707 }
2708
2709 /* ------------------------- SPECIAL TAG ROUTINES ------------------------- */
2710 /*
2711 The HDF tag space is divided as follows based on the 2 highest bits:
2712 00: NCSA reserved ordinary tags
2713 01: NCSA reserved special tags
2714 10, 11: User tags.
2715
2716 It is relatively cheap to operate with special tags within the NCSA
2717 reserved tags range. For users to specify special tags and their
2718 corresponding ordinary tag, the pair has to be added to the
2719 special_table.
2720
2721 The special_table contains pairs of each tag and its corrsponding
2722 special tag. The same table is also used to determine if a tag is
2723 special. Add to this table any additional tag/special_tag pairs
2724 that might be necessary.
2725
2726 */
2727
2728 /*
2729 The functionality of these routines is covered by the SPECIALTAG,
2730 MKSPECIALTAG and BASETAG macros
2731 */
2732
2733 #ifdef SPECIAL_TABLE
2734
2735 typedef struct special_table_t
2736 {
2737 uint16 tag;
2738 uint16 special_tag;
2739 }
2740 special_table_t;
2741
2742 PRIVATE special_table_t special_table[] =
2743 {
2744 {0x8010, 0x4000 | 0x8010}, /* dummy */
2745 };
2746
2747 #define SP_TAB_SZ (sizeof(special_table) / sizeof(special_table[0]))
2748
2749 /*--------------------------------------------------------------------------
2750 --------------------------------------------------------------------------*/
2751 uint16
HDmake_special_tag(uint16 tag)2752 HDmake_special_tag(uint16 tag)
2753 {
2754 int i;
2755 uint16 ret_value = DFTAG_NULL; /* FAIL */
2756
2757 if (~tag & 0x8000)
2758 {
2759 ret_value = ((uint16) (tag | 0x4000));
2760 goto done;
2761 }
2762
2763 for (i = 0; i < SP_TAB_SZ; i++)
2764 if (special_table[i].tag == tag)
2765 {
2766 ret_value = (uint16) special_table[i].special_tag;
2767 break;
2768 }
2769
2770
2771 done:
2772 if(ret_value == DFTAG_NULL)
2773 { /* Error condition cleanup */
2774
2775 } /* end if */
2776
2777 /* Normal function cleanup */
2778
2779 return ret_value;
2780 }
2781
2782 /*--------------------------------------------------------------------------
2783 --------------------------------------------------------------------------*/
2784 intn
HDis_special_tag(uint16 tag)2785 HDis_special_tag(uint16 tag)
2786 {
2787 int i;
2788 intn ret_value = FALSE; /* FAIL */
2789
2790 if (~tag & 0x8000)
2791 {
2792 ret_value = (tag & 0x4000) ? TRUE : FALSE;
2793 goto done;
2794 }
2795
2796 for (i = 0; i < SP_TAB_SZ; i++)
2797 if (special_table[i].special_tag == tag)
2798 {
2799 ret_value = TRUE;
2800 break;
2801 }
2802
2803 done:
2804 if(ret_value == FALSE)
2805 { /* Error condition cleanup */
2806
2807 } /* end if */
2808
2809 /* Normal function cleanup */
2810
2811 return ret_value;
2812 }
2813
2814 /*--------------------------------------------------------------------------
2815 --------------------------------------------------------------------------*/
2816 uint16
HDbase_tag(uint16 tag)2817 HDbase_tag(uint16 tag)
2818 {
2819 int i;
2820 uint16 ret_value = tag;
2821
2822 if (~tag & 0x8000)
2823 {
2824 ret_value = ((uint16) (tag & ~0x4000));
2825 goto done;
2826 }
2827
2828 for (i = 0; i < SP_TAB_SZ; i++)
2829 if (special_table[i].special_tag == tag)
2830 {
2831 ret_value = special_table[i].special_tag;
2832 break;
2833 }
2834 done:
2835 if(ret_value == tag)
2836 { /* Error condition cleanup */
2837
2838 } /* end if */
2839
2840 /* Normal function cleanup */
2841
2842 return ret_value;
2843 }
2844
2845 #endif /* SPECIAL_TABLE */
2846
2847 /*--------------------------------------------------------------------------
2848 NAME
2849 Hgetlibversion -- return version info for current HDF library
2850 USAGE
2851 intn Hgetlibversion(majorv, minorv, release, string)
2852 uint32 *majorv; OUT: majorv version number
2853 uint32 *minorv; OUT: minorv versoin number
2854 uint32 *release; OUT: release number
2855 char string[]; OUT: informational text string (80 chars)
2856 RETURNS
2857 returns SUCCEED (0).
2858 DESCRIPTION
2859 Copies values from #defines in hfile.h to provided buffers. This
2860 information is statistically compilied into the HDF library, so
2861 it is not necessary to have any files open to get this information.
2862
2863 --------------------------------------------------------------------------*/
2864 intn
Hgetlibversion(uint32 * majorv,uint32 * minorv,uint32 * releasev,char * string)2865 Hgetlibversion(uint32 *majorv, uint32 *minorv, uint32 *releasev, char *string)
2866 {
2867 #ifdef LATER
2868 CONSTR(FUNC, "Hgetlibversion");
2869 #endif
2870 HEclear();
2871
2872 *majorv = LIBVER_MAJOR;
2873 *minorv = LIBVER_MINOR;
2874 *releasev = LIBVER_RELEASE;
2875 HIstrncpy(string, LIBVER_STRING, LIBVSTR_LEN + 1);
2876
2877 return (SUCCEED);
2878 } /* HDgetlibversion */
2879
2880 /*--------------------------------------------------------------------------
2881 NAME
2882 Hgetfileversion -- return version info for HDF file
2883 USAGE
2884 intn Hgetfileversion(file_id, majorv, minorv, release, string)
2885 int32 file_id; IN: handle of file
2886 uint32 *majorv; OUT: majorv version number
2887 uint32 *minorv; OUT: minorv versoin number
2888 uint32 *release; OUT: release number
2889 char *string; OUT: informational text string (80 chars)
2890 RETURNS
2891 returns SUCCEED (0) if successful and FAIL (-1) if failed.
2892 DESCRIPTION
2893 Copies values from file_records[] structure for a given file to
2894 provided buffers.
2895 GLOBAL VARIABLES
2896 Reads file_records[]
2897
2898 --------------------------------------------------------------------------*/
2899 intn
Hgetfileversion(int32 file_id,uint32 * majorv,uint32 * minorv,uint32 * release,char * string)2900 Hgetfileversion(int32 file_id, uint32 *majorv, uint32 *minorv,
2901 uint32 *release, char *string)
2902 {
2903 CONSTR(FUNC, "Hgetfileversion");
2904 filerec_t *file_rec;
2905 intn ret_value = SUCCEED;
2906
2907 HEclear();
2908
2909 file_rec = HAatom_object(file_id);
2910 if (BADFREC(file_rec))
2911 HGOTO_ERROR(DFE_ARGS, FAIL);
2912
2913 if (majorv != NULL)
2914 *majorv = file_rec->version.majorv;
2915 if (minorv != NULL)
2916 *minorv = file_rec->version.minorv;
2917 if (release != NULL)
2918 *release = file_rec->version.release;
2919 if (string != NULL)
2920 HIstrncpy(string, file_rec->version.string, LIBVSTR_LEN + 1);
2921
2922 done:
2923 if(ret_value == FAIL)
2924 { /* Error condition cleanup */
2925
2926 } /* end if */
2927
2928 /* Normal function cleanup */
2929 return ret_value;
2930 } /* Hgetfileversion */
2931
2932 /*--------------------------------------------------------------------------
2933 NAME
2934 HIcheckfileversion -- check version info for HDF file
2935 USAGE
2936 intn Hgetfileversion(file_id)
2937 int32 file_id; IN: handle of file
2938 RETURNS
2939 returns SUCCEED (0) if successful and FAIL (-1) if failed.
2940 DESCRIPTION
2941 Checks that the file's version is current and update it if it isn't.
2942
2943 --------------------------------------------------------------------------*/
2944 PRIVATE intn
HIcheckfileversion(int32 file_id)2945 HIcheckfileversion(int32 file_id)
2946 {
2947 CONSTR(FUNC, "HIcheckfileversion");
2948 filerec_t *file_rec;
2949 uint32 lmajorv, lminorv, lrelease;
2950 uint32 fmajorv, fminorv, frelease;
2951 char string[LIBVSTR_LEN + 1]; /* len 80+1 */
2952 intn newver = 0;
2953 intn ret_value = SUCCEED;
2954
2955 HEclear();
2956
2957 file_rec = HAatom_object(file_id);
2958 if (BADFREC(file_rec))
2959 HGOTO_ERROR(DFE_ARGS, FAIL);
2960
2961 /* get file version and set newver condition */
2962 if (Hgetfileversion(file_id, &fmajorv, &fminorv, &frelease, string) != SUCCEED)
2963 {
2964 newver = 1;
2965 HEclear();
2966 } /* end if */
2967
2968 /* get library version */
2969 Hgetlibversion(&lmajorv, &lminorv, &lrelease, string);
2970
2971 /* check whether we need to update the file version tag */
2972 if(lmajorv > fmajorv || (lmajorv==fmajorv && lminorv > fminorv) ||
2973 (lmajorv==fmajorv && lminorv==fminorv && lrelease > frelease))
2974 newver=1;
2975 if (newver == 1)
2976 {
2977 file_rec->version.majorv = lmajorv;
2978 file_rec->version.minorv = lminorv;
2979 file_rec->version.release = lrelease;
2980 HIstrncpy(file_rec->version.string, string, LIBVSTR_LEN + 1);
2981 file_rec->version.modified = 1;
2982 } /* end if */
2983
2984 file_rec->version_set = TRUE;
2985
2986 done:
2987 if(ret_value == FAIL)
2988 { /* Error condition cleanup */
2989
2990 } /* end if */
2991
2992 /* Normal function cleanup */
2993
2994 return ret_value;
2995 } /* HIcheckfileversion */
2996
2997 /*--------------------------------------------------------------------------
2998 NAME
2999 HIget_filerec_node -- find a filerec for a FILE
3000 USAGE
3001 filerec_t *HIget_filerec_node(path)
3002 char * path; IN: name of file
3003 RETURNS
3004 a file record or else NULL
3005 DESCRIPTION
3006 Search the file record array for a matching record, or allocate an
3007 empty slot.
3008 The file is considered the same if the path matches exactly. This
3009 routine is unable to detect aliases, or how to compare relative and
3010 absolute paths.
3011
3012 --------------------------------------------------------------------------*/
3013 PRIVATE filerec_t *
HIget_filerec_node(const char * path)3014 HIget_filerec_node(const char *path)
3015 {
3016 CONSTR(FUNC, "HIget_filerec_node");
3017 filerec_t *ret_value=NULL;
3018
3019 if((ret_value=HAsearch_atom(FIDGROUP,HPcompare_filerec_path,path))==NULL)
3020 {
3021 if((ret_value=(filerec_t *)HDcalloc(1,sizeof(filerec_t)))==NULL)
3022 HGOTO_ERROR(DFE_NOSPACE,NULL);
3023
3024 if((ret_value->path=(char *)HDstrdup(path))==NULL)
3025 HGOTO_ERROR(DFE_NOSPACE,NULL);
3026
3027 /* Initialize annotation stuff */
3028 ret_value->an_tree[AN_DATA_LABEL] = NULL;
3029 ret_value->an_tree[AN_DATA_DESC] = NULL;
3030 ret_value->an_tree[AN_FILE_LABEL] = NULL;
3031 ret_value->an_tree[AN_FILE_DESC] = NULL;
3032 ret_value->an_num[AN_DATA_LABEL] = -1;
3033 ret_value->an_num[AN_DATA_DESC] = -1;
3034 ret_value->an_num[AN_FILE_LABEL] = -1;
3035 ret_value->an_num[AN_FILE_DESC] = -1;
3036 } /* end if */
3037
3038 done:
3039 if(ret_value == NULL)
3040 { /* Error condition cleanup */
3041
3042 } /* end if */
3043
3044 /* Normal function cleanup */
3045
3046 return ret_value;
3047 } /* HIget_filerec_node */
3048
3049 /*--------------------------------------------------------------------------
3050 NAME
3051 HIrelease_filerec_node -- release/recycle a filerec
3052 USAGE
3053 intn HIrelease_filerec_node(file_rec)
3054 filerec_t *file_rec; IN: File record to release
3055 RETURNS
3056 SUCCEED/FAIL
3057 DESCRIPTION
3058 Release a file record back to the system
3059
3060 --------------------------------------------------------------------------*/
3061 PRIVATE intn
HIrelease_filerec_node(filerec_t * file_rec)3062 HIrelease_filerec_node(filerec_t *file_rec)
3063 {
3064 #ifdef LATER
3065 CONSTR(FUNC, "HIrelease_filerec_node");
3066 #endif /* LATER */
3067
3068 /* Close file if it's opened */
3069 if(file_rec->file!=NULL)
3070 HI_CLOSE(file_rec->file);
3071
3072 /* Free all the components of the file record */
3073 if(file_rec->path!=NULL)
3074 HDfree(file_rec->path);
3075 HDfree(file_rec);
3076
3077 #ifdef LATER
3078 done:
3079 if(ret_value == FAIL)
3080 { /* Error condition cleanup */
3081
3082 } /* end if */
3083 #endif /* LATER */
3084
3085 /* Normal function cleanup */
3086
3087 return SUCCEED;
3088 } /* HIrelease_filerec_node */
3089
3090 /*--------------------------------------------------------------------------
3091 NAME
3092 HPisfile_in_use -- check if a FILE is currently in use
3093 USAGE
3094 intn HPisfile_in_use(path)
3095 const char * path; IN: name of file
3096 RETURNS
3097 TRUE if the file is in use or FALSE, otherwise.
3098 DESCRIPTION
3099 Get its record if the file is opened, then check its
3100 reference count to decide whether the file is currently in use.
3101
3102 --------------------------------------------------------------------------*/
HPisfile_in_use(const char * path)3103 intn HPisfile_in_use(const char *path)
3104 {
3105 #ifdef LATER
3106 CONSTR(FUNC, "HPisfile_in_use");
3107 #endif /* LATER */
3108
3109 filerec_t *file_rec=NULL;
3110 intn ret_value=FALSE;
3111
3112 /* Search for the record of a file named "path". */
3113 file_rec = (filerec_t *)HAsearch_atom(FIDGROUP,HPcompare_filerec_path,path);
3114
3115 /* If the file is not found, it can't be in use, return FALSE */
3116 if (file_rec == NULL)
3117 ret_value = FALSE;
3118 else
3119 if (file_rec->refcount) /* file is in use if ref count is not 0 */
3120 ret_value = TRUE;
3121
3122 #ifdef LATER
3123 done:
3124 if(ret_value == FALSE)
3125 { /* Error condition cleanup */
3126
3127 } /* end if */
3128 #endif /* LATER */
3129
3130 /* Normal function cleanup */
3131
3132 return ret_value;
3133 } /* HPisfile_in_use */
3134
3135 /*--------------------------------------------------------------------------
3136 NAME
3137 HPcompare_filerec_path -- compare filerec objects for the atom API
3138 USAGE
3139 intn HPcompare_filerec_path(obj, key)
3140 const void * obj; IN: pointer to the file record
3141 const void * key; IN: pointer to the name of file
3142 RETURNS
3143 TRUE if the key matches the obj, FALSE otherwise
3144 DESCRIPTION
3145 Look inside the file record for the atom API and compare the the
3146 paths.
3147 --------------------------------------------------------------------------*/
HPcompare_filerec_path(const void * obj,const void * key)3148 intn HPcompare_filerec_path(const void * obj, const void * key)
3149 {
3150 const filerec_t *frec = obj;
3151 const char *fname = key;
3152 intn ret_value = FALSE; /* set default as FALSE */
3153 #ifdef LATER
3154 CONSTR(FUNC, "HPcompare_filerec_path");
3155 #endif /* LATER */
3156
3157 /* check args */
3158 if (frec != NULL && fname != NULL)
3159 {
3160 /* check bad file record */
3161 if (BADFREC(frec))
3162 ret_value = FALSE;
3163 else
3164 {
3165 if(!HDstrcmp(frec->path,fname))
3166 ret_value = TRUE;
3167 else
3168 ret_value = FALSE;
3169 }
3170 }
3171
3172 #ifdef LATER
3173 done:
3174 if(ret_value == FALSE)
3175 { /* Error condition cleanup */
3176
3177 } /* end if */
3178 #endif /* LATER */
3179
3180 /* Normal function cleanup */
3181
3182 return ret_value;
3183 } /* HPcompare_filerec_path */
3184
3185 /*--------------------------------------------------------------------------
3186 NAME
3187 HPcompare_accrec_tagref -- compare accrec objects for the atom API
3188 USAGE
3189 intn HPcompare_accrec_tagref(obj, key)
3190 const void * rec1; IN: pointer to the access record #1
3191 const void * rec2; IN: pointer to the access record #2
3192 RETURNS
3193 TRUE if tag/ref of rec1 matches the tag/ref of rec2, FALSE otherwise
3194 DESCRIPTION
3195 Look inside the access record for the atom API and compare the the
3196 paths.
3197 --------------------------------------------------------------------------*/
HPcompare_accrec_tagref(const void * rec1,const void * rec2)3198 intn HPcompare_accrec_tagref(const void * rec1, const void * rec2)
3199 {
3200 CONSTR(FUNC, "HPcompare_accrec_tagref");
3201 uint16 tag1,ref1; /* tag/ref of access record #1 */
3202 uint16 tag2,ref2; /* tag/ref of access record #2 */
3203 intn ret_value = FALSE; /* FAIL */
3204
3205 if(rec1!=rec2)
3206 {
3207 if(HTPinquire(((const accrec_t *)rec1)->ddid,&tag1,&ref1,NULL,NULL)==FAIL)
3208 HGOTO_ERROR(DFE_INTERNAL, FALSE);
3209
3210 if(HTPinquire(((const accrec_t *)rec2)->ddid,&tag2,&ref2,NULL,NULL)==FAIL)
3211 HGOTO_ERROR(DFE_INTERNAL, FALSE);
3212
3213 if (((const accrec_t *)rec1)->file_id == ((const accrec_t *)rec2)->file_id
3214 && tag1 == tag2 && ref1 == ref2)
3215 HGOTO_DONE(TRUE);
3216 } /* end if */
3217
3218 done:
3219 if(ret_value == FALSE)
3220 { /* Error condition cleanup */
3221
3222 } /* end if */
3223
3224 /* Normal function cleanup */
3225
3226 return(ret_value);
3227 } /* HPcompare_accrec_tagref */
3228
3229 /*--------------------------------------------------------------------------
3230 NAME
3231 HIvalid_magic -- verify the magic number in a file
3232 USAGE
3233 int32 HIvalid_magic(path)
3234 hdf_file_t file; IN: FILE pointer
3235 RETURNS
3236 TRUE if valid magic number else FALSE
3237 DESCRIPTION
3238 Given an open file pointer, see if the first four bytes of the
3239 file are the HDF "magic number" HDFMAGIC
3240
3241 --------------------------------------------------------------------------*/
3242 PRIVATE intn
HIvalid_magic(hdf_file_t file)3243 HIvalid_magic(hdf_file_t file)
3244 {
3245 CONSTR(FUNC, "HIvalid_magic");
3246 char b[MAGICLEN]; /* Temporary buffer */
3247 intn ret_value = FALSE; /* FAIL */
3248
3249 /* Seek to beginning of the file. */
3250 if (HI_SEEK(file, 0) == FAIL)
3251 HGOTO_ERROR(DFE_SEEKERROR, FALSE);
3252
3253 /* Read in magic cookie and compare. */
3254 if (HI_READ(file, b, MAGICLEN) == FAIL)
3255 HGOTO_ERROR(DFE_READERROR, FALSE);
3256
3257 if (NSTREQ(b, HDFMAGIC, MAGICLEN))
3258 ret_value = TRUE;
3259
3260 done:
3261 if(ret_value == FALSE)
3262 { /* Error condition cleanup */
3263
3264 } /* end if */
3265
3266 /* Normal function cleanup */
3267
3268 return ret_value;
3269 }
3270
3271 /*--------------------------------------------------------------------------
3272 NAME
3273 HIget_access_rec -- allocate a new access record
3274 USAGE
3275 int HIget_access_rec(void)
3276 RETURNS
3277 returns access_record pointer or NULL if failed.
3278 DESCRIPTION
3279 Return an pointer to a new access_rec to use for a new AID.
3280
3281 --------------------------------------------------------------------------*/
HIget_access_rec(void)3282 accrec_t *HIget_access_rec(void)
3283 {
3284 CONSTR(FUNC, "HIget_access_rec");
3285 accrec_t *ret_value = NULL;
3286
3287 HEclear();
3288
3289 /* Grab from free list if possible */
3290 if(accrec_free_list!=NULL)
3291 {
3292 ret_value=accrec_free_list;
3293 accrec_free_list=accrec_free_list->next;
3294 } /* end if */
3295 else
3296 {
3297 if((ret_value=(accrec_t *)HDmalloc(sizeof(accrec_t)))==NULL)
3298 HGOTO_ERROR(DFE_NOSPACE, NULL);
3299 } /* end else */
3300
3301 /* Initialize to zeros */
3302 HDmemset(ret_value,0,sizeof(accrec_t));
3303
3304 done:
3305 if(ret_value == NULL)
3306 { /* Error condition cleanup */
3307
3308 } /* end if */
3309
3310 /* Normal function cleanup */
3311
3312 return ret_value;
3313 } /* HIget_access_rec */
3314
3315 /******************************************************************************
3316 NAME
3317 HIrelease_accrec_node - Releases an atom node
3318
3319 DESCRIPTION
3320 Puts an accrec node into the free list
3321
3322 RETURNS
3323 No return value
3324
3325 *******************************************************************************/
HIrelease_accrec_node(accrec_t * acc)3326 void HIrelease_accrec_node(accrec_t *acc)
3327 {
3328 #ifdef LATER
3329 CONSTR(FUNC, "HIrelease_atom_node"); /* for HERROR */
3330 #endif /* LATER */
3331
3332 /* Insert the atom at the beginning of the free list */
3333 acc->next=accrec_free_list;
3334 accrec_free_list=acc;
3335 } /* end HIrelease_accrec_node() */
3336
3337 /*--------------------------------------------------------------------------
3338 PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
3339 NAME
3340 HIupdate_version -- determine whether new version tag should be written
3341 USAGE
3342 int HIupdate_version(file_id)
3343 int32 file_id; IN: handle of file
3344 RETURNS
3345 returns SUCCEED (0) if successful and FAIL (-1) if failed.
3346 DESCRIPTION
3347 Writes out version numbers of current library as file version.
3348 GLOBAL VARIABLES
3349 Resets modified field of version field of appropriate file_records[]
3350 entry.
3351
3352 --------------------------------------------------------------------------*/
3353 PRIVATE int
HIupdate_version(int32 file_id)3354 HIupdate_version(int32 file_id)
3355 {
3356 /* uint32 lmajorv, lminorv, lrelease; */
3357 uint8 /*lstring[81], */ lversion[LIBVER_LEN];
3358 filerec_t * file_rec;
3359 int i;
3360 CONSTR(FUNC, "Hupdate_version");
3361 int ret_value = SUCCEED;
3362
3363 HEclear();
3364
3365 /* Check args */
3366 file_rec=HAatom_object(file_id);
3367 if (BADFREC(file_rec))
3368 HGOTO_ERROR(DFE_ARGS, FAIL);
3369
3370 /* copy in-memory version to file */
3371 Hgetlibversion(&(file_rec->version.majorv), &(file_rec->version.minorv),
3372 &(file_rec->version.release), file_rec->version.string);
3373
3374 {
3375 uint8 *p;
3376
3377 p = lversion;
3378 UINT32ENCODE(p, file_rec->version.majorv);
3379 UINT32ENCODE(p, file_rec->version.minorv);
3380 UINT32ENCODE(p, file_rec->version.release);
3381 HIstrncpy((char *) p, file_rec->version.string, LIBVSTR_LEN);
3382 i = (int)HDstrlen((char *) p);
3383 HDmemset(&p[i],0,LIBVSTR_LEN-i);
3384 }
3385
3386 if(Hputelement(file_id, (uint16) DFTAG_VERSION, (uint16) 1, lversion,
3387 (int32) LIBVER_LEN)==FAIL)
3388 HGOTO_ERROR(DFE_INTERNAL, FAIL);
3389
3390 file_rec->version.modified = 0;
3391
3392 done:
3393 if(ret_value == FAIL)
3394 { /* Error condition cleanup */
3395
3396 } /* end if */
3397
3398 /* Normal function cleanup */
3399
3400 return ret_value;
3401 } /* HIupdate_version */
3402
3403 /*--------------------------------------------------------------------------
3404 PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
3405 NAME
3406 HIread_version -- reads a version tag from a file
3407 USAGE
3408 int HIread_version(file_id)
3409 int32 file_id; IN: handle of file
3410 RETURNS
3411 returns SUCCEED (0) if successful and FAIL (-1) if failed.
3412 DESCRIPTION
3413 Reads a version tag from the specified file into the version fields
3414 of the appropriate filerec_t. On failure, zeros are put in the version
3415 number fields and NULLS in the string.
3416 GLOBAL VARIABLES
3417 Writes to version fields of appropriate file_records[] entry.
3418
3419 --------------------------------------------------------------------------*/
3420 PRIVATE int
HIread_version(int32 file_id)3421 HIread_version(int32 file_id)
3422 {
3423 filerec_t *file_rec;
3424 uint8 fversion[LIBVER_LEN];
3425 CONSTR(FUNC, "Hread_version");
3426 int ret_value = SUCCEED;
3427
3428 HEclear();
3429
3430 file_rec = HAatom_object(file_id);
3431 if (BADFREC(file_rec))
3432 HGOTO_ERROR(DFE_ARGS, FAIL);
3433
3434 if (Hgetelement(file_id, (uint16) DFTAG_VERSION, (uint16) 1, fversion) == FAIL)
3435 {
3436 file_rec->version.majorv = 0;
3437 file_rec->version.minorv = 0;
3438 file_rec->version.release = 0;
3439 HDstrcpy(file_rec->version.string, "");
3440 file_rec->version.modified = 0;
3441 HGOTO_ERROR(DFE_INTERNAL, FAIL);
3442 }
3443 else
3444 {
3445 uint8 *p;
3446
3447 p = fversion;
3448 UINT32DECODE(p, file_rec->version.majorv);
3449 UINT32DECODE(p, file_rec->version.minorv);
3450 UINT32DECODE(p, file_rec->version.release);
3451 HIstrncpy(file_rec->version.string, (char *) p, LIBVSTR_LEN);
3452 }
3453 file_rec->version.modified = 0;
3454
3455 done:
3456 if(ret_value == FAIL)
3457 { /* Error condition cleanup */
3458
3459 } /* end if */
3460
3461 /* Normal function cleanup */
3462
3463 return ret_value;
3464 } /* HIread_version */
3465
3466 /*-----------------------------------------------------------------------
3467 NAME
3468 HPgetdiskblock --- Get the offset of a free block in the file.
3469 USAGE
3470 int32 HPgetdiskblock(file_rec, block_size)
3471 filerec_t *file_rec; IN: ptr to the file record
3472 int32 block_size; IN: size of the block needed
3473 intn moveto; IN: whether to move the file position
3474 to the allocated position or leave
3475 it undefined.
3476 RETURNS
3477 returns offset of block in the file if successful, FAIL (-1) if failed.
3478 DESCRIPTION
3479 Used to "allocate" space in the file. Currently, it just appends
3480 blocks to the end of the file willy-nilly. At some point in the
3481 future, this could be changed to use a "real" free-list of empty
3482 blocks in the file and dole those out.
3483
3484 -------------------------------------------------------------------------*/
3485 int32
HPgetdiskblock(filerec_t * file_rec,int32 block_size,intn moveto)3486 HPgetdiskblock(filerec_t * file_rec, int32 block_size, intn moveto)
3487 {
3488 CONSTR(FUNC, "HPgetdiskblock");
3489 uint8 temp;
3490 int32 ret_value = SUCCEED;
3491
3492 /* check for valid arguments */
3493 if (file_rec == NULL || block_size < 0)
3494 HGOTO_ERROR(DFE_ARGS, FAIL);
3495
3496
3497 #ifdef DISKBLOCK_DEBUG
3498 block_size+=(DISKBLOCK_HSIZE+DISKBLOCK_TSIZE);
3499 /* get the offset of the allocated block */
3500 ret_value = file_rec->f_end_off+DISKBLOCK_HSIZE;
3501 #else /* DISKBLOCK_DEBUG */
3502 /* get the offset of the allocated block */
3503 ret_value = file_rec->f_end_off;
3504 #endif /* DISKBLOCK_DEBUG */
3505
3506 /* reserve the space by marking the end of the element */
3507 if (block_size > 0)
3508 {
3509 #ifdef DISKBLOCK_DEBUG
3510 if (file_rec->cache)
3511 file_rec->dirty |= FILE_END_DIRTY;
3512 else
3513 {
3514 /* Write the debugging head & tail to the file block allocated */
3515 if (HPseek(file_rec, file_rec->f_end_off) == FAIL)
3516 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
3517 if (HP_write(file_rec, diskblock_header, DISKBLOCK_HSIZE) == FAIL)
3518 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
3519 if (HPseek(file_rec, file_rec->f_end_off+block_size-DISKBLOCK_TSIZE) == FAIL)
3520 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
3521 if (HP_write(file_rec, diskblock_tail, DISKBLOCK_TSIZE) == FAIL)
3522 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
3523 } /* end else */
3524 #else /* DISKBLOCK_DEBUG */
3525 if (file_rec->cache)
3526 file_rec->dirty |= FILE_END_DIRTY;
3527 else
3528 {
3529 if (HPseek(file_rec, ret_value + block_size - 1) == FAIL)
3530 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
3531 if (HP_write(file_rec, &temp, 1) == FAIL)
3532 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
3533 } /* end else */
3534 #endif /* DISKBLOCK_DEBUG */
3535 } /* end if */
3536 if (moveto == TRUE) /* move back to the beginning of the element */
3537 {
3538 if (HPseek(file_rec, ret_value) == FAIL)
3539 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
3540 } /* end if */
3541
3542 /* incr. offset of end of file */
3543 file_rec->f_end_off +=block_size;
3544
3545 done:
3546 if(ret_value == FAIL)
3547 { /* Error condition cleanup */
3548
3549 } /* end if */
3550
3551 /* Normal function cleanup */
3552
3553 return ret_value;
3554 } /* HPgetdiskblock() */
3555
3556 /*-----------------------------------------------------------------------
3557 NAME
3558 HPfreediskblock --- Release a block in a file to be re-used.
3559 USAGE
3560 intn HPfreediskblock(file_rec, block_off, block_size)
3561 filerec_t *file_rec; IN: ptr to the file record
3562 int32 block_off; IN: offset of the block to release
3563 int32 block_size; IN: size of the block to release
3564 RETURNS
3565 returns SUCCEED (0) if successful, FAIL (-1) if failed.
3566 DESCRIPTION
3567 Used to "release" space in the file. Currently, it does nothing.
3568 At some point in the future, this could be changed to add the block
3569 to a "real" free-list of empty blocks in the file and manage those.
3570
3571 -------------------------------------------------------------------------*/
3572 intn
HPfreediskblock(filerec_t * file_rec,int32 block_off,int32 block_size)3573 HPfreediskblock(filerec_t * file_rec, int32 block_off, int32 block_size)
3574 {
3575 #ifdef LATER
3576 CONSTR(FUNC, "HPfreediskblock");
3577 #endif
3578 intn ret_value = SUCCEED;
3579
3580 /* shut compiler up */
3581 file_rec = file_rec;
3582 block_off = block_off;
3583 block_size = block_size;
3584
3585 return ret_value;
3586 } /* HPfreediskblock() */
3587
3588 /*--------------------------------------------------------------------------
3589 NAME
3590 HDget_special_info -- get information about a special element
3591 USAGE
3592 intn HDget_special_info(access_id, info_block)
3593 int32 access_id; IN: id of READ access element
3594 sp_info_block_t * info_block;
3595 OUT: information about the special element
3596 RETURNS
3597 SUCCEED / FAIL
3598 DESCRIPTION
3599 Fill in the given info_block with information about the special
3600 element. Return FAIL if it is not a special element AND set
3601 the 'key' field to FAIL in info_block.
3602
3603 --------------------------------------------------------------------------*/
3604 int32
HDget_special_info(int32 access_id,sp_info_block_t * info_block)3605 HDget_special_info(int32 access_id, sp_info_block_t * info_block)
3606 {
3607 CONSTR(FUNC, "HDget_special_info");
3608 accrec_t *access_rec; /* access record */
3609 int32 ret_value = FAIL;
3610
3611 /* clear error stack and check validity of access id */
3612 HEclear();
3613 access_rec = HAatom_object(access_id);
3614 if (access_rec == (accrec_t *) NULL || info_block == NULL)
3615 HGOTO_ERROR(DFE_ARGS, FAIL);
3616
3617 /* special elt, so call special function */
3618 if (access_rec->special)
3619 ret_value = (*access_rec->special_func->info) (access_rec, info_block);
3620 else /* else is not special so FAIL */
3621 info_block->key = FAIL;
3622
3623 done:
3624 if(ret_value == FAIL)
3625 { /* Error condition cleanup */
3626
3627 } /* end if */
3628
3629 /* Normal function cleanup */
3630
3631 return ret_value;
3632 } /* HDget_special_info */
3633
3634 /*--------------------------------------------------------------------------
3635 NAME
3636 HDset_special_info -- reset information about a special element
3637 USAGE
3638 intn HDet_special_info(access_id, info_block)
3639 int32 access_id; IN: id of READ access element
3640 sp_info_block_t * info_block;
3641 IN: information about the special element
3642 RETURNS
3643 SUCCEED / FAIL
3644 DESCRIPTION
3645 Attempt to replace the special information for the given element
3646 with new information. This routine should be used to rename
3647 external elements for example. Doing things like changing the
3648 blocking of a linekd block element are beyond the scope of this
3649 routine.
3650
3651 --------------------------------------------------------------------------*/
3652 int32
HDset_special_info(int32 access_id,sp_info_block_t * info_block)3653 HDset_special_info(int32 access_id, sp_info_block_t * info_block)
3654 {
3655 CONSTR(FUNC, "HDset_special_info");
3656 accrec_t *access_rec; /* access record */
3657 int32 ret_value = FAIL;
3658
3659 /* clear error stack and check validity of access id */
3660 HEclear();
3661 access_rec = HAatom_object(access_id);
3662 if (access_rec == (accrec_t *) NULL || info_block == NULL)
3663 HGOTO_ERROR(DFE_ARGS, FAIL);
3664
3665 /* special elt, so call special function */
3666 if (access_rec->special)
3667 ret_value = (*access_rec->special_func->reset) (access_rec, info_block);
3668
3669 /* else is not special so fail */
3670 done:
3671 if(ret_value == FAIL)
3672 { /* Error condition cleanup */
3673
3674 } /* end if */
3675
3676 /* Normal function cleanup */
3677
3678 return ret_value;
3679 } /* HDset_special_info */
3680
3681 /*--------------------------------------------------------------------------
3682 NAME
3683 Hshutdown
3684 PURPOSE
3685 Terminate various static buffers.
3686 USAGE
3687 intn Hshutdown()
3688 RETURNS
3689 Returns SUCCEED/FAIL
3690 DESCRIPTION
3691 Free various buffers allocated in the H routines.
3692 GLOBAL VARIABLES
3693 COMMENTS, BUGS, ASSUMPTIONS
3694 Should only ever be called by the "atexit" function HDFend
3695 EXAMPLES
3696 REVISION LOG
3697 --------------------------------------------------------------------------*/
3698 intn
Hshutdown(void)3699 Hshutdown(void)
3700 {
3701 accrec_t *curr;
3702
3703 /* Release the free-list if it exists */
3704 if(accrec_free_list != NULL)
3705 {
3706 while(accrec_free_list != NULL
3707 && accrec_free_list != accrec_free_list->next)
3708 {
3709 curr = accrec_free_list;
3710 accrec_free_list = accrec_free_list->next;
3711 curr->next = NULL;
3712 HDfree(curr);
3713 } /* end while */
3714 } /* end if */
3715
3716 return (SUCCEED);
3717 } /* end Hshutdown() */
3718
3719 /* #define HFILE_SEEKINFO */
3720 #ifdef HFILE_SEEKINFO
3721 static uint32 seek_taken=0;
3722 static uint32 seek_avoided=0;
3723 static uint32 write_force_seek=0;
3724 static uint32 read_force_seek=0;
3725
3726 void
Hdumpseek(void)3727 Hdumpseek(void)
3728 {
3729 printf("Seeks taken=%lu\n",(unsigned long)seek_taken);
3730 printf("Seeks avoided=%lu\n",(unsigned long)seek_avoided);
3731 printf("# of times write forced a seek=%lu\n",(unsigned long)write_force_seek);
3732 printf("# of times read forced a seek=%lu\n",(unsigned long)read_force_seek);
3733 } /* Hdumpseek() */
3734 #endif /* HFILE_SEEKINFO */
3735
3736 /*--------------------------------------------------------------------------
3737 NAME
3738 HP_read
3739 PURPOSE
3740 Alias for HI_READ on HDF files.
3741 USAGE
3742 intn HP_read(file_rec,buf,bytes)
3743 filerec_t * file_rec; IN: Pointer to the HDF file record
3744 void * buf; IN: Pointer to the buffer to read data into
3745 int32 bytes; IN: # of bytes to read
3746 RETURNS
3747 Returns SUCCEED/FAIL
3748 DESCRIPTION
3749 Function to wrap around HI_READ
3750 GLOBAL VARIABLES
3751 COMMENTS, BUGS, ASSUMPTIONS
3752 Should only be called by HDF low-level routines
3753 EXAMPLES
3754 REVISION LOG
3755 --------------------------------------------------------------------------*/
3756 intn
HP_read(filerec_t * file_rec,void * buf,int32 bytes)3757 HP_read(filerec_t *file_rec,void * buf,int32 bytes)
3758 {
3759 CONSTR(FUNC, "HP_read");
3760 intn ret_value = SUCCEED;
3761
3762 /* Check for switching file access operations */
3763 if(file_rec->last_op==H4_OP_WRITE || file_rec->last_op==H4_OP_UNKNOWN)
3764 {
3765 #ifdef HFILE_SEEKINFO
3766 read_force_seek++;
3767 #endif /* HFILE_SEEKINFO */
3768 file_rec->last_op=H4_OP_UNKNOWN;
3769 if(HPseek(file_rec,file_rec->f_cur_off)==FAIL)
3770 HGOTO_ERROR(DFE_INTERNAL,FAIL);
3771 } /* end if */
3772
3773 if(HI_READ(file_rec->file,buf,bytes)==FAIL)
3774 HGOTO_ERROR(DFE_READERROR, FAIL);
3775 file_rec->f_cur_off+=bytes;
3776 file_rec->last_op=H4_OP_READ;
3777 done:
3778 if(ret_value == FAIL)
3779 { /* Error condition cleanup */
3780
3781 } /* end if */
3782
3783 /* Normal function cleanup */
3784
3785 return ret_value;
3786 } /* end HP_read() */
3787
3788 /*--------------------------------------------------------------------------
3789 NAME
3790 HPseek
3791 PURPOSE
3792 Alias for HI_SEEK on HDF files.
3793 USAGE
3794 intn HPseek(file_rec,offset)
3795 filerec_t * file_rec; IN: Pointer to the HDF file record
3796 int32 offset; IN: offset in the file to go to
3797 RETURNS
3798 Returns SUCCEED/FAIL
3799 DESCRIPTION
3800 Function to wrap around HI_SEEK
3801 GLOBAL VARIABLES
3802 COMMENTS, BUGS, ASSUMPTIONS
3803 Should only be called by HDF low-level routines
3804 EXAMPLES
3805 REVISION LOG
3806 --------------------------------------------------------------------------*/
3807 intn
HPseek(filerec_t * file_rec,int32 offset)3808 HPseek(filerec_t *file_rec,int32 offset)
3809 {
3810 CONSTR(FUNC, "HPseek");
3811 intn ret_value = SUCCEED;
3812
3813 #ifdef HFILE_SEEKINFO
3814 printf("%s: file_rec=%p, last_offset=%ld, offset=%ld, last_op=%d",FUNC,file_rec,(long)file_rec->f_cur_off,(long)offset,(int)file_rec->last_op);
3815 #endif /* HFILE_SEEKINFO */
3816 if(file_rec->f_cur_off!=offset || file_rec->last_op==H4_OP_UNKNOWN)
3817 {
3818 #ifdef HFILE_SEEKINFO
3819 seek_taken++;
3820 printf(" taken: %d\n",(int)seek_taken);
3821 #endif /* HFILE_SEEKINFO */
3822 if (HI_SEEK(file_rec->file, offset) == FAIL)
3823 HGOTO_ERROR(DFE_SEEKERROR, FAIL);
3824 file_rec->f_cur_off=offset;
3825 file_rec->last_op=H4_OP_SEEK;
3826 } /* end if */
3827 #ifdef HFILE_SEEKINFO
3828 else
3829 {
3830 seek_avoided++;
3831 printf(" avoided: %d\n",(int)seek_avoided);
3832 }
3833 #endif /* HFILE_SEEKINFO */
3834
3835 done:
3836 if(ret_value == FAIL)
3837 { /* Error condition cleanup */
3838
3839 } /* end if */
3840
3841 /* Normal function cleanup */
3842
3843 return ret_value;
3844 } /* end HPseek() */
3845
3846 /*--------------------------------------------------------------------------
3847 NAME
3848 HP_write
3849 PURPOSE
3850 Alias for HI_WRITE on HDF files.
3851 USAGE
3852 intn HP_write(file_rec,buf,bytes)
3853 filerec_t * file_rec; IN: Pointer to the HDF file record
3854 void * buf; IN: Pointer to the buffer to write
3855 int32 bytes; IN: # of bytes to write
3856 RETURNS
3857 Returns SUCCEED/FAIL
3858 DESCRIPTION
3859 Function to wrap around HI_WRITE
3860 GLOBAL VARIABLES
3861 COMMENTS, BUGS, ASSUMPTIONS
3862 Should only be called by HDF low-level routines
3863 EXAMPLES
3864 REVISION LOG
3865 --------------------------------------------------------------------------*/
3866 intn
HP_write(filerec_t * file_rec,const void * buf,int32 bytes)3867 HP_write(filerec_t *file_rec,const void * buf,int32 bytes)
3868 {
3869 CONSTR(FUNC, "HP_write");
3870 intn ret_value = SUCCEED;
3871
3872 /* Check for switching file access operations */
3873 if(file_rec->last_op==H4_OP_READ || file_rec->last_op==H4_OP_UNKNOWN)
3874 {
3875 #ifdef HFILE_SEEKINFO
3876 write_force_seek++;
3877 #endif /* HFILE_SEEKINFO */
3878 file_rec->last_op=H4_OP_UNKNOWN;
3879 if(HPseek(file_rec,file_rec->f_cur_off)==FAIL)
3880 HGOTO_ERROR(DFE_INTERNAL,FAIL);
3881 } /* end if */
3882
3883 if(HI_WRITE(file_rec->file,buf,bytes)==FAIL)
3884 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
3885 file_rec->f_cur_off+=bytes;
3886 file_rec->last_op=H4_OP_WRITE;
3887
3888 done:
3889 if(ret_value == FAIL)
3890 { /* Error condition cleanup */
3891
3892 } /* end if */
3893
3894 /* Normal function cleanup */
3895
3896 return ret_value;
3897 } /* end HP_write() */
3898
3899
3900 /*--------------------------------------------------------------------------
3901 NAME
3902 HDread_drec -- reads a description record
3903 USAGE
3904 int32 HDread_drec(file_id, data_id, drec_buf)
3905 int32 file_id; IN: id of file
3906 atom_t data_id; IN: id of an element
3907 uint8** drec_buf OUT: buffer containing special info header
3908 RETURNS
3909 Returns the length of the info read
3910 DESCRIPTION
3911 This private function contains code that was repeated in several places
3912 throughout the library. It gets access to the element's description
3913 record and read the special info header.
3914 GLOBAL VARIABLES
3915 COMMENTS, BUGS, ASSUMPTIONS
3916 EXAMPLES
3917 REVISION LOG
3918 03-20-2010 BMR: Factored out repeated code
3919 --------------------------------------------------------------------------*/
3920 int32
HPread_drec(int32 file_id,atom_t data_id,uint8 ** drec_buf)3921 HPread_drec(int32 file_id, atom_t data_id, uint8** drec_buf)
3922 {
3923 CONSTR(FUNC, "HDread_drec"); /* for HERROR */
3924 int32 drec_len=0; /* length of the description record */
3925 int32 drec_aid=-1; /* description record access id */
3926 uint16 drec_tag, drec_ref; /* description record tag/ref */
3927 int32 ret_value=0;
3928
3929 /* get the info for the dataset (description record) */
3930 if (HTPinquire(data_id,&drec_tag,&drec_ref,NULL,&drec_len) == FAIL)
3931 HGOTO_ERROR(DFE_INTERNAL, FAIL);
3932
3933 if ((*drec_buf = (uint8 *)HDmalloc(drec_len)) == NULL)
3934 HGOTO_ERROR(DFE_NOSPACE, FAIL);
3935
3936 /* get the special info header */
3937 drec_aid = Hstartaccess(file_id,MKSPECIALTAG(drec_tag),drec_ref,DFACC_READ);
3938 if (drec_aid == FAIL)
3939 HGOTO_ERROR(DFE_BADAID, FAIL);
3940 if (Hread(drec_aid,0,*drec_buf) == FAIL)
3941 HGOTO_ERROR(DFE_READERROR, FAIL);
3942 if(Hendaccess(drec_aid)==FAIL)
3943 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
3944
3945 ret_value = drec_len;
3946
3947 done:
3948 if(ret_value == FAIL)
3949 { /* Error condition cleanup */
3950
3951 } /* end if */
3952
3953 /* Normal function cleanup */
3954 return ret_value;
3955 } /* HPread_drec */
3956
3957 /*--------------------------------------------------------------------------
3958 NAME
3959 HDcheck_empty -- determines if an element has been written with data
3960 USAGE
3961 int32 HDcheck_empty(file_id, tag, ref, *emptySDS)
3962 int32 file_id; IN: id of file
3963 uint16 tag; IN: tag of data element
3964 uint16 ref; IN: ref of data element
3965 intn *emptySDS; OUT: TRUE if data element is empty
3966 RETURNS
3967 Returns SUCCEED/FAIL
3968 DESCRIPTION
3969 If the data element is special, gets the compressed or chunked description
3970 record and retrieves the special tag. If the special tag indicates that
3971 the data element is compressed, then this function will retrieve the data
3972 length. If the special tag indicates the data element is chunked, then
3973 retrieve the vdata chunk table to get its number of records.
3974
3975 Uses the data length or number of records to determine the value for
3976 'emptySDS'.
3977 GLOBAL VARIABLES
3978 COMMENTS, BUGS, ASSUMPTIONS
3979 EXAMPLES
3980 REVISION LOG
3981 10-30-2004 BMR: This function was added for SDcheckempty
3982 08-28-2007 BMR: The old code of this function failed when szip library
3983 didn't present (bugzilla 842.) Modified to read info directly
3984 from file.
3985 --------------------------------------------------------------------------*/
3986 int32
HDcheck_empty(int32 file_id,uint16 tag,uint16 ref,intn * emptySDS)3987 HDcheck_empty(int32 file_id, uint16 tag, uint16 ref,
3988 intn *emptySDS /* TRUE if data element is empty */)
3989 {
3990 CONSTR(FUNC, "HDcheck_empty"); /* for HERROR */
3991 int32 length; /* length of the element's data */
3992 atom_t data_id = FAIL; /* dd ID of existing regular element */
3993 filerec_t *file_rec; /* file record pointer */
3994 uint8 *local_ptbuf=NULL, *p;
3995 int16 sptag = -1; /* special tag read from desc record */
3996 int32 ret_value = SUCCEED;
3997
3998 /* clear error stack */
3999 HEclear();
4000
4001 /* convert file id to file rec and check for validity */
4002 file_rec = HAatom_object(file_id);
4003 if (BADFREC(file_rec))
4004 HGOTO_ERROR(DFE_ARGS, FAIL);
4005
4006 /* get access element from dataset's tag/ref */
4007 if ((data_id=HTPselect(file_rec,tag,ref))!=FAIL)
4008 {
4009 int32 dlen=0, doff=0; /* offset/length of the description record */
4010
4011 /* Get the info pointed to by this dd, which could point to data or
4012 description record, or neither */
4013 if (HTPinquire(data_id, NULL, NULL, &doff, &dlen) == FAIL)
4014 HGOTO_ERROR(DFE_INTERNAL, FAIL);
4015
4016 /* doff/dlen = -1 means no data had been written */
4017 if (doff == INVALID_OFFSET && dlen == INVALID_LENGTH)
4018 {
4019 *emptySDS = TRUE;
4020 }
4021
4022 /* if the element is not special, that means dataset's tag/ref
4023 specifies the actual data that was written to the dataset, so
4024 we don't need to check further */
4025 else if (HTPis_special(data_id)==FALSE)
4026 {
4027 *emptySDS = FALSE;
4028 }
4029 else
4030 {
4031 int32 rec_len=0;
4032
4033 /* Get the compression header (description record) */
4034 rec_len = HPread_drec(file_id, data_id, &local_ptbuf);
4035 if (rec_len <= 0)
4036 HGOTO_ERROR(DFE_INTERNAL, FAIL);
4037
4038 /* get special tag */
4039 p = local_ptbuf;
4040 INT16DECODE(p, sptag);
4041
4042 /* if it is a compressed element, get the data length and set
4043 flag emptySDS appropriately */
4044 if (sptag == SPECIAL_COMP)
4045 {
4046 /* skip 2byte header_version */
4047 p = p + 2;
4048 INT32DECODE(p, length); /* get _uncompressed_ data length */
4049
4050 /* set flag specifying whether the dataset is empty */
4051 *emptySDS = length == 0 ? TRUE : FALSE;
4052 }
4053
4054 /* if it is a chunked element, get the number of records in
4055 the chunk table (vdata) to determine emptySDS value */
4056 else if (sptag == SPECIAL_CHUNKED)
4057 {
4058 uint16 chk_tbl_tag, chk_tbl_ref; /* chunk table tag/ref */
4059 int32 vdata_id = -1; /* chunk table id */
4060 int32 n_records = 0; /* number of records in chunk table */
4061
4062 /* skip 4byte header len, 1byte chunking version, 4byte flag, */
4063 /* 4byte elm_tot_length, 4byte chunk_size and 4byte nt_size */
4064 p = p + 4 + 1 + 4 + 4 + 4 + 4;
4065 UINT16DECODE(p, chk_tbl_tag);
4066 UINT16DECODE(p, chk_tbl_ref);
4067
4068 /* make sure it is really the vdata */
4069 if (chk_tbl_tag == DFTAG_VH)
4070 {
4071 /* attach to the chunk table vdata and get its num of records */
4072 if ((vdata_id = VSattach(file_id,chk_tbl_ref,"r")) == FAIL)
4073 HGOTO_ERROR(DFE_CANTATTACH, FAIL);
4074
4075 if (VSinquire(vdata_id, &n_records,NULL,NULL,NULL,NULL) == FAIL)
4076 HGOTO_ERROR(DFE_INTERNAL, FAIL);
4077 if (VSdetach(vdata_id) == FAIL)
4078 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
4079
4080 /* set flag specifying whether the dataset is empty */
4081 *emptySDS = n_records == 0 ? TRUE : FALSE;
4082 } /* it is a vdata */
4083 else
4084 HGOTO_ERROR(DFE_INTERNAL, FAIL);
4085 }
4086 /* need to check about other special cases - BMR 08/28/2007 */
4087 } /* else, data_id is special */
4088
4089 /* end access to the aid */
4090 if (HTPendaccess(data_id) == FAIL)
4091 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
4092 } /* end if data_id != FAIL */
4093 else
4094 {
4095 HGOTO_ERROR(DFE_CANTACCESS, FAIL);
4096 }
4097
4098 done:
4099 if(ret_value == FAIL)
4100 { /* Error condition cleanup */
4101
4102 } /* end if */
4103
4104 /* Normal function cleanup */
4105 if (local_ptbuf != NULL)
4106 HDfree(local_ptbuf);
4107
4108 return ret_value;
4109 } /* end HDcheck_empty() */
4110
4111
4112 /*--------------------------------------------------------------------------
4113 NAME
4114 Hgetspecinfo
4115 PURPOSE
4116 Returns the special type if the given element is special.
4117 USAGE
4118 intn Hgetspecinfo(file_id, tag, ref)
4119 int32 file_id; IN: file id
4120 uint16 tag; IN: tag of the element
4121 uint16 ref; IN: ref of the element
4122 RETURNS
4123 Special type:
4124 SPECIAL_LINKED
4125 SPECIAL_EXT
4126 SPECIAL_COMP
4127 SPECIAL_VLINKED
4128 SPECIAL_CHUNKED
4129 SPECIAL_BUFFERED
4130 SPECIAL_COMPRAS
4131 or 0 if the element is not special element.
4132 DESCRIPTION
4133 Called internally by the GRIget_image_list to allow a chunked or
4134 linked-block element to proceed eventhough its offset is 0.
4135 GLOBAL VARIABLES
4136 COMMENTS, BUGS, ASSUMPTIONS
4137
4138 *** Only called by library routines, should _not_ be called externally ***
4139
4140 EXAMPLES
4141 REVISION LOG
4142 --------------------------------------------------------------------------*/
4143 intn
Hgetspecinfo(int32 file_id,uint16 tag,uint16 ref,sp_info_block_t * info)4144 Hgetspecinfo(int32 file_id, uint16 tag, uint16 ref, sp_info_block_t *info)
4145 {
4146 CONSTR(FUNC, "Hgetspecinfo");
4147 accrec_t* access_rec=NULL;/* access element record */
4148 int32 aid;
4149 intn status=0, ret_value=0;
4150
4151 /* Clear error stack */
4152 HEclear();
4153
4154 /* Start read access on the access record of the data element, which
4155 is being inquired for its special information */
4156 aid = Hstartread(file_id, tag, ref);
4157
4158 /* Get the access_rec pointer */
4159 access_rec = HAatom_object(aid);
4160 if (access_rec == NULL) HGOTO_ERROR(DFE_ARGS, FAIL);
4161
4162 /* Only return the valid special code, anything else return 0 */
4163 ret_value = access_rec->special;
4164 switch (access_rec->special)
4165 {
4166 case SPECIAL_LINKED:
4167 case SPECIAL_EXT:
4168 case SPECIAL_COMP:
4169 case SPECIAL_CHUNKED:
4170 case SPECIAL_BUFFERED:
4171 case SPECIAL_COMPRAS:
4172 /* special elt, call special function */
4173 status = (*access_rec->special_func->info) (access_rec, info);
4174 /* return FAIL if special function fails eventhough special type
4175 was OK */
4176 if (status == FAIL) ret_value = FAIL;
4177 break;
4178 #ifdef LATER
4179 case SPECIAL_VLINKED:
4180 break;
4181 #endif /* LATER */
4182 default:
4183 ret_value = 0;
4184 } /* switch */
4185
4186 /* End access to the aid */
4187 if (Hendaccess(aid) == FAIL)
4188 HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
4189 done:
4190 if(ret_value == FAIL)
4191 { /* Error condition cleanup */
4192 /* End access to the aid if it's been accessed */
4193 if (aid != 0)
4194 if (Hendaccess(aid)== FAIL)
4195 HERROR(DFE_CANTENDACCESS);
4196 } /* end if */
4197
4198 /* Normal function cleanup */
4199 return ret_value;
4200 } /* Hgetspecinfo */
4201
4202
4203 /* ------------------------------- Hgetntinfo ------------------------------ */
4204 /*
4205 NAME
4206 Hgetntinfo -- retrieves some information of a number type in text format
4207 USAGE
4208 intn Hgetntinfo(numbertype, nt_info)
4209 int32 numbertype; IN: HDF-supported number type
4210 hdf_ntinfo_t *nt_info; OUT: structure containing number type's info
4211 RETURNS
4212 FAIL if there is no match for the number type, otherwise, SUCCEED.
4213 DESCRIPTION
4214 Load the structure hdf_ntinfo_t with the number type's name and byte
4215 order in array of characters format. When the "default:" is reached,
4216 it means that a supported number type is missing from the switch statement
4217 or an unrecognized value is encountered. The type will be verified and
4218 added or appropriate error handling will be added. The structure
4219 hdf_ntinfo_t is defined in hdf.h.
4220
4221 Design note: Passing the struct hdf_ntinfo_t into this function instead
4222 of individual strings will allow expandability without changing the
4223 function's prototype in the event of more information is desired.
4224 -BMR (Sep 2010)
4225
4226 ---------------------------------------------------------------------------*/
4227 intn
Hgetntinfo(const int32 numbertype,hdf_ntinfo_t * nt_info)4228 Hgetntinfo(const int32 numbertype, hdf_ntinfo_t *nt_info)
4229 {
4230 /* Clear error stack */
4231 HEclear();
4232
4233 /* Get byte order string */
4234 if ((DFNT_LITEND & numbertype) > 0)
4235 {
4236 HDstrcpy(nt_info->byte_order, "littleEndian");
4237 }
4238 else
4239 HDstrcpy(nt_info->byte_order, "bigEndian");
4240
4241 /* Get type name string; must mask native and little-endian to make
4242 sure we get standard type */
4243 switch((numbertype & ~DFNT_NATIVE) & ~DFNT_LITEND)
4244 {
4245 case DFNT_UCHAR8:
4246 HDstrcpy(nt_info->type_name, "uchar8");
4247 break;
4248 case DFNT_CHAR8:
4249 HDstrcpy(nt_info->type_name, "char8");
4250 break;
4251 case DFNT_FLOAT32:
4252 HDstrcpy(nt_info->type_name, "float32");
4253 break;
4254 case DFNT_FLOAT64:
4255 HDstrcpy(nt_info->type_name, "float64");
4256 break;
4257 case DFNT_FLOAT128:
4258 HDstrcpy(nt_info->type_name, "float128");
4259 break;
4260 case DFNT_INT8:
4261 HDstrcpy(nt_info->type_name, "int8");
4262 break;
4263 case DFNT_UINT8:
4264 HDstrcpy(nt_info->type_name, "uint8");
4265 break;
4266 case DFNT_INT16:
4267 HDstrcpy(nt_info->type_name, "int16");
4268 break;
4269 case DFNT_UINT16:
4270 HDstrcpy(nt_info->type_name, "uint16");
4271 break;
4272 case DFNT_INT32:
4273 HDstrcpy(nt_info->type_name, "int32");
4274 break;
4275 case DFNT_UINT32:
4276 HDstrcpy(nt_info->type_name, "uint32");
4277 break;
4278 case DFNT_INT64:
4279 HDstrcpy(nt_info->type_name, "int64");
4280 break;
4281 case DFNT_UINT64:
4282 HDstrcpy(nt_info->type_name, "uint64");
4283 break;
4284 case DFNT_INT128:
4285 HDstrcpy(nt_info->type_name, "int128");
4286 break;
4287 case DFNT_UINT128:
4288 HDstrcpy(nt_info->type_name, "uint128");
4289 break;
4290 case DFNT_CHAR16:
4291 HDstrcpy(nt_info->type_name, "char16");
4292 break;
4293 case DFNT_UCHAR16:
4294 HDstrcpy(nt_info->type_name, "uchar16");
4295 break;
4296 default:
4297 return FAIL;
4298 } /* end switch */
4299 return SUCCEED;
4300 } /* Hgetntinfo */
4301
4302
4303 #ifdef HAVE_FMPOOL
4304 /******************************************************************************
4305 NAME
4306 Hmpset - set pagesize and maximum number of pages to cache on next open/create
4307
4308 DESCRIPTION
4309 Set the pagesize and maximum number of pages to cache on the next
4310 open/create of a file. A pagesize that is a power of 2 is recommended.
4311
4312 The values set here only affect the next open/creation of a file and
4313 do not change a particular file's paging behaviour after it has been
4314 opened or created. This maybe changed in a later release.
4315
4316 Use flags arguement of 'MP_PAGEALL' if the whole file is to be cached
4317 in memory otherwise passs in zero.
4318
4319 RETURNS
4320 Returns SUCCEED if successful and FAIL otherwise
4321
4322 NOTE
4323 This calls the real routine MPset().
4324 Currently 'maxcache' has to be greater than 1. Maybe use special
4325 case of 0 to specify you want to turn page buffering off or use
4326 the flags arguement.
4327
4328 ******************************************************************************/
4329 int
Hmpset(int pagesize,int maxcache,int flags)4330 Hmpset(int pagesize, /* IN: pagesize to use for next open/create */
4331 int maxcache, /* IN: max number of pages to cache */
4332 int flags /* IN: flags = 0, MP_PAGEALL */
4333 )
4334 {
4335 int ret_value = SUCCEED;
4336
4337 /* call the real routine */
4338 ret_value = MPset(pagesize,maxcache,flags);
4339
4340 done:
4341 if(ret_value == FAIL)
4342 { /* Error condition cleanup */
4343
4344 } /* end if */
4345
4346 /* Normal function cleanup */
4347
4348 return ret_value;
4349 }
4350
4351 /******************************************************************************
4352 NAME
4353 Hmpget - get last pagesize and max number of pages cached for open/create
4354
4355 DESCRIPTION
4356 This gets the last pagesize and maximum number of pages cached for
4357 the last open/create of a file.
4358
4359 RETURNS
4360 Returns SUCCEED.
4361
4362 NOTES
4363 This routine calls the real routine MPget().
4364 ******************************************************************************/
4365 int
Hmpget(int * pagesize,int * maxcache,int flags)4366 Hmpget(int *pagesize, /* OUT: pagesize to used in last open/create */
4367 int *maxcache, /* OUT: max number of pages cached in last open/create */
4368 int flags /* IN: */
4369 )
4370 {
4371 int psize = 0;
4372 int mcache = 0;
4373 int ret_value = SUCCEED;
4374
4375 /* call the real routine */
4376 ret_value = MPget(&psize,&mcache,flags);
4377 *pagesize = psize;
4378 *maxcache = mcache;
4379
4380 done:
4381 if(ret_value == FAIL)
4382 { /* Error condition cleanup */
4383
4384 } /* end if */
4385
4386 /* Normal function cleanup */
4387
4388 return ret_value;
4389 } /* Hmpget() */
4390
4391 #endif /* HAVE_FMPOOL */
4392