home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / hdf / unix / hdf3_2r2 / src / hblocks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-29  |  37.3 KB  |  1,241 lines

  1. /***************************************************************************
  2. *
  3. *
  4. *                         NCSA HDF version 3.2r2
  5. *                            October 30, 1992
  6. *
  7. * NCSA HDF Version 3.2 source code and documentation are in the public
  8. * domain.  Specifically, we give to the public domain all rights for future
  9. * licensing of the source code, all resale rights, and all publishing rights.
  10. *
  11. * We ask, but do not require, that the following message be included in all
  12. * derived works:
  13. *
  14. * Portions developed at the National Center for Supercomputing Applications at
  15. * the University of Illinois at Urbana-Champaign, in collaboration with the
  16. * Information Technology Institute of Singapore.
  17. *
  18. * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE
  19. * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
  20. * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
  21. *
  22. ****************************************************************************
  23. */
  24.  
  25. #ifdef RCSID
  26. static char RcsId[] = "@(#)$Revision: 1.1 $";
  27. #endif
  28. /*
  29. $Header: /hdf/hdf/v3.2r2/src/RCS/hblocks.c,v 1.1 1992/08/25 21:40:44 koziol beta koziol $
  30.  
  31. $Log: hblocks.c,v $
  32.  * Revision 1.1  1992/08/25  21:40:44  koziol
  33.  * Initial revision
  34.  *
  35. */
  36. /*LINTLIBRARY*/
  37. /*+ hblocks .c
  38.  routines to implement linked-block elements
  39. +*/
  40. /*
  41. [[ (since we no longer have a way to generate special tags from
  42.     normal tags, we no longer provide the conversion. LCC 7jun91)
  43.   Linked element in HDF files created in two ways
  44.   -- created from the start or
  45.   -- converted from a normal data element
  46. ]]
  47.  
  48.   A linked-block element is a special element.
  49. [[ (This part is not true any more, LCC 7jun91)
  50.   Special elements are
  51.   flagged with a set high-bit in their tag.  Thus, a tag t has
  52.   BASETAG == t & 0x7f and is a special tag if t & 0x80 != 0x00
  53. ]]
  54.   The first 16 bits of the meta-element that this tag/ref points to
  55.   tells us what type of special element this is.  If these 16 bits is
  56.   SPECIAL_LINKED, then it contains information about the linked blocks.
  57.   After this 16 bits, 32 bit which is the length of each block, after
  58.   which is the information header:
  59.  
  60.   -----------------------------------------------------------------------
  61.   | # blocks in | tag/ref of | tag/ref of blocks list .......          |
  62.   | this header | next header|                                         |
  63.   -----------------------------------------------------------------------
  64. */
  65.  
  66. #include "hdf.h"
  67. #include "hfile.h"
  68. #include "herr.h"
  69.  
  70. /* block_t - record of a linked block. contains the tag and ref of the
  71.    data elt that forms the linked block */
  72.  
  73. typedef struct block_t {
  74.     uint16 ref;                        /* ref of the linked block */
  75. } block_t;
  76.  
  77. /* link_t - a linked list block table.
  78.    Very similar to the dd block structure */
  79.  
  80. typedef struct link_t {
  81.     uint16 nextref;            /* ref of the next block table */
  82.     struct link_t *next;       /* ptr to the next block table */
  83.     struct block_t *block_list;     /* ptr to the block list for this table */
  84. } link_t;
  85.  
  86. /* information on this special linked block data elt */
  87.  
  88. typedef struct linkinfo_t {
  89.     int attached;              /* how many access records refer to this elt */
  90.     int32 length;              /* the actual length of the data elt */
  91. #ifndef oldspecial
  92.     int32 first_length;                /* length of first block */
  93. #endif
  94.     int32 block_length;                /* the length of the remaining blocks */
  95.     int32 number_blocks;       /* total number of blocks in each link/block
  96.                                   table */
  97.     uint16 link_ref;           /* ref of the first block table structure */
  98.     struct link_t *link;       /* pointer to the first block table */
  99.     struct link_t *last_link;  /* pointer to the last block table */
  100. } linkinfo_t;
  101.  
  102. /* private functions */
  103.  
  104. PRIVATE int32 HLIstaccess PROTO((accrec_t *access_rec, int16 access));
  105. PRIVATE int32 HLIstread PROTO((accrec_t *access_rec));
  106. PRIVATE int32 HLIstwrite PROTO((accrec_t *access_rec));
  107. PRIVATE link_t *HLIgetlink PROTO((int32 file_id, uint16 ref, \
  108.                         int32 number_blocks));
  109. PRIVATE int32 HLIseek PROTO((accrec_t *access_rec, int32 offset, int origin));
  110. PRIVATE int32 HLIread PROTO((accrec_t *access_rec, int32 length, uint8 *data));
  111. PRIVATE int32 HLIwrite PROTO((accrec_t *access_rec, int32 length, uint8 *data));
  112. PRIVATE link_t *HLInewlink PROTO((int32 file_id, int32 number_blocks,
  113.                           uint16 link_ref, uint16 first_block_ref));
  114. PRIVATE int32 HLIinquire PROTO((accrec_t *access_rec, int32 *pfile_id, \
  115.                 uint16 *ptag, uint16 *pref, int32 *plength, int32 *poffset, \
  116.                 int32 *pposn, int16 *paccess, int16 *pspecial));
  117. PRIVATE int32 HLIendaccess PROTO((accrec_t *access_rec));
  118.  
  119. /* the accessing function table for linked blocks */
  120.  
  121. int32 (*linked_funcs[])() = {
  122.     HLIstread,
  123.     HLIstwrite,
  124.     HLIseek,
  125.     HLIinquire,
  126.     HLIread,
  127.     HLIwrite,
  128.     HLIendaccess,
  129. };
  130.  
  131. /*- HLcreate
  132.  creates a linked block special data element
  133.  Took out all portions for converting a normal data elt to
  134.  a linked block data elt.  LCC 11jun91
  135. -*/
  136. #ifdef PROTOTYPE
  137. int32 HLcreate(int32 file_id, uint16 tag, uint16 ref, int32 block_length,
  138.               int32 number_blocks)
  139. #else
  140. int32 HLcreate(file_id, tag, ref, block_length, number_blocks)
  141.     int32 file_id;
  142.     uint16 tag;
  143.     uint16 ref;
  144.     int32 block_length;
  145.     int32 number_blocks;
  146. #endif
  147. {
  148.     char *FUNC="HLcreate";     /* for HERROR */
  149.     filerec_t *file_rec;       /* file record */
  150.     accrec_t *access_rec;      /* access record */
  151.     int slot;                  /* slot in access records */
  152.     dd_t *dd;                  /* ptr to created dd */
  153.     ddblock_t *data_block;     /* dd lbock of the data dd */
  154.     int32 data_idx;            /* dd list index of data dd */
  155.     linkinfo_t *info;          /* information for the linked blocks elt */
  156.     uint16 link_ref;           /* the ref of the link structure
  157.                                   (block table) */
  158. #ifndef oldspecial
  159.     dd_t *data_dd;             /* dd of existing regular element */
  160.     uint16 special_tag;                /* special version of this tag */
  161. #endif
  162.  
  163.     /* clear error stack and validate file record id */
  164.  
  165.     HEclear();
  166.     file_rec = FID2REC(file_id);
  167.     if (!file_rec ||
  168.        file_rec->refcount == 0 ||
  169.        block_length < 0 ||
  170.        number_blocks < 0
  171. #ifndef oldspecial
  172.        || SPECIALTAG(tag)
  173.        || (special_tag = MKSPECIALTAG(tag)) == DFTAG_NULL
  174. #endif
  175.        ) {
  176.        HERROR(DFE_ARGS);
  177.        return FAIL;
  178.     }
  179.     if (!(file_rec->access & DFACC_WRITE)) {
  180.        HERROR(DFE_DENIED);
  181.        return FAIL;
  182.     }
  183.  
  184.     /* get empty slot in access records */
  185.  
  186.     slot = HIget_access_slot();
  187.     if (slot == FAIL) {
  188.        HERROR(DFE_TOOMANY);
  189.        return FAIL;
  190.     }
  191.     access_rec = &access_records[slot];
  192.  
  193.     /* update maxref if necessary */
  194.  
  195.     if (ref > file_rec->maxref)
  196.        file_rec->maxref = ref;
  197.  
  198.     /* search for identical dd */
  199.     if (HIlookup_dd(file_rec, tag, ref, &data_block, &data_idx) != FAIL) {
  200. #ifndef oldspecial
  201.        data_dd = &(data_block->ddlist[data_idx]);
  202.        if (SPECIALTAG(data_dd->tag)) {
  203.            HERROR(DFE_CANTMOD);
  204.            access_rec->used = FALSE;
  205.            return FAIL;
  206.        }
  207.     } else {
  208.        data_dd = (dd_t *) NULL;
  209. #else
  210.        HERROR(DFE_CANTMOD);
  211.        access_rec->used = FALSE;
  212.         return FAIL;
  213. #endif
  214.     }
  215.  
  216.     /* search for the empty dd to put new dd */
  217.  
  218.     if (HIlookup_dd(file_rec, DFTAG_NULL, DFREF_WILDCARD, &file_rec->null_block,
  219.                  &file_rec->null_idx) == FAIL) {
  220.        if (HInew_dd_block(file_rec, FILE_NDDS(file_rec), FUNC) == FAIL) {
  221.            HERROR(DFE_NOFREEDD);
  222.            access_rec->used = FALSE;
  223.            return FAIL;
  224.        } else {
  225.            access_rec->block = file_rec->ddlast;
  226.            access_rec->idx = 0;
  227.        }
  228.     } else {
  229.       access_rec->block = file_rec->null_block;
  230.       access_rec->idx   = file_rec->null_idx;
  231.     }
  232.     dd = &access_rec->block->ddlist[access_rec->idx];
  233.  
  234. #ifndef oldspecial
  235.     if (data_dd) {
  236.  
  237.        /* remove old tag from hash table */
  238.        if(HIdel_hash_dd(file_rec, data_dd->tag, data_dd->ref) == FAIL) 
  239.          return FAIL;
  240.  
  241.        data_dd->tag = DFTAG_LINKED;
  242.        if (HIupdate_dd(file_rec, data_block, data_idx, FUNC) == FAIL) {
  243.            access_rec->used = FALSE;
  244.            return FAIL;
  245.        }
  246.  
  247.        /* update hash table */
  248.        if(HIadd_hash_dd(file_rec, data_dd->tag, data_dd->ref, data_block, 
  249.                         data_idx) == FAIL) 
  250.          return FAIL;
  251.  
  252.     }
  253. #endif
  254.  
  255.     /* write the special info structure to fill */
  256.  
  257.     link_ref = Hnewref(file_id);
  258.     dd->length = 16;
  259.  
  260.     /* write new dd at the end of file */
  261.  
  262.     if (HI_SEEKEND(file_rec->file) == FAIL) {
  263.        HERROR(DFE_SEEKERROR);
  264.        access_rec->used = FALSE;
  265.        return FAIL;
  266.     }
  267.     dd->offset = HI_TELL(file_rec->file);
  268.     access_rec->special_info = (VOIDP) HDgetspace((uint32)sizeof(linkinfo_t));
  269.     if (!access_rec->special_info) {
  270.        HERROR(DFE_NOSPACE);
  271.        access_rec->used = FALSE;
  272.        return FAIL;
  273.     }
  274.  
  275.     info = (linkinfo_t *) access_rec->special_info;
  276.     info->attached = 1;
  277. #ifndef oldspecial
  278.     info->length = data_dd ? data_dd->length : 0;
  279.     info->first_length = data_dd ? data_dd->length : block_length;
  280. #else
  281.     info->length = 0;
  282. #endif
  283.     info->block_length = block_length;
  284.     info->number_blocks = number_blocks;
  285.  
  286.     {
  287.        uint8 *p;
  288.        p = tbuf;
  289.        UINT16ENCODE(p, SPECIAL_LINKED);
  290.        INT32ENCODE(p, info->length);
  291.        INT32ENCODE(p, block_length);
  292.        INT32ENCODE(p, number_blocks);
  293.        UINT16ENCODE(p, link_ref); /* link_ref */
  294.     }
  295.     if (HI_WRITE(file_rec->file, tbuf, dd->length) == FAIL) {
  296.        HERROR(DFE_WRITEERROR);
  297.        access_rec->used = FALSE;
  298.        return FAIL;
  299.     }
  300.     dd->tag = special_tag;
  301.     dd->ref = ref;
  302.  
  303.     /* allocate info structure and file it in */
  304.     info->link = HLInewlink(file_id, number_blocks, link_ref,
  305. #ifndef oldspecial
  306.                            data_dd ? data_dd->ref : 0
  307. #else
  308.                            0
  309. #endif
  310.                            );
  311.     if (!info->link) {
  312.        access_rec->used = FALSE;
  313.        return FAIL;
  314.     }
  315.     info->link_ref = link_ref;
  316.  
  317.     /* update dd list in file */
  318.     if (HIupdate_dd(file_rec, access_rec->block, access_rec->idx, FUNC) ==
  319.        FAIL) {
  320.        access_rec->used = FALSE;
  321.         return FAIL;
  322.     }
  323.  
  324.     /* update hash table */
  325.     if(HIadd_hash_dd(file_rec, dd->tag, dd->ref, access_rec->block, 
  326.                      access_rec->idx) == FAIL) 
  327.       return FAIL;
  328.  
  329.     /* update access record and file record */
  330.  
  331.     access_rec->special_func = linked_funcs;
  332.     access_rec->special = SPECIAL_LINKED;
  333.     access_rec->posn = 0;
  334.     access_rec->access = DFACC_WRITE;
  335.     access_rec->file_id = file_id;
  336.     file_rec->attach++;
  337.  
  338.     return ASLOT2ID(slot);
  339. }
  340.  
  341.  
  342. /*---------------------------------------------------------------------------
  343.  HDinqblockinfo - Given an aid, return special info for linked-block
  344.           element in space provided.  This function works like
  345.           HDinquire().
  346. ---------------------------------------------------------------------------*/
  347. #ifdef PROTOTYPE
  348. int HDinqblockinfo(int32 aid, int32 *length, int32 *first_length,
  349.                 int32 *block_length, int32 *number_blocks)
  350. #else
  351. int HDinqblockinfo(aid, length, first_length, block_length, number_blocks)
  352. int32 aid;
  353. int32 *length, *first_length, *block_length, *number_blocks;
  354. #endif /* PROTOTYPE */
  355. {
  356.     accrec_t *arec;
  357.     char *FUNC="HDinqblockinfo";
  358.  
  359.  
  360.     HEclear();
  361.     if ((arec = AID2REC(aid)) == (accrec_t *)NULL) {
  362.         HERROR(DFE_BADAID);
  363.         return (FAIL);
  364.     }
  365.  
  366.     if (arec->special != SPECIAL_LINKED) {
  367.         HERROR(DFE_ARGS);
  368.         return (FAIL);
  369.     }
  370.  
  371.     if(length) *length = ((linkinfo_t *)(arec->special_info))->length;
  372.     if(first_length)
  373.         *first_length = ((linkinfo_t *)(arec->special_info))->first_length;
  374.     if(block_length)
  375.         *block_length = ((linkinfo_t *)(arec->special_info))->block_length;
  376.     if(number_blocks)
  377.         *number_blocks = ((linkinfo_t *)(arec->special_info))->number_blocks;
  378.  
  379.     return(SUCCEED);
  380. }
  381.  
  382.  
  383.  
  384. /*- HLIstaccess
  385.  start access to the special linked block data elt
  386. -*/
  387. #ifdef PROTOTYPE
  388. PRIVATE int32 HLIstaccess(accrec_t *access_rec, int16 access)
  389. #else
  390. PRIVATE int32 HLIstaccess(access_rec, access)
  391.     accrec_t *access_rec;      /* access record */
  392.     int16 access;               /* access mode */
  393. #endif
  394. {
  395.     char *FUNC="HLIstaccess";  /* for HERROR */
  396.     filerec_t *file_rec;       /* file record */
  397.     linkinfo_t *info;          /* information about data elt */
  398.     dd_t *dd;                  /* dd for the special elt */
  399.  
  400.     /* validate file record id */
  401.  
  402.     file_rec = FID2REC(access_rec->file_id);
  403.     if (!file_rec || file_rec->refcount == 0 || !(file_rec->access & access)) {
  404.        HERROR(DFE_ARGS);
  405.        return FAIL;
  406.     }
  407.  
  408.     /* set up some data in access record */
  409.  
  410.     access_rec->special = SPECIAL_LINKED;
  411.     access_rec->posn = 0;
  412.     access_rec->access = access;
  413.     dd = &access_rec->block->ddlist[access_rec->idx];
  414.  
  415.     /* if the special information are already in some other acc elt,
  416.        copy it */
  417.  
  418.     access_rec->special_info = HIgetspinfo(access_rec, dd->tag, dd->ref);
  419.     if (access_rec->special_info) {
  420.        ((linkinfo_t *)access_rec->special_info)->attached++;
  421.         file_rec->attach++;
  422.        return ASLOT2ID(access_rec-access_records);
  423.     }
  424.  
  425.     /* read in the information from file */
  426.  
  427.     if (HI_SEEK(file_rec->file, dd->offset+2) == FAIL) {
  428.        HERROR(DFE_SEEKERROR);
  429.        return FAIL;
  430.     }
  431.     if (HI_READ(file_rec->file, tbuf, 14) == FAIL) {
  432.        HERROR(DFE_READERROR);
  433.        return FAIL;
  434.     }
  435.     access_rec->special_info = (VOIDP) HDgetspace((uint32)sizeof(linkinfo_t));
  436.     info = (linkinfo_t *) access_rec->special_info;
  437.     if (!info) {
  438.        HERROR(DFE_NOSPACE);
  439.        return FAIL;
  440.     }
  441.     {
  442.     uint8 *p = tbuf;
  443.     INT32DECODE(p, info->length);
  444.     INT32DECODE(p, info->block_length);
  445.     INT32DECODE(p, info->number_blocks);
  446.     UINT16DECODE(p, info->link_ref);
  447.     }
  448.  
  449.     /* set up the block tables of the information */
  450.  
  451.     info->link = HLIgetlink(access_rec->file_id,
  452.                            info->link_ref, info->number_blocks);
  453.     if (!info->link) {
  454.        HDfreespace((VOIDP) info);
  455.        return FAIL;
  456.     }
  457. #ifndef oldspecial
  458.     if (info->link->block_list[0].ref) {
  459.        info->first_length = Hlength(access_rec->file_id,
  460.                                     DFTAG_LINKED,
  461.                                     info->link->block_list[0].ref);
  462.        if (info->first_length == FAIL) {
  463.            HERROR(DFE_INTERNAL);
  464.            HDfreespace((VOIDP) info->link);
  465.            HDfreespace((VOIDP) info);
  466.            return FAIL;
  467.        }
  468.     } else {
  469.        info->first_length = info->block_length;
  470.     }
  471. #endif
  472.  
  473.     info->last_link = info->link;
  474.     while (info->last_link->nextref != 0) {
  475.        info->last_link->next = HLIgetlink(access_rec->file_id,
  476.                                           info->last_link->nextref,
  477.                                           info->number_blocks);
  478.        if (!info->last_link->next) {
  479.             link_t *l, *next;
  480.            for (l=info->link; l; l=next) {
  481.                next = l->next;
  482.                if (l->block_list) HDfreespace((VOIDP) l->block_list);
  483.                HDfreespace((VOIDP)l);
  484.            }
  485.            HDfreespace((VOIDP) info);
  486.            return FAIL;
  487.        }
  488.        info->last_link = info->last_link->next;
  489.     }
  490.     /* update data */
  491.  
  492.     info->attached = 1;
  493.     file_rec->attach++;
  494.  
  495.     return ASLOT2ID(access_rec - access_records);
  496. }
  497.  
  498. /*- HLIstread
  499.  start read on special linked block data element
  500.  just calls HLIstaccess
  501. -*/
  502. #ifdef PROTOTYPE
  503. PRIVATE int32 HLIstread(accrec_t *access_rec)
  504. #else
  505. PRIVATE int32 HLIstread(access_rec)
  506.     accrec_t *access_rec;      /* access record */
  507. #endif
  508. {
  509.     return HLIstaccess(access_rec, DFACC_READ);
  510. }
  511.  
  512. /*- HLKIstwrite
  513.  start write on a special linked block data element
  514.  calls HLIstaccess
  515. -*/
  516. #ifdef PROTOTYPE
  517. PRIVATE int32 HLIstwrite(accrec_t *access_rec)
  518. #else
  519. PRIVATE int32 HLIstwrite(access_rec)
  520.     accrec_t *access_rec;
  521. #endif
  522. {
  523.     return HLIstaccess(access_rec, DFACC_WRITE);
  524. }
  525.  
  526. /*- HLIgetlink
  527.  get link information
  528. -*/
  529. #ifdef PROTOTYPE
  530. PRIVATE link_t *HLIgetlink(int32 file_id, uint16 ref, int32 number_blocks)
  531. #else
  532. PRIVATE link_t * HLIgetlink(file_id, ref, number_blocks)
  533.     int32 file_id;             /* file record id */
  534.     uint16 ref;                        /* tag ref of block table elt */
  535.     int32 number_blocks;       /* number of blocks in this link elt */
  536. #endif
  537. {
  538.     char *FUNC="HLIgetlink";   /* for HERROR */
  539.     int32 access_id;           /* access record id */
  540.     uint8 *buffer;
  541.     uint16 tag = DFTAG_LINKED;
  542.  
  543.     /* allocate necessary memory for block table */
  544.  
  545.     link_t *link = (link_t *) HDgetspace((uint32)sizeof(link_t));
  546.     if (!link) {
  547.        HERROR(DFE_NOSPACE);
  548.        return (link_t *) NULL;
  549.     }
  550.     link->block_list = (block_t*) HDgetspace((uint32)number_blocks
  551.                                         * sizeof(block_t));
  552.     if (!link) {
  553.        HDfreespace((VOIDP) link);
  554.        HERROR(DFE_NOSPACE);
  555.        return (link_t *)NULL;
  556.     }
  557.     link->next = (link_t *) NULL;
  558.  
  559.     /* read block table into buffer */
  560.  
  561.     buffer = (uint8 *) HDgetspace((uint32)(2 + 2*number_blocks));
  562.     if (!buffer) {
  563.        HERROR(DFE_NOSPACE);
  564.        return (link_t *) NULL;
  565.     }
  566.     access_id = Hstartread(file_id, tag, ref);
  567.     if (access_id == FAIL ||
  568.        Hread(access_id, 2+2*number_blocks, buffer) == FAIL) {
  569.        HERROR(DFE_READERROR);
  570.        return (link_t *) NULL;
  571.     }
  572. {
  573.     register int32 i;
  574.     uint8 *p = buffer;
  575.     UINT16DECODE(p, link->nextref);
  576.     for (i=0; i<number_blocks; i++) {
  577.        UINT16DECODE(p, link->block_list[i].ref);
  578.     }
  579. }
  580.     Hendaccess(access_id);
  581.  
  582.     return link;
  583. }
  584.  
  585. /*- HLIseek
  586.  set position of next access into data elt
  587. -*/
  588. #ifdef PROTOTYPE
  589. PRIVATE int32 HLIseek(accrec_t *access_rec, int32 offset, int origin)
  590. #else
  591. PRIVATE int32 HLIseek(access_rec, offset, origin)
  592.     accrec_t *access_rec;
  593.     int32 offset;
  594.     int origin;
  595. #endif
  596. {
  597.     char *FUNC="HLIseek";      /* for HERROR */
  598.  
  599.     /* validate access record */
  600.  
  601.     if (access_rec->special != SPECIAL_LINKED) {
  602.        HERROR(DFE_INTERNAL);
  603.        return FAIL;
  604.     }
  605.  
  606.     /* adjust the offset according to origin and validate */
  607.  
  608.     /* there is no upper bound to posn */
  609.  
  610.     if (origin == DF_CURRENT) offset += access_rec->posn;
  611.     if (origin == DF_END)
  612.        offset += ((linkinfo_t *)(access_rec->special_info))->length;
  613.     if (offset < 0) {
  614.        HERROR(DFE_RANGE);
  615.        return FAIL;
  616.     }
  617.  
  618.     /* set position */
  619.     access_rec->posn = offset;
  620.  
  621.     return SUCCEED;
  622. }
  623.  
  624. /*- HLIread
  625.  read data from elt into data buffer
  626. -*/
  627. #ifdef PROTOTYPE
  628. PRIVATE int32 HLIread(accrec_t *access_rec, int32 length, uint8 *data)
  629. #else
  630. PRIVATE int32 HLIread(access_rec, length, data)
  631.     accrec_t *access_rec;      /* access record */
  632.     int32 length;              /* length of data to read */
  633.     uint8 *data;               /* buffer to read data into */
  634. #endif
  635. {
  636.     char *FUNC="HLIread";      /* for HERROR */
  637.  
  638.     /* information record for this special data elt */
  639.  
  640.     linkinfo_t *info = (linkinfo_t*)(access_rec->special_info);
  641.  
  642.     /* block table record */
  643.  
  644.     link_t *link = info->link;
  645.  
  646.     /* relative position in linked block of data elt */
  647.  
  648.     int32 relative_posn = access_rec->posn;
  649.  
  650.     int32 block_idx;             /* block table index of current block */
  651. #ifndef oldspecial
  652.     int32 current_length;      /* length of current block */
  653. #endif
  654.     int32 nbytes = 0;           /* # bytes read on any single Hread() */
  655.     int32 bytes_read = 0;       /* total # bytes read for this call of HLIread*/
  656.  
  657.     /* validate length */
  658.  
  659.     if (length == 0) length = info->length - access_rec->posn;
  660.     else
  661. /*      if (length < 0 || access_rec->posn + length > info->length) {*/
  662.         if (length < 0) {
  663.            HERROR(DFE_RANGE);
  664.            return FAIL;
  665.         }
  666.     if (access_rec->posn + length > info->length)
  667.         length = info->length - access_rec->posn;
  668.  
  669.     /* search for linked block to start reading from */
  670.  
  671. #ifndef oldspecial
  672.     if (relative_posn < info->first_length) {
  673.        block_idx = 0;
  674.        current_length = info->first_length;
  675.     } else {
  676.        relative_posn -= info->first_length;
  677.        block_idx = relative_posn / info->block_length + 1;
  678.        relative_posn %= info->block_length;
  679.        current_length = info->block_length;
  680.     }
  681. #else
  682.     block_idx = relative_posn / info->block_length + 1;
  683.     relative_posn %= info->block_length;
  684. #endif
  685.  
  686.     {
  687.         register int32 i;
  688.        for (i=0; i<block_idx/info->number_blocks; i++) {
  689.            if (!link) {
  690.                HERROR(DFE_INTERNAL);
  691.                return FAIL;
  692.            }
  693.            link = link->next;
  694.        }
  695.     }
  696.     block_idx %= info->number_blocks;
  697.  
  698.     /* found the starting block, now read in the data */
  699.  
  700.     do {
  701.        register int32 remaining = /* remaining data in current block */
  702. #ifndef oldspecial
  703.            current_length
  704. #else
  705.            info->block_length
  706. #endif
  707.                - relative_posn;
  708.  
  709.        /* read in the data in this block */
  710.  
  711.        if (remaining > length) remaining = length;
  712.        if (link->block_list[block_idx].ref != 0) {
  713.            int32 access_id;    /* access record id for this block */
  714.            block_t *current_block = /* record on the current block */
  715.                &(link->block_list[block_idx]);
  716.  
  717.            access_id = Hstartread(access_rec->file_id,
  718.                                   DFTAG_LINKED,
  719.                                   current_block->ref);
  720.            if (access_id == (int32) FAIL ||
  721.                    (relative_posn &&
  722.                    (int32)FAIL == Hseek(access_id, relative_posn, DF_START)) ||
  723.                    (int32)FAIL == (nbytes = Hread(access_id, remaining, data))) {
  724.                HERROR(DFE_READERROR);
  725.                return FAIL;
  726.            }
  727.            bytes_read += nbytes;
  728.            Hendaccess(access_id);
  729.  
  730.        } else {
  731.  
  732.            /*if block is missing, fill this part of buffer with zero's */
  733.  
  734.             register int32 i;
  735.            for (i=0; i<remaining; i++)
  736.                data[i] = '\0';
  737.             bytes_read += nbytes;
  738.        }
  739.  
  740.        /* move variables for the next block */
  741.  
  742.        data +=remaining;
  743.        length -= remaining;
  744.        if (length > 0 && ++block_idx >= info->number_blocks) {
  745.            block_idx = 0;
  746.            link = link->next;
  747.            if (!link) {
  748.                HERROR(DFE_INTERNAL);
  749.                return FAIL;
  750.            }
  751.        }
  752.        relative_posn = 0;
  753. #ifndef oldspecial
  754.        current_length = info->block_length;
  755. #endif
  756.     } while (length > 0);      /* if still somemore to read in, repeat */
  757.  
  758.     return bytes_read;
  759. }
  760.  
  761. /*- HLIwrite
  762.  write out data into linked block data elt
  763. -*/
  764. #ifdef PROTOTYPE
  765. PRIVATE int32 HLIwrite(accrec_t *access_rec, int32 length, uint8 *data)
  766. #else
  767. PRIVATE int32 HLIwrite(access_rec, length, data)
  768.     accrec_t *access_rec;      /* access record */
  769.     int32 length;              /* length of data */
  770.     uint8 *data;                        /* data buffer to write from */
  771. #endif
  772. {
  773.     char *FUNC="HLIwrite";     /* for HERROR */
  774.     filerec_t *file_rec =      /* file record */
  775.        FID2REC(access_rec->file_id);
  776.     dd_t *info_dd =                    /* dd of the special info record */
  777.         &(access_rec->block->ddlist[access_rec->idx]);
  778.     linkinfo_t *info =         /* linked blocks information record */
  779.        (linkinfo_t*)(access_rec->special_info);
  780.     link_t *link =             /* ptr to link block table */
  781.        info->link;
  782.     int32 relative_posn =      /* relative position in linked block */
  783.        access_rec->posn;
  784.     int32 block_idx;           /* block table index of current block */
  785.     link_t *prev_link =        /* ptr to block table before
  786.                                   current block table.
  787.                                   for groking the offset of
  788.                                   current block table */
  789.        NULL;
  790. #ifndef oldspecial
  791.     int32 current_length;      /* length of current block */
  792. #endif
  793.     int32 nbytes = 0;           /* #bytes written by any single Hwrite */
  794.     int32 bytes_written = 0;    /* total #bytes written by HLIwrite */
  795.  
  796.     /* validate length and file records */
  797.  
  798.     if (length < 0) {
  799.        HERROR(DFE_RANGE);
  800.        return FAIL;
  801.     }
  802.     if (file_rec == (filerec_t *) NULL || file_rec->refcount == 0) {
  803.        HERROR(DFE_INTERNAL);
  804.        return FAIL;
  805.     }
  806.  
  807.     /* determine linked block and position to start writing into */
  808.  
  809.     /* determine where to start.  Setup missing block tables
  810.        along the way. */
  811.  
  812. #ifndef oldspecial
  813.     if (relative_posn < info->first_length) {
  814.        block_idx = 0;
  815.        current_length = info->first_length;
  816.     } else {
  817.        relative_posn -= info->first_length;
  818.        block_idx = relative_posn / info->block_length + 1;
  819.        relative_posn %= info->block_length;
  820.        current_length = info->block_length;
  821.     }
  822. #else
  823.     block_idx = relative_posn / info->block_length + 1;
  824.     relative_posn %= info->block_length;
  825. #endif
  826.     {
  827.        /* follow the links of block tables and create missing
  828.           block tabels along the way */
  829.  
  830.         register int32 num_links;        /* number of links to follow */
  831.  
  832.        for (num_links=block_idx/info->number_blocks;
  833.             num_links>0;
  834.             num_links--) {
  835.            if (!link->next) {
  836.  
  837.                /* create missing link (block table) */
  838.  
  839.                 link->nextref = Hnewref(access_rec->file_id);
  840.                link->next =
  841.                    HLInewlink(access_rec->file_id, info->number_blocks,
  842.                               link->nextref, 0);
  843.                if (!link->next)
  844.                    return FAIL;
  845.                {               /* AA */
  846.                    /* update previous link with information about new link */
  847.  
  848.                    uint16 link_tag = DFTAG_LINKED;
  849.                    uint16 link_ref = /* ref of current link */
  850.                        prev_link!=NULL ? prev_link->nextref : info->link_ref;
  851.  
  852.                    uint8 *p = tbuf;   /* temp buf ptr */
  853.  
  854.                    /* write file the updated portion of current link */
  855.  
  856.                    int32 link_id = /* access id for current link */
  857.                        Hstartwrite(access_rec->file_id, link_tag,
  858.                                    link_ref, 0);
  859.                    if (link_id == FAIL) {
  860.                        HERROR(DFE_WRITEERROR);
  861.                        return FAIL;
  862.                    }
  863.                    UINT16ENCODE(p, link->nextref);
  864.                    if (Hwrite(link_id, 2, tbuf) == FAIL) {
  865.                        HERROR(DFE_WRITEERROR);
  866.                        return FAIL;
  867.                    }
  868.                    Hendaccess(link_id);
  869.                }               /* AA */
  870.            }                   /* if not link->next */
  871.  
  872.            /* move to the next link */
  873.  
  874.             prev_link = link;
  875.            link = link->next;
  876.        }                       /* for */
  877.     }                          /*  */
  878.  
  879.     block_idx %= info->number_blocks;
  880.  
  881.     /* start writing in that block */
  882.  
  883.     do {
  884.        int32 access_id;        /* access record id */
  885.        int32 remaining =       /* remaining data length in this block */
  886. #ifndef oldspecial
  887.            current_length
  888. #else
  889.            info->block_length
  890. #endif
  891.                - relative_posn;
  892.        uint16 new_ref =        /* ref of newly created block */
  893.            0;
  894.  
  895.        /* determine length and write this block */
  896.  
  897.        if (remaining > length) remaining = length;
  898.        if (link->block_list[block_idx].ref != 0) {
  899.  
  900.            /* this block already exist, so just set up access to it */
  901.  
  902.            block_t *current_block = /* ptr to current block record */
  903.                &(link->block_list[block_idx]);
  904.  
  905.            access_id= Hstartwrite(access_rec->file_id,
  906.                                   DFTAG_LINKED,
  907.                                   current_block->ref,
  908. #ifndef oldspecial
  909.                                   current_length
  910. #else
  911.                                   info->block_length
  912. #endif
  913.                                   );
  914.  
  915.        } else {
  916.  
  917.            /* block is missing, set up a new block */
  918.  
  919.            new_ref = Hnewref(access_rec->file_id);
  920.            access_id = Hstartwrite(access_rec->file_id, DFTAG_LINKED,
  921.                                    new_ref,
  922. #ifndef oldspecial
  923.                                    current_length
  924. #else
  925.                                    info->block_length
  926. #endif
  927.                                    );
  928.  
  929.        }
  930.  
  931.        if (access_id == (int32) FAIL) {
  932.            HERROR(DFE_WRITEERROR);
  933.            return FAIL;
  934.        }
  935.        if ((relative_posn &&
  936.            (int32)FAIL == Hseek(access_id, relative_posn, DF_START)) ||
  937.            (int32)FAIL == (nbytes = Hwrite(access_id, remaining, data))) {
  938.            HERROR(DFE_WRITEERROR);
  939.            return FAIL;
  940.        }
  941.        Hendaccess(access_id);
  942.        bytes_written += nbytes;
  943.  
  944.        if (new_ref) {
  945.  
  946.            /* created a new block, so update the link/block table */
  947.  
  948.            uint16 link_tag = DFTAG_LINKED;
  949.            uint16 link_ref =   /* ref of the current link/block table */
  950.                prev_link ? prev_link->nextref : info->link_ref;
  951.  
  952.            uint8 *p =  /* temp buffer ptr */
  953.                tbuf;
  954.  
  955.            int32 link_id =     /* access record id of the current
  956.                                   link/block table */
  957.                Hstartwrite(access_rec->file_id, link_tag, link_ref, 0);
  958.  
  959.            if (link_id == FAIL) {
  960.                HERROR(DFE_WRITEERROR);
  961.                return FAIL;
  962.            }
  963.            UINT16ENCODE(p, new_ref);
  964.            if (Hseek(link_id, 2+2*block_idx, DF_START) == FAIL) {
  965.                HERROR(DFE_SEEKERROR);
  966.                return FAIL;
  967.            }
  968.            if (Hwrite(link_id, 2, tbuf) == FAIL) {
  969.                HERROR(DFE_WRITEERROR);
  970.                return FAIL;
  971.            }
  972.            Hendaccess(link_id);
  973.  
  974.            /* update memory structure */
  975.  
  976.            link->block_list[block_idx].ref = new_ref;
  977.        }                       /* if new_ref */
  978.  
  979.        /* move ptrs and counters for next phase */
  980.  
  981.        data +=remaining;
  982.        length -= remaining;
  983.  
  984.        if (length>0 &&
  985.            ++block_idx >= info->number_blocks) {
  986.  
  987.            /* move to the next link/block table */
  988.  
  989.            block_idx = 0;
  990.  
  991.            if (!link->next) {
  992.  
  993.                /* create missing link/block table */
  994.  
  995.                 link->nextref = Hnewref(access_rec->file_id);
  996.                link->next = HLInewlink(access_rec->file_id,
  997.                                        info->number_blocks,
  998.                                         link->nextref, 0);
  999.                if (!link->next)
  1000.                    return FAIL;
  1001.  
  1002.                {               /* BB */
  1003.                    uint16 link_tag = DFTAG_LINKED;
  1004.                    uint16 link_ref = /* ref of current link/block table */
  1005.                        prev_link ? prev_link->nextref : info->link_ref;
  1006.  
  1007.                    uint8 *p = /* temp buffer ptr */
  1008.                        tbuf;
  1009.  
  1010.                    int32 link_id = /* access record id of
  1011.                                       current link/block table */
  1012.                        Hstartwrite(access_rec->file_id, link_tag,
  1013.                                    link_ref, 0);
  1014.  
  1015.                    if (link_id == FAIL) {
  1016.                        HERROR(DFE_WRITEERROR);
  1017.                        return FAIL;
  1018.                    }
  1019.                    UINT16ENCODE(p, link->nextref);
  1020.                    if (Hwrite(link_id, 2, tbuf) == FAIL) {
  1021.                        HERROR(DFE_WRITEERROR);
  1022.                        return FAIL;
  1023.                    }
  1024.                    Hendaccess(link_id);
  1025.                }               /* BB */
  1026.            }                   /* if not link->next  */
  1027.  
  1028.            /* move to the next link/block table */
  1029.  
  1030.             prev_link = link;
  1031.            link = link->next;
  1032.  
  1033.        }
  1034.  
  1035.        /* update vars for next phase */
  1036.  
  1037.        relative_posn = 0;
  1038. #ifndef oldspecial
  1039.        current_length = info->block_length;
  1040. #endif
  1041.  
  1042.     } while (length > 0);
  1043.  
  1044.     if (HI_SEEK(file_rec->file, info_dd->offset+2) == FAIL) {
  1045.         HERROR(DFE_SEEKERROR);
  1046.        return FAIL;
  1047.     }
  1048.         {
  1049.             int32 tmp;
  1050.  
  1051.             tmp = bytes_written + access_rec->posn;
  1052.             if (tmp > info->length)
  1053.                 info->length = tmp;
  1054.         }
  1055.     {
  1056.         uint8 *p = tbuf;
  1057.        INT32ENCODE(p, info->length);
  1058.     }
  1059.     if (HI_WRITE(file_rec->file, tbuf, 4) == FAIL) {
  1060.         HERROR(DFE_WRITEERROR);
  1061.        return(FAIL);
  1062.     }
  1063.  
  1064.     access_rec->posn += bytes_written;
  1065.     /* return SUCCEED; */
  1066.     /* if wrong # bytes written, FAIL has already been returned */
  1067.     return bytes_written;
  1068. }
  1069.  
  1070. /*- HLInewlink
  1071.  create a new link/block table in memory and in file
  1072.  returns ptr to the new link/block table
  1073. -*/
  1074. #ifdef PROTOTYPE
  1075. PRIVATE link_t *HLInewlink(int32 file_id, int32 number_blocks,
  1076.                           uint16 link_ref, uint16 first_block_ref)
  1077. #else
  1078. PRIVATE link_t *HLInewlink(file_id, number_blocks, link_ref, first_block_ref)
  1079.     int32 file_id;              /* file record id */
  1080.     int32 number_blocks;        /* number os block to put in this link */
  1081.     uint16 link_ref;            /* ref of link to create */
  1082.     uint16 first_block_ref;     /* ref of first block in this link */
  1083. #endif
  1084. {
  1085.     char *FUNC="HLInewlink";   /* for HERROR */
  1086.     int32 link_id;             /* access record id of new link */
  1087.     uint8 *buf;                 /* temp buffer */
  1088.  
  1089.     /* set up new link record in memory */
  1090.  
  1091.     link_t *link =             /* new link record */
  1092.        (link_t *)HDgetspace((uint32)sizeof(link_t));
  1093.  
  1094.     if (!link) {
  1095.        HERROR(DFE_NOSPACE);
  1096.        return NULL;
  1097.     }
  1098.     link->block_list = (block_t *) HDgetspace((uint32)number_blocks
  1099.                                          * sizeof(block_t));
  1100.     if (!link->block_list) {
  1101.        HDfreespace((VOIDP) link);
  1102.        HERROR(DFE_NOSPACE);
  1103.        return NULL;
  1104.     }
  1105.     link->next = NULL;
  1106.  
  1107.     /* write the new link to file */
  1108.  
  1109.     link_id = Hstartwrite(file_id, DFTAG_LINKED, link_ref, 2+2*number_blocks);
  1110.     if (link_id==FAIL) {
  1111.        HDfreespace((VOIDP) link->block_list);
  1112.        HDfreespace((VOIDP) link);
  1113.         HERROR(DFE_WRITEERROR);
  1114.         return NULL;
  1115.     }
  1116.     {                          /* CC */
  1117.        register int32 i;       /* temp int index */
  1118.        uint8 *p;       /* temp buffer ptr */
  1119.  
  1120.        p = buf = (uint8 *)HDgetspace((uint32) (2 + 2*number_blocks));
  1121.        if (!buf) {
  1122.            HERROR(DFE_NOSPACE);
  1123.            return NULL;
  1124.        }
  1125.  
  1126.        /* set up the record and write to file */
  1127.  
  1128.        link->nextref = 0;
  1129.        UINT16ENCODE(p, 0);
  1130.        link->block_list[0].ref = first_block_ref;
  1131.        UINT16ENCODE(p, first_block_ref);
  1132.  
  1133.        for (i=1; i<number_blocks; i++) {
  1134.  
  1135.            /* set up each block in this link */
  1136.  
  1137.            link->block_list[i].ref = 0;
  1138.            UINT16ENCODE(p, 0);
  1139.        }
  1140.     }                          /* CC */
  1141.  
  1142.     /* write the link */
  1143.  
  1144.     if (Hwrite(link_id, 2+2*number_blocks, buf) == FAIL) {
  1145.         HDfreespace(buf);
  1146.        HDfreespace((VOIDP) link->block_list);
  1147.        HDfreespace((VOIDP) link);
  1148.         HERROR(DFE_WRITEERROR);
  1149.         return NULL;
  1150.     }
  1151.     HDfreespace(buf);
  1152.     Hendaccess(link_id);
  1153.  
  1154.     return link;
  1155. }
  1156.  
  1157. /*- HLIinquire
  1158.  
  1159. -*/
  1160. #ifdef PROTOTYPE
  1161. PRIVATE int32 HLIinquire(accrec_t *access_rec, int32 *pfile_id, uint16 *ptag,
  1162.                 uint16 *pref, int32 *plength, int32 *poffset, int32 *pposn,
  1163.                 int16 *paccess, int16 *pspecial)
  1164. #else
  1165. PRIVATE int32 HLIinquire(access_rec, pfile_id, ptag, pref, plength, poffset,
  1166.                         pposn, paccess, pspecial)
  1167.      accrec_t *access_rec;     /* access record */
  1168.      int32 *pfile_id;          /* ptr to file id, OUT */
  1169.      uint16 *ptag;             /* ptr to tag of information, OUT */
  1170.      uint16 *pref;             /* ptr to ref of information, OUT */
  1171.      int32 *plength;           /* ptr to length of data element, OUT */
  1172.      int32 *poffset;           /* ptr to offset of data element, OUT */
  1173.      int32 *pposn;             /* ptr to position of access in element, OUT */
  1174.      int16 *paccess;           /* ptr to access mode, OUT */
  1175.      int16 *pspecial;          /* ptr to special code */
  1176. #endif
  1177. {
  1178.     dd_t *info_dd =            /* dd of special information */
  1179.        &(access_rec->block->ddlist[access_rec->idx]);
  1180.     linkinfo_t *info =         /* special information record */
  1181.        (linkinfo_t *)access_rec->special_info;
  1182.  
  1183.     /* fill in the variables if they are present */
  1184.  
  1185.     if (pfile_id) *pfile_id = access_rec->file_id;
  1186.     if (ptag) *ptag = info_dd->tag;
  1187.     if (pref) *pref = info_dd->ref;
  1188.     if (plength) *plength = info->length;
  1189.     if (poffset) *poffset = 0; /* meaningless */
  1190.     if (pposn) *pposn = access_rec->posn;
  1191.     if (paccess) *paccess = access_rec->access;
  1192.     if (pspecial) *pspecial = access_rec->special;
  1193.  
  1194.     return SUCCEED;
  1195. }
  1196.  
  1197. /*- HLIendaccess
  1198.  
  1199. -*/
  1200. #ifdef PROTOTYPE
  1201. PRIVATE int32 HLIendaccess(accrec_t *access_rec)
  1202. #else
  1203. PRIVATE int32 HLIendaccess(access_rec)
  1204.     accrec_t *access_rec;      /* access record to dispose of */
  1205. #endif
  1206. {
  1207.     char *FUNC="HLIendaccess"; /* for HERROR */
  1208.     linkinfo_t *info =         /* special information record */
  1209.        (linkinfo_t *)access_rec->special_info;
  1210.     filerec_t *file_rec =      /* file record */
  1211.        FID2REC(access_rec->file_id);
  1212.  
  1213.     /* detach the special information record.
  1214.        If no more references to that, free the record */
  1215.  
  1216.     if (--(info->attached) == 0) {
  1217.        link_t *link;           /* current link to free */
  1218.        link_t *next;           /* next link to free */
  1219.  
  1220.        /* free the linked list of links/block tables */
  1221.  
  1222.        for (link = info->link; link; link = next) {
  1223.            next = link->next;
  1224.            HDfreespace((VOIDP) link->block_list);
  1225.            HDfreespace((VOIDP) link);
  1226.        }
  1227.  
  1228.        HDfreespace((VOIDP) info);
  1229.     }
  1230.  
  1231.     /* detach from the file */
  1232.  
  1233.     file_rec->attach--;
  1234.  
  1235.     /* free the access record */
  1236.  
  1237.     access_rec->used = FALSE;
  1238.  
  1239.     return SUCCEED;
  1240. }
  1241.