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 /* ------------------------------ hblocks.c -------------------------------
18    routines to implement linked-block elements
19 
20    Linked element in HDF files created in two ways
21    -- created from the start or
22    -- converted from a normal data element
23 
24    A linked-block element is a special element.
25 
26    Special elements are
27    flagged with a set high-bit in their tag.  Thus, a tag t has
28    BASETAG == t & 0x7f and is a special tag if t & 0x80 != 0x00
29 
30    The first 16 bits of the meta-element that this tag/ref points to
31    tells us what type of special element this is.  If these 16 bits is
32    SPECIAL_LINKED, then it contains information about the linked blocks.
33    After this 16 bits, 32 bit which is the length of each block, after
34    which is the information header:
35 
36    ----------------------------------------------------------------------
37    | # blocks in | tag/ref of | tag/ref of blocks list .......          |
38    | this header | next header|                                         |
39    ----------------------------------------------------------------------
40 
41    File Description of Linked Block Element
42    ****************************************
43    DD for Linked Block pointing to Linked Block Description Record
44    ==============================================================
45    <-  2 bytes -> <- 2 bytes -> <- 4 bytes -> <- 4bytes ->
46    --------------------------------------------------------
47    |extended tag | reference # |  Offset     |  Length    |
48    --------------------------------------------------------
49                                     \______________/
50    __________________________________________|
51    V
52    LINKED BLOCK DESCRIPTION RECORD(LBDR - 16 bytes)
53    ===============================================
54    <-  2 bytes -> <- 4 bytes  -> <- 4 bytes -> <- 4 bytes -> <- 2 bytes ->
55    ---------------------------------------------- ------------------------
56    |ext_tag_desc | elem_tot_len | blk_length  |   num_blk   | link_ref   |
57    ---------------------------------------------- ------------------------
58 
59 
60    ext_tag_desc   - SPECIAL_LINKED(16 bit constant), identifies this as
61                     a linked block description record
62    elem_tot_len   - Length of the entire element(32 bit field)
63    blk_length     - Length of successive data blocks(32 bit field) after first block,
64 			first block is calculated.
65    num_blk        - Number of blocks per block table(32 bit field)
66    link_ref       - Reference number of the first block table(16 bit field)
67 
68    Linked Block Table(12 + 2 + 2 + 2 + 2 + ... bytes)
69    ===================================================
70    <-  2 bytes -> <- 2 bytes -> <- 4 bytes -> <- 4bytes ->
71    --------------------------------------------------------
72    |link_blk_tag | link_ref    |  Offset     |  Length    |
73    --------------------------------------------------------
74                                     \______________/
75    __________________________________________|
76    V
77    <-  2 bytes -> <- 2 bytes -> <- 2 bytes -> <- 2 bytes -> <-...
78    -----------------------------------------------------------...
79    | next_ref    | block_ref_1 | block_ref_2 | block_ref_3 |  ...
80    -----------------------------------------------------------...
81 
82    link_blk_tag   - DFTAG_LINKED(16 bit)
83    link_ref       - Reference number for this table(16 bit)
84    next_ref       - Reference number for next block table(16 bit)
85                     Zero(0) signifies no more block tables for this element.
86    blk_ref_x      - Reference number for data block X (16 bit).
87                   e.g. for data block 1
88                   <-  2 bytes ->  <- 2 bytes -> <- 4 bytes -> <- 4bytes ->
89                   --------------------------------------------------------
90                   | DFTAG_LINKED | block_ref_1 |  Offset     |  Length    |
91                   --------------------------------------------------------
92                                                     \______________/
93                   __________________________________________|
94                   V
95                   -----------------------
96                   | Data_block          |
97                   -----------------------
98                   Note: The "Length" here is specified by either
99                         "elem_first_len" or "blk_length".
100 
101    For now, HLcreate() has the best description of what the on-disk
102    representation of a linked block element looks like.
103 
104 EXPORTED ROUTINES
105 
106    HLcreate       -- create a linked block element
107    HLconvert      -- convert an AID into a linked block element
108    HLgetdatainfo  -- get data information of linked blocks
109    HDinqblockinfo -- return info about linked blocks
110    HLPstread      -- open an access record for reading
111    HLPstwrite     -- open an access record for writing
112    HLPseek        -- set the seek posn
113    HLPread        -- read some data out of a linked block element
114    HLPwrite       -- write out some data to a linked block
115    HLPinquire     -- Hinquire for linked blocks
116    HLPendacess    -- close a linked block AID
117    HLPinfo        -- return info about a linked block element
118 LOCAL ROUTINES
119    HLIstaccess -- set up AID to access a linked block elem
120    HLIgetlink  -- get link information
121    HLInewlink  -- write out some data to a linked block
122 */
123 
124 #include "hdf.h"
125 #include "hfile.h"
126 
127 /* block_t - record of a linked block. contains the tag and ref of the
128    data elt that forms the linked block */
129 typedef struct block_t
130 {
131     uint16      ref;          /* ref of the linked block */
132 }
133 block_t;
134 
135 /* link_t - a linked list block table.
136    Very similar to the dd block structure */
137 typedef struct link_t
138 {
139     uint16          nextref;   /* ref of the next block table */
140     struct link_t  *next;      /* ptr to the next block table */
141     struct block_t *block_list;/* ptr to the block list for this table */
142 }
143 link_t;
144 
145 /* information on this special linked block data elt */
146 typedef struct linkinfo_t
147 {
148     int      attached;     /* how many access records refer to this elt */
149     int32    length;       /* the actual length of the data elt */
150     int32    first_length; /* length of first block */
151     int32    block_length; /* the length of the remaining blocks */
152     int32    number_blocks;/* total number of blocks in each link/block table */
153     uint16   link_ref;     /* ref of the first block table structure */
154     link_t  *link;         /* pointer to the first block table */
155     link_t  *last_link;    /* pointer to the last block table */
156 }
157 linkinfo_t;
158 
159 /* private functions */
160 PRIVATE int32 HLIstaccess(accrec_t *access_rec,
161                           int16     acc_mode);
162 
163 PRIVATE link_t *HLInewlink(int32  file_id,
164                            int32  number_blocks,
165                            uint16 link_ref,
166                            uint16 first_block_ref);
167 
168 PRIVATE link_t *HLIgetlink(int32  file_id,
169                            uint16 ref,
170                            int32  number_blocks);
171 
172 /* the accessing function table for linked blocks */
173 funclist_t  linked_funcs =
174 {
175     HLPstread,
176     HLPstwrite,
177     HLPseek,
178     HLPinquire,
179     HLPread,
180     HLPwrite,
181     HLPendaccess,
182     HLPinfo,
183     NULL         /* no routine registered */
184 };
185 
186 /* ------------------------------------------------------------------------
187 NAME
188    HLcreate -- create a linked block element
189 USAGE
190    int32 HLcreate(fid, tag, ref, blocklen, numblocks)
191    int32   fid;         IN: file to put linked block element in
192    uint16  tag;         IN: tag of element
193    uint16  ref;         IN: ref of element
194    int32   blocklen;    IN: length of standard block
195    int32   numblocks;   IN: number of blocks per block list
196 RETURNS
197    The AID of newly created linked block element, FAIL on error.
198 DESCRIPTION
199    This routine takes an HDF element and promotes it into a linked
200    block element.  Basically, the element becomes a linked list
201    allowing easy appending.  If the element already exists, it
202    is promoted to being a linked block element, otherwise a new
203    element is created.
204 
205    All of the pieces of the linked list are the same size (blocklen)
206    except for the first one which stays the size of the element
207    at the time HLcreate was called.
208 
209    numblocks gives the number of linked list objects in each
210    block header.
211 
212    The ideal setting for numblocks and blocklen are very data
213    and application depedent.
214 
215  --------------------------------------------------------------------------- */
216 int32
HLcreate(int32 file_id,uint16 tag,uint16 ref,int32 block_length,int32 number_blocks)217 HLcreate(int32  file_id,
218          uint16 tag,
219          uint16 ref,
220          int32  block_length,
221          int32  number_blocks)
222 {
223     CONSTR(FUNC, "HLcreate");   /* for HERROR */
224     filerec_t  *file_rec;       /* file record */
225     accrec_t   *access_rec=NULL;/* access record */
226     int32       dd_aid;         /* AID for writing the special info */
227     linkinfo_t *info = NULL;   /* information for the linked blocks elt */
228     uint16      link_ref;       /* the ref of the link structure
229                                    (block table) */
230     atom_t      data_id;        /* dd ID of existing regular element */
231     uint16      new_data_tag, new_data_ref=0;  /* Tag/ref of the new data in the file */
232     int32       data_len;		/* length of the data we are checking */
233     int32       data_off;		/* offset of the data we are checking */
234     uint16      special_tag;    /* special version of this tag */
235     uint8       local_ptbuf[16];
236     int32       ret_value = SUCCEED;
237 
238     /* clear error stack and validate file record id */
239     HEclear();
240     file_rec = HAatom_object(file_id);
241 
242     /* check args and create special tag */
243     if (BADFREC(file_rec) || block_length < 0 || number_blocks < 0
244         || SPECIALTAG(tag)
245         || (special_tag = MKSPECIALTAG(tag)) == DFTAG_NULL)
246         HGOTO_ERROR(DFE_ARGS, FAIL);
247 
248     /* make sure write access to file */
249     if (!(file_rec->access & DFACC_WRITE))
250         HGOTO_ERROR(DFE_DENIED, FAIL);
251 
252     /* get empty access record */
253     access_rec = HIget_access_rec();
254     if (access_rec == NULL)
255         HGOTO_ERROR(DFE_TOOMANY, FAIL);
256 
257     /* search for identical dd */
258     if ((data_id = HTPselect(file_rec,tag,ref))!=FAIL)
259       {
260           /* Check if the element is already special */
261           if (HTPis_special(data_id)==TRUE)
262             {
263                 HTPendaccess(data_id);
264                 HGOTO_ERROR(DFE_CANTMOD, FAIL);
265             }   /* end if */
266 
267           /* If the data already was in the file,
268            * convert it into the first linked block
269            * get the info for the dataset */
270           if(HTPinquire(data_id,NULL,NULL,&data_off,&data_len)==FAIL)
271             {
272                 HTPendaccess(data_id);
273                 HGOTO_ERROR(DFE_INTERNAL, FAIL);
274             } /* end if */
275 
276           if(data_off == INVALID_OFFSET || data_len==INVALID_LENGTH)
277             { /* data object which has been created, but has no data */
278               /* Delete the old data ID */
279               if(HTPdelete(data_id)==FAIL)
280                   HGOTO_ERROR(DFE_CANTDELHASH, FAIL);
281 
282               data_id=FAIL; /* reset this so the first block is a "regular" fixed length block */
283             } /* end if */
284           else
285             {   /* existing data object with real data in it */
286               new_data_tag = DFTAG_LINKED;
287               new_data_ref = Htagnewref(file_id,new_data_tag);
288               /* create new linked-block table DD to point to existing data */
289               if(Hdupdd(file_id, new_data_tag, new_data_ref, tag, ref)==FAIL)
290                 {
291                     HTPendaccess(data_id);
292                     HGOTO_ERROR(DFE_CANTUPDATE, FAIL);
293                 } /* end if */
294 
295               /* Delete the old data ID */
296               if(HTPdelete(data_id)==FAIL)
297                   HGOTO_ERROR(DFE_CANTDELHASH, FAIL);
298 
299               /* Attach to the new data ID */
300               if ((data_id = HTPselect(file_rec,new_data_tag,new_data_ref))==FAIL)
301                   HGOTO_ERROR(DFE_INTERNAL, FAIL);
302             } /* end else */
303       } /* end if */
304 
305     /* get ref for next linked-block? */
306     link_ref = Htagnewref(file_id,DFTAG_LINKED);
307 
308     /* allocate and fill special info struct */
309     if (( info = (linkinfo_t *) HDmalloc((uint32) sizeof(linkinfo_t)))==NULL)
310         HGOTO_ERROR(DFE_NOSPACE, FAIL);
311 
312     info->attached     = 1;
313     info->length       = (data_id!=FAIL) ? data_len : 0;
314     info->first_length = (data_id!=FAIL) ? data_len : block_length;
315     info->block_length = block_length;
316     info->number_blocks = number_blocks;
317     info->link_ref      = link_ref;
318 
319     /* encode special information for writing to file */
320     {
321         uint8      *p;
322         p = local_ptbuf;
323         UINT16ENCODE(p, SPECIAL_LINKED);
324         INT32ENCODE(p, info->length);
325         INT32ENCODE(p, block_length);
326         INT32ENCODE(p, number_blocks);
327         UINT16ENCODE(p, link_ref);  /* link_ref */
328     }
329 
330     /* write the special info structure */
331     if((dd_aid = Hstartaccess(file_id,special_tag,ref,DFACC_ALL))==FAIL)
332         HGOTO_ERROR(DFE_CANTACCESS, FAIL);
333     if (Hwrite(dd_aid, 16, local_ptbuf) == FAIL)
334         HGOTO_ERROR(DFE_WRITEERROR, FAIL);
335     if(Hendaccess(dd_aid)==FAIL)
336         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
337 
338     /* write out linked block */
339     info->link = HLInewlink(file_id, number_blocks, link_ref,
340                             (uint16) ((data_id!=FAIL) ? new_data_ref : 0));
341     if (!info->link)
342         HGOTO_ERROR(DFE_INTERNAL, FAIL);
343 
344     /* Detach from the data DD ID */
345     if(data_id != FAIL)
346       {
347         if(HTPendaccess(data_id)==FAIL)
348             HGOTO_ERROR(DFE_INTERNAL, FAIL);
349       }
350 
351     /* update access record and file record */
352     if((access_rec->ddid=HTPselect(file_rec,special_tag,ref))==FAIL)
353         HGOTO_ERROR(DFE_INTERNAL, FAIL);
354 
355     access_rec->special_func = &linked_funcs;
356     access_rec->special_info = (void *)info;
357     access_rec->special      = SPECIAL_LINKED;
358     access_rec->posn         = 0;
359     access_rec->access       = DFACC_RDWR;
360     access_rec->file_id      = file_id;
361     access_rec->appendable   = FALSE;     /* start data as non-appendable */
362 
363     file_rec->attach++; /* increment number of elements attached to file */
364 
365     /* set return value */
366     ret_value = HAregister_atom(AIDGROUP,access_rec);
367 
368 done:
369   if(ret_value == FAIL)
370     { /* Error condition cleanup */
371         if (info != NULL)
372             HDfree(info);
373         if(access_rec!=NULL)
374             HIrelease_accrec_node(access_rec);
375     } /* end if */
376 
377   /* Normal function cleanup */
378   return ret_value;
379 } /* HLcreate() */
380 
381 /* ------------------------------------------------------------------------
382 NAME
383    HLconvert -- convert an AID into a linked block element
384 USAGE
385    intn HLconvert(aid, blocklen, numblocks)
386    int32   aid;         IN: AID to convert
387    int32   blocklen;    IN: length of standard block
388    int32   numblocks;   IN: number of blocks per block list
389 RETURNS
390    SUCCEED / FAIL
391 DESCRIPTION
392    This routine takes an HDF element and promotes it into a linked
393    block element.  Basically, the element becomes a linked list
394    allowing easy appending.  If the element already exists, it
395    is promoted to being a linked block element, otherwise a new
396    element is created.
397 
398    All of the pieces of the linked list are the same size (blocklen)
399    except for the first one which stays the size of the element
400    at the time HLcreate was called.
401 
402    This routine is similar to HLcreate but is used to convert an
403    existing AID into a linked block element "in-place".  This is
404    done for convenience and ease-of-use mostly internally to the
405    library in various places, but it is allowable for user-level
406    code to do this also.
407 
408    Hopefully HLcreate will get re-written to call this routine for
409    most of it's work...
410 
411    numblocks gives the number of linked list objects in each
412    block header.
413 
414    The ideal setting for numblocks and blocklen are very data
415    and application depedent.
416 
417 ---------------------------------------------------------------------------*/
418 intn
HLconvert(int32 aid,int32 block_length,int32 number_blocks)419 HLconvert(int32 aid,
420           int32 block_length,
421           int32 number_blocks)
422 {
423     CONSTR(FUNC, "HLconvert");  /* for HERROR */
424     filerec_t  *file_rec;       /* file record */
425     accrec_t   *access_rec=NULL;/* access record */
426     linkinfo_t *info;           /* information for the linked blocks elt */
427     uint16      link_ref;       /* the ref of the link structure
428                                    (block table) */
429     int32       dd_aid;         /* AID for writing the special info */
430     uint16      new_data_tag=DFTAG_NULL, new_data_ref=0;  /* Tag/ref of the new data in the file */
431     uint16      data_tag, data_ref;  /* Tag/ref of the data in the file */
432     int32       data_len;		/* length of the data we are checking */
433     int32       data_off;		/* offset of the data we are checking */
434     uint16      special_tag;    /* special version of this tag */
435     int32       file_id;        /* file ID for the access record */
436     uint8       local_ptbuf[16];
437     int32       old_posn;       /* position in the access element */
438     intn        ret_value = SUCCEED;
439 
440     /* clear error stack */
441     HEclear();
442 
443     /* start checking the func. args */
444     if (HAatom_group(aid)!=AIDGROUP || block_length < 0 || number_blocks < 0)
445         HGOTO_ERROR(DFE_ARGS, FAIL);
446 
447     /* get the access_rec pointer */
448     if ((access_rec = HAatom_object(aid)) == NULL)
449         HGOTO_ERROR(DFE_ARGS, FAIL);
450 
451     file_id = access_rec->file_id;
452     file_rec = HAatom_object(file_id);
453     if (BADFREC(file_rec))
454         HGOTO_ERROR(DFE_ARGS, FAIL);
455 
456     if (!(file_rec->access & DFACC_WRITE))
457         HGOTO_ERROR(DFE_DENIED, FAIL);
458 
459     /* verify that the object is not already special. Can not convert
460        if already special.  */
461     if (HTPis_special(access_rec->ddid))
462         HGOTO_ERROR(DFE_CANTMOD, FAIL);
463 
464     /* Save previous position in data element so that we can come back to it */
465     old_posn=access_rec->posn;
466 
467     /* get the info for the dataset */
468     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,&data_off,&data_len)==FAIL)
469         HGOTO_ERROR(DFE_INTERNAL, FAIL);
470 
471     /* make data tag special i.e. will be linked-block element */
472     if ((special_tag = MKSPECIALTAG(data_tag)) == DFTAG_NULL)
473         HGOTO_ERROR(DFE_BADDDLIST, FAIL);
474 
475     /* is data defined but does not exist in the file? */
476     if(data_off==INVALID_OFFSET && data_len==INVALID_LENGTH)
477       { /* catch the case where the data doesn't exist yet */
478 
479           /* set length to zero */
480         if(Hsetlength(aid,0)==FAIL)
481             HGOTO_ERROR(DFE_INTERNAL, FAIL);
482 
483         /* get back new offset and length */
484         if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,&data_off,&data_len)==FAIL)
485             HGOTO_ERROR(DFE_INTERNAL, FAIL);
486       } /* end if */
487 
488     /* set up new tag/ref for linked block element */
489     new_data_tag = DFTAG_LINKED;
490     new_data_ref = Htagnewref(file_id,new_data_tag);
491 
492     /* make new tag/ref point to existing data element */
493     if(Hdupdd(file_id, new_data_tag, new_data_ref, data_tag, data_ref)==FAIL)
494         HGOTO_ERROR(DFE_CANTUPDATE, FAIL);
495 
496     /* Delete the old data ID */
497     if(HTPdelete(access_rec->ddid)==FAIL)
498         HGOTO_ERROR(DFE_CANTDELHASH, FAIL);
499 
500     /* Attach to the new data ID */
501     if ((access_rec->ddid=HTPcreate(file_rec,special_tag,data_ref))==FAIL)
502         HGOTO_ERROR(DFE_INTERNAL, FAIL);
503 
504     /* get link ref for linked-block ? */
505     link_ref = Htagnewref(file_id,DFTAG_LINKED);
506 
507     /* allocates special info struct for linked blocks */
508     access_rec->special_info = HDmalloc((uint32) sizeof(linkinfo_t));
509     if (!access_rec->special_info)
510         HGOTO_ERROR(DFE_NOSPACE, FAIL);
511 
512     /* fill in special info struct */
513     info = (linkinfo_t *) access_rec->special_info;
514     info->attached     = 1;
515     info->length       = data_len;
516     info->first_length = data_len;
517     info->block_length = block_length;
518     info->number_blocks = number_blocks;
519     info->link_ref = link_ref;
520 
521     /* Get ready to fill and write the special info structure  */
522 
523     /* start write access on special tag/ref */
524     if((dd_aid=Hstartaccess(file_id,special_tag,data_ref,DFACC_ALL))==FAIL)
525         HGOTO_ERROR(DFE_CANTACCESS, FAIL);
526 
527     /* encode special information to write out */
528     {
529         uint8      *p;
530 
531         p = local_ptbuf;
532         UINT16ENCODE(p, SPECIAL_LINKED);
533         INT32ENCODE(p, info->length);
534         INT32ENCODE(p, block_length);
535         INT32ENCODE(p, number_blocks);
536         UINT16ENCODE(p, link_ref);  /* link_ref */
537     }
538 
539     /* write out special information */
540     if (Hwrite(dd_aid, 16, local_ptbuf) == FAIL)
541         HGOTO_ERROR(DFE_WRITEERROR, FAIL);
542     if(Hendaccess(dd_aid)==FAIL)
543         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
544 
545     /* write out linked block */
546     if ((info->link = HLInewlink(file_id, number_blocks, link_ref, (uint16)new_data_ref)) ==NULL)
547         HGOTO_ERROR(DFE_CANTLINK, FAIL);
548 
549     /* update access record and file record */
550     access_rec->special_func = &linked_funcs;
551     access_rec->special = SPECIAL_LINKED;
552     access_rec->appendable = FALSE;     /* start data as non-appendable */
553 
554     /* check whether we should seek out to the proper position */
555     if(old_posn>0)
556       {
557         if(Hseek(aid,old_posn,DF_START)==FAIL)
558               HGOTO_ERROR(DFE_BADSEEK, FAIL);
559       } /* end if */
560 
561 done:
562   if(ret_value == FAIL)
563     { /* Error condition cleanup */
564         if(access_rec->special_info != NULL)
565             HDfree(access_rec->special_info);
566         if(access_rec!=NULL)
567             HIrelease_accrec_node(access_rec);
568     } /* end if */
569 
570   /* Normal function cleanup */
571   return ret_value;
572 }   /* end HLconvert() */
573 
574 /* ---------------------------- HDinqblockinfo ---------------------------- */
575 /*
576 NAME
577    HDinqblockinfo -- return info about linked blocks
578 USAGE
579    int32 HDinqblockinfo(aid, length, flength, blen, nblocks)
580    int32   aid;          IN:  aid of element
581    int32 * length;       OUT: total element length
582    int32 * flength;      OUT: length of first element
583    int32 * blen;         OUT: length of block elements
584    int32 * nblocks;      OUT: number of blocks per block header
585 RETURNS
586    SUCCEED / FAIL
587 DESCRIPTION
588    Given an aid, return low level special info for linked-block
589    element in space provided.  This function works like HDinquire()
590    but provides more low level info than HLPinquire.  NULL can
591    be passed for any non-interesting entries.
592 
593    hdfpack is the only application that I know of which uses
594    this function.
595 
596 ---------------------------------------------------------------------------*/
597 int
HDinqblockinfo(int32 aid,int32 * length,int32 * first_length,int32 * block_length,int32 * number_blocks)598 HDinqblockinfo(int32 aid,
599                int32 *length,
600                int32 *first_length,
601                int32 *block_length,
602                int32 *number_blocks)
603 {
604     accrec_t   *arec;
605     int        ret_value = SUCCEED;
606     CONSTR(FUNC, "HDinqblockinfo");
607 
608     HEclear();
609     if ((arec = HAatom_object(aid)) == (accrec_t *) NULL)
610         HGOTO_ERROR(DFE_BADAID, FAIL);
611 
612     if (arec->special != SPECIAL_LINKED)
613         HGOTO_ERROR(DFE_ARGS, FAIL);
614 
615     if (length)
616         *length = ((linkinfo_t *) (arec->special_info))->length;
617     if (first_length)
618         *first_length = ((linkinfo_t *) (arec->special_info))->first_length;
619     if (block_length)
620         *block_length = ((linkinfo_t *) (arec->special_info))->block_length;
621     if (number_blocks)
622         *number_blocks = ((linkinfo_t *) (arec->special_info))->number_blocks;
623 
624 done:
625   if(ret_value == FAIL)
626     { /* Error condition cleanup */
627 
628     } /* end if */
629 
630   /* Normal function cleanup */
631 
632   return ret_value;
633 }   /* HDinqblockinfo */
634 
635 /* ----------------------------- HLIstaccess ------------------------------ */
636 /*
637 NAME
638    HLIstaccess -- set up AID to access a linked block elem
639 USAGE
640    int32 HLIstaccess(access_rec, acc_mode)
641    access_t * access_rec;   IN: access record to fill in
642    int16      acc_mode;     IN: access mode
643 RETURNS
644    The AID of the access record on success FAIL on error.
645 DESCRIPTION
646    Calls to HLIstread and HLIstwrite resolve to this function.
647    Given an active AID fill in all of the special information.
648    If this information has already been read in for a different
649    element use that else we must go out to the HDF file and
650    pull in the information ourselves
651 
652 ----------------------------------------------------------------------------*/
653 PRIVATE int32
HLIstaccess(accrec_t * access_rec,int16 acc_mode)654 HLIstaccess(accrec_t *access_rec,
655             int16     acc_mode)
656 {
657     CONSTR(FUNC, "HLIstaccess");    /* for HERROR */
658     filerec_t  *file_rec;       /* file record */
659     linkinfo_t *info = NULL;           /* information about data elt */
660     int32       dd_aid;         /* AID for writing the special info */
661     uint16      data_tag, data_ref;  /* Tag/ref of the data in the file */
662     uint8       local_ptbuf[14];
663     int32       ret_value = SUCCEED;
664 
665     /* validate file record id */
666     file_rec = HAatom_object(access_rec->file_id);
667     if (BADFREC(file_rec) || !(file_rec->access & acc_mode))
668         HGOTO_ERROR(DFE_ARGS, FAIL);
669 
670     /* set up some data in access record */
671     access_rec->special = SPECIAL_LINKED;
672     access_rec->posn = 0;
673     access_rec->access = (uint32)(acc_mode|DFACC_READ);
674 
675     /*
676      * Lets free old special info first,if one exists,
677      * before copying a new one
678      */
679     if (access_rec->special_info != NULL)
680       {   /* special information record */
681           linkinfo_t *t_info = (linkinfo_t *) access_rec->special_info;
682 
683           if (--(t_info->attached) == 0)
684             {
685                 link_t     *t_link; /* current link to free */
686                 link_t     *next;   /* next link to free */
687 
688                 /* free the linked list of links/block tables */
689                 if(t_info->link!=NULL)
690                   {
691                     for (t_link = t_info->link; t_link; t_link = next)
692                       {
693                           next = t_link->next;
694                           if(t_link->block_list!=NULL)
695                               HDfree(t_link->block_list);
696                           HDfree(t_link);
697                       }
698                   } /* end if */
699                 HDfree(t_info);
700                 access_rec->special_info = NULL;
701             }
702       }
703 
704     /* get the info for the dataset */
705     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,NULL,NULL)==FAIL)
706         HGOTO_ERROR(DFE_INTERNAL, FAIL);
707 
708     /* if the special information are already in some other acc elt,
709      * point to it */
710     access_rec->special_info = HIgetspinfo(access_rec);
711     if (access_rec->special_info)
712       {
713           ((linkinfo_t *) access_rec->special_info)->attached++;
714           file_rec->attach++;
715           ret_value = HAregister_atom(AIDGROUP,access_rec);
716           goto done; /* we are done */
717       }
718 
719     /* read the special info structure from the file */
720     if((dd_aid = Hstartaccess(access_rec->file_id,data_tag,data_ref,DFACC_READ))==FAIL)
721         HGOTO_ERROR(DFE_CANTACCESS, FAIL);
722     if (Hseek(dd_aid, 2, DF_START) == FAIL)
723         HGOTO_ERROR(DFE_SEEKERROR, FAIL);
724     if (Hread(dd_aid, 14, local_ptbuf) == FAIL)
725         HGOTO_ERROR(DFE_READERROR, FAIL);
726     if(Hendaccess(dd_aid)==FAIL)
727         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
728 
729     /* allocate space for special information */
730     access_rec->special_info = HDmalloc((uint32) sizeof(linkinfo_t));
731     info = (linkinfo_t *) access_rec->special_info;
732     if (!info)
733         HGOTO_ERROR(DFE_NOSPACE, FAIL);
734 
735     /* decode special information retrieved from file into info struct */
736     {
737         uint8      *p = local_ptbuf;
738         INT32DECODE(p, info->length);
739         INT32DECODE(p, info->block_length);
740         INT32DECODE(p, info->number_blocks);
741         UINT16DECODE(p, info->link_ref);
742     }
743 
744     /* get the block length and number of blocks */
745     access_rec->block_size = info->block_length;
746     access_rec->num_blocks = info->number_blocks;
747 
748     /* set up the block tables of the information */
749     info->link = HLIgetlink(access_rec->file_id,
750                             info->link_ref, info->number_blocks);
751     if (!info->link)
752         HGOTO_DONE(FAIL);
753 
754     /* find and set the length of the first linked-block */
755     if (info->link->block_list[0].ref)
756       {
757           info->first_length = Hlength(access_rec->file_id, DFTAG_LINKED,
758                                        info->link->block_list[0].ref);
759           if (info->first_length == FAIL)
760             {
761                 HDfree(info->link);
762                 HGOTO_ERROR(DFE_INTERNAL, FAIL);
763             }
764       }
765     else
766         info->first_length = info->block_length;
767 
768     /* process through all the linked-blocks in the file for this element */
769     info->last_link = info->link;
770     while (info->last_link->nextref != 0)
771       {
772           info->last_link->next = HLIgetlink(access_rec->file_id,
773                  info->last_link->nextref, info->number_blocks);
774           if (!info->last_link->next)
775             {
776                 link_t     *l, *next;
777 
778                 for (l = info->link; l; l = next)
779                   {
780                       next = l->next;
781                       if (l->block_list)
782                           HDfree(l->block_list);
783                       HDfree(l);
784                   }
785                 HGOTO_ERROR(DFE_INTERNAL, FAIL);
786             }
787           info->last_link = info->last_link->next;
788       }
789 
790     /* update data */
791     info->attached = 1;
792 
793     file_rec->attach++; /* increment number of elements attached to file */
794 
795     ret_value = HAregister_atom(AIDGROUP,access_rec);
796 
797 done:
798   if(ret_value == FAIL)
799     { /* Error condition cleanup */
800         if(access_rec->special_info != NULL)
801             HDfree(access_rec->special_info);
802     } /* end if */
803 
804   /* Normal function cleanup */
805 
806   return ret_value;
807 }   /* HLIstaccess */
808 
809 /* ----------------------------- HLgetdatainfo --------------------------- */
810 /*
811 NAME
812    HLgetdatainfo -- get data information from linked blocks
813 USAGE
814    int32 HLgetdatainfo(file_id, link_ref, num_blocks, offsetarray, lengtharray)
815    int32  file_id;	IN: the file
816    uint8 *buf;		IN: special header info read from the file by caller
817    uintn start_block,   IN: data block to start at, 0 base
818    uintn info_count,    IN: size of offset/length lists
819    int32 *offsetarray;	OUT: offsets of data blocks
820    int32 *lengtharray;	OUT: lengths of data blocks
821 RETURNS
822    The number of actual data blocks, if successful, FAIL, otherwise
823 DESCRIPTION
824    HLgetdatainfo uses HLIgetlink to get each block table in the element.
825    We're looking for actual data blocks which have a positive reference number.
826    Blocks with ref# as 0 will signal the end of the actual data blocks.
827    HLgetdatainfo goes through the block table to record offset and length of
828    the actual data blocks.
829    Aug 08, 2010 -BMR
830 TODO
831    - No effect from start_block yet; since it's not used in the HDF Mapping
832      project, and we're running out of time, I'm leaving it out.
833      Feb 18, 2011 -BMR
834 ---------------------------------------------------------------------------*/
835 intn
HLgetdatainfo(int32 file_id,uint8 * buf,uintn start_block,uintn info_count,int32 * offsetarray,int32 * lengtharray)836 HLgetdatainfo(int32 file_id,
837            uint8 *buf, 		   /* IN: special header info */
838            uintn start_block,      /* IN: data block to start at, 0 base */
839            uintn info_count,       /* IN: size of offset/length lists */
840 	   int32 *offsetarray,     /* OUT: array to hold offsets */
841 	   int32 *lengtharray)     /* OUT: array to hold lengths */
842 {
843     CONSTR(FUNC, "HLgetdatainfo");	/* for HERROR */
844     link_t *link_info=NULL;  /* link information, to get block ref#s*/
845     intn    num_data_blocks; /* number of blocks that actually have data */
846     uint16  link_ref;        /* ref# pointing to a block table */
847     uint8  *p=NULL;          /* pointer to special info buffer */
848     int32   num_blocks,      /* number of blocks in each table */
849             block_length,    /* length of each block */
850             total_length,    /* total data length of the element */
851             accum_length;    /* accummulative length of actual data in blocks */
852     int     ii;
853     intn   ret_value = SUCCEED;
854 
855     /* Clear error stack */
856     HEclear();
857 
858     /* Validate arguments */
859     if (info_count == 0 && offsetarray != NULL && lengtharray != NULL)
860         HGOTO_ERROR(DFE_ARGS, FAIL);
861 
862     /* Decode special information retrieved from file */
863     p = &buf[0];
864     INT32DECODE(p, total_length);
865     INT32DECODE(p, block_length);
866     INT32DECODE(p, num_blocks);     /* get number of blocks in link table */
867     UINT16DECODE(p, link_ref);      /* get ref# link table */
868 
869     /* Initialize number of actual data blocks and the accumulative data len */
870     num_data_blocks = 0;
871     accum_length = 0;
872 
873     /* Get the block table pointed to by link_ref; the table contains ref#s of
874        the blocks */
875     link_info = HLIgetlink(file_id, link_ref, num_blocks);
876     if (!link_info) /* no data */
877         HGOTO_DONE(FAIL);
878 
879     /* Go through all the linked-block tables of this element, as long as the
880        number of data blocks being collected has not reached the maximum length
881        of the non-NULL arrays provided */
882     while (link_info != NULL &&
883 	(info_count == 0 ||	/* case of offset/length arrays being NULL */
884 	 num_data_blocks < info_count))
885     {
886         uint16 next_ref = link_info->nextref; /* shortcut */
887 
888         /* Get offset/length of blocks that actually point to a data elem,
889            until all blocks in this table with valid ref#s are processed */
890         for (ii = 0; ii < num_blocks && link_info->block_list[ii].ref != 0;ii++)
891 	{
892             int32 offset, length;
893             uint16 block_ref = link_info->block_list[ii].ref; /* shortcut */
894 
895             /* If this block has a valid ref# then get the offset/length of
896                the data if they are requested, and increment the number of
897 	       data blocks */
898             if (block_ref != 0)
899             {
900                 if (offsetarray != NULL)
901 		{
902                     offset = Hoffset(file_id, DFTAG_LINKED, block_ref);
903                     if (offset == FAIL)
904                         HGOTO_ERROR(DFE_INTERNAL, FAIL);
905                     offsetarray[num_data_blocks] = offset;
906                 }
907                 if (lengtharray != NULL)
908 		{
909                     length = Hlength(file_id, DFTAG_LINKED, block_ref);
910                     if (length == FAIL)
911                         HGOTO_ERROR(DFE_INTERNAL, FAIL);
912 
913                     /* Make sure to detect when the last block of the element is
914 		       reached and calculate the len of the actual data in it */
915 
916 		    /* Continue accumulating data length if there is
917 		       another block table coming */
918                     if (next_ref != 0)
919                         accum_length = accum_length + length;
920 
921 		    /* When no more block table following this one, i.e., this
922                        is the last block table in the element */
923                     else
924                     {
925 		        /* if this is NOT the last block having data in the
926                            current table, continue accumulating */
927                         if (ii < num_blocks - 1 && link_info->block_list[ii + 1].ref != 0)
928                             accum_length = accum_length + length;
929 
930 			/* else, i.e., this is the last block in the curr table,
931 			      or the last block that points to actual data */
932                         else
933                         {
934 			    /* then calculate the data's actual length when the
935                                length is the same as the default block length,
936                                because it might not be */
937                             if (length == block_length)
938                                 length = total_length - accum_length;
939                         }
940                     }
941                     /* Record the actual data length in the current block */
942                     lengtharray[num_data_blocks] = length;
943                 }
944                 num_data_blocks++; /* count number of blocks with data */
945             }
946         } /* for each block in the current table */
947 
948         /* Free allocated memory before getting the next block table if
949 	   there is one */
950         if (link_info != NULL)
951         {
952             if (link_info->block_list != NULL)
953                 HDfree(link_info->block_list);
954             HDfree(link_info);
955             link_info = NULL;
956         }
957 	/* Get next block table */
958         if (next_ref != 0)
959             link_info = HLIgetlink(file_id, next_ref, num_blocks);
960     } /* while there are more linked-block tables and the offset/length arrays
961 	 are not full yet */
962 
963     /* Return the number of blocks with actual data */
964     ret_value = num_data_blocks;
965 
966 done:
967   if(ret_value == FAIL)
968     { /* Error condition cleanup */
969         if(link_info != NULL)
970             if (link_info->block_list != NULL)
971                 HDfree(link_info->block_list);
972             HDfree(link_info);
973     } /* end if */
974 
975   /* Normal function cleanup */
976   return ret_value;
977 }   /* HLgetdatainfo */
978 
979 /* ------------------------------ HLPstread ------------------------------- */
980 /*
981 NAME
982    HLPstread -- open an access record for reading
983 USAGE
984    int32 HLPstread(access_rec)
985    access_t * access_rec;   IN: access record to fill in
986 RETURNS
987    The AID of the access record on success FAIL on error.
988 DESCRIPTION
989    Calls to HLIstaccess to fill in the access rec for
990    reading
991 
992 ---------------------------------------------------------------------------*/
993 int32
HLPstread(accrec_t * access_rec)994 HLPstread(accrec_t * access_rec)
995 {
996   int32 ret_value;
997 
998   ret_value = HLIstaccess(access_rec, DFACC_READ);
999 
1000   return ret_value;
1001 }   /* HLPstread */
1002 
1003 /* ------------------------------ HLPstwrite ------------------------------- */
1004 /*
1005 NAME
1006    HLPstwrite -- open an access record for writing
1007 USAGE
1008    int32 HLPstwrite(access_rec)
1009    access_t * access_rec;   IN: access record to fill in
1010 RETURNS
1011    The AID of the access record on success FAIL on error.
1012 DESCRIPTION
1013    Calls to HLIstaccess to fill in the access rec for
1014    writing
1015 
1016 ---------------------------------------------------------------------------*/
1017 int32
HLPstwrite(accrec_t * access_rec)1018 HLPstwrite(accrec_t * access_rec)
1019 {
1020   int32  ret_value;
1021 
1022   ret_value = HLIstaccess(access_rec, (int16)DFACC_WRITE);
1023 
1024   return ret_value;
1025 }   /* HLPstwrite */
1026 
1027 /* ------------------------------ HLIgetlink ------------------------------ */
1028 /*
1029 NAME
1030    HLIgetlink -- get link information
1031 USAGE
1032    link_t * HLIgetlink(fid, ref, num_blocks)
1033    int32  file_id;             IN: the file
1034    uint16 ref;                 IN: ref number of the link table
1035    int32  num_blocks;          IN: number of blocks in the table
1036 RETURNS
1037    A pointer to a link_t or NULL.
1038 DESCRIPTION
1039    Read a block table out of the file and return a pointer to
1040    the internal table representing it.
1041 
1042    It seems that num_blocks is redundant.
1043 
1044 ---------------------------------------------------------------------------*/
1045 PRIVATE link_t *
HLIgetlink(int32 file_id,uint16 ref,int32 number_blocks)1046 HLIgetlink(int32  file_id,
1047            uint16 ref,
1048            int32  number_blocks)
1049 {
1050     CONSTR(FUNC, "HLIgetlink");     /* for HERROR */
1051     int32    access_id;      /* access record id */
1052     uint8    *buffer = NULL;
1053     uint16   tag     = DFTAG_LINKED;
1054     link_t   *new_link  = NULL;
1055     link_t   *ret_value = NULL; /* FAIL */
1056 
1057     /* allocate necessary memory for in-memory block table */
1058     new_link = (link_t *) HDmalloc((uint32) sizeof(link_t));
1059 
1060     if (new_link == NULL)
1061         HGOTO_ERROR(DFE_NOSPACE, NULL);
1062 
1063     new_link->block_list = (block_t *) HDmalloc((uint32) number_blocks
1064                                                   * sizeof(block_t));
1065     if (new_link->block_list == NULL)
1066         HGOTO_ERROR(DFE_NOSPACE, NULL);
1067 
1068     new_link->next = (link_t *) NULL;
1069 
1070     /* create temp buffer to read block table in */
1071     buffer = (uint8 *) HDmalloc((uint32) (2 + 2 * number_blocks));
1072     if (buffer == NULL)
1073         HGOTO_ERROR(DFE_NOSPACE, NULL);
1074 
1075     /* read block table into buffer */
1076     access_id = Hstartread(file_id, tag, ref);
1077     if (access_id == FAIL ||
1078         Hread(access_id, 2 + 2 * number_blocks, buffer) == FAIL)
1079         HGOTO_ERROR(DFE_READERROR, NULL);
1080 
1081     /* decode block table information read from file */
1082     {
1083         int32 i;
1084         uint8      *p = buffer;
1085 
1086         UINT16DECODE(p, new_link->nextref);
1087         for (i = 0; i < number_blocks; i++)
1088             UINT16DECODE(p, new_link->block_list[i].ref);
1089     }
1090 
1091     /* end acces to this block table */
1092     Hendaccess(access_id);
1093 
1094     /* set return value */
1095     ret_value = new_link;
1096 
1097 done:
1098   if(ret_value == NULL)
1099     { /* Error condition cleanup */
1100         if (new_link->block_list != NULL)
1101             HDfree(new_link->block_list);
1102         if (new_link != NULL)
1103             HDfree(new_link);
1104     } /* end if */
1105 
1106   /* Normal function cleanup */
1107   if (buffer != NULL)
1108       HDfree(buffer);
1109 
1110   return ret_value;
1111 }   /* HLIgetlink */
1112 
1113 /* ------------------------------- HLPseek -------------------------------- */
1114 /*
1115 NAME
1116    HLPseek -- set the seek posn
1117 USAGE
1118    int32 HLPseek(access_rec, offset, origin)
1119    access_t * access_rec;      IN: access record to mess with
1120    int32      offset;          IN: seek offset
1121    int32      origin;          IN: where we should calc the offset from
1122 RETURNS
1123    SUCCEED / FAIL
1124 DESCRIPTION
1125    Set the seek posn in the given linked block element
1126 
1127 ---------------------------------------------------------------------------*/
1128 int32
HLPseek(accrec_t * access_rec,int32 offset,int origin)1129 HLPseek(accrec_t *access_rec,
1130         int32     offset,
1131         int       origin)
1132 {
1133     CONSTR(FUNC, "HLPseek");    /* for HERROR */
1134     int32   ret_value = SUCCEED;
1135 
1136     /* validate access record */
1137     if (access_rec->special != SPECIAL_LINKED)
1138         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1139 
1140     /* adjust the offset according to origin and validate */
1141     /* there is no upper bound to posn */
1142     if (origin == DF_CURRENT)
1143         offset += access_rec->posn;
1144     if (origin == DF_END)
1145         offset += ((linkinfo_t *) (access_rec->special_info))->length;
1146     if (offset < 0)
1147         HGOTO_ERROR(DFE_RANGE, FAIL);
1148 
1149     /* set position */
1150     access_rec->posn = offset;
1151 
1152 done:
1153   if(ret_value == FAIL)
1154     { /* Error condition cleanup */
1155 
1156     } /* end if */
1157 
1158   /* Normal function cleanup */
1159 
1160   return ret_value;
1161 }   /* HLPseek */
1162 
1163 /* ------------------------------- HLPread -------------------------------- */
1164 /*
1165 NAME
1166    HLPread -- read some data out of a linked block element
1167 USAGE
1168    int32 HLPseek(access_rec, length, data)
1169    access_t * access_rec;      IN: access record to mess with
1170    int32      length;          IN: number of bytes to read
1171    void *      data;            IN: buffer for data
1172 RETURNS
1173    The number of bytes read or FAIL on error
1174 DESCRIPTION
1175    Read in some data from a linked block element.  If length
1176    is zero read until the end of the element.  It is assumed
1177    that the data buffer is big enough to store the data.
1178    If length would take us off the end of the element only
1179    read what has been written.
1180 
1181 --------------------------------------------------------------------------- */
1182 int32
HLPread(accrec_t * access_rec,int32 length,void * datap)1183 HLPread(accrec_t *access_rec,
1184         int32     length,
1185         void *     datap)
1186 {
1187     CONSTR(FUNC, "HLPread");    /* for HERROR */
1188     uint8      *data = (uint8 *) datap;
1189     /* information record for this special data elt */
1190     linkinfo_t *info = (linkinfo_t *) (access_rec->special_info);
1191     link_t     *t_link = info->link;    /* block table record */
1192 
1193     /* relative position in linked block of data elt */
1194     int32       relative_posn = access_rec->posn;
1195 
1196     int32       block_idx;      /* block table index of current block */
1197     int32       current_length; /* length of current block */
1198     int32       nbytes = 0;     /* # bytes read on any single Hread() */
1199     int32       bytes_read = 0; /* total # bytes read for this call of HLIread */
1200     int32       ret_value = SUCCEED;
1201 
1202     /* validate length */
1203     if (length == 0)
1204         length = info->length - access_rec->posn;
1205     else
1206         if (length < 0)
1207             HGOTO_ERROR(DFE_RANGE, FAIL);
1208 
1209     if (access_rec->posn + length > info->length)
1210         length = info->length - access_rec->posn;
1211 
1212     /* search for linked block to start reading from */
1213     if (relative_posn < info->first_length)
1214       { /* first block */
1215           block_idx = 0;
1216           current_length = info->first_length;
1217       }
1218     else /* not first block? */
1219       {
1220           relative_posn -= info->first_length;
1221           block_idx = relative_posn / info->block_length + 1;
1222           relative_posn %= info->block_length;
1223           current_length = info->block_length;
1224       }
1225 
1226 /* calculate which block to start from? */
1227     {
1228         int32 i;
1229 
1230         for (i = 0; i < block_idx / info->number_blocks; i++)
1231           {
1232               if (t_link == NULL)
1233                   HGOTO_ERROR(DFE_INTERNAL, FAIL);
1234               t_link = t_link->next;
1235           }
1236     }
1237     block_idx %= info->number_blocks;
1238 
1239     /* found the starting block, now read in the data */
1240     do
1241       {
1242           int32 remaining =    /* remaining data in current block */
1243               current_length - relative_posn;
1244 
1245           /* read in the data in this block */
1246           if (remaining > length)
1247               remaining = length;
1248           if (t_link->block_list[block_idx].ref != 0)
1249             {
1250                 int32       access_id;  /* access record id for this block */
1251                 block_t    *current_block =     /* record on the current block */
1252                     &(t_link->block_list[block_idx]);
1253 
1254                 access_id = Hstartread(access_rec->file_id, DFTAG_LINKED,
1255                                        current_block->ref);
1256                 if (access_id == (int32) FAIL
1257                     || (relative_posn
1258                 && (int32) FAIL == Hseek(access_id, relative_posn, DF_START))
1259                     || (int32) FAIL == (nbytes = Hread(access_id, remaining, data)))
1260                     HGOTO_ERROR(DFE_READERROR, FAIL);
1261 
1262                 bytes_read += nbytes;
1263                 Hendaccess(access_id);
1264             }
1265           else
1266             {   /*if block is missing, fill this part of buffer with zero's */
1267                 HDmemset(data, 0, (size_t)remaining);
1268                 bytes_read += nbytes;
1269             }
1270 
1271           /* move variables for the next block */
1272           data += remaining;
1273           length -= remaining;
1274           if (length > 0 && ++block_idx >= info->number_blocks)
1275             {
1276                 block_idx = 0;
1277                 t_link = t_link->next;
1278                 if (t_link == NULL)
1279                     HGOTO_ERROR(DFE_INTERNAL, FAIL);
1280             }
1281           relative_posn = 0;
1282           current_length = info->block_length;
1283       }
1284     while (length > 0);     /* if still somemore to read in, repeat */
1285 
1286     access_rec->posn += bytes_read;
1287     ret_value = bytes_read;
1288 
1289 done:
1290   if(ret_value == FAIL)
1291     { /* Error condition cleanup */
1292 
1293     } /* end if */
1294 
1295   /* Normal function cleanup */
1296 
1297   return ret_value;
1298 }   /* HLPread  */
1299 
1300 /* ------------------------------- HLPwrite ------------------------------- */
1301 /*
1302 NAME
1303    HLPwrite -- write out some data to a linked block
1304 USAGE
1305    int32 HLPwrite(access_rec, length, data)
1306    access_t * access_rec;      IN: access record to mess with
1307    int32      length;          IN: number of bytes to write
1308    void *      data;            IN: buffer for data
1309 RETURNS
1310    The number of bytes written or FAIL on error
1311 DESCRIPTION
1312    Write out some data from a linked block element.  If we write
1313    passed the end of the existing element new blocks are created
1314    as needed.
1315 
1316 ---------------------------------------------------------------------------*/
1317 int32
HLPwrite(accrec_t * access_rec,int32 length,const void * datap)1318 HLPwrite(accrec_t   *access_rec,
1319          int32       length,
1320          const void * datap)
1321 {
1322     CONSTR(FUNC, "HLPwrite");   /* for HERROR */
1323     const uint8      *data = datap;
1324     filerec_t  *file_rec;       /* file record */
1325     int32       dd_aid;         /* AID for writing the special info */
1326     uint16      data_tag, data_ref;  /* Tag/ref of the data in the file */
1327     linkinfo_t *info =          /* linked blocks information record */
1328         (linkinfo_t *) (access_rec->special_info);
1329     link_t     *t_link =        /* ptr to link block table */
1330         info->link;
1331     int32       relative_posn = /* relative position in linked block */
1332         access_rec->posn;
1333     int32       block_idx;      /* block table index of current block */
1334     link_t     *prev_link = NULL; /* ptr to block table before current block table.
1335                                        for groking the offset of
1336                                        current block table */
1337     int32       current_length; /* length of current block */
1338     int32       nbytes = 0;     /* #bytes written by any single Hwrite */
1339     int32       bytes_written = 0;  /* total #bytes written by HLIwrite */
1340     uint8       local_ptbuf[4];
1341     int32       ret_value = SUCCEED;
1342 
1343     /* convert file id to file record */
1344     file_rec = HAatom_object(access_rec->file_id);
1345 
1346     /* validate length and file records */
1347     if (length <= 0)
1348         HGOTO_ERROR(DFE_RANGE, FAIL);
1349     if (BADFREC(file_rec))
1350         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1351 
1352     /* determine linked block and position to start writing into */
1353     /* determine where to start.  Setup missing block tables
1354        along the way. */
1355     if (relative_posn < info->first_length)
1356       {
1357           block_idx = 0;
1358           current_length = info->first_length;
1359       }
1360     else
1361       {
1362           relative_posn -= info->first_length;
1363           block_idx = relative_posn / info->block_length + 1;
1364           relative_posn %= info->block_length;
1365           current_length = info->block_length;
1366       }
1367     {
1368         /* follow the links of block tables and create missing
1369            block tables along the way */
1370         int32 num_links;   /* number of links to follow */
1371 
1372         for (num_links = block_idx / info->number_blocks; num_links > 0; num_links--)
1373           {
1374               if (!t_link->next)
1375                 {   /* create missing link (block table) */
1376                     t_link->nextref = Htagnewref(access_rec->file_id,DFTAG_LINKED);
1377                     t_link->next = HLInewlink(access_rec->file_id,
1378                                    info->number_blocks, t_link->nextref, 0);
1379                     if (!t_link->next)
1380                         HGOTO_ERROR(DFE_NOSPACE,FAIL);
1381                     {   /* AA */
1382                         /* update previous link with information about new link */
1383 
1384                         uint16      link_tag = DFTAG_LINKED;
1385                         uint16      link_ref =  /* ref of current link */
1386                         (uint16) (prev_link != NULL ?
1387                                   prev_link->nextref : info->link_ref);
1388 
1389                         uint8      *p = local_ptbuf;    /* temp buf ptr */
1390 
1391                         /* write file the updated portion of current link */
1392 
1393                         int32       link_id =   /* access id for current link */
1394                         Hstartwrite(access_rec->file_id, link_tag, link_ref, 0);
1395 
1396                         if (link_id == FAIL)
1397                             HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1398                         UINT16ENCODE(p, t_link->nextref);
1399                         if (Hwrite(link_id, 2, local_ptbuf) == FAIL)
1400                             HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1401                         Hendaccess(link_id);
1402                     }   /* AA */
1403                 }   /* if not t_link->next */
1404 
1405               /* move to the next link */
1406               prev_link = t_link;
1407               t_link = t_link->next;
1408           }     /* end for */
1409     }   /* end block statement(bad) */
1410 
1411     block_idx %= info->number_blocks;
1412 
1413     /* start writing in that block */
1414     do
1415       {
1416           int32       access_id;    /* access record id */
1417           int32       remaining =   /* remaining data length in this block */
1418               current_length - relative_posn;
1419           uint16      new_ref = 0;  /* ref of newly created block */
1420 
1421           /* determine length and write this block */
1422           if (remaining > length)
1423               remaining = length;
1424 
1425           /* this block already exist, so just set up access to it */
1426           if (t_link->block_list[block_idx].ref != 0)
1427             {
1428                 block_t    *current_block =     /* ptr to current block record */
1429                 &(t_link->block_list[block_idx]);
1430 
1431                 access_id = Hstartwrite(access_rec->file_id, DFTAG_LINKED,
1432                                         current_block->ref, current_length);
1433             }
1434           else
1435             {   /* block is missing, set up a new block */
1436                 new_ref = Htagnewref(access_rec->file_id,DFTAG_LINKED);
1437                 access_id = Hstartwrite(access_rec->file_id, DFTAG_LINKED,
1438                                         new_ref, current_length);
1439             }
1440 
1441           if (access_id == (int32) FAIL)
1442               HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1443 
1444           if ((relative_posn &&
1445                (int32) FAIL == Hseek(access_id, relative_posn, DF_START)) ||
1446               (int32) FAIL == (nbytes = Hwrite(access_id, remaining, data)))
1447             {
1448                 HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1449             }
1450           Hendaccess(access_id);
1451           bytes_written += nbytes;
1452 
1453           if (new_ref)
1454             {   /* created a new block, so update the link/block table */
1455                 uint16      link_tag = DFTAG_LINKED;
1456                 uint16      link_ref =  /* ref of the current link/block table */
1457                 (uint16) (prev_link ? prev_link->nextref : info->link_ref);
1458                 uint8      *p = /* temp buffer ptr */
1459                 local_ptbuf;
1460                 int32       link_id =   /* access record id of the current
1461                                            link/block table */
1462                 Hstartwrite(access_rec->file_id, link_tag, link_ref, 0);
1463 
1464                 if (link_id == FAIL)
1465                     HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1466                 UINT16ENCODE(p, new_ref);
1467                 if (Hseek(link_id, 2 + 2 * block_idx, DF_START) == FAIL)
1468                     HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1469                 if (Hwrite(link_id, 2, local_ptbuf) == FAIL)
1470                     HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1471                 Hendaccess(link_id);
1472 
1473                 /* update memory structure */
1474                 t_link->block_list[block_idx].ref = new_ref;
1475             }   /* if new_ref */
1476 
1477           /* move ptrs and counters for next phase */
1478           data += remaining;
1479           length -= remaining;
1480 
1481           if (length > 0 && ++block_idx >= info->number_blocks)
1482             {  /* move to the next link/block table */
1483                 block_idx = 0;
1484                 if (!t_link->next)
1485                   {     /* create missing link/block table */
1486                       t_link->nextref = Htagnewref(access_rec->file_id,DFTAG_LINKED);
1487                       t_link->next = HLInewlink(access_rec->file_id,
1488                                    info->number_blocks, t_link->nextref, 0);
1489                       if (!t_link->next)
1490                           HGOTO_ERROR(DFE_NOSPACE, FAIL);
1491 
1492                       {     /* BB */
1493                           uint16      link_tag = DFTAG_LINKED;
1494                           uint16      link_ref =    /* ref of current link/block table */
1495                           (uint16) (prev_link ? prev_link->nextref : info->link_ref);
1496                           uint8      *p =   /* temp buffer ptr */
1497                           local_ptbuf;
1498                           int32       link_id =     /* access record id of
1499                                                        current link/block table */
1500                           Hstartwrite(access_rec->file_id, link_tag,
1501                                       link_ref, 0);
1502 
1503                           if (link_id == FAIL)
1504                               HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1505                           UINT16ENCODE(p, t_link->nextref);
1506                           if (Hwrite(link_id, 2, local_ptbuf) == FAIL)
1507                               HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1508                           Hendaccess(link_id);
1509                       }     /* BB */
1510                   }     /* if not t_link->next  */
1511 
1512                 /* move to the next link/block table */
1513                 prev_link = t_link;
1514                 t_link = t_link->next;
1515             }   /* end if "length" */
1516 
1517           /* update vars for next phase */
1518           relative_posn = 0;
1519           current_length = info->block_length;
1520       }
1521     while (length > 0);
1522 
1523     /* update the info for the dataset */
1524     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,NULL,NULL)==FAIL)
1525         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1526     if((dd_aid=Hstartaccess(access_rec->file_id,data_tag,data_ref,DFACC_WRITE))==FAIL)
1527         HGOTO_ERROR(DFE_CANTACCESS, FAIL);
1528     if (Hseek(dd_aid, 2, DF_START) == FAIL)
1529         HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1530     {
1531         int32       tmp;
1532         uint8      *p = local_ptbuf;
1533 
1534         tmp = bytes_written + access_rec->posn;
1535         if (tmp > info->length)
1536             info->length = tmp;
1537         INT32ENCODE(p, info->length);
1538 
1539     }
1540     if (Hwrite(dd_aid, 4, local_ptbuf) == FAIL)
1541         HGOTO_ERROR(DFE_READERROR, FAIL);
1542     if(Hendaccess(dd_aid)==FAIL)
1543         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1544 
1545     access_rec->posn += bytes_written;
1546     /* return SUCCEED; */
1547     /* if wrong # bytes written, FAIL has already been returned */
1548     ret_value = bytes_written;
1549 
1550 done:
1551   if(ret_value == FAIL)
1552     { /* Error condition cleanup */
1553 
1554     } /* end if */
1555 
1556   /* Normal function cleanup */
1557 
1558   return ret_value;
1559 }   /* HLPwrite */
1560 
1561 /* ------------------------------ HLInewlink ------------------------------ */
1562 /*
1563 NAME
1564    HLInewlink -- write out some data to a linked block
1565 USAGE
1566    link_t * HLInewlink(fid, nblocks, link_ref, first_block_ref)
1567    int32  fid;               IN: file ID
1568    int32  nblocks;           IN: number of blocks in the table
1569    uint16 link_ref;          IN: ref number for the table
1570    uint16 first_block_ref;   IN: ref number for first block
1571 RETURNS
1572    A pointer to a new link/block table or NULL
1573 DESCRIPTION
1574    Create a new link/block table in memory and in file returns
1575    ptr to the new link/block table.
1576 
1577 ---------------------------------------------------------------------------*/
1578 PRIVATE link_t *
HLInewlink(int32 file_id,int32 number_blocks,uint16 link_ref,uint16 first_block_ref)1579 HLInewlink(int32  file_id,
1580            int32  number_blocks,
1581            uint16 link_ref,
1582            uint16 first_block_ref)
1583 {
1584     CONSTR(FUNC, "HLInewlink");     /* for HERROR */
1585     int32       link_id;        /* access record id of new link */
1586     uint8      *buf       = NULL;            /* temp buffer */
1587     link_t     *t_link    = NULL;
1588     link_t     *ret_value = NULL; /* FAIL */
1589 
1590     /* set up new link record in memory */
1591     /* new link record */
1592     t_link = (link_t *) HDmalloc((uint32) sizeof(link_t));
1593 
1594     if (!t_link)
1595         HGOTO_ERROR(DFE_NOSPACE, NULL);
1596 
1597     t_link->block_list = (block_t *) HDmalloc((uint32) number_blocks
1598                                                 * sizeof(block_t));
1599     if (!t_link->block_list)
1600         HGOTO_ERROR(DFE_NOSPACE, NULL);
1601 
1602     t_link->next = NULL;
1603 
1604     /* get ready to write the new link to file */
1605     link_id = Hstartwrite(file_id, DFTAG_LINKED, link_ref, 2 + 2 * number_blocks);
1606     if (link_id == FAIL)
1607         HGOTO_ERROR(DFE_WRITEERROR, NULL);
1608 
1609     /* encode this block information for writing to the file */
1610     {   /* CC */
1611         int32 i;       /* temp int index */
1612         uint8      *p;          /* temp buffer ptr */
1613 
1614         p = buf = (uint8 *) HDmalloc((uint32) (2 + 2 * number_blocks));
1615         if (!buf)
1616             HGOTO_ERROR(DFE_NOSPACE, NULL);
1617 
1618         /* set up the record and write to file */
1619         t_link->nextref = 0;
1620         UINT16ENCODE(p, 0);
1621         t_link->block_list[0].ref = first_block_ref;
1622         UINT16ENCODE(p, first_block_ref);
1623 /* why is this first_block_ref = 0? */
1624         for (i = 1; i < number_blocks; i++)
1625           {     /* set up each block in this link */
1626               t_link->block_list[i].ref = 0;
1627               UINT16ENCODE(p, 0);
1628           }
1629     }   /* CC */
1630 
1631     /* write the link */
1632     if (Hwrite(link_id, 2 + 2 * number_blocks, buf) == FAIL)
1633         HGOTO_ERROR(DFE_WRITEERROR, NULL);
1634 
1635     /* close down acces to this block */
1636     Hendaccess(link_id);
1637 
1638     /* set return value */
1639     ret_value = t_link;
1640 
1641 done:
1642   if(ret_value == NULL)
1643     { /* Error condition cleanup */
1644         if (t_link->block_list != NULL)
1645             HDfree(t_link->block_list);
1646         if (t_link != NULL)
1647             HDfree(t_link);
1648     } /* end if */
1649 
1650   /* Normal function cleanup */
1651   if (buf != NULL)
1652       HDfree(buf);
1653 
1654   return ret_value;
1655 }   /* HLInewlink */
1656 
1657 /* ------------------------------ HLPinquire ------------------------------ */
1658 /*
1659 NAME
1660    HLPinquire -- Hinquire for linked blocks
1661 USAGE
1662    int32 HLPinquire(access_rec, fid, tag, ref, len, off, pos, acc, sp)
1663    access_t * access_rec;      IN:  access record to return info about
1664    uint16   * file;            OUT: file ID;
1665    uint16   * tag;             OUT: tag of info record;
1666    uint16   * ref;             OUT: ref of info record;
1667    int32    * len;             OUT: length of element;
1668    int32    * off;             OUT: offset of element -- meaningless
1669    int32    * pos;             OUT: current position in element;
1670    int16    * acc;             OUT: access mode;
1671    int16    * sp;              OUT: special code;
1672 RETURNS
1673    SUCCEED
1674 DESCRIPTION
1675    Return interesting information about a linked block element.
1676    NULL can be passed for any of the OUT parameters if their
1677    value is not needed.
1678 
1679 --------------------------------------------------------------------------- */
1680 int32
HLPinquire(accrec_t * access_rec,int32 * pfile_id,uint16 * ptag,uint16 * pref,int32 * plength,int32 * poffset,int32 * pposn,int16 * paccess,int16 * pspecial)1681 HLPinquire(accrec_t  *access_rec,
1682            int32     *pfile_id,
1683            uint16    *ptag,
1684            uint16    *pref,
1685            int32     *plength,
1686            int32     *poffset,
1687            int32     *pposn,
1688            int16     *paccess,
1689            int16     *pspecial)
1690 {
1691     CONSTR(FUNC, "HLPinquire");   /* for HERROR */
1692     uint16      data_tag, data_ref;  /* Tag/ref of the data in the file */
1693     linkinfo_t *info =          /* special information record */
1694         (linkinfo_t *) access_rec->special_info;
1695     int32   ret_value = SUCCEED;
1696 
1697     /* update the info for the dataset */
1698     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,NULL,NULL)==FAIL)
1699         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1700 
1701     /* fill in the variables if they are present */
1702     if (pfile_id)
1703         *pfile_id = access_rec->file_id;
1704     if (ptag)
1705         *ptag = data_tag;
1706     if (pref)
1707         *pref = data_ref;
1708     if (plength)
1709         *plength = info->length;
1710     if (poffset)
1711         *poffset = 0;   /* meaningless */
1712     if (pposn)
1713         *pposn = access_rec->posn;
1714     if (paccess)
1715         *paccess = (int16)access_rec->access;
1716     if (pspecial)
1717         *pspecial = (int16)access_rec->special;
1718 
1719 done:
1720   if(ret_value == FAIL)
1721     { /* Error condition cleanup */
1722 
1723     } /* end if */
1724 
1725   /* Normal function cleanup */
1726 
1727     return ret_value;
1728 }   /* HLPinquire */
1729 
1730 /* ----------------------------- HLPendaccess ----------------------------- */
1731 /*
1732 NAME
1733    HLPendacess -- close a linked block AID
1734 USAGE
1735    intn HLPendaccess(access_rec)
1736    access_t * access_rec;      IN:  access record to close
1737 RETURNS
1738    SUCCEED / FAIL
1739 DESCRIPTION
1740    Free up all of the space used to store information about a
1741    linked block element.  Information is flushed to disk as
1742    it is created so this routine does NOT have to write anything
1743    out.
1744 
1745 --------------------------------------------------------------------------- */
1746 intn
HLPendaccess(accrec_t * access_rec)1747 HLPendaccess(accrec_t * access_rec)
1748 {
1749     CONSTR(FUNC, "HLPendaccess");   /* for HERROR */
1750     filerec_t  *file_rec;           /* file record */
1751     intn      ret_value = SUCCEED;
1752 
1753     /* validate argument */
1754     if (access_rec == NULL)
1755         HGOTO_ERROR(DFE_ARGS, FAIL);
1756 
1757     /* convert file id to file record */
1758     file_rec = HAatom_object(access_rec->file_id);
1759     if (BADFREC(file_rec))
1760         HGOTO_ERROR(DFE_ARGS, FAIL);
1761 
1762     /* detach the special information record.
1763        If no more references to that, free the record */
1764     if (HLPcloseAID(access_rec) == FAIL)
1765         HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
1766 
1767     /* update file and access records */
1768     if (HTPendaccess(access_rec->ddid) == FAIL)
1769       HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1770 
1771     /* detach from the file */
1772     file_rec->attach--;
1773 
1774     /* free the access record */
1775     HIrelease_accrec_node(access_rec);
1776 
1777 done:
1778   if(ret_value == FAIL)
1779     { /* Error condition cleanup */
1780       if(access_rec!=NULL)
1781           HIrelease_accrec_node(access_rec);
1782     } /* end if */
1783 
1784   /* Normal function cleanup */
1785 
1786   return ret_value;
1787 }   /* HLPendaccess */
1788 
1789 /* ----------------------------- HLPcloseAID ------------------------------ */
1790 /*
1791 NAME
1792    HLPcloseAID -- close file but keep AID active
1793 USAGE
1794    int32 HLPcloseAID(access_rec)
1795    access_t * access_rec;      IN:  access record of file to close
1796 RETURNS
1797    SUCCEED / FAIL
1798 DESCRIPTION
1799    close the file currently being pointed to by this AID but
1800    do *NOT* free the AID.
1801 
1802    This is called by Hnextread() which reuses an AID to point to
1803    the 'next' object as requested.  If the current object was an
1804    linked object, the linked information needs to be closed before all
1805    reference to it is lost.
1806 
1807 ---------------------------------------------------------------------------*/
1808 int32
HLPcloseAID(accrec_t * access_rec)1809 HLPcloseAID(accrec_t * access_rec)
1810 {
1811 #ifdef LATER
1812     CONSTR(FUNC, "HLPcloseAID");    /* for HERROR */
1813 #endif /* LATER */
1814     linkinfo_t *info =          /* special information record */
1815         (linkinfo_t *) access_rec->special_info;
1816     int32      ret_value = SUCCEED;
1817 
1818     /* detach the special information record.
1819        If no more references to that, free the record */
1820     if (--(info->attached) == 0)
1821       {
1822           link_t     *t_link;   /* current link to free */
1823           link_t     *next;     /* next link to free */
1824 
1825           /* free the linked list of links/block tables */
1826           for (t_link = info->link; t_link; t_link = next)
1827             {
1828                 next = t_link->next;
1829                 HDfree(t_link->block_list);
1830                 HDfree(t_link);
1831             }
1832 
1833           HDfree(info);
1834           access_rec->special_info = NULL;
1835       }
1836 
1837 #ifdef LATER
1838 done:
1839 #endif /* LATER */
1840   if(ret_value == FAIL)
1841     { /* Error condition cleanup */
1842 
1843     } /* end if */
1844 
1845   /* Normal function cleanup */
1846 
1847     return ret_value;
1848 }   /* HLPcloseAID */
1849 
1850 /* ------------------------------- HLPinfo -------------------------------- */
1851 /*
1852 NAME
1853    HLPinfo -- return info about a linked block element
1854 USAGE
1855    int32 HLPinfo(access_rec, info_block)
1856    access_t        * access_rec;
1857    IN: access record of access element
1858    sp_info_block_t * info_block;
1859    OUT: information about the special element
1860 RETURNS
1861    SUCCEED / FAIL
1862 DESCRIPTION
1863    Return information about the given linked block.  Info_block is
1864    assumed to be non-NULL.
1865 
1866 --------------------------------------------------------------------------- */
1867 int32
HLPinfo(accrec_t * access_rec,sp_info_block_t * info_block)1868 HLPinfo(accrec_t * access_rec, sp_info_block_t * info_block)
1869 {
1870     CONSTR(FUNC, "HLPinfo");
1871     linkinfo_t *info =          /* special information record */
1872     (linkinfo_t *) access_rec->special_info;
1873     int32     ret_value = SUCCEED;
1874 
1875     /* validate access record */
1876     if (access_rec->special != SPECIAL_LINKED)
1877         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1878 
1879     /* fill in the info_block */
1880     info_block->key = SPECIAL_LINKED;
1881 
1882     info_block->first_len = info->first_length;
1883     info_block->block_len = info->block_length;
1884     info_block->nblocks = info->number_blocks;
1885 
1886 done:
1887   if(ret_value == FAIL)
1888     { /* Error condition cleanup */
1889 
1890     } /* end if */
1891 
1892   /* Normal function cleanup */
1893 
1894   return ret_value;
1895 }   /* HLPinfo */
1896 
1897 /*--------------------------------------------------------------------------
1898 NAME
1899    HLsetblockinfo -- set the block length of a linked-block element
1900 
1901 USAGE
1902    intn HLsetblockinfo(
1903    int32 aid		IN: access record id
1904    int32 block_size	IN: length to be used for each linked-block
1905    int32 num_blocks	IN: number of blocks the element will have
1906 
1907 RETURNS
1908    SUCCEED / FAIL
1909 
1910 DESCRIPTION
1911    HLsetblockinfo sets (accrec_t).block_size and (accrec_t).num_blocks
1912    to block_size and num_blocks, respectively.  An error will occur, if
1913    either of the parameters is a 0 or a negative number, that is not
1914    -1, which is used to indicate that the respective field is not to be
1915    changed.
1916 
1917    In the library, this routine is used by:
1918 	VSsetblocksize
1919 	VSsetnumblocks
1920 
1921 MODIFICATION
1922    BMR - added in June 2001 to fix bug# 267
1923 
1924 --------------------------------------------------------------------------*/
1925 intn
HLsetblockinfo(int32 aid,int32 block_size,int32 num_blocks)1926 HLsetblockinfo(int32 aid,	/* access record id */
1927               int32 block_size, /* length to be used for each linked-block */
1928               int32 num_blocks) /* number of blocks the element will have */
1929 {
1930     CONSTR(FUNC, "HLsetblockinfo");  	/* for HERROR */
1931     accrec_t   *access_rec;               /* access record */
1932     intn	ret_value = SUCCEED;
1933 
1934     /* clear error stack */
1935     HEclear();
1936 
1937     /* validate aid */
1938     if (HAatom_group(aid)!=AIDGROUP)
1939         HGOTO_ERROR(DFE_ARGS, FAIL);
1940 
1941     /* block_size and num_blocks should be either -1, to keep the original
1942        values, or positive values to change the block size and/or the
1943        number of blocks */
1944     if ((block_size <= 0 && block_size != -1) ||
1945         (num_blocks <= 0 && num_blocks != -1))
1946         HGOTO_ERROR(DFE_ARGS, FAIL);
1947 
1948     /* get the access record */
1949     if ((access_rec = HAatom_object(aid)) == NULL)
1950         HGOTO_ERROR(DFE_ARGS, FAIL);
1951 
1952     /* If this element is already stored as linked-block, do not allow
1953        to change the block info, ignore the request to change. */
1954     if (access_rec->special != SPECIAL_LINKED)
1955     {
1956 	/* Set the linked-block size, if requested */
1957 	if (block_size != -1)
1958 	    access_rec->block_size = block_size;
1959 
1960 	/* Set the number of blocks in each block table, if requested */
1961 	if (num_blocks != -1)
1962 	    access_rec->num_blocks = num_blocks;
1963     }
1964 
1965 done:
1966     if(ret_value == FAIL)
1967     { /* Error condition cleanup */
1968     } /* end if */
1969 
1970   /* Normal function cleanup */
1971     return ret_value;
1972 }       /* end HLsetblockinfo */
1973 
1974 /*--------------------------------------------------------------------------
1975 NAME
1976    HLgetblockinfo -- get the block size and the number of blocks of a
1977 		    linked-block element
1978 
1979 USAGE
1980    intn HLgetblockinfo(aid, block_size, num_blocks)
1981    int32  aid		IN: access record id
1982    int32* block_size	OUT: the returned block size of each linked-block
1983    int32* num_blocks	OUT: the returned number of blocks of the element
1984 
1985 RETURNS
1986    SUCCEED / FAIL
1987 
1988 DESCRIPTION
1989    HLgetblockinfo retrieves the values of (accrec_t).block_size and
1990    (accrec_t).num_blocks to block_size and num_blocks, respectively.
1991    A NULL can be passed in for an unwanted value.
1992 
1993    In the library, this routine is used by:
1994 	VSgetblockinfo
1995 
1996 MODIFICATION
1997    BMR - added in June 2001 to fix bug# 267
1998 
1999 --------------------------------------------------------------------------*/
2000 intn
HLgetblockinfo(int32 aid,int32 * block_size,int32 * num_blocks)2001 HLgetblockinfo(int32 aid,	/* access record id */
2002               int32* block_size, /* length being used for each linked-block */
2003               int32* num_blocks) /* number of blocks the element will have */
2004 {
2005     CONSTR(FUNC, "HLgetblockinfo");  /* for HERROR */
2006     accrec_t   *access_rec;               /* access record */
2007     intn	ret_value = SUCCEED;
2008 
2009     /* clear error stack */
2010     HEclear();
2011 
2012     /* get the access record */
2013     if ((access_rec = HAatom_object(aid)) == NULL)
2014         HGOTO_ERROR(DFE_ARGS, FAIL);
2015 
2016     /* get the linked-block size and the number of linked-blocks if requested */
2017     if (block_size != NULL)
2018         *block_size = access_rec->block_size;
2019     if (num_blocks != NULL)
2020         *num_blocks = access_rec->num_blocks;
2021 
2022 done:
2023     if(ret_value == FAIL)
2024     { /* Error condition cleanup */
2025 
2026     } /* end if */
2027 
2028   /* Normal function cleanup */
2029     return ret_value;
2030 }       /* end HLgetblockinfo */
2031 
2032