mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-17 00:32:52 +00:00
Fix various compiler warnings. Fix bug causing double free when a file isn't found. Fix bug using uninitialized variable parsing null filename. Fix bug causing crash when format 3 retrieval pointer encountered. Add support for readline (command line editing and history on Unix) Untangle NT I/O so it builds without the direct access SCSI API & works. Report errors as text messages everywhere. Add MSVC project files. Implement most of dir/full Partially implement XABITM Add help to command tables. Allow choice of VMS qualifiers or Unix options. mount /write // /dev/cdrom or mount -write /dev/cdrom Parse quoted strings as command parameters. Mount /write "/dev/cdrom" search [*...]*.txt "My words for you" Resolve command, parameter & qualifier ambiguity from tables. Consolidate the various makefiles into a common file with very small platform-specific wrappers. This simplifies maintenance. Add diskio module to allow easy access to .iso images and simulator files. Removes requirement for loop device or equivalent. Builds as a separate executable. Writes to the ODS2 volumes are broken.
682 lines
25 KiB
C
682 lines
25 KiB
C
#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 USE_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 = 1;
|
|
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;
|
|
|
|
if( rethead != NULL ) *rethead = 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 %u rvn %u\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);
|
|
}
|
|
if( rethead != NULL ) *rethead = head;
|
|
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
|
|
|