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