#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "ssdef.h"
#include "access.h"

unsigned deaccesshead(struct VIOC *vioc,struct HEAD *head,unsigned idxblk);
unsigned accesshead(struct VCB *vcb,struct fiddef *fid,unsigned seg_num,
                    struct VIOC **vioc,struct HEAD **headbuff,
                    unsigned *retidxblk,unsigned wrtflg);
unsigned getwindow(struct FCB * fcb,unsigned vbn,struct VCBDEV **devptr,
                   unsigned *phyblk,unsigned *phylen,struct fiddef *hdrfid,
                   unsigned *hdrseq);
struct VCBDEV *rvn_to_dev(struct VCB *vcb,unsigned rvn);



/* Bitmaps get accesses in 'WORK_UNITs' which can be an integer
   on a little endian machine but must be a byte on a big endian system */

#ifdef BIG_ENDIAN
#define WORK_UNIT unsigned char
#define WORK_MASK 0xff
#else
#define WORK_UNIT unsigned int
#define WORK_MASK 0xffffffff
#endif
#define WORK_BITS (sizeof(WORK_UNIT) * 8)

/* update_freecount() to read the device cluster bitmap and compute
   the number of un-used clusters */

unsigned update_freecount(struct VCBDEV *vcbdev,unsigned *retcount)
{
    register unsigned sts;
    register unsigned free_clusters = 0;
    register unsigned map_block, map_end = (vcbdev->max_cluster + 4095) / 4096 + 2;
    for (map_block = 2; map_block < map_end; ) {
        struct VIOC *vioc;
        unsigned blkcount;
        WORK_UNIT *bitmap,*work_ptr;
        register unsigned work_count;
        sts = accesschunk(vcbdev->mapfcb,map_block, &vioc,(char **) &bitmap,&blkcount,0);
        if (!(sts & 1)) return sts;
        if (blkcount > map_end - map_block) blkcount = map_end - map_block + 1;
        work_ptr = bitmap;
        work_count = blkcount * 512 / sizeof(WORK_UNIT);
        do {
            register WORK_UNIT work_val = *work_ptr++;
            if (work_val == WORK_MASK) {
                free_clusters += WORK_BITS;
            } else {
                while (work_val != 0) {
                    if (work_val & 1) free_clusters++;
                    work_val = work_val >> 1;
                }
            }
        } while (--work_count > 0);
        sts = deaccesschunk(vioc,0,0,1);
        if (!(sts & 1)) return sts;
        map_block += blkcount;
    }
    *retcount = free_clusters;
    return sts;
}

/* bitmap_modify() will either set or release a block of bits in the
   device cluster bitmap */

unsigned bitmap_modify(struct VCBDEV *vcbdev,unsigned cluster,unsigned count,
                       unsigned release_flag)
{
    register unsigned sts;
    register unsigned clust_count = count;
    register unsigned map_block = cluster / 4096 + 2;
    register unsigned block_offset = cluster % 4096;
    if (clust_count < 1) return SS$_BADPARAM;
    if (cluster + clust_count > vcbdev->max_cluster + 1) return SS$_BADPARAM;
    do {
        struct VIOC *vioc;
        unsigned blkcount;
        WORK_UNIT *bitmap;
        register WORK_UNIT *work_ptr;
        register unsigned work_count;
        sts = accesschunk(vcbdev->mapfcb,map_block,&vioc,(char **) &bitmap,&blkcount,1);
        if (!(sts & 1)) return sts;
        work_ptr = bitmap + block_offset / WORK_BITS;
        if (block_offset % WORK_BITS) {
            register unsigned bit_no = block_offset % WORK_BITS;
            register WORK_UNIT bit_mask = WORK_MASK;
            if (bit_no + clust_count < WORK_BITS) {
                bit_mask = bit_mask >> (WORK_BITS - clust_count);
                clust_count = 0;
            } else {
                clust_count -= WORK_BITS - bit_no;
            }
            bit_mask = bit_mask << bit_no;
            if (release_flag) {
                *work_ptr++ |= bit_mask;
            } else {
                *work_ptr++ &= ~bit_mask;
            }
            block_offset += WORK_BITS - bit_no;
        }
        work_count = (blkcount * 4096 - block_offset) / WORK_BITS;
        if (work_count > clust_count / WORK_BITS) {
            work_count = clust_count / WORK_BITS;
            block_offset = 1;
        } else {
            block_offset = 0;
        }
        clust_count -= work_count * WORK_BITS;
        if (release_flag) {
            while (clust_count-- > 0) {
                *work_ptr++ = WORK_MASK;
            }
        } else {
            while (work_count-- > 0) {
                *work_ptr++ = 0;
            }
        }
        if (clust_count != 0 && block_offset) {
            register WORK_UNIT bit_mask = WORK_MASK >> (WORK_BITS - clust_count);
            if (release_flag) {
                *work_ptr++ |= bit_mask;
            } else {
                *work_ptr++ &= ~bit_mask;
            }
            clust_count = 0;
        }
        sts = deaccesschunk(vioc,map_block,blkcount,1);
        if (!(sts & 1)) return sts;
        map_block += blkcount;
        block_offset = 0;
    } while (clust_count != 0);
    return sts;
}

/* bitmap_search() is a routine to find a pool of free clusters in the
   device cluster bitmap */

unsigned bitmap_search(struct VCBDEV *vcbdev,unsigned *position,unsigned *count)
{
    register unsigned sts;
    register unsigned map_block,block_offset;
    register unsigned search_words,needed;
    register unsigned run = 0,cluster;
    register unsigned best_run = 0,best_cluster = 0;
    needed = *count;
    if (needed < 1 || needed > vcbdev->max_cluster + 1) return SS$_BADPARAM;
    cluster = *position;
    if (cluster + *count > vcbdev->max_cluster + 1) cluster = 0;
    map_block = cluster / 4096 + 2;
    block_offset = cluster % 4096;
    cluster = cluster - (cluster % WORK_BITS);
    search_words = vcbdev->max_cluster / WORK_BITS;
    do {
        struct VIOC *vioc;
        unsigned blkcount;
        WORK_UNIT *bitmap;
        register WORK_UNIT *work_ptr, work_val;
        register unsigned work_count;
        sts = accesschunk(vcbdev->mapfcb,map_block,&vioc,(char **) &bitmap,&blkcount,1);
        if ((sts & 1) == 0) return sts;
        work_ptr = bitmap + block_offset / WORK_BITS;
        work_val = *work_ptr++;
        if (block_offset % WORK_BITS) {
            work_val = work_val && (WORK_MASK << block_offset % WORK_BITS);
        }        
        work_count = (blkcount * 4096 - block_offset) / WORK_BITS;
        if (work_count > search_words) work_count = search_words;
        search_words -= work_count;
        do {
            if (work_val == WORK_MASK) {
                run += WORK_BITS;
            } else {
                register unsigned bit_no = 0;
                while (work_val != 0) {
                    if (work_val & 1) {
                        run++;
                    } else {
                        if (run > best_run) {
                            best_run = run;
                            best_cluster = cluster + bit_no;
                        }
                        run = 0;
                    }
                    work_val = work_val >> 1;
                    bit_no++;
                }
                if (bit_no < WORK_BITS) {
                    if (run > best_run) {
                        best_run = run;
                        best_cluster = cluster + bit_no;
                    }
                    run = 0;
                }
            }
            cluster += WORK_BITS;
            if (work_count-- > 0) {
                work_val = *work_ptr++;
            } else {
                break;
            }
        } while (best_run < needed);
        deaccesschunk(vioc,map_block,0,1);
        if ((sts & 1) == 0) break;
        map_block += blkcount;
        block_offset = 0;
    } while (best_run < needed && search_words != 0);
    if (best_run > needed) best_run = needed;
    *count = best_run;
    *position = best_cluster;
    return sts;
}

/* headmap_clear() will release a header from the indexf.sys file header
   bitmap */

unsigned headmap_clear(struct VCBDEV *vcbdev,unsigned head_no)
{
    WORK_UNIT *bitmap;
    struct VIOC *vioc;
    register unsigned sts;
    register unsigned map_block = head_no / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
    if (head_no < 10) return 0;
    sts = accesschunk(vcbdev->idxfcb,map_block,&vioc,(char **) &bitmap,NULL,1);
    if (sts & 1) {
        bitmap[(head_no % 4096) / WORK_BITS] &= ~(1 << (head_no % WORK_BITS));
        sts = deaccesschunk(vioc,map_block,1,1);
    }
    return sts;
}

/* update_findhead() will locate a free header from indexf.sys */

unsigned update_findhead(struct VCBDEV *vcbdev,unsigned *rethead_no,
                         struct VIOC **retvioc,struct HEAD **headbuff,
                         unsigned *retidxblk)
{
    unsigned head_no = 0;
    register unsigned sts;
    do {
        struct VIOC *vioc;
        int modify_flag = 0;
        unsigned blkcount;
        WORK_UNIT *bitmap,*work_ptr;
        register unsigned map_block,work_count;
        map_block = head_no / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
        sts = accesschunk(vcbdev->idxfcb,map_block,
            &vioc,(char **) &bitmap,&blkcount,1);
        if ((sts & 1) == 0) return sts;
        work_count = (head_no % 4096) / WORK_BITS;
        work_ptr = bitmap + work_count;
        work_count = blkcount * 512 / WORK_BITS - work_count;
        do {
            register WORK_UNIT work_val = *work_ptr;
            if (work_val == WORK_MASK) {
                head_no += WORK_BITS;
            } else {
                register unsigned bit_no = 0;
                for (bit_no = 0; bit_no < WORK_BITS; bit_no++) {
                    if ((work_val & (1 << bit_no)) == 0) {
                        register unsigned idxblk = head_no +
                            VMSWORD(vcbdev->home.hm2$w_ibmapvbn) +
                            VMSWORD(vcbdev->home.hm2$w_ibmapsize);
                        sts = accesschunk(vcbdev->idxfcb,idxblk,retvioc,(char **) headbuff,NULL,1);
                        if (sts & 1) {
                            *work_ptr |= 1 << bit_no;
                            modify_flag = 1;
                            if ((*headbuff)->fh2$w_checksum != 0 || (*headbuff)->fh2$w_fid.fid$w_num != 0 ||
                                VMSLONG((*headbuff)->fh2$l_filechar) & FH2$M_MARKDEL == 0) {
                                sts = deaccesschunk(*retvioc,0,0,0);
                            } else {
                                *rethead_no = head_no + 1;
                                *retidxblk = idxblk;
                                deaccesschunk(vioc,map_block,blkcount,modify_flag);
                                return SS$_NORMAL;
                            }
                        }
                    }
                    head_no++;
                }
            }
            work_ptr++;
        } while (--work_count != 0);
        deaccesschunk(vioc,map_block,blkcount,modify_flag);
        if ((sts & 1) == 0) break;
    } while (head_no < VMSLONG(vcbdev->home.hm2$l_maxfiles));
    return sts;
}

unsigned update_addhead(struct VCB *vcb,char *filename,struct fiddef *back,
                     unsigned seg_num,struct fiddef *fid,
                     struct VIOC **vioc,struct HEAD **rethead,
                     unsigned *idxblk)
{
    register unsigned free_space = 0;
    register unsigned device,rvn,sts;
    unsigned head_no;
    struct IDENT *id;
    struct HEAD *head;
    struct VCBDEV *vcbdev = NULL;
    for (device = 0; device < vcb->devices; device++) {
        if (vcb->vcbdev[device].dev != NULL) {
            if (vcb->vcbdev[device].free_clusters > free_space) {
                free_space = vcb->vcbdev[device].free_clusters;
                vcbdev = &vcb->vcbdev[device];
                rvn = device;
            }
        }
    }
    if (vcbdev == NULL) return SS$_DEVICEFULL;

    sts = update_findhead(vcbdev,&head_no,vioc,&head,idxblk);
    if (!(sts & 1)) return sts;
    printf("Header %d index %d rvn %d\n",head_no,idxblk,rvn);
    fid->fid$w_num = head_no;
    fid->fid$w_seq = ++head->fh2$w_fid.fid$w_seq;
    if (fid->fid$w_seq == 0) fid->fid$w_seq = 1;
    if (rvn > 0) {
        fid->fid$b_rvn = rvn + 1;
    } else {
        fid->fid$b_rvn = 0;
    }
    fid->fid$b_nmx = head_no >> 16;
    memset(head,0,512);
    head->fh2$b_idoffset = 40;
    head->fh2$b_mpoffset = 100;
    head->fh2$b_acoffset = 255;
    head->fh2$b_rsoffset = 255;
    head->fh2$w_seg_num = seg_num;
    head->fh2$w_struclev = 513;
    head->fh2$l_fileowner.uic$w_mem = 4;
    head->fh2$l_fileowner.uic$w_grp = 1;
    fid_copy(&head->fh2$w_fid,fid,0);
    if (back != NULL) fid_copy(&head->fh2$w_backlink,back,0);
    id = (struct IDENT *) ((unsigned short *) head + 40);
    memset(id->fi2$t_filenamext,' ',66);
    if (strlen(filename) < 20) {
        memset(id->fi2$t_filename,' ',20);
        memcpy(id->fi2$t_filename,filename,strlen(filename));
    } else {
        memcpy(id->fi2$t_filename,filename,20);
        memcpy(id->fi2$t_filenamext,filename+20,strlen(filename+20));
    }
    id->fi2$w_revision = 1;
    sys_gettim(id->fi2$q_credate);
    memcpy(id->fi2$q_revdate,id->fi2$q_credate,sizeof(id->fi2$q_credate));
    memcpy(id->fi2$q_expdate,id->fi2$q_credate,sizeof(id->fi2$q_credate));
    head->fh2$w_recattr.fat$l_efblk = VMSSWAP(1);
    {
        unsigned short check = checksum((vmsword *) head);
        head->fh2$w_checksum = VMSWORD(check);
    }
    return 1;
}

/* update_create() will create a new file... */

unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename,
                       struct fiddef *fid,struct FCB **fcb)
{
    struct VIOC *vioc;
    struct HEAD *head;
    unsigned idxblk;
    register unsigned sts;
    sts = update_addhead(vcb,filename,did,0,fid,&vioc,&head,&idxblk);
    if (!(sts & 1)) return sts;
    sts = deaccesshead(vioc,head,idxblk);
    if (sts & 1 && fcb != NULL) {
        sts = accessfile(vcb,fid,fcb,1);
    }
    printf("(%d,%d,%d) %d\n",fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn,sts);
    return sts;
}

unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig)
{
    register unsigned sts;
    struct VCBDEV *vcbdev;
    struct VIOC *vioc;
    struct HEAD *head;
    unsigned headvbn;
    struct fiddef hdrfid;
    unsigned hdrseq;
    unsigned start_pos = 0;
    unsigned block_count = blocks;
    if (block_count < 1) return 0;
    if ((fcb->status & FCB_WRITE) == 0) return SS$_WRITLCK;
    if (fcb->hiblock > 0) {
        unsigned mapblk,maplen;
        sts = getwindow(fcb,fcb->hiblock,&vcbdev,&mapblk,&maplen,&hdrfid,&hdrseq);
        if ((sts & 1) == 0) return sts;
        start_pos = mapblk + 1;
        if (hdrseq != 0) {
            sts = accesshead(fcb->vcb,&hdrfid,hdrseq,&vioc,&head,&headvbn,1);
            if ((sts & 1) == 0) return sts;
        } else {
            head = fcb->head;
            vioc = NULL;
        }
    } else {
        head = fcb->head;
        vioc = NULL;
        start_pos = 0;          /* filenum * 3 /indexfsize * volumesize; */
    }
    if (vioc == NULL) vcbdev = rvn_to_dev(fcb->vcb,fcb->rvn);
    if (vcbdev->free_clusters == 0 || head->fh2$b_map_inuse + 4 >=
                head->fh2$b_acoffset - head->fh2$b_mpoffset) {
        struct VIOC *nvioc;
        struct HEAD *nhead;
        unsigned nidxblk;
        sts = update_addhead(fcb->vcb,"",&head->fh2$w_fid,head->fh2$w_seg_num+1,
              &head->fh2$w_ext_fid,&nvioc,&nhead,&nidxblk);
        if (!(sts & 1)) return sts;
        if (vioc != NULL) deaccesshead(vioc,head,headvbn);
        vioc = nvioc;
        head = nhead;
        headvbn = nidxblk;
        vcbdev = rvn_to_dev(fcb->vcb,head->fh2$w_fid.fid$b_rvn);
    }
    sts = bitmap_search(vcbdev,&start_pos,&block_count);
    printf("Update_extend %d %d\n",start_pos,block_count);
    if (sts & 1) {
        if (block_count < 1 || contig && block_count * vcbdev->clustersize < blocks) {
            sts = SS$_DEVICEFULL;
        } else {
            register unsigned short *mp;
            mp = (unsigned short *) head + head->fh2$b_mpoffset + head->fh2$b_map_inuse;
            *mp++ = (3 << 14) | ((block_count *vcbdev->clustersize - 1) >> 16);
            *mp++ = (block_count * vcbdev->clustersize - 1) & 0xffff;
            *mp++ = (start_pos * vcbdev->clustersize) & 0xffff;
            *mp++ = (start_pos * vcbdev->clustersize) >> 16;
            head->fh2$b_map_inuse += 4;
            fcb->hiblock += block_count * vcbdev->clustersize;
            fcb->head->fh2$w_recattr.fat$l_hiblk = VMSSWAP(fcb->hiblock * vcbdev->clustersize);
            sts = bitmap_modify(vcbdev,start_pos,block_count,0);
        }
    }
    if (vioc != NULL) deaccesshead(vioc,head,headvbn);
    return sts;
}




/* This routine has bugs and does NOT work properly yet!!!!
It may be something simple but I haven't had time to look...
So DON'T use mount/write!!!  */

unsigned deallocfile(struct FCB *fcb)
{
    register unsigned sts = 1;
    /*
    First mark all file clusters as free in BITMAP.SYS
    */
    register unsigned vbn = 1;
    while (vbn <= fcb->hiblock) {
        register unsigned sts;
        unsigned phyblk,phylen;
        struct VCBDEV *vcbdev;
        sts = getwindow(fcb,vbn,&vcbdev,&phyblk,&phylen,NULL,NULL);
        if ((sts & 1) == 0) break;

        sts = bitmap_modify(vcbdev,phyblk,phylen,1);
        if ((sts & 1) == 0) break;
    }
    /*
    Now reset file header bit map in INDEXF.SYS and
    update each of the file headers...
    */
    {
        unsigned rvn = fcb->rvn;
        unsigned headvbn = fcb->headvbn;
        struct HEAD *head = fcb->head;
        struct VIOC *headvioc = fcb->headvioc;
        do {
            unsigned ext_seg_num = 0;
            struct fiddef extfid;
            register struct VCBDEV *vcbdev;
            unsigned *bitmap;
            struct VIOC *vioc;
            register unsigned filenum = (head->fh2$w_fid.fid$b_nmx << 16) +
                head->fh2$w_fid.fid$w_num - 1;
            register unsigned idxblk;
            vcbdev = rvn_to_dev(fcb->vcb,rvn);
            if (vcbdev == NULL) break;
            idxblk = filenum / 4096 +
                vcbdev->home.hm2$w_cluster * 4 + 1;
            sts = accesschunk(vcbdev->idxfcb,idxblk,&vioc,
                (char **) &bitmap,NULL,1);
            if (sts & 1) {
                bitmap[(filenum % 4096) / WORK_BITS] &=
                    ~(1 << (filenum % WORK_BITS));
                sts = deaccesschunk(vioc,idxblk,1,1);
            } else {
                break;
            }
            head->fh2$w_fid.fid$w_num = 0;
            head->fh2$w_fid.fid$b_rvn = 0;
            head->fh2$w_fid.fid$b_nmx = 0;
            head->fh2$w_checksum = 0;
            ext_seg_num++;
            memcpy(&extfid,&fcb->head->fh2$w_ext_fid,sizeof(struct fiddef));
            sts = deaccesshead(headvioc,NULL,headvbn);
            if ((sts & 1) == 0) break;
            if (extfid.fid$b_rvn == 0) {
                extfid.fid$b_rvn = rvn;
            } else {
                rvn = extfid.fid$b_rvn;
            }
            if (extfid.fid$w_num != 0 || extfid.fid$b_nmx != 0) {
                sts = accesshead(fcb->vcb,&extfid,ext_seg_num,&headvioc,&head,&headvbn,1);
                if ((sts & 1) == 0) break;
            } else {
                break;
            }
        } while (1);
        if (sts & 1) {
            fcb->headvioc = NULL;
            cache_untouch(&fcb->cache,0);
            cache_delete(&fcb->cache);
        }
    }
    return sts;
}



/* accesserase: delete a file... */

unsigned accesserase(struct VCB * vcb,struct fiddef * fid)
{
    struct FCB *fcb;
    register int sts;
    sts = accessfile(vcb,fid,&fcb,1);
    if (sts & 1) {
        fcb->head->fh2$l_filechar |= FH2$M_MARKDEL;
        printf("Accesserase ... \n");
        sts = deaccessfile(fcb);
    }
    return sts;
}




#ifdef EXTEND
unsigned extend(struct FCB *fcb,unsigned blocks)
{
    register unsigned sts;
    struct VCBDEV *vcbdev;
    unsigned clusterno;
    unsigned extended = 0;
    if ((fcb->status & FCB_WRITE) == 0) return SS$_WRITLCK;
    if (fcb->hiblock > 0) {
        unsigned phyblk,phylen;
        sts = getwindow(fcb,fcb->hiblock,&vcbdev,&phyblk,&phylen,NULL,NULL);
        clusterno = (phyblk + 1) / vcbdev->home.hm2$w_cluster;
        if ((sts & 1) == 0) return sts;
    } else {
        vcbdev = fcb->vcb->vcbdev;
        clusterno = 0;          /* filenum * 3 /indexfsize * volumesize; */
    }
    while (extended < blocks) {
        unsigned *bitmap,blkcount;
        struct VIOC *vioc;
        register unsigned clustalq = 0;
        register unsigned clustersz = vcbdev->home.hm2$w_cluster;
        sts = accesschunk(vcbdev->mapfcb,clusterno / 4096 + 2,
            &vioc,(char **) &bitmap,&blkcount,1);
        if ((sts & 1) == 0) return sts;
        do {
            register unsigned wordno = (clusterno % 4096) / WORK_BITS;
            register unsigned wordval = bitmap[wordno];
            if (wordval == 0xffff) {
                if (clustalq) break;
                clusterno = (clusterno % WORK_BITS) *
                    WORK_BITS + 1;
            } else {
                register unsigned bitno = clusterno % WORK_BITS;
                do {
                    if (wordval & (1 << bitno)) {
                        if (clustalq) break;
                    } else {
                        clustalq++;
                        wordval |= 1 << bitno;
                    }
                    clusterno++;
                    if (clustalq >= (extended - blocks)) break;
                } while (++bitno < WORK_BITS);
                if (clustalq) {
                    bitmap[wordno] = wordval;
                    if (bitno < WORK_BITS) break;
                }
            }
        } while (++wordno < blkcount * 512 / sizeof(unsigned));
        mp = (unsigned word *) fcb->head + fcb->head->fh2$b_mpoffset;
        *mp++ = (3 << 14) | (clustalq >> 16);
        *mp++ = clustalq & 0xff;
        *mp++ = clustno & 0xff;
        *clusertize
            * mp++ = clustno << 16;
        fcb->head->fh2$b_map_inuse + 4;
        fcb->hiblock += clustalq;
        fcb->head.fh2$w_recattr.fat$l_hiblk[0] = fcb->hiblock >> 16;
        fcb->head.fh2$w_recattr.fat$l_hiblk[1] = fcb->hiblock & 0xff;
        sts = deaccesschunk(vioc,clusterno / 4096 + 2,blkcount,1);
        /* code to append clusterno:clustalq to map */
    }
}
#endif



#ifdef EXTEND

unsigned access_create(struct VCB * vcb,struct FCB ** fcbadd,unsigned blocks) {
    register struct FCB *fcb;
    struct fiddef fid;
    unsigned create = sizeof(struct FCB);
    if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;

    sts = headmap_search(struct VCBDEV * vcbdev,struct fiddef * fid,
        struct VIOC ** vioc,struct HEAD ** headbuff,unsigned *retidxblk,) {
        fcb = cachesearch((void *) &vcb->fcb,filenum,0,NULL,NULL,&create);
        if (fcb == NULL) return SS$_INSFMEM;
        /* If not found make one... */
        if (create == 0) {
            fcb->cache.objtype = CACHETYPE_DEV;
            fcb->rvn = fid->fid_b_rvn;
            if (fcb->rvn == 0 && vcb->devices > 1) fcb->rvn = 1;
            fcb->vcb = vcb;
            fcb->wcb = NULL;
            fcb->headvbn = 0;
            fcb->vioc = NULL;
            fcb->headvioc = NULL;
            fcb->cache.objmanager = fcbmanager;
        }
        if (wrtflg) {
            if (fcb->headvioc != NULL && (fcb->cache.status & CACHE_WRITE) == 0) {
                deaccesshead(fcb->headvioc,NULL,0);
                fcb->headvioc = NULL;
            }
            fcb->cache.status |= CACHE_WRITE;
        }
        if (fcb->headvioc == NULL) {
            register unsigned sts;
            if (vcb->idxboot != NULL) {
                *fcbadd = fcb;
                fcb->hiblock = 32767;   /* guess at indexf.sys file size */
                fcb->highwater = 0;
                fcb->head = vcb->idxboot;       /* Load bootup header */
            }
            sts = accesshead(vcb,fid,0,&fcb->headvioc,&fcb->head,&fcb->headvbn,wrtflg);
            if (sts & 1) {
                fcb->hiblock = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
                if (fcb->head->fh2$b_idoffset > 39) {
                    fcb->highwater = fcb->head->fh2$l_highwater;
                } else {
                    fcb->highwater = 0;
                }
            } else {
                printf("Accessfile status %d\n",sts);
                fcb->cache.objmanager = NULL;
                cacheuntouch(&fcb->cache,0,0);
                cachefree(&fcb->cache);
                return sts;
            }
        }
        *fcbadd = fcb;
        return SS$_NORMAL;
    }
#endif



syntax highlighted by Code2HTML, v. 0.9.1