diff --git a/.gitignore b/.gitignore
index 5b7dd43..510595b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -248,3 +248,4 @@ _Pvt_Extensions
.idea/
*.sln.iml
+.gdb_history
diff --git a/extracters/ods2/ODS2.exe b/extracters/ods2/ODS2.exe
old mode 100644
new mode 100755
index c697cfc..2a1d842
Binary files a/extracters/ods2/ODS2.exe and b/extracters/ods2/ODS2.exe differ
diff --git a/extracters/ods2/ODS2.vcxproj b/extracters/ods2/ODS2.vcxproj
index 9d826bb..fe1a955 100644
--- a/extracters/ods2/ODS2.vcxproj
+++ b/extracters/ods2/ODS2.vcxproj
@@ -46,17 +46,18 @@
- HOME_SKIP=1 ;HOME_LOG;USE_VLD;DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ USE_VLD;DEBUG_BUILD;USE_VHD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
MultiThreadedDebugDLL
Level3
EditAndContinue
Disabled
+ vhd\;%(AdditionalIncludeDirectories)
MachineX86
true
Console
- Shlwapi.lib;%(AdditionalDependencies)
+ Rpcrt4.lib;Shlwapi.lib;%(AdditionalDependencies)
@@ -80,10 +81,11 @@
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ USE_VHD;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
MultiThreadedDLL
Level3
ProgramDatabase
+ vhd\;%(AdditionalIncludeDirectories)
MachineX86
@@ -91,7 +93,7 @@
Console
true
true
- Shlwapi.lib;%(AdditionalDependencies)
+ Rpcrt4.lib;Shlwapi.lib;%(AdditionalDependencies)
@@ -108,31 +110,65 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extracters/ods2/ODS2.vcxproj.filters b/extracters/ods2/ODS2.vcxproj.filters
index 66da791..00f22da 100644
--- a/extracters/ods2/ODS2.vcxproj.filters
+++ b/extracters/ods2/ODS2.vcxproj.filters
@@ -51,6 +51,69 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -101,6 +164,39 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/extracters/ods2/access.c b/extracters/ods2/access.c
index 7491681..01b0dc5 100644
--- a/extracters/ods2/access.c
+++ b/extracters/ods2/access.c
@@ -1,4 +1,4 @@
-/* Access.c V2.1 */
+/* Access.c */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -17,6 +17,14 @@
'RMS' routines.
*/
+#if !defined( DEBUG ) && defined( DEBUG_ACCESS )
+#define DEBUG DEBUG_ACCCESS
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
#include
#include
@@ -26,20 +34,15 @@
#include "ssdef.h"
#include "access.h"
#include "device.h"
+#include "initvol.h"
#include "ods2.h"
-#include "phyio.h"
#include "phyvirt.h"
#include "stsdef.h"
#include "compat.h"
#include "sysmsg.h"
#include "vmstime.h"
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
+extern int mountdef( const char *devnam );
struct VCB *vcb_list = NULL;
@@ -51,15 +54,6 @@ struct WCBKEY {
struct WCB *prevwcb;
};
-#if 0
-static unsigned int delta_from_name( const char *diskname );
-#endif
-static unsigned int delta_from_index( size_t index );
-static unsigned int compute_delta( unsigned long sectorsize,
- unsigned long sectors,
- unsigned long tracks,
- unsigned long cylinders );
-
unsigned deallocfile(struct FCB *fcb); /* Update.c */
#define DEBUGx
@@ -67,7 +61,7 @@ unsigned deallocfile(struct FCB *fcb); /* Update.c */
/* checksum() to produce header checksum values... */
-vmsword checksumn( vmsword *block, int count ) {
+f11word checksumn( f11word *block, int count ) {
register unsigned result;
register unsigned short *ptr;
register unsigned data;
@@ -76,12 +70,12 @@ vmsword checksumn( vmsword *block, int count ) {
result = 0;
for ( ; count > 0; --count ) {
data = *ptr++;
- result += VMSWORD(data);
+ result += F11WORD(data);
}
- return (vmsword)(result & 0xFFFF);
+ return (f11word)(result & 0xFFFF);
}
-vmsword checksum( vmsword *block ) {
+f11word checksum( f11word *block ) {
return checksumn( block, 255 );
}
@@ -91,8 +85,8 @@ vmsword checksum( vmsword *block ) {
void fid_copy(struct fiddef *dst,struct fiddef *src,unsigned rvn)
{
- dst->fid$w_num = VMSWORD(src->fid$w_num);
- dst->fid$w_seq = VMSWORD(src->fid$w_seq);
+ dst->fid$w_num = F11WORD(src->fid$w_num);
+ dst->fid$w_seq = F11WORD(src->fid$w_seq);
dst->fid$b_rvn = src->fid$b_rvn == 0 ? rvn : src->fid$b_rvn;
dst->fid$b_nmx = src->fid$b_nmx;
}
@@ -103,11 +97,11 @@ void fid_copy(struct fiddef *dst,struct fiddef *src,unsigned rvn)
unsigned deaccesshead( struct VIOC *vioc, struct HEAD *head, unsigned idxblk ) {
- vmsword check;
+ f11word check;
if ( head && idxblk ) {
- check = checksum( (vmsword *) head );
- head->fh2$w_checksum = VMSWORD(check);
+ check = checksum( (f11word *) head );
+ head->fh2$w_checksum = F11WORD(check);
}
return deaccesschunk( vioc, idxblk, 1, TRUE );
}
@@ -125,15 +119,19 @@ unsigned accesshead(struct VCB *vcb,struct fiddef *fid,unsigned seg_num,
register unsigned idxblk;
vcbdev = RVN_TO_DEV(vcb,fid->fid$b_rvn);
if (vcbdev == NULL) return SS$_DEVNOTMOUNT;
- if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;
+ if( wrtflg && !(vcb->status & VCB_WRITE) )
+ return SS$_WRITLCK;
idxblk = fid->fid$w_num +
(fid->fid$b_nmx << 16) - 1 +
- VMSWORD(vcbdev->home.hm2$w_ibmapvbn) +
- VMSWORD(vcbdev->home.hm2$w_ibmapsize);
+ F11WORD(vcbdev->home.hm2$w_ibmapvbn) +
+ F11WORD(vcbdev->home.hm2$w_ibmapsize);
if (vcbdev->idxfcb->head != NULL) {
if (idxblk >=
- VMSSWAP(vcbdev->idxfcb->head->fh2$w_recattr.fat$l_efblk)) {
- printf("Not in index file\n");
+ F11SWAP(vcbdev->idxfcb->head->fh2$w_recattr.fat$l_efblk)) {
+#if DEBUG
+ printf("%u,%u,%u, %u Not in index file\n",
+ fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn,fid->fid$b_nmx);
+#endif
return SS$_NOSUCHFILE;
}
}
@@ -144,9 +142,9 @@ unsigned accesshead(struct VCB *vcb,struct fiddef *fid,unsigned seg_num,
if (retidxblk) {
*retidxblk = wrtflg ? idxblk : 0;
}
- if (VMSWORD(head->fh2$w_fid.fid$w_num) != fid->fid$w_num ||
+ if (F11WORD(head->fh2$w_fid.fid$w_num) != fid->fid$w_num ||
head->fh2$w_fid.fid$b_nmx != fid->fid$b_nmx ||
- VMSWORD(head->fh2$w_fid.fid$w_seq) != fid->fid$w_seq ||
+ F11WORD(head->fh2$w_fid.fid$w_seq) != fid->fid$w_seq ||
(head->fh2$w_fid.fid$b_rvn != fid->fid$b_rvn &&
head->fh2$w_fid.fid$b_rvn != 0)) {
/* lib$signal(SS$_NOSUCHFILE); */
@@ -158,18 +156,18 @@ unsigned accesshead(struct VCB *vcb,struct fiddef *fid,unsigned seg_num,
head->fh2$b_acoffset > head->fh2$b_rsoffset ||
head->fh2$b_map_inuse >
head->fh2$b_acoffset - head->fh2$b_mpoffset ||
- checksum( (vmsword *) head ) !=
- VMSWORD( head->fh2$w_checksum ) ) {
-#ifdef DEBUG
+ checksum( (f11word *) head ) !=
+ F11WORD( head->fh2$w_checksum ) ) {
+#if DEBUG
printf( "--->accesshead(): File header checksum failure:" );
printf( " FH2$W_CHECKSUM=%u, checksum()=%u\n",
- VMSWORD( head->fh2$w_checksum ),
- checksum( (vmsword *) head )
+ F11WORD( head->fh2$w_checksum ),
+ checksum( (f11word *) head )
);
#endif
sts = SS$_DATACHECK;
} else {
- if (VMSWORD(head->fh2$w_seg_num) != seg_num) {
+ if (F11WORD(head->fh2$w_seg_num) != seg_num) {
sts = SS$_FILESEQCHK;
}
}
@@ -230,24 +228,24 @@ struct HEAD *premap_indexf(struct FCB *fcb,unsigned *retsts)
if (head == NULL) {
*retsts = SS$_INSFMEM;
} else {
- *retsts = phyio_read( vcbdev->dev,
- VMSLONG( vcbdev->home.hm2$l_ibmaplbn ) +
- VMSWORD( vcbdev->home.hm2$w_ibmapsize ),
+ *retsts = virt_read( vcbdev->dev,
+ F11LONG( vcbdev->home.hm2$l_ibmaplbn ) +
+ F11WORD( vcbdev->home.hm2$w_ibmapsize ),
sizeof( struct HEAD ), (char *) head );
if (!(*retsts & STS$M_SUCCESS)) {
free(head);
head = NULL;
} else {
- if (VMSWORD(head->fh2$w_fid.fid$w_num) != 1 ||
+ if (F11WORD(head->fh2$w_fid.fid$w_num) != 1 ||
head->fh2$w_fid.fid$b_nmx != 0 ||
- VMSWORD(head->fh2$w_fid.fid$w_seq) != 1 ||
- VMSWORD(head->fh2$w_checksum) !=
- checksum( (vmsword *) head ) ) {
-#ifdef DEBUG
+ F11WORD(head->fh2$w_fid.fid$w_seq) != 1 ||
+ F11WORD(head->fh2$w_checksum) !=
+ checksum( (f11word *) head ) ) {
+#if DEBUG
printf( "--->premap_indexf(): Index file header checksum" );
printf( " failure: FH2$W_CHECKSUM=%u, checksum()=%u\n",
- VMSWORD( head->fh2$w_checksum ),
- checksum( (vmsword *) head )
+ F11WORD( head->fh2$w_checksum ),
+ checksum( (f11word *) head )
);
#endif
*retsts = SS$_DATACHECK;
@@ -315,28 +313,28 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) {
while (mp < me) {
register unsigned phylen,phyblk;
register unsigned short mp0;
- switch ((mp0 = VMSWORD(*mp)) >> 14) {
+ switch ((mp0 = F11WORD(*mp)) >> 14) {
case 0:
phylen = 0;
mp++;
break;
case 1:
phylen = (mp0 & 0x00ff) + 1;
- phyblk = ((mp0 & 0x3f00) << 8) | VMSWORD(mp[1]);
+ phyblk = ((mp0 & 0x3f00) << 8) | F11WORD(mp[1]);
mp += 2;
break;
case 2:
phylen = (mp0 & 0x3fff) + 1;
- phyblk = (VMSWORD(mp[2]) << 16) | VMSWORD(mp[1]);
+ phyblk = (F11WORD(mp[2]) << 16) | F11WORD(mp[1]);
mp += 3;
break;
case 3:
- phylen = ((mp0 & 0x3fff) << 16) + VMSWORD(mp[1]) + 1;
- phyblk = (VMSWORD(mp[3]) << 16) | VMSWORD(mp[2]);
+ phylen = ((mp0 & 0x3fff) << 16) + F11WORD(mp[1]) + 1;
+ phyblk = (F11WORD(mp[3]) << 16) | F11WORD(mp[2]);
mp += 4;
break;
default:
- printf( "Unknown type %x\n", (VMSWORD(*mp)>>14) );
+ printf( "Unknown type %x\n", (F11WORD(*mp)>>14) );
abort();
}
curvbn += phylen;
@@ -355,7 +353,7 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) {
}
}
if (extents >= EXTMAX ||
- (VMSWORD(head->fh2$w_ext_fid.fid$w_num) == 0 &&
+ (F11WORD(head->fh2$w_ext_fid.fid$w_num) == 0 &&
head->fh2$w_ext_fid.fid$b_nmx == 0)) {
break;
} else {
@@ -376,7 +374,7 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) {
*retsts = SS$_NORMAL;
if (curvbn <= wcbkey->vbn) {
free(wcb);
-#ifdef DEBUG
+#if DEBUG
printf( "--->wcb_create(): curvbn (=%u) <= wcbkey->vbn (=%u)\n",
curvbn, wcbkey->vbn );
#endif
@@ -398,7 +396,7 @@ unsigned getwindow(struct FCB * fcb,unsigned vbn,struct VCBDEV **devptr,
unsigned sts;
struct WCB *wcb;
struct WCBKEY wcbkey;
-#ifdef DEBUG
+#if DEBUG
printf("Accessing window for vbn %d, file (%x)\n",vbn,fcb->cache.hashval);
#endif
wcbkey.vbn = vbn;
@@ -418,7 +416,7 @@ unsigned getwindow(struct FCB * fcb,unsigned vbn,struct VCBDEV **devptr,
*phylen = wcb->phylen[extent] - togo;
if (hdrfid != NULL) memcpy(hdrfid,&wcb->hd_fid,sizeof(struct fiddef));
if (hdrseq != NULL) *hdrseq = wcb->hd_seg_num;
-#ifdef DEBUG
+#if DEBUG
printf("Mapping vbn %d to %d (%d -> %d)[%d] file (%x)\n",
vbn,*phyblk,wcb->loblk,wcb->hiblk,wcb->hd_basevbn,
fcb->cache.hashval);
@@ -447,19 +445,21 @@ void *vioc_manager(struct CACHE * cacheobj,int flushonly)
register unsigned curvbn = vioc->cache.hashval + 1;
register char *address = (char *) vioc->data;
register unsigned modmask = vioc->modmask;
+#if DEBUG
printf("\nvioc_manager writing vbn %d\n",curvbn);
+#endif
do {
register unsigned sts;
unsigned int wrtlen = 0;
unsigned phyblk,phylen;
struct VCBDEV *vcbdev;
- while (length > 0 && (1 & modmask) == 0) {
+ while (length > 0 && !(1 & modmask) ) {
length--;
curvbn++;
address += 512;
modmask = modmask >> 1;
}
- while (wrtlen < length && (1 & modmask) != 0) {
+ while (wrtlen < length && (1 & modmask) ) {
wrtlen++;
modmask = modmask >> 1;
}
@@ -476,7 +476,7 @@ void *vioc_manager(struct CACHE * cacheobj,int flushonly)
curvbn + phylen > fcb->highwater) {
phylen = fcb->highwater - curvbn;
}
- sts = phyio_write( vcbdev->dev, phyblk, phylen * 512, address );
+ sts = virt_write( vcbdev->dev, phyblk, phylen * 512, address );
if (!(sts & STS$M_SUCCESS)) return NULL;
wrtlen -= phylen;
curvbn += phylen;
@@ -496,7 +496,7 @@ void *vioc_manager(struct CACHE * cacheobj,int flushonly)
unsigned deaccesschunk(struct VIOC *vioc,unsigned wrtvbn,
int wrtblks,int reuse)
{
-#ifdef DEBUG
+#if DEBUG
printf("Deaccess chunk %8x\n",vioc->cache.hashval);
#endif
if (wrtvbn) {
@@ -550,7 +550,7 @@ static void *vioc_create( unsigned hashval, void *keyval, unsigned *retsts ) {
if (fcb->highwater != 0 && curvbn + phylen > fcb->highwater) {
phylen = fcb->highwater - curvbn;
}
- sts = phyio_read( vcbdev->dev, phyblk, phylen * 512,
+ sts = virt_read( vcbdev->dev, phyblk, phylen * 512,
address);
}
if (!(sts & STS$M_SUCCESS)) {
@@ -578,13 +578,14 @@ unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc,
unsigned sts;
register unsigned int blocks;
register struct VIOC *vioc;
-#ifdef DEBUG
+#if DEBUG
printf("Access chunk %d (%x)\n",vbn,fcb->cache.hashval);
#endif
if (vbn < 1 || vbn > fcb->hiblock) return SS$_ENDOFFILE;
blocks = (vbn - 1) / VIOC_CHUNKSIZE * VIOC_CHUNKSIZE;
if (wrtblks) {
- if (!(fcb->status & FCB_WRITE)) return SS$_WRITLCK;
+ if( !(fcb->status & FCB_WRITE) )
+ return SS$_WRITLCK;
if (vbn + wrtblks > blocks + VIOC_CHUNKSIZE + 1) {
return SS$_BADPARAM;
}
@@ -618,7 +619,7 @@ unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc,
unsigned deaccessfile(struct FCB *fcb)
{
-#ifdef DEBUG
+#if DEBUG
printf("Deaccessing file (%x) reference %d\n",fcb->cache.hashval,
fcb->cache.refcount);
#endif
@@ -627,17 +628,19 @@ unsigned deaccessfile(struct FCB *fcb)
refcount = cache_refcount((struct CACHE *) fcb->wcb) +
cache_refcount((struct CACHE *) fcb->vioc);
if (refcount != 0) {
+#if DEBUG
printf("File reference counts non-zero %d (%d)\n",refcount,
fcb->cache.hashval);
-#ifdef DEBUG
+#endif
+#if DEBUG
printf("File reference counts non-zero %d %d\n",
cache_refcount((struct CACHE *) fcb->wcb),
cache_refcount((struct CACHE *) fcb->vioc));
#endif
return SS$_BUGCHECK;
}
- if (fcb->status & FCB_WRITE) {
- if (VMSLONG(fcb->head->fh2$l_filechar) & FH2$M_MARKDEL) {
+ if( fcb->status & FCB_WRITE ) {
+ if (F11LONG(fcb->head->fh2$l_filechar) & FH2$M_MARKDEL) {
return deallocfile(fcb);
}
}
@@ -704,12 +707,13 @@ unsigned accessfile(struct VCB * vcb,struct fiddef * fid,struct FCB **fcbadd,
unsigned sts;
register struct FCB *fcb;
register unsigned filenum = (fid->fid$b_nmx << 16) + fid->fid$w_num;
-#ifdef DEBUG
+#if DEBUG
printf("Accessing file (%d,%d,%d)\n",(fid->fid$b_nmx << 16) +
fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn);
#endif
if (filenum < 1) return SS$_BADPARAM;
- if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;
+ if( wrtflg && !(vcb->status & VCB_WRITE) )
+ return SS$_WRITLCK;
if (fid->fid$b_rvn > 1) filenum |= fid->fid$b_rvn << 24;
fcb = cache_find((void *) &vcb->fcb,filenum,NULL,&sts,NULL,fcb_create);
if (fcb == NULL) return sts;
@@ -721,7 +725,7 @@ unsigned accessfile(struct VCB * vcb,struct fiddef * fid,struct FCB **fcbadd,
fcb->vcb = vcb;
}
if (wrtflg) {
- if (fcb->headvioc != NULL && (fcb->status & FCB_WRITE) == 0) {
+ if( fcb->headvioc != NULL && !(fcb->status & FCB_WRITE) ) {
deaccesshead(fcb->headvioc,NULL,0);
fcb->headvioc = NULL;
}
@@ -732,14 +736,16 @@ unsigned accessfile(struct VCB * vcb,struct fiddef * fid,struct FCB **fcbadd,
sts = accesshead(vcb,fid,0,&fcb->headvioc,&fcb->head,&fcb->headvbn,
wrtflg);
if (sts & STS$M_SUCCESS) {
- fcb->hiblock = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
+ fcb->hiblock = F11SWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
if (fcb->head->fh2$b_idoffset > 39) {
- fcb->highwater = VMSLONG(fcb->head->fh2$l_highwater);
+ fcb->highwater = F11LONG(fcb->head->fh2$l_highwater);
} else {
fcb->highwater = 0;
}
} else {
+#if DEBUG
printf("Accessfile status %d\n",sts);
+#endif
fcb->cache.objmanager = NULL;
cache_untouch(&fcb->cache,FALSE);
cache_delete(&fcb->cache);
@@ -759,8 +765,9 @@ unsigned dismount(struct VCB * vcb)
struct VCBDEV *vcbdev;
int expectfiles = vcb->devices;
int openfiles = cache_refcount(&vcb->fcb->cache);
- if (vcb->status & VCB_WRITE) expectfiles *= 2;
-#ifdef DEBUG
+ if( vcb->status & VCB_WRITE )
+ expectfiles *= 2;
+#if DEBUG
printf("Dismounting disk %d\n",openfiles);
#endif
sts = SS$_NORMAL;
@@ -769,14 +776,14 @@ unsigned dismount(struct VCB * vcb)
} else {
vcbdev = vcb->vcbdev;
for (device = 0; device < vcb->devices; device++) {
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): vcbdev[%d] = \"%s\"\n", device,
vcbdev->dev != NULL ? vcbdev->dev->devnam : "NULL" );
#endif
if (vcbdev->dev != NULL) {
if (vcb->status & VCB_WRITE && vcbdev->mapfcb != NULL) {
sts = deaccessfile(vcbdev->mapfcb);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): %d = deaccessfile()\n", sts );
#endif
if (!(sts & STS$M_SUCCESS)) break;
@@ -784,25 +791,25 @@ unsigned dismount(struct VCB * vcb)
vcbdev->mapfcb = NULL;
}
cache_remove(&vcb->fcb->cache);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): cache_remove()\n" );
#endif
sts = deaccesshead(vcbdev->idxfcb->headvioc,
vcbdev->idxfcb->head,
vcbdev->idxfcb->headvbn);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): %d = deaccesshead()\n", sts );
#endif
if (!(sts & STS$M_SUCCESS)) break;
vcbdev->idxfcb->headvioc = NULL;
cache_untouch(&vcbdev->idxfcb->cache,FALSE);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): cache_untouch()\n" );
#endif
vcbdev->dev->vcb = NULL;
- phyio_done( vcbdev->dev );
-#ifdef DEBUG
- printf( "--->dismount(): phyio_done()\n" );
+ virt_close( vcbdev->dev );
+#if DEBUG
+ printf( "--->dismount(): virt_close()\n" );
#endif
}
vcbdev++;
@@ -811,12 +818,12 @@ unsigned dismount(struct VCB * vcb)
struct VCB *lp;
cache_remove(&vcb->fcb->cache);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): cache_remove()\n" );
#endif
while (vcb->dircache) {
cache_delete((struct CACHE *) vcb->dircache);
-#ifdef DEBUG
+#if DEBUG
printf( "--->dismount(): cache_delete()\n" );
#endif
}
@@ -834,7 +841,7 @@ unsigned dismount(struct VCB * vcb)
/******************************************************************** mount() */
-#ifdef DEBUG
+#if DEBUG
#ifndef HOME_SKIP
#define HOME_SKIP 1
#endif
@@ -855,18 +862,15 @@ unsigned dismount(struct VCB * vcb)
unsigned mount( unsigned flags,
unsigned devices,
char *devnam[],
- char *label[],
- struct VCB **retvcb ) {
+ char *label[] ) {
register unsigned device,sts = 0;
struct VCB *vcb;
struct VCBDEV *vcbdev;
struct VOLSETREC *volsetSYS = NULL;
-#ifdef DEBUG
+#if DEBUG
if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL;
#endif
- if( retvcb )
- *retvcb = NULL;
vcb = (struct VCB *) calloc( 1, sizeof(struct VCB) +
((devices - 1) * sizeof(struct VCBDEV)) );
@@ -897,29 +901,10 @@ unsigned mount( unsigned flags,
sts = SS$_BADPARAM;
break;
}
- if( flags & MOU_VIRTUAL ) {
- sts = virt_device( dname, &dname );
- if( !(sts & STS$M_SUCCESS) ) break;
- } else {
- if( virt_lookup( dname ) != NULL ) {
- char *p;
- p = strchr( dname, ':' );
- if( p != NULL ) *p = '\0';
- printf( "%%ODS2-E-VIRTDEV, %s is a virtual device\n", dname );
- sts = SS$_DEVMOUNT;
- break;
- }
- }
+ sts = virt_open( &dname, flags, &vcbdev->dev );
+ if( !(sts & STS$M_SUCCESS) )
+ break;
vcb->devices++;
- sts = device_lookup( strlen( dname ), dname, TRUE,
- &vcbdev->dev );
- if( !(sts & STS$M_SUCCESS) )
- break;
- vcbdev->dev->access = flags; /* Requested mount options */
- /* (e.g., /Write) */
- sts = phyio_init( vcbdev->dev );
- if( !(sts & STS$M_SUCCESS) )
- break;
if (vcbdev->dev->vcb != NULL) {
sts = SS$_DEVMOUNT;
break;
@@ -933,7 +918,7 @@ unsigned mount( unsigned flags,
if( homtry < HOME_SKIP )
continue;
#endif
- sts = phyio_read( vcbdev->dev, hba, sizeof( struct HOME ),
+ sts = virt_read( vcbdev->dev, hba, sizeof( struct HOME ),
(char *) &vcbdev->home );
if (!(sts & STS$M_SUCCESS)) break;
hom = &vcbdev->home;
@@ -941,70 +926,73 @@ unsigned mount( unsigned flags,
printf( "--->mount(%u): LBA=%u, HM2$L_HOMELBN=%u, "
"HM2$L_ALHOMELBN=%u, "
"HM2$T_FORMAT=\"%12.12s\", memcmp()=%u\n",
- homtry+1,hba, VMSLONG( hom->hm2$l_homelbn ),
- VMSLONG( hom->hm2$l_alhomelbn ),
+ homtry+1,hba, F11LONG( hom->hm2$l_homelbn ),
+ F11LONG( hom->hm2$l_alhomelbn ),
hom->hm2$t_format,
memcmp( hom->hm2$t_format, "DECFILE11B ", 12 )
);
#endif
- if( (hba == VMSLONG(hom->hm2$l_homelbn)) &&
- (VMSLONG(hom->hm2$l_alhomelbn) != 0) &&
- (VMSLONG(hom->hm2$l_altidxlbn) != 0) &&
- (VMSWORD(hom->hm2$w_homevbn) != 0) &&
- (VMSLONG(hom->hm2$l_ibmaplbn) != 0) &&
- (VMSWORD(hom->hm2$w_ibmapsize) != 0) &&
- (VMSWORD(hom->hm2$w_resfiles) >= 5) &&
- (VMSWORD(hom->hm2$w_checksum1) ==
- checksumn( (vmsword *)hom,
+ if( (hba == F11LONG(hom->hm2$l_homelbn)) &&
+ (F11LONG(hom->hm2$l_alhomelbn) != 0) &&
+ (F11LONG(hom->hm2$l_altidxlbn) != 0) &&
+ (F11WORD(hom->hm2$w_homevbn) != 0) &&
+ (F11LONG(hom->hm2$l_ibmaplbn) != 0) &&
+ (F11WORD(hom->hm2$w_ibmapsize) != 0) &&
+ (F11WORD(hom->hm2$w_resfiles) >= 5) &&
+ (F11WORD(hom->hm2$w_checksum1) ==
+ checksumn( (f11word *)hom,
(offsetof( struct HOME, hm2$w_checksum1 )/2) )) &&
- (VMSWORD(hom->hm2$w_checksum2) ==
- checksum( (vmsword *)hom )) &&
+ (F11WORD(hom->hm2$w_checksum2) ==
+ checksum( (f11word *)hom )) &&
(memcmp(hom->hm2$t_format,"DECFILE11B ",12) == 0) ) {
break;
}
#if defined( DEBUG ) || defined( HOME_LOG )
printf( "--->mount(): Home block validation failure\n" );
- printf( "(VMSLONG(hom->hm2$l_alhomelbn) != 0) %u\n", (VMSLONG(hom->hm2$l_alhomelbn) != 0) );
- printf( "(VMSLONG(hom->hm2$l_altidxlbn) != 0) %u\n", (VMSLONG(hom->hm2$l_altidxlbn) != 0) );
- printf( "(VMSWORD(hom->hm2$w_homevbn) != 0) %u\n", (VMSWORD(hom->hm2$w_homevbn) != 0));
- printf( "(VMSLONG(hom->hm2$l_ibmaplbn) != 0) %u\n", (VMSLONG(hom->hm2$l_ibmaplbn) != 0) );
- printf( "(VMSWORD(hom->hm2$w_ibmapsize) != 0) %u\n", (VMSWORD(hom->hm2$w_ibmapsize) != 0));
- printf( "(VMSWORD(hom->hm2$w_resfiles) >= 5) %u\n", (VMSWORD(hom->hm2$w_resfiles) >= 5));
- printf( "(VMSWORD(hom->hm2$w_checksum1) = %u %u\n", VMSWORD(hom->hm2$w_checksum1),
- checksumn( (vmsword *)hom,
+ printf( "(F11LONG(hom->hm2$l_alhomelbn) != 0) %u\n", (F11LONG(hom->hm2$l_alhomelbn) != 0) );
+ printf( "(F11LONG(hom->hm2$l_altidxlbn) != 0) %u\n", (F11LONG(hom->hm2$l_altidxlbn) != 0) );
+ printf( "(F11WORD(hom->hm2$w_homevbn) != 0) %u\n", (F11WORD(hom->hm2$w_homevbn) != 0));
+ printf( "(F11LONG(hom->hm2$l_ibmaplbn) != 0) %u\n", (F11LONG(hom->hm2$l_ibmaplbn) != 0) );
+ printf( "(F11WORD(hom->hm2$w_ibmapsize) != 0) %u\n", (F11WORD(hom->hm2$w_ibmapsize) != 0));
+ printf( "(F11WORD(hom->hm2$w_resfiles) >= 5) %u\n", (F11WORD(hom->hm2$w_resfiles) >= 5));
+ printf( "(F11WORD(hom->hm2$w_checksum1) = %u %u\n", F11WORD(hom->hm2$w_checksum1),
+ checksumn( (f11word *)hom,
(offsetof( struct HOME, hm2$w_checksum1 )/2) ) );
- printf( "(VMSWORD(hom->hm2$w_checksum2) = %u %u\n", VMSWORD(hom->hm2$w_checksum2),
- checksum( (vmsword *)hom ));
+ printf( "(F11WORD(hom->hm2$w_checksum2) = %u %u\n", F11WORD(hom->hm2$w_checksum2),
+ checksum( (f11word *)hom ));
#endif
sts = SS$_ENDOFFILE;
}
- if( !(sts & 1) ) break;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
if( label[device] != NULL ) {
int i;
char lbl[12+1]; /* Pad CLI-supplied label to match ODS */
- snprintf( lbl, sizeof(lbl), "%-12s", label[device] );
+ (void) snprintf( lbl, sizeof(lbl), "%-12s", label[device] );
for( i = 0; i < 12; i++ ) {
- if( toupper(lbl[i]) != vcbdev->home.hm2$t_volname[i] ) {
+ if( toupper( lbl[i] ) != toupper( vcbdev->home.hm2$t_volname[i] ) ) {
printf( "%%ODS2-W-WRONGVOL, Device %s contains volume '%12.12s', '%s' expected\n",
dname, vcbdev->home.hm2$t_volname, lbl );
sts = SS$_ITEMNOTFOUND;
break;
}
}
- if (!(sts & STS$M_SUCCESS)) break;
- if (flags & MOU_WRITE && !(vcbdev->dev->access & MOU_WRITE)) {
- printf("%%MOUNT-W-WRITELOCK, %s is write locked\n",
- dname);
- vcb->status &= ~VCB_WRITE;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
+ if (flags & MOU_WRITE && !(vcbdev->dev->access & MOU_WRITE)) {
+ printf("%%MOUNT-W-WRITELOCK, %s is write locked\n",
+ dname);
+ vcb->status &= ~VCB_WRITE;
+ }
}
- }
- if( (VMSWORD(vcbdev->home.hm2$w_rvn) != device + 1) &&
- !(VMSWORD(vcbdev->home.hm2$w_rvn) == 0 && device == 0) ) {
+ if( (F11WORD(vcbdev->home.hm2$w_rvn) != device + 1) &&
+ !(F11WORD(vcbdev->home.hm2$w_rvn) == 0 && device == 0) ) {
printf( "%%ODS2-E-WRONGVOL, Device %s contains RVN %u, RVN %u expected\n",
- dname, VMSWORD(vcbdev->home.hm2$w_rvn), device+1 );
+ dname, F11WORD(vcbdev->home.hm2$w_rvn), device+1 );
sts = SS$_UNSUPVOLSET;
}
- if (!(sts & 1)) break;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
} /* for(each device) */
}
if (sts & STS$M_SUCCESS) {
@@ -1024,11 +1012,12 @@ unsigned mount( unsigned flags,
idxfid.fid$b_rvn = device + 1;
sts = accessfile( vcb, &idxfid, &vcbdev->idxfcb, (vcb->status & VCB_WRITE) != 0 );
if (!(sts & STS$M_SUCCESS)) {
- vcbdev->dev = NULL; /*** DECREF ***/
+ virt_close( vcbdev->dev );
+ vcbdev->dev = NULL;
continue;
}
vcbdev->dev->vcb = vcb;
- if( VMSWORD(vcbdev->home.hm2$w_rvn) != 0 ) {
+ if( F11WORD(vcbdev->home.hm2$w_rvn) != 0 ) {
if( device == 0 ) {
struct fiddef vsfid = {6,6,1,0};
struct FCB *vsfcb = NULL;
@@ -1037,7 +1026,7 @@ unsigned mount( unsigned flags,
int rec;
unsigned int vbn = 1;
struct VOLSETREC *bufp;
- int setcount = VMSWORD(vcbdev->home.hm2$w_setcount);
+ int setcount = F11WORD(vcbdev->home.hm2$w_setcount);
if( setcount != (int)devices ) {
printf( "%%ODS2-E-VOLCOUNT, Volume set %12.12s has %u members, but %u specified\n",
@@ -1048,7 +1037,7 @@ unsigned mount( unsigned flags,
/* Read VOLSET.SYS */
volsetSYS = (struct VOLSETREC *)malloc( (1+setcount) * sizeof( struct VOLSETREC ) );
sts = accessfile( vcb, &vsfid, &vsfcb, 0 );
- if( (sts & 1) == 0 ) {
+ if( !(sts & STS$M_SUCCESS) ) {
printf( "%%ODS2-E-NOVOLSET, Unable to access VOLSET.SYS: %s\n", getmsg(sts, MSG_TEXT) );
break;
}
@@ -1056,7 +1045,8 @@ unsigned mount( unsigned flags,
if( recs == 0 ) {
if( vbn != 1 ) deaccesschunk(vioc,0,0,0);
sts = accesschunk(vsfcb,vbn, &vioc,(char **)&bufp, &recs, 0);
- if( (sts & 1) == 0 ) break;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
vbn += recs;
recs *= 512 / sizeof( struct VOLSETREC );
}
@@ -1065,9 +1055,9 @@ unsigned mount( unsigned flags,
deaccesschunk(vioc,0,0,0);
{ int st2;
st2 = deaccessfile(vsfcb);
- if( sts & 1 ) sts = st2;
+ if( sts & STS$M_SUCCESS ) sts = st2;
}
- if( (sts & 1) == 0 ) {
+ if( !(sts & STS$M_SUCCESS) ) {
printf( "%%ODS2-E-VOLIOERR, Error reading VOLSET.SYS: %s\n", getmsg(sts, MSG_TEXT) );
break;
}
@@ -1102,97 +1092,103 @@ unsigned mount( unsigned flags,
} /* rvn != 0 */
if( vcb->status & VCB_WRITE ) {
- struct fiddef mapfid = {2,2,0,0};
+ struct fiddef mapfid = { 2, 2, 0, 0 };
mapfid.fid$b_rvn = device + 1;
- sts = accessfile(vcb,&mapfid,&vcbdev->mapfcb,TRUE);
- if (sts & STS$M_SUCCESS) {
- struct VIOC *vioc;
- struct SCB *scb;
- sts = accesschunk(vcbdev->mapfcb,1,&vioc,
- (char **) &scb,NULL,0);
- if (sts & STS$M_SUCCESS) {
- if (scb->scb$w_cluster ==
- vcbdev->home.hm2$w_cluster) {
+ sts = accessfile( vcb,&mapfid, &vcbdev->mapfcb, TRUE );
+ if( sts & STS$M_SUCCESS ) {
+ struct VIOC *vioc;
+ struct SCB *scb;
+
+/* TODO *** scb->scb$w_checksum == checksum( (f11word *)scb */
+ sts = accesschunk( vcbdev->mapfcb, 1, &vioc,
+ (char **) &scb, NULL ,0 );
+ if( sts & STS$M_SUCCESS ) {
+ if( scb->scb$w_cluster ==
+ vcbdev->home.hm2$w_cluster ) {
vcbdev->clustersize =
- vcbdev->home.hm2$w_cluster;
+ F11WORD( vcbdev->home.hm2$w_cluster );
vcbdev->max_cluster =
- (scb->scb$l_volsize +
- scb->scb$w_cluster - 1) /
- scb->scb$w_cluster;
+ (F11LONG(scb->scb$l_volsize) +
+ F11WORD(scb->scb$w_cluster) - 1) /
+ F11WORD(scb->scb$w_cluster);
deaccesschunk(vioc,0,0,FALSE);
sts = update_freecount(
- vcbdev,&vcbdev->free_clusters
- );
-#ifdef DEBUG
- printf( "%d of %d blocks are free on %12.12s\n",
- vcbdev->free_clusters * vcbdev->clustersize, scb->scb$l_volsize,
+ vcbdev,&vcbdev->free_clusters
+ );
+#if DEBUG
+ printf( "%d of %d blocks are free on %12.12s\n",
+ vcbdev->free_clusters * vcbdev->clustersize, scb->scb$l_volsize,
vcbdev->home.hm2$t_volname );
#endif
- }
+ } else {
+ deaccesschunk(vioc,0,0,FALSE);
+ }
}
- } else {
- printf( "%%ODS2-E-NOBITMAP, Unable to access BITMAP.SYS: %s\n", getmsg(sts, MSG_TEXT) );
+ } else {
+ printf( "%%ODS2-E-NOBITMAP, Unable to access BITMAP.SYS: %s\n", getmsg(sts, MSG_TEXT) );
vcbdev->mapfcb = NULL;
break;
}
}
- if( (sts & 1) && (flags & MOU_LOG) ) {
- printf("%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n",
- vcbdev->home.hm2$t_volname, vcbdev->dev->devnam);
+ if( (sts & STS$M_SUCCESS) && (flags & MOU_LOG) ) {
+ printf( "%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n",
+ vcbdev->home.hm2$t_volname, vcbdev->dev->devnam );
}
} /* device len */
} /* for( each device ) */
- if( !(sts & 1) ) {
+ if( !(sts & STS$M_SUCCESS) ) {
vcbdev = vcb->vcbdev;
for( device = 0; device < devices; device++, vcbdev++ ) {
if (vcbdev->dev == NULL) {
- if( flags & MOU_VIRTUAL )
- virt_device( devnam[device], NULL );
continue;
}
if( vcb->status & VCB_WRITE && vcbdev->mapfcb != NULL ) {
/* sts = */
deaccessfile(vcbdev->mapfcb);
- /* if( !(sts & 1) ) ??; */
+ /* if( !(sts & STS$M_SUCCESS) ) ??; */
vcbdev->idxfcb->status &= ~FCB_WRITE;
vcbdev->mapfcb = NULL;
}
cache_remove( &vcb->fcb->cache );
/* sts = */
deaccesshead(vcbdev->idxfcb->headvioc,vcbdev->idxfcb->head,vcbdev->idxfcb->headvbn);
- /* if (!(sts & 1)) ??; */
+ /* if (!(sts & STS$M_SUCCESS)) ??; */
vcbdev->idxfcb->headvioc = NULL;
cache_untouch(&vcbdev->idxfcb->cache,0);
vcbdev->dev->vcb = NULL;
- /* ?? vcbdev->dev = NULL *//* **DECREF **/
- sts = phyio_done( vcbdev->dev );
+ sts = virt_close( vcbdev->dev );
}
cache_remove( &vcb->fcb->cache );
while( vcb->dircache ) cache_delete( (struct CACHE *) vcb->dircache );
}
- } else { /* *** DECREF *** */
+ } else {
vcbdev = vcb->vcbdev;
for( device = 0; device < vcb->devices; device++, vcbdev++ ) {
if (vcbdev->dev == NULL) {
- if( flags & MOU_VIRTUAL )
- virt_device( devnam[device], NULL );
continue;
}
- phyio_done( vcbdev->dev );
+ virt_close( vcbdev->dev );
}
free(vcb);
vcb = NULL;
}
- if( (sts & 1) && (flags & MOU_LOG) && VMSWORD(vcb->vcbdev[0].home.hm2$w_rvn) != 0 ) {
+ if( (sts & STS$M_SUCCESS) && (flags & MOU_LOG) && F11WORD(vcb->vcbdev[0].home.hm2$w_rvn) != 0 ) {
printf ( "%%MOUNT-I-MOUNTEDVS, Volume set %12.12s mounted\n", vcb->vcbdev[0].home.hm2$t_strucname );
}
if( vcb != NULL ) {
- vcb->next = vcb_list;
- vcb_list = vcb;
+ struct VCB *lp;
+
+ for( lp = (struct VCB *)&vcb_list; lp->next != NULL; lp = lp->next )
+ ;
+ lp->next = vcb;
+ vcb->next = NULL;
}
if( volsetSYS != NULL ) free( volsetSYS );
- if (retvcb != NULL) *retvcb = vcb;
+
+ if( sts & STS$M_SUCCESS )
+ (void) mountdef( vcb->vcbdev[0].dev->devnam );
+
return sts;
}
@@ -1208,7 +1204,7 @@ static void print_volhdr( int volset, size_t devwid ) {
else
printf( " " );
printf(
-"%-*s Volume Lvl Clust Owner/CreateDate VolProt/Default FileProt\n",
+"%-*s Volume/User Lvl Clust Owner/CreateDate VolProt/Default FileProt\n",
(int)devwid, "Dev" );
if( volset )
printf( " --- " );
@@ -1224,7 +1220,7 @@ static void print_volhdr( int volset, size_t devwid ) {
}
/********************************************************** print_prot() */
-static void print_prot( vmsword code, int vol ) {
+static void print_prot( f11word code, int vol ) {
static const char grp[4] = { "SOGW" };
static const char acc[2][4] = {{"RWED"}, {"RWCD"}};
int g, b, w;
@@ -1253,11 +1249,42 @@ static void print_volinf( struct VCB *vcb,
unsigned device,
size_t wrap ) {
struct VCBDEV *vcbdev;
+ struct SCB *scb = NULL;
+ struct VIOC *vioc = NULL;
+ unsigned sts;
size_t n;
- vmsword timbuf[7];
+ f11word timbuf[7];
vcbdev = vcb->vcbdev+device;
+ if( !(vcb->status & VCB_WRITE) ) {
+ struct fiddef mapfid = { 2, 2, 0, 0 };
+
+ if( !(( sts = accessfile( vcb, &mapfid, &vcbdev->mapfcb, 0 )) & STS$M_SUCCESS) ) {
+ printf( " *Can't access BITMAP.SYS %s\n", getmsg( sts, MSG_TEXT ) );
+ return;
+ }
+ }
+ if( (sts = accesschunk( vcbdev->mapfcb, 1, &vioc, (char **)&scb, NULL, 0 )) & STS$M_SUCCESS ) {
+ if( scb->scb$w_cluster == vcbdev->home.hm2$w_cluster ) {
+ vcbdev->clustersize = F11WORD(vcbdev->home.hm2$w_cluster);
+ vcbdev->max_cluster = (F11LONG(scb->scb$l_volsize) +
+ F11WORD(scb->scb$w_cluster) - 1) /
+ F11WORD(scb->scb$w_cluster);
+ deaccesschunk(vioc,0,0,FALSE);
+ if( !(vcb->status & VCB_WRITE) )
+ sts = update_freecount( vcbdev, &vcbdev->free_clusters );
+ } else {
+ printf(" SCB data doesn't match HOM %u / %u ",
+ F11WORD(scb->scb$w_cluster), F11WORD(vcbdev->home.hm2$w_cluster) );
+ deaccesschunk(vioc,0,0,FALSE);
+ }
+ } else {
+ printf( " *Can't read SCB %s", getmsg( sts, MSG_TEXT ) );
+ }
+ if( !(vcb->status & VCB_WRITE) )
+ deaccessfile( vcbdev->mapfcb );
+
for( n = 0; n < strlen( vcbdev->dev->devnam ); n++ ) {
if( vcbdev->dev->devnam[n] == ':' )
break;
@@ -1268,18 +1295,53 @@ static void print_volinf( struct VCB *vcb,
printf( "%12.12s", vcbdev->home.hm2$t_volname );
printf( " %u.%u %5u [%6o,%6o]",
- VMSWORD( vcbdev->home.hm2$w_struclev ) >> 8,
- VMSWORD( vcbdev->home.hm2$w_struclev ) & 0xFF,
- VMSWORD( vcbdev->home.hm2$w_cluster ),
- VMSWORD( vcbdev->home.hm2$w_volowner.uic$w_grp ),
- VMSWORD( vcbdev->home.hm2$w_volowner.uic$w_mem )
+ F11WORD( vcbdev->home.hm2$w_struclev ) >> 8,
+ F11WORD( vcbdev->home.hm2$w_struclev ) & 0xFF,
+ F11WORD( vcbdev->home.hm2$w_cluster ),
+ F11WORD( vcbdev->home.hm2$w_volowner.uic$w_grp ),
+ F11WORD( vcbdev->home.hm2$w_volowner.uic$w_mem )
);
printf( " " );
- print_prot( VMSWORD( vcbdev->home.hm2$w_protect ), 1 );
+ print_prot( F11WORD( vcbdev->home.hm2$w_protect ), 1 );
if( !(vcb->status & VCB_WRITE) )
printf( " write-locked" );
- printf( "\n%*s ", (int)(wrap+devwid+23), "" );
+ if( sts & STS$M_SUCCESS ) {
+ disktypep_t dp;
+ int first = 1;
+
+ for( dp = disktype; dp->name != NULL; dp++ ) {
+ unsigned size;
+ unsigned blksize = 1;
+
+ size = dp->sectors * dp->tracks * dp->cylinders - dp->reserved;
+ if( dp->sectorsize > 512 )
+ size = size * dp->sectorsize / 512;
+ else {
+ if( dp->sectorsize < 512 ) {
+ blksize = (512 / dp->sectorsize);
+ size = size / blksize;
+ }
+ }
+ if( scb->scb$l_volsize == size &&
+ scb->scb$l_blksize == blksize &&
+ scb->scb$l_sectors == dp->sectors &&
+ scb->scb$l_tracks == dp->tracks &&
+ scb->scb$l_cylinders == dp->cylinders ) {
+ if( first ) {
+ printf( " type:" );
+ first = 0;
+ } else
+ printf( "|" );
+ printf( " %s", dp->name );
+ }
+ }
+ if( first )
+ printf( " Unrecognized type" );
+ }
+
+ printf( "\n%*s %12.12s ", (int)(wrap+devwid), "",
+ vcbdev->home.hm2$t_ownername );
if( sys$numtim( timbuf, vcbdev->home.hm2$q_credate ) & STS$M_SUCCESS ) {
static const char *months =
@@ -1291,7 +1353,16 @@ static void print_volinf( struct VCB *vcb,
} else
printf( "%*s", 41-23, "" );
- print_prot( VMSWORD( vcbdev->home.hm2$w_fileprot ), 0 );
+ print_prot( F11WORD( vcbdev->home.hm2$w_fileprot ), 0 );
+
+ if( sts & STS$M_SUCCESS ) {
+ printf( " Free: %u/%u", vcbdev->free_clusters * vcbdev->clustersize,
+ scb->scb$l_volsize );
+ printf( " Geo: %u/%u/%u", F11LONG(scb->scb$l_sectors),
+ F11LONG(scb->scb$l_tracks), F11LONG(scb->scb$l_cylinders) );
+ if( F11LONG(scb->scb$l_blksize) != 1 )
+ printf( " %u phys blks/LBN", F11LONG(scb->scb$l_blksize) );
+ }
putchar( '\n' );
}
@@ -1330,7 +1401,7 @@ void show_volumes( void ) {
unsigned device;
vcbdev = vcb->vcbdev;
- if( VMSWORD(vcbdev->home.hm2$w_rvn) == 0 )
+ if( F11WORD(vcbdev->home.hm2$w_rvn) == 0 )
continue;
nvol--;
@@ -1339,7 +1410,7 @@ void show_volumes( void ) {
print_volhdr( TRUE, maxd );
for( device = 0; device < vcb->devices; device++, vcbdev++ ) {
- printf( " %3d ", VMSWORD(vcbdev->home.hm2$w_rvn) );
+ printf( " %3d ", F11WORD(vcbdev->home.hm2$w_rvn) );
print_volinf( vcb, maxd, device, 8 );
}
}
@@ -1354,7 +1425,7 @@ void show_volumes( void ) {
unsigned device;
vcbdev = vcb->vcbdev;
- if( VMSWORD(vcbdev->home.hm2$w_rvn) != 0 )
+ if( F11WORD(vcbdev->home.hm2$w_rvn) != 0 )
continue;
vcbdev = vcb->vcbdev;
@@ -1377,187 +1448,8 @@ void access_rundown( void ) {
sts = dismount( vcb );
if( !(sts & STS$M_SUCCESS) ) {
- printf( "Dismount failed in rundown: %s", getmsg(sts, MSG_TEXT) );
+ printf( "Dismount failed in rundown: %s\n", getmsg(sts, MSG_TEXT) );
}
}
}
-/*************************************************************** compute_delta() */
-/*
- * The search delta is computed from the
- * volume geometry, expressed in sectors, tracks (surfaces), and
- * cylinders, according to the following rules, to handle the cases where
- * one or two dimensions of the volume have a size of 1.
- *
- * Geometry: Delta
- *
- * s x 1 x 1: 1 Rule 1
- * 1 x t x 1: 1 Rule 2
- * 1 x 1 x c: 1 Rule 3
- *
- * s x t x 1: s+1 Rule 4
- * s x 1 x c: s+1 Rule 5
- * 1 x t x c: t+1 Rule 6
- *
- * s x t x c: (t+1)*s+1 Rule 7
- */
-
-
-#define DISK( name, sectors, tracks, cylinders ) \
- {#name, 512 ## ul, sectors ## ul, tracks ## ul, cylinders ## ul},
-#define DISKS( name, sectorsize, sectors, tracks, cylinders ) \
- {#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul},
-struct disktype disktype[] = {
- DISK(UNKNOWN, 1, 1, 1) /* First = short sequence delta = 1 */
- DISK(RK05, 12, 2, 203)
- DISK(RK06, 22, 3, 411)
- DISK(RK07, 22, 3, 815)
- DISK(RK11, 12, 2, 203)
-
- DISK(RL01, 40, 2, 256)
- DISK(RL02, 40, 2, 512)
-
- DISK(RM02, 32, 5, 823)
- DISK(RM03, 32, 5, 823)
- DISK(RP04, 22, 19, 411)
- DISK(RP05, 22, 19, 411)
- DISK(RM80, 31, 14, 559)
- DISK(RP06, 22, 19, 815)
- DISK(RM05, 32, 19, 823)
- DISK(RP07, 50, 32, 630)
-
-#if 0 /* Not useful now as RSX20-F used ODS-1 */
- DISKS(RM02-T, 576, 30, 5, 823)
- DISKS(RM03-T, 576, 30, 5, 823)
- DISKS(RP04-T, 576, 20, 19, 411)
- DISKS(RP05-T, 576, 20, 19, 411)
- DISKS(RM80-T, 576, 30, 14, 559)
- DISKS(RP06-T, 576, 20, 19, 815)
- DISKS(RM05-T, 576, 30, 19, 823)
- DISKS(RP07-T, 576, 43, 32, 630)
-#endif
-
- DISK(RX50, 10, 1, 80)
- DISK(RX33, 15, 2, 80)
-
-#if 0
- DISK(RD50, 99, 99, 9999)
-#endif
- DISK(RD51, 18, 4, 306)
- DISK(RD31, 17, 4, 615)
- DISK(RD52, 17, 8, 512)
- DISK(RD53, 17, 7, 1024)
- DISK(RD54, 17, 15, 1225)
-
- DISK(RA72, 51, 20, 1921)
-
-#if 0
- DISK(RA80, 99, 99, 9999)
-
-#endif
- DISK(RA81, 51, 14, 1258)
- DISK(RA82, 57, 15, 1435)
-
- DISK(RA90, 69, 13, 2649)
- DISK(RA92, 73, 13, 3099)
-
- DISK(RRD40,128, 1, 10400)
- DISK(RRD50,128, 1, 10400)
- DISKS(RX01, 128, 26, 1, 77)
- DISKS(RX02, 256, 26, 1, 77)
-
-#if 0
- DISK(RX23-SD, 99, 99, 9999)
- DISK(RX23-DD, 99, 99, 9999)
-
- DISK(RX33-SD, 10, 1, 80)
- DISK(RX33-DD, 99, 99, 9999)
-#endif
-
- DISK(RX50, 10, 1, 80)
-#if 0
- DISK(RC25, 99, 99, 9999 )
-
- DISK(RF30, 99, 99, 9999 )
- DISK(RF31, 99, 99, 9999 )
- DISK(RF35, 99, 99, 9999 )
- DISK(RF36, 99, 99, 9999 )
- DISK(RF71, 99, 99, 9999 )
- DISK(RF72, 99, 99, 9999 )
- DISK(RF73, 99, 99, 9999 )
- DISK(RF74, 99, 99, 9999 )
-
- DISK(RZ22, 99, 99, 9999 )
- DISK(RZ23, 99, 99, 9999 )
- DISK(RZ24, 99, 99, 9999 )
- DISK(RZ25, 99, 99, 9999 )
- DISK(RZ26, 99, 99, 9999 )
- DISK(RZ27, 99, 99, 9999 )
- DISK(RZ28, 99, 99, 9999 )
- DISK(RZ29, 99, 99, 9999 )
- DISK(RZ31, 99, 99, 9999 )
- DISK(RZ33, 99, 99, 9999 )
- DISK(RZ35, 99, 99, 9999 )
- DISK(RZ55, 99, 99, 9999 )
- DISK(RZ56, 99, 99, 9999 )
- DISK(RZ57, 99, 99, 9999 )
- DISK(RZ58, 99, 99, 9999 )
- DISK(RZ59, 99, 99, 9999 )
-
- DISK(RZ72, 99, 99, 9999 )
- DISK(RZ73, 99, 99, 9999 )
- DISK(RZ74, 99, 99, 9999 )
-#endif
-
- { NULL, 0, 0, 0, 0 }
-};
-
-
-static unsigned int compute_delta( unsigned long sectorsize,
- unsigned long sectors,
- unsigned long tracks,
- unsigned long cylinders ) {
-
- if( sectorsize < 512 )
- sectors = (sectorsize * sectors) / 512;
-
- if( sectors > 1 && tracks > 1 && cylinders > 1 ) /* Rule 7 */
- return (tracks + 1) * sectors +1;
-
- if( (sectors > 1 && tracks > 1 && cylinders == 1 ) || /* Rule 4 */
- (sectors > 1 && tracks == 1 && cylinders > 1 ) ) /* Rule 5 */
- return sectors + 1;
-
- if( sectors == 1 && tracks > 1 && cylinders > 1 ) /* Rule 6 */
- return tracks + 1;
-
- return 1; /* Rules 1-3 */
-}
-
-#if 0
-static unsigned int delta_from_name( const char *diskname ) {
- struct disktype *dp;
-
- for( dp = disktype; dp->name != NULL; dp++ ) {
- if( !strcmp( dp->name, diskname ) )
- return compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
- }
-
- return ~0u;
-}
-#endif
-static unsigned int delta_from_index( size_t index ) {
- struct disktype *dp;
- unsigned int delta;
-
- if( index >= sizeof(disktype)/sizeof(disktype[0]) )
- abort();
- dp = disktype + index;
- delta = compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
-
-#if defined( DEBUG ) || HOME_SKIP > 0
- printf( "HOM search index for %s is %u\n", dp->name, delta );
-#endif
-
- return delta;
-}
diff --git a/extracters/ods2/access.h b/extracters/ods2/access.h
index 2ef9f46..b8cc266 100644
--- a/extracters/ods2/access.h
+++ b/extracters/ods2/access.h
@@ -1,4 +1,4 @@
-/* Access.h V2.1 Definitions for file access routines */
+/* Access.h Definitions for file access routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -14,180 +14,9 @@
#define _ACCESS_H
#include "cache.h"
+#include "f11def.h"
#include "vmstime.h"
-#ifdef ODS2_BIG_ENDIAN
-#define VMSLONG( l ) ( ( (l) & 0x000000ff ) << 24 | \
- ( (l) & 0x0000ff00 ) << 8 | \
- ( (l) & 0x00ff0000 ) >> 8 | \
- (l) >> 24 )
-#define VMSWORD( w ) ( ( (w) & 0x00ff ) << 8 | \
- (w) >> 8 )
-#define VMSSWAP( l ) ( ( (l) & 0x00ff0000 ) << 8 | \
- ( (l) & 0xff000000 ) >> 8 | \
- ( (l) & 0x000000ff ) << 8 | \
- ( (l) & 0x0000ff00 ) >> 8 )
-#else
-#define VMSLONG( l ) (l)
-#define VMSWORD( w ) (w)
-#define VMSSWAP( l ) ( ( (l) & 0x0000ffff ) << 16 | \
- (l) >> 16 )
-#endif
-
-typedef unsigned char vmsbyte;
-typedef unsigned short vmsword;
-typedef unsigned int vmsswap;
-typedef unsigned int vmslong;
-
-#define FH2$M_NOBACKUP 0x00002
-#define FH2$M_CONTIGB 0x00020
-#define FH2$M_CONTIG 0x00080
-#define FH2$M_DIRECTORY 0x02000
-#define FH2$M_MARKDEL 0x08000
-#define FH2$M_ERASE 0x20000
-
-#ifdef __ALPHA
-#pragma member_alignment save
-#pragma nomember_alignment
-#endif
-
-
-struct UIC {
- vmsword uic$w_mem;
- vmsword uic$w_grp;
-};
-
-struct fiddef {
- vmsword fid$w_num;
- vmsword fid$w_seq;
- vmsbyte fid$b_rvn;
- vmsbyte fid$b_nmx;
-};
-
-struct RECATTR {
- vmsbyte fat$b_rtype;
- vmsbyte fat$b_rattrib;
- vmsword fat$w_rsize;
- vmsswap fat$l_hiblk;
- vmsswap fat$l_efblk;
- vmsword fat$w_ffbyte;
- vmsbyte fat$b_bktsize;
- vmsbyte fat$b_vfcsize;
- vmsword fat$w_maxrec;
- vmsword fat$w_defext;
- vmsword fat$w_gbc;
- vmsbyte fat$_UU0[8];
- vmsword fat$w_versions;
-};
-
-struct HOME {
- vmslong hm2$l_homelbn;
- vmslong hm2$l_alhomelbn;
- vmslong hm2$l_altidxlbn;
- vmsword hm2$w_struclev;
- vmsword hm2$w_cluster;
- vmsword hm2$w_homevbn;
- vmsword hm2$w_alhomevbn;
- vmsword hm2$w_altidxvbn;
- vmsword hm2$w_ibmapvbn;
- vmslong hm2$l_ibmaplbn;
- vmslong hm2$l_maxfiles;
- vmsword hm2$w_ibmapsize;
- vmsword hm2$w_resfiles;
- vmsword hm2$w_devtype;
- vmsword hm2$w_rvn;
- vmsword hm2$w_setcount;
- vmsword hm2$w_volchar;
- struct UIC hm2$w_volowner;
- vmslong hm2$l_reserved1;
- vmsword hm2$w_protect;
- vmsword hm2$w_fileprot;
- vmsword hm2$w_reserved2;
- vmsword hm2$w_checksum1;
- VMSTIME hm2$q_credate;
- vmsbyte hm2$b_window;
- vmsbyte hm2$b_lru_lim;
- vmsword hm2$w_extend;
- VMSTIME hm2$q_retainmin;
- VMSTIME hm2$q_retainmax;
- VMSTIME hm2$q_revdate;
- vmsbyte hm2$r_min_class[20];
- vmsbyte hm2$r_max_class[20];
- vmsbyte hm2$t_reserved3[320];
- vmslong hm2$l_serialnum;
- char hm2$t_strucname[12];
- char hm2$t_volname[12];
- char hm2$t_ownername[12];
- char hm2$t_format[12];
- vmsword hm2$w_reserved4;
- vmsword hm2$w_checksum2;
-};
-
-struct IDENT {
- char fi2$t_filename[20];
- vmsword fi2$w_revision;
- VMSTIME fi2$q_credate;
- VMSTIME fi2$q_revdate;
- VMSTIME fi2$q_expdate;
- VMSTIME fi2$q_bakdate;
- char fi2$t_filenamext[66];
-};
-
-struct HEAD {
- vmsbyte fh2$b_idoffset;
- vmsbyte fh2$b_mpoffset;
- vmsbyte fh2$b_acoffset;
- vmsbyte fh2$b_rsoffset;
- vmsword fh2$w_seg_num;
- vmsword fh2$w_struclev;
- struct fiddef fh2$w_fid;
- struct fiddef fh2$w_ext_fid;
- struct RECATTR fh2$w_recattr;
- vmslong fh2$l_filechar;
- vmsword fh2$w_reserved1;
- vmsbyte fh2$b_map_inuse;
- vmsbyte fh2$b_acc_mode;
- struct UIC fh2$l_fileowner;
- vmsword fh2$w_fileprot;
- struct fiddef fh2$w_backlink;
- vmsbyte fh2$b_journal;
- vmsbyte fh2$b_ru_active;
- vmsword fh2$w_reserved2;
- vmslong fh2$l_highwater;
- vmsbyte fh2$b_reserved3[8];
- vmsbyte fh2$r_class_prot[20];
- vmsbyte fh2$r_restofit[402];
- vmsword fh2$w_checksum;
-};
-
-struct SCB {
- vmsword scb$w_struclev;
- vmsword scb$w_cluster;
- vmslong scb$l_volsize;
- vmslong scb$l_blksize;
- vmslong scb$l_sectors;
- vmslong scb$l_tracks;
- vmslong scb$l_cylinders;
- vmslong scb$l_status;
- vmslong scb$l_status2;
- vmsword scb$w_writecnt;
- char scb$t_volockname[12];
- VMSTIME scb$q_mounttime;
- vmsword scb$w_backrev;
- vmslong scb$q_genernum[2];
- char scb$b_reserved[446];
- vmsword scb$w_checksum;
-};
-
-struct VOLSETREC {
- char vsr$t_label[12];
- char vsr$b_reserved[52];
-};
-
-#ifdef __ALPHA
-#pragma member_alignment restore
-#endif
-
#define EXTMAX 20
struct WCB {
@@ -256,13 +85,6 @@ struct VCB {
extern struct VCB *vcb_list;
void show_volumes( void );
-struct disktype {
- const char *name;
- unsigned long sectorsize, sectors, tracks, cylinders;
-};
-
-extern struct disktype disktype[];
-
/* RVN_TO_DEV( vcb, rvn ) - returns device from relative volume number */
/* returns NULL if RVN illegal or device not mounted */
@@ -278,8 +100,7 @@ extern struct disktype disktype[];
void fid_copy(struct fiddef *dst,struct fiddef *src,unsigned rvn);
unsigned dismount(struct VCB *vcb);
-unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
- struct VCB **vcb);
+unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[] );
unsigned accesserase(struct VCB *vcb,struct fiddef *fid);
unsigned deaccessfile(struct FCB *fcb);
@@ -294,7 +115,8 @@ unsigned update_freecount(struct VCBDEV *vcbdev,unsigned *retcount);
unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename,
struct fiddef *fid,struct FCB **fcb);
unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig);
-vmsword checksum( vmsword *block );
+f11word checksumn( f11word *block, int count );
+f11word checksum( f11word *block );
void access_rundown( void );
diff --git a/extracters/ods2/build.com b/extracters/ods2/build.com
old mode 100644
new mode 100755
diff --git a/extracters/ods2/cache.c b/extracters/ods2/cache.c
index 4983dcd..111e78f 100644
--- a/extracters/ods2/cache.c
+++ b/extracters/ods2/cache.c
@@ -1,4 +1,4 @@
-/* Cache.c V2.1 Caching control routines */
+/* Cache.c Caching control routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -46,24 +46,26 @@
about ODS2 objects or structures....
*/
+#if !defined( DEBUG ) && defined( DEBUG_CACHE )
+#define DEBUG DEBUG_CACHE
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+/* *** TEMP TODO ***/
+#undef DEBUG
+#define DEBUG 1
+
#include
#include
#include "cache.h"
+#include "ods2.h"
#include "ssdef.h"
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
-#ifndef DEBUG
-#define DEBUG
-#endif
-
#define IMBALANCE 5 /* Tree imbalance limit */
#define CACHELIM 256 /* Free object limit */
#define CACHEGOAL 128 /* Free object goal */
@@ -80,6 +82,8 @@ static int cachedeleteing = FALSE; /* Cache deletion in progress... */
struct CACHE lrulist = {&lrulist,&lrulist,NULL,NULL,NULL,NULL,0,0,1,0};
+static void cache_deleter( struct CACHE *cacheobj, struct CACHE **actualobj );
+
/*************************************************************** cache_show() */
/* cache_show() - to print cache statistics */
@@ -118,26 +122,40 @@ int cache_refcount(struct CACHE *cacheobj)
/* cache_delete() - blow away item from cache - allow item to select a proxy (!)
and adjust 'the tree' containing the item. */
-struct CACHE *cache_delete(struct CACHE *cacheobj)
+void cache_delete( struct CACHE *cacheobj )
{
+ cache_deleter( cacheobj, NULL );
+}
+
+/* Internal routine that does the work. Optionally returns the address of the
+ * object actually deleted, which allows pointers to be adjusted correctly.
+ */
+static void cache_deleter( struct CACHE *cacheobj, struct CACHE **actualobj ) {
while (cacheobj->objmanager != NULL) {
register struct CACHE *proxyobj;
cachedeleteing = TRUE;
proxyobj = (*cacheobj->objmanager) (cacheobj,FALSE);
cachedeleteing = FALSE;
- if (proxyobj == NULL) return NULL;
+ if( proxyobj == NULL ) {
+ if( actualobj != NULL )
+ *actualobj = NULL;
+ return;
+ }
if (proxyobj == cacheobj) break;
cacheobj = proxyobj;
}
-#ifdef DEBUG
+#if DEBUG
if (cachedeleteing) printf("CACHE deletion while delete in progress\n");
#endif
if (cacheobj->refcount != 0) {
-#ifdef DEBUG
+#if DEBUG
printf("CACHE attempt to delete referenced object %d:%d\n",
cacheobj->objtype,cacheobj->hashval);
#endif
- return NULL;
+ abort();
+ if( actualobj != NULL )
+ *actualobj = NULL;
+ return;
}
cacheobj->lastlru->nextlru = cacheobj->nextlru;
cacheobj->nextlru->lastlru = cacheobj->lastlru;
@@ -173,7 +191,7 @@ struct CACHE *cache_delete(struct CACHE *cacheobj)
cachecount--;
cachefreecount--;
cachedeletes++;
-#ifdef DEBUG
+#if DEBUG
cacheobj->nextlru = NULL;
cacheobj->lastlru = NULL;
cacheobj->left = NULL;
@@ -184,22 +202,25 @@ struct CACHE *cache_delete(struct CACHE *cacheobj)
cacheobj->balance = 0;
cacheobj->refcount = 0;
#endif
- free(cacheobj);
- return cacheobj;
+ if( actualobj != NULL ) /* The returned value is used as a flag. It will not be dereferenced. */
+ *actualobj = cacheobj;
+
+ free(cacheobj); /* This may be the supplied object, or it may have been replaced by a proxy. */
+ return;
}
/************************************************************** cache_purge() */
/* cache_purge() - trim size of free list */
-void cache_purge(void)
+void cache_purge(int all)
{
if (!cachedeleteing) {
register struct CACHE *cacheobj = lrulist.lastlru;
cachepurges++;
- while (cachefreecount > CACHEGOAL && cacheobj != &lrulist) {
+ while ( (all || cachefreecount > CACHEGOAL) && cacheobj != &lrulist) {
register struct CACHE *lastobj = cacheobj->lastlru;
-#ifdef DEBUG
+#if DEBUG
if (cacheobj->lastlru->nextlru != cacheobj ||
cacheobj->nextlru->lastlru != cacheobj ||
*(cacheobj->parent) != cacheobj) {
@@ -207,7 +228,9 @@ void cache_purge(void)
}
#endif
if (cacheobj->refcount == 0) {
- if (cache_delete(cacheobj) != lastobj) cacheobj = lastobj;
+ struct CACHE *actualobj;
+ cache_deleter( cacheobj, &actualobj );
+ if (actualobj != lastobj) cacheobj = lastobj;
} else {
cacheobj = lastobj;
}
@@ -242,7 +265,7 @@ void cache_remove(struct CACHE *cacheobj)
if (cacheobj->refcount == 0) {
struct CACHE *delobj;
do {
- delobj = cache_delete(cacheobj);
+ cache_deleter(cacheobj, &delobj);
} while (delobj != NULL && delobj != cacheobj);
}
}
@@ -255,9 +278,10 @@ void cache_remove(struct CACHE *cacheobj)
void cache_touch(struct CACHE *cacheobj)
{
if (cacheobj->refcount++ == 0) {
-#ifdef DEBUG
+#if DEBUG
if (cacheobj->nextlru == NULL || cacheobj->lastlru == NULL) {
printf("CACHE LRU pointers corrupt!\n");
+ abort();
}
#endif
cacheobj->nextlru->lastlru = cacheobj->lastlru;
@@ -276,8 +300,8 @@ void cache_untouch(struct CACHE *cacheobj,int recycle)
{
if (cacheobj->refcount > 0) {
if (--cacheobj->refcount == 0) {
- if (++cachefreecount >= CACHELIM) cache_purge();
-#ifdef DEBUG
+ if (++cachefreecount >= CACHELIM) cache_purge(FALSE);
+#if DEBUG
if (cacheobj->nextlru != NULL || cacheobj->lastlru != NULL) {
printf("CACHE LRU pointers corrupt\n");
}
@@ -294,10 +318,11 @@ void cache_untouch(struct CACHE *cacheobj,int recycle)
lrulist.lastlru = cacheobj;
}
}
-#ifdef DEBUG
} else {
+#if DEBUG
printf("CACHE untouch limit exceeded\n");
#endif
+ abort();
}
}
@@ -325,7 +350,7 @@ void *cache_find( void **root, unsigned hashval, void *keyval, unsigned *retsts,
cachefinds++;
while ((cacheobj = *parent) != NULL) {
register int cmp = hashval - cacheobj->hashval;
-#ifdef DEBUG
+#if DEBUG
if (cacheobj->parent != parent) {
printf("CACHE Parent pointer is corrupt\n");
}
diff --git a/extracters/ods2/cache.h b/extracters/ods2/cache.h
index a463917..59f0671 100644
--- a/extracters/ods2/cache.h
+++ b/extracters/ods2/cache.h
@@ -1,4 +1,4 @@
-/* Cache.h V2.1 Definitions for cache routines */
+/* Cache.h Definitions for cache routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -38,8 +38,8 @@ struct CACHE {
void cache_show(void);
int cache_refcount(struct CACHE *cacheobj);
-struct CACHE *cache_delete(struct CACHE *cacheobj);
-void cache_purge(void);
+void cache_delete(struct CACHE *cacheobj);
+void cache_purge(int all);
void cache_flush(void);
void cache_remove(struct CACHE *cacheobj);
void cache_touch(struct CACHE * cacheobj);
diff --git a/extracters/ods2/cmddef.h b/extracters/ods2/cmddef.h
new file mode 100644
index 0000000..f5887ae
--- /dev/null
+++ b/extracters/ods2/cmddef.h
@@ -0,0 +1,108 @@
+/* Definitions for command handlers */
+
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+
+#ifndef _CMDDEF_H
+#define _CMDDEF_H
+
+#define _BSD_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _WIN32
+#include
+#else
+#include
+#include
+#endif
+
+#include "compat.h"
+#include "ods2.h"
+#include "rms.h"
+#include "ssdef.h"
+#include "stsdef.h"
+#include "sysmsg.h"
+
+#define MAXREC 32767
+#define PRINT_ATTR ( FAB$M_CR | FAB$M_PRN | FAB$M_FTN )
+
+#define DT_NAME "drive_type"
+
+#define DECL_CMD(x) unsigned do ## x(int argc,char **argv,int qualc,char **qualv)
+
+typedef struct CMDSET CMDSET_t;
+typedef struct param param_t;
+typedef struct qual qual_t;
+
+typedef CMDSET_t *CMDSETp_t;
+typedef param_t *paramp_t;
+typedef qual_t *qualp_t;
+
+/* Command table entry */
+
+struct CMDSET {
+ char *name;
+ unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]);
+ int uniq;
+ qualp_t validquals;
+ paramp_t params;
+ char *helpstr;
+};
+
+/* set, clear: bits specified are cleared, then set in value
+ * helpstr: if null, switch not listed in help. If starts with -,
+ * listed as negatable in help
+ */
+#define NV NOVAL, NULL
+#define KV(list) KEYVAL, list
+#define CV(list) KEYCOL, list
+#define DV(val) DECVAL, val
+#define SV(val) STRVAL, ((void *)val)
+struct qual {
+ const char *name;
+ int set;
+ int clear;
+ enum qualtype { NOVAL, KEYVAL, KEYCOL, DECVAL, STRVAL } qtype;
+ void *arg;
+ const char *helpstr;
+};
+
+typedef const char *(hlpfunc_t)( CMDSET_t *cmd, param_t *p, int argc, char **argv );
+
+struct param {
+ const char *name;
+ enum parflags { REQ, OPT, CND } flags;
+ enum partype { VMSFS, LCLFS, LIST, KEYWD, STRING, CMDNAM, NONE } ptype;
+#define PA(arg) NULL, (arg)
+#define NOPA PA(NULL)
+ hlpfunc_t *hlpfnc;
+ void *arg;
+ const char *helpstr;
+};
+
+extern int vms_qual;
+extern int verify_cmd;
+
+int parselist( char ***items, size_t min, char *arg, const char *label );
+int checkquals( int result, qual_t qualset[],int qualc,char *qualv[] );
+int keycomp(const char *param, const char *keywrd);
+char *fgetline( FILE *stream, int keepnl );
+
+int prvmstime(VMSTIME vtime, const char *sfx);
+void pwrap( int *pos, const char *fmt, ... );
+
+#endif
diff --git a/extracters/ods2/compat.c b/extracters/ods2/compat.c
index e4bd3ed..2fefec5 100644
--- a/extracters/ods2/compat.c
+++ b/extracters/ods2/compat.c
@@ -1,24 +1,60 @@
-/* Timothe Litt February 2016 */
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
/* This module contains compatibility code, currently just
* to support Microsoft Windows.
*
* Microsoft deprecates sprintf, but doesn't supply standard
* replacement until very recent IDEs.
- * Microsoft doesn't like fopen, or strerror, or getcwd.
+ * Microsoft doesn't like fopen, or strerror, or getcwd, or getenv.
* One needs to use a M$ call to translate system errors.
*
* Finding out about drive letter assignments is unique to windows.
*/
+#if !defined( DEBUG ) && defined( DEBUG_COMPAT )
+#define DEBUG DEBUG_COMPAT
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
#include
#include
+#include
+#include
#include "compat.h"
+#include "descrip.h"
+#include "stsdef.h"
+#ifdef VMS
+#include
+#else
#ifdef _WIN32
#include
-#include
+#else
+#include
+#include
+#ifndef USER_FROM_ENV
+#include
+#endif
+#endif
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
@@ -74,7 +110,7 @@ const char *ods2_strerror( int errn ) {
static char buf[256];
if( strerror_s( buf, sizeof( buf ), errn ) != 0 )
- snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn );
+ (void) snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn );
return buf;
}
@@ -93,7 +129,11 @@ TCHAR *w32_errstr( DWORD eno, ... ) {
FORMAT_MESSAGE_FROM_SYSTEM, NULL, eno, 0,
(LPSTR)&msg, 1, &ap ) == 0 ) {
msg = (TCHAR *)malloc( 32 );
- snprintf( msg, 32, "(%u)", eno );
+ if( msg == NULL ) {
+ perror( "malloc" );
+ printf( "Original error number (%u)\n", eno );
+ } else
+ (void) snprintf( msg, 32, "(%u)", eno );
}
va_end(ap);
return msg;
@@ -128,5 +168,86 @@ char *driveFromLetter( const char *letter ) {
}
#endif
-/* For ISO C compliance, ensure that there's something in this module */
-void dummy_compat ( void ) { return; }
+/******************************************************************* get_env() */
+
+char *get_env( const char *name ) {
+ size_t i;
+ char *r;
+
+#ifdef _WIN32
+ (void) getenv_s( &i, NULL, 0, name );
+ if( i == 0 )
+ return NULL;
+ if ((r = malloc( i )) == NULL )
+ return NULL;
+ (void)getenv_s( &i, r, i, "USERNAME" );
+ return r;
+#else
+ char *t;
+
+ t = getenv( name );
+ if( t == NULL )
+ return NULL;
+ i = strlen( t );
+ r = malloc( i + 1 );
+ if( r == NULL )
+ return NULL;
+
+ memcpy( r, t, i+1 );
+
+ return r;
+#endif
+}
+
+/******************************************************************* get_username() */
+
+char *get_username( void ) {
+ char *username;
+ char *r;
+ size_t i;
+#ifdef VMS
+ char uame[12 + 1] = "UNKNOWN ";
+ struct dsc$descriptor_s userdsc = { sizeof( uname ) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, uname };
+
+ r = "UNKNOWN";
+ if( lib$getjpi( &JPI$_USERNAME, 0, 0, 0, &userdsc, 0 ) & STS$M_SUCCESS ) {
+ for( i = sizeof( uname ) - 1; i >= 0; i-- ) {
+ if( uname[i] == ' ' )
+ uname[i] = '\0';
+ else
+ break;
+ }
+ if( uname[0] )
+ r = uname;
+ }
+#else
+#ifdef _WIN32
+ (void) getenv_s( &i, NULL, 0, "USERNAME" );
+ if( i == 0 )
+ r = "UNKNOWN";
+ else {
+ if ((r = malloc( i )) == NULL )
+ return NULL;
+ (void)getenv_s( &i, r, i, "USERNAME" );
+ return r;
+ }
+#else
+#ifdef USER_FROM_ENV
+ if( (r = getenv( "USER" )) == NULL )
+ r = getenv( "LOGNAME" );
+ if( r == NULL )
+ r = "UNKNOWN";
+#else
+ struct passwd *pw;
+
+ pw = getpwuid(geteuid());
+ r = pw->pw_name;
+#endif
+#endif
+#endif
+ i = strlen( r );
+ if( (username = malloc( i + 1 )) == NULL )
+ return NULL;
+ memcpy( username, r, i + 1 );
+ return username;
+}
diff --git a/extracters/ods2/compat.h b/extracters/ods2/compat.h
index ae39b2b..9023bb3 100644
--- a/extracters/ods2/compat.h
+++ b/extracters/ods2/compat.h
@@ -1,3 +1,20 @@
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
#ifndef COMPAT_H
#define COMPAT_H
@@ -14,6 +31,7 @@ int c99_snprintf(char *outBuf, size_t size, const char *format, ...);
#endif
#ifdef _MSC_VER
+#include
FILE *openf( const char *filename, const char *mode );
#else
#define openf fopen
@@ -28,6 +46,14 @@ FILE *openf( const char *filename, const char *mode );
#define getcwd _getcwd
#undef chdir
#define chdir _chdir
+#undef tzset
+#define tzset _tzset
+#undef setenv
+#define setenv(name, value, overwrite) _putenv_s(name, value)
+#undef unsetenv
+#define unsetenv(name) _putenv_s(name,"")
+#undef unlink
+#define unlink _unlink
#undef strerror
#define strerror(n) ods2_strerror(n)
@@ -40,6 +66,9 @@ char *driveFromLetter( const char *letter );
#include
#endif
+char *get_username( void );
+char *get_env( const char *name );
+
#define UNUSED(x) (void)(x)
#endif
diff --git a/extracters/ods2/copycmd.c b/extracters/ods2/copycmd.c
new file mode 100644
index 0000000..974956a
--- /dev/null
+++ b/extracters/ods2/copycmd.c
@@ -0,0 +1,239 @@
+
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_COPYCMD )
+#define DEBUG DEBUG_COPYCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+
+/******************************************************************* docopy() */
+
+/* copy: a file copy routine */
+
+#define copy_binary OPT_GENERIC_1
+#define copy_log OPT_GENERIC_2
+
+qual_t copyquals[] = { {"ascii", 0, copy_binary, NV, "Copy file in ascii mode (default)"},
+ {"binary", copy_binary, 0, NV, "Copy file in binary mode", },
+ {"log", copy_log, 0, NV, "-Log files copied"},
+ {"nolog", 0, copy_log, NV, NULL},
+ {NULL, 0, 0, NV, NULL}
+};
+
+param_t copypars[] = { {"from_filespec", REQ, VMSFS, NOPA,
+ "for source file. Wildcards are allowed."},
+ {"to_filespec", REQ, LCLFS, NOPA,
+ "for destination file. Wildcards are replaced from source file name."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(copy) {
+ int sts,options;
+ struct NAM nam = cc$rms_nam;
+ struct FAB fab = cc$rms_fab;
+ char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
+ int filecount = 0;
+
+ UNUSED(argc);
+
+ nam.nam$l_esa = res;
+ nam.nam$b_ess = NAM$C_MAXRSS;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ options = checkquals(0,copyquals,qualc,qualv);
+ if( options == -1 )
+ return SS$_BADPARAM;
+ sts = sys_parse(&fab);
+ if ( sts & STS$M_SUCCESS ) {
+ nam.nam$l_rsa = rsa;
+ nam.nam$b_rss = NAM$C_MAXRSS;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ while( (sts = sys_search( &fab )) & STS$M_SUCCESS ) {
+ int directory = 0;
+ struct RAB rab = cc$rms_rab;
+ struct XABDAT dat = cc$rms_xabdat;
+ struct XABITM itm = cc$rms_xabitm;
+ struct item_list xitems[] = {
+ { XAB$_UCHAR_DIRECTORY, sizeof(int), NULL, 0 },
+ { 0, 0, NULL, 0 }
+ };
+
+ itm.xab$l_nxt = &dat;
+ xitems[0].buffer = &directory;
+ itm.xab$b_mode = XAB$K_SENSEMODE;
+ itm.xab$l_itemlist = xitems;
+ fab.fab$l_xab = &itm;
+
+ sts = sys_open(&fab);
+ fab.fab$l_xab = NULL;
+
+ if ( !(sts & STS$M_SUCCESS) ) {
+ printf("%%COPY-F-OPENFAIL, Open error: %s\n",getmsg(sts, MSG_TEXT));
+ perror("-COPY-F-ERR ");
+ continue;
+ }
+ if( directory ) {
+ rsa[nam.nam$b_rsl] = '\0';
+ printf( "%%COPY-I-NOTDIR, %s is directory, not copied\n", rsa );
+ sys_close( &fab );
+ continue;
+ }
+
+ rab.rab$l_fab = &fab;
+ if( (sts = sys_connect(&rab)) & STS_M_SUCCESS ) {
+ FILE *tof;
+ char name[NAM$C_MAXRSS + 1];
+ unsigned records = 0;
+ char *out = name,*inp = argv[2]; /* unquote(argv[2]) */
+ int dot = FALSE;
+ while (*inp != '\0') {
+ if (*inp == '*') {
+ inp++;
+ if (dot) {
+ memcpy(out,nam.nam$l_type + 1,
+ nam.nam$b_type - 1);
+ out += nam.nam$b_type - 1;
+ } else {
+ unsigned length = nam.nam$b_name;
+ if (*inp == '\0') length += nam.nam$b_type;
+ memcpy(out,nam.nam$l_name,length);
+ out += length;
+ }
+ } else {
+ if (*inp == '.') {
+ dot = TRUE;
+ } else {
+ if (strchr(":]\\/",*inp)) dot = FALSE;
+ }
+ *out++ = *inp++;
+ }
+ }
+ *out++ = '\0';
+#ifndef _WIN32
+ tof = openf( name,"w" );
+#else
+ if( !(options & copy_binary) && (fab.fab$b_rat & PRINT_ATTR) ) {
+ tof = openf(name,"w");
+ } else {
+ tof = openf( name, "wb" );
+ }
+#endif
+ if (tof == NULL) {
+ printf("%%COPY-F-OPENOUT, Could not open %s\n",name);
+ perror("-COPY-F-ERR ");
+ } else {
+ char *rec;
+
+ if( (rec = malloc( MAXREC + 2 )) == NULL )
+ sts = SS$_INSFMEM;
+ else {
+ filecount++;
+ rab.rab$l_ubf = rec;
+ rab.rab$w_usz = MAXREC;
+ while( (sts = sys_get( &rab )) & STS$M_SUCCESS ) {
+ unsigned rsz = rab.rab$w_rsz;
+ if( !(options & copy_binary) &&
+ (fab.fab$b_rat & PRINT_ATTR) ) rec[rsz++] = '\n';
+ if( fwrite( rec, rsz, 1, tof ) == 1 ) {
+ records++;
+ } else {
+ printf( "%%COPY-F- fwrite error!!\n" );
+ perror( "-COPY-F-ERR " );
+ break;
+ }
+ }
+ free( rec );
+ rec = NULL;
+ }
+ if( fclose( tof ) ) {
+ printf( "%%COPY-F- fclose error!!\n" );
+ perror( "-COPY-F-ERR " );
+ } else {
+ time_t posixtime;
+ unsigned short timvec[7];
+ char *tz;
+ struct tm tm;
+#ifdef _WIN32
+ struct _utimbuf tv;
+#else
+ struct timeval tv[2];
+#endif
+ if( sys$numtim( timvec, dat.xab$q_rdt ) & STS$M_SUCCESS ) {
+ tm.tm_sec = timvec[5];
+ tm.tm_min = timvec[4];
+ tm.tm_hour = timvec[3];
+ tm.tm_mday = timvec[2];
+ tm.tm_mon = timvec[1] -1;
+ tm.tm_year = timvec[0] - 1900;
+
+ tz = get_env( "TZ" );
+ setenv( "TZ", "", 1 );
+ tzset();
+ posixtime = mktime( &tm );
+ if( posixtime != (time_t)-1 ) {
+#ifdef _WIN32
+ tv.actime =
+ tv.modtime = posixtime;
+ (void)_utime( name, &tv );
+#else
+ tv[0].tv_sec = posixtime;
+ tv[0].tv_usec = timvec[6] * 10000;
+ tv[1] = tv[0]; /* Set mtime to atime */
+ (void) utimes( name, tv );
+#endif
+ }
+ if( tz != NULL )
+ setenv( "TZ", tz, 1 );
+ else
+ unsetenv( "TZ" );
+ tzset();
+ free( tz );
+ }
+ }
+ }
+
+ sys_disconnect( &rab );
+ rsa[nam.nam$b_rsl] = '\0';
+ if (sts == RMS$_EOF) {
+ if( options & copy_log )
+ printf(
+ "%%COPY-S-COPIED, %s copied to %s (%d record%s)\n",
+ rsa, name, records, (records == 1 ? "" : "s")
+ );
+ } else {
+ printf("%%COPY-F-ERROR Status: %s for %s\n",getmsg(sts, MSG_TEXT),rsa);
+ sts = SS$_NORMAL;
+ }
+ }
+ sys_close(&fab);
+ }
+ if (sts == RMS$_NMF) sts = SS$_NORMAL;
+ }
+ if ( sts & STS$M_SUCCESS ) {
+ if (filecount > 0) {
+ if( options & copy_log )
+ printf("%%COPY-S-NEWFILES, %d file%s copied\n",
+ filecount,(filecount == 1 ? "" : "s"));
+ } else {
+ printf( "%%COPY-I-NOFILES, no files found\n" );
+ }
+ } else {
+ printf("%%COPY-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
diff --git a/extracters/ods2/createcmd.c b/extracters/ods2/createcmd.c
new file mode 100644
index 0000000..9052183
--- /dev/null
+++ b/extracters/ods2/createcmd.c
@@ -0,0 +1,52 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_CREATECMD )
+#define DEBUG DEBUG_CREATECMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#include "f11def.h"
+
+/******************************************************************* dotest() */
+
+param_t createpars[] = { {"parameter", REQ, STRING, NOPA, "for create."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+#if 0
+extern struct VCB *test_vcb;
+#endif
+
+/* docreate: you don't want to know! */
+
+DECL_CMD(create) {
+ unsigned sts = 0;
+ struct fiddef fid;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+#if 0 /* Needs to call RMS, etc */
+ sts = update_create( test_vcb, NULL, "Test.File", &fid, NULL );
+#else
+ memset( &fid, 0, sizeof( struct fiddef ) );
+#endif
+ printf( "Create status of %d (%s)\n", sts, argv[1] );
+ return sts;
+}
+
+
+
diff --git a/extracters/ods2/debug.c b/extracters/ods2/debug.c
new file mode 100644
index 0000000..5aa2f1f
--- /dev/null
+++ b/extracters/ods2/debug.c
@@ -0,0 +1,122 @@
+/* Debug routines */
+
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+
+#include
+#include
+
+#include "debug.h"
+
+/*********************************************************** dumpblock() */
+void dumpblock( unsigned block, unsigned length, const char *buffer,
+ const char *more, ... ) {
+ va_list ap;
+
+ va_start( ap, more );
+ vdumpblockto( stdout, block, length, buffer, more, ap );
+ va_end( ap );
+}
+
+/*********************************************************** vdumpblock() */
+
+void vdumpblock( unsigned block, unsigned length, const char *buffer,
+ const char *more, va_list ap ) {
+
+ vdumpblockto( stdout, block, length, buffer, more, ap );
+}
+
+/*********************************************************** dumpblockto() */
+
+void dumpblockto( FILE *fp, unsigned block, unsigned length, const char *buffer,
+ const char *more, ... ) {
+ va_list ap;
+
+ va_start( ap, more );
+ vdumpblockto( fp, block, length, buffer, more, ap );
+ va_end( ap );
+}
+
+/*********************************************************** vdumpblockto() */
+
+void vdumpblockto( FILE *fp, unsigned block, unsigned length, const char *buffer,
+ const char *more, va_list ap ) {
+#ifndef DEBUG_DISKIO
+ (void) fp;
+ (void) block;
+ (void) length;
+ (void) buffer;
+ (void) more;
+ (void) ap;
+#else
+ const char *p;
+
+ size_t n, wid = 32, off = 0;
+
+ fprintf( fp, "\n****************************************\n"
+ "Block %u Length %u", block, length );
+ if( more != NULL ) {
+ fputc( ' ', fp );
+ vfprintf( fp, more, ap );
+ }
+ fputc( '\n', fp );
+ if( length == 0 )
+ return;
+
+ fprintf( fp, " " );
+ for( n = 0; n < wid; n++ ) {
+ if( n % 2 == 0 )
+ fprintf( fp, " %02x", (int)n );
+ else
+ fprintf( fp, " " );
+ }
+ fprintf( fp, " " );
+ for( n = 0; n < wid; n++ ) {
+ if( n % 4 == 0 )
+ fprintf( fp, " %02x ", (int)n );
+ }
+ fputc( '\n', fp );
+
+ while( length ) {
+ fprintf( fp, "%04x:", (unsigned) off );
+ p = buffer;
+ for( n = 0; n < wid; n++ ) {
+ if( n % 2 == 0 )
+ fputc( ' ', fp );
+ if( n < length ) {
+ fprintf( fp, "%02x", 0xff & (unsigned)*p++ );
+ } else
+ fprintf( fp, " " );
+ }
+
+ fprintf( fp, " " );
+ p = buffer;
+ for( n = 0; n < wid; n++, p++ ) {
+ if( n % 4 == 0 )
+ fputc( ' ', fp );
+ fprintf( fp, "%c", (n >= length)? ' ': (*p < 040 || *p > 0176)? '.': *p );
+ }
+ length -= wid;
+ buffer += wid;
+ off += wid;
+ fputc( '\n', fp );
+ }
+#endif
+
+ return;
+}
diff --git a/extracters/ods2/debug.h b/extracters/ods2/debug.h
new file mode 100644
index 0000000..e14179c
--- /dev/null
+++ b/extracters/ods2/debug.h
@@ -0,0 +1,15 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include
+#include
+
+void dumpblock( unsigned block, unsigned length, const char *buffer,
+ const char *more, ... );
+void vdumpblock( unsigned block, unsigned length, const char *buffer,
+ const char *more, va_list ap );
+void dumpblockto( FILE *fp, unsigned block, unsigned length, const char *buffer,
+ const char *more, ... );
+void vdumpblockto( FILE *fp, unsigned block, unsigned length, const char *buffer,
+ const char *more, va_list ap );
+#endif
diff --git a/extracters/ods2/deletecmd.c b/extracters/ods2/deletecmd.c
new file mode 100644
index 0000000..9a2c61d
--- /dev/null
+++ b/extracters/ods2/deletecmd.c
@@ -0,0 +1,85 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_DELETECMD )
+#define DEBUG DEBUG_DELETECMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+/***************************************************************** dodelete() */
+
+#define delete_log OPT_GENERIC_1
+
+qual_t delquals[] = { {"log", delete_log, 0, NV, "-List name of each file deleted. (Default)"},
+ {"nolog", 0, delete_log, NV, NULL },
+ { NULL, 0, 0, NV, NULL }
+};
+param_t delpars[] = { {"filespec", REQ, VMSFS, NOPA,
+ "for files to be deleted from ODS-2 volume. Wildcards are permitted.."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(delete) {
+ int sts = 0;
+ char res[NAM$C_MAXRSS + 1], rsa[NAM$C_MAXRSS + 1];
+ struct NAM nam = cc$rms_nam;
+ struct FAB fab = cc$rms_fab;
+ int options, filecount = 0;
+
+ UNUSED(argc);
+
+ options = checkquals( delete_log, delquals, qualc, qualv );
+ if( options == -1 )
+ return SS$_BADPARAM;
+
+ nam.nam$l_esa = res;
+ nam.nam$b_ess = NAM$C_MAXRSS;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ sts = sys_parse(&fab);
+ if ( sts & STS$M_SUCCESS ) {
+ if (nam.nam$b_ver < 2) {
+ printf( "%s\n", getmsg( DELETE$_DELVER, MSG_FULL) );
+ return SS$_BADPARAM;
+ }
+
+ nam.nam$l_rsa = rsa;
+ nam.nam$b_rss = NAM$C_MAXRSS;
+ fab.fab$l_fop = FAB$M_NAM;
+ while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
+ sts = sys_erase(&fab);
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ printf("%%DELETE-F-DELERR, Delete error: %s\n",getmsg(sts, MSG_TEXT));
+ break;
+ } else {
+ filecount++;
+ if( options & delete_log ) {
+ rsa[nam.nam$b_rsl] = '\0';
+ printf("%%DELETE-I-DELETED, Deleted %s\n",rsa);
+ }
+ }
+ }
+ if( sts == RMS$_NMF ) sts = SS$_NORMAL;
+ }
+ if( sts & STS$M_SUCCESS ) {
+ if( filecount < 1 ) {
+ printf( "%%DELETE-W-NOFILES, no files deleted\n" );
+ }
+ } else {
+ printf( "%%DELETE-F-ERROR Status: %s\n", getmsg(sts, MSG_TEXT) );
+ }
+
+ return sts;
+}
diff --git a/extracters/ods2/descrip.h b/extracters/ods2/descrip.h
index fca0e1a..9fa6518 100644
--- a/extracters/ods2/descrip.h
+++ b/extracters/ods2/descrip.h
@@ -1,4 +1,4 @@
-/* Descrip.h V2.1 Definitions for descriptors */
+/* Descrip.h Definitions for descriptors */
/*
This is part of ODS2 written by Paul Nankervis,
diff --git a/extracters/ods2/descrip.mms b/extracters/ods2/descrip.mms
index 930c505..0a48161 100644
--- a/extracters/ods2/descrip.mms
+++ b/extracters/ods2/descrip.mms
@@ -1,62 +1,162 @@
-#
-# MMS (MMK) description file to build ODS2 for VMS
-#
-# To compile on VAX using VAX C, use:
-#
-# $ mmk/macro=vaxc=1
-#
-#
-.IFDEF EXE
-.ELSE
-EXE = .EXE
-OBJ = .OBJ
-OLB = .OLB
-.ENDIF
-
-.IFDEF __DEBUG__
-CFLAGS = $(CFLAGS)/DEBUG/NOOPTIMIZE
-LINKFLAGS = $(LINKFLAGS)/DEBUG
-.ELSE
-LINKFLAGS = $(LINKFLAGS)/NOTRACE
-.ENDIF
-CFLAGS = $(CFLAGS)/DEFINE=(NO_DOLLAR)
-
-.IFDEF __VAXC__
-OPTFILE = ,VAXCRTL.OPT
-OPTIONS = $(OPTFILE)/OPTIONS
-.ELSE
-OPTFILE =
-OPTIONS =
-.ENDIF
-
-OBJS = ODS2,RMS,DIRECT,ACCESS,DEVICE,CACHE,PHYVMS,SYSMSG,UPDATE,PHYVIRT
-
-ODS2$(EXE) : ODS2$(OLB)($(OBJS))$(OPTFILE)
- $(LINK)$(LINKFLAGS) ODS2$(OLB)/INCLUDE=($(OBJS))$(OPTIONS)
-
-phyvirt$(obj) : phyvirt.c phyvirt.h compat.h ssdef.h
-
-sysmsg$(obj) : sysmsg.c sysmsg.h rms.h ssdef.h
-
-compat$(obj) : compat.c compat.h
-
-cache$(obj) : cache.c cache.h ssdef.h
-
-phyvms$(obj) : phyvms.c phyio.h phyvirt.h ssdef.h descrip.h access.h rms.h
-
-device$(obj) : device.c ssdef.h access.h phyio.h
-
-access$(obj) : access.c ssdef.h access.h phyio.h compat.h sysmsg.h phyvirt.h
-
-update$(obj) : update.c ssdef.h access.h
-
-direct$(obj) : direct.c direct.h access.h fibdef.h descrip.h ssdef.h
-
-rms$(obj) : rms.c rms.h compat.h direct.h access.h fibdef.h descrip.h ssdef.h
-
-ods2$(obj) : ods2.c compat.h sysmsg.h phyio.h ssdef.h descrip.h access.h rms.h version.h
-
-VAXCRTL.OPT :
- @ open/write tmp $(MMS$TARGET)
- @ write tmp "SYS$SHARE:VAXCRTL.EXE/SHARE"
- @ close tmp
+#
+# MMS (MMK) description file to build ODS2 for VMS
+#
+# To compile on VAX using VAX C, use:
+#
+# $ mmk/macro=vaxc=1
+#
+#
+.IFDEF EXE
+.ELSE
+EXE = .EXE
+OBJ = .OBJ
+OLB = .OLB
+.ENDIF
+
+.IFDEF __DEBUG__
+CFLAGS = $(CFLAGS)/DEBUG/NOOPTIMIZE
+LINKFLAGS = $(LINKFLAGS)/DEBUG
+.ELSE
+LINKFLAGS = $(LINKFLAGS)/NOTRACE
+.ENDIF
+CFLAGS = $(CFLAGS)/DEFINE=(NO_DOLLAR)
+
+.IFDEF __VAXC__
+OPTFILE = ,VAXCRTL.OPT
+OPTIONS = $(OPTFILE)/OPTIONS
+.ELSE
+OPTFILE =
+OPTIONS =
+.ENDIF
+
+# The next line is automatically generated. Do not change the format or split into multiple lines
+OBJS = ODS2 ACCESS CACHE COMPAT COPYCMD CREATECMD DEBUG DELETECMD DEVICE DIFFCMD DIRCMD DIRECT DISMOUNTCMD EXTENDCMD HELPCMD IMPORTCMD INITIALCMD INITVOL MOUNTCMD PHYVMS PHYVIRT RMS SEARCHCMD SETCMD SHOWCMD SPAWNCMD SYSMSG TYPECMD UPDATE VMSTIME
+
+ODS2$(EXE) : ODS2$(OLB)($(OBJS))$(OPTFILE)
+ $(LINK)$(LINKFLAGS) ODS2$(OLB)/INCLUDE=($(OBJS))$(OPTIONS)
+
+VAXCRTL.OPT :
+ @ open/write tmp $(MMS$TARGET)
+ @ write tmp "SYS$SHARE:VAXCRTL.EXE/SHARE"
+ @ close tmp
+
+# Everything from the next line through EOF is automatically generated by make -f makefile.unix depend
+# (or make -f makefile.vms depend) on Unix.
+
+# ### BEGIN RULES ###
+
+ODS2$(OBJ): VERSION.H
+ODS2$(OBJ): CMDDEF.H
+ODS2$(OBJ): COMPAT.H
+ODS2$(OBJ): ODS2.H RMS.H
+ODS2$(OBJ): VMSTIME.H DESCRIP.H SSDEF.H STSDEF.H SYSMSG.H CACHE.H PHYVIRT.H
+ACCESS$(OBJ): SSDEF.H ACCESS.H CACHE.H F11DEF.H
+ACCESS$(OBJ): VMSTIME.H
+ACCESS$(OBJ): DESCRIP.H STSDEF.H DEVICE.H PHYIO.H INITVOL.H ODS2.H PHYVIRT.H
+ACCESS$(OBJ): COMPAT.H
+ACCESS$(OBJ): SYSMSG.H
+CACHE$(OBJ): CACHE.H ODS2.H SSDEF.H
+COMPAT$(OBJ): COMPAT.H
+COMPAT$(OBJ): DESCRIP.H STSDEF.H
+COPYCMD$(OBJ): CMDDEF.H
+COPYCMD$(OBJ): COMPAT.H
+COPYCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+COPYCMD$(OBJ): STSDEF.H SYSMSG.H
+CREATECMD$(OBJ): CMDDEF.H
+CREATECMD$(OBJ): COMPAT.H
+CREATECMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+CREATECMD$(OBJ): STSDEF.H SYSMSG.H F11DEF.H
+DEBUG$(OBJ): DEBUG.H
+DELETECMD$(OBJ): CMDDEF.H
+DELETECMD$(OBJ): COMPAT.H
+DELETECMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+DELETECMD$(OBJ): STSDEF.H SYSMSG.H
+DEVICE$(OBJ): ODS2.H ACCESS.H CACHE.H F11DEF.H
+DEVICE$(OBJ): VMSTIME.H
+DEVICE$(OBJ): DESCRIP.H SSDEF.H STSDEF.H DEVICE.H PHYIO.H
+DIFFCMD$(OBJ): CMDDEF.H
+DIFFCMD$(OBJ): COMPAT.H
+DIFFCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+DIFFCMD$(OBJ): STSDEF.H SYSMSG.H
+DIRCMD$(OBJ): CMDDEF.H
+DIRCMD$(OBJ): COMPAT.H
+DIRCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+DIRCMD$(OBJ): STSDEF.H SYSMSG.H
+DIRECT$(OBJ): ACCESS.H CACHE.H F11DEF.H
+DIRECT$(OBJ): VMSTIME.H
+DIRECT$(OBJ): DESCRIP.H SSDEF.H STSDEF.H DIRECT.H FIBDEF.H ODS2.H
+DISMOUNTCMD$(OBJ): CMDDEF.H
+DISMOUNTCMD$(OBJ): COMPAT.H
+DISMOUNTCMD$(OBJ): ODS2.H
+DISMOUNTCMD$(OBJ): RMS.H VMSTIME.H DESCRIP.H SSDEF.H STSDEF.H SYSMSG.H ACCESS.H
+DISMOUNTCMD$(OBJ): CACHE.H F11DEF.H
+DISMOUNTCMD$(OBJ): DEVICE.H PHYIO.H
+EXTENDCMD$(OBJ): CMDDEF.H
+EXTENDCMD$(OBJ): COMPAT.H
+EXTENDCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+EXTENDCMD$(OBJ): STSDEF.H SYSMSG.H
+HELPCMD$(OBJ): CMDDEF.H
+HELPCMD$(OBJ): COMPAT.H
+HELPCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+HELPCMD$(OBJ): STSDEF.H SYSMSG.H
+IMPORTCMD$(OBJ): CMDDEF.H
+IMPORTCMD$(OBJ): COMPAT.H
+IMPORTCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+IMPORTCMD$(OBJ): STSDEF.H SYSMSG.H
+INITIALCMD$(OBJ): CMDDEF.H
+INITIALCMD$(OBJ): COMPAT.H
+INITIALCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H
+INITIALCMD$(OBJ): SSDEF.H STSDEF.H SYSMSG.H ACCESS.H CACHE.H F11DEF.H
+INITIALCMD$(OBJ): DEVICE.H
+INITIALCMD$(OBJ): PHYIO.H INITVOL.H PHYVIRT.H
+INITVOL$(OBJ): COMPAT.H
+INITVOL$(OBJ): F11DEF.H
+INITVOL$(OBJ): VMSTIME.H
+INITVOL$(OBJ): DESCRIP.H SSDEF.H STSDEF.H INITVOL.H ODS2.H PHYVIRT.H RMS.H
+MOUNTCMD$(OBJ): CMDDEF.H
+MOUNTCMD$(OBJ): COMPAT.H
+MOUNTCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+MOUNTCMD$(OBJ): STSDEF.H SYSMSG.H ACCESS.H CACHE.H F11DEF.H
+MOUNTCMD$(OBJ): DEVICE.H
+MOUNTCMD$(OBJ): PHYIO.H PHYVIRT.H
+PHYVMS$(OBJ): DESCRIP.H RMS.H VMSTIME.H SSDEF.H STSDEF.H
+PHYVMS$(OBJ): ODS2.H PHYIO.H PHYVIRT.H
+PHYVIRT$(OBJ): COMPAT.H
+PHYVIRT$(OBJ): DEVICE.H
+PHYVIRT$(OBJ): ACCESS.H CACHE.H F11DEF.H
+PHYVIRT$(OBJ): VMSTIME.H DESCRIP.H SSDEF.H STSDEF.H
+PHYVIRT$(OBJ): PHYIO.H ODS2.H PHYVIRT.H
+RMS$(OBJ): ACCESS.H CACHE.H
+RMS$(OBJ): F11DEF.H VMSTIME.H
+RMS$(OBJ): DESCRIP.H SSDEF.H STSDEF.H DEVICE.H PHYIO.H DIRECT.H FIBDEF.H ODS2.H
+RMS$(OBJ): RMS.H COMPAT.H
+RMS$(OBJ): SYSMSG.H
+SEARCHCMD$(OBJ): CMDDEF.H
+SEARCHCMD$(OBJ): COMPAT.H
+SEARCHCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+SEARCHCMD$(OBJ): STSDEF.H SYSMSG.H
+SETCMD$(OBJ): CMDDEF.H
+SETCMD$(OBJ): COMPAT.H
+SETCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+SETCMD$(OBJ): STSDEF.H SYSMSG.H
+SHOWCMD$(OBJ): CMDDEF.H
+SHOWCMD$(OBJ): COMPAT.H
+SHOWCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+SHOWCMD$(OBJ): STSDEF.H SYSMSG.H ACCESS.H CACHE.H F11DEF.H
+SHOWCMD$(OBJ): DIRECT.H PHYIO.H
+SHOWCMD$(OBJ): PHYVIRT.H VERSION.H
+SPAWNCMD$(OBJ): CMDDEF.H
+SPAWNCMD$(OBJ): COMPAT.H
+SPAWNCMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+SPAWNCMD$(OBJ): STSDEF.H SYSMSG.H
+SYSMSG$(OBJ): SSDEF.H RMS.H
+SYSMSG$(OBJ): VMSTIME.H DESCRIP.H STSDEF.H COMPAT.H
+SYSMSG$(OBJ): SYSMSG.H
+TYPECMD$(OBJ): CMDDEF.H
+TYPECMD$(OBJ): COMPAT.H
+TYPECMD$(OBJ): ODS2.H RMS.H VMSTIME.H DESCRIP.H SSDEF.H
+TYPECMD$(OBJ): STSDEF.H SYSMSG.H
+UPDATE$(OBJ): ACCESS.H CACHE.H
+UPDATE$(OBJ): F11DEF.H
+UPDATE$(OBJ): VMSTIME.H DESCRIP.H SSDEF.H STSDEF.H DEVICE.H PHYIO.H ODS2.H
+VMSTIME$(OBJ): VMSTIME.H DESCRIP.H SSDEF.H STSDEF.H
diff --git a/extracters/ods2/device.c b/extracters/ods2/device.c
index d38cdbb..0631283 100644
--- a/extracters/ods2/device.c
+++ b/extracters/ods2/device.c
@@ -1,4 +1,4 @@
-/* Device.c V2.1 Module to remember and find devices...*/
+/* Device.c Module to remember and find devices...*/
/*
This is part of ODS2 written by Paul Nankervis,
@@ -20,11 +20,20 @@
#include
#include
+#include "ods2.h"
#include "access.h"
#include "cache.h"
#include "device.h"
#include "ssdef.h"
+#if !defined( DEBUG ) && defined( DEBUG_DEVICE )
+#define DEBUG DEBUG_DEVICE
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
static void *device_create( unsigned devsiz, void *keyval, unsigned *retsts );
static int device_compare( unsigned keylen, void *keyval, void *node );
@@ -48,12 +57,32 @@ static void *device_create( unsigned devsiz, void *keyval, unsigned *retsts ) {
dev->cache.objtype = OBJTYPE_DEV;
dev->vcb = NULL;
dev->access = 0;
+ dev->context = NULL;
memcpy( dev->devnam, keyval, devsiz );
memcpy( dev->devnam + devsiz, ":", 2 );
*retsts = SS$_NORMAL;
return dev;
}
+/************************************************************ device_done() */
+
+/* device_done() releases a device reference and
+ * eventually the device structure.
+ */
+
+void device_done( struct DEV *dev ) {
+ if( dev->cache.refcount < 1 ) {
+#if DEBUG
+ printf( "Device done with no reference\n" );
+#endif
+ abort();
+ }
+ cache_untouch( &dev->cache, FALSE );
+ if( dev->cache.refcount == 0 ) /* Safe because on LRU list */
+ cache_delete( &dev->cache );
+ return;
+}
+
/*********************************************************** device_compare() */
/* device_compare() compares a device name to that of a device object... */
diff --git a/extracters/ods2/device.h b/extracters/ods2/device.h
index 50fb10c..66aedee 100644
--- a/extracters/ods2/device.h
+++ b/extracters/ods2/device.h
@@ -1,4 +1,4 @@
-/* Device.h V2.1 Definitions for device routines */
+/* Device.h Definitions for device routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -17,14 +17,18 @@
#include /* HANDLE */
#endif
+#include
+#include
#include "access.h"
#include "cache.h"
+#include "phyio.h"
struct DEV { /* Device information */
struct CACHE cache;
struct VCB *vcb; /* Pointer to volume (if mounted) */
- int access; /* Device mount options (e.g., /Write) */
- unsigned sectors; /* Device physical sectors */
+ int access; /* Device mount options (e.g., /Write) */
+ void *context; /* Context for implementation */
+
#ifdef _WIN32
short drive; /* Drive no. (0=A, 1=B, 2=C, ...) */
unsigned bytespersector; /* Device physical sectorsize (bytes) */
@@ -39,15 +43,22 @@ struct DEV { /* Device information */
short id; /* ASPI device id */
} ASPI;
} API;
- char *IoBuffer; /* Pointer to a buffer for the device */
unsigned last_sector; /* Last sector no read (still in buffer) */
#else
int handle; /* Device physical I/O handle */
#endif
+#if defined(_WIN32) || defined(USE_VHD)
+ char *IoBuffer; /* Pointer to a buffer for the device */
+#endif
+ struct disktype *disktype; /* Structure defining virtual disk geometry */
+ phy_iord_t devread; /* Device read function */
+ phy_iowr_t devwrite; /* Device write function */
+ off_t eofptr; /* End of file on virtual files */
char devnam[1]; /* Device name */
};
unsigned device_lookup( unsigned devlen, char *devnam, int create,
struct DEV **retdev );
+void device_done( struct DEV *dev );
#endif /* # ifndef _DEVICE_H */
diff --git a/extracters/ods2/diffcmd.c b/extracters/ods2/diffcmd.c
new file mode 100644
index 0000000..c7d7f83
--- /dev/null
+++ b/extracters/ods2/diffcmd.c
@@ -0,0 +1,96 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_DIFFCMD )
+#define DEBUG DEBUG_DIFFCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+/******************************************************************* dodiff() */
+
+/* dodiff: a simple file difference routine */
+
+param_t diffpars[] = { {"ods-2_filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
+ {"local_filespec", REQ, LCLFS, NOPA, "for file on local filesystem."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(diff) {
+ int sts, records = 0;
+ char *rec, *cpy = NULL;
+ char *name;
+ FILE *tof;
+ struct FAB fab = cc$rms_fab;
+ struct RAB rab = cc$rms_rab;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ name = argv[1];
+ sts = SS$_BADFILENAME;
+ if ( *name == '\0' ) {
+ return sts;
+ }
+ records = 0;
+ fab.fab$l_fna = name;
+ fab.fab$b_fns = strlen( fab.fab$l_fna );
+ tof = openf( argv[2], "r" );
+ if ( tof == NULL ) {
+ printf("%%ODS2-E-OPENERR, Could not open file %s\n",name);
+ perror( " - " );
+ return SS$_NOSUCHFILE;
+ }
+ sts = sys_open( &fab );
+ if ( sts & STS$M_SUCCESS ) {
+ rab.rab$l_fab = &fab;
+ sts = sys_connect( &rab );
+ if( sts & STS$M_SUCCESS ) {
+ if( (rec = malloc( MAXREC + 2 )) == NULL ) {
+ perror( "malloc" );
+ } else {
+ rab.rab$l_ubf = rec;
+ rab.rab$w_usz = MAXREC;
+ while( (sts = sys_get( &rab )) & STS$M_SUCCESS ) {
+ rec[rab.rab$w_rsz] = '\0';
+ cpy = fgetline( tof, FALSE );
+ if( cpy == NULL ||
+ rab.rab$w_rsz != strlen( cpy ) ||
+ memcmp( rec, cpy, rab.rab$w_rsz ) != 0 ) {
+
+ printf( "%%DIFF-F-DIFFERENT Files are different!\n" );
+ sts = 4;
+ break;
+ }
+ free( cpy );
+ cpy = NULL;
+ records++;
+ }
+ if( cpy != NULL ) free( cpy );
+ free( rec );
+ rec = cpy = NULL;
+ }
+ sys_disconnect(&rab);
+ }
+ sys_close(&fab);
+ }
+ fclose(tof);
+ if (sts == RMS$_EOF) sts = SS$_NORMAL;
+ if ( sts & STS$M_SUCCESS ) {
+ printf( "%%DIFF-I-Compared %d records\n", records );
+ } else if ( sts != 4 ) {
+ printf("%%DIFF-F-Error %s in difference\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
diff --git a/extracters/ods2/dircmd.c b/extracters/ods2/dircmd.c
new file mode 100644
index 0000000..55bbe2f
--- /dev/null
+++ b/extracters/ods2/dircmd.c
@@ -0,0 +1,436 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_DIRCMD )
+#define DEBUG DEBUG_DIRCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+static void dirtotal( int options, int size, int alloc );
+
+
+/******************************************************************* dodir() */
+
+#define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size)
+#define dir_date (1 << 0)
+#define dir_fileid (1 << 1)
+#define dir_owner (1 << 2)
+#define dir_prot (1 << 3)
+#define dir_size (1 << 4)
+
+#define dir_grand (1 << 5)
+#define dir_heading (1 << 6)
+#define dir_names (1 << 7)
+#define dir_trailing (1 << 8)
+#define dir_full (1 << 9)
+#define dir_total (1 << 10)
+
+#define dir_backup (1 << 11)
+#define dir_created (1 << 12)
+#define dir_expired (1 << 13)
+#define dir_modified (1 << 14)
+#define dir_dates (dir_backup | dir_created | dir_expired | dir_modified)
+
+#define dir_allocated (1 << 15)
+#define dir_used (1 << 16)
+#define dir_sizes (dir_allocated | dir_used)
+
+#define dir_default (dir_heading|dir_names|dir_trailing)
+
+const int dir_defaults = dir_default;
+
+static qual_t datekwds[] = { {"created", dir_created, 0, NV, "Date file created (default)"},
+ {"modified", dir_modified, 0, NV, "Date file modified"},
+ {"expired", dir_expired, 0, NV, "Date file expired"},
+ {"backup", dir_backup, 0, NV, "Date of last backup"},
+ {NULL, 0, 0, NV, NULL}
+};
+static qual_t sizekwds[] = { {"both", dir_used|dir_allocated, 0, NV, "Both used and allocated" },
+ {"allocation", dir_allocated, 0, NV, "Blocks allocated to file" },
+ {"used", dir_used, 0, NV, "Blocks used in file" },
+ {NULL, 0, 0, NV, NULL}
+};
+qual_t dirquals[] = { {"brief", dir_default, ~dir_default, NV,
+ "Brief display - names with header/trailer (default)"},
+ {"date", dir_date, dir_dates, KV(datekwds),
+ "-Include file date(s)", },
+ {"nodate", 0, dir_date, NV, NULL, },
+ {"file_id", dir_fileid, 0, NV, "-Include file ID", },
+ {"nofile_id", 0, dir_fileid, NV, NULL },
+ {"full", dir_full|dir_heading|dir_trailing,
+ ~dir_full, NV, "Include full details", },
+ {"grand_total", dir_grand, ~dir_grand & ~(dir_size|dir_sizes),
+ NV, "-Include only grand total",},
+ {"nogrand_total", 0, dir_grand, NV, NULL},
+ {"heading", dir_heading, 0, NV, "-Include heading", },
+ {"noheading", 0, dir_heading, NV, NULL},
+ {"owner", dir_owner, 0, NV, "-Include file owner", },
+ {"noowner", 0, dir_owner, NV, NULL, },
+ {"protection", dir_prot, 0, NV,
+ "-Include file protection", },
+ {"noprotection", 0, dir_prot, NV, NULL, },
+ {"size", dir_size, dir_sizes, KV(sizekwds),
+ "-Include file size (blocks)", },
+ {"nosize", 0, dir_size|dir_sizes,
+ NV, NULL, },
+ {"total", dir_total|dir_heading,
+ ~dir_total & ~(dir_size|dir_sizes),
+ NV,
+ "Include only directory name and summary",},
+ {"trailing", dir_trailing, 0, NV,
+ "-Include trailing summary line",},
+ {"notrailing", 0, dir_trailing, NV, NULL},
+ {NULL, 0, 0, NV, NULL} };
+int dir_defopt = dir_default;
+
+param_t dirpars[] = { {"filespec", OPT, VMSFS, NOPA, "for files to select. Wildcards are allowed."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+
+/************************************************************ dodir() */
+
+DECL_CMD(dir) {
+ char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
+ int options;
+ unsigned sts;
+ int filecount = 0, nobackup = 0, contigb = 0, contig = 0, directory = 0;
+ struct NAM nam = cc$rms_nam;
+ struct FAB fab = cc$rms_fab;
+ struct XABDAT dat = cc$rms_xabdat;
+ struct XABFHC fhc = cc$rms_xabfhc;
+ struct XABPRO pro = cc$rms_xabpro;
+ struct XABITM itm = cc$rms_xabitm;
+ struct item_list xitems[] = {
+ { XAB$_UCHAR_NOBACKUP, sizeof(int), NULL, 0 },
+ { XAB$_UCHAR_CONTIG, sizeof(int), NULL, 0 },
+ { XAB$_UCHAR_CONTIGB, sizeof(int), NULL, 0 },
+ { XAB$_UCHAR_DIRECTORY, sizeof(int), NULL, 0 },
+ { 0, 0, NULL, 0 }
+ };
+
+ UNUSED(argc);
+
+ nam.nam$l_esa = res;
+ nam.nam$b_ess = NAM$C_MAXRSS;
+
+ fab.fab$l_nam = &nam;
+ fab.fab$l_xab = &dat;
+
+ dat.xab$l_nxt = &fhc;
+
+ fhc.xab$l_nxt = &pro;
+
+ pro.xab$l_nxt = &itm;
+ xitems[0].buffer = &nobackup;
+ xitems[1].buffer = &contig;
+ xitems[2].buffer = &contigb;
+ xitems[3].buffer = &directory;
+
+ itm.xab$b_mode = XAB$K_SENSEMODE;
+ itm.xab$l_itemlist = xitems;
+
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ fab.fab$l_dna = "*.*;*";
+ fab.fab$b_dns = strlen(fab.fab$l_dna);
+
+ options = checkquals(dir_defopt,dirquals,qualc,qualv);
+ if( options == -1 )
+ return SS$_BADPARAM;
+
+ if (options & dir_full)
+ options |= dir_extra;
+ if (options & (dir_total | dir_grand)) {
+ options |= dir_trailing;
+ if (options & (dir_extra & ~dir_size))
+ options |= dir_names;
+ } else {
+ if (options & dir_extra)
+ options |= dir_names;
+ }
+ if( (options & dir_size) && !(options & dir_sizes) )
+ options |= dir_used;
+ if( (options & dir_date) && !(options & dir_dates) )
+ options |= dir_created;
+
+ sts = sys_parse(&fab);
+ if ( sts & STS$M_SUCCESS ) {
+ char dir[NAM$C_MAXRSS + 1];
+ int namelen;
+ int dirlen = 0;
+ int dirfiles = 0, dircount = 0;
+ int dirblocks = 0, diralloc = 0, totblocks = 0, totalloc = 0;
+ int printcol = 0;
+#if DEBUG
+ res[nam.nam$b_esl] = '\0';
+ printf("Parse: %s\n",res);
+#endif
+ nam.nam$l_rsa = rsa;
+ nam.nam$b_rss = NAM$C_MAXRSS;
+ fab.fab$l_fop = FAB$M_NAM;
+ while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
+
+ if (dirlen != nam.nam$b_dev + nam.nam$b_dir ||
+ memcmp(rsa, dir, nam.nam$b_dev + nam.nam$b_dir) != 0) {
+ if (dirfiles > 0 && (options & dir_trailing)) {
+ if (printcol > 0) printf("\n");
+ printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
+ dirtotal( options, dirblocks, diralloc );
+ fputs(".\n",stdout);
+ }
+ dirlen = nam.nam$b_dev + nam.nam$b_dir;
+ memcpy(dir,rsa,dirlen);
+ dir[dirlen] = '\0';
+ if( options & dir_heading) printf("\nDirectory %s\n\n",dir);
+ filecount += dirfiles;
+ totblocks += dirblocks;
+ totalloc += diralloc;
+ dircount++;
+ dirfiles = 0;
+ dirblocks = 0;
+ diralloc = 0;
+ printcol = 0;
+ }
+ rsa[nam.nam$b_rsl] = '\0';
+ namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
+ if ((options & (dir_heading|dir_extra|dir_full)) == dir_heading) {
+ if( options & dir_names ) {
+ if (printcol > 0) {
+ int newcol = (printcol + 20) / 20 * 20;
+ if (newcol + namelen >= 80) {
+ fputs("\n",stdout);
+ printcol = 0;
+ } else {
+ printf("%*s",newcol - printcol," ");
+ printcol = newcol;
+ }
+ }
+ fputs(rsa + dirlen,stdout);
+ printcol += namelen;
+ }
+ } else {
+ if (options & dir_names) {
+ if ( (options & dir_heading) == 0 ) printf( "%s",dir );
+ if (namelen > 18) {
+ printf("%s",rsa + dirlen);
+ if( options & dir_extra )
+ printf( "\n " );
+ } else {
+ printf("%-19s",rsa + dirlen);
+ }
+ }
+ sts = sys_open(&fab);
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ printf("%%ODS2-E-OPENERR, Open error: %s\n", getmsg(sts, MSG_TEXT));
+ } else {
+ sts = sys_close(&fab);
+ if (options & dir_fileid) {
+ char fileid[30]; /* 24 bits, 16 bits. 8 bits = 8 + 5 + 3 digits = 16 + (,,)\0 => 21 */
+ if( options & dir_full) printf( " File ID:" );
+ (void) snprintf(fileid,sizeof(fileid),"(%d,%d,%d)",
+ (nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num,
+ nam.nam$w_fid_seq, nam.nam$b_fid_rvn );
+ printf(" %-22s",fileid);
+ }
+ diralloc += fab.fab$l_alq;
+ if (options & dir_used) {
+ unsigned filesize = fhc.xab$l_ebk;
+ if (fhc.xab$w_ffb == 0) filesize--;
+ dirblocks += filesize;
+
+ if (options & dir_names) { /* Don't print w/o names (e.g. totals) */
+ if( options & dir_full) printf( "\nSize: " );
+ printf("%9d",filesize);
+ if( options & (dir_allocated|dir_full)) printf( "/%-9d ",fab.fab$l_alq );
+ }
+ } else {
+ if ( (options & (dir_allocated|dir_names)) == (dir_allocated|dir_names)) {
+ printf( "%9d", fab.fab$l_alq );
+ }
+ }
+#define pprot(val,pos,del) {\
+ unsigned int v = ~(((val) >> (pos)) & xab$m_prot); \
+ if( v & xab$m_noread ) printf( "R" ); \
+ if( v & xab$m_nowrite ) printf( "W" ); \
+ if( v & xab$m_noexe ) printf( "E" ); \
+ if( v & xab$m_nodel ) printf( "D" ); \
+ printf( del ); \
+ }
+ if (options & dir_full) {
+ int pos = 0;
+
+ printf( "Owner: [%o,%o]\n", ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF);
+ printf( "Created: " ); prvmstime( dat.xab$q_cdt, "\n" );
+ printf( "Revised: " ); prvmstime( dat.xab$q_rdt, " (" ); printf( "%u)\n", dat.xab$w_rvn );
+ printf( "Expires: " ); prvmstime( dat.xab$q_edt, "\n" );
+ printf( "Backup: " ); prvmstime( dat.xab$q_bdt, "\n" );
+ pwrap( &pos, "File organization: " );
+ switch( fab.fab$b_org ) {
+ case FAB$C_SEQ:
+ pwrap( &pos, "Sequential" ); break;
+ case FAB$C_REL:
+ pwrap( &pos, "Relative" /*, Maximum record number %u", fab.fab$l_mrn*/ ); break;
+ case FAB$C_IDX:
+ pwrap( &pos, "Indexed" ); break; /*, Prolog: 3, Using 4 keys\nIn 3 areas */
+ default:
+ pwrap( &pos, "Unknown (%u)", fab.fab$b_org ); break;
+ }
+ /* File attributes: Allocation: 372, Extend: 3, Maximum bucket size: 3, Global buffer count: 0, No version limit
+ Contiguous best try */
+ pwrap( &pos, "\nFile attributes: " );
+ pwrap( &pos, "Allocation: %u", fab.fab$l_alq );
+ pwrap( &pos, ", Extend: %u", fab.fab$w_deq );
+ /* Missing: , Maximum bucket size: n*/
+ pwrap( &pos, ", Global buffer count: %u", fab.fab$w_gbc );
+ if( fhc.xab$w_verlimit == 0 || fhc.xab$w_verlimit == 32767 )
+ pwrap( &pos, ", No %sversion limit", directory? "default ": "" );
+ else
+ pwrap( &pos, ", %sersion limit: %u", (directory? "Default v": "V"), fhc.xab$w_verlimit );
+ if( contig )
+ pwrap( &pos, ", Contiguous" );
+ if( contigb )
+ pwrap( &pos, ", Contiguous best try" );
+ if( nobackup )
+ pwrap( &pos, ", Backups disabled" );
+ if( directory )
+ pwrap( &pos, ", Directory file" );
+ pwrap( &pos, "\n" );
+
+ pwrap( &pos, "Record format: " );
+ switch( fab.fab$b_rfm ) {
+ default:
+ case FAB$C_UDF:
+ pwrap( &pos, "Undefined" ); break;
+ case FAB$C_FIX:
+ pwrap( &pos, "Fixed length %u byte records", fab.fab$w_mrs ); break;
+ case FAB$C_VAR:
+ pwrap( &pos, "Variable length, maximum %u bytes", fab.fab$w_mrs ); break;
+ case FAB$C_VFC:
+ pwrap( &pos, "Variable length, fixed carriage control %u, maximum %u bytes", (fab.fab$b_fsz? fab.fab$b_fsz: 2), fab.fab$w_mrs ); break;
+ case FAB$C_STM:
+ pwrap( &pos, "Stream" ); break;
+ case FAB$C_STMLF:
+ pwrap( &pos, "Stream-LF" ); break;
+ case FAB$C_STMCR:
+ pwrap( &pos, "Stream-CR" ); break;
+ }
+ pwrap( &pos, "\n" );
+
+ pwrap( &pos, "Record attributes: " );
+ if( fab.fab$b_rat == 0 )
+ pwrap( &pos, "None" );
+ else {
+ const char *more = "";
+ if( fab.fab$b_rat & FAB$M_FTN ) {
+ pwrap( &pos, "%sFortran carriage control", more );
+ more = ", ";
+ }
+ if( fab.fab$b_rat & FAB$M_CR ) {
+ pwrap( &pos, "%sCarriage return carriage control", more );
+ more = ", ";
+ }
+ if( fab.fab$b_rat & FAB$M_PRN ) {
+ pwrap( &pos, "%sPrinter control", more );
+ more = ", ";
+ }
+ if( fab.fab$b_rat & FAB$M_BLK ) {
+ pwrap( &pos, "%sNon-spanned", more );
+ }
+ }
+ printf( "\n" );
+ /*
+RMS attributes: None
+Journaling enabled: None
+*/
+ printf( "File protection: System:" );
+ pprot(pro.xab$w_pro,xab$v_system,", Owner:")
+ pprot(pro.xab$w_pro,xab$v_owner,", Group:")
+ pprot(pro.xab$w_pro,xab$v_group,", World:")
+ pprot(pro.xab$w_pro,xab$v_world,"\n");
+ } else { /* !full */
+ if (options & dir_date) {
+ if( options & dir_created )
+ sts = prvmstime( dat.xab$q_cdt, NULL );
+ if( options & dir_modified )
+ sts = prvmstime( dat.xab$q_rdt, NULL );
+ if( options & dir_expired )
+ sts = prvmstime( dat.xab$q_edt, NULL );
+ if( options & dir_backup )
+ sts = prvmstime( dat.xab$q_bdt, NULL );
+ }
+ if (options & dir_owner) {
+ printf(" [%o,%o]", ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF);
+ }
+ if (options & dir_prot) {
+ printf( " (" );
+ pprot(pro.xab$w_pro,xab$v_system,",")
+ pprot(pro.xab$w_pro,xab$v_owner,",")
+ pprot(pro.xab$w_pro,xab$v_group,",")
+ pprot(pro.xab$w_pro,xab$v_world,")")
+ }
+ }
+#undef pprot
+ if (options & dir_names)
+ printf("\n");
+ }
+ }
+ dirfiles++;
+ }
+ if (sts == RMS$_NMF) sts = SS$_NORMAL;
+ if (printcol > 0) printf("\n");
+ if (options & dir_trailing) {
+ printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
+ dirtotal( options, dirblocks, diralloc );
+ fputs(".\n",stdout);
+ }
+ filecount += dirfiles;
+ totblocks += dirblocks;
+ totalloc += diralloc;
+ if (options & dir_grand) {
+ printf("\nGrand total of %d director%s, %d file%s",
+ dircount,(dircount == 1 ? "y" : "ies"),
+ filecount,(filecount == 1 ? "" : "s"));
+ dirtotal( options, totblocks, totalloc );
+ fputs(".\n",stdout);
+ }
+ }
+ if ( sts & STS$M_SUCCESS ) {
+ if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n");
+ } else {
+ printf("%%DIR-E-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
+
+/*********************************************************** dirtotal() */
+
+static void dirtotal( int options, int size, int alloc ) {
+ if ( !(options & dir_size) )
+ return;
+ fputs( ", ", stdout );
+
+ if ( options & dir_used )
+ printf( "%d", size );
+ if ( options & dir_allocated ) {
+ if (options & dir_used) printf( "/" );
+ printf( "%d", alloc );
+ }
+ if ((options & dir_dates) == dir_dates)
+ printf( " block%s",(size ==1 && alloc == 1 ? "" : "s"));
+ else
+ printf( " block%s",(((options & dir_used) && size == 1) ||
+ ((options & dir_allocated) && alloc == 1))? "" : "s");
+ return;
+}
diff --git a/extracters/ods2/direct.c b/extracters/ods2/direct.c
index 435fb8c..edb5301 100644
--- a/extracters/ods2/direct.c
+++ b/extracters/ods2/direct.c
@@ -1,4 +1,4 @@
-/* Direct.c V2.1 */
+/* Direct.c */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -13,6 +13,14 @@
/* This module does all directory file handling - mostly
lookups of filenames in directory files... */
+#if !defined( DEBUG ) && defined( DEBUG_DIRECT )
+#define DEBUG DEBUG_DIRECT
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#define DEBUGx on
#include
@@ -24,20 +32,13 @@
#include "descrip.h"
#include "direct.h"
#include "fibdef.h"
+#include "ods2.h"
#include "ssdef.h"
#include "stsdef.h"
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
#define BLOCKSIZE 512
#define MAXREC (BLOCKSIZE - 2)
-
/* Some statistical counters... */
static int direct_lookups = 0;
@@ -66,8 +67,7 @@ void direct_show( void ) {
/* name_check() - take a name specification and return name length without
the version number, an integer version number, and a wildcard flag */
-unsigned name_check(char *str,int len,int *retlen,int *retver,int *wildflag)
-{
+static unsigned name_check( char *str, int len, int *retlen, int *retver, int *wildflag ) {
int wildcard = FALSE;
char *name_start = str;
register int dots = 0;
@@ -256,7 +256,7 @@ int name_match(char *spec,int spec_len,char *dirent,int dirent_len)
unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
struct VIOC * vioc,char *buffer,
- struct dir$rec * dr,struct dir$ent * de,
+ struct dir$r_rec * dr,struct dir$r_ent * de,
char *filename,unsigned filelen,
unsigned version,struct fiddef * fid)
{
@@ -265,10 +265,10 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
/* Compute space required... */
- register int addlen = sizeof(struct dir$ent);
+ register int addlen = sizeof(struct dir$r_ent);
direct_inserts++;
if (de == NULL)
- addlen += (filelen + sizeof(struct dir$rec)) & ~1;
+ addlen += (filelen + sizeof(struct dir$r_rec)) & ~1;
/* Compute block space in use ... */
@@ -276,29 +276,29 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
int invalid_dir = TRUE;
while (TRUE) {
register int sizecheck;
- register struct dir$rec *nr = (struct dir$rec *) (buffer + inuse);
+ register struct dir$r_rec *nr = (struct dir$r_rec *) (buffer + inuse);
if (dr == nr) invalid_dir = FALSE;
- sizecheck = VMSWORD(nr->dir$size);
- if (sizecheck == 0xffff)
+ sizecheck = F11WORD(nr->dir$w_size);
+ if (sizecheck == 0xffff) /* End of data marker */
break;
sizecheck += 2;
inuse += sizecheck;
- sizecheck -= (nr->dir$namecount + sizeof(struct dir$rec)) & ~1;
+ sizecheck -= (nr->dir$b_namecount + sizeof(struct dir$r_rec)) & ~1;
if (inuse > MAXREC || (inuse & 1) || sizecheck <= 0 ||
- sizecheck % sizeof(struct dir$ent) != 0) {
+ sizecheck % sizeof(struct dir$r_ent) != 0) {
deaccesschunk(vioc,0,0,FALSE);
return SS$_BADIRECTORY;
}
- };
+ }
if (invalid_dir) {
printf("BUGCHECK invalid dir\n");
exit(EXIT_FAILURE);
}
if (de != NULL) {
- if (VMSWORD(dr->dir$size) > MAXREC ||
- (char *) de < dr->dir$name + dr->dir$namecount ||
- (char *) de > (char *) dr + VMSWORD(dr->dir$size) + 2) {
+ if (F11WORD(dr->dir$w_size) > MAXREC ||
+ (char *) de < dr->dir$t_name + dr->dir$b_namecount ||
+ (char *) de > (char *) dr + F11WORD(dr->dir$w_size) + 2) {
printf("BUGCHECK invalid de\n");
exit(EXIT_FAILURE);
}
@@ -308,14 +308,18 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
/* If not enough space free extend the directory... */
if (addlen > MAXREC - inuse) {
- register struct dir$rec *nr;
+ register struct dir$r_rec *nr;
unsigned keep_new = 0;
char *newbuf;
struct VIOC *newvioc;
unsigned newblk = eofblk + 1;
direct_splits++;
- printf("Splitting record... %s %u,%u,%u,%u\n", dr->dir$name,de->dir$fid.fid$w_num,
- de->dir$fid.fid$w_seq,de->dir$fid.fid$b_rvn,de->dir$fid.fid$b_nmx);
+ printf( "Splitting record... %s", dr->dir$t_name );
+ if( de != NULL )
+ printf( " %u,%u,%u,%u\n", de->dir$w_fid.fid$w_num,
+ de->dir$w_fid.fid$w_seq, de->dir$w_fid.fid$b_rvn, de->dir$w_fid.fid$b_nmx );
+ else
+ putchar( '\n' );
if (newblk > fcb->hiblock) {
printf("I can't extend a directory yet!!\n");
exit(EXIT_FAILURE);
@@ -345,49 +349,49 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
}
memset(newbuf,0,BLOCKSIZE);
eofblk++;
- fcb->head->fh2$w_recattr.fat$l_efblk = VMSWORD(eofblk + 1);
+ fcb->head->fh2$w_recattr.fat$l_efblk = F11WORD(eofblk + 1);
/* First find where the next record is... */
nr = dr;
- if (VMSWORD(nr->dir$size) <= MAXREC)
- nr = (struct dir$rec *) ((char *) nr + VMSWORD(nr->dir$size) + 2);
+ if (F11WORD(nr->dir$w_size) <= MAXREC)
+ nr = (struct dir$r_rec *) ((char *) nr + F11WORD(nr->dir$w_size) + 2);
/* Can we split between records? */
if (de == NULL || (char *) dr != buffer ||
- VMSWORD(nr->dir$size) <= MAXREC) {
- register struct dir$rec *sp = dr;
+ F11WORD(nr->dir$w_size) <= MAXREC) {
+ register struct dir$r_rec *sp = dr;
if ((char *) dr == buffer && de != NULL) sp = nr;
memcpy(newbuf,sp,((buffer + BLOCKSIZE) - (char *) sp));
memset(sp,0,((buffer + BLOCKSIZE) - (char *) sp));
- sp->dir$size = VMSWORD(0xffff);
+ sp->dir$w_size = F11WORD(0xffff);
if (sp == dr &&
(de != NULL || (char *) sp >= buffer + MAXREC - addlen)) {
if (de != NULL)
- de = (struct dir$ent *)
+ de = (struct dir$r_ent *)
(newbuf + ((char *) de - (char *) sp));
- dr = (struct dir$rec *) (newbuf + ((char *) dr - (char *) sp));
+ dr = (struct dir$r_rec *) (newbuf + ((char *) dr - (char *) sp));
keep_new = 1;
}
/* OK, we have to split the record then.. */
} else {
- register unsigned reclen = (dr->dir$namecount +
- sizeof(struct dir$rec)) & ~1;
- register struct dir$rec *nbr = (struct dir$rec *) newbuf;
- printf("Super split %s %u,%u,%u,%u\n", dr->dir$name,de->dir$fid.fid$w_num,
- de->dir$fid.fid$w_seq,de->dir$fid.fid$b_rvn,de->dir$fid.fid$b_nmx);
+ register unsigned reclen = (dr->dir$b_namecount +
+ sizeof(struct dir$r_rec)) & ~1;
+ register struct dir$r_rec *nbr = (struct dir$r_rec *) newbuf;
+ printf("Super split %s %u,%u,%u,%u\n", dr->dir$t_name,de->dir$w_fid.fid$w_num,
+ de->dir$w_fid.fid$w_seq,de->dir$w_fid.fid$b_rvn,de->dir$w_fid.fid$b_nmx);
memcpy(newbuf,buffer,reclen);
memcpy(newbuf + reclen,de,((char *) nr - (char *) de) + 2);
- nbr->dir$size = VMSWORD(reclen + ((char *) nr - (char *) de) - 2);
+ nbr->dir$w_size = F11WORD(reclen + ((char *) nr - (char *) de) - 2);
memset((char *) de + 2,0,((char *) nr - (char *) de));
- ((struct dir$rec *) de)->dir$size = VMSWORD(0xffff);
- dr->dir$size = VMSWORD(((char *) de - (char *) dr) - 2);
+ ((struct dir$r_rec *) de)->dir$w_size = F11WORD(0xffff);
+ dr->dir$w_size = F11WORD(((char *) de - (char *) dr) - 2);
if ((char *) de >= (char *) nr) {
- dr = (struct dir$rec *) newbuf;
- de = (struct dir$ent *) (newbuf + reclen);
+ dr = (struct dir$r_rec *) newbuf;
+ de = (struct dir$r_ent *) (newbuf + reclen);
keep_new = 1;
}
}
@@ -409,23 +413,23 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
if (de == NULL) {
memmove((char *) dr + addlen,dr,
BLOCKSIZE - (((char *) dr + addlen) - buffer));
- dr->dir$size = VMSWORD(addlen - 2);
- dr->dir$verlimit = 0;
- dr->dir$flags = 0;
- dr->dir$namecount = filelen;
- memcpy(dr->dir$name,filename,filelen);
- de = (struct dir$ent *)
- ((char *) dr + (addlen - sizeof(struct dir$ent)));
+ dr->dir$w_size = F11WORD(addlen - 2);
+ dr->dir$w_verlimit = 0;
+ dr->dir$b_flags = 0;
+ dr->dir$b_namecount = filelen;
+ memcpy(dr->dir$t_name,filename,filelen);
+ de = (struct dir$r_ent *)
+ ((char *) dr + (addlen - sizeof(struct dir$r_ent)));
} else {
- dr->dir$size = VMSWORD(VMSWORD(dr->dir$size) + addlen);
+ dr->dir$w_size = F11WORD(F11WORD(dr->dir$w_size) + addlen);
memmove((char *) de + addlen,de,
BLOCKSIZE - (((char *) de + addlen) - buffer));
}
/* Write the entry values are we are done! */
- de->dir$version = VMSWORD(version);
- fid_copy(&de->dir$fid,fid,0);
+ de->dir$w_version = F11WORD(version);
+ fid_copy(&de->dir$w_fid,fid,0);
return deaccesschunk(vioc,curblk,1,TRUE);
}
@@ -434,20 +438,20 @@ unsigned insert_ent(struct FCB * fcb,unsigned eofblk,unsigned curblk,
/* delete_ent() - delete a directory entry */
unsigned delete_ent(struct FCB * fcb,struct VIOC * vioc,unsigned curblk,
- struct dir$rec * dr,struct dir$ent * de,
+ struct dir$r_rec * dr,struct dir$r_ent * de,
char *buffer,unsigned eofblk)
{
unsigned sts = SS$_NORMAL;
unsigned ent;
direct_deletes++;
- ent = (VMSWORD(dr->dir$size) - sizeof(struct dir$rec)
- - dr->dir$namecount + 3) / sizeof(struct dir$ent);
+ ent = (F11WORD(dr->dir$w_size) - sizeof(struct dir$r_rec)
+ - dr->dir$b_namecount + 3) / sizeof(struct dir$r_ent);
if (ent > 1) {
- char *ne = (char *) de + sizeof(struct dir$ent);
+ char *ne = (char *) de + sizeof(struct dir$r_ent);
memcpy(de,ne,BLOCKSIZE - (ne - buffer));
- dr->dir$size = VMSWORD(VMSWORD(dr->dir$size) - sizeof(struct dir$ent));
+ dr->dir$w_size = F11WORD(F11WORD(dr->dir$w_size) - sizeof(struct dir$r_ent));
} else {
- char *nr = (char *) dr + VMSWORD(dr->dir$size) + 2;
+ char *nr = (char *) dr + F11WORD(dr->dir$w_size) + 2;
if (eofblk == 1 || (char *) dr > buffer ||
(nr <= buffer + MAXREC && (unsigned short) *nr < BLOCKSIZE)) {
memcpy(dr,nr,BLOCKSIZE - (nr - buffer));
@@ -464,7 +468,7 @@ unsigned delete_ent(struct FCB * fcb,struct VIOC * vioc,unsigned curblk,
vioc = nxtvioc;
}
if (sts & STS$M_SUCCESS) {
- fcb->head->fh2$w_recattr.fat$l_efblk = VMSSWAP(eofblk);
+ fcb->head->fh2$w_recattr.fat$l_efblk = F11SWAP(eofblk);
eofblk--;
}
}
@@ -481,17 +485,17 @@ unsigned delete_ent(struct FCB * fcb,struct VIOC * vioc,unsigned curblk,
/* return_ent() - return information about a directory entry */
unsigned return_ent(struct FCB * fcb,struct VIOC * vioc,unsigned curblk,
- struct dir$rec * dr,struct dir$ent * de,struct fibdef * fib,
+ struct dir$r_rec * dr,struct dir$r_ent * de,struct fibdef * fib,
unsigned short *reslen,struct dsc_descriptor * resdsc,
int wildcard)
{
register int scale = 10;
- register int version = VMSWORD(de->dir$version);
- register int length = dr->dir$namecount;
+ register int version = F11WORD(de->dir$w_version);
+ register int length = dr->dir$b_namecount;
register char *ptr = resdsc->dsc_a_pointer;
register int outlen = resdsc->dsc_w_length;
if (length > outlen) length = outlen;
- memcpy(ptr,dr->dir$name,length);
+ memcpy(ptr,dr->dir$t_name,length);
while (version >= scale) scale *= 10;
ptr += length;
if (length < outlen) {
@@ -506,8 +510,9 @@ unsigned return_ent(struct FCB * fcb,struct VIOC * vioc,unsigned curblk,
} while (scale > 1);
}
*reslen = length;
- fid_copy((struct fiddef *)&fib->fib$w_fid_num,&de->dir$fid,0);
+ fid_copy((struct fiddef *)&fib->fib$w_fid_num,&de->dir$w_fid,0);
if (fib->fib$b_fid_rvn == 0) fib->fib$b_fid_rvn = fcb->rvn;
+ fib->fib$w_verlimit = dr->dir$w_verlimit;
if (wildcard || (fib->fib$w_nmctl & FIB$M_WILD)) {
fib->fib$l_wcc = curblk;
} else {
@@ -540,14 +545,15 @@ unsigned search_ent(struct FCB *fcb,
curblk = fib->fib$l_wcc;
if (curblk != 0) {
searchspec = resdsc->dsc_a_pointer;
- sts = name_check(searchspec,*reslen,&searchlen,&version,&wildcard);
- if (action || wildcard) sts = SS$_BADFILENAME;
+ sts = name_check( searchspec, *reslen, &searchlen, &version, &wildcard );
+ if( MODIFIES(action) || wildcard )
+ sts = SS$_BADFILENAME;
wcc_flag = TRUE;
} else {
searchspec = filedsc->dsc_a_pointer;
- sts = name_check(searchspec,filedsc->dsc_w_length,&searchlen,&version,
- &wildcard);
- if ((action && wildcard) || (action > 1 && version < 0)) {
+ sts = name_check( searchspec, filedsc->dsc_w_length, &searchlen, &version,
+ &wildcard);
+ if( (MODIFIES(action) && wildcard) || (action == DIRECT_CREATE && version < 0) ) {
sts = SS$_BADFILENAME;
}
wcc_flag = FALSE;
@@ -564,27 +570,27 @@ unsigned search_ent(struct FCB *fcb,
while (loblk < hiblk) {
register int cmp;
register unsigned newblk;
- register struct dir$rec *dr;
+ register struct dir$r_rec *dr;
direct_searches++;
- sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0);
+ sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,MODIFIES(action));
if (!(sts & STS$M_SUCCESS)) return sts;
- dr = (struct dir$rec *) buffer;
- if (VMSWORD(dr->dir$size) > MAXREC) {
+ dr = (struct dir$r_rec *) buffer;
+ if (F11WORD(dr->dir$w_size) > MAXREC) {
cmp = MAT_GT;
} else {
- cmp = name_match(searchspec,searchlen,dr->dir$name,
- dr->dir$namecount);
+ cmp = name_match(searchspec,searchlen,dr->dir$t_name,
+ dr->dir$b_namecount);
if (cmp == MAT_EQ) {
if (wildcard || version < 1 || version > 32767) {
cmp = MAT_NE; /* no match - want to find start */
} else {
- register struct dir$ent *de =
- (struct dir$ent *)
- (dr->dir$name + ((dr->dir$namecount + 1) & ~1));
- if (VMSWORD(de->dir$version) < version) {
+ register struct dir$r_ent *de =
+ (struct dir$r_ent *)
+ (dr->dir$t_name + ((dr->dir$b_namecount + 1) & ~1));
+ if (F11WORD(de->dir$w_version) < version) {
cmp = MAT_GT; /* too far... */
} else {
- if (VMSWORD(de->dir$version) > version) {
+ if (F11WORD(de->dir$w_version) > version) {
cmp = MAT_LT; /* further ahead... */
}
}
@@ -624,21 +630,21 @@ unsigned search_ent(struct FCB *fcb,
unsigned last_len = 0;
register int relver = 0;
while ((sts & STS$M_SUCCESS) && curblk <= eofblk) {
- register struct dir$rec *dr;
+ register struct dir$r_rec *dr;
register int cmp = MAT_LT;
/* Access a directory block. Reset relative version if it starts
with a record we haven't seen before... */
- if (vioc == NULL) {
- sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0);
+ if( vioc == NULL ) {
+ sts = accesschunk( fcb,curblk,&vioc,&buffer,NULL,MODIFIES(action) );
if (!(sts & STS$M_SUCCESS)) return sts;
}
- dr = (struct dir$rec *) buffer;
- if (last_len != dr->dir$namecount) {
+ dr = (struct dir$r_rec *) buffer;
+ if (last_len != dr->dir$b_namecount) {
relver = 0;
} else {
- if (name_match(last_name,last_len,dr->dir$name,last_len) !=
+ if (name_match(last_name,last_len,dr->dir$t_name,last_len) !=
MAT_EQ) {
relver = 0;
}
@@ -647,11 +653,11 @@ unsigned search_ent(struct FCB *fcb,
/* Now loop through the records seeing which match our spec... */
while (TRUE) { /* dr records within block */
- register char *nr = (char *) dr + VMSWORD(dr->dir$size) + 2;
+ register char *nr = (char *) dr + F11WORD(dr->dir$w_size) + 2;
if (nr >= buffer + BLOCKSIZE) break;
- if (dr->dir$name + dr->dir$namecount >= nr) break;
- cmp = name_match(searchspec,searchlen,dr->dir$name,
- dr->dir$namecount);
+ if (dr->dir$t_name + dr->dir$b_namecount >= nr) break;
+ cmp = name_match(searchspec,searchlen,dr->dir$t_name,
+ dr->dir$b_namecount);
if (cmp == MAT_GT && wcc_flag) {
wcc_flag = FALSE;
searchspec = filedsc->dsc_a_pointer;
@@ -660,12 +666,12 @@ unsigned search_ent(struct FCB *fcb,
if (!(sts & STS$M_SUCCESS)) break;
} else {
if (cmp == MAT_EQ) {
- register struct dir$ent *de;
- de = (struct dir$ent *)
- (dr->dir$name +
- ((dr->dir$namecount + 1) & ~1));
- if (version == 0 && action == 2) {
- version = VMSWORD(de->dir$version) + 1;
+ register struct dir$r_ent *de;
+ de = (struct dir$r_ent *)
+ (dr->dir$t_name +
+ ((dr->dir$b_namecount + 1) & ~1));
+ if (version == 0 && action == DIRECT_CREATE) {
+ version = F11WORD(de->dir$w_version) + 1;
if (version > 32767) {
sts = SS$_BADFILENAME;
break;
@@ -679,12 +685,12 @@ unsigned search_ent(struct FCB *fcb,
while ((char *) de < nr) {
if ((version < 1) ?
(relver > version) :
- (version < VMSWORD(de->dir$version))) {
+ (version < F11WORD(de->dir$w_version))) {
relver--;
de++;
} else {
if (version > 32767 || version == relver ||
- version == VMSWORD(de->dir$version)) {
+ version == F11WORD(de->dir$w_version)) {
cmp = MAT_EQ;
} else {
cmp = MAT_GT;
@@ -694,14 +700,15 @@ unsigned search_ent(struct FCB *fcb,
} else {
wcc_flag = FALSE;
searchspec = filedsc->dsc_a_pointer;
- sts = name_check(searchspec,
- filedsc->dsc_w_length,
- &searchlen,&version,
- &wildcard);
- if (!(sts & STS$M_SUCCESS)) break;
+ sts = name_check( searchspec,
+ filedsc->dsc_w_length,
+ &searchlen,&version,
+ &wildcard );
+ if( !(sts & STS$M_SUCCESS) )
+ break;
if (name_match(searchspec,searchlen,
- dr->dir$name,
- dr->dir$namecount) !=
+ dr->dir$t_name,
+ dr->dir$b_namecount) !=
MAT_EQ) {
cmp = MAT_NE;
break;
@@ -725,23 +732,25 @@ unsigned search_ent(struct FCB *fcb,
if (cmp == MAT_EQ) {
switch (action) {
- case 0:
- return return_ent(fcb,vioc,curblk,dr,de,fib,
- reslen,resdsc,wildcard);
- case 1:
- return delete_ent(fcb,vioc,curblk,dr,de,
- buffer,eofblk);
- default:
- sts = SS$_DUPFILENAME;
- break;
+ case DIRECT_FIND:
+ return return_ent( fcb, vioc, curblk, dr, de, fib,
+ reslen, resdsc, wildcard );
+ case DIRECT_DELETE:
+ return delete_ent( fcb, vioc, curblk, dr, de,
+ buffer, eofblk );
+ case DIRECT_CREATE:
+ sts = SS$_DUPFILENAME;
+ break;
+ default:
+ abort();
}
} else {
- if (cmp != MAT_NE && action == 2) {
- return insert_ent(fcb,eofblk,curblk,vioc,buffer,
- dr,de,searchspec,searchlen,
- version,
- (struct fiddef *)
- &fib->fib$w_fid_num);
+ if( cmp != MAT_NE && action == DIRECT_CREATE ) {
+ return insert_ent( fcb, eofblk, curblk, vioc, buffer,
+ dr, de, searchspec, searchlen,
+ version,
+ (struct fiddef *)
+ &fib->fib$w_fid_num);
}
}
}
@@ -753,23 +762,23 @@ unsigned search_ent(struct FCB *fcb,
so that if it continues into the next block we can get
the relative version right! Sigh! */
- if (VMSWORD(((struct dir$rec *) nr)->dir$size) > MAXREC) {
- last_len = dr->dir$namecount;
+ if (F11WORD(((struct dir$r_rec *) nr)->dir$w_size) > MAXREC) {
+ last_len = dr->dir$b_namecount;
if (last_len > sizeof(last_name)) {
last_len = sizeof(last_name);
}
- memcpy(last_name,dr->dir$name,last_len);
- dr = (struct dir$rec *) nr;
+ memcpy(last_name,dr->dir$t_name,last_len);
+ dr = (struct dir$r_rec *) nr;
break;
}
- dr = (struct dir$rec *) nr;
+ dr = (struct dir$r_rec *) nr;
}
}
/* Release the buffer ready to get the next one - unless it is the
last one in which case we can't defer an insert any longer!! */
- if (!(sts & STS$M_SUCCESS) || action != 2 ||
+ if (!(sts & STS$M_SUCCESS) || action != DIRECT_CREATE ||
(cmp != MAT_GT && curblk < eofblk)) {
register unsigned dests = deaccesschunk(vioc,0,0,TRUE);
if (!(dests & STS$M_SUCCESS)) {
@@ -805,7 +814,8 @@ unsigned search_ent(struct FCB *fcb,
/* direct() - this routine handles all directory manipulations:-
action 0 - find directory entry
1 - delete entry
- 2 - create an entry */
+ 2 - create an entry
+ */
unsigned direct(struct VCB * vcb,struct dsc_descriptor * fibdsc,
struct dsc_descriptor * filedsc,unsigned short *reslen,
@@ -814,11 +824,11 @@ unsigned direct(struct VCB * vcb,struct dsc_descriptor * fibdsc,
struct FCB *fcb;
register unsigned sts,eofblk;
register struct fibdef *fib = (struct fibdef *) fibdsc->dsc_a_pointer;
- sts = accessfile(vcb,(struct fiddef *) & fib->fib$w_did_num,&fcb,action);
+ sts = accessfile(vcb,(struct fiddef *) &fib->fib$w_did_num, &fcb, (action != DIRECT_FIND) );
if (sts & STS$M_SUCCESS) {
- if (VMSLONG(fcb->head->fh2$l_filechar) & FH2$M_DIRECTORY) {
- eofblk = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
- if (VMSWORD(fcb->head->fh2$w_recattr.fat$w_ffbyte) == 0) --eofblk;
+ if (F11LONG(fcb->head->fh2$l_filechar) & FH2$M_DIRECTORY) {
+ eofblk = F11SWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
+ if (F11WORD(fcb->head->fh2$w_recattr.fat$w_ffbyte) == 0) --eofblk;
sts = search_ent(fcb,fibdsc,filedsc,reslen,resdsc,eofblk,action);
} else {
sts = SS$_BADIRECTORY;
diff --git a/extracters/ods2/direct.h b/extracters/ods2/direct.h
index 2706388..b62e324 100644
--- a/extracters/ods2/direct.h
+++ b/extracters/ods2/direct.h
@@ -1,4 +1,4 @@
-/* Direct.h V2.1 Definitions for directory access routines */
+/* Direct.h Definitions for directory access routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -13,23 +13,19 @@
#ifndef _DIRECT_H
#define _DIRECT_H
-struct dir$rec {
- vmsword dir$size;
- vmsword dir$verlimit;
- vmsbyte dir$flags;
- vmsbyte dir$namecount;
- char dir$name[1];
-};
-
-struct dir$ent {
- vmsword dir$version;
- struct fiddef dir$fid;
-};
-
+#include "access.h"
+#include "descrip.h"
+#include "f11def.h"
void direct_show( void );
unsigned direct(struct VCB *vcb,struct dsc_descriptor *fibdsc,
struct dsc_descriptor *filedsc,unsigned short *reslen,
struct dsc_descriptor *resdsc,unsigned action);
+#define DIRECT_FIND 0
+#define DIRECT_DELETE 1
+#define DIRECT_CREATE 2
+
+#define MODIFIES(action) (action != DIRECT_FIND)
+
#endif /* #ifndef _DIRECT_H */
diff --git a/extracters/ods2/dismountcmd.c b/extracters/ods2/dismountcmd.c
new file mode 100644
index 0000000..76e24f7
--- /dev/null
+++ b/extracters/ods2/dismountcmd.c
@@ -0,0 +1,49 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_DISMOUNTCMD )
+#define DEBUG DEBUG_DISMOUNTCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#include "access.h"
+#include "device.h"
+
+/******************************************************************* dodismount() */
+
+param_t dmopars[] = { {"drive_letter", REQ, STRING, NOPA, "Drive containing volume to dismount", },
+ {NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(dismount) {
+ struct DEV *dev;
+ int sts;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ sts = device_lookup( strlen(argv[1]), argv[1], FALSE, &dev );
+ if( sts & STS$M_SUCCESS ) {
+ device_done( dev );
+ if( dev->vcb != NULL ) {
+ sts = dismount( dev->vcb );
+ } else {
+ sts = SS$_DEVNOTMOUNT;
+ }
+ }
+ if( !(sts & STS$M_SUCCESS) )
+ printf("%%DISMOUNT-E-STATUS Error: %s\n",getmsg(sts, MSG_TEXT));
+ return sts;
+}
diff --git a/extracters/ods2/extendcmd.c b/extracters/ods2/extendcmd.c
new file mode 100644
index 0000000..9b9c433
--- /dev/null
+++ b/extracters/ods2/extendcmd.c
@@ -0,0 +1,50 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_EXTENDCMD )
+#define DEBUG DEBUG_EXTENDCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+
+/***************************************************************** doextend() */
+
+/* more test code... */
+
+param_t extendpars[] = { {"ods-2_filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(extend) {
+ int sts;
+ struct FAB fab = cc$rms_fab;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ fab.fab$b_fac = FAB$M_UPD;
+ sts = sys_open( &fab );
+ if ( sts & STS$M_SUCCESS ) {
+ fab.fab$l_alq = 32;
+ sts = sys_extend(&fab);
+ sys_close(&fab);
+ }
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ printf("%%EXTEND-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
diff --git a/extracters/ods2/f11def.h b/extracters/ods2/f11def.h
new file mode 100644
index 0000000..dcbd630
--- /dev/null
+++ b/extracters/ods2/f11def.h
@@ -0,0 +1,217 @@
+/* Access.h Definitions for file access routines */
+
+/*
+ This is part of ODS2 written by Paul Nankervis,
+ email address: Paulnank@au1.ibm.com
+
+ ODS2 is distributed freely for all members of the
+ VMS community to use. However all derived works
+ must maintain comments in their source to acknowledge
+ the contibution of the original author.
+*/
+
+#ifndef _F11DEF_H
+#define _F11DEF_H
+
+#include
+
+#include "vmstime.h"
+
+#ifndef ODS2_BIG_ENDIAN
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define ODS2_BIG_ENDIAN 1
+#endif
+#else
+#if defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)
+#define ODS2_BIG_ENDIAN 1
+#endif
+#endif
+#endif
+
+#ifdef ODS2_BIG_ENDIAN
+#define F11LONG( l ) ( ( (l) & 0x000000ff ) << 24 | \
+ ( (l) & 0x0000ff00 ) << 8 | \
+ ( (l) & 0x00ff0000 ) >> 8 | \
+ (l) >> 24 )
+#define F11WORD( w ) ( ( (w) & 0x00ff ) << 8 | \
+ (w) >> 8 )
+#define F11SWAP( l ) ( ( (l) & 0x00ff0000 ) << 8 | \
+ ( (l) & 0xff000000 ) >> 8 | \
+ ( (l) & 0x000000ff ) << 8 | \
+ ( (l) & 0x0000ff00 ) >> 8 )
+#else
+#define F11LONG( l ) (l)
+#define F11WORD( w ) (w)
+#define F11SWAP( l ) ( ( (l) & 0x0000ffff ) << 16 | \
+ (l) >> 16 )
+#endif
+
+typedef uint8_t f11byte;
+typedef uint16_t f11word;
+typedef uint32_t f11swap;
+typedef uint32_t f11long;
+
+#define FH2$M_NOBACKUP 0x00002
+#define FH2$M_CONTIGB 0x00020
+#define FH2$M_CONTIG 0x00080
+#define FH2$M_DIRECTORY 0x02000
+#define FH2$M_MARKDEL 0x08000
+#define FH2$M_ERASE 0x20000
+
+#ifdef __ALPHA
+#pragma member_alignment save
+#pragma nomember_alignment
+#endif
+
+struct UIC {
+ f11word uic$w_mem;
+ f11word uic$w_grp;
+};
+
+struct fiddef {
+ f11word fid$w_num;
+ f11word fid$w_seq;
+ f11byte fid$b_rvn;
+ f11byte fid$b_nmx;
+};
+
+struct RECATTR {
+ f11byte fat$b_rtype;
+ f11byte fat$b_rattrib;
+ f11word fat$w_rsize;
+ f11swap fat$l_hiblk;
+ f11swap fat$l_efblk;
+ f11word fat$w_ffbyte;
+ f11byte fat$b_bktsize;
+ f11byte fat$b_vfcsize;
+ f11word fat$w_maxrec;
+ f11word fat$w_defext;
+ f11word fat$w_gbc;
+ f11byte fat$_UU0[8];
+ f11word fat$w_versions;
+};
+
+struct HOME {
+ f11long hm2$l_homelbn;
+ f11long hm2$l_alhomelbn;
+ f11long hm2$l_altidxlbn;
+ f11word hm2$w_struclev;
+ f11word hm2$w_cluster;
+ f11word hm2$w_homevbn;
+ f11word hm2$w_alhomevbn;
+ f11word hm2$w_altidxvbn;
+ f11word hm2$w_ibmapvbn;
+ f11long hm2$l_ibmaplbn;
+ f11long hm2$l_maxfiles;
+ f11word hm2$w_ibmapsize;
+ f11word hm2$w_resfiles;
+ f11word hm2$w_devtype;
+ f11word hm2$w_rvn;
+ f11word hm2$w_setcount;
+ f11word hm2$w_volchar;
+ struct UIC hm2$w_volowner;
+ f11long hm2$l_reserved1;
+ f11word hm2$w_protect;
+ f11word hm2$w_fileprot;
+ f11word hm2$w_reserved2;
+ f11word hm2$w_checksum1;
+ VMSTIME hm2$q_credate;
+ f11byte hm2$b_window;
+ f11byte hm2$b_lru_lim;
+ f11word hm2$w_extend;
+ VMSTIME hm2$q_retainmin;
+ VMSTIME hm2$q_retainmax;
+ VMSTIME hm2$q_revdate;
+ f11byte hm2$r_min_class[20];
+ f11byte hm2$r_max_class[20];
+ f11byte hm2$t_reserved3[320];
+ f11long hm2$l_serialnum;
+ char hm2$t_strucname[12];
+ char hm2$t_volname[12];
+ char hm2$t_ownername[12];
+ char hm2$t_format[12];
+ f11word hm2$w_reserved4;
+ f11word hm2$w_checksum2;
+};
+
+struct IDENT {
+ char fi2$t_filename[20];
+ f11word fi2$w_revision;
+ VMSTIME fi2$q_credate;
+ VMSTIME fi2$q_revdate;
+ VMSTIME fi2$q_expdate;
+ VMSTIME fi2$q_bakdate;
+ char fi2$t_filenamext[66];
+};
+
+struct HEAD {
+ f11byte fh2$b_idoffset;
+ f11byte fh2$b_mpoffset;
+ f11byte fh2$b_acoffset;
+ f11byte fh2$b_rsoffset;
+ f11word fh2$w_seg_num;
+ f11word fh2$w_struclev;
+ struct fiddef fh2$w_fid;
+ struct fiddef fh2$w_ext_fid;
+ struct RECATTR fh2$w_recattr;
+ f11long fh2$l_filechar;
+ f11word fh2$w_reserved1;
+ f11byte fh2$b_map_inuse;
+ f11byte fh2$b_acc_mode;
+ struct UIC fh2$l_fileowner;
+ f11word fh2$w_fileprot;
+ struct fiddef fh2$w_backlink;
+ f11byte fh2$b_journal;
+ f11byte fh2$b_ru_active;
+ f11word fh2$w_reserved2;
+ f11long fh2$l_highwater;
+ f11byte fh2$b_reserved3[8];
+ f11byte fh2$r_class_prot[20];
+ f11byte fh2$r_restofit[402];
+ f11word fh2$w_checksum;
+};
+
+struct SCB {
+ f11word scb$w_struclev;
+ f11word scb$w_cluster;
+ f11long scb$l_volsize;
+ f11long scb$l_blksize;
+ f11long scb$l_sectors;
+ f11long scb$l_tracks;
+ f11long scb$l_cylinders;
+ f11long scb$l_status;
+ f11long scb$l_status2;
+ f11word scb$w_writecnt;
+ char scb$t_volockname[12];
+ VMSTIME scb$q_mounttime;
+ f11word scb$w_backrev;
+ f11long scb$q_genernum[2];
+ char scb$b_reserved[446];
+ f11word scb$w_checksum;
+};
+
+struct VOLSETREC {
+ char vsr$t_label[12];
+ char vsr$b_reserved[52];
+};
+
+struct dir$r_rec {
+ f11word dir$w_size;
+ f11word dir$w_verlimit;
+ f11byte dir$b_flags;
+ f11byte dir$b_namecount;
+ char dir$t_name[1];
+};
+
+struct dir$r_ent {
+ f11word dir$w_version;
+ struct fiddef dir$w_fid;
+};
+
+
+#ifdef __ALPHA
+#pragma member_alignment restore
+#endif
+
+#endif
diff --git a/extracters/ods2/fibdef.h b/extracters/ods2/fibdef.h
index 99402fe..d3b7bd7 100644
--- a/extracters/ods2/fibdef.h
+++ b/extracters/ods2/fibdef.h
@@ -1,4 +1,4 @@
-/* Fibdef.h V2.1 Definition of 'struct fibdef' */
+/* Fibdef.h Definition of 'struct fibdef' */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -29,6 +29,7 @@ struct fibdef {
unsigned fib$w_nmctl;
unsigned fib$l_exsz;
unsigned fib$w_exctl;
+ unsigned short fib$w_verlimit;
};
#endif /* #ifndef _FIBDEF_H */
diff --git a/extracters/ods2/helpcmd.c b/extracters/ods2/helpcmd.c
new file mode 100644
index 0000000..646d9b7
--- /dev/null
+++ b/extracters/ods2/helpcmd.c
@@ -0,0 +1,344 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_HELPCMD )
+#define DEBUG DEBUG_HELPCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+extern void mounthelp(void);
+
+extern CMDSET_t maincmds[];
+extern void show_version( void );
+
+static void cmdhelp( CMDSETp_t cmdset );
+static void parhelp( CMDSETp_t cmd, int argc, char **argv );
+static void qualhelp( int par, qualp_t qtable );
+
+static int cmdcmp( const void *qa, const void *qb );
+static int qualcmp( const void *qa, const void *qb );
+
+/******************************************************************* dohelp() */
+
+/* help: Display help guided by command table. */
+
+param_t helppars[] = { {"command", OPT, CMDNAM, PA(maincmds), "" },
+ {"parameter", OPT, STRING, NOPA, "" },
+ {"value", OPT, STRING, NOPA, "" },
+ {NULL, 0, 0, NOPA, NULL },
+};
+
+DECL_CMD(help) {
+ CMDSETp_t cmd;
+
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ if( argc <= 1 ) {
+ show_version();
+
+ printf( " The orginal version of ods2 was developed by Paul Nankervis\n" );
+ printf( " \n" );
+ printf( " This modified version was developed by Timothe Litt, and\n" );
+ printf( " incorporates significant previous modifications by Larry \n" );
+ printf( " Baker of the USGS and by Hunter Goatley\n" );
+ printf("\n Please send problems/comments to litt@ieee.org\n\n");
+
+ printf(" Commands are:\n");
+ cmdhelp( maincmds );
+ printf( "\n Type HELP COMMAND for information on any command.\n" );
+ return 1;
+ }
+
+ for( cmd = maincmds; cmd->name; cmd++ ) {
+ if( keycomp(argv[1],cmd->name) ) {
+ if( argc >= 3 ) {
+ parhelp( cmd, argc-2, argv+2 );
+ return 1;
+ }
+ if( cmd->helpstr == NULL ) {
+ printf( "%s: No help available\n",cmd->name );
+ } else {
+ printf( "%s: %s\n",cmd->name,cmd->helpstr );
+ }
+ if( cmd->validquals != NULL )
+ qualhelp( 0, cmd->validquals );
+ if( cmd->params != NULL )
+ parhelp( cmd, 0, NULL );
+ if( strcmp(cmd->name, "mount") == 0 )
+ mounthelp();
+ return 1;
+ }
+ }
+ printf( "%s: command not found\n", argv[1] );
+ return 0;
+}
+
+/*********************************************************** cmdhelp() */
+
+static void cmdhelp( CMDSETp_t cmdset ) {
+ CMDSETp_t cmd;
+ int n = 0;
+ size_t max = 0;
+
+ for( cmd = cmdset; cmd->name != NULL; cmd++ ) {
+ if( strlen(cmd->name) > max )
+ max = strlen(cmd->name);
+ }
+ qsort( cmdset, (size_t)(cmd - cmdset), sizeof( CMDSET_t ), cmdcmp );
+
+ for( cmd = cmdset; cmd->name; cmd++ ) {
+ if( cmd->helpstr == NULL )
+ continue;
+ if( n++ % 4 == 0 )
+ printf( "\n" );
+ printf(" %-*s", (int)max,cmd->name );
+ }
+ printf( "\n" );
+}
+
+/*********************************************************** parhelp() */
+
+static void parhelp( CMDSETp_t cmd, int argc, char **argv ) {
+ paramp_t p;
+ paramp_t ptable;
+ const char *footer = NULL;
+
+ ptable = cmd->params;
+
+ if( ptable == NULL ) {
+ printf( "%s has no parameters\n", cmd->name );
+ return;
+ }
+
+ if( argc == 0 ) {
+ int col = 0;
+ size_t max = 0;
+
+ for( p = ptable; p->name != NULL; p++ ) {
+ if( p->helpstr ) {
+ size_t len = strlen(p->name);
+ if( len > max )
+ max = len;
+ }
+ }
+ for( p = ptable; p->name != NULL; p++ ) {
+ if( p->helpstr ) {
+ size_t len = strlen(p->name);
+ if( !col ) {
+ printf( " Parameters:\n " );
+ col = 4;
+ } else {
+ if( 1+col + len > 80 ) {
+ printf( "\n " );
+ col = 4;
+ } else {
+ printf ( " " );
+ col++;
+ }
+ }
+ printf( "%-*s", (int)max, p->name );
+ col += len;
+ }
+ }
+ printf( "\n\n Type help %s PARAMETER for more about each parameter.\n",
+ cmd->name );
+ return;
+ }
+
+ for( p = ptable; p->name != NULL; p++ ) {
+ if( keycomp( argv[0], p->name ) )
+ break;
+ }
+ if( p->name == NULL ) {
+ printf( "No parameter '%s' found\n", argv[0] );
+ return;
+ }
+ if( p->hlpfnc != NULL )
+ footer = (*p->hlpfnc)(cmd, p, argc, argv);
+ if( p->ptype == NONE ) {
+ printf( "Parameter is not used for this command\n" );
+ return;
+ }
+
+ printf( " %s: ", p->name );
+
+ if( p->flags == OPT )
+ printf( "optional " );
+
+ switch( p->ptype ) {
+ case VMSFS:
+ printf( "VMS file specification %s\n", p->helpstr );
+ break;
+ case LCLFS:
+ printf( "local file specification %s\n", p->helpstr );
+ break;
+ case KEYWD:
+ printf( "%skeyword, one of the following:\n",
+ (p->helpstr == NULL? "": p->helpstr) );
+ qualhelp( 1, (qualp_t )p->arg );
+ break;
+ case LIST:
+ printf( "list, %s\n", p->helpstr );
+ break;
+ case STRING:
+ printf( "%s\n", p->helpstr );
+ break;
+ case CMDNAM:
+ printf( "command name, one of the following:\n");
+ cmdhelp( (CMDSETp_t )p->arg );
+ break;
+ default:
+ abort();
+ }
+ if( footer )
+ printf( "%s", footer );
+
+ return;
+}
+
+/*********************************************************** qualhelp() */
+
+static void qualhelp( int par, qualp_t qtable ) {
+ qualp_t q;
+ int n = 0;
+ size_t max = 0, col = 4;
+
+ if( par < 0 )
+ max = -par;
+
+#define NOSTR "[no]"
+#define NOSTR_LEN (sizeof(NOSTR)-1)
+ for( q = qtable; q->name; q++ ) {
+ if( q->helpstr ) {
+ size_t len = strlen(q->name);
+ if( *q->helpstr == '-' )
+ len += NOSTR_LEN;
+ if( q->qtype != NOVAL )
+ ++len;
+ if( q->qtype == DECVAL )
+ ++len;
+ if( len > max )
+ max = len;
+ }
+ }
+
+ if( !(q->set & OPT_NOSORT) ) {
+ qsort( qtable, (size_t)(q - qtable), sizeof( qual_t ), qualcmp );
+ }
+
+ for( q = qtable; q->name; q++ ) {
+ if( q->helpstr ) {
+ if( !n++ && !par )
+ printf( " %s:\n", "Qualifiers" );
+ printf(" %s", par? par < 0? " ": "": vms_qual? "/" : "-" );
+ if( *q->helpstr == '-' )
+ switch( q->qtype ) {
+ case NOVAL:
+ if( *q->helpstr ) {
+ printf( NOSTR "%-*s - %s\n",
+ (int) (max-NOSTR_LEN), q->name, q->helpstr+1 );
+ break;
+ }
+ if( col + max > 50 ) {
+ printf( "\n " );
+ col = 8;
+ } else {
+ while( col < 8 ) {
+ putchar( ' ' ); col++;
+ }
+ }
+ printf( "%-*s", (int) max, q->name );
+ col += max;
+ break;
+ case KEYVAL:
+ case KEYCOL:
+ printf( NOSTR "%s=%-*s - %s\n",
+ q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+1)), "",
+ q->helpstr+1 );
+ qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (qualp_t )q->arg );
+ break;
+ case DECVAL:
+ printf( NOSTR "%s=n%-*s - %s\n",
+ q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+2)), "",
+ q->helpstr+1 );
+ break;
+ case STRVAL:
+ printf( NOSTR "%s=%-*s - %s\n",
+ q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+2)), "",
+ q->helpstr+1 );
+ break;
+ default:
+ abort();
+ }
+ else
+ switch( q->qtype ) {
+ case NOVAL:
+ if( *q->helpstr ) {
+ printf("%-*s - %s\n", (int) max, q->name, q->helpstr );
+ break;
+ }
+ if( col + max > 50 ) {
+ printf( "\n " );
+ col = 8;
+ } else {
+ while( col < 8 ) {
+ putchar( ' ' ); col++;
+ }
+ }
+ printf( "%-*s", (int) max, q->name );
+ col += max;
+ break;
+ case KEYVAL:
+ case KEYCOL:
+ printf( "%s=%-*s - %s\n", q->name, (int)(max-(strlen(q->name)+1)), "",
+ q->helpstr );
+ qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (qualp_t )q->arg );
+ break;
+ case DECVAL:
+ printf( "%s=n%-*s - %s\n",
+ q->name, (int) (max-(strlen(q->name)+2)), "",
+ q->helpstr );
+ break;
+ case STRVAL:
+ printf( "%s=%-*s - %s\n",
+ q->name, (int) (max-(strlen(q->name)+1)), "",
+ q->helpstr );
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+ if( par >= 0 )
+ printf( "\n" );
+}
+#undef NOSTR
+#undef NOSTR_LEN
+
+/***************************************************************** cmdcmp() */
+
+static int cmdcmp( const void *qa, const void *qb ){
+
+ return strcmp( ((CMDSETp_t )qa)[0].name,
+ ((CMDSETp_t )qb)[0].name );
+}
+
+/***************************************************************** qualcmp() */
+
+static int qualcmp( const void *qa, const void *qb ) {
+
+ return strcmp( ((qualp_t )qa)[0].name,
+ ((qualp_t )qb)[0].name );
+}
diff --git a/extracters/ods2/importcmd.c b/extracters/ods2/importcmd.c
new file mode 100644
index 0000000..303be14
--- /dev/null
+++ b/extracters/ods2/importcmd.c
@@ -0,0 +1,119 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_IMPORTCMD )
+#define DEBUG DEBUG_IMPORTCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+
+/***************************************************************** doimport() */
+
+#define import_binary OPT_GENERIC_1
+#define import_log OPT_GENERIC_2
+
+qual_t importquals[] = { {"ascii", 0, import_binary, NV,
+ "Transfer file in ascii mode (default)"},
+ {"binary", import_binary, 0, NV, "Transfer file in binary mode", },
+ {NULL, 0, 0, NV, NULL}
+};
+param_t importpars[] = { {"from_filespec", REQ, LCLFS, NOPA, "for source file."},
+ {"to_filespec", REQ, VMSFS, NOPA, "for destination file."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(import) {
+ int options;
+ unsigned sts;
+ char *name;
+ FILE *fromf;
+ struct FAB fab = cc$rms_fab;
+ struct RAB rab = cc$rms_rab;
+
+ UNUSED(argc);
+
+ options = checkquals( 0, importquals, qualc, qualv );
+ if( options == -1 )
+ return SS$_BADPARAM;
+
+ sts = SS$_BADFILENAME;
+ name = argv[1]; /*unquote( argv[1] );*/
+ if ( *name == '\0' ) {
+ return sts;
+ }
+ fromf = openf( name, (options & import_binary)? "rb": "r" );
+ if( fromf == NULL ) {
+ printf( "%%ODS2-E-OPENERR, Can't open %s\n", name );
+ perror( " - " );
+ return sts;
+ }
+ fab.fab$b_fac = FAB$M_PUT;
+ fab.fab$l_fop = FAB$M_OFP | FAB$M_TEF;
+ fab.fab$b_org = FAB$C_SEQ;
+ if( options & import_binary ) {
+ fab.fab$w_mrs = 512;
+ fab.fab$b_rfm = FAB$C_FIX;
+ } else {
+ fab.fab$b_rat = 0;
+ fab.fab$b_rfm = FAB$C_STM;
+ }
+
+ fab.fab$l_fna = argv[2];
+ fab.fab$b_fns = strlen( fab.fab$l_fna );
+ sts = sys_create( &fab );
+ if ( sts & STS$M_SUCCESS ) {
+ rab.rab$l_fab = &fab;
+ sts = sys_connect( &rab );
+ if ( sts & STS$M_SUCCESS ) {
+ if( options & import_binary ) {
+ char *buf;
+ size_t len;
+
+ if( (buf = malloc( 512 )) == NULL )
+ sts = SS$_INSFMEM;
+ else {
+ rab.rab$l_rbf = buf;
+ while( (len = fread( buf, 1, 512, fromf )) > 0 ) {
+ if( len != 512 )
+ memset( buf + len, 0, 512 - len );
+ rab.rab$w_rsz = len;
+ sts = sys_put( &rab );
+ if( !(sts & STS$M_SUCCESS) ) {
+ break;
+ }
+ }
+ free( buf );
+ buf = NULL;
+ }
+ } else {
+ while ( (rab.rab$l_rbf = fgetline( fromf, TRUE )) != NULL ) {
+ rab.rab$w_rsz = strlen( rab.rab$l_rbf );
+ sts = sys_put( &rab );
+ free( rab.rab$l_rbf );
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ break;
+ }
+ }
+ }
+ sys_disconnect( &rab );
+ }
+ sys_close( &fab );
+ }
+ fclose( fromf );
+ if ( !(sts & STS$M_SUCCESS) ) {
+ printf("%%IMPORT-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+
+ return sts;
+}
diff --git a/extracters/ods2/initialcmd.c b/extracters/ods2/initialcmd.c
new file mode 100644
index 0000000..f680417
--- /dev/null
+++ b/extracters/ods2/initialcmd.c
@@ -0,0 +1,161 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_INITIALCMD )
+#define DEBUG DEBUG_INITIALCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#include "access.h"
+#include "device.h"
+#include "initvol.h"
+#include "phyvirt.h"
+
+/******************************************************************* doinitial() */
+
+static struct NEWVOL initpars;
+
+#define init_beg OPT_GENERIC_1
+#define init_mid OPT_GENERIC_2
+#define init_blk OPT_GENERIC_3
+#define init_mount OPT_GENERIC_4
+
+qual_t idxkwds[] = { {"beginning", init_beg, init_mid|init_blk, NV,
+ "Place index file in lowest available LBNs"},
+ {"block", init_blk, init_beg|init_mid, DV(&initpars.indexlbn),
+ "Place index file near specific LBN"},
+ {"middle", init_mid, init_beg|init_blk, NV,
+ "Place index file near middle of volume (default)"},
+ {NULL, 0, 0, NV, NULL}
+};
+
+qual_t iniquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "},
+ {"cluster_size", 0, 0, DV(&initpars.clustersize),
+ "Cluster size (blocks)" },
+ {"create", PHY_CREATE|MOU_VIRTUAL, 0, NV, "Create a new image file" },
+ {"directories", 0, 0, DV(&initpars.directories),
+ "Directory entries to pre-allocate" },
+ {"headers", 0, 0, DV(&initpars.headers),
+ "File headers to pre-allocate" },
+ {"index", 0, init_beg|init_mid|init_blk, KV(idxkwds),
+ "Index file placement hint"},
+ {"image", PHY_CREATE|MOU_VIRTUAL, 0, NV,
+ "Initialize a disk image file", },
+ {"log", MOU_LOG, 0, NV, "-Show progress"},
+ {"nolog", 0, MOU_LOG, NV, NULL},
+ {"replace", MOU_VIRTUAL, PHY_CREATE, NV,
+ "Replace filesystem in existing image file" },
+ {"mount", init_mount, 0, NV, "-Mount volume after initializing it"},
+ {"nomount", 0, init_mount, NV, NULL },
+ {"virtual", PHY_CREATE|MOU_VIRTUAL, 0, NV, NULL, },
+ {"maximum_files", 0, 0, DV(&initpars.maxfiles),
+ "Maximum number of files volume can (ever) contain" },
+ {"owner_uic", 0, 0, SV(&initpars.useruic),
+ "Volume owner's UIC, default [1,1]"},
+ {"user_name", 0, 0, SV(&initpars.username),
+ "Volume owner's username, default yours"},
+ {NULL, 0, 0, NV, NULL } };
+
+param_t inipars[] = { {"device", REQ, LCLFS, NOPA,
+ "for device or disk image to be initialized.\n "
+ "ALL EXISTING DATA WILL BE LOST."
+ },
+ {"labels", REQ, LCLFS, NOPA, "volume label for new volume" },
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(initial) {
+ int sts = SS$_NORMAL;
+ char *devname = NULL;
+ size_t len;
+ struct DEV *dev;
+ int options;
+
+ UNUSED(argc);
+
+ devname = argv[1];
+
+ options = checkquals( PHY_CREATE | init_mid | init_mount, iniquals, qualc, qualv );
+ do {
+
+ if( options == -1 ) {
+ sts = SS$_BADPARAM;
+ break;
+ }
+ options |= MOU_WRITE;
+ if( !(options & MOU_VIRTUAL) )
+ options &= ~PHY_CREATE;
+
+ if( options & init_mid )
+ initpars.indexlbn = INIT_INDEX_MIDDLE;
+ if( options & init_beg )
+ initpars.indexlbn = 0;
+ if( (options & init_blk) && initpars.indexlbn == INIT_INDEX_MIDDLE )
+ initpars.indexlbn--;
+
+ initpars.options = 0;
+ if( options & MOU_LOG )
+ initpars.options |= INIT_LOG;
+ if( options & MOU_VIRTUAL )
+ initpars.options |= INIT_VIRTUAL;
+
+ initpars.devtype = disktype[(options & MOU_DEVTYPE) >> MOU_V_DEVTYPE].name;
+
+ len = strlen( argv[2] );
+ if( len > 12 || !*argv[2] ||
+ strspn( argv[2], VOL_ALPHABET ) != len ) {
+ printf( "Volume label must be between 1 and 12 alphanumeric characters long\n" );
+ sts = SS$_BADPARAM;
+ break;
+ }
+ initpars.label = argv[2];
+
+ if( !((sts = virt_open( &devname, options, &dev )) & STS$M_SUCCESS) )
+ break;
+
+ if( !(dev->access & MOU_WRITE) ) {
+ sts = SS$_WRITLCK;
+ virt_close( dev );
+ break;
+ }
+ initpars.devnam = devname;
+ if( !((sts = initvol( dev, &initpars )) & STS$M_SUCCESS) ) {
+ virt_close( dev );
+ break;
+ }
+ if( !((sts = virt_close( dev )) & STS$M_SUCCESS) )
+ break;
+
+ if( options & init_mount ) {
+ sts = mount( (options & (MOU_VIRTUAL|MOU_DEVTYPE|MOU_WRITE)) | MOU_LOG,
+ 1, argv+1, argv+2 );
+ }
+ } while( 0 );
+
+ initpars.username =
+ initpars.useruic = NULL;
+
+ if( sts & STS$M_SUCCESS )
+ return sts;
+
+ printf( "%%ODS2-E-FAILED, Initialize failed: %s\n", getmsg( sts, MSG_TEXT ) );
+
+ if( (options & (MOU_VIRTUAL|PHY_CREATE)) == (MOU_VIRTUAL|PHY_CREATE) &&
+ !( (sts & STS$M_COND_ID) == (SS$_DUPFILENAME & STS$M_COND_ID) ||
+ (sts & STS$M_COND_ID) == (SS$_IVDEVNAM & STS$M_COND_ID) ) ) {
+ (void) unlink( argv[1] );
+ }
+
+ return sts;
+}
diff --git a/extracters/ods2/initvol.c b/extracters/ods2/initvol.c
new file mode 100644
index 0000000..01caa13
--- /dev/null
+++ b/extracters/ods2/initvol.c
@@ -0,0 +1,1264 @@
+/* Initialize a FILES-11 volume */
+
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_INITVOL )
+#define DEBUG DEBUG_INITVOL
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "compat.h"
+
+#include "f11def.h"
+#include "initvol.h"
+#include "ods2.h"
+#include "phyvirt.h"
+#include "rms.h"
+#include "stsdef.h"
+#include "vmstime.h"
+
+#define bootlbn 0
+
+#define STRUCLEV (0x0201)
+#define FM2$M_FORMAT1 (1 << 14)
+#define FM2$M_FORMAT2 (2 << 14)
+#define FM2$M_FORMAT3 (3 << 14)
+#define FM2$C_FMT1_MAXLBN ((1 << 22) - 1)
+#define FM2$C_FMT1_MAXCNT (256)
+#define FM2$C_FMT2_MAXLBN (0xFFFFFFFF)
+#define FM2$C_FMT2_MAXCNT (1 << 14)
+#define FM2$C_FMT3_MAXCNT (1 << 30)
+
+#define CLUSTERS(lbns) ( ((lbns) + clustersize - 1) / clustersize )
+#define CLU2LBN(cluster) ( (cluster) * clustersize )
+
+#if DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+static unsigned add2dir( void *mfdp, unsigned *mfdlen, unsigned mfdblocks,
+ struct HEAD *head );
+
+static unsigned add2map( struct NEWVOL *params, struct HEAD *fhd,
+ unsigned start, unsigned n );
+
+static unsigned writeHEAD( void *dev, struct HEAD *head, unsigned hdrbase ) ;
+static unsigned writeHDR( void *dev, struct HEAD *head, unsigned lbn );
+static unsigned writeHOM( void *dev,
+ struct HOME *hom,
+ unsigned homlbn, unsigned homvbn,
+ unsigned ncopies );
+static unsigned alloclbns( unsigned char *bitmap,
+ unsigned clustersize,
+ unsigned n_clusters,
+ unsigned startlbn, unsigned n,
+ unsigned *found );
+static int tstlbnbit( struct NEWVOL *params, unsigned char *bitmap, unsigned lbn );
+static void modlbnbits( struct NEWVOL *params, unsigned char *bitmap, int set, unsigned start, unsigned n );
+static void modbits( unsigned char *bitmap, int set, unsigned start, unsigned n );
+static f11word checksum( void *data, size_t length );
+#if 0
+static unsigned int delta_from_name( const char *diskname );
+#endif
+static unsigned int compute_delta( unsigned long sectorsize,
+ unsigned long sectors,
+ unsigned long tracks,
+ unsigned long cylinders );
+
+static void *Malloc( void ***list, size_t size );
+static void *Calloc( void ***list, size_t nmemb, size_t n );
+#define MALLOC(name, size) do { \
+ if( (name = Malloc( size )) == NULL ) \
+ return SS$_INSFMEM; \
+ } while( 0 )
+#define CALLOC(name, nmemb, n) do { \
+ if( (name = Calloc( nmemb, n )) == NULL ) \
+ return SS$_INSFMEM; \
+ } while( 0 )
+
+unsigned eofmark = 0;
+
+#define WRITE(dev, lbn, n, buf) do { \
+ unsigned status; \
+ \
+ if( !((status = virt_write( dev, (lbn), ((n)*512), (char *)(buf) )) & STS$M_SUCCESS) ) \
+ return status; \
+ if( ( (lbn) + (n) ) > eofmark ) \
+ eofmark = (lbn) + (n) -1; \
+ } while( 0 );
+
+#define WRITEP(dev, pbn, n, buf) do { \
+ unsigned status; \
+ \
+ if( !((status = virt_writep( dev, (pbn), ((n)*dp->sectorsize), (char *)(buf) )) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 );
+
+#define READ(dev, lbn, n, buf) do { \
+ unsigned status; \
+ \
+ if( !((status = virt_read( dev, (lbn), ((n)*512), (char *)(buf) )) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 );
+
+#define READP(dev, pbn, n, buf) do { \
+ unsigned status; \
+ \
+ if( !((status = virt_readp( dev, (pbn), ((n)*dp->sectorsize), (char *)(buf) )) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 );
+
+static unsigned doinit( void ***memlist, void *dev, struct NEWVOL *params );
+
+static uint16_t bootcode[] = { /* EHPLI M'T ARPPDEI SNDI E ADP-P11 */
+ 000240, 012706, 001000, 010700, 062700, 000036, 0112001, 001403,
+ 004767, 000006, 000773, 000005, 000000, 0110137, 0177566, 0105737,
+ 0177564, 0100375, 000207, 020040, 020040, 020040, 020040, 020040,
+ 020040, 020040, 020040, 071551, 067040, 072157, 060440, 071440,
+ 071571, 062564, 020155, 064544, 065563, 005015, 000012, 000000,
+#define BOOT_LABEL_OFS 046
+#define BOOT_LABEL_SIZE 15
+};
+
+unsigned initvol( void *dev, struct NEWVOL *params ) {
+ void **memlist, **mp;
+ unsigned status;
+ memlist = (void **)calloc( 1, sizeof( void * ) );
+
+ if( params->options & INIT_LOG ) {
+ printf( "%%INIT-I-STARTING, Initializing %s on %s as %s %s\n",
+ params->label, params->devnam, params->devtype,
+ (params->options & INIT_VIRTUAL)? "disk image": "physical device" );
+ }
+
+ status = doinit( &memlist, dev, params );
+
+ for( mp = memlist; *mp != NULL; mp++ )
+ free( *mp );
+ free( memlist );
+
+ if((status & STS$M_SUCCESS) && (params->options & INIT_LOG) ) {
+ printf( "%%INIT-I-VOLINIT, %s initialized successfully\n",
+ params->label );
+ }
+
+ return status;
+}
+
+static void *Calloc( void ***list, size_t nmemb, size_t n ) {
+ void *mp;
+
+ n *= nmemb;
+ mp = Malloc( list, n );
+ if( mp == NULL )
+ return NULL;
+ memset( mp, 0, n );
+ return mp;
+}
+
+static void *Malloc( void ***memlist, size_t size ) {
+ void **mp;
+ size_t n;
+ for( n = 0, mp = *memlist; *mp != NULL; n++, mp++ )
+ ;
+ mp = realloc( *memlist, (n + 2) * sizeof( void * ) );
+ if( mp == NULL )
+ return NULL;
+ *memlist = mp;
+ mp[n] = malloc( size );
+ if( mp[n] == NULL )
+ return NULL;
+ mp[n+1] = NULL;
+ return mp[n];
+}
+#define Malloc( size ) Malloc( memlist, size )
+#define Calloc( nmemb, size ) Calloc( memlist, nmemb, size )
+
+static unsigned doinit( void ***memlist, void *dev, struct NEWVOL *params ) {
+ struct disktype *dp = NULL;
+ struct HOME *hom = NULL;
+ struct SCB *scb = NULL;
+ struct HEAD
+ *idxhead = NULL,
+ *badhead = NULL,
+ *corhead = NULL,
+ *volhead = NULL,
+ *conthead = NULL,
+ *bakhead = NULL,
+ *loghead = NULL,
+ *bmphead = NULL,
+ *mfdhead = NULL;
+ struct IDENT *ident = NULL;
+ struct BAD144 *mbad = NULL;
+ struct SWBAD *sbad = NULL;
+ unsigned status, tmp, volstart, clustersize;
+ unsigned pbs, pb_per_lb, lb_per_pb, npb, nlb, n_clusters;
+ unsigned homlbn, homvbn, hm2lbn, hm2cluster, fhlbn;
+ unsigned mfdlbn, bmplbn, idxlbn, aidxlbn;
+ const char *p = NULL;
+ unsigned char *bitmap = NULL, *indexmap = NULL;
+ unsigned bitmap_size, indexmap_size;
+ uint16_t *bootblock = NULL;
+ time_t serial;
+ char tbuf[12+1];
+ char *mfdp = NULL;
+ unsigned mfdlen = 0, mfdblocks = 3, mfdalloc;
+ struct UIC owneruic = { 1, 1 };
+
+ if( params->username && (!params->username[0] ||
+ (tmp = strlen( params->username )) > 12 ||
+ strspn( params->username, VOL_ALPHABET ) != tmp) )
+ return SS$_BADPARAM;
+
+ if( params->useruic &&
+#ifdef _WIN32
+ sscanf_s
+#else
+ sscanf
+#endif
+ ( params->useruic, " [%ho,%ho]", &owneruic.uic$w_grp, &owneruic.uic$w_mem ) != 2 )
+ return SS$_BADPARAM;
+
+ for( dp = disktype; dp->name != NULL; dp++ ) {
+ if( !strcmp( params->devtype, dp->name ) )
+ break;
+
+ }
+ if( dp->name == NULL )
+ return SS$_BADPARAM;
+
+ pbs = dp->sectorsize;
+ pb_per_lb = (pbs < 512)? 512/pbs: 1;
+ lb_per_pb = (pbs >512)? pbs/512: 1;
+
+ npb = (dp->sectors * dp->tracks * dp->cylinders ) - dp->reserved;
+ nlb = (unsigned) ((((unsigned long long)npb) * lb_per_pb)
+ / pb_per_lb);
+
+ if( params->clustersize == 0 ) {
+ if( nlb < 50000 )
+ params->clustersize = 1;
+ else {
+ unsigned long long tmp;
+ tmp = (nlb + (255 * 4096) - 1) / (255 * 4096);
+
+ params->clustersize = (unsigned) (tmp > 3? tmp: 3);
+ }
+ }
+ tmp = nlb / 50;
+ if( tmp > 16382 )
+ tmp = 16382;
+ if( params->clustersize > tmp )
+ params->clustersize = tmp;
+
+ clustersize = params->clustersize;
+
+ if( npb < 100 || nlb < 100 || clustersize < 1 ) {
+ printf( "%%INIT-E-TOOSMALL, Device is too small to hold a useful Files-11 volume\n" );
+ return SS$_DEVICEFULL;
+ }
+
+ n_clusters = CLUSTERS( nlb );
+
+ if( params->maxfiles < 16 ) {
+ params->maxfiles = nlb / ((clustersize +1) * 2);
+ if( params->maxfiles < 16 )
+ params->maxfiles = 16;
+ }
+ tmp = nlb / (clustersize + 1 );
+ if( params->maxfiles > tmp )
+ params->maxfiles = tmp;
+
+ if( params->maxfiles > ((1 << 24) - 1) )
+ params->maxfiles = ((1 << 24) - 1);
+
+ if( params->headers < 16 )
+ params->headers = 16;
+ if( params->headers > 65500 )
+ params->headers = 65500;
+
+ if( params->headers > params->maxfiles )
+ params->headers = params->maxfiles;
+
+ if( params->directories > 16000 )
+ params->directories = 16000;
+ if( params->directories > params->maxfiles )
+ params->directories = params->maxfiles;
+ if( params->directories < 16 )
+ params->directories = 16;
+
+ mfdalloc = params->directories / 16;
+ mfdalloc = CLU2LBN( CLUSTERS( mfdalloc ) );
+ if( mfdalloc < mfdblocks )
+ mfdalloc = mfdblocks;
+
+ (void) time( &serial );
+
+ /* Create the bootblock. (This is PDP-11 code. )
+ */
+
+ CALLOC( bootblock, 256, sizeof( uint16_t ) );
+ memcpy( bootblock, bootcode, sizeof( bootcode ) );
+
+ for( p = params->label, tmp = 0; *p && tmp < BOOT_LABEL_SIZE; tmp++, p++ )
+ ((char *)bootblock)[BOOT_LABEL_OFS+tmp] = toupper(*p);
+#ifdef ODS2_BIG_ENDIAN
+ for( tmp = 0; tmp < 256; tmp++ )
+ bootblock[tmp] = F11WORD(bootblock[tmp]);
+#endif
+
+#define ALLHEAD(name) \
+ CALLOC( name, 1, sizeof(struct HEAD) )
+
+ ALLHEAD( idxhead );
+ ALLHEAD( badhead );
+ ALLHEAD( corhead );
+ ALLHEAD( volhead );
+ ALLHEAD( conthead );
+ ALLHEAD( bakhead );
+ ALLHEAD( loghead );
+ ALLHEAD( bmphead );
+ ALLHEAD( mfdhead );
+
+ CALLOC(hom, 1, sizeof( struct HOME ) );
+
+ hom->hm2$w_struclev = F11WORD( STRUCLEV );
+ hom->hm2$w_cluster = F11WORD( clustersize );
+ hom->hm2$w_resfiles = F11WORD( 9 );
+ hom->hm2$l_maxfiles = F11LONG( params->maxfiles );
+ hom->hm2$w_volowner.uic$w_grp = F11WORD( owneruic.uic$w_grp );
+ hom->hm2$w_volowner.uic$w_mem = F11WORD( owneruic.uic$w_mem );
+ hom->hm2$w_protect = F11WORD( 0 );
+ hom->hm2$w_fileprot = F11WORD( 0xFA00 );
+ hom->hm2$b_window = 7;
+ hom->hm2$b_lru_lim = 16;
+ hom->hm2$w_extend = F11WORD( 5 );
+
+ CALLOC( scb, 1, 512 );
+ scb->scb$w_cluster = F11WORD(clustersize);
+ scb->scb$w_struclev = F11WORD(STRUCLEV);
+ scb->scb$l_volsize = F11LONG(nlb);
+ scb->scb$l_blksize = F11LONG(pb_per_lb);
+ scb->scb$l_sectors = F11LONG(dp->sectors);
+ scb->scb$l_tracks = F11LONG(dp->tracks);
+ scb->scb$l_cylinders = F11LONG(dp->cylinders);
+ scb->scb$l_status = F11LONG( 0 );
+ scb->scb$l_status = F11LONG( 0 );
+ scb->scb$w_writecnt = 0;
+
+ /* If necessary, scb$t_volockname will be initialized by mount under
+ * an OS.
+ */
+
+ if( !((status = sys$gettim( scb->scb$q_mounttime )) & STS$M_SUCCESS) ) {
+ return status;
+ }
+ scb->scb$w_checksum = F11WORD(checksum((f11word *)&scb, offsetof( struct SCB, scb$w_checksum ) / 2 ) );
+
+ bitmap_size = (n_clusters + 4095) / 4096;
+
+ indexmap_size = (params->maxfiles + 4095) / 4096;
+ hom->hm2$l_maxfiles = F11LONG( params->maxfiles );
+ memcpy( hom->hm2$q_credate, scb->scb$q_mounttime, sizeof(hom->hm2$q_credate) );
+ memcpy( hom->hm2$q_revdate, scb->scb$q_mounttime, sizeof(hom->hm2$q_revdate) );
+
+ DPRINTF(("Total LBNs: %u cluster size: %u total clusters: %u, "
+ "bitmap size: %u blocks maxfiles %u index map size %u blocks\n",
+ nlb, clustersize, n_clusters, bitmap_size, params->maxfiles,
+ indexmap_size));
+
+ hom->hm2$l_serialnum = (f11long) F11LONG( serial );
+ memset( hom->hm2$t_strucname, ' ', sizeof( hom->hm2$t_strucname ) );
+ (void) snprintf( tbuf, sizeof( tbuf), "%-12.12s", params->label );
+ for( tmp = 0; tmp < sizeof( tbuf ); tmp++ )
+ tbuf[tmp] = toupper( tbuf[tmp] );
+ memcpy( hom->hm2$t_volname, tbuf, sizeof( hom->hm2$t_volname ) );
+ p = get_username();
+ (void) snprintf( tbuf, sizeof( tbuf), "%-12.12s",
+ (params->username? params->username: (p == NULL)? "": p) );
+ free( (void *)p );
+ for( tmp = 0; tmp < sizeof( tbuf ); tmp++ )
+ tbuf[tmp] = toupper( tbuf[tmp] );
+ memcpy( hom->hm2$t_ownername, tbuf, sizeof( hom->hm2$t_ownername ) );
+ (void) snprintf( tbuf, sizeof( tbuf ), "%-12.12s", "DECFILE11B" );
+ memcpy( hom->hm2$t_format, tbuf, sizeof( hom->hm2$t_format ) );
+
+ CALLOC( indexmap, 1, indexmap_size * 512 );
+
+ hom->hm2$w_ibmapsize = F11WORD( (f11word)indexmap_size );
+
+ /* Index header will be template for all other files.
+ * Index-specific settings must come after copy.
+ */
+
+ idxhead->fh2$b_idoffset = offsetof( struct HEAD, fh2$r_restofit ) / 2;
+ idxhead->fh2$b_acoffset = offsetof( struct HEAD, fh2$w_checksum ) / 2;
+ idxhead->fh2$b_rsoffset = offsetof( struct HEAD, fh2$w_checksum ) / 2;
+
+ idxhead->fh2$w_seg_num = F11WORD( 0 );
+ idxhead->fh2$w_struclev = F11WORD( STRUCLEV );
+
+ idxhead->fh2$w_fid.fid$b_rvn = 0;
+ idxhead->fh2$w_fid.fid$b_nmx = 0;
+ idxhead->fh2$w_ext_fid.fid$w_num = F11WORD( 0 );
+ idxhead->fh2$w_ext_fid.fid$w_seq = F11WORD( 0 );
+ idxhead->fh2$w_ext_fid.fid$b_rvn = 0;
+ idxhead->fh2$w_ext_fid.fid$b_nmx = 0;
+
+ idxhead->fh2$w_recattr.fat$l_hiblk = F11LONG( 0 );
+ idxhead->fh2$w_recattr.fat$l_efblk = F11LONG( 0 );
+ idxhead->fh2$w_recattr.fat$w_ffbyte = F11WORD( 0 );
+ idxhead->fh2$w_recattr.fat$b_bktsize = 0;
+ idxhead->fh2$w_recattr.fat$b_vfcsize = 0;
+ idxhead->fh2$w_recattr.fat$w_defext = F11WORD( 0 );
+ idxhead->fh2$w_recattr.fat$w_gbc = F11WORD( 0 );
+ idxhead->fh2$w_recattr.fat$w_versions = F11WORD( 0 );
+ idxhead->fh2$l_filechar = F11LONG( 0 );
+ idxhead->fh2$b_map_inuse = 0;
+ idxhead->fh2$b_acc_mode = 0;
+ idxhead->fh2$l_fileowner.uic$w_mem = F11WORD( 1 );
+ idxhead->fh2$l_fileowner.uic$w_grp = F11WORD( 1 );
+ idxhead->fh2$w_fileprot = F11WORD( 0xFA00 );
+ idxhead->fh2$w_backlink.fid$w_num = F11WORD( 4 );
+ idxhead->fh2$w_backlink.fid$w_seq = F11WORD( 4 );
+ idxhead->fh2$w_backlink.fid$b_rvn = 0;
+ idxhead->fh2$w_backlink.fid$b_nmx = 0;
+ idxhead->fh2$l_highwater = F11LONG( 1 );
+
+#define IDENTp(head) ((struct IDENT *) (((f11word *)head) + F11WORD(head->fh2$b_idoffset)))
+ ident = IDENTp(idxhead);
+
+ ident->fi2$w_revision = F11WORD( 1 );
+ memcpy( ident->fi2$q_credate, scb->scb$q_mounttime, sizeof(ident->fi2$q_credate) );
+ memcpy( ident->fi2$q_revdate, scb->scb$q_mounttime, sizeof(ident->fi2$q_credate) );
+ idxhead->fh2$b_mpoffset =F11WORD( F11WORD(idxhead->fh2$b_idoffset) +
+ (offsetof( struct IDENT, fi2$t_filenamext ) / 2) );
+
+ memcpy( badhead, idxhead, sizeof( *badhead ) );
+ memcpy( corhead, idxhead, sizeof( *corhead ) );
+ memcpy( volhead, idxhead, sizeof( *volhead ) );
+ memcpy( conthead, idxhead, sizeof( *conthead ) );
+ memcpy( bakhead, idxhead, sizeof( *bakhead ) );
+ memcpy( loghead, idxhead, sizeof( *loghead ) );
+ memcpy( bmphead, idxhead, sizeof( *bmphead ) );
+ memcpy( mfdhead, idxhead, sizeof( *mfdhead ) );
+
+ bmphead->fh2$l_filechar = F11LONG( FH2$M_CONTIG );
+ mfdhead->fh2$l_filechar = F11LONG( FH2$M_DIRECTORY | FH2$M_CONTIG );
+ mfdhead->fh2$w_fileprot &= ~F11WORD( 0x4000 ); /* W:E allowed for MFD */
+
+ mfdblocks = CLU2LBN( CLUSTERS( mfdblocks ) );
+ CALLOC( mfdp, 1, mfdblocks * 512 );
+
+#define SETFILE(head, num, seq, name, rtype, rattr, rsize ) do { \
+ unsigned status; \
+ struct IDENT *id; \
+ char fname[sizeof( id->fi2$t_filename )+1]; \
+ id = IDENTp(head); \
+ (void) snprintf( fname, sizeof( fname ), "%-20.20s", #name ); \
+ memcpy( id->fi2$t_filename, fname, sizeof( id->fi2$t_filename ) ); \
+ head->fh2$w_fid.fid$w_num = F11WORD( num ); \
+ head->fh2$w_fid.fid$w_seq = F11WORD( seq ); \
+ head->fh2$w_recattr.fat$b_rtype = (FAB$C_SEQ << 4) | (rtype); \
+ head->fh2$w_recattr.fat$b_rattrib = rattr; \
+ head->fh2$w_recattr.fat$w_rsize = F11WORD( rsize ); \
+ head->fh2$w_recattr.fat$w_maxrec = F11WORD( rsize ); \
+ if( !((status = add2dir( mfdp, &mfdlen, mfdblocks, head )) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 )
+
+ /* Must be in alphabetical order for MFD */
+ SETFILE( mfdhead, 4,4, 000000.DIR;1, FAB$C_VAR, FAB$M_BLK, 512 );
+ SETFILE( bakhead, 8,8, BACKUP.SYS;1, FAB$C_FIX, 0, 64 );
+ SETFILE( badhead, 3,3, BADBLK.SYS;1, FAB$C_FIX, 0, 512 );
+ SETFILE( loghead, 9,9, BADLOG.SYS;1, FAB$C_FIX, 0, 16 );
+ SETFILE( bmphead, 2,2, BITMAP.SYS;1, FAB$C_FIX, 0, 512 );
+ SETFILE( conthead, 7,7, CONTIN.SYS;1, FAB$C_FIX, 0, 512 );
+ SETFILE( corhead, 5,5, CORIMG.SYS;1, FAB$C_FIX, 0, 512 );
+ SETFILE( idxhead, 1,1, INDEXF.SYS;1, FAB$C_FIX, 0, 512 );
+ SETFILE( volhead, 6,6, VOLSET.SYS;1, FAB$C_FIX, 0, 64 );
+
+ modbits( indexmap, 1, 0, 9 );
+
+ MALLOC( bitmap, 512 * bitmap_size );
+ memset( bitmap, 0xFF, 512 * bitmap_size );
+
+ DPRINTF(("Non-existent bitmap bits %u / %u LBNs %u - %u\n",
+ (bitmap_size *4096) - n_clusters, bitmap_size *4096,
+ n_clusters * clustersize, bitmap_size * 4096 * clustersize));
+ modbits( bitmap, 0, n_clusters, (bitmap_size * 4096) - n_clusters );
+
+#define ADDMAPENTRY(head, start, n ) do { \
+ unsigned status; \
+ \
+ if( !((status = add2map( params, (head), start, n)) & STS$M_SUCCESS ) ) \
+ return status; \
+ } while( 0 )
+
+ if( dp->flags & DISK_BAD144 ) {
+ unsigned start, count;
+
+ tmp = dp->sectors * dp->sectorsize;
+
+ MALLOC( mbad, tmp * 10 );
+ if( params->options & INIT_VIRTUAL ) {
+ memset( mbad->bbd$l_badblock, ~0, tmp );
+ mbad->bbd$l_serial = (uint32_t) serial;
+ mbad->bbd$w_reserved = 0;
+ mbad->bbd$w_flags = 0;
+ for( count = 0; count < 10; count++ )
+ memcpy( ((char *)mbad)+(count * dp->sectorsize),
+ mbad, dp->sectorsize );
+ }
+
+ /* Might have to deal with finding clusters more accurately
+ * for disks with interleave/skew.
+ */
+ start = npb - 10;
+ start = (unsigned) ( ( ((off_t)tmp) * pb_per_lb ) / lb_per_pb );
+ count = (unsigned) ( ( ((off_t)10) * lb_per_pb ) / pb_per_lb );
+
+ modlbnbits( params, bitmap, 0, start, count );
+ ADDMAPENTRY( badhead, start, count );
+ if( !(params->options & INIT_VIRTUAL) ) {
+ READP( dev, start, 10, mbad );
+ /* *** TODO : Decode and add to bitmap/badblk.sys */
+ }
+ }
+ if( dp->flags & DISK_BADSW ) {
+ CALLOC( sbad, 1, sizeof( struct SWBAD ) );
+ if( params->options & INIT_VIRTUAL ) {
+ sbad->bbm$b_countsize = 1;
+ sbad->bbm$b_lbnsize = 3;
+ sbad->bbm$b_inuse = 0;
+ sbad->bbm$b_avail = (uint8_t)( ( offsetof( struct SWBAD, bbm$w_checksum ) -
+ offsetof( struct SWBAD, bbm$r_map ) ) / sizeof( uint8_t ) );
+ }
+ modlbnbits( params, bitmap, 0, nlb - 1, 1 );
+ ADDMAPENTRY( badhead, nlb-1, 1 );
+ if( !(params->options & INIT_VIRTUAL) ) {
+ READ( dev, nlb-1, 1, sbad );
+ /* *** TODO : Decode and add to bitmap/badblk.sys */
+ }
+ }
+
+ /* Make index file map entries (in increasing VBN order)
+ */
+
+ /* BOOT and HOM blocks.
+ *
+ * HOM1 and boot merge if clustersize >1 & primary HOM is good.
+ */
+
+ homlbn = 1;
+ tmp = 0;
+
+ if( !tstlbnbit( params, bitmap, homlbn ) ) {
+ tmp = delta_from_index( dp - disktype );
+ do {
+ int freelbn;
+
+ freelbn = tstlbnbit( params, bitmap, homlbn );
+ modlbnbits( params, bitmap, 0, homlbn, 1 );
+ modlbnbits( params, bitmap, 0, bootlbn, 1 );
+
+ if( freelbn )
+ break;
+
+ /* add to bad blocks */
+
+ homlbn += tmp;
+ } while( homlbn < nlb );
+ }
+
+ if( homlbn >= nlb ) {
+ printf( "No good block found for HOM block\n" );
+ return SS$_DEVICEFULL;
+ }
+
+ modlbnbits( params, bitmap, 0, bootlbn, 1 );
+
+
+ DPRINTF(("Boot block = %u, primary HOM block = %u\n", bootlbn, homlbn));
+
+ if( bootlbn == 0 && homlbn < clustersize * 2 ) {
+ modlbnbits( params, bitmap, 0, bootlbn, clustersize * 2);
+ ADDMAPENTRY( idxhead, bootlbn, clustersize * 2 );
+ } else {
+ modlbnbits( params, bitmap, 0, bootlbn, clustersize );
+ modlbnbits( params, bitmap, 0, homlbn, clustersize *2 );
+
+ ADDMAPENTRY( idxhead, bootlbn, clustersize );
+ ADDMAPENTRY( idxhead, homlbn, clustersize * 2 );
+ }
+
+ /* Alternate HOM block
+ */
+
+ if( tmp == 0 )
+ tmp = delta_from_index( dp - disktype );
+
+ hm2lbn = homlbn;
+ do {
+ int freelbn;
+
+ hm2lbn += tmp;
+ freelbn = tstlbnbit( params, bitmap, hm2lbn );
+
+ modlbnbits( params, bitmap, 0, hm2lbn, 1 );
+ if( freelbn && hm2lbn >= params->clustersize * 2 )
+ break;
+ /* Add to bad blocks */
+ } while( hm2lbn < nlb );
+
+ if( hm2lbn >= nlb ) {
+ printf( "No good block found for HOM block\n" );
+ return SS$_DEVICEFULL;
+ }
+
+ hm2cluster = hm2lbn / clustersize;
+
+ DPRINTF(("Alternate HOM block is %u\n", hm2lbn));
+
+ ADDMAPENTRY( idxhead, CLU2LBN( hm2cluster ), 1 );
+
+ hom->hm2$l_alhomelbn = F11LONG( hm2lbn );
+
+ if( params->options & INIT_LOG ) {
+ printf( "%%INIT-I-SIZING, Volume size %u block, cluster size %us, maximum files %u\n",
+ nlb, clustersize, params->maxfiles );
+ printf( " -I-SIZING, Preallocated %u file headers, %u directory entries\n",
+ params->headers, params->directories );
+ printf( "%%INIT-I-PLACED, Boot block at LBN %u, HOM blocks at LBNs %u and %u\n",
+ bootlbn, homlbn, hm2lbn );
+ }
+
+ /* Variable placement. */
+
+ if( params->indexlbn == INIT_INDEX_MIDDLE )
+ volstart = nlb / 2;
+ else
+ volstart = params->indexlbn;
+
+#define ALLOCLBNS( start, number, result ) do { \
+ unsigned status; \
+ if( !((status = alloclbns( bitmap, clustersize, n_clusters, \
+ (start), (number), (result))) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 )
+
+ /* This order is recommended for best placement */
+
+ /* MFD */
+ ALLOCLBNS( volstart, mfdalloc, &mfdlbn );
+
+ /* Storage bitmap */
+ ALLOCLBNS( volstart, 1 + bitmap_size, &bmplbn );
+
+ /* Index bitmap and initial file headers. */
+ ALLOCLBNS( volstart, indexmap_size + params->headers, &idxlbn );
+
+ /* Backup index header -- Could be up around +nlb /4... */
+ ALLOCLBNS( volstart, 1, &aidxlbn );
+
+ hom->hm2$l_altidxlbn = F11LONG( aidxlbn );
+ hom->hm2$w_altidxvbn = F11WORD( (clustersize * 3) +1 );
+
+ DPRINTF(("Backup index header %u\n", aidxlbn));
+ ADDMAPENTRY( idxhead, aidxlbn, 1 );
+
+ fhlbn = idxlbn + indexmap_size;
+ hom->hm2$l_ibmaplbn = F11LONG( idxlbn );
+
+ DPRINTF(("Index bitmap LBN is %u, first extent %u\n",
+ idxlbn, indexmap_size+params->headers));
+
+ /* EOF is 1 block past the 9 used headers */
+
+ tmp = (clustersize * 4) + indexmap_size + 9 +1;
+ idxhead->fh2$w_recattr.fat$l_efblk = F11SWAP( tmp );
+ idxhead->fh2$w_recattr.fat$w_ffbyte = F11WORD( 0 );
+ idxhead->fh2$l_highwater = F11LONG( tmp );
+
+ ADDMAPENTRY( idxhead, idxlbn, indexmap_size + params->headers );
+
+ hom->hm2$w_ibmapvbn = F11WORD( (clustersize * 4) + 1 );
+
+ /* Accurate EOF is not kept for directories, reclen = 32767 is
+ * end marker in data.
+ */
+#if 0
+ mfdhead->fh2$w_recattr.fat$l_efblk = F11SWAP( 1 + (mfdlen / 512) );
+ mfdhead->fh2$w_recattr.fat$w_ffbyte = F11WORD( mfdlen % 512 );
+#else
+ mfdhead->fh2$w_recattr.fat$l_efblk = F11SWAP( 1 + ((mfdlen + 511) / 512) );
+ mfdhead->fh2$w_recattr.fat$w_ffbyte = F11WORD( 0 );
+#endif
+ mfdhead->fh2$l_highwater = F11LONG( 1 + ((mfdlen + 511) / 512) );
+
+ ADDMAPENTRY( mfdhead, mfdlbn, mfdalloc );
+
+ /* Storage bitmap */
+
+ bmphead->fh2$w_recattr.fat$l_efblk = F11SWAP( 1 + bitmap_size + 1);
+ bmphead->fh2$w_recattr.fat$w_ffbyte = F11WORD( 0 );
+ bmphead->fh2$l_highwater = F11LONG( 1 + bitmap_size + 1 );
+
+ ADDMAPENTRY( bmphead, bmplbn, 1 + bitmap_size );
+
+ if( params->options & INIT_LOG ) {
+ printf( "%%INIT-I-PLACED, MFD at LBN %u, index file at LBNs %u thru %u\n",
+ mfdlbn, idxlbn, idxlbn + indexmap_size + params->headers -1 );
+ }
+
+ /* Let's try for a spiral write... */
+
+ WRITE( dev, 0, 1, bootblock );
+
+ /* Write HOM blocks */
+
+ homvbn = 2;
+ hom->hm2$w_homevbn = F11WORD( homvbn );
+
+ DPRINTF(("Primary HOM block lbn %u vbn %u\n", homlbn, homvbn ));
+
+ homvbn = (clustersize * 2) + 1;
+ hom->hm2$w_alhomevbn = F11WORD( homvbn );
+
+ tmp = (clustersize > 2)? /* Copies needed */
+ (clustersize * 2) - 1: 1;
+
+ if( !((status = writeHOM( dev, hom, homlbn, 2, tmp )) & STS$M_SUCCESS) )
+ return status;
+
+ DPRINTF(("Secondary HOM block lbn %u vbn %u\n", hm2lbn, homvbn));
+
+ if( !((status = writeHOM( dev, hom, hm2cluster * clustersize, homvbn, clustersize )) & STS$M_SUCCESS) )
+ return status;
+
+ /* MFD */
+
+ DPRINTF(("MFD at %u, %u blocks, len %u\n", mfdlbn, mfdalloc, mfdlen));
+
+ WRITE( dev, mfdlbn, mfdblocks, mfdp );
+
+ DPRINTF(("Writing BITMAP.SYS at %u, %u blocks\n", bmplbn,
+ 1 + bitmap_size));
+
+ WRITE( dev, bmplbn, 1, scb );
+ WRITE( dev, bmplbn + 1, bitmap_size, bitmap );
+
+ DPRINTF(("Index file bitmap\n"));
+ WRITE( dev, idxlbn, indexmap_size, indexmap );
+
+#define WRITEHEAD(head,name) do { \
+ unsigned status; \
+ head->fh2$w_checksum = checksum( (f11word *)(head), \
+ offsetof( struct HEAD, fh2$w_checksum ) / 2 ); \
+ DPRINTF(("Writing " #name " header\n")); \
+ if( !((status = writeHEAD( dev, (head), fhlbn )) & STS$M_SUCCESS) ) \
+ return status; \
+ } while( 0 )
+
+ WRITEHEAD( idxhead, INDEXF.SYS;1 );
+ WRITEHEAD( bmphead, BITMAP.SYS;1 );
+ WRITEHEAD( badhead, BADBLK.SYS;1 );
+ WRITEHEAD( mfdhead, 000000.DIR;1 );
+ WRITEHEAD( corhead, CORIMG.SYS;1 );
+ WRITEHEAD( volhead, VOLSET.SYS;1 );
+ WRITEHEAD( conthead, CONTIN.SYS;1 );
+ WRITEHEAD( bakhead, BACKUP.SYS;1 );
+ WRITEHEAD( loghead, BADLOG.SYS;1 );
+
+ if( !((status = writeHDR( dev, idxhead, aidxlbn )) & STS$M_SUCCESS) )
+ return status;
+
+ if( params->options & INIT_VIRTUAL ) {
+ if( dp->flags & DISK_BAD144 ) {
+ if( params->options & INIT_LOG ) {
+ printf( "%%INIT-I-MFGBAD, writing manufacturer's bad block index\n" );
+ }
+ WRITEP( dev, npb - 10, 10, mbad );
+ }
+ if( dp->flags & DISK_BADSW ) {
+ if( params->options & INIT_LOG ) {
+ printf( "%%INIT-I-SWBAD, writing software bad block descriptor\n" );
+ }
+ sbad->bbm$w_checksum = checksum( sbad, offsetof( struct SWBAD, bbm$w_checksum ) / 2 );
+ WRITE( dev, nlb - 1, 1, sbad );
+ }
+
+ /* Access last block so full size of file is allocated. (Hopefully
+ * sparse.) To account for possible interleaving, do the last track.
+ * Helps humans in various ways.
+ */
+
+ if( eofmark < nlb ) {
+ for( tmp = nlb - ((dp->sectors * lb_per_pb) / pb_per_lb);
+ tmp < nlb; tmp++ ) {
+ READ( dev, tmp, 1, idxhead );
+ WRITE( dev, tmp, 1, idxhead );
+ }
+ }
+ }
+
+ return status;
+}
+#undef Malloc
+
+static unsigned add2dir( void *dirp, unsigned *dirlen, unsigned dirblocks,
+ struct HEAD *head ) {
+ struct dir$r_ent *de;
+ struct dir$r_rec *dr;
+ struct IDENT *ident;
+ unsigned block, offset;
+ f11word reclen, paddednamelen, version, verlimit;
+ size_t namelen, typlen;
+ char fname[ sizeof( ident->fi2$t_filename ) +
+ sizeof( ident->fi2$t_filenamext ) + 1], *p;
+ int extlen;
+
+ ident = IDENTp(head);
+
+ memcpy( fname, ident->fi2$t_filename, sizeof( ident->fi2$t_filename ) );
+
+ extlen = ((head->fh2$b_mpoffset - head->fh2$b_idoffset) * sizeof( f11word )) -
+ offsetof( struct IDENT, fi2$t_filenamext );
+ if( extlen > 0 ) {
+ if( extlen > (int) sizeof( ident->fi2$t_filenamext ) )
+ extlen = sizeof( ident->fi2$t_filenamext );
+ memcpy( fname + sizeof( ident->fi2$t_filename ),
+ ident->fi2$t_filenamext, extlen );
+ } else extlen = 0;
+
+ namelen = sizeof( ident->fi2$t_filename ) + extlen;
+ fname[namelen] = '\0';
+ while( namelen > 1 && fname[namelen - 1] == ' ' )
+ fname[--namelen] = '\0';
+
+ if( (p = strrchr( fname, ';' )) != NULL ) {
+ typlen = (size_t) ( fname + namelen - p );
+ namelen = (size_t)(p -fname );
+ *p++ = '\0';
+ version = (f11word)strtoul( p, &p, 10 );
+ if( p != fname + namelen + typlen || typlen < 1 )
+ return SS$_BADFILENAME;
+ } else
+ version = 1;
+
+ block = *dirlen / 512;
+ offset = *dirlen % 512;
+
+ verlimit = (head->fh2$l_filechar & FH2$M_DIRECTORY)? 1: 0;
+
+ paddednamelen = (f11word) ( ((namelen + 1) / 2) * 2 );
+
+ reclen = offsetof( struct dir$r_rec, dir$t_name ) + paddednamelen + sizeof( struct dir$r_ent );
+ if( reclen + offset > 512 ) {
+ block++;
+ if( block >= dirblocks )
+ return SS$_DEVICEFULL;
+ if( offset <= 512 - sizeof(f11word) ) {
+ ((f11word *)dirp)[offset / sizeof(f11word)] = F11WORD( -1 );
+ offset += sizeof( f11word );
+ }
+ *dirlen += 512 - offset;
+ offset = 0;
+ }
+ dr = (struct dir$r_rec *)( ((char *)dirp) + *dirlen );
+ dr->dir$w_size = (f11word) F11WORD( reclen - sizeof( dr->dir$w_size ) );
+ dr->dir$w_verlimit = F11WORD( verlimit );
+ dr->dir$b_flags = 0; /* dir$c_fid */
+ dr->dir$b_namecount = (uint8_t) namelen;
+ memcpy( dr->dir$t_name, fname, paddednamelen );
+ de = (struct dir$r_ent *) ( ((char *)dirp) + ( block * 512 ) + offset + reclen - sizeof( struct dir$r_ent ));
+ de->dir$w_version = version;
+ de->dir$w_fid = head->fh2$w_fid;
+ offset += reclen;
+ if( offset <= 512 - sizeof(f11word) )
+ ((f11word *)dirp)[offset/sizeof(f11word)] = F11WORD( -1 );
+ *dirlen += reclen;
+
+ return SS$_NORMAL;
+}
+
+static unsigned add2map( struct NEWVOL *params, struct HEAD *fhd,
+ unsigned start, unsigned n ) {
+ f11word *mpe;
+ uint8_t mapsize, inuse;
+ f11long hiblk;
+ unsigned clustersize;
+
+ clustersize = params->clustersize;
+
+ hiblk = F11SWAP( fhd->fh2$w_recattr.fat$l_hiblk );
+
+#if DEBUG
+ printf( "Adding %u blocks at lbn %u, clu %u to %-20.20s",
+ n, start, start / clustersize, IDENTp(fhd)->fi2$t_filename );
+#endif
+
+ n = CLU2LBN( CLUSTERS( n ) );
+ start = CLU2LBN( start / clustersize );
+
+ mapsize = fhd->fh2$b_acoffset - fhd->fh2$b_mpoffset;
+ inuse = fhd->fh2$b_map_inuse;
+
+ mpe = ((f11word *)fhd) + F11WORD( fhd->fh2$b_mpoffset ) + inuse;
+
+#if DEBUG
+ printf( "Alloc: %u\n", n );
+#endif
+
+ while( n > 0 ) {
+ f11word freew = mapsize - inuse;
+ unsigned count;
+
+ count = n;
+ if( start <= FM2$C_FMT1_MAXLBN ) {
+ if( freew < 2 )
+ return SS$_DEVICEFULL;
+ if( count <= FM2$C_FMT1_MAXCNT ) {
+ hiblk += count;
+ n -= count--;
+ *mpe++ = F11WORD( FM2$M_FORMAT1 | ((start >> 16) << 8) | count );
+ *mpe++ = F11WORD( (f11word)start );
+ inuse += 2;
+ start += count + 1;
+ continue;
+ }
+ }
+ if( count <= FM2$C_FMT2_MAXCNT ) {
+ if( freew < 3 )
+ return SS$_DEVICEFULL;
+ hiblk += count--;
+ *mpe++ = F11WORD( FM2$M_FORMAT2 | count );
+ *mpe++ = F11WORD( (f11word)start );
+ *mpe++ = F11WORD( (f11word)(start >> 16) );
+ inuse += 3;
+ break;
+ }
+ if( freew < 4 )
+ return SS$_DEVICEFULL;
+ if( count > FM2$C_FMT3_MAXCNT )
+ count = FM2$C_FMT3_MAXCNT;
+ hiblk += count;
+ n -= count--;
+ *mpe++ = F11WORD( FM2$M_FORMAT3 | (f11word)(count >> 16) );
+ *mpe++ = F11WORD( (f11word)count );
+ *mpe++ = F11WORD( (f11word)start );
+ *mpe++ = F11WORD( (f11word)(start >> 16) );
+ inuse += 4;
+ start += count + 1;
+ }
+
+ fhd->fh2$w_recattr.fat$l_hiblk = F11SWAP( hiblk );
+
+#if DEBUG
+ {
+ unsigned vbn = 1;
+ unsigned i;
+ f11word *mp;
+
+ mp = ((f11word *)fhd) + F11WORD( fhd->fh2$b_mpoffset );
+
+ for( i = 0; i < inuse; i++ ) {
+ f11word e0;
+ unsigned count, pbn;
+
+ e0 = *mp++;
+ e0 = F11WORD(e0);
+ switch( e0 & FM2$M_FORMAT3 ) {
+ case FM2$M_FORMAT1:
+ count = e0 & 0xff;
+ pbn = F11WORD(*mp) | (((e0 & ~FM2$M_FORMAT3) >> 8) << 16);
+ mp++;
+ break;
+ case FM2$M_FORMAT2:
+ count = e0 & ~FM2$M_FORMAT3;
+ pbn = *mp++;
+ pbn = F11WORD( pbn );
+ pbn |= F11WORD (*mp ) << 16;
+ mp++;
+ break;
+ case FM2$M_FORMAT3:
+ count = ((e0 & ~FM2$M_FORMAT3) << 16);
+ count |= F11WORD( *mp );
+ mp++;
+ pbn = *mp++;
+ pbn = F11WORD( pbn );
+ pbn |= F11WORD (*mp ) << 16;
+ mp++;
+ break;
+ default:
+ continue;
+ }
+ ++count;
+ printf(" VBN %u, FMT %u PBN %u, Count %u\n", vbn, (e0 >> 14), pbn, count );
+ vbn += count;
+ }
+ printf( " File EOF VBN %u FFB %u, Alloc: %u\n",
+ F11SWAP( fhd->fh2$w_recattr.fat$l_efblk ),
+ fhd->fh2$w_recattr.fat$w_ffbyte,
+ F11SWAP( fhd->fh2$w_recattr.fat$l_hiblk ) );
+ }
+#endif
+
+ fhd->fh2$b_map_inuse = inuse;
+ return SS$_NORMAL;
+}
+
+static unsigned writeHEAD( void *dev, struct HEAD *head, unsigned hdrbase ) {
+ hdrbase += head->fh2$w_fid.fid$w_num - 1;
+
+ return writeHDR( dev, head, hdrbase );
+}
+
+static unsigned writeHDR( void *dev, struct HEAD *head, unsigned lbn ) {
+ head->fh2$w_checksum = checksum( (f11word *)head, offsetof( struct HEAD, fh2$w_checksum ) / 2 );
+ head->fh2$w_checksum = F11WORD( head->fh2$w_checksum );
+
+ WRITE( dev, lbn, 1, head );
+ return SS$_NORMAL;
+}
+static unsigned writeHOM( void *dev, struct HOME *hom,
+ unsigned homlbn, unsigned homvbn,
+ unsigned ncopies ) {
+ unsigned copy = 0;
+
+ do {
+ hom->hm2$l_homelbn = F11LONG( homlbn );
+ hom->hm2$w_homevbn = F11WORD( homvbn );
+ hom->hm2$w_checksum1 = checksum( (f11word *)hom,
+ offsetof( struct HOME, hm2$w_checksum1 ) /2 );
+ hom->hm2$w_checksum1 = F11WORD( hom->hm2$w_checksum1 );
+ hom->hm2$w_checksum2 = checksum( (f11word *)hom,
+ offsetof( struct HOME, hm2$w_checksum2 ) /2 );
+ hom->hm2$w_checksum2 = F11WORD( hom->hm2$w_checksum2 );
+
+ WRITE( dev, homlbn, 1, hom );
+ homlbn++;
+ homvbn++;
+ } while( ++copy < ncopies );
+
+ return SS$_NORMAL;
+}
+
+static unsigned alloclbns( unsigned char *bitmap,
+ unsigned clustersize,
+ unsigned n_clusters,
+ unsigned startlbn, unsigned n,
+ unsigned *found ) {
+ unsigned nfound;
+ int pass;
+
+ *found = ~0U;
+
+ startlbn /= clustersize;
+ n = CLUSTERS( n );
+
+ for( pass = 0, nfound = 0; pass < 2 && nfound < n; pass++ ) {
+ unsigned lbn;
+
+ if( pass > 0 ) startlbn = 0;
+
+ for( lbn = startlbn, nfound = 0; nfound < n && lbn + n < n_clusters; lbn++ ) {
+ if( bitmap[ lbn >> 3 ] & (1 << (lbn & 0x7)) ) {
+ if( nfound++ == 0 )
+ startlbn = lbn;
+ } else
+ nfound = 0;
+ }
+ }
+
+ if( nfound < n )
+ return SS$_DEVICEFULL;
+
+ modbits( bitmap, 0, startlbn, n );
+
+ *found = startlbn * clustersize;
+ return SS$_NORMAL;
+}
+
+static void modlbnbits( struct NEWVOL *params, unsigned char *bitmap, int set, unsigned start, unsigned n ) {
+ ldiv_t d;
+ unsigned first, clusters, clustersize;
+
+ if( n == 0 )
+ return;
+
+ clustersize = params->clustersize;
+
+ d = ldiv( start, clustersize );
+
+ clusters = 1;
+
+ if( (first = clustersize - d.rem) < n )
+ clusters += CLUSTERS( n - first );
+
+ modbits( bitmap, set, d.quot, clusters );
+ return;
+}
+
+static int tstlbnbit( struct NEWVOL *params, unsigned char *bitmap, unsigned lbn ) {
+
+ lbn = lbn / params->clustersize;
+
+ return (bitmap[lbn >> 3] & (1 << (lbn & 0x7))) != 0;
+}
+
+static void modbits( unsigned char *bitmap, int set, unsigned start, unsigned n ) {
+ unsigned q, bit, byte;
+
+ if( set ) {
+ while( n > 0 ) {
+ bit = start & 0x7;
+ byte = start >>3;
+
+ if( bit == 0 && n > 8 ) {
+ q = n >> 3;
+ n &= 0x7;
+
+ if( q == 1 )
+ bitmap[byte] = 0xff;
+ else
+ memset( bitmap+byte, 0xff, q );
+ start += q << 3;
+ } else {
+ bitmap[byte] |= 1 << bit;
+ start++;
+ n--;
+ }
+ }
+ return;
+ }
+ while( n > 0 ) {
+ bit = start & 0x7;
+ byte = start >>3;
+
+ if( bit == 0 && n > 8 ) {
+ q = n >> 3;
+ n &= 0x7;
+
+ if( q == 1 )
+ bitmap[byte] = 0;
+ else
+ memset( bitmap+byte, 0x00, q );
+ start += q << 3;
+ } else {
+ bitmap[byte] &= ~(1 << bit);
+ start++;
+ n--;
+ }
+ }
+ return;
+}
+
+static f11word checksum( void *data, size_t length ) {
+ f11word sum, *dp;
+ size_t count;
+
+ for( sum = 0, dp = (f11word *)data,
+ count = 0; count < length; count++ )
+ sum += *dp++;
+ return sum;
+}
+
+/*************************************************************** compute_delta() */
+/*
+ * The search delta is computed from the
+ * volume geometry, expressed in sectors, tracks (surfaces), and
+ * cylinders, according to the following rules, to handle the cases where
+ * one or two dimensions of the volume have a size of 1.
+ *
+ * Geometry: Delta
+ *
+ * s x 1 x 1: 1 Rule 1
+ * 1 x t x 1: 1 Rule 2
+ * 1 x 1 x c: 1 Rule 3
+ *
+ * s x t x 1: s+1 Rule 4
+ * s x 1 x c: s+1 Rule 5
+ * 1 x t x c: t+1 Rule 6
+ *
+ * s x t x c: (t+1)*s+1 Rule 7
+ */
+
+
+static unsigned int compute_delta( unsigned long sectorsize,
+ unsigned long sectors,
+ unsigned long tracks,
+ unsigned long cylinders ) {
+
+ if( sectorsize < 512 )
+ sectors = (sectorsize * sectors) / 512;
+
+ if( sectors > 1 && tracks > 1 && cylinders > 1 ) /* Rule 7 */
+ return (tracks + 1) * sectors +1;
+
+ if( (sectors > 1 && tracks > 1 && cylinders == 1 ) || /* Rule 4 */
+ (sectors > 1 && tracks == 1 && cylinders > 1 ) ) /* Rule 5 */
+ return sectors + 1;
+
+ if( sectors == 1 && tracks > 1 && cylinders > 1 ) /* Rule 6 */
+ return tracks + 1;
+
+ return 1; /* Rules 1-3 */
+}
+
+#if 0
+static unsigned int delta_from_name( const char *diskname ) {
+ struct disktype *dp;
+
+ for( dp = disktype; dp->name != NULL; dp++ ) {
+ if( !strcmp( dp->name, diskname ) )
+ return compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
+ }
+
+ return ~0u;
+}
+#endif
+unsigned int delta_from_index( size_t index ) {
+ struct disktype *dp;
+ unsigned int delta;
+
+ if( index > max_disktype )
+ abort();
+
+ dp = disktype + index;
+ delta = compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
+
+#if defined( DEBUG ) || HOME_SKIP > 0
+ printf( "HOM search index for %s is %u\n", dp->name, delta );
+#endif
+
+ return delta;
+}
diff --git a/extracters/ods2/initvol.h b/extracters/ods2/initvol.h
new file mode 100644
index 0000000..e30aeab
--- /dev/null
+++ b/extracters/ods2/initvol.h
@@ -0,0 +1,84 @@
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#ifndef _INITVOL_H
+#define _INITVOL_H
+
+#include
+
+struct NEWVOL {
+ const char *label;
+ const char *devtype;
+ const char *devnam;
+ const char *username;
+ const char *useruic;
+ unsigned options;
+ unsigned clustersize;
+ unsigned maxfiles;
+ unsigned headers;
+ unsigned indexlbn;
+ unsigned directories;
+};
+#define INIT_INDEX_MIDDLE (~0U)
+#define INIT_LOG (1 << 0)
+#define INIT_VIRTUAL (1 << 1)
+
+#define VOL_ALPHABET "abcdefghijklmnopqrstuvwxyz$-_" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+#ifdef __ALPHA
+#pragma member_alignment save
+#pragma nomember_alignment
+#endif
+
+struct BAD144 {
+ uint32_t bbd$l_serial;
+ uint16_t bbd$w_reserved;
+ uint16_t bbd$w_flags;
+ uint32_t bbd$l_badblock[1];
+#define BBD$M_TRACK (0x7F << BBD$V_TRACK)
+#define BBD$V_TRACK (24)
+#define BBD$M_SECTOR (0xFF << BBD$V_SECTOR)
+#define BBD$V_SECTOR (16)
+#define BBD$M_CYLINDER (0x7FFF << BBD$V_CYLINDER)
+#define BBD$V_CYLINDER (0)
+#define BBD$C_FILL ((uint32_t)~0u)
+};
+
+struct SWBADENT {
+ uint8_t bbm$b_highlbn;
+ uint8_t bbm$b_count;
+ uint16_t bbm$w_lowlbn;
+};
+struct SWBAD {
+ uint8_t bbm$b_countsize;
+ uint8_t bbm$b_lbnsize;
+ uint8_t bbm$b_inuse;
+ uint8_t bbm$b_avail;
+ struct SWBADENT bbm$r_map[126];
+ uint16_t bbm$w_reserved;
+ uint16_t bbm$w_checksum;
+};
+
+#ifdef __ALPHA
+#pragma member_alignment restore
+#endif
+
+unsigned initvol( void *dev, struct NEWVOL *params );
+unsigned int delta_from_index( size_t index );
+
+#endif
diff --git a/extracters/ods2/makefile-vhd.nt b/extracters/ods2/makefile-vhd.nt
new file mode 100644
index 0000000..c0586e5
--- /dev/null
+++ b/extracters/ods2/makefile-vhd.nt
@@ -0,0 +1,11 @@
+# -*- Makefile -*-
+
+# Include file for VHD format image file support on
+# Unix OSs that support it
+
+# Enable VHD static library, disable syslog so errors go
+# to stderr.
+DEFS += -DUSE_VHD -Ivhd -DLIBVHD_HAS_SYSLOG=0
+LIBS += Rpcrt4.lib
+VHDLIB = phyvhd.c vhd/libvhd.c vhd/relative-path.c
+
diff --git a/extracters/ods2/makefile-vhd.unix b/extracters/ods2/makefile-vhd.unix
new file mode 100644
index 0000000..8426b75
--- /dev/null
+++ b/extracters/ods2/makefile-vhd.unix
@@ -0,0 +1,19 @@
+# -*- Makefile -*-
+
+# Include file for VHD format image file support on
+# Unix OSs that support it
+
+# Enable VHD static library, disable syslog so errors go
+# to stderr.
+DEFS += -DUSE_VHD -Ivhd -D_GNU_SOURCE -DLIBVHD_HAS_SYSLOG=0
+LDLIBS += -luuid
+VHDLIB = phyvhd.c vhd/libvhd.c vhd/relative-path.c
+
+# Enable VHD sharable library
+# Not recommended, as it logs to syslog. Used for testing
+# against unmodified Xen libraries. A modified sharable image
+# can also be built - see the vhdtools makefile.
+#
+#DEFS += -DUSE_VHD -DUSE_LIBVHD="libvhd.so" -Ivhd -D_GNU_SOURCE
+#LDLIBS += -ldl
+#VHDLIB = phyvhd.c
diff --git a/extracters/ods2/makefile.depends b/extracters/ods2/makefile.depends
new file mode 100644
index 0000000..9cfd6c9
--- /dev/null
+++ b/extracters/ods2/makefile.depends
@@ -0,0 +1,123 @@
+# DO NOT DELETE
+
+ods2.o: version.h cmddef.h
+ods2.o: compat.h
+ods2.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+ods2.o: stsdef.h sysmsg.h cache.h phyvirt.h
+access.o: ssdef.h access.h
+access.o: cache.h f11def.h
+access.o: vmstime.h descrip.h stsdef.h device.h phyio.h initvol.h ods2.h
+access.o: phyvirt.h compat.h
+access.o: sysmsg.h
+cache.o: cache.h ods2.h ssdef.h
+compat.o: compat.h
+compat.o: descrip.h stsdef.h
+copycmd.o: cmddef.h
+copycmd.o: compat.h
+copycmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+copycmd.o: stsdef.h sysmsg.h
+createcmd.o: cmddef.h
+createcmd.o: compat.h
+createcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+createcmd.o: stsdef.h sysmsg.h f11def.h
+debug.o: debug.h
+deletecmd.o: cmddef.h
+deletecmd.o: compat.h
+deletecmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+deletecmd.o: stsdef.h sysmsg.h
+device.o: ods2.h access.h cache.h
+device.o: f11def.h vmstime.h
+device.o: descrip.h ssdef.h stsdef.h device.h phyio.h
+diffcmd.o: cmddef.h
+diffcmd.o: compat.h
+diffcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+diffcmd.o: stsdef.h sysmsg.h
+dircmd.o: cmddef.h
+dircmd.o: compat.h
+dircmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+dircmd.o: stsdef.h sysmsg.h
+direct.o: access.h cache.h
+direct.o: f11def.h vmstime.h
+direct.o: descrip.h ssdef.h stsdef.h direct.h fibdef.h ods2.h
+dismountcmd.o: cmddef.h
+dismountcmd.o: compat.h
+dismountcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+dismountcmd.o: stsdef.h sysmsg.h access.h cache.h f11def.h
+dismountcmd.o: device.h
+dismountcmd.o: phyio.h
+extendcmd.o: cmddef.h
+extendcmd.o: compat.h
+extendcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+extendcmd.o: stsdef.h sysmsg.h
+helpcmd.o: cmddef.h
+helpcmd.o: compat.h
+helpcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+helpcmd.o: stsdef.h sysmsg.h
+importcmd.o: cmddef.h
+importcmd.o: compat.h
+importcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+importcmd.o: stsdef.h sysmsg.h
+initialcmd.o: cmddef.h
+initialcmd.o: compat.h
+initialcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+initialcmd.o: stsdef.h sysmsg.h access.h cache.h f11def.h
+initialcmd.o: device.h
+initialcmd.o: phyio.h initvol.h phyvirt.h
+initvol.o: compat.h
+initvol.o: f11def.h
+initvol.o: vmstime.h descrip.h ssdef.h stsdef.h
+initvol.o: initvol.h ods2.h phyvirt.h rms.h
+mountcmd.o: cmddef.h
+mountcmd.o: compat.h
+mountcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+mountcmd.o: stsdef.h sysmsg.h access.h cache.h f11def.h
+mountcmd.o: device.h phyio.h phyvirt.h phyvhd.h
+phyunix.o: device.h
+phyunix.o: access.h cache.h f11def.h vmstime.h descrip.h ssdef.h stsdef.h
+phyunix.o: phyio.h ods2.h phyvirt.h compat.h
+phyvirt.o: compat.h
+phyvirt.o: device.h access.h cache.h f11def.h
+phyvirt.o: vmstime.h
+phyvirt.o: descrip.h ssdef.h stsdef.h phyio.h ods2.h phyvirt.h phyvhd.h
+rms.o: access.h cache.h f11def.h
+rms.o: vmstime.h descrip.h ssdef.h stsdef.h
+rms.o: device.h phyio.h direct.h fibdef.h ods2.h rms.h compat.h
+rms.o: sysmsg.h
+searchcmd.o: cmddef.h
+searchcmd.o: compat.h
+searchcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+searchcmd.o: stsdef.h sysmsg.h
+setcmd.o: cmddef.h
+setcmd.o: compat.h
+setcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+setcmd.o: stsdef.h sysmsg.h
+showcmd.o: cmddef.h
+showcmd.o: compat.h
+showcmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+showcmd.o: stsdef.h sysmsg.h
+showcmd.o: access.h cache.h f11def.h
+showcmd.o: direct.h phyio.h
+showcmd.o: phyvhd.h phyvirt.h version.h
+spawncmd.o: cmddef.h
+spawncmd.o: compat.h
+spawncmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+spawncmd.o: stsdef.h sysmsg.h
+sysmsg.o: ssdef.h rms.h vmstime.h
+sysmsg.o: descrip.h stsdef.h compat.h
+sysmsg.o: sysmsg.h
+typecmd.o: cmddef.h
+typecmd.o: compat.h
+typecmd.o: ods2.h rms.h vmstime.h descrip.h ssdef.h
+typecmd.o: stsdef.h sysmsg.h
+update.o: access.h cache.h
+update.o: f11def.h vmstime.h
+update.o: descrip.h ssdef.h stsdef.h device.h phyio.h ods2.h
+vmstime.o: vmstime.h descrip.h ssdef.h stsdef.h
+phyvhd.o: device.h
+phyvhd.o: access.h cache.h f11def.h
+phyvhd.o: vmstime.h descrip.h ssdef.h stsdef.h
+phyvhd.o: phyio.h ods2.h phyvirt.h vhd/libvhd.h
+phyvhd.o: vhd/blk_uuid.h vhd/vhd.h
+vhd/libvhd.o: vhd/libvhd.h
+vhd/libvhd.o: vhd/blk_uuid.h vhd/vhd.h vhd/relative-path.h
+vhd/relative-path.o: vhd/relative-path.h
diff --git a/extracters/ods2/makefile.generic b/extracters/ods2/makefile.generic
index 46c20d1..5ebfc0e 100644
--- a/extracters/ods2/makefile.generic
+++ b/extracters/ods2/makefile.generic
@@ -1,5 +1,11 @@
+# -*- Makefile -*-
+
# Generic makefile for ods2
#
+# This tries really hard to be OS-agnostic, because
+# otherwise, every little change means updating all
+# the os-specific makefiles.
+#
# See makefile., which normally includes it
#
# If your make doesn't support include, these can be
@@ -18,72 +24,112 @@
#DEFS =
# Libraries, e.g. -lreadline
+#LDLIBS =
+
+# Linker flags
#LDFLAGS =
# Object file suffix
#OBJ = .o
+# Executable file suffix
+
+#EXE =
+
# Physical IO module
#PHYSIO = phyunix
# Extra physical IO headers
#PHYSIOH =
+# VHD format options
+
+include $(VHDOPTS)
+
# #####################################################
-all : ods2
+DEPENDS = makefile.depends
+MAKEDEPEND = makedepend
+SED = sed
-OBJS = $(ODS2_OBJS)
+all : ods2$(EXE)
-COMMON_OBJS = \
-access$(OBJ) \
-cache$(OBJ) \
-compat$(OBJ)\
-device$(OBJ) \
-direct$(OBJ) \
-phyvirt$(OBJ) \
-rms$(OBJ) \
-sysmsg$(OBJ) \
-update$(OBJ) \
-vmstime$(OBJ)
+SRCS = ods2.c \
+access.c \
+cache.c \
+compat.c \
+copycmd.c \
+createcmd.c \
+debug.c \
+deletecmd.c \
+device.c \
+diffcmd.c \
+dircmd.c \
+direct.c \
+dismountcmd.c \
+extendcmd.c \
+helpcmd.c \
+importcmd.c \
+initialcmd.c \
+initvol.c \
+mountcmd.c \
+$(PHYSIO).c \
+phyvirt.c \
+rms.c \
+searchcmd.c \
+setcmd.c \
+showcmd.c \
+spawncmd.c \
+sysmsg.c \
+typecmd.c \
+update.c \
+vmstime.c \
+$(VHDLIB)
-ODS2_OBJS = ods2$(OBJ) $(COMMON_OBJS) $(PHYSIO)$(OBJ)
+OBJS = $(SRCS:.c=$(OBJ))
-ods2 : $(ODS2_OBJS) $(LIBS)
- $(CC) $(CCFLAGS) -o ods2 $(ODS2_OBJS) $(LDFLAGS)
+depend: $(MAKEFILE_LIST)
+ $(DELETE) $(DEPENDS)
+ $(MAKE) -f $(TOPMAKE) $(DEPENDS)
+ $(MAKE) -f makefile.vms descrip.mms
-access$(OBJ) : access.c ssdef.h access.h phyio.h compat.h sysmsg.h phyvirt.h
- $(CC) -c $(CCFLAGS) $(DEFS) access.c
+# Used to list sourcefiles for updating VC project & git repository.
+# Not used for Makefile builds
+# Run after make depends
+# To get the Windows file list on Unix, use
+# make -f makefile.nt "DELETE=rm -f" depend vclist
-cache$(OBJ) : cache.c cache.h ssdef.h
- $(CC) -c $(CCFLAGS) $(DEFS) cache.c
+vclist:
+ @echo "** Header files **"
+ @$(SED) $(DEPENDS) -e'/ *#/d' -e's/^.*.$(OBJ): //g' -e's/ /\n/g' | sort | uniq
+ @echo ""
+ @echo "** Source files **"
+ @echo $(SRCS) | sed -e's/ */\n/g' | sort | uniq
-compat$(OBJ) : compat.c compat.h
- $(CC) -c $(CCFLAGS) $(DEFS) compat.c
+# This processing is so the kit can contain a generic, up-to-date depends file
+# I don't want to require makedepend for people to build from source.
+# I do want the file to be accurate when shipped, so auto-maintained.
+# makedepend will include all the system library includes, which is not
+# helpful for this case. So the sed processing removes dependencies that
+# start with "/" - e.g. /usr/include and friends.
-device$(OBJ) : device.c ssdef.h access.h phyio.h
- $(CC) -c $(CCFLAGS) $(DEFS) device.c
+$(DEPENDS): $(MAKEFILE_LIST)
+ touch $(DEPENDS)
+ 2>/dev/null $(MAKEDEPEND) -o$(OBJ) -I. -f- -- $(CFLAGS) $(CPPFLAGS) $(DEFS) -- $(SRCS) | $(SED) -e's/ \/[^ ]*\.h/ /g' -e'/^[^:]*: *$$/d' -e's/ */ /g' >$(DEPENDS)
-direct$(OBJ) : direct.c direct.h access.h fibdef.h descrip.h ssdef.h
- $(CC) -c $(CCFLAGS) $(DEFS) direct.c
+-include $(DEPENDS)
-ods2$(OBJ) : ods2.c compat.h sysmsg.h phyio.h ssdef.h descrip.h access.h rms.h version.h
- $(CC) -c $(CCFLAGS) $(VERSION) $(DEFS) ods2.c
+# Currently, the descrip.mms file is updated on Unix. A makefile.vms
+# exists solely to enable this. It might be possible to build ODS2
+# on VMS with it using GNU tools. But that's not the point.
-$(PHYSIO)$(OBJ) : $(PHYSIO).c phyio.h phyvirt.h ssdef.h compat.h $(PHYSIOH)
- $(CC) -c $(CCFLAGS) $(DEFS) $(PHYSIO).c
+descrip.mms : $(SRCS) $(DEPENDS)
+ $(SED) -i.bak -e's!^OBJS = .*$$!OBJS = $(SRCS:.c=)!' -e'/^# ### BEGIN RULES ###/,$$d' -e'/^OBJS =/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' descrip.mms
+ echo "# ### BEGIN RULES ###" >>descrip.mms
+ 2>/dev/null $(MAKEDEPEND) -o$(OBJ) -I. -f- -- $(CFLAGS) $(CPPFLAGS) $(DEFS) -- $(SRCS) | $(SED) -e's/ \/[^ ]*\.h/ /g' -e'/^[^:]*: *$$/d' -e's/ */ /g' | $(SED) -e'/^# DO NOT DELETE/d' -e's/^\([^:]*\)$(OBJ):/\1$$(OBJ):/g' -e'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' >>descrip.mms
-phyvirt$(OBJ) : phyvirt.c phyvirt.h compat.h ssdef.h
- $(CC) -c $(CCFLAGS) $(DEFS) phyvirt.c
+%$(OBJ): %.c
+ $(CC) -c $(CCFLAGS) $(CPPFLAGS) $(DEFS) $< -o $@
-rms$(OBJ) : rms.c rms.h compat.h direct.h access.h fibdef.h descrip.h ssdef.h
- $(CC) -c $(CCFLAGS) $(DEFS) rms.c
-
-sysmsg$(OBJ) : sysmsg.c sysmsg.h rms.h ssdef.h
- $(CC) -c $(CCFLAGS) $(DEFS) sysmsg.c
-
-update$(OBJ) : update.c ssdef.h access.h
- $(CC) -c $(CCFLAGS) $(DEFS) update.c
-
-vmstime$(OBJ) : vmstime.c vmstime.h
- $(CC) -c $(CCFLAGS) $(DEFS) vmstime.c
+ods2$(EXE) : $(OBJS) $(LIBS)
+ $(CC) $(LDFLAGS) -o ods2$(EXE) $(OBJS) $(LDLIBS)
diff --git a/extracters/ods2/makefile.nt b/extracters/ods2/makefile.nt
index 822c6e7..a4f94ee 100644
--- a/extracters/ods2/makefile.nt
+++ b/extracters/ods2/makefile.nt
@@ -1,23 +1,37 @@
+# -*- Makefile -*-
# Makefile for Windows NT
#
CCFLAGS = "-Oxs"
+LIBS = Shlwapi.lib
+
# For the direct SCSI module
#DEFS = -DUSE_ASPI
-#LDFLAGS = wnaspi32.lib
+#LDLIBS = wnaspi32.lib
#PHYSIOH = wnaspi32.h scsidefs.h
-#LIBS = wnaspi32.lib
+#LIBS += wnaspi32.lib
OBJ = .OBJ
PHYSIO = phynt
+EXE = .EXE
+DELETE = DEL
-include makefile.generic
+# Include VHD format image file support
+
+VHDOPTS = makefile-vhd.nt
wnaspi32.lib : wnaspi32.def
LIB /DEF:WNASPI32.DEF /MACHINE:IX86
+TOPMAKE = makefile.nt
+
+all:
+
clean:
- del $(OBJS)
- del ods2.exe
+ $(DELETE) $(OBJS)
+ $(DELETE) ods2.exe
+
+include makefile.generic
+
diff --git a/extracters/ods2/makefile.solaris b/extracters/ods2/makefile.solaris
index 186be7d..bf7b5cb 100644
--- a/extracters/ods2/makefile.solaris
+++ b/extracters/ods2/makefile.solaris
@@ -1,3 +1,5 @@
+# -*- Makefile -*-
+
# Makefile for solaris OS
# Use gcc
@@ -9,14 +11,24 @@ CCFLAGS = -O4 -g
DEFS = -DUSE_READLINE
LDFLAGS = -lreadline -ltermcap
+# Include VHD format image file support
+
+VHDOPTS = makefile-vhd.unix
+
# Object file extension
OBJ = .o
+DELETE = "rm -f"
+
# Physical I/O module
PHYSIO = phyunix
PHYSIOH =
-include makefile.generic
+TOPMAKE = makefile.solaris
+
+all:
clean:
rm -f ods2 $(OBJS)
+
+include makefile.generic
diff --git a/extracters/ods2/makefile.tru64 b/extracters/ods2/makefile.tru64
index d4b10a3..0b7f72a 100644
--- a/extracters/ods2/makefile.tru64
+++ b/extracters/ods2/makefile.tru64
@@ -1,3 +1,5 @@
+# -*- Makefile -*-
+
# Makefile for Tru64 (DEC/OSF1)
#
@@ -6,14 +8,24 @@ CCFLAGS = -O4 -g
# DEFS = -DUSE_READLINE
# LDFLAGS = -lreadline -ltermcap
+# Include VHD format image file support
+
+VHDOPTS = makefile-vhd.unix
+
# Object file extension
OBJ = .o
+DELETE = rm -f
+
# Physical I/O module
PHYSIO = phyunix
PHYSIOH =
-include makefile.generic
+TOPMAKE = makefile.tru64
+
+all:
clean:
rm -f ods2 $(OBJS)
+
+include makefile.generic
diff --git a/extracters/ods2/makefile.unix b/extracters/ods2/makefile.unix
index fb334d4..3bb6cc3 100644
--- a/extracters/ods2/makefile.unix
+++ b/extracters/ods2/makefile.unix
@@ -1,6 +1,11 @@
+# -*- Makefile -*-
+
# Makefile for most Unix distributions
#
+# Special defines, e.g.
+# DEFS="-DDEBUG_RMS -DDEBUG_BUILD -D_FILE_OFFSET_BITS=32"
+
CCFLAGS = -O4 -g
#-O0 -g -DUSE_READLINE -Wall -pedantic
# Extra warns about $ in identifiers...
@@ -9,16 +14,28 @@ CCFLAGS = -O4 -g
# Include readline support
DEFS = -DUSE_READLINE
-LDFLAGS = -lreadline -ltermcap
+LDLIBS = -lreadline -ltermcap
+
+# Include VHD format image file support
+
+VHDOPTS = makefile-vhd.unix
# Object file extension
OBJ = .o
+EXE =
+
+DELETE = rm -f
+
# Physical I/O module
PHYSIO = phyunix
-PHYSIOH =
+
+TOPMAKE = makefile.unix
+
+all:
+
+clean:
+ rm -f ods2$(EXE) $(OBJS)
include makefile.generic
-clean:
- rm -f ods2 ods2i $(OBJS)
diff --git a/extracters/ods2/makefile.vms b/extracters/ods2/makefile.vms
new file mode 100644
index 0000000..8eeb967
--- /dev/null
+++ b/extracters/ods2/makefile.vms
@@ -0,0 +1,32 @@
+# -*- Makefile -*-
+
+# Used to generate descrip.mms
+# In theory should build under VMS with GNU tools.
+# But that's just a theory...
+
+# Special defines, e.g.
+# DEFS="-DDEBUG_RMS -DDEBUG_BUILD -D_FILE_OFFSET_BITS=32"
+
+CCFLAGS = -O4 -g
+
+#LDLIBS = -lreadline -ltermcap
+
+# Object file extension
+OBJ = .OBJ
+
+EXE = .EXE
+
+DELETE = DELETE
+GEN = ";*"
+
+# Physical I/O module
+PHYSIO = phyvms
+
+TOPMAKE = makefile.vms
+
+all:
+
+clean:
+ $(DELETE) *.$(OBJ)$(GEN),*.$(EXE)$(GEN)
+
+include makefile.generic
diff --git a/extracters/ods2/mountcmd.c b/extracters/ods2/mountcmd.c
new file mode 100644
index 0000000..e1a5b4d
--- /dev/null
+++ b/extracters/ods2/mountcmd.c
@@ -0,0 +1,153 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_MOUNTCMD )
+#define DEBUG DEBUG_MOUNTCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#include "access.h"
+#include "device.h"
+#include "phyio.h"
+#include "phyvirt.h"
+
+#ifdef USE_VHD
+#include "phyvhd.h"
+
+static char *parents = NULL;
+#endif
+
+void mounthelp(void);
+
+#define mou_snapshot OPT_GENERIC_1
+
+
+qual_t mouquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "},
+ {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", },
+ {"log", MOU_LOG, 0, NV, "-Show progress"},
+ {"nolog", 0, MOU_LOG, NV, NULL},
+ {"readonly", 0, MOU_WRITE, NV, "Only allow reading from volume"},
+#ifdef USE_VHD
+ {"snapshots_of", MOU_VIRTUAL | MOU_WRITE | mou_snapshot, PHY_CREATE, SV(&parents),
+ "Create snapshot(s) of the (existing) VHD disk(s) specified by this qualifier." },
+#endif
+ {"virtual", MOU_VIRTUAL, 0, NV, NULL, },
+ {"write", MOU_WRITE, 0, NV, "Allow writing to volume", },
+ {NULL, 0, 0, NV, NULL } };
+
+param_t moupars[] = { {"volumes", REQ, LIST, NOPA,
+ "devices or disk image(s) of volume set in RVN order separated by comma"
+ },
+ {"labels", OPT, LIST, NOPA, "volume labels in RVN order separated by comma" },
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+/******************************************************************* domount() */
+
+DECL_CMD(mount) {
+ int sts = 1, devices = 0;
+ char **devs = NULL, **labs = NULL;
+ int options;
+
+#ifdef USE_VHD
+ int nparents = 0;
+ size_t i;
+ char **parfiles = NULL;
+#endif
+
+ options = checkquals( 0, mouquals, qualc, qualv );
+ if( options == -1 )
+ return SS$_BADPARAM;
+
+ UNUSED(argc);
+
+ if( (devices = parselist( &devs, 0, argv[1], "devices")) < 0 )
+ return SS$_BADPARAM;
+ if( parselist( &labs, devices, argv[2], "labels") < 0 ) {
+ free( devs );
+ return SS$_BADPARAM;
+ }
+#ifdef USE_VHD
+ if( options & mou_snapshot ) {
+ nparents = parselist( &parfiles, devices, parents, "parent VHD files " );
+ if( nparents != devices ) {
+ printf( "%%ODS2-E-NOTSAME, You must specify the same number of existing files (%u) with %cSNAPSHOT as filenames to create (%u)\n",
+ nparents, vms_qual? '/': '-', devices );
+ free( parfiles );
+ return SS$_BADPARAM;
+ }
+ for( i = 0; i < (size_t)nparents; i++ ) {
+ sts = phyvhd_snapshot( devs[i], parfiles[i] );
+ if( !(sts & STS$M_SUCCESS) ) {
+ if( (sts & STS$M_COND_ID) != (SS$_DUPFILENAME & STS$M_COND_ID) ) {
+ (void) unlink( devs[i] );
+ }
+ while( i > 0 ) {
+ --i;
+ (void) unlink( devs[i] );
+ }
+ free( parfiles );
+ return SS$_BADPARAM;
+ }
+ }
+ if( options & MOU_LOG ) {
+ for( i = 0; i < (size_t)nparents; i++ )
+ printf( "%%ODS2-I-SNAPOK, %s created from %s\n",
+ devs[i], parfiles[i] );
+ }
+ options |= MOU_WRITE;
+ free( parfiles );
+ parfiles = NULL;
+ }
+#endif
+
+ if (devices > 0) {
+ sts = mount( options | MOU_LOG, devices, devs, labs );
+ if( !(sts & STS$M_SUCCESS) )
+ printf("%%ODS2-E-MOUNTERR, Mount failed with %s\n", getmsg(sts, MSG_TEXT));
+ }
+
+ free( devs );
+ free( labs );
+ return sts;
+}
+
+void mounthelp(void) {
+ printf( "\n" );
+ printf( "You can mount a volume(-set) from either physical devices\n" );
+ printf( "such a CDROM or hard disk drive, or files containing an\n" );
+ printf( "image of a volume, such as a .ISO file or simulator disk\n\n" );
+ printf( "To mount a disk image, use the %cimage qualifier and\n",
+ (vms_qual? '/': '-') );
+ printf( "specify the filename as the parameter.\n\n" );
+ printf( "If the filename contains %c, specify it in double quotes\n\n",
+ (vms_qual? '/': '-') );
+ printf( "Mount will assign a virtual device name to each volume.\n" );
+ printf( "You can select a virtual device name using the format\n" );
+ printf( " dka100=my_files.iso\n\n" );
+ printf( "To mount a physical device, use the format:\n" );
+ phyio_help(stdout);
+ printf( "To mount a volume set, specify all the members in RVN order\n" );
+ printf( "as a comma-separated list.\n\n" );
+ printf( "If you specify a list of volume labels, they must be in\n" );
+ printf( "the same order as the volumes, and each must match the label\n" );
+ printf( "stored in the data\n" );
+#ifdef USE_VHD
+ printf( "\nTo create and mount a snapshot of a VHD-based volume set, use the %csnapshot_of qualifier.\n", vms_qual? '/': '-' );
+ printf( "Specify the existing volumes' filenames as an argument to %csnapshot, and\n", vms_qual? '/': '-' );
+ printf( "list the corresponding filenames to be created as the mount parameter.\n" );
+#endif
+
+ return;
+}
diff --git a/extracters/ods2/ods2.c b/extracters/ods2/ods2.c
index 0878537..755e4b4 100644
--- a/extracters/ods2/ods2.c
+++ b/extracters/ods2/ods2.c
@@ -1,90 +1,64 @@
-#define MODULE_NAME ODS2
-
-/* Feb-2016, v1.4 add readline support, dir/full etc
- * See git commit messages for details.
- * V2.1 - Merge and adapte code from Larry Baker's V2.0
- */
-
-/* Jul-2003, v1.3hb, some extensions by Hartmut Becker */
-
-/* ODS2.c V2.1 Mainline ODS2 program */
+/* main() - command parsing and dispatch */
/*
- This is part of ODS2 written by Paul Nankervis,
- email address: Paulnank@au1.ibm.com
-
- ODS2 is distributed freely for all members of the
- VMS community to use. However all derived works
- must maintain comments in their source to acknowledge
- the contibution of the original author.
-
- The modules in ODS2 are:-
-
- ACCESS.C Routines for accessing ODS2 disks
- CACHE.C Routines for managing memory cache
- COMPAT.C Routines for OS compatibility
- DEVICE.C Routines to maintain device information
- DIRECT.C Routines for handling directories
- ODS2.C The mainline program
- PHYVMS.C Routine to perform physical I/O
- PHYVIRT.C Routines for managing virtual disks.
- RMS.C Routines to handle RMS structures
- SYSMSG.C Routines to convert status codes to text
- UPDATE.C Routines for updating ODS2 structures
- VMSTIME.C Routines to handle VMS times
-
- On non-VMS platforms PHYVMS.C should be replaced as follows:-
-
- Unix PHYUNIX.C
- OS/2 PHYOS2.C
- Windows 95/NT PHYNT.C
-
- For example under OS/2 the program is compiled using the GCC
- compiler with the single command:-
-
- gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
- access.c,device.c,cache.c,phyos2.c,vmstime.c
-
- For accessing disk images (e.g. .ISO or simulator files),
- simply mount /image (or /virtual) filename.
-
- The included make/mms/com files do all this for you.
-*/
-
-/* Modified by:
- * Feb 2016 Timothe Litt
- * Bug fixes, readline support, build on NT without wnaspi32,
- * Decode error messages, patch from vms2linux.de. VS project files.
- * Rework command parsing and help. Bugs, bugs & bugs. Merge
- * code from Larry Baker, USGS. See git
- * commit history for details.
+ * This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
*
- * 31-AUG-2001 01:04 Hunter Goatley
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
*
- * For VMS, added routine getcmd() to read commands with full
- * command recall capabilities.
+ * The modules in ODS2 are:-
*
- * 8-JUN-2005 Larry Baker
+ * ACCESS.C Routines for accessing ODS2 disks
+ * CACHE.C Routines for managing memory cache
+ * COMPAT.C Routines for OS compatibility
+ * DEVICE.C Routines to maintain device information
+ * DIRECT.C Routines for handling directories
+ * ODS2.C The mainline program
+ * *CMD.C Routines to execute CLI commands
+ * PHYVMS.C Routine to perform physical I/O
+ * PHYVHD.C Interface to libvhd for VHD format virtual disks.
+ * PHYVIRT.C Routines for managing virtual disks.
+ * RMS.C Routines to handle RMS structures
+ * SYSMSG.C Routines to convert status codes to text
+ * UPDATE.C Routines for updating ODS2 structures
+ * VMSTIME.C Routines to handle VMS times
*
- * Add #include guards in .h files.
- * Use named constants in place of literals.
- * Replace BIG_ENDIAN with ODS2_BIG_ENDIAN (Linux always #defines
- * BIG_ENDIAN).
- * Add SUBST DRIVE: FILE to "mount" a file (vs. a disk).
- * Implement quoted arguments (paired " or '; no escape characters)
- * in cmdsplit(), e.g., to specify a Unix path or a null argument.
- * Remove VMSIO conditional code (need to "mount" a file now).
+ * On non-VMS platforms PHYVMS.C should be replaced as follows:-
+ *
+ * Unix PHYUNIX.C
+ * OS/2 PHYOS2.C
+ * Windows 95/NT PHYNT.C
+ *
+ * The included make/mms/com files do all this for you.
+ *
+ * For accessing disk images (e.g. .ISO or simulator files),
+ * simply mount /image (or /virtual) filename.
+ *
+ * See version.h for revision history.
*/
/* This is the top level set of routines. It is fairly
- simple minded asking the user for a command, doing some
- primitive command parsing, and then calling a set of routines
- to perform whatever function is required (for example COPY).
- Some routines are implemented in different ways to test the
- underlying routines - for example TYPE is implemented without
- a NAM block meaning that it cannot support wildcards...
- (sorry! - could be easily fixed though!)
-*/
+ * simple minded asking the user for a command, doing some
+ * primitive command parsing, and then calling a set of routines
+ * to perform whatever function is required (for example COPY).
+ * Some routines are implemented in different ways to test the
+ * underlying routines - for example TYPE is implemented without
+ * a NAM block meaning that it cannot support wildcards...
+ * (sorry! - could be easily fixed though!)
+ */
+
+#include "version.h"
+
+#if !defined( DEBUG ) && defined( DEBUG_ODS2 )
+#define DEBUG DEBUG_ODS2
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
#ifdef VMS
#ifdef __DECC
@@ -101,45 +75,19 @@
#define DEBUGx on
-#define _BSD_SOURCE
-#include /* isalpha(), isspace(), tolower() */
-
-#include
-#include
-#include
-#include
-#include
-
#include "version.h"
-#include "access.h"
+#include "cmddef.h"
+
+#include "cache.h"
#include "compat.h"
#include "descrip.h"
-#include "device.h"
-#include "direct.h"
#include "ods2.h"
-#include "phyio.h"
#include "phyvirt.h"
-#include "rms.h"
#include "ssdef.h"
#include "stsdef.h"
#include "sysmsg.h"
-#if !defined( _WIN32 ) && !defined( VMS )
-#include
-#include
-#else
-# ifdef _WIN32
-# include
-# endif
-#endif
-
-#ifdef VMS
-#include
-#else
-#include "vmstime.h"
-#endif
-
#ifdef VAXC
#ifdef EXIT_SUCCESS
#undef EXIT_SUCCESS
@@ -147,13 +95,6 @@
#define EXIT_SUCCESS SS$_NORMAL
#endif
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
#if defined( _WIN32 ) && defined(_MSC_VER) && defined( DEBUG_BUILD ) && defined( USE_VLD )
/* Normally done in the project file, but VLD is optional and I'd rather not provide
* instructions as they vary by IDE version. See http://vld.codeplex.com/ if interested.
@@ -162,1613 +103,489 @@
#pragma comment (lib,"C:\\Program Files (x86)\\Visual Leak Detector\\lib\\Win32\\vld.lib")
#endif
-#define MAXREC 32767
-#define PRINT_ATTR ( FAB$M_CR | FAB$M_PRN | FAB$M_FTN )
-
#ifdef USE_READLINE
+#ifndef _GNU_SOURCE
#define _XOPEN_SOURCE
+#endif
#include
#include
#include
#endif
-/******************************************************************* fgetline() */
-/* Read a line of input - unlimited length
- * Removes \n, returns NULL at EOF
- * Caller responsible for free()
- */
-static char *fgetline( FILE *stream, int keepnl ) {
- size_t bufsize = 0,
- xpnsize = 80,
- idx = 0;
- char *buf = NULL;
- int c;
- while( (c = fgetc(stream)) != EOF && c != '\n' ) {
- if( idx + (keepnl != 0) +2 > bufsize ) { /* In buf + char + (optional \n) + \0 */
- char *nbuf;
- bufsize += xpnsize;
- nbuf = (char *) realloc( buf, bufsize );
- if( nbuf == NULL ) {
- perror( "realloc" );
- abort();
- }
- buf = nbuf;
- }
- buf[idx++] = c;
- }
- if( c == '\n' ) {
- if( keepnl )
- buf[idx++] = '\n';
- } else {
- if( c == EOF && idx == 0 ) {
- free( buf );
- return NULL;
- }
- }
- if( bufsize == 0 ) {
- buf = (char *) malloc( 1 );
- if( buf == NULL ) {
- perror( "malloc" );
- abort();
- }
- }
- buf[idx] = '\0';
- return buf;
-}
+static int disktypecmp( const void *da, const void *db );
+static int cmdsplit( char *str );
+static int cmdexecute( int argc, char **argv, int qualc, char **qualv );
-/******************************************************************* keycomp() */
-/* keycomp: routine to compare parameter to a keyword - case insensitive! */
+DECL_CMD(copy);
+DECL_CMD(create);
+DECL_CMD(delete);
+DECL_CMD(diff);
+DECL_CMD(dir);
+DECL_CMD(dismount);
+DECL_CMD(extend);
+DECL_CMD(help);
+DECL_CMD(import);
+DECL_CMD(initial);
+DECL_CMD(mount);
+DECL_CMD(search);
+DECL_CMD(set);
+DECL_CMD(show);
+DECL_CMD(spawn);
+DECL_CMD(type);
-static int keycomp(const char *param, const char *keywrd) {
- while (*param != '\0') {
- if( tolower(*param++) != tolower(*keywrd++) ) return 0;
- }
- return 1;
-}
-/* set, clear: bits specified are cleared, then set in value
- * helpstr: if null, switch not listed in help. If starts with -,
- * listed as negatable in help
- */
-#define NV NOVAL, NULL
-#define KV(list) KEYVAL, list
-#define CV(list) KEYCOL, list
-struct qual {
- const char *name;
- int set;
- int clear;
- enum qualtype { NOVAL, KEYVAL, KEYCOL } qtype;
- void *arg;
- const char *helpstr;
-};
+#ifdef VMS
+static char *getcmd( char *inp, size_t max, char *prompt );
+#endif
-struct param;
-struct CMDSET;
-
-typedef const char *(hlpfunc_t)( struct CMDSET *cmd, struct param *p, int argc, char **argv );
-
-struct param {
- const char *name;
- enum parflags { REQ, OPT, CND } flags;
- enum partype { VMSFS, LCLFS, LIST, KEYWD, STRING, CMDNAM, NONE } ptype;
-#define PA(arg) NULL, (arg)
-#define NOPA PA(NULL)
- hlpfunc_t *hlpfnc;
- void *arg;
- const char *helpstr;
-};
-
-/* Command table entry */
-
-struct CMDSET {
- char *name;
- unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]);
- unsigned uniq;
- struct qual *validquals;
- struct param *params;
- char *helpstr;
-};
-
-static void qualhelp( int par, struct qual *qtable );
+static void add_diskkwds( qualp_t qualset, const char *qname, qualp_t *disks );
/* Qualifier style = vms = /qualifier; else -option
*/
-static int vms_qual = 1;
-static int verify_cmd = 1;
+int vms_qual = 1;
+int verify_cmd = 1;
-/******************************************************************* checkquals() */
-/* checkquals: Given valid qualifier definitions, process qualifer
- * list from a command left to right. Also handles parameters and
- * qualifier values (/Qual=value).
+/******************************************************************* Command table */
+
+/* information about the commands we know... */
+extern qual_t copyquals[], delquals[], dirquals[], importquals[],
+ iniquals[], mouquals[];
+
+extern param_t copypars[], createpars[], delpars[], diffpars[], dirpars[],
+ dmopars[], extendpars[], helppars[], importpars[], inipars[], moupars[],
+ searchpars[], setpars[], showpars[], typepars[];
+
+CMDSET_t maincmds[] = {
+ { "copy", docopy, 0,copyquals, copypars, "Copy a file from VMS to host file" },
+ { "create", docreate, 0,NULL, createpars, NULL },
+ { "delete", dodelete, 0,delquals, delpars, "Delete a VMS file" },
+ { "difference", dodiff, 0,NULL, diffpars, "Compare VMS file to host file" },
+ { "directory", dodir, 0,dirquals, dirpars, "List directory of VMS files" },
+ { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume" },
+ { "exit", NULL, 2,NULL, NULL, "Exit ODS2" },
+ { "extend", doextend, 0,NULL, extendpars, NULL },
+ { "help", dohelp, 0,NULL, helppars, "Obtain help on a command" },
+ { "import", doimport, 0,importquals,importpars, "Copy a file from host to VMS" },
+ { "initialize", doinitial,-4, iniquals, inipars, "Create a new filesystem" },
+ { "mount", domount, 0,mouquals, moupars, "Mount a VMS volume" },
+ { "quit", NULL, 2,NULL, NULL, "Exit ODS2" },
+ { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string" },
+ { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list" },
+ { "show", doshow, 0,NULL, showpars, "Display state" },
+ { "spawn", dospawn, 0,NULL, NULL, "Open a command subprocess" },
+ { "type", dotype, 0,NULL, typepars, "Display a VMS file on the terminal" },
+
+ { NULL, NULL, 0,NULL, NULL, NULL } /* ** END MARKER ** */
+};
+
+
+/*********************************************************** main() */
+
+/*
+ * Parse the command line to read and execute commands:
+ * ./ods2 mount scd1 $ set def [hartmut] $ copy *.com $ exit
+ * '$' is used as command delimiter because it is a familiar character
+ * in the VMS world. However, it should be used surounded by white spaces;
+ * otherwise, a token '$copy' is interpreted by the Unix shell as a shell
+ * variable. Quoting the whole command string might help:
+ * ./ods2 'mount scd1 $set def [hartmut] $copy *.com $exit'
+ * If the ods2 reader should use any switches '-c' should be used for
+ * the command strings, then quoting will be required:
+ * ./ods2 -c 'mount scd1 $ set def [hartmut] $ copy *.com $ exit'
+ *
+ * The same command concatenation can be implemented for the prompted input.
*/
-static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[]) {
- int i;
- const char *type;
-
- type = (qualc < 0)? "parameter": "qualifier";
- qualc = abs( qualc );
-
- for( i = 0; i < qualc; i++ ) {
- char *qv;
- struct qual *qs, *qp = NULL;
-
- qv = strchr( qualv[i], '=' );
- if( qv == NULL )
- qv = strchr( qualv[i], ':' );
- if( qv != NULL )
- *qv++ = '\0';
- for( qs = qualset; qs->name != NULL; qs++) {
- if (keycomp(qualv[i],qs->name)) {
- if( qp != NULL ) {
- printf ( "%%ODS2-W-AMBQUAL, %c%s '%s' is ambiguous\n",
- type[0], type+1, qualv[i] );
- return -1;
- }
- qp = qs;
- }
- }
- if (qp == NULL) {
- printf("%%ODS2-W-ILLQUAL, Unknown %s '%s'\n", type, qualv[i]);
- return -1;
- }
- result = (result & ~qp->clear) | qp->set;
- if( qv != NULL ) {
- char *nvp;
-
- if( qp->qtype == NOVAL ) {
- printf( "%%ODS2-W-NOQVAL, %c%s '%s' does not accept a value\n",
- toupper( *type ), type+1, qualv[i] );
- return -1;
- }
- if( *qv == '(' ) {
- qv++;
- nvp = strchr( qv, ')' );
- if( nvp == NULL ) {
- printf( "%%ODS2-W-NQP, %c%s %s is missing ')'\n",
- toupper( *type ), type+1, qualv[i] );
- return -1;
- }
- *nvp = '\0';
- }
- do {
- while( *qv == ' ' ) qv++;
- nvp = strchr( qv, ',' );
- if( nvp != NULL )
- *nvp++ = '\0';
- switch( qp->qtype ) {
- case KEYVAL:
- case KEYCOL:
- result = checkquals( result, (struct qual *)qp->arg, -1, &qv );
- if( result == -1 )
- return result;
- break;
- default:
- abort();
- }
- qv = nvp;
- } while( qv != NULL );
- }
- }
- return result;
-}
-
-/******************************************************************* dodir() */
-/*********************************************************** prvmstime() */
-
-static int prvmstime(VMSTIME vtime, const char *sfx) {
- int sts = 0;
- char tim[24];
- static const VMSTIME nil;
- struct dsc_descriptor timdsc;
-
- if( memcmp( vtime, nil, sizeof(nil) ) ) {
- timdsc.dsc_w_length = 23;
- timdsc.dsc_a_pointer = tim;
- sts = sys_asctim(0,&timdsc,vtime,0);
- if ((sts & 1) == 0) printf("%%ODS2-W-TIMERR, SYS$ASCTIM error: %s\n",getmsg(sts, MSG_TEXT));
- tim[23] = '\0';
- printf(" %s",tim);
- } else {
- printf( " %-23s", " " );
- sts = 1;
- }
- if (sfx != NULL)
- printf( "%s", sfx );
- return sts;
-}
-
-/*********************************************************** pwrap() */
-
-static void pwrap( int *pos, const char *fmt, ... ) {
- char pbuf[200], *p, *q;
- va_list ap;
- va_start(ap, fmt );
- vsnprintf( pbuf, sizeof(pbuf), fmt, ap );
- va_end(ap);
- p = pbuf;
- while( *p ) {
- int len;
- int eol = 0;
-
- q = strchr( p, '\n' );
- if( q != NULL ) {
- *q++ = '\0';
- eol = 1;
- len = strlen(p);
- } else {
- len = strlen(p);
- q = p + len;
- }
- if( *pos + len > 80 ) {
- static const char wrap[] = " ";
- printf( "\n%s", wrap );
- *pos = sizeof(wrap) -1;
- if( p[0] == ',' && p[1] == ' ' )
- p += 2;
- }
- *pos += strlen(p);
- printf( "%s%s", p, eol? "\n":"" );
- if( eol ) *pos = 0;
- p = q;
- }
-}
-
-/*********************************************************** dirtotal() */
-
-#define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size)
-#define dir_date (1 << 0)
-#define dir_fileid (1 << 1)
-#define dir_owner (1 << 2)
-#define dir_prot (1 << 3)
-#define dir_size (1 << 4)
-
-#define dir_grand (1 << 5)
-#define dir_heading (1 << 6)
-#define dir_names (1 << 7)
-#define dir_trailing (1 << 8)
-#define dir_full (1 << 9)
-#define dir_total (1 << 10)
-
-#define dir_backup (1 << 11)
-#define dir_created (1 << 12)
-#define dir_expired (1 << 13)
-#define dir_modified (1 << 14)
-#define dir_dates (dir_backup | dir_created | dir_expired | dir_modified)
-
-#define dir_allocated (1 << 15)
-#define dir_used (1 << 16)
-#define dir_sizes (dir_allocated | dir_used)
-
-#define dir_default (dir_heading|dir_names|dir_trailing)
-
-static struct qual datekwds[] = { {"created", dir_created, 0, NV, "Date file created (default)"},
- {"modified", dir_modified, 0, NV, "Date file modified"},
- {"expired", dir_expired, 0, NV, "Date file expired"},
- {"backup", dir_backup, 0, NV, "Date of last backup"},
- {NULL, 0, 0, NV, NULL}
-};
-static struct qual sizekwds[] = { {"both", dir_used|dir_allocated, 0, NV, "Both used and allocated" },
- {"allocation", dir_allocated, 0, NV, "Blocks allocated to file" },
- {"used", dir_used, 0, NV, "Blocks used in file" },
- {NULL, 0, 0, NV, NULL}
-};
-static struct qual dirquals[] = { {"brief", dir_default, ~dir_default, NV,
- "Brief display - names with header/trailer (default)"},
- {"date", dir_date, dir_dates, KV(datekwds),
- "-Include file date(s)", },
- {"nodate", 0, dir_date, NV, NULL, },
- {"file_id", dir_fileid, 0, NV, "-Include file ID", },
- {"nofile_id", 0, dir_fileid, NV, NULL },
- {"full", dir_full|dir_heading|dir_trailing,
- ~dir_full, NV, "Include full details", },
- {"grand_total", dir_grand, ~dir_grand & ~(dir_size|dir_sizes),
- NV, "-Include only grand total",},
- {"nogrand_total", 0, dir_grand, NV, NULL},
- {"heading", dir_heading, 0, NV, "-Include heading", },
- {"noheading", 0, dir_heading, NV, NULL},
- {"owner", dir_owner, 0, NV, "-Include file owner", },
- {"noowner", 0, dir_owner, NV, NULL, },
- {"protection", dir_prot, 0, NV,
- "-Include file protection", },
- {"noprotection", 0, dir_prot, NV, NULL, },
- {"size", dir_size, dir_sizes, KV(sizekwds),
- "-Include file size (blocks)", },
- {"nosize", 0, dir_size|dir_sizes,
- NV, NULL, },
- {"total", dir_total|dir_heading,
- ~dir_total & ~(dir_size|dir_sizes),
- NV,
- "Include only directory name and summary",},
- {"trailing", dir_trailing, 0, NV,
- "-Include trailing summary line",},
- {"notrailing", 0, dir_trailing, NV, NULL},
- {NULL, 0, 0, NV, NULL} };
-static int dir_defopt = dir_default;
-
-static struct param dirpars[] = { {"filespec", OPT, VMSFS, NOPA, "for files to select. Wildcards are allowed."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static void dirtotal( int options, int size, int alloc ) {
- if ( !(options & dir_size) )
- return;
- fputs( ", ", stdout );
-
- if ( options & dir_used )
- printf( "%d", size );
- if ( options & dir_allocated ) {
- if (options & dir_used) printf( "/" );
- printf( "%d", alloc );
- }
- if ((options & dir_dates) == dir_dates)
- printf( " block%s",(size ==1 && alloc == 1 ? "" : "s"));
- else
- printf( " block%s",(((options & dir_used) && size == 1) ||
- ((options & dir_allocated) && alloc == 1))? "" : "s");
- return;
-}
-
-/************************************************************ dodir() */
-
-static unsigned dodir(int argc,char *argv[],int qualc,char *qualv[]) {
- char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
- int options;
- unsigned sts;
- int filecount = 0, nobackup = 0, contigb = 0, contig = 0, directory = 0;
- struct NAM nam = cc$rms_nam;
- struct FAB fab = cc$rms_fab;
- struct XABDAT dat = cc$rms_xabdat;
- struct XABFHC fhc = cc$rms_xabfhc;
- struct XABPRO pro = cc$rms_xabpro;
- struct XABITM itm = cc$rms_xabitm;
- struct item_list xitems[] = {
- { XAB$_UCHAR_NOBACKUP, sizeof(int), NULL, 0 },
- { XAB$_UCHAR_CONTIG, sizeof(int), NULL, 0 },
- { XAB$_UCHAR_CONTIGB, sizeof(int), NULL, 0 },
- { XAB$_UCHAR_DIRECTORY, sizeof(int), NULL, 0 },
- { 0, 0, NULL, 0 }
- };
-
- UNUSED(argc);
-
- nam.nam$l_esa = res;
- nam.nam$b_ess = NAM$C_MAXRSS;
-
- fab.fab$l_nam = &nam;
- fab.fab$l_xab = &dat;
-
- dat.xab$l_nxt = &fhc;
-
- fhc.xab$l_nxt = &pro;
-
- pro.xab$l_nxt = &itm;
- xitems[0].buffer = &nobackup;
- xitems[1].buffer = &contig;
- xitems[2].buffer = &contigb;
- xitems[3].buffer = &directory;
-
- itm.xab$b_mode = XAB$K_SENSEMODE;
- itm.xab$l_itemlist = xitems;
-
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- fab.fab$l_dna = "*.*;*";
- fab.fab$b_dns = strlen(fab.fab$l_dna);
-
- options = checkquals(dir_defopt,dirquals,qualc,qualv);
- if( options == -1 )
- return SS$_BADPARAM;
-
- if (options & dir_full)
- options |= dir_extra;
- if (options & (dir_total | dir_grand)) {
- options |= dir_trailing;
- if (options & (dir_extra & ~dir_size))
- options |= dir_names;
- } else {
- if (options & dir_extra)
- options |= dir_names;
- }
- if( (options & dir_size) && !(options & dir_sizes) )
- options |= dir_used;
- if( (options & dir_date) && !(options & dir_dates) )
- options |= dir_created;
-
- sts = sys_parse(&fab);
- if ( sts & STS$M_SUCCESS ) {
- char dir[NAM$C_MAXRSS + 1];
- int namelen;
- int dirlen = 0;
- int dirfiles = 0, dircount = 0;
- int dirblocks = 0, diralloc = 0, totblocks = 0, totalloc = 0;
- int printcol = 0;
-#ifdef DEBUG
- res[nam.nam$b_esl] = '\0';
- printf("Parse: %s\n",res);
-#endif
- nam.nam$l_rsa = rsa;
- nam.nam$b_rss = NAM$C_MAXRSS;
- fab.fab$l_fop = FAB$M_NAM;
- while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
-
- if (dirlen != nam.nam$b_dev + nam.nam$b_dir ||
- memcmp(rsa, dir, nam.nam$b_dev + nam.nam$b_dir) != 0) {
- if (dirfiles > 0 && (options & dir_trailing)) {
- if (printcol > 0) printf("\n");
- printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
- dirtotal( options, dirblocks, diralloc );
- fputs(".\n",stdout);
- }
- dirlen = nam.nam$b_dev + nam.nam$b_dir;
- memcpy(dir,rsa,dirlen);
- dir[dirlen] = '\0';
- if( options & dir_heading) printf("\nDirectory %s\n\n",dir);
- filecount += dirfiles;
- totblocks += dirblocks;
- totalloc += diralloc;
- dircount++;
- dirfiles = 0;
- dirblocks = 0;
- diralloc = 0;
- printcol = 0;
- }
- rsa[nam.nam$b_rsl] = '\0';
- namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
- if ((options & (dir_heading|dir_extra|dir_full)) == dir_heading) {
- if( options & dir_names ) {
- if (printcol > 0) {
- int newcol = (printcol + 20) / 20 * 20;
- if (newcol + namelen >= 80) {
- fputs("\n",stdout);
- printcol = 0;
- } else {
- printf("%*s",newcol - printcol," ");
- printcol = newcol;
- }
- }
- fputs(rsa + dirlen,stdout);
- printcol += namelen;
- }
- } else {
- if (options & dir_names) {
- if ( (options & dir_heading) == 0 ) printf( "%s",dir );
- if (namelen > 18) {
- printf("%s",rsa + dirlen);
- if( options & dir_extra )
- printf( "\n " );
- } else {
- printf("%-19s",rsa + dirlen);
- }
- }
- sts = sys_open(&fab);
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%ODS2-E-OPENERR, Open error: %s\n", getmsg(sts, MSG_TEXT));
- } else {
- sts = sys_close(&fab);
- if (options & dir_fileid) {
- char fileid[30]; /* 24 bits, 16 bits. 8 bits = 8 + 5 + 3 digits = 16 + (,,)\0 => 21 */
- if( options & dir_full) printf( " File ID:" );
- snprintf(fileid,sizeof(fileid),"(%d,%d,%d)",
- (nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num,
- nam.nam$w_fid_seq,nam.nam$b_fid_rvn);
- printf(" %-22s",fileid);
- }
- diralloc += fab.fab$l_alq;
- if (options & dir_used) {
- unsigned filesize = fhc.xab$l_ebk;
- if (fhc.xab$w_ffb == 0) filesize--;
- dirblocks += filesize;
-
- if (options & dir_names) { /* Don't print w/o names (e.g. totals) */
- if( options & dir_full) printf( "\nSize: " );
- printf("%9d",filesize);
- if( options & (dir_allocated|dir_full)) printf( "/%-9d ",fab.fab$l_alq );
- }
- } else {
- if ( (options & (dir_allocated|dir_names)) == (dir_allocated|dir_names)) {
- printf( "%9d", fab.fab$l_alq );
- }
- }
-#define pprot(val,pos,del) {\
- unsigned int v = ~(((val) >> (pos)) & xab$m_prot); \
- if( v & xab$m_noread ) printf( "R" ); \
- if( v & xab$m_nowrite ) printf( "W" ); \
- if( v & xab$m_noexe ) printf( "E" ); \
- if( v & xab$m_nodel ) printf( "D" ); \
- printf( del ); \
- }
- if (options & dir_full) {
- int pos = 0;
-
- printf( "Owner: [%o,%o]\n", ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF);
- printf( "Created: " ); prvmstime( dat.xab$q_cdt, "\n" );
- printf( "Revised: " ); prvmstime( dat.xab$q_rdt, " (" ); printf( "%u)\n", dat.xab$w_rvn );
- printf( "Expires: " ); prvmstime( dat.xab$q_edt, "\n" );
- printf( "Backup: " ); prvmstime( dat.xab$q_bdt, "\n" );
- pwrap( &pos, "File organization: " );
- switch( fab.fab$b_org ) {
- case FAB$C_SEQ:
- pwrap( &pos, "Sequential" ); break;
- case FAB$C_REL:
- pwrap( &pos, "Relative" /*, Maximum record number %u", fab.fab$l_mrn*/ ); break;
- case FAB$C_IDX:
- pwrap( &pos, "Indexed" ); break; /*, Prolog: 3, Using 4 keys\nIn 3 areas */
- default:
- pwrap( &pos, "Unknown (%u)", fab.fab$b_org ); break;
- }
- /* File attributes: Allocation: 372, Extend: 3, Maximum bucket size: 3, Global buffer count: 0, No version limit
- Contiguous best try */
- pwrap( &pos, "\nFile attributes: " );
- pwrap( &pos, "Allocation: %u", fab.fab$l_alq );
- pwrap( &pos, ", Extend: %u", fab.fab$w_deq );
- /* Missing: , Maximum bucket size: n*/
- pwrap( &pos, ", Global buffer count: %u", fab.fab$w_gbc );
- if( fhc.xab$w_verlimit == 0 || fhc.xab$w_verlimit == 32767 )
- pwrap( &pos, ", No %sversion limit", directory? "default ": "" );
- else
- pwrap( &pos, ", %sersion limit: %u", (directory? "Default v": "V"), fhc.xab$w_verlimit );
- if( contig )
- pwrap( &pos, ", Contiguous" );
- if( contigb )
- pwrap( &pos, ", Contiguous best try" );
- if( nobackup )
- pwrap( &pos, ", Backups disabled" );
- if( directory )
- pwrap( &pos, ", Directory file" );
- pwrap( &pos, "\n" );
-
- pwrap( &pos, "Record format: " );
- switch( fab.fab$b_rfm ) {
- default:
- case FAB$C_UDF:
- pwrap( &pos, "Undefined" ); break;
- case FAB$C_FIX:
- pwrap( &pos, "Fixed length %u byte records", fab.fab$w_mrs ); break;
- case FAB$C_VAR:
- pwrap( &pos, "Variable length, maximum %u bytes", fab.fab$w_mrs ); break;
- case FAB$C_VFC:
- pwrap( &pos, "Variable length, fixed carriage control %u, maximum %u bytes", (fab.fab$b_fsz? fab.fab$b_fsz: 2), fab.fab$w_mrs ); break;
- case FAB$C_STM:
- pwrap( &pos, "Stream" ); break;
- case FAB$C_STMLF:
- pwrap( &pos, "Stream-LF" ); break;
- case FAB$C_STMCR:
- pwrap( &pos, "Stream-CR" ); break;
- }
- pwrap( &pos, "\n" );
-
- pwrap( &pos, "Record attributes: " );
- if( fab.fab$b_rat == 0 )
- pwrap( &pos, "None" );
- else {
- const char *more = "";
- if( fab.fab$b_rat & FAB$M_FTN ) {
- pwrap( &pos, "%sFortran carriage control", more );
- more = ", ";
- }
- if( fab.fab$b_rat & FAB$M_CR ) {
- pwrap( &pos, "%sCarriage return carriage control", more );
- more = ", ";
- }
- if( fab.fab$b_rat & FAB$M_PRN ) {
- pwrap( &pos, "%sPrinter control", more );
- more = ", ";
- }
- if( fab.fab$b_rat & FAB$M_BLK ) {
- pwrap( &pos, "%sNon-spanned", more );
- }
- }
- printf( "\n" );
- /*
-RMS attributes: None
-Journaling enabled: None
-*/
- printf( "File protection: System:" );
- pprot(pro.xab$w_pro,xab$v_system,", Owner:")
- pprot(pro.xab$w_pro,xab$v_owner,", Group:")
- pprot(pro.xab$w_pro,xab$v_group,", World:")
- pprot(pro.xab$w_pro,xab$v_world,"\n");
- } else { /* !full */
- if (options & dir_date) {
- if( options & dir_created )
- sts = prvmstime( dat.xab$q_cdt, NULL );
- if( options & dir_modified )
- sts = prvmstime( dat.xab$q_rdt, NULL );
- if( options & dir_expired )
- sts = prvmstime( dat.xab$q_edt, NULL );
- if( options & dir_backup )
- sts = prvmstime( dat.xab$q_bdt, NULL );
- }
- if (options & dir_owner) {
- printf(" [%o,%o]", ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF);
- }
- if (options & dir_prot) {
- printf( " (" );
- pprot(pro.xab$w_pro,xab$v_system,",")
- pprot(pro.xab$w_pro,xab$v_owner,",")
- pprot(pro.xab$w_pro,xab$v_group,",")
- pprot(pro.xab$w_pro,xab$v_world,")")
- }
- }
-#undef pprot
- if (options & dir_names)
- printf("\n");
- }
- }
- dirfiles++;
- }
- if (sts == RMS$_NMF) sts = SS$_NORMAL;
- if (printcol > 0) printf("\n");
- if (options & dir_trailing) {
- printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
- dirtotal( options, dirblocks, diralloc );
- fputs(".\n",stdout);
- }
- filecount += dirfiles;
- totblocks += dirblocks;
- totalloc += diralloc;
- if (options & dir_grand) {
- printf("\nGrand total of %d director%s, %d file%s",
- dircount,(dircount == 1 ? "y" : "ies"),
- filecount,(filecount == 1 ? "" : "s"));
- dirtotal( options, totblocks, totalloc );
- fputs(".\n",stdout);
- }
- }
- if ( sts & STS$M_SUCCESS ) {
- if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n");
- } else {
- printf("%%DIR-E-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/******************************************************************* docopy() */
-
-/* copy: a file copy routine */
-
-#define COP_BINARY 1
-
-static struct qual copyquals[] = { {"ascii", 0, COP_BINARY, NV, "Copy file in ascii mode (default)"},
- {"binary", COP_BINARY, 0, NV, "Copy file in binary mode", },
- {NULL, 0, 0, NV, NULL}
-};
-
-static struct param copypars[] = { {"from_filespec", REQ, VMSFS, NOPA,
- "for source file. Wildcards are allowed."},
- {"to_filespec", REQ, LCLFS, NOPA,
- "for destination file. Wildcards are replaced from source file name."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned docopy(int argc,char *argv[],int qualc,char *qualv[]) {
- int sts,options;
- struct NAM nam = cc$rms_nam;
- struct FAB fab = cc$rms_fab;
- char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
- int filecount = 0;
-
- UNUSED(argc);
-
- nam.nam$l_esa = res;
- nam.nam$b_ess = NAM$C_MAXRSS;
- fab.fab$l_nam = &nam;
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- options = checkquals(0,copyquals,qualc,qualv);
- if( options == -1 )
- return SS$_BADPARAM;
- sts = sys_parse(&fab);
- if ( sts & STS$M_SUCCESS ) {
- nam.nam$l_rsa = rsa;
- nam.nam$b_rss = NAM$C_MAXRSS;
- fab.fab$l_fop = FAB$M_NAM;
- while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
- sts = sys_open(&fab);
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%COPY-F-OPENFAIL, Open error: %s\n",getmsg(sts, MSG_TEXT));
- perror("-COPY-F-ERR ");
- } else {
- struct RAB rab = cc$rms_rab;
- rab.rab$l_fab = &fab;
- if ((sts = sys_connect(&rab)) & STS_M_SUCCESS) {
- FILE *tof;
- char name[NAM$C_MAXRSS + 1];
- unsigned records = 0;
- {
- char *out = name,*inp = argv[2]; /* unquote(argv[2]) */
- int dot = FALSE;
- while (*inp != '\0') {
- if (*inp == '*') {
- inp++;
- if (dot) {
- memcpy(out,nam.nam$l_type + 1,
- nam.nam$b_type - 1);
- out += nam.nam$b_type - 1;
- } else {
- unsigned length = nam.nam$b_name;
- if (*inp == '\0') length += nam.nam$b_type;
- memcpy(out,nam.nam$l_name,length);
- out += length;
- }
- } else {
- if (*inp == '.') {
- dot = TRUE;
- } else {
- if (strchr(":]\\/",*inp)) dot = FALSE;
- }
- *out++ = *inp++;
- }
- }
- *out++ = '\0';
- }
-#ifndef _WIN32
- tof = openf(name,"w");
-#else
- if ((options & 1) == 0 && fab.fab$b_rat & PRINT_ATTR) {
- tof = openf(name,"w");
- } else {
- tof = openf(name,"wb");
- }
-#endif
- if (tof == NULL) {
- printf("%%COPY-F-OPENOUT, Could not open %s\n",name);
- perror("-COPY-F-ERR ");
- } else {
- char rec[MAXREC + 2];
- filecount++;
- rab.rab$l_ubf = rec;
- rab.rab$w_usz = MAXREC;
- while ( ( sts = sys_get( &rab ) ) & STS$M_SUCCESS ) {
- unsigned rsz = rab.rab$w_rsz;
- if ((options & 1) == 0 &&
- fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
- if (fwrite(rec,rsz,1,tof) == 1) {
- records++;
- } else {
- printf("%%COPY-F- fwrite error!!\n");
- perror("-COPY-F-ERR ");
- break;
- }
- }
- if (fclose(tof)) {
- printf("%%COPY-F- fclose error!!\n");
- perror("-COPY-F-ERR ");
- }
- }
- sys_disconnect(&rab);
- rsa[nam.nam$b_rsl] = '\0';
- if (sts == RMS$_EOF) {
- printf(
- "%%COPY-S-COPIED, %s copied to %s (%d record%s)\n",
- rsa,name,records,(records == 1 ? "" : "s")
- );
- } else {
- printf("%%COPY-F-ERROR Status: %s for %s\n",getmsg(sts, MSG_TEXT),rsa);
- sts = SS$_NORMAL;
- }
- }
- sys_close(&fab);
- }
- }
- if (sts == RMS$_NMF) sts = SS$_NORMAL;
- }
- if ( sts & STS$M_SUCCESS ) {
- if (filecount > 0) printf("%%COPY-S-NEWFILES, %d file%s created\n",
- filecount,(filecount == 1 ? "" : "s"));
- } else {
- printf("%%COPY-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/***************************************************************** doimport() */
-
-static struct qual importquals[] = { {"ascii", 0, COP_BINARY, NV,
- "Transfer file in ascii mode (default)"},
- {"binary", COP_BINARY, 0, NV, "Transfer file in binary mode", },
- {NULL, 0, 0, NV, NULL}
-};
-static struct param importpars[] = { {"from_filespec", REQ, LCLFS, NOPA, "for source file."},
- {"to_filespec", REQ, VMSFS, NOPA, "for destination file."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned doimport( int argc, char *argv[], int qualc, char *qualv[] ) {
- int options;
- unsigned sts;
- char *name;
- FILE *fromf;
- struct FAB fab = cc$rms_fab;
- struct RAB rab = cc$rms_rab;
-
- UNUSED(argc);
-
- options = checkquals( 0, importquals, qualc, qualv );
- if( options == -1 )
- return SS$_BADPARAM;
-
- sts = SS$_BADFILENAME;
- name = argv[1]; /*unquote( argv[1] );*/
- if ( *name == '\0' ) {
- return sts;
- }
- fromf = openf( name, (options & COP_BINARY)? "rb": "r" );
- if( fromf == NULL ) {
- printf( "%%ODS2-E-OPENERR, Can't open %s\n", name );
- perror( " - " );
- return sts;
- }
- fab.fab$b_fac = FAB$M_PUT;
- fab.fab$l_fop = FAB$M_OFP | FAB$M_TEF;
- fab.fab$b_org = FAB$C_SEQ;
- if( options & COP_BINARY ) {
- fab.fab$w_mrs = 512;
- fab.fab$b_rfm = FAB$C_FIX;
- } else {
- fab.fab$b_rat = 0;
- fab.fab$b_rfm = FAB$C_STM;
- }
-
- fab.fab$l_fna = argv[2];
- fab.fab$b_fns = strlen( fab.fab$l_fna );
- sts = sys_create( &fab );
- if ( sts & STS$M_SUCCESS ) {
- rab.rab$l_fab = &fab;
- sts = sys_connect( &rab );
- if ( sts & STS$M_SUCCESS ) {
- if( options & COP_BINARY ) {
- char buf[512];
- size_t len;
-
- rab.rab$l_rbf = buf;
- while( (len = fread( buf, 1, 512, fromf )) > 0 ) {
- if( len != 512 )
- memset( buf+len, 0, 512-len );
- rab.rab$w_rsz = len;
- sts = sys_put( &rab );
- if ( !( sts & STS$M_SUCCESS ) ) {
- break;
- }
- }
- } else {
- while ( (rab.rab$l_rbf = fgetline( fromf, TRUE )) != NULL ) {
- rab.rab$w_rsz = strlen( rab.rab$l_rbf );
- sts = sys_put( &rab );
- free( rab.rab$l_rbf );
- if ( !( sts & STS$M_SUCCESS ) ) {
- break;
- }
- }
- }
- sys_disconnect( &rab );
- }
- sys_close( &fab );
- }
- fclose( fromf );
- if ( !(sts & STS$M_SUCCESS) ) {
- printf("%%IMPORT-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
-
- return sts;
-}
-
-/******************************************************************* dodiff() */
-
-/* dodiff: a simple file difference routine */
-
-static struct param diffpars[] = { {"ods-2_filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
- {"local_filespec", REQ, LCLFS, NOPA, "for file on local filesystem."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-unsigned dodiff(int argc,char *argv[],int qualc,char *qualv[]) {
- int sts, records = 0;
- char rec[MAXREC + 2], *cpy = NULL;
- char *name;
- FILE *tof;
- struct FAB fab = cc$rms_fab;
- struct RAB rab = cc$rms_rab;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- name = argv[1];
- sts = SS$_BADFILENAME;
- if ( *name == '\0' ) {
- return sts;
- }
- records = 0;
- fab.fab$l_fna = name;
- fab.fab$b_fns = strlen( fab.fab$l_fna );
- tof = openf( argv[2], "r" );
- if ( tof == NULL ) {
- printf("%%ODS2-E-OPENERR, Could not open file %s\n",name);
- perror( " - " );
- return SS$_NOSUCHFILE;
- }
- sts = sys_open( &fab );
- if ( sts & STS$M_SUCCESS ) {
- rab.rab$l_fab = &fab;
- sts = sys_connect( &rab );
- if( sts & STS$M_SUCCESS ) {
- rab.rab$l_ubf = rec;
- rab.rab$w_usz = MAXREC;
- while( (sts = sys_get( &rab )) & STS$M_SUCCESS ) {
- rec[rab.rab$w_rsz] = '\0';
- cpy = fgetline( tof, FALSE );
- if( cpy == NULL ||
- rab.rab$w_rsz != strlen( cpy ) ||
- memcmp(rec,cpy,rab.rab$w_rsz) != 0 ) {
-
- printf("%%DIFF-F-DIFFERENT Files are different!\n");
- sts = 4;
- break;
- }
- free(cpy);
- cpy = NULL;
- records++;
- }
- if( cpy != NULL ) free(cpy);
- sys_disconnect(&rab);
- }
- sys_close(&fab);
- }
- fclose(tof);
- if (sts == RMS$_EOF) sts = SS$_NORMAL;
- if ( sts & STS$M_SUCCESS ) {
- printf( "%%DIFF-I-Compared %d records\n", records );
- } else if ( sts != 4 ) {
- printf("%%DIFF-F-Error %s in difference\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/******************************************************************* dotype() */
-
-/* dotype: a file TYPE routine */
-
-static struct param typepars[] = { {"filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned dotype(int argc,char *argv[],int qualc,char *qualv[]) {
+int main( int argc,char **argv ) {
int sts;
- int records;
- struct FAB fab = cc$rms_fab;
- struct RAB rab = cc$rms_rab;
+ FILE *atfile = NULL;
+ char *rl = NULL;
+ qualp_t disks = NULL;
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- records = 0;
-
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- sts = sys_open( &fab );
- if ( sts & STS$M_SUCCESS ) {
- rab.rab$l_fab = &fab;
- sts = sys_connect( &rab );
- if ( sts & STS$M_SUCCESS ) {
- char rec[MAXREC + 2];
- rab.rab$l_ubf = rec;
- rab.rab$w_usz = MAXREC;
- while ( ( sts = sys_get( &rab ) ) & STS$M_SUCCESS ) {
- unsigned rsz = rab.rab$w_rsz;
- if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
- rec[rsz++] = '\0';
- fputs(rec,stdout);
- records++;
- }
- sys_disconnect(&rab);
- }
- sys_close(&fab);
- if (sts == RMS$_EOF) sts = SS$_NORMAL;
- }
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%TYPE-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/***************************************************************** dosearch() */
-
-/* dosearch: a simple file search routine */
-
-static struct param searchpars[] = { {"filespec", REQ, VMSFS, NOPA, "for file to search. Wildcards are allowed."},
- {"string", REQ, STRING, NOPA, "string to search for."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned dosearch(int argc,char *argv[],int qualc,char *qualv[]) {
- int sts = 0;
- int filecount = 0;
- int findcount = 0;
- char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
- register char firstch, *searstr, *searend, *s;
- struct NAM nam = cc$rms_nam;
- struct FAB fab = cc$rms_fab;
- struct RAB rab = cc$rms_rab;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- searstr = argv[2]; /* unquote( argv[2] ); */
-
- searend = searstr + strlen( searstr );
- for ( s = searstr; s < searend; s++ ) {
- *s = tolower( *s );
- }
- firstch = *searstr++;
- filecount = 0;
- findcount = 0;
- nam = cc$rms_nam;
- fab = cc$rms_fab;
- nam.nam$l_esa = res;
- nam.nam$b_ess = NAM$C_MAXRSS;
- fab.fab$l_nam = &nam;
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- fab.fab$l_dna = "";
- fab.fab$b_dns = strlen(fab.fab$l_dna);
- sts = sys_parse(&fab);
- if ( sts & STS$M_SUCCESS ) {
- nam.nam$l_rsa = rsa;
- nam.nam$b_rss = NAM$C_MAXRSS;
- fab.fab$l_fop = FAB$M_NAM;
- while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
- sts = sys_open(&fab);
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%SEARCH-F-OPENFAIL, Open error: %s\n",getmsg(sts, MSG_TEXT));
- } else {
- rab.rab$l_fab = &fab;
- sts = sys_connect( &rab );
- if ( sts & STS$M_SUCCESS ) {
- int printname = 1;
- char rec[MAXREC + 2];
- filecount++;
- rab.rab$l_ubf = rec;
- rab.rab$w_usz = MAXREC;
- while ( ( sts = sys_get( &rab ) ) & STS$M_SUCCESS ) {
- register char *strng = rec;
- register char *strngend = strng + (rab.rab$w_rsz -
- (searend - searstr));
- while (strng < strngend) {
- register char ch = *strng++;
- if (ch == firstch ||
- (ch >= 'A' && ch <= 'Z' &&
- ch + 32 == firstch)) {
- register char *str = strng;
- register char *cmp = searstr;
- while (cmp < searend) {
- register char ch2 = *str++;
- ch = *cmp;
- if (ch2 != ch &&
- (ch2 < 'A' || ch2 > 'Z' ||
- ch2 + 32 != ch)) break;
- cmp++;
- }
- if (cmp >= searend) {
- findcount++;
- rec[rab.rab$w_rsz] = '\0';
- if (printname) {
- rsa[nam.nam$b_rsl] = '\0';
- printf(
- "\n******************************\n"
- );
- printf("%s\n\n",rsa);
- printname = 0;
- }
- fputs(rec,stdout);
- if (fab.fab$b_rat & PRINT_ATTR) {
- fputc('\n',stdout);
- }
- break;
- }
- }
- }
- }
- sys_disconnect(&rab);
- }
- if (sts == SS$_NOTINSTALL) {
- printf(
- "%%SEARCH-W-NOIMPLEM, file operation not implemented\n"
- );
- sts = SS$_NORMAL;
- }
- sys_close(&fab);
- }
- }
- if (sts == RMS$_NMF || sts == RMS$_FNF) sts = SS$_NORMAL;
- }
- if ( sts & STS$M_SUCCESS ) {
- if (filecount < 1) {
- printf("%%SEARCH-W-NOFILES, no files found\n");
- } else {
- if (findcount < 1) {
- printf("%%SEARCH-I-NOMATCHES, no strings matched\n");
- }
- }
- } else {
- printf("%%SEARCH-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/***************************************************************** dodelete() */
-
-/* dodelete: you don't want to know! */
-
-static struct qual delquals[] = { {"log", 1, 0, NV, "-List name of each file deleted. (Default)"},
- {"nolog", 0, 1, NV, NULL },
- { NULL, 0, 0, NV, NULL }
-};
-static struct param delpars[] = { {"filespec", REQ, VMSFS, NOPA,
- "for files to be deleted from ODS-2 volume. Wildcards are permitted.."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned dodelete(int argc,char *argv[],int qualc,char *qualv[]) {
- int sts = 0;
- char res[NAM$C_MAXRSS + 1], rsa[NAM$C_MAXRSS + 1];
- struct NAM nam = cc$rms_nam;
- struct FAB fab = cc$rms_fab;
- int options, filecount = 0;
-
- UNUSED(argc);
-
- options = checkquals(1,delquals,qualc,qualv);
- if( options == -1 )
- return SS$_BADPARAM;
-
- nam.nam$l_esa = res;
- nam.nam$b_ess = NAM$C_MAXRSS;
- fab.fab$l_nam = &nam;
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- sts = sys_parse(&fab);
- if ( sts & STS$M_SUCCESS ) {
- if (nam.nam$b_ver < 2) {
- printf("%%DELETE-F-NOVER, you must specify a version!!\n");
- return SS$_BADPARAM;
- }
-
- nam.nam$l_rsa = rsa;
- nam.nam$b_rss = NAM$C_MAXRSS;
- fab.fab$l_fop = FAB$M_NAM;
- while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
- sts = sys_erase(&fab);
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%DELETE-F-DELERR, Delete error: %s\n",getmsg(sts, MSG_TEXT));
- break;
- } else {
- filecount++;
- if( options & 1 ) {
- rsa[nam.nam$b_rsl] = '\0';
- if( options & 1 )
- printf("%%DELETE-I-DELETED, Deleted %s\n",rsa);
- }
- }
- }
- if (sts == RMS$_NMF) sts = SS$_NORMAL;
- }
- if ( sts & STS$M_SUCCESS ) {
- if (filecount < 1) {
- printf("%%DELETE-W-NOFILES, no files deleted\n");
- }
- } else {
- printf("%%DELETE-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
-
- return sts;
-}
-
-/******************************************************************* dotest() */
-
-static struct param testpars[] = { {"parameter", REQ, STRING, NOPA, "for test."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-struct VCB *test_vcb;
-
-/* dotest: you don't want to know! */
-
-static unsigned dotest( int argc, char *argv[], int qualc, char *qualv[] ) {
- unsigned sts = 0;
- struct fiddef fid;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- sts = update_create( test_vcb, NULL, "Test.File", &fid, NULL );
- printf( "Test status of %d (%s)\n", sts, argv[1] );
- return sts;
-}
-
-/***************************************************************** doextend() */
-
-/* more test code... */
-
-static struct param extendpars[] = { {"ods-2_filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
- { NULL, 0, 0, NOPA, NULL }
-};
-
-static unsigned doextend(int argc,char *argv[],int qualc,char *qualv[]) {
- int sts;
- struct FAB fab = cc$rms_fab;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- fab.fab$l_fna = argv[1];
- fab.fab$b_fns = strlen(fab.fab$l_fna);
- fab.fab$b_fac = FAB$M_UPD;
- sts = sys_open( &fab );
- if ( sts & STS$M_SUCCESS ) {
- fab.fab$l_alq = 32;
- sts = sys_extend(&fab);
- sys_close(&fab);
- }
- if ( !( sts & STS$M_SUCCESS ) ) {
- printf("%%EXTEND-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
-}
-
-/****************************************************************** dostats() */
-
-/* dostats: print some simple statistics */
-
-static unsigned dostats( void ) {
-
- printf("Statistics:-\n");
- direct_show();
- cache_show();
- phyio_show(SHOW_STATS);
-
- return SS$_NORMAL;
-}
-
-/******************************************************************* doshow() */
-
-/*********************************************************** show_version() */
-
-#define MNAMEX(n) #n
-#define MNAME(n) MNAMEX(n)
-
-static void show_version( void ) {
- printf(" %s %s", MNAME(MODULE_NAME), MODULE_IDENT );
- printf( " built %s %s", __DATE__, __TIME__ );
+#ifdef VMS
+ char str[2048];
+#endif
#ifdef USE_READLINE
- printf(" with readline version %s", rl_library_version );
+ char *p;
+ wordexp_t wex;
+ char *hfname = NULL;
+ char mname[3+sizeof( MNAME(MODULE_NAME) )];
+
+ snprintf( mname, sizeof(mname ), "~/.%s", MNAME(MODULE_NAME) );
+ rl_readline_name =
+ p = mname+3;
+ do {
+ *p = tolower( *p );
+ } while( *p++ );
+ memset( &wex, 0, sizeof( wordexp_t ) );
+ if( wordexp( mname, &wex, WRDE_NOCMD ) == 0 && wex.we_wordc == 1 ) {
+ hfname = wex.we_wordv[0];
+ history_truncate_file( hfname, 200 );
+ stifle_history( 200 );
+ read_history( hfname );
+ }
#endif
-#ifdef USE_WNASPI32
-# ifdef USE_READLINE
- printf( " and" );
-# else
- printf( " with" );
-# endif
- printf( " direct SCSI access support");
+ sts = sys_initialize();
+ if( !(sts & STS$M_SUCCESS) ) {
+ printf( "Unable to initialize library: %s\n", getmsg( sts, MSG_TEXT ) );
+ exit(EXIT_FAILURE);
+ }
+
+ add_diskkwds( mouquals, DT_NAME, &disks );
+ add_diskkwds( iniquals, DT_NAME, &disks );
+
+ argc--;
+ argv++;
+
+ while( 1 ) {
+ char *ptr = NULL;
+
+ if( argc > 0 ) {
+ size_t n, al = 0;
+
+ free( rl );
+ rl = NULL;
+
+ for( n = 0; n < (unsigned)argc; n++ )
+ if( !strcmp( "$", argv[n] ) )
+ break;
+ else
+ al += 1 + strlen( argv[n] );
+ if( al > 0 ) {
+ size_t i;
+ char *cp;
+
+ cp =
+ rl = (char *) malloc( al );
+ if( rl == NULL ) {
+ perror( "malloc" );
+ exit( EXIT_FAILURE );
+ }
+ for( i = 0; i < n; i++ ) {
+ size_t len;
+
+ len = strlen( *argv );
+ if( i != 0 )
+ *cp++ = ' ';
+ memcpy( cp, *argv++, len );
+ argc--;
+ cp += len;
+ }
+ *cp = '\0';
+
+ ptr = rl;
+#ifdef USE_READLINE
+ if( *ptr )
+ add_history( ptr );
#endif
- printf( "\n " );
- phyio_show( SHOW_FILE64 );
- putchar( '\n' );
+ }
+ if( argc > 0 ) {
+ argc--;
+ argv++;
+ }
+ }
+ if( ptr == NULL ) {
+ if (atfile != NULL) {
+ free( rl );
+ if( (rl = fgetline( atfile, FALSE )) == NULL) {
+ fclose(atfile);
+ atfile = NULL;
+ } else {
+#ifndef _WIN32
+ ptr = strchr( rl, '\r' );
+ if( ptr != NULL )
+ *ptr = '\0';
+#endif
+ if( verify_cmd )
+ printf("%c> %s\n", (vms_qual? '$': '-'), rl );
+ }
+ ptr = rl;
+ }
+ if( ptr == NULL ) {
+#ifdef VMS
+ if( getcmd( str, sizeof(str),
+ (vms_qual? "$> ": "-> ") ) == NULL )
+ break;
+ ptr = str;
+#else
+ free( rl );
+#ifdef USE_READLINE
+ rl =
+ ptr = readline( vms_qual?
+ MNAME(MODULE_NAME) "$> ": MNAME(MODULE_NAME) "-> " );
+ if (rl == NULL) {
+ break;
+ } else {
+ if( *rl != '\0' ) {
+ add_history( rl );
+ }
+ }
+#else
+ printf( "%s", vms_qual? "$> ": "-> " );
+ if( (rl = fgetline(stdin, FALSE)) == NULL ) break;
+ ptr = rl;
+#endif
+#endif
+ }
+ }
+
+ while( *ptr == ' ' || *ptr == '\t' )
+ ptr++;
+ if( !strlen(ptr) || *ptr == '!' || *ptr == ';' )
+ continue;
+
+ if (*ptr == '@') {
+ if (atfile != NULL) {
+ printf("%%ODS2-W-INDIRECT, nested indirect command files not supported\n");
+ } else {
+ if( (atfile = openf( ptr + 1, "r" )) == NULL ) {
+ perror("%%ODS2-E-INDERR, Failed to open indirect command file");
+ putchar( '\n' );
+ argc = 0;
+ }
+ }
+ continue;
+ }
+
+ sts = cmdsplit(ptr);
+ if( sts == -1 )
+ break;
+ if( !(sts & STS$M_SUCCESS) ) {
+ if( atfile != NULL ) {
+ fclose(atfile);
+ atfile = NULL;
+ }
+ argc = 0;
+ }
+ } /* while 1 */
+
+ free( rl );
+
+#ifdef USE_READLINE
+ if( hfname != NULL ) {
+ write_history( hfname );
+ clear_history();
+ }
+ wordfree( &wex ); /* hfname points into wex and should not be free()d */
+#endif
+ if (atfile != NULL)
+ fclose(atfile);
+
+ free( disks );
+
+ exit( EXIT_SUCCESS );
+}
+
+/***************************************************************** add_diskkwds() */
+/* Build parser keyword list from disk table entries */
+static void add_diskkwds( qualp_t qualset, const char *qname, qualp_t *disks ) {
+ qualp_t qp;
+
+ if( *disks == NULL ) {
+ disktypep_t dp;
+ size_t n = 0;
+
+ for( dp = disktype; dp->name != NULL; dp++ )
+ ;
+ n = (size_t) (dp - disktype);
+ if( (n << MOU_V_DEVTYPE) & ~MOU_DEVTYPE )
+ abort(); /* MOU_DEVTYPE isn't wide enough for the max index */
+
+ *disks = (qualp_t)calloc( n+1, sizeof( qual_t ) );
+ if( *disks == NULL ) {
+ perror( "malloc" );
+ exit( EXIT_FAILURE );
+ }
+ /* Do NOT sort 1st element (default, must have search seq 1)
+ * or last - list terminator.
+ */
+ qsort( disktype+1, n - 1, sizeof( disktype_t ),
+ disktypecmp );
+
+ for( qp = *disks, dp = disktype; dp->name != NULL; dp++, qp++ ) {
+ qp->name = dp->name;
+ qp->set = OPT_NOSORT | (int)((dp-disktype) << MOU_V_DEVTYPE);
+ qp->clear = MOU_DEVTYPE;
+ qp->qtype = NOVAL;
+ if( dp != disktype )
+ qp->helpstr = "";
+ }
+
+ }
+ for( qp = qualset; qp->name != NULL; qp++ )
+ if( !strcmp( qp->name, qname ) )
+ break;
+ if( qp->name == NULL )
+ abort();
+
+ qp->arg = *disks;
+
return;
}
-/*********************************************************** doshow() */
+/***************************************************************** disktypecmp() */
-static struct qual showkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
- {"default", 1, 0, NV, "Default directory on VMS volume"},
- {"devices", 2, 0, NV, "Devices"},
- {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)" },
- {"statistics", 4, 0, NV, "Debugging statistics"},
- {"time", 5, 0, NV, "Time"},
- {"verify", 6, 0, NV, "Command file echo" },
- {"version", 7, 0, NV, "Version"},
- {"volumes", 8, 0, NV, "Mounted volume information" },
- {NULL, 0, 0, NV, NULL }
-};
-static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), "" },
- {NULL, 0, 0, NOPA, NULL }
-};
+static int disktypecmp( const void *da, const void *db ) {
-unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) {
- int parnum;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- parnum = checkquals( 0, showkwds, -1, argv+1 );
- switch( parnum ) {
- default:
- return SS$_BADPARAM;
- case 0: {
- size_t size = 32;
- char *buf = NULL;
- while( 1 ) {
- char *nbuf;
- nbuf = (char *)realloc( buf, size );
- if( nbuf == NULL ) {
- free( buf );
- return SS$_INSFMEM;
- }
- buf = nbuf;
- if( getcwd( buf, size ) != NULL )
- break;
- if( errno != ERANGE ) {
- perror( "getcwd" );
- return SS$_BADPARAM;
- }
- size *= 2;
- }
- printf( " Current working directory is %s\n", buf );
- free( buf );
- return SS$_NORMAL;
- }
- case 1: {
- int sts;
- unsigned short curlen;
- char curdir[NAM$C_MAXRSS + 1];
- struct dsc_descriptor curdsc;
- curdsc.dsc_w_length = NAM$C_MAXRSS;
- curdsc.dsc_a_pointer = curdir;
- sts = sys_setddir( NULL, &curlen, &curdsc );
- if ( sts & STS$M_SUCCESS ) {
- curdir[curlen] = '\0';
- puts( curdir );
- } else {
- printf("%%ODS2-E-GETDEF, Error %s getting default\n",getmsg(sts, MSG_TEXT));
- }
- return sts;
- }
- case 2:
- phyio_show( SHOW_DEVICES );
- virt_show( NULL );
- return SS$_NORMAL;
- case 3:
- printf ( " Qualifier style: %s\n", vms_qual? "/VMS": "-unix" );
- return SS$_NORMAL;
- case 4:
- return dostats();
- case 5: {
- unsigned sts;
- char timstr[24];
- unsigned short timlen;
- struct dsc_descriptor timdsc;
-
- timdsc.dsc_w_length = 20;
- timdsc.dsc_a_pointer = timstr;
- sts = sys$asctim( &timlen, &timdsc, NULL, 0 );
- if ( sts & STS$M_SUCCESS ) {
- timstr[timlen] = '\0';
- printf(" %s\n",timstr);
- } else {
- printf("%%SHOW-W-TIMERR error %s\n",getmsg(sts, MSG_TEXT));
- }
- }
- return SS$_NORMAL;
- case 6:
- printf( "Command file verification is %s\n", (verify_cmd? "on": "off") );
- return SS$_NORMAL;
- case 7:
- show_version();
- return SS$_NORMAL;
- case 8:
- show_volumes();
- return SS$_NORMAL;
- }
- return SS$_NORMAL;
+ return strcmp( ((disktypep_t )da)[0].name,
+ ((disktypep_t )db)[0].name );
}
-/******************************************************************* doset() */
-/*********************************************************** setdef() */
+/***************************************************************** cmdsplit() */
-static int default_set = FALSE;
+/* cmdsplit: break a command line into its components */
-static unsigned setdef( char *newdef ) {
- register unsigned sts;
- struct dsc_descriptor defdsc;
+/*
+ * Feature for Unix: '//' or '--' stops qualifier parsing.
+ * This enables us to copy to Unix directories with VMS style /qualifiers.
+ * copy /bin // *.com /tmp/ *
+ * is split into argv[0] -> "*.com" argv[1] -> "/tmp/ *" qualv[0]-> "/bin"
+ *
+ * Of course, one can just "" the string (VMS double quote rules)...
+ */
+#define MAXITEMS 32
+static int cmdsplit( char *str ) {
+ int argc = 0,qualc = 0;
+ char *argv[MAXITEMS],*qualv[MAXITEMS];
+ char *sp = str;
+ int i;
+ char q = vms_qual? '/': '-';
- defdsc.dsc_a_pointer = (char *) newdef;
- defdsc.dsc_w_length = (unsigned short)strlen( defdsc.dsc_a_pointer );
- sts = sys_setddir( &defdsc, NULL, NULL );
- if ( sts & STS$M_SUCCESS ) {
- default_set = TRUE;
- } else {
- printf( "%%ODS2-E-SETDEF, Error %s setting default to %s\n", getmsg(sts, MSG_TEXT), newdef );
- }
- return sts;
-}
+ for( i = 0; i < MAXITEMS; i++ )
+ argv[i] = qualv[i] = "";
-static unsigned setcwd( char *newdef ) {
- if( chdir( newdef ) != 0 ) {
- printf( "%%ODS2-W-SETDEF, Error %s setting cwd to %s\n",
- strerror( errno ), newdef );
- return SS$_BADPARAM;
- }
- return SS$_NORMAL;
-}
-
-/************************************************************ sethelp() */
-
-static hlpfunc_t sethelp;
-
-static struct qual setkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
- {"directory_qualifiers", 1, 0, NV, "Default qualifiers for DIRECTORY command" },
- {"default", 2, 0, NV, "Default directory on VMS volume"},
- {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)"},
- {"verify", 4, 0, NV, "-Display commands in indirect files"},
- {"noverify", 5, 0, NV, NULL },
- {NULL, 0, 0, NV, NULL }
-};
-static struct qual setqskwds[] = {{"unix", 1, 0, NV, "Unix style options, '-option'"},
- {"vms", 2, 0, NV, "VMS style qualifiers, '/qualifier'"},
- {NULL, 0, 0, NV, NULL }
-};
-static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), "" },
- {"value" , CND, KEYWD, sethelp, setqskwds, "" },
- {NULL, 0, 0, NOPA, NULL },
-};
-
-static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char **argv ) {
- int par;
-
- UNUSED( cmd );
- UNUSED( argc );
-
- if( argc == 1 ) {
- p->helpstr = "";
- p->ptype = KEYWD;
- p->arg = setkwds;
- return "Type 'help set value ITEM' for item details\n";
- }
-
- par = checkquals( 0, setkwds, -1, argv+1 );
- if( par == -1 )
- return NULL;
- switch( par ) {
- case 0:
- p->helpstr = "working directory for local files";
- p->ptype = STRING;
- break;
- case 1:
- p->helpstr = "default directory on volume";
- p->ptype = VMSFS;
- break;
- case 2:
- p->helpstr = "directory qualifier name ";
- p->ptype = KEYWD;
- p->arg = dirquals;
- break;
- case 3:
- p->helpstr = "style ";
- p->ptype = KEYWD;
- p->arg = setqskwds;
- break;
- case 4:
- case 5:
- p->ptype = NONE;
- break;
-
- default:
- abort();
- }
- return NULL;
-}
-
-/*********************************************************** doset() */
-
-static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) {
- int parnum;
-
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
-
- parnum = checkquals( 0, setkwds, -1, argv+1 );
- switch( parnum ) {
- default:
- return SS$_BADPARAM;
- case 0: /* default */
- case 2: /* current working directory */
- if( qualc ) {
- printf( "%%ODS2-E-NOQUAL, No qualifiers are permitted\n" );
- return 0;
- }
- return (parnum == 0)? setdef( argv[2] ) : setcwd( argv[2] );
- case 1:{ /* directory_qualifiers */
- int options = checkquals(dir_default,dirquals,qualc,qualv);
- if( options == -1 )
- return SS$_BADPARAM;
- dir_defopt = options;
- return 1;
- }
- case 3: { /* qualifier_style */
- int par = checkquals (0,setqskwds,1,argv+2);
- if( par == -1 )
- return SS$_BADPARAM;
- switch(par) {
- default:
- abort();
- case 2:
- vms_qual = 1;
- break;
- case 1:
- vms_qual = 0;
+ while( *sp != '\0' ) {
+ while( *sp == ' ' ) sp++;
+ if( *sp == '\0' )
break;
+
+ if( *sp == q ) { /* Start of qualifier */
+ *sp++ = '\0'; /* Terminate previous word */
+ if (*sp == q) { /* qq = end of qualifiers */
+ sp++;
+ q = '\0';
+ continue;
+ }
+ if( qualc >= MAXITEMS ) {
+ printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" );
+ return 0;
+ }
+ qualv[qualc++] = sp;
+ } else { /* New argument */
+ int qt;
+
+ if( argc >= MAXITEMS ) {
+ printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" );
+ return 0;
+ }
+ argv[argc++] = sp;
+ if( (qt = *sp) == '"' || (qt = *sp) == '\'' ) {
+ ++argv[argc-1];
+ for( ++sp; *sp && (*sp != qt || sp[1] == qt); sp++ ) {
+ if( *sp == qt ) /* Interior "" => " */
+ memmove( sp, sp+1, strlen(sp+1)+1 );
+ }
+ if( *sp == qt ) { /* Ending " of string */
+ *sp++ = '\0';
+ if( *sp && *sp != ' ' ) { /* Something following */
+ printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
+ return 0;
+ }
+ } else {
+ printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
+ return 0;
+ }
+ continue;
+ } /* Quoted string */
}
- return 1;
- }
- case 4:
- verify_cmd = 1;
- return 1;
- case 5:
- verify_cmd = 0;
- return 1;
+
+ /* Find end of atom */
+
+ while( !(*sp == '\0' || *sp == ' ' || *sp == q) ) sp++;
+ if (*sp == '\0')
+ break;
+ if( *sp == ' ' )
+ *sp++ = '\0';
}
+
+ if( argc > 0 )
+ return cmdexecute( argc, argv, qualc, qualv );
+
+ return 1;
}
-/******************************************************************* dodismount() */
-static struct param dmopars[] = { {"drive_letter", REQ, STRING, NOPA, "Drive containing volume to dismount", },
- {NULL, 0, 0, NOPA, NULL }
-};
+/*************************************************************** cmdexecute() */
+/* cmdexecute: identify and execute a command */
-unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) {
- struct DEV *dev;
+static int cmdexecute( int argc, char **argv, int qualc, char **qualv ) {
+ char *ptr;
+ CMDSETp_t cmd, cp = NULL;
+ unsigned cmdsiz;
+ int minpars, maxpars;
+ paramp_t p;
int sts;
- UNUSED(argc);
- UNUSED(qualc);
- UNUSED(qualv);
+ ptr = argv[0];
+ while (*ptr != '\0') {
+ *ptr = tolower(*ptr);
+ ptr++;
+ }
+ ptr = argv[0];
+ cmdsiz = strlen(ptr);
- sts = device_lookup(strlen(argv[1]),argv[1],FALSE,&dev);
- if (sts & 1) {
- if (dev->vcb != NULL) {
- sts = dismount(dev->vcb);
- } else {
- sts = SS$_DEVNOTMOUNT;
+ for( cmd = maincmds; cmd->name != NULL; cmd++ ) {
+ if( cmdsiz <= strlen( cmd->name ) &&
+ keycomp( ptr, cmd->name ) ) {
+ if( cmd->uniq ) {
+ if( cmd->uniq > 0 && (int) cmdsiz >= cmd->uniq ) {
+ cp = cmd; /* Unique in n */
+ break;
+ }
+ if( cmd->uniq < 0 && cmdsiz < (size_t) abs( cmd->uniq ) )
+ cp = cmd; /* Requires n even if fewer unique */
+ }
+ if( cp != NULL ) {
+ printf("%%ODS2-E-AMBCMD, '%s' is ambiguous\n", ptr );
+ return 0;
+ }
+ cp = cmd;
}
}
- if (!(sts & STS$M_SUCCESS)) printf("%%DISMOUNT-E-STATUS Error: %s\n",getmsg(sts, MSG_TEXT));
+ if( cp == NULL ) {
+ printf("%%ODS2-E-ILLCMD, Unknown command '%s'\n", ptr );
+ return 0;
+ }
+ cmd = cp;
+
+ if( cmd->proc == NULL )
+ return -1;
+
+ minpars =
+ maxpars = 1;
+ for( p = cmd->params; p && p->name != NULL; p++ ) {
+ maxpars++;
+ if( p->flags == REQ )
+ minpars++;
+ }
+
+ if (argc < minpars || argc > maxpars) {
+ printf( "%%ODS2-E-PARAMS, Too %s parameters specified\n",
+ (argc < minpars? "few": "many") );
+ return 0;
+ }
+ sts = (*cmd->proc) (argc,argv,qualc,qualv);
+
+ cache_flush();
+
return sts;
}
-#if MOU_WRITE != 1
-#error MOU_WRITE != 1
-#endif
-
-#define DT_NAME "drive_type"
-
-static struct qual mouquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "},
- {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", },
- {"readonly", 0, MOU_WRITE, NV, "Only allow reading from volume"},
- {"virtual", MOU_VIRTUAL, 0, NV, NULL, },
- {"write", MOU_WRITE, 0, NV, "Allow writing to volume", },
- {NULL, 0, 0, NV, NULL } };
-
-static struct param moupars[] = { {"volumes", REQ, LIST, NOPA,
- "devices or disk image(s) of volume set in RVN order separated by comma"
- },
- {"labels", OPT, LIST, NOPA, "volume labels in RVN order separated by comma" },
- { NULL, 0, 0, NOPA, NULL }
-};
-
-/******************************************************************* domount() */
-
/*********************************************************** parselist() */
-static int parselist( char ***items, size_t min, char *arg, const char *label ) {
+int parselist( char ***items, size_t min, char *arg, const char *label ) {
size_t n = 0, i;
char **list = NULL;
@@ -1799,6 +616,7 @@ static int parselist( char ***items, size_t min, char *arg, const char *label )
}
if( list == NULL ) {
+ n = 0;
list = (char **) malloc( (min + 1) * sizeof( char * ) );
if( list == NULL ) {
printf( "%%ODS2-E-NOMEM, Not enough memory for %s\n", label );
@@ -1814,577 +632,158 @@ static int parselist( char ***items, size_t min, char *arg, const char *label )
return (int)n;
}
-/*********************************************************** domount() */
-
-static unsigned domount( int argc,char *argv[],int qualc,char *qualv[] ) {
- int sts = 1,devices = 0;
- char **devs = NULL, **labs = NULL;
-
- int options;
-
- options = checkquals( 0, mouquals, qualc, qualv );
- if( options == -1 )
- return SS$_BADPARAM;
-
- UNUSED(argc);
-
- if( (devices = parselist( &devs, 0, argv[1], "devices")) < 0 )
- return SS$_BADPARAM;
- if( parselist( &labs, devices, argv[2], "labels") < 0 ) {
- free( devs );
- return SS$_BADPARAM;
- }
-
- if (devices > 0) {
- struct VCB *vcb;
- sts = mount( options | MOU_LOG, devices, devs, labs, &vcb );
- if (sts & STS$M_SUCCESS) {
- if( !default_set ) {
- char *colon, *buf;
- size_t len;
-
- len = strlen( vcb->vcbdev[0].dev->devnam );
- buf = (char *) malloc( len + sizeof( ":[000000]" ));
- if( buf == NULL ) {
- perror( "malloc" );
- } else {
- colon = strchr( vcb->vcbdev[0].dev->devnam, ':' );
- if( colon != NULL )
- len = (size_t)(colon - vcb->vcbdev[0].dev->devnam);
- memcpy( buf, vcb->vcbdev[0].dev->devnam, len );
- memcpy( buf+len, ":[000000]", sizeof( ":[000000]" ) );
- setdef(buf);
- free( buf );
- }
- }
- test_vcb = vcb;
- } else {
- printf("%%ODS2-E-MOUNTERR, Mount failed with %s\n", getmsg(sts, MSG_TEXT));
- }
- }
-
- free( devs );
- free( labs );
- return sts;
-}
-
-/******************************************************************* dospawn() */
-
-static unsigned dospawn( int argc,char *argv[],int qualc,char *qualv[] ) {
-#ifdef VMS
- unsigned sts;
-
- UNUSED( argc );
- UNUSED( argv );
- UNUSED( qualc );
- UNUSED( qualv );
-
- sts = lib$spawn( 0,0,0,0,0,0,0,0,0,0,0,0,0 );
- return sts;
-#else
-# ifdef _WIN32
- UNUSED( argc );
- UNUSED( argv );
- UNUSED( qualc );
- UNUSED( qualv );
-
- if( system( "cmd" ) == -1 ) {
- perror( "cmd" );
- return SS$_NOSUCHFILE;
- }
- return SS$_NORMAL;
-# else
- char *shell, *p;
- pid_t pid;
-
- UNUSED( argc );
- UNUSED( argv );
- UNUSED( qualc );
- UNUSED( qualv );
-
- if( (shell = getenv( "SHELL" )) == NULL )
- shell = "/bin/sh";
- if( (p = strrchr( shell, '/')) == NULL )
- p = shell;
- else
- p++;
-
- if( (pid = fork()) == 0 ) {
- execlp( shell, p, (char *)NULL );
- perror( "%s" );
- exit(EXIT_FAILURE);
- }
- if( pid == -1 ) {
- perror( shell );
- return SS$_NOSUCHFILE;
- }
- waitpid( pid, NULL, 0 );
-
- return SS$_NORMAL;
-# endif
-#endif
-
-}
-
-/******************************************************************* dohelp() */
-
-/*********************************************************** cmdhelp() */
-
-static void cmdhelp( struct CMDSET *cmdset ) {
- struct CMDSET *cmd;
- int n = 0;
- size_t max = 0;
-
- for( cmd = cmdset; cmd->name; cmd++ ) {
- if( strlen(cmd->name) > max )
- max = strlen(cmd->name);
- }
- for( cmd = cmdset; cmd->name; cmd++ ) {
- if( cmd->helpstr == NULL )
- continue;
- if( n++ % 4 == 0 )
- printf( "\n" );
- printf(" %-*s", (int)max,cmd->name );
- }
- printf( "\n" );
-}
-
-/*********************************************************** cmdhelp() */
-
-static void qualhelp( int par, struct qual *qtable ) {
- struct qual *q;
- int n = 0;
- size_t max = 0, col = 4;
-
- if( par < 0 )
- max = -par;
-
-#define NOSTR "[no]"
-#define NOSTR_LEN (sizeof(NOSTR)-1)
- for( q = qtable; q->name; q++ ) {
- if( q->helpstr ) {
- size_t len = strlen(q->name);
- if( *q->helpstr == '-' )
- len += NOSTR_LEN;
- if( q->qtype != NOVAL )
- len++;
- if( len > max )
- max = len;
- }
- }
- for( q = qtable; q->name; q++ ) {
- if( q->helpstr ) {
- if( !n++ && !par )
- printf( " %s:\n", "Qualifiers" );
- printf(" %s", par? par<0? " ": "": vms_qual? "/" : "-" );
- if( *q->helpstr == '-' )
- switch( q->qtype ) {
- case NOVAL:
- if( *q->helpstr ) {
- printf( NOSTR "%-*s - %s\n",
- (int) (max-NOSTR_LEN), q->name, q->helpstr+1 );
- break;
- }
- if( col + max > 50 ) {
- printf( "\n " );
- col = 8;
- } else {
- while( col < 8 ) {
- putchar( ' ' ); col++;
- }
- }
- printf( "%-*s", (int) max, q->name );
- col += max;
- break;
- case KEYVAL:
- case KEYCOL:
- printf( NOSTR "%s=%-*s - %s\n",
- q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+1)), "",
- q->helpstr+1 );
- qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg );
- break;
- default:
- abort();
- }
- else
- switch( q->qtype ) {
- case NOVAL:
- if( *q->helpstr ) {
- printf("%-*s - %s\n", (int) max, q->name, q->helpstr );
- break;
- }
- if( col + max > 50 ) {
- printf( "\n " );
- col = 8;
- } else {
- while( col < 8 ) {
- putchar( ' ' ); col++;
- }
- }
- printf( "%-*s", (int) max, q->name );
- col += max;
- break;
- case KEYVAL:
- case KEYCOL:
- printf( "%s=%-*s - %s\n", q->name, (int)(max-strlen(q->name)+1), "",
- q->helpstr );
- qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg );
- break;
- default:
- abort();
- }
- }
- }
- if( par >= 0 )
- printf( "\n" );
-}
-#undef NOSTR
-#undef NOSTR_LEN
-
-/*********************************************************** parhelp() */
-
-static void parhelp( struct CMDSET *cmd, int argc, char **argv) {
- struct param *p;
- struct param *ptable;
- const char *footer = NULL;
-
- ptable = cmd->params;
-
- if( ptable == NULL ) {
- printf( "%s has no parameters\n", cmd->name );
- return;
- }
-
- if( argc == 0 ) {
- int col = 0;
- size_t max = 0;
-
- for( p = ptable; p->name != NULL; p++ ) {
- if( p->helpstr ) {
- size_t len = strlen(p->name);
- if( len > max )
- max = len;
- }
- }
- for( p = ptable; p->name != NULL; p++ ) {
- if( p->helpstr ) {
- size_t len = strlen(p->name);
- if( !col ) {
- printf( " Parameters:\n " );
- col = 4;
- } else {
- if( 1+col + len > 80 ) {
- printf( "\n " );
- col = 4;
- } else {
- printf ( " " );
- col++;
- }
- }
- printf( "%-*s", (int)max, p->name );
- col += len;
- }
- }
- printf( "\n\n Type help %s PARAMETER for more about each parameter.\n",
- cmd->name );
- return;
- }
-
- for( p = ptable; p->name != NULL; p++ ) {
- if( keycomp( argv[0], p->name ) )
- break;
- }
- if( p->name == NULL ) {
- printf( "No parameter '%s' found\n", argv[0] );
- return;
- }
- if( p->hlpfnc != NULL )
- footer = (*p->hlpfnc)(cmd, p, argc, argv);
- if( p->ptype == NONE ) {
- printf( "Parameter is not used for this command\n" );
- return;
- }
-
- printf( " %s: ", p->name );
-
- if( p->flags == OPT )
- printf( "optional " );
-
- switch( p->ptype ) {
- case VMSFS:
- printf( "VMS file specification %s\n", p->helpstr );
- break;
- case LCLFS:
- printf( "local file specification %s\n", p->helpstr );
- break;
- case KEYWD:
- printf( "%skeyword, one of the following:\n",
- (p->helpstr == NULL? "": p->helpstr) );
- qualhelp( 1, (struct qual *)p->arg );
- break;
- case LIST:
- printf( "list, %s\n", p->helpstr );
- break;
- case STRING:
- printf( "%s\n", p->helpstr );
- break;
- case CMDNAM:
- printf( "command name, one of the following:\n");
- cmdhelp( (struct CMDSET *)p->arg );
- break;
- default:
- abort();
- }
- if( footer )
- printf( "%s", footer );
-
- return;
-}
-
-/*********************************************************** dohelp() */
-/* help: Display help guided by command table. */
-
-#define NCMD 17
-static struct CMDSET cmdset[NCMD+1];
-
-static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), "" },
- {"parameter", OPT, STRING, NOPA, "" },
- {"value", OPT, STRING, NOPA, "" },
- {NULL, 0, 0, NOPA, NULL },
-};
-
-/* information about the commands we know... */
-static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]);
-
-static struct CMDSET cmdset[NCMD+1] = {
- { "copy", docopy, 0,copyquals,copypars, "Copy a file from VMS to host file", },
- { "delete", dodelete, 0,delquals, delpars, "Delete a VMS file", },
- { "difference",dodiff, 0,NULL, diffpars, "Compare VMS file to host file", },
- { "directory", dodir, 0,dirquals,dirpars, "List directory of VMS files", },
- { "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", },
- { "exit", NULL, 2,NULL, NULL, "Exit ODS2", },
- { "extend", doextend, 0,NULL, extendpars, NULL },
- { "help", dohelp, 0,NULL, helppars, "Obtain help on a command", },
- { "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", },
- { "mount", domount, 0,mouquals, moupars, "Mount a VMS volume", },
- { "quit", NULL, 2,NULL, NULL, "Exit ODS-2", },
- { "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", },
- { "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", },
- { "show", doshow, 0,NULL, showpars, "Display state", },
- { "spawn", dospawn, 0,NULL, NULL, "Open a command subprocess", },
- { "test", dotest, 0,NULL, testpars, NULL },
- { "type", dotype, 0,NULL, typepars, "Display a VMS file on the terminal", },
- { NULL, NULL, 0,NULL, NULL, NULL } /* ** END MARKER ** */
-};
-
-static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]) {
- struct CMDSET *cmd;
-
- UNUSED(qualc);
- UNUSED(qualv);
-
- if( argc <= 1 ) {
- show_version();
-
- printf( " The orginal version of ods2 was developed by Paul Nankervis\n" );
- printf( " \n" );
- printf( " This modified version was developed by Timothe Litt, and\n" );
- printf( " incorporates significant previous modifications by Larry \n" );
- printf( " Baker of the USGS and by Hunter Goatley\n" );
- printf("\n Please send problems/comments to litt@ieee.org\n\n");
-
- printf(" Commands are:\n");
- cmdhelp( cmdset );
- printf( "\n Type HELP COMMAND for information on any command.\n" );
- return 1;
- }
-
- for( cmd = cmdset; cmd->name; cmd++ ) {
- if( keycomp(argv[1],cmd->name) ) {
- if( argc >= 3 ) {
- parhelp( cmd, argc-2, argv+2 );
- return 1;
- }
- if( cmd->helpstr == NULL ) {
- printf( "%s: No help available\n",cmd->name );
- } else {
- printf( "%s: %s\n",cmd->name,cmd->helpstr );
- }
- if( cmd->validquals != NULL )
- qualhelp( 0, cmd->validquals );
- if( cmd->params != NULL )
- parhelp( cmd, 0, NULL );
- if( strcmp(cmd->name, "mount") == 0 ) {
- printf( "\n" );
- printf( "You can mount a volume(-set) from either physical devices\n" );
- printf( "such a CDROM or hard disk drive, or files containing an\n" );
- printf( "image of a volume, such as a .ISO file or simulator disk\n\n" );
- printf( "To mount a disk image, use the %cimage qualifier and\n",
- (vms_qual? '/': '-') );
- printf( "specify the filename as the parameter.\n\n" );
- printf( "If the filename contains %c, specify it in double quotes\n\n",
- (vms_qual? '/': '-') );
- printf( "Mount will assign a virtual device name to each volume.\n" );
- printf( "You can select a virtual device name using the format\n" );
- printf( " dka100=my_files.iso\n\n" );
- printf( "To mount a physical device, use the format:\n" );
- phyio_help(stdout);
- printf( "To mount a volume set, specify all the members in RVN order\n" );
- printf( "as a comma-separated list.\n\n" );
- printf( "If you specify a list of volume labels, they must be in\n" );
- printf( "the same order as the volumes, and each must match the label\n" );
- printf( "stored in the data\n" );
- }
- return 1;
- }
- }
- printf( "%s: command not found\n", argv[1] );
- return 0;
-}
-
-/*************************************************************** cmdexecute() */
-/* cmdexecute: identify and execute a command */
-
-static int cmdexecute( int argc, char *argv[], int qualc, char *qualv[] ) {
- char *ptr;
- struct CMDSET *cmd, *cp = NULL;
- unsigned cmdsiz;
- int minpars, maxpars;
- struct param *p;
- int sts;
-
- ptr = argv[0];
- while (*ptr != '\0') {
- *ptr = tolower(*ptr);
- ptr++;
- }
- ptr = argv[0];
- cmdsiz = strlen(ptr);
-
- for( cmd = cmdset; cmd->name != NULL; cmd++ ) {
- if( cmdsiz <= strlen( cmd->name ) &&
- keycomp( ptr, cmd->name ) ) {
- if( (cmd->uniq && cmdsiz >= cmd->uniq) ) {
- cp = cmd;
- break;
- }
- if( cp != NULL ) {
- printf("%%ODS2-E-AMBCMD, '%s' is ambiguous\n", ptr );
- return 0;
- }
- cp = cmd;
- }
- }
- if( cp == NULL ) {
- printf("%%ODS2-E-ILLCMD, Unknown command '%s'\n", ptr );
- return 0;
- }
- cmd = cp;
-
- if (cmd->proc == NULL)
- return -1;
-
- minpars =
- maxpars = 1;
- for( p = cmd->params; p && p->name != NULL; p++ ) {
- maxpars++;
- if( p->flags == REQ )
- minpars++;
- }
-
- if (argc < minpars|| argc > maxpars) {
- printf( "%%ODS2-E-PARAMS, Too %s parameters specified\n", (argc < minpars? "few": "many") );
- return 0;
- }
- sts = (*cmd->proc) (argc,argv,qualc,qualv);
-#ifndef VMSIO
- /* cache_flush(); */
-#endif
-
- return sts;
-}
-
-/***************************************************************** cmdsplit() */
-
-/* cmdsplit: break a command line into its components */
-
-/*
- * Feature for Unix: '//' or '--' stops qualifier parsing.
- * This enables us to copy to Unix directories with VMS style /qualifiers.
- * copy /bin // *.com /tmp/ *
- * is split into argv[0] -> "*.com" argv[1] -> "/tmp/ *" qualv[0]-> "/bin"
- *
- * Of course, one can just "" the string (VMS double quote rules)...
+/******************************************************************* checkquals() */
+/* checkquals: Given valid qualifier definitions, process qualifer
+ * list from a command left to right. Also handles parameters and
+ * qualifier values (/Qual=value).
*/
-#define MAXITEMS 32
-static int cmdsplit(char *str) {
- int argc = 0,qualc = 0;
- char *argv[MAXITEMS],*qualv[MAXITEMS];
- char *sp = str;
+
+int checkquals(int result, qualp_t qualset,int qualc,char **qualv) {
int i;
- char q = vms_qual? '/': '-';
+ const char *type;
- for( i = 0; i < MAXITEMS; i++ ) argv[i] = qualv[i] = "";
+#ifdef _WIN32 /* Code analysis thinks qualset can be NULL, resulting in a false positive. */
+ if( qualset == NULL )
+ abort();
+#endif
- while( *sp != '\0' ) {
- while( *sp == ' ' ) sp++;
- if( *sp == '\0' )
- break;
+ type = (qualc < 0)? "parameter": "qualifier";
+ qualc = abs( qualc );
- if( *sp == q ) { /* Start of qualifier */
- *sp++ = '\0'; /* Terminate previous word */
- if (*sp == q) { /* qq = end of qualifiers */
- sp++;
- q = '\0';
- continue;
- }
- if( qualc >= MAXITEMS ) {
- printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" );
- return 0;
- }
- qualv[qualc++] = sp;
- } else { /* New argument */
- if( argc >= MAXITEMS ) {
- printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" );
- return 0;
- }
- argv[argc++] = sp;
- if( *sp == '"' ) {
- ++argv[argc-1];
- for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) {
- if( *sp == '"' ) /* Interior "" => " */
- memmove( sp, sp+1, strlen(sp+1)+1 );
+ for( i = 0; i < qualc; i++ ) {
+ char *qv;
+ qualp_t qs, qp = NULL;
+
+ qv = strchr( qualv[i], '=' );
+ if( qv == NULL )
+ qv = strchr( qualv[i], ':' );
+ if( qv != NULL )
+ *qv++ = '\0';
+ for( qs = qualset; qs->name != NULL; qs++) {
+ if( keycomp( qualv[i], qs->name ) ) {
+ if( qp != NULL ) {
+ printf ( "%%ODS2-W-AMBQUAL, %c%s '%s' is ambiguous\n",
+ type[0], type+1, qualv[i] );
+ return -1;
}
- if( *sp == '"' ) { /* Ending " of string */
- *sp++ = '\0';
- if( *sp && *sp != ' ' ) { /* Something following */
- printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
- return 0;
- }
- } else {
- printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
- return 0;
- }
- continue;
- } /* Quoted string */
+ qp = qs;
+ }
}
+ if( qp == NULL ) {
+ printf("%%ODS2-W-ILLQUAL, Unknown %s '%s'\n", type, qualv[i]);
+ return -1;
+ }
+ result = (result & ~qp->clear) | qp->set;
+ if( qv != NULL ) {
+ char *nvp;
- /* Find end of atom */
+ if( qp->qtype == NOVAL ) {
+ printf( "%%ODS2-W-NOQVAL, %c%s '%s' does not accept a value\n",
+ toupper( *type ), type+1, qualv[i] );
+ return -1;
+ }
+ if( qp->qtype == STRVAL ) {
+ *((char **)qp->arg) = qv;
+ continue;
+ }
+ if( *qv == '(' ) {
+ qv++;
+ nvp = strchr( qv, ')' );
+ if( nvp == NULL ) {
+ printf( "%%ODS2-W-NQP, %c%s %s is missing ')'\n",
+ toupper( *type ), type+1, qualv[i] );
+ return -1;
+ }
+ *nvp = '\0';
+ }
+ do {
+ while( *qv == ' ' ) qv++;
+ nvp = strchr( qv, ',' );
+ if( nvp != NULL )
+ *nvp++ = '\0';
+ switch( qp->qtype ) {
+ case DECVAL: {
+ unsigned long int val;
+ char *ep;
- while( !(*sp == '\0' || *sp == ' ' || *sp == q) ) sp++;
- if (*sp == '\0')
- break;
- if( *sp == ' ' )
- *sp++ = '\0';
+ errno = 0;
+ val = strtoul( qv, &ep, 10 );
+ if( !*qv || *ep || errno != 0 ) {
+ printf( "%%ODS2-BADVAL, %s is not a valid number\n", qv );
+ return -1;
+ }
+ *((unsigned *)qp->arg) = (unsigned)val;
+ break;
+ }
+ case KEYVAL:
+ case KEYCOL:
+ result = checkquals( result, (qualp_t )qp->arg, -1, &qv );
+ if( result == -1 )
+ return result;
+ break;
+ default:
+ abort();
+ }
+ qv = nvp;
+ } while( qv != NULL );
+ }
}
+ return result;
+}
- if( argc > 0 )
- return cmdexecute( argc, argv, qualc, qualv );
+/******************************************************************* keycomp() */
+/* keycomp: routine to compare parameter to a keyword - case insensitive! */
+int keycomp(const char *param, const char *keywrd) {
+ while (*param != '\0') {
+ if( tolower(*param++) != tolower(*keywrd++) )
+ return 0;
+ }
return 1;
}
-/******************************************************************* main() */
+/******************************************************************* fgetline() */
+/* Read a line of input - unlimited length
+ * Removes \n, returns NULL at EOF
+ * Caller responsible for free()
+ */
+char *fgetline( FILE *stream, int keepnl ) {
+ size_t bufsize = 0,
+ xpnsize = 80,
+ idx = 0;
+ char *buf = NULL;
+ int c;
+
+ if( (buf = malloc( (bufsize = xpnsize) )) == NULL ) {
+ perror( "malloc" );
+ abort();
+ }
+
+ while( (c = fgetc( stream )) != EOF && c != '\n' ) {
+ if( idx + (keepnl != 0) +2 > bufsize ) { /* Now + char + (? \n) + \0 */
+ char *nbuf;
+ bufsize += xpnsize;
+ nbuf = (char *) realloc( buf, bufsize );
+ if( nbuf == NULL ) {
+ perror( "realloc" );
+ abort();
+ }
+ buf = nbuf;
+ }
+ buf[idx++] = c;
+ }
+ if( c == '\n' ) {
+ if( keepnl )
+ buf[idx++] = '\n';
+ } else {
+ if( c == EOF && idx == 0 ) {
+ free( buf );
+ return NULL;
+ }
+ }
+ buf[idx] = '\0';
+ return buf;
+}
/*********************************************************** getcmd() */
@@ -2401,15 +800,16 @@ static char *getcmd( char *inp, size_t max, char *prompt ) {
if (key_table_id == 0) {
status = smg$create_key_table( &key_table_id );
- if (status & 1)
+ if( status & STS$M_SUCCESS )
status = smg$create_virtual_keyboard( &keyboard_id );
- if (!(status & 1)) return (NULL);
+ if( !(status & STS$M_SUCCESS) )
+ return (NULL);
}
- status = smg$read_composed_line (&keyboard_id, &key_table_id,
- &input_d, &prompt_d, &input_d, 0,0,0,0,0,0,0);
+ status = smg$read_composed_line( &keyboard_id, &key_table_id,
+ &input_d, &prompt_d, &input_d, 0,0,0,0,0,0,0 );
- if (status == SMG$_EOF)
+ if( status == SMG$_EOF )
retstat = NULL;
else {
inp[input_d.dsc_w_length] = '\0';
@@ -2420,230 +820,64 @@ static char *getcmd( char *inp, size_t max, char *prompt ) {
}
#endif /* VMS */
-/*********************************************************** main() */
-/* main: the simple mainline of this puppy... */
+/*********************************************************** prvmstime() */
-/*
- * Parse the command line to read and execute commands:
- * ./ods2 mount scd1 $ set def [hartmut] $ copy *.com $ exit
- * '$' is used as command delimiter because it is a familiar character
- * in the VMS world. However, it should be used surounded by white spaces;
- * otherwise, a token '$copy' is interpreted by the Unix shell as a shell
- * variable. Quoting the whole command string might help:
- * ./ods2 'mount scd1 $set def [hartmut] $copy *.com $exit'
- * If the ods2 reader should use any switches '-c' should be used for
- * the command strings, then quoting will be required:
- * ./ods2 -c 'mount scd1 $ set def [hartmut] $ copy *.com $ exit'
- *
- * The same command concatenation can be implemented for the prompted input.
- */
+int prvmstime(VMSTIME vtime, const char *sfx) {
+ int sts = 0;
+ char tim[24];
+ static const VMSTIME nil;
+ struct dsc_descriptor timdsc;
-int main( int argc,char *argv[] ) {
- int sts;
- char *command_line = NULL;
- FILE *atfile = NULL;
- char *rl = NULL;
-#ifdef VMS
- char str[2048];
-#endif
-#ifdef USE_READLINE
- char *p;
- wordexp_t wex;
- char *hfname = NULL;
- char mname[3+sizeof( MNAME(MODULE_NAME) )];
-
- snprintf( mname, sizeof(mname ), "~/.%s", MNAME(MODULE_NAME) );
- rl_readline_name =
- p = mname+3;
- do {
- *p = tolower( *p );
- } while( *p++ );
- memset( &wex, 0, sizeof( wordexp_t ) );
- if( wordexp( mname, &wex, WRDE_NOCMD ) == 0 && wex.we_wordc == 1 ) {
- hfname = wex.we_wordv[0];
- history_truncate_file( hfname, 200 );
- stifle_history( 200 );
- read_history( hfname );
+ if( memcmp( vtime, nil, sizeof(nil) ) ) {
+ timdsc.dsc_w_length = 23;
+ timdsc.dsc_a_pointer = tim;
+ sts = sys_asctim(0,&timdsc,vtime,0);
+ if( !(sts & STS$M_SUCCESS) )
+ printf("%%ODS2-W-TIMERR, SYS$ASCTIM error: %s\n",getmsg(sts, MSG_TEXT));
+ tim[23] = '\0';
+ printf(" %s",tim);
+ } else {
+ printf( " %-23s", " " );
+ sts = 1;
+ }
+ if (sfx != NULL)
+ printf( "%s", sfx );
+ return sts;
+}
+
+/*********************************************************** pwrap() */
+
+void pwrap( int *pos, const char *fmt, ... ) {
+ char pbuf[200], *p, *q;
+ va_list ap;
+
+ va_start(ap, fmt );
+ vsnprintf( pbuf, sizeof(pbuf), fmt, ap );
+ va_end(ap);
+
+ for( p = pbuf; *p; ) {
+ int len;
+ int eol = 0;
+
+ q = strchr( p, '\n' );
+ if( q != NULL ) {
+ *q++ = '\0';
+ eol = 1;
+ len = strlen(p);
+ } else {
+ len = strlen(p);
+ q = p + len;
+ }
+ if( *pos + len > 80 ) {
+ static const char wrap[] = " ";
+ printf( "\n%s", wrap );
+ *pos = sizeof(wrap) -1;
+ if( p[0] == ',' && p[1] == ' ' )
+ p += 2;
+ }
+ *pos += strlen(p);
+ printf( "%s%s", p, eol? "\n":"" );
+ if( eol ) *pos = 0;
+ p = q;
}
-#endif
- sts = sys_initialize();
- if( !(sts & STS$M_SUCCESS) ) {
- printf( "Unable to initialize library: %s\n", getmsg( sts, MSG_TEXT ) );
- exit(EXIT_FAILURE);
- }
- { /* Build parser keyword list from disk table entries */
- struct qual *qp, *kp = NULL;
- struct disktype * dp;
- size_t n = 0;
-
- for( dp = disktype; dp->name != NULL; dp++ )
- ;
- n = (size_t) (dp - disktype);
- kp = (struct qual *)calloc( n+1, sizeof( struct qual ) );
- if( kp == NULL ) {
- perror( "malloc" );
- exit( EXIT_FAILURE );
- }
- for( qp = mouquals; qp->name != NULL; qp++ )
- if( !strcmp( qp->name, DT_NAME ) )
- break;
- qp->arg = kp;
-
- for( dp = disktype; dp->name != NULL; dp++ ) {
- kp->name = dp->name;
- kp->set = (int)((dp-disktype) << MOU_V_DEVTYPE);
- kp->clear = MOU_DEVTYPE;
- kp->qtype = NOVAL;
- if( dp != disktype )
- kp->helpstr = "";
- kp++;
- }
- if( (((unsigned)(dp-disktype)) << MOU_V_DEVTYPE) & ~MOU_DEVTYPE )
- abort(); /* MOU_DEVTYPE isn't wide enough for the max index */
- }
-
- if( argc > 1 ) {
- int i, l = 0;
- for( i = 1; i < argc; i++ ) {
- int al;
- char *newp;
-
- al = strlen(argv[i]);
- newp = (char *)realloc( command_line, l+(l != 0)+al+1 );
- if( newp == NULL ) {
- perror( "realloc" );
- exit (1);
- }
- command_line = newp;
- if( l != 0 ) command_line[l++] = ' ';
- memcpy( command_line+l, argv[i], al+1 );
- l += al;
- }
- }
- while( 1 ) {
- char *ptr = NULL;
- if( command_line ) {
- static int i = 0;
- char *p;
-
- ptr = command_line + i;
- if( (p = strchr( ptr, '$' )) == NULL ) {
- if( *ptr == '\0' ) {
- free( command_line );
- command_line = NULL;
- ptr = NULL;
- } else {
- i += strlen( ptr );
- }
- } else {
- *p = '\0';
- i += strlen( ptr ) +1;
- }
-#ifdef USE_READLINE
- if( ptr != NULL && *ptr )
- add_history( ptr );
-#endif
- }
- if( ptr == NULL ) {
- if (atfile != NULL) {
- if( rl != NULL ) free( rl );
- if( (rl = fgetline(atfile, FALSE)) == NULL) {
- fclose(atfile);
- atfile = NULL;
- } else {
-#ifndef _WIN32
- ptr = strchr( rl, '\r' );
- if( ptr != NULL )
- *ptr = '\0';
-#endif
- if( verify_cmd )
- printf("$> %s\n", rl);
- }
- ptr = rl;
- }
- if( ptr == NULL ) {
-#ifdef VMS
- if( getcmd( str, sizeof(str), "$> " ) == NULL ) break;
- ptr = str;
-#else
- if( rl != NULL ) {
- free( rl );
- }
-#ifdef USE_READLINE
- rl =
- ptr = readline( MNAME(MODULE_NAME) "$> " );
- if (rl == NULL) {
- break;
- } else {
- if( *rl != '\0' ) {
- add_history( rl );
- }
- }
-#else
- printf("$> ");
- if( (rl = fgetline(stdin, FALSE)) == NULL) break;
- ptr = rl;
-#endif
-#endif
- }
- }
-
- while( *ptr == ' ' || *ptr == '\t' )
- ptr++;
- if( !strlen(ptr) || *ptr == '!' || *ptr == ';' )
- continue;
-
- if (*ptr == '@') {
- if (atfile != NULL) {
- printf("%%ODS2-W-INDIRECT, nested indirect command files not supported\n");
- } else {
- if ((atfile = openf(ptr + 1,"r")) == NULL) {
- perror("%%ODS2-E-INDERR, Failed to open indirect command file");
- printf("\n");
- free(command_line);
- command_line = NULL;
- }
- }
- continue;
- }
-
- sts = cmdsplit(ptr);
- if( sts == -1 )
- break;
- if ((sts & 1) == 0) {
- if( atfile != NULL ) {
- fclose(atfile);
- atfile = NULL;
- }
- free(command_line);
- command_line = NULL;
- }
- } /* while 1 */
-
- free( command_line );
-
- if( rl != NULL ) {
- free( rl );
- }
-#ifdef USE_READLINE
- if( hfname != NULL ) {
- write_history( hfname );
- clear_history();
- }
- wordfree( &wex ); /* hfname points into wex and should not be free()d */
-#endif
- if (atfile != NULL)
- fclose(atfile);
-
- {
- struct qual *qp;
-
- for( qp = mouquals; qp->name != NULL; qp++ )
- if( !strcmp( qp->name, DT_NAME ) ) {
- free( qp-> arg );
- qp->arg = NULL;
- break;
- }
- }
- exit( EXIT_SUCCESS );
}
diff --git a/extracters/ods2/ods2.h b/extracters/ods2/ods2.h
index 7b7bcb2..c81652e 100644
--- a/extracters/ods2/ods2.h
+++ b/extracters/ods2/ods2.h
@@ -5,11 +5,40 @@
#ifndef _ODS2_H
#define _ODS2_H
-#define MOU_WRITE 1
-#define MOU_VIRTUAL 2
-#define MOU_LOG 4
+#ifndef TRUE
+#define TRUE ( 0 == 0 )
+#endif
+#ifndef FALSE
+#define FALSE ( 0 != 0 )
+#endif
-#define MOU_V_DEVTYPE 8
+#if DEBUG
+#include "debug.h"
+#endif
+
+/* Option bits common to I/O, access, visible outside the ODS-2 parser */
+
+#define MOU_WRITE (1 << 0)
+#define MOU_VIRTUAL (1 << 1)
+#define MOU_LOG (1 << 2)
+#define PHY_CREATE (1 << 3)
+#define PHY_VHDDSK (1 << 4)
+
+#define MOU_V_DEVTYPE (8)
#define MOU_DEVTYPE (0xffff << MOU_V_DEVTYPE)
+#define MOU_S_DEVTYPE (16)
+
+/* Option bits that will not conflict with I/O */
+
+#define OPT_GENERIC_1 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 0) )
+#define OPT_GENERIC_2 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 1) )
+#define OPT_GENERIC_3 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 2) )
+#define OPT_GENERIC_4 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 3) )
+#define OPT_GENERIC_5 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 4) )
+#define OPT_GENERIC_6 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 5) )
+#define OPT_GENERIC_7 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 6) )
+#define OPT_GENERIC_8 (1 << (MOU_V_DEVTYPE + MOU_S_DEVTYPE + 7) )
+
+#define OPT_NOSORT (1 << 31)
#endif /* #ifndef _ODS2_H */
diff --git a/extracters/ods2/ods2_alpha.exe b/extracters/ods2/ods2_alpha.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_solaris_intel.exe b/extracters/ods2/ods2_solaris_intel.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_solaris_sparc.exe b/extracters/ods2/ods2_solaris_sparc.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_tru64.exe b/extracters/ods2/ods2_tru64.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_vax_decc.exe b/extracters/ods2/ods2_vax_decc.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_vax_vaxc.exe b/extracters/ods2/ods2_vax_vaxc.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/ods2_win32.exe b/extracters/ods2/ods2_win32.exe
old mode 100644
new mode 100755
diff --git a/extracters/ods2/phyio.h b/extracters/ods2/phyio.h
index 8b11032..1586dde 100644
--- a/extracters/ods2/phyio.h
+++ b/extracters/ods2/phyio.h
@@ -1,4 +1,4 @@
-/* Phyio.h V2.1 Definition of Physical I/O routines */
+/* Phyio.h Definition of Physical I/O routines */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -37,7 +37,7 @@
#ifndef _PHYIO_H
#define _PHYIO_H
-#include "device.h"
+#include
#define PHYIO_READONLY 1
@@ -47,14 +47,18 @@ typedef enum showtype {
SHOW_DEVICES
} showtype_t;
+struct DEV;
+
void phyio_show( showtype_t type );
char *phyio_path( const char *filnam );
unsigned phyio_init( struct DEV *dev );
unsigned phyio_done( struct DEV *dev );
-unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
- char *buffer );
-unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
- const char *buffer );
+
+typedef unsigned (*phy_iord_t)( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer );
+typedef unsigned (*phy_iowr_t)( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer );
+
void phyio_help(FILE *fp );
#endif /* #ifndef _PHYIO_H */
diff --git a/extracters/ods2/phynt.c b/extracters/ods2/phynt.c
index 1f2543a..53b763d 100644
--- a/extracters/ods2/phynt.c
+++ b/extracters/ods2/phynt.c
@@ -1,4 +1,4 @@
-/* PHYNT.C V2.1 Physical I/O module for Windows NT */
+/* PHYNT.C Physical I/O module for Windows NT */
/* Win9X code now included with code to automatically determine
if we are running under WinNT...
@@ -21,6 +21,13 @@
use the NT drive letter, which will do physical I/O to the device.
*/
+#if !defined( DEBUG ) && defined( DEBUG_PHYNT )
+#define DEBUG DEBUG_PHYNT
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
#include
#include
@@ -139,6 +146,10 @@ static void getsysversion( void );
static unsigned phy_getsect( struct DEV *dev, unsigned sector );
static unsigned phy_putsect( struct DEV *dev, unsigned sector );
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer );
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer );
#ifdef USE_ASPI
/************************************************************* aspi_execute() */
@@ -408,10 +419,10 @@ static BOOL GetDiskGeometry( struct DEV *dev, unsigned *sectors,
);
}
if ( result ) {
- *sectors = Geometry.Cylinders.QuadPart *
- Geometry.TracksPerCylinder *
- Geometry.SectorsPerTrack;
- *bytespersector = Geometry.BytesPerSector;
+ *sectors = (unsigned int)(Geometry.Cylinders.QuadPart * /* In theory, this can overfolow */
+ Geometry.TracksPerCylinder *
+ Geometry.SectorsPerTrack);
+ *bytespersector = (unsigned int) Geometry.BytesPerSector;
}
} else {
@@ -445,7 +456,7 @@ static BOOL GetDiskGeometry( struct DEV *dev, unsigned *sectors,
&TotalNumberOfBytes,
&TotalNumberOfFreeBytes
) ) {
- *sectors = TotalNumberOfBytes.QuadPart / BytesPerSector;
+ *sectors = (unsigned int)(TotalNumberOfBytes.QuadPart / BytesPerSector);
}
}
}
@@ -596,9 +607,11 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
FILE_BEGIN /* dwMoveMethod */
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
if ( sts & STS$M_SUCCESS ) {
@@ -616,9 +629,11 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
return SS$_ENDOFFILE;
msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
}
@@ -650,9 +665,11 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
) && !( reg.reg_Flags & 0x0001 );
if ( !result ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_READ: Read sector %d failed: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_READ: Read sector %d failed: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
}
@@ -691,9 +708,11 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
FILE_BEGIN /* dwMoveMethod */
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
if ( sts & STS$M_SUCCESS ) {
@@ -705,9 +724,11 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
NULL /* lpOverlapped */
) || BytesWritten != dev->bytespersector ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
}
@@ -738,9 +759,11 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
) && !( reg.reg_Flags & 0x0001 );
if ( !result ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_WRITE: Write sector %d failed: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_WRITE: Write sector %d failed: %s\n",
sector, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
sts = SS$_PARITY;
}
}
@@ -767,7 +790,7 @@ void phyio_show( showtype_t type ) {
TCHAR l;
for( l = 'A'; l <= 'Z'; l++ ) {
- snprintf( devname, sizeof( devname ), "%c:", l );
+ (void) snprintf( devname, sizeof( devname ), "%c:", l );
dname = namep = driveFromLetter( devname );
if( namep != NULL ) {
const char *type = NULL;
@@ -858,17 +881,76 @@ unsigned phyio_init( struct DEV *dev ) {
init_count++;
- dev->access &= ~MOU_VIRTUAL;
+
dev->API.Win32.handle = INVALID_HANDLE_VALUE;
+ dev->devread = phyio_read;
+ dev->devwrite = phyio_write;
dev->drive = -1;
- dev->sectors = 0;
dev->bytespersector = 0;
dev->blockspersector = 0;
dev->last_sector = 0;
dev->IoBuffer = NULL;
- virtual = virt_lookup( dev->devnam );
- if ( virtual == NULL ) {
+ if( dev->access & MOU_VIRTUAL ) {
+ DWORD FileSizeLow, FileSizeHigh;
+
+ virtual = virt_lookup( dev->devnam );
+ if ( virtual == NULL ) {
+ return SS$_NOSUCHDEV;
+ }
+ dev->API.Win32.handle =
+ CreateFile( virtual, /* lpFileName */
+ GENERIC_READ | /* dwDesiredAccess */
+ ((dev->access & MOU_WRITE)? GENERIC_WRITE : 0 ),
+ 0, /* dwShareMode */
+ NULL, /* lpSecurityAttributes */
+ ((dev->access & PHY_CREATE)? CREATE_NEW: OPEN_EXISTING),
+ /* dwCreationDisposition */
+ /* dwFlagsAndAttributes */
+ FILE_FLAG_RANDOM_ACCESS |
+ ( dev->access & MOU_WRITE ?
+ FILE_FLAG_WRITE_THROUGH : 0 ),
+ NULL /* hTemplateFile */
+ );
+ if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE &&
+ (dev->access & (MOU_WRITE|PHY_CREATE)) == MOU_WRITE ) {
+ dev->access &= ~MOU_WRITE;
+ dev->API.Win32.handle =
+ CreateFile( virtual, /* lpFileName */
+ GENERIC_READ, /* dwDesiredAccess */
+ 0, /* dwShareMode */
+ NULL, /* lpSecurityAttributes */
+ OPEN_EXISTING, /* dwCreationDisposition */
+ /* dwFlagsAndAttributes */
+ FILE_FLAG_RANDOM_ACCESS,
+ NULL /* hTemplateFile */
+ );
+ }
+ if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
+ TCHAR *msg = w32_errstr(NO_ERROR);
+ if( msg != NULL ) {
+ printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n",
+ virtual, msg );
+ LocalFree( msg );
+ }
+ return SS$_NOSUCHFILE;
+ }
+ SetLastError( 0 );
+ FileSizeLow = GetFileSize( dev->API.Win32.handle, /* hFile */
+ &FileSizeHigh /* lpFileSizeHigh */
+ );
+ if ( GetLastError() == NO_ERROR ) {
+#if 0
+ dev->sectors = ( FileSizeHigh << 23 ) |
+ ( ( ( FileSizeLow + 511 ) >> 9 ) & 0x007FFFFF ) ;
+#endif
+ dev->eofptr = (off_t)(( ((__int64)FileSizeHigh) << 32 ) | FileSizeLow);
+ dev->bytespersector = 512;
+ dev->blockspersector = 1;
+ }
+ } else { /* Physical */
+ unsigned sectors;
+
if ( strlen( dev->devnam ) != 2 ||
!isalpha( dev->devnam[0] ) || dev->devnam[1] != ':' ) {
return SS$_IVDEVNAM;
@@ -895,6 +977,7 @@ unsigned phyio_init( struct DEV *dev ) {
if ( is_NT ) {
char ntname[7] = "\\\\.\\"; /* 7 = sizeof \\.\a:\0 */
+
memcpy( ntname+4, dev->devnam, 3 ); /* Copy a:\0 */
ntname[4] = toupper( ntname[4] );
dev->API.Win32.handle =
@@ -942,77 +1025,41 @@ unsigned phyio_init( struct DEV *dev ) {
}
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n",
dev->devnam, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
return SS$_NOSUCHDEV;
}
if ( !LockVolume( dev ) ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n",
dev->devnam, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
phyio_done( dev );
return SS$_DEVNOTALLOC;
}
}
- if ( !GetDiskGeometry( dev, &dev->sectors, &dev->bytespersector ) ) {
+
+ if ( !GetDiskGeometry( dev, §ors, &dev->bytespersector ) ) {
TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n",
+ if( msg != NULL ) {
+ printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n",
dev->devnam, msg );
- LocalFree(msg);
+ LocalFree( msg );
+ }
phyio_done( dev );
return 80;
}
dev->blockspersector = dev->bytespersector / 512;
- } else { /* Virtual device */
- DWORD FileSizeLow, FileSizeHigh;
- dev->access |= MOU_VIRTUAL;
- dev->API.Win32.handle =
- CreateFile( virtual, /* lpFileName */
- GENERIC_READ | /* dwDesiredAccess */
- ( dev->access & MOU_WRITE ? GENERIC_WRITE : 0 ),
- 0, /* dwShareMode */
- NULL, /* lpSecurityAttributes */
- OPEN_EXISTING, /* dwCreationDisposition */
- /* dwFlagsAndAttributes */
- FILE_FLAG_RANDOM_ACCESS |
- ( dev->access & MOU_WRITE ?
- FILE_FLAG_WRITE_THROUGH : 0 ),
- NULL /* hTemplateFile */
- );
- if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE &&
- dev->access & MOU_WRITE ) {
- dev->access &= ~MOU_WRITE;
- dev->API.Win32.handle =
- CreateFile( virtual, /* lpFileName */
- GENERIC_READ, /* dwDesiredAccess */
- 0, /* dwShareMode */
- NULL, /* lpSecurityAttributes */
- OPEN_EXISTING, /* dwCreationDisposition */
- /* dwFlagsAndAttributes */
- FILE_FLAG_RANDOM_ACCESS,
- NULL /* hTemplateFile */
- );
- }
- if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
- TCHAR *msg = w32_errstr(NO_ERROR);
- printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n",
- virtual, msg );
- LocalFree(msg);
- return SS$_NOSUCHFILE;
- }
- SetLastError( 0 );
- FileSizeLow = GetFileSize( dev->API.Win32.handle, /* hFile */
- &FileSizeHigh /* lpFileSizeHigh */
- );
- if ( GetLastError() == NO_ERROR ) {
- dev->sectors = ( FileSizeHigh << 23 ) |
- ( ( ( FileSizeLow + 511 ) >> 9 ) & 0x007FFFFF ) ;
- dev->bytespersector = 512;
- dev->blockspersector = 1;
- }
+ dev->eofptr = ((off_t)sectors) * dev->bytespersector;
}
+
+ /* Common exit for virtual and physical */
+
dev->IoBuffer = VirtualAlloc( NULL, /* lpAddress */
dev->bytespersector, /* dwSize */
MEM_COMMIT, /* flAllocationType */
@@ -1022,7 +1069,7 @@ unsigned phyio_init( struct DEV *dev ) {
phyio_done( dev );
return SS$_INSFMEM;
}
-#ifdef DEBUG
+#if DEBUG
printf( "--->phyio_init(): sectors = %u, bytespersector = %u\n",
dev->sectors, dev->bytespersector );
#endif
@@ -1040,11 +1087,9 @@ unsigned phyio_done( struct DEV *dev ) {
);
dev->API.Win32.handle = INVALID_HANDLE_VALUE;
}
- if( dev->access & MOU_VIRTUAL )
- virt_device( dev->devnam, NULL );
if ( dev->IoBuffer != NULL ) {
VirtualFree( dev->IoBuffer, /* lpAddress */
- dev->bytespersector, /* dwSize */
+ 0, /* dwSize */
MEM_RELEASE /* dwFreeType */
);
dev->IoBuffer = NULL;
@@ -1057,13 +1102,13 @@ unsigned phyio_done( struct DEV *dev ) {
/* Handle a read request ... need to read the approriate sectors to
complete the request... */
-unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
- char *buffer ) {
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer ) {
register unsigned sts, transfer, sectno, offset;
char *sectbuff;
-#ifdef DEBUG
+#if DEBUG
printf( "Phyio read block: %d into %x (%d bytes)\n",
block, buffer, length );
#endif
@@ -1105,13 +1150,13 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
/* Handle a write request ... need to read the approriate sectors to
complete the request... */
-unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
- const char *buffer) {
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer) {
register unsigned sts, transfer, sectno, offset;
char *sectbuff;
-#ifdef DEBUG
+#if DEBUG
printf( "Phyio write block: %d from %x (%d bytes)\n",
block, buffer, length );
#endif
diff --git a/extracters/ods2/phyos2.c b/extracters/ods2/phyos2.c
index 5d068f2..b937067 100644
--- a/extracters/ods2/phyos2.c
+++ b/extracters/ods2/phyos2.c
@@ -15,7 +15,10 @@
#include "phyio.h"
#include "ssdef.h"
-
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer );
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer );
unsigned init_count = 0;
unsigned read_count = 0;
@@ -70,8 +73,17 @@ void phyio_help(FILE *fp ) {
return;
}
+NOTE: This will not compile. The API for phyio_init has changed to
+taking a DEV struct. I'm leaving it this way becauses I don't have the
+ability to test under OS2. This was left undone when the API was changed...
+before my time.
+
+
unsigned phyio_init(int devlen,char *devnam,unsigned *hand,struct phyio_info *info)
{
+ dev->devread = phyio_read;
+ dev->devwrite = phyio_write;
+
if (hand_count < HANDLE_MAX - 1) {
ULONG usAction;
ULONG open_mode;
@@ -163,10 +175,10 @@ unsigned phy_getsect(HFILE hfile,unsigned sector,char *buffer)
-unsigned phyio_read(unsigned handno,unsigned block,unsigned length,char *buffer)
+static unsigned phyio_read(unsigned handno,unsigned block,unsigned length,char *buffer)
{
register unsigned sts = 1;
-#ifdef DEBUG
+#if DEBUG
printf("PHYIO_READ block %d length %d\n",block,length);
#endif
if (handno >= hand_count) {
@@ -212,7 +224,7 @@ unsigned phyio_read(unsigned handno,unsigned block,unsigned length,char *buffer)
}
-unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer)
+static unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer)
{
write_count++;
return SS$_WRITLCK;
diff --git a/extracters/ods2/phyunix.c b/extracters/ods2/phyunix.c
index 51a911f..bd8265f 100644
--- a/extracters/ods2/phyunix.c
+++ b/extracters/ods2/phyunix.c
@@ -1,4 +1,4 @@
-/* PHYUNIX.c V2.1 Physical I/O module for Unix */
+/* PHYUNIX.c Physical I/O module for Unix */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -26,6 +26,14 @@
/* */
/******************************************************************************/
+#if !defined( DEBUG ) && defined( DEBUG_PHYUNIX )
+#define DEBUG DEBUG_PHYUNIX
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
#include
#include
@@ -46,13 +54,6 @@
#include "phyvirt.h"
#include "compat.h"
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
#if defined(__digital__) && defined(__unix__)
#define DEV_PREFIX "/devices/rdisk/"
#else
@@ -73,6 +74,11 @@ struct devdat {
unsigned high;
};
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer );
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer );
+
/*************************************************************** showdevs() */
static int devcmp( const void *d1, const void *d2 ) {
@@ -253,85 +259,131 @@ char *phyio_path( const char *filnam ) {
/*************************************************************** phyio_init() */
unsigned phyio_init( struct DEV *dev ) {
-
+ int sts = SS$_NORMAL;
size_t n;
- int fd;
+ int fd, saverr = 0;
char *device;
const char *virtual;
struct stat statbuf;
init_count++;
- dev->access &= ~MOU_VIRTUAL;
- dev->handle = 0;
- dev->sectors = 0;
+ dev->handle = -1;
+ dev->devread = phyio_read;
+ dev->devwrite = phyio_write;
- virtual = virt_lookup( dev->devnam );
- if ( virtual == NULL ) {
- n = sizeof( DEV_PREFIX ) + strlen( dev->devnam );
- device = (char *) malloc( n );
- if ( device != NULL ) {
- memcpy( device, DEV_PREFIX, sizeof( DEV_PREFIX ) -1 );
- memcpy( device+sizeof( DEV_PREFIX ) -1, dev->devnam, n +1 - sizeof( DEV_PREFIX ) );
- device[n - 2] = '\0'; /* Remove : from device name */
+ if( dev->access & MOU_VIRTUAL ) {
+ virtual = virt_lookup( dev->devnam );
+ if ( virtual == NULL ) {
+ return SS$_NOSUCHDEV;
}
- } else {
n = strlen( virtual );
device = (char *) malloc( n + 1 );
- if ( device != NULL ) {
- memcpy( device, virtual, n + 1 );
- dev->access |= MOU_VIRTUAL;
- }
+ if( device == NULL )
+ return SS$_INSFMEM;
+
+ memcpy( device, virtual, n + 1 );
+ } else {
+ n = sizeof( DEV_PREFIX ) + strlen( dev->devnam );
+ device = (char *) malloc( n );
+ if ( device == NULL )
+ return SS$_INSFMEM;
+
+ memcpy( device, DEV_PREFIX, sizeof( DEV_PREFIX ) -1 );
+ memcpy( device+sizeof( DEV_PREFIX ) -1, dev->devnam, n +1 - sizeof( DEV_PREFIX ) );
+ device[n - 2] = '\0'; /* Remove : from device name */
}
- if ( device == NULL ) {
- return SS$_INSFMEM;
- }
- stat( device, &statbuf );
- dev->sectors = ( statbuf.st_size + (off_t) 511 ) / (off_t) 512;
- fd = open( device, ( dev->access & MOU_WRITE ) ? O_RDWR : O_RDONLY );
-#ifdef DEBUG
- printf( "%d = open( \"%s\", %s )\n", fd, device,
- ( dev->access & MOU_WRITE ) ? "O_RDWR" : "O_RDONLY" );
+
+ fd = open( device,
+ ((dev->access & MOU_WRITE )? O_RDWR : O_RDONLY) |
+ ((dev->access & (MOU_VIRTUAL|PHY_CREATE)) == (MOU_VIRTUAL|PHY_CREATE)?
+ O_CREAT | O_EXCL : 0),
+ 0644 );
+ if( fd < 0 )
+ saverr = errno;
+#if DEBUG
+ printf( "%d = open( \"%s\", %s%s )\n", fd, device,
+ (dev->access & MOU_WRITE )? "O_RDWR" : "O_RDONLY",
+ (dev->access & PHY_CREATE)? "|O_CREAT|O_EXCL, 0666" : "" );
#endif
- if ( fd < 0 && dev->access & MOU_WRITE ) {
+ if ( fd < 0 && (dev->access & (MOU_WRITE|PHY_CREATE)) == MOU_WRITE ) {
dev->access &= ~MOU_WRITE;
fd = open( device, O_RDONLY );
-#ifdef DEBUG
+#if DEBUG
printf( "%d = open( \"%s\", O_RDONLY )\n", fd, device );
#endif
}
- free( device );
+ dev->handle = fd;
+
+ if( fd >= 0 ) {
+ if( fstat( fd, &statbuf ) == 0 ) {
+ if( dev->access & MOU_VIRTUAL ) {
+ if( !S_ISREG(statbuf.st_mode) ) {
+ printf( "%%ODS2-E-NOTFILE, %s is not a regular file\n", device );
+ close( fd );
+ dev->handle = -1;
+ sts = SS$_IVDEVNAM;
+ } else
+ dev->eofptr = statbuf.st_size;
+ } else {
+ if( !S_ISBLK(statbuf.st_mode ) ) {
+ printf( "%%ODS2-E-NOTFILE, %s is not a block device\n", device );
+ close( fd );
+ dev->handle = -1;
+ sts = SS$_IVDEVNAM;
+ }
+ }
+ } else {
+ if( !saverr )
+ saverr = errno;
+ close( fd );
+ dev->handle = -1;
+ fd = -1;
+ }
+ }
+
if ( fd < 0 ) {
-#ifdef DEBUG
+#if DEBUG
+ errno = saverr;
perror( "open" );
#endif
- return ( ( dev->access & MOU_VIRTUAL ) ?
- SS$_NOSUCHFILE : SS$_NOSUCHDEV );
+
+ errno = saverr;
+ switch( errno ) {
+ case EEXIST:
+ printf( "%%ODS2-E-EXISTS, File %s already exists, not superseded\n", device );
+ sts = SS$_DUPFILENAME;
+ break;
+ default:
+ printf( "%%ODS2-E-OPENERR, Open %s: %s\n", device, strerror( errno ) );
+ sts = (dev->access & MOU_VIRTUAL) ? SS$_NOSUCHFILE : SS$_NOSUCHDEV;
+ }
}
- dev->handle = fd;
- return SS$_NORMAL;
+ free( device );
+
+ return sts;
}
/*************************************************************** phyio_done() */
unsigned phyio_done( struct DEV *dev ) {
- close( dev->handle );
- dev->handle = 0;
- if( dev->access & MOU_VIRTUAL )
- virt_device( dev->devnam, NULL );
+ if( dev->handle != -1 )
+ close( dev->handle );
+ dev->handle = -1;
+
return SS$_NORMAL;
}
/*************************************************************** phyio_read() */
-unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
char *buffer ) {
ssize_t res;
off_t pos;
-#ifdef DEBUG
+#if DEBUG
printf("Phyio read block: %d into %p (%d bytes)\n",
block, buffer, length );
#endif
@@ -340,15 +392,19 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
pos = (off_t) block * (off_t) 512;
if ( ( pos = lseek( dev->handle, pos, SEEK_SET ) ) < 0 ) {
perror( "lseek " );
- printf("lseek failed %" PRIuMAX "u\n",(uintmax_t)pos);
+ printf("lseek failed %" PRIuMAX "\n",(uintmax_t)pos);
return SS$_PARITY;
}
if ( ( res = read( dev->handle, buffer, length ) ) != length ) {
if( res == 0 ) {
return SS$_ENDOFFILE;
}
- perror( "read " );
- printf("read failed %" PRIuMAX "u\n", (uintmax_t)res);
+ if( res == (off_t)-1 ) {
+ perror( "%%ODS2-F-READERR, read failed" );
+ } else {
+ printf( "%%ODS2-F-READERR, read failed with bc = %" PRIuMAX " for length %u, lbn %u\n",
+ (uintmax_t)res, length, block );
+ }
return SS$_PARITY;
}
return SS$_NORMAL;
@@ -356,13 +412,13 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
/************************************************************** phyio_write() */
-unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
const char *buffer ) {
off_t pos;
ssize_t res;
-#ifdef DEBUG
+#if DEBUG
printf("Phyio write block: %d from %p (%d bytes)\n",
block, buffer, length );
#endif
@@ -371,12 +427,16 @@ unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
pos = (off_t) block * (off_t) 512;
if ( ( pos = lseek( dev->handle, pos, SEEK_SET ) ) < 0 ) {
perror( "lseek " );
- printf( "lseek failed %" PRIuMAX "u\n", (uintmax_t)pos );
+ printf( "lseek failed %" PRIuMAX "\n", (uintmax_t)pos );
return SS$_PARITY;
}
if ( ( res = write( dev->handle, buffer, length ) ) != length ) {
- perror( "write " );
- printf( "write failed %" PRIuMAX "u\n", (uintmax_t)res );
+ if( res == (off_t)-1 ) {
+ perror( "%%ODS2-F-WRITEERR, write failed" );
+ } else {
+ printf( "%%ODS2-F-WRITEERR, write failed with bc = %" PRIuMAX " for length %u, lbn %u\n",
+ (uintmax_t)res, length, block );
+ }
return SS$_PARITY;
}
return SS$_NORMAL;
diff --git a/extracters/ods2/phyvhd.c b/extracters/ods2/phyvhd.c
new file mode 100644
index 0000000..3cbd59a
--- /dev/null
+++ b/extracters/ods2/phyvhd.c
@@ -0,0 +1,447 @@
+/* Phyvhd.c Physical I/O for VHD format disks */
+
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_PHYVHD )
+#define DEBUG DEBUG_PHYVHD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#ifndef phyvhd_BUFSIZE
+#define phyvhd_BUFSIZE (10 * 512)
+#endif
+
+#ifndef phyvhd_MINSIZE
+#define phyvhd_MINSIZE (20 * 1000 * 1000)
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _WIN32
+#include
+#define close _close
+#else
+#include
+#define _aligned_free free
+#endif
+
+#include "device.h"
+#include "ods2.h"
+#include "phyvirt.h"
+#include "ssdef.h"
+#include "stsdef.h"
+
+#include "libvhd.h"
+
+typedef vhd_context_t *vhd_contextp;
+typedef vhd_context_t vhd_context;
+
+#ifdef USE_LIBVHD
+#include
+#include
+#include
+#include
+#include
+
+typedef int (*vhd_open_p)( vhd_contextp ctx, const char *filename, int flags );
+typedef void (*vhd_close_p)( vhd_contextp ctx );
+typedef int (*vhd_create_p)(const char *file, uint64_t size,
+ int type, uint32_t flags );
+typedef int vhd_header_decode_parent(vhd_contextp ctx,
+ vhd_header_t *header, char **buf);
+typedef int (*vhd_snapshot_p)( const char *filename, const char *parent, uint64_t size,
+ const char *parentfile, uint32_t flags );
+typedef int (*vhd_io_read_p)(vhd_contextp ctx, void *buf, uint64_t pbn, uint32_t count );
+typedef int (*vhd_io_write_p)(vhd_contextp ctx, void *buf, uint64_t pbn, uint32_t count);
+typedef void (*libvhd_set_log_level_p)(int);
+typedef uint32_t (*vhd_chs_p)(uint64_t size);
+/* *** */
+
+static void *libvhd = NULL;
+
+#define vhddeclare(s) s ## _p s ## _fcn = NULL
+ vhddeclare(vhd_open);
+ vhddeclare(vhd_close);
+ vhddeclare(vhd_create);
+ vhddeclare(libvhd_set_log_level);
+ vhddeclare(vhd_header_decode_parent);
+ vhddeclare(vhd_snapshot);
+#if 0
+ vhddeclare(vhd_chs);
+#endif
+ vhddeclare(vhd_io_read);
+ vhddeclare(vhd_io_write);
+
+#define vhdresolve(s) do { \
+ if( libvhd != NULL && \
+ (s ## _fcn = (s ## _p)dlsym( libvhd, #s )) == NULL ) { \
+ printf( "VHD format image files can not be used\n" ); \
+ printf( "%%ODS2-F-NOSYM, Missing symbol %s in " LIBVHDSO(USE_LIBVHD) "\n", #s ); \
+ dlclose( libvhd ); \
+ libvhd = NULL; \
+ } \
+ } while( 0 )
+#else
+
+#define vhd_open_fcn vhd_open
+#define vhd_close_fcn vhd_close
+#define vhd_create_fcn vhd_create
+#define libvhd_set_log_level_fcn libvhd_set_log_level
+#define vhd_header_decode_parent_fcn vhd_header_decode_parent
+#define vhd_snapshot_fcn vhd_snapshot
+#if 0
+#define vhd_chs_fcn vhd_chs
+#endif
+#define vhd_io_read_fcn vhd_io_read
+#define vhd_io_write_fcn vhd_io_write
+
+#endif
+
+static unsigned phyvhd_read( struct DEV *dev, unsigned lbn, unsigned length,
+ char *buffer );
+static unsigned phyvhd_write( struct DEV *dev, unsigned lbn, unsigned length,
+ const char *buffer );
+
+/*********************************************************** phyvhd_available() */
+int phyvhd_available( int query ) {
+#ifdef USE_LIBVHD
+#define LIBVHDSOx(x) #x
+#define LIBVHDSO(n) LIBVHDSOx(n)
+
+ if( libvhd == NULL ) {
+ if( (libvhd = dlopen( LIBVHDSO(USE_LIBVHD), RTLD_LAZY )) == NULL ) {
+ const char *err;
+
+ if( query )
+ printf( "VHD format image file support is configud, but not available\n" );
+
+ printf( "%%ODS2-F-NOLIB, " LIBVHDSO(USE_LIBVHD) " not could not be loaded (see vhdtools or XEN libraries)" );
+ if( (err = dlerror()) != NULL )
+ printf( ": %s\n", err );
+ else
+ putchar( '\n' );
+ return FALSE;
+ }
+
+ vhdresolve( vhd_open );
+ vhdresolve( vhd_close );
+ vhdresolve( vhd_create );
+ vhdresolve( vhd_snapshot );
+ vhdresolve( libvhd_set_log_level );
+ vhdresolve( vhd_header_decode_parent );
+
+ vhdresolve( vhd_io_read );
+ vhdresolve( vhd_io_write );
+
+ if( libvhd == NULL ) {
+ printf( "%%ODS2-F-BADLIB, the " LIBVHDSO(USE_LIBVHD) " library is not valid\n" );
+ return FALSE;
+ }
+ }
+#endif
+
+ if( query )
+ printf( "VHD format image files can be used\n" );
+
+ return TRUE;
+}
+
+#ifdef _WIN32
+#pragma warning(push)
+#pragma warning(disable: 4996) /* MS complains about _open, which is open() */
+#endif
+/*********************************************************** phyvhd_snapshot() */
+unsigned phyvhd_snapshot( const char *filename, const char *parent ) {
+ int fd, err;
+ char *p;
+
+ if( !( (p = strrchr( filename, '.')) != NULL && ( !strcmp( p, ".vhd" ) ||
+ !strcmp( p, ".VHD" ) ) ) ) {
+ printf( "%%ODS2-E-NOTVHD, %s: Snapshots can only be taken of VHD format image files\n", filename );
+ return SS$_DUPFILENAME;
+ }
+
+#ifdef USE_LIBVHD
+ if( libvhd == NULL && !phyvhd_available( FALSE ) )
+ return SS$_NOTINSTALL;
+#endif
+
+#ifdef _WIN32
+ fd = _open( filename, _O_RDWR | _O_CREAT | _O_EXCL, 0644 );
+#else
+ fd = open( filename, O_RDWR | O_CREAT | O_EXCL, 0644 );
+#endif
+ if( fd == -1 ) {
+ printf( "%%ODS2-E-EXISTS, %s already exists\n", filename );
+ return SS$_DUPFILENAME;
+ }
+ err = vhd_snapshot_fcn( filename, 0, parent, 0 );
+ close( fd );
+
+ if( err == 0 )
+ return SS$_NORMAL;
+
+ printf( "%%ODS2-E-NOSNAP, snapshot failed\n" );
+ errno = -err;
+ perror( " - " );
+ return SS$_DEVOFFLINE;
+}
+
+/*********************************************************** phyvhd_init() */
+unsigned phyvhd_init( struct DEV *dev ) {
+ int err;
+ char *fname;
+ unsigned status;
+ long align;
+#ifdef _WIN32
+ SYSTEM_INFO inf;
+
+ GetSystemInfo( &inf );
+ align = inf.dwPageSize;
+#elif defined( _SC_PAGESIZE)
+ align = sysconf( _SC_PAGESIZE );
+#else
+ align = getpagesize();
+#endif
+
+#ifdef USE_LIBVHD
+ if( libvhd == NULL && !phyvhd_available( FALSE ) )
+ return SS$_NOTINSTALL;
+#endif
+ libvhd_set_log_level_fcn( -1 );
+
+ fname = virt_lookup( dev->devnam );
+ if( fname == NULL )
+ return SS$_NOSUCHDEV;
+
+ dev->devread = phyvhd_read;
+ dev->devwrite = phyvhd_write;
+
+#ifdef _WIN32
+ if( (dev->IoBuffer = _aligned_malloc( phyvhd_BUFSIZE, align )) == NULL ) {
+ printf( "Unable to allocate memory for bufer\n" );
+ return SS$_INSFMEM;
+ }
+
+ if( (dev->context = _aligned_malloc( sizeof( vhd_context ), align )) == NULL ) {
+ printf( "Unable to allocate memory for context\n" );
+ _aligned_free(dev->IoBuffer);
+ dev->IoBuffer = NULL;
+ return SS$_INSFMEM;
+ }
+#else
+ if( posix_memalign( (void**)&dev->IoBuffer, align, phyvhd_BUFSIZE ) != 0 ) {
+ printf( "Unable to allocate memory for bufer\n" );
+ return SS$_INSFMEM;
+ }
+ if( posix_memalign( (void**)&dev->context, align,
+ sizeof( vhd_context ) ) != 0 ) {
+ printf( "Unable to allocate memory for context\n" );
+ free(dev->IoBuffer);
+ dev->IoBuffer = NULL;
+ return SS$_INSFMEM;
+ }
+#endif
+
+ status = SS$_NORMAL;
+
+ do {
+ if( dev->access & PHY_CREATE ) {
+ disktypep_t dp;
+ uint64_t size;
+ int fd;
+
+#ifdef _WIN32
+ fd = _open( fname, _O_RDWR | _O_CREAT | _O_EXCL, 0644 );
+#else
+ fd = open( fname, O_RDWR | O_CREAT | O_EXCL, 0644 );
+#endif
+ if( fd == -1 ) {
+ close( fd );
+ status = SS$_DUPFILENAME;
+ break;
+ }
+ if( dev->access & MOU_LOG )
+ printf( "%%ODS2-I-VHDINIT, Formatting %s\n", fname );
+
+ dp = dev->disktype;
+ size = ((uint64_t)dp->sectors) * dp->tracks * dp->cylinders * dp->sectorsize;
+ size = (size + 511) / 512;
+ size *= 512;
+
+ err = vhd_create_fcn( fname, size, (size >= phyvhd_MINSIZE?
+ HD_TYPE_DYNAMIC: HD_TYPE_FIXED),
+ 0 );
+ close( fd );
+ if( err != 0 ) {
+ errno = -err;
+ perror( "vhd create" );
+ status = SS$_NOSUCHDEV;
+ break;
+ }
+ if( dev->access & MOU_LOG )
+ printf( "%%ODS2-I-VHDDONE, VHD volume formatting completed\n" );
+ }
+ err = vhd_open_fcn( dev->context, fname,
+ (dev->access & MOU_WRITE)?
+ VHD_OPEN_RDWR | VHD_OPEN_STRICT :
+ VHD_OPEN_RDONLY | VHD_OPEN_STRICT );
+ if( err != 0 && (dev->access & (MOU_WRITE|PHY_CREATE)) == MOU_WRITE ) {
+ dev->access &= ~MOU_WRITE;
+ err = vhd_open_fcn( dev->context, fname, VHD_OPEN_RDONLY | VHD_OPEN_STRICT );
+ }
+ if( err != 0 ) {
+ errno = -err;
+ perror( "vhd open" );
+ status = SS$_NOSUCHDEV;
+ break;
+ }
+ if( (dev->access & MOU_WRITE) && ((vhd_contextp)dev->context)->footer.saved ) {
+ printf( "%%ODS2-W-VHDSAVED, %s contains a suspended system and should not be modified\n", fname );
+ }
+ dev->eofptr = (off_t)(((vhd_contextp)dev->context)->footer.curr_size);
+ } while( 0 );
+
+ if( !(status & STS$M_SUCCESS) ) {
+ _aligned_free( dev->context );
+ _aligned_free( dev->IoBuffer );
+ dev->context =
+ dev->IoBuffer = NULL;
+ }
+ return status;
+}
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+/*********************************************************** phyvhd_show() */
+void phyvhd_show( struct DEV *dev, size_t column ) {
+ vhd_contextp ctx;
+ const char *type, *p;
+ size_t i, n;
+
+ if( (ctx = dev->context) == NULL )
+ return;
+ i = ctx->footer.type;
+ if( i > HD_TYPE_MAX )
+ type = "Unknown";
+ else
+ type = HD_TYPE_STR[i];
+
+ n = strlen( type );
+ if( (p = strchr( type, ' ' )) == NULL )
+ p = type + n;
+ n = (size_t) (p -type);
+
+ printf( " VHD %*.*s disk", (int)n, (int)n, type );
+ if( i == HD_TYPE_DIFF ) {
+ char *name;
+#define PLABEL "parent: "
+ if( vhd_header_decode_parent_fcn( ctx, &ctx->header, &name ) == 0 ) {
+ printf( "\n%*sparent: %s", (int)(column < sizeof( PLABEL ) -1?
+ (sizeof( PLABEL )-1)-column :
+ column - (sizeof( PLABEL ) -1)),
+ "", name );
+ free( name );
+ }
+ }
+
+ return;
+}
+/*********************************************************** phyvhd_read() */
+static unsigned phyvhd_read( struct DEV *dev, unsigned lbn, unsigned length,
+ char *buffer ) {
+ unsigned status;
+ int err;
+
+ status = SS$_NORMAL;
+ while( length > 0 ) {
+ unsigned rdsize;
+
+ rdsize = (length + 511) / 512;
+ rdsize = ( (rdsize > phyvhd_BUFSIZE/512)?
+ phyvhd_BUFSIZE/512 : rdsize );
+
+ if( (err = vhd_io_read_fcn(dev->context, dev->IoBuffer, lbn, rdsize)) != 0 ) {
+ if( err == -ERANGE )
+ return SS$_ILLBLKNUM;
+ return SS$_PARITY;
+ }
+ lbn += rdsize;
+ rdsize *= 512;
+ if( rdsize > length )
+ rdsize = length;
+ memcpy( buffer, dev->IoBuffer, rdsize );
+ buffer += rdsize;
+ length -= rdsize;
+ }
+ return status;
+}
+
+
+/*********************************************************** phyvhd_write() */
+
+static unsigned phyvhd_write( struct DEV *dev, unsigned lbn, unsigned length,
+ const char *buffer ) {
+ unsigned status;
+ int err;
+
+ status = SS$_NORMAL;
+ while( length > 0 ) {
+ unsigned wrsize, iosize;
+
+ iosize = (length + 511) / 512;
+ iosize = ( (iosize > phyvhd_BUFSIZE/512)?
+ phyvhd_BUFSIZE/512 : iosize );
+
+ wrsize = iosize * 512;
+ if( wrsize > length )
+ wrsize = length;
+ memcpy( dev->IoBuffer, buffer, wrsize );
+ buffer += wrsize;
+ length -= wrsize;
+
+ if( (err = vhd_io_write_fcn(dev->context, dev->IoBuffer, lbn, iosize)) != 0 ) {
+ if( err == -ERANGE )
+ return SS$_ILLBLKNUM;
+ return SS$_PARITY;
+ }
+ lbn += iosize;
+ }
+ return status;
+}
+
+/*********************************************************** phyvhd_close() */
+unsigned phyvhd_close( struct DEV *dev ) {
+ if( dev->context != NULL ) {
+ vhd_close_fcn( dev->context );
+ _aligned_free( dev->context );
+ dev->context = NULL;
+ }
+ _aligned_free( dev->IoBuffer );
+ dev->IoBuffer = NULL;
+ return SS$_NORMAL;
+}
+
diff --git a/extracters/ods2/phyvhd.h b/extracters/ods2/phyvhd.h
new file mode 100644
index 0000000..6c30bb2
--- /dev/null
+++ b/extracters/ods2/phyvhd.h
@@ -0,0 +1,13 @@
+#ifndef _PHYVHD_H
+#define _PHYVHD_H 1
+
+struct DEV;
+
+unsigned phyvhd_snapshot( const char *filename, const char *parent );
+unsigned phyvhd_init( struct DEV *dev );
+unsigned phyvhd_close( struct DEV *dev );
+void phyvhd_show( struct DEV *dev, size_t column );
+
+int phyvhd_available( int query );
+
+#endif
diff --git a/extracters/ods2/phyvirt.c b/extracters/ods2/phyvirt.c
index ccc1f8a..cb148c3 100644
--- a/extracters/ods2/phyvirt.c
+++ b/extracters/ods2/phyvirt.c
@@ -1,18 +1,25 @@
-/* Phyvirt.c V2.1 Module to map, remember and find virtual devices */
+/* Phyvirt.c Module to map, remember and find virtual devices */
/* Timothe Litt Feb 2016
* Incorporates some code from Larry Baker of the USGS.
*/
-/*
- This is part of ODS2 written by Paul Nankervis,
- email address: Paulnank@au1.ibm.com
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
- ODS2 is distributed freely for all members of the
- VMS community to use. However all derived works
- must maintain comments in their source to acknowledge
- the contibution of the original author.
-*/
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
/* A virtual device is used when normal file I/O is desired, e.g. to
* a disk image (simulator, .iso).
@@ -21,35 +28,78 @@
* /virtual to the mount command.
* If the device name is of the form dev:file, dev: becomes the
* virtual device name. Otherwise, a suitable name is created.
+ *
+ * This module also virtualizes all I/O, living between the filesystem
+ * and the platform-specific read/write LBN layer. This enables
+ * device specific transformations, such as interleave and skew.
+ *
+ * It also provides an access layer for VHD format image files, on
+ * platforms where libvhd is available.
*/
+#if !defined( DEBUG ) && defined( DEBUG_PHYVIRT )
+#define DEBUG DEBUG_PHYVIRT
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
+#include
#include
#include
#include
-#include "phyio.h"
-#include "ssdef.h"
+
#include "compat.h"
+#include "device.h"
+#include "ods2.h"
+#include "phyio.h"
+#include "phyvirt.h"
+#include "ssdef.h"
static struct VDEV {
struct VDEV *next;
char *devnam;
char *path;
+ struct DEV *dev;
} *virt_device_list = NULL;
+#ifdef USE_VHD
+#include "phyvhd.h"
+#endif
+
static int virt_compare( unsigned keylen, const char *keynam,
- const char *devnam );
+ const char *devnam );
static struct VDEV *virt_insert( const char *devnam, unsigned devsiz,
const char *path );
static void virt_remove( const char *devnam, unsigned devsiz );
+
+unsigned virt_open( char **devname, unsigned flags, struct DEV **dev );
+static unsigned virt_makedev( char *devnam, char **vname );
static char *autodev( void );
+static unsigned virt_assign( char *devnam, struct DEV *dev );
+unsigned virt_close( struct DEV *dev );
+
+static unsigned maplbn( unsigned lbn, disktypep_t dp, unsigned sect );
+
+unsigned virt_read( struct DEV *dev, unsigned lbn, unsigned length,
+ char *buffer ) ;
+unsigned virt_write( struct DEV *dev, unsigned lbn, unsigned length,
+ const char *buffer );
+unsigned virt_readp( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer );
+unsigned virt_writep( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer );
+static size_t get_devsiz( const char *devnam );
+
/************************************************************* virt_show() */
void virt_show( const char *devnam ) {
- unsigned devlen, devsiz;
+ unsigned devsiz;
struct VDEV *vp;
if( devnam == NULL ) {
@@ -81,16 +131,17 @@ void virt_show( const char *devnam ) {
for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
n = strlen( vp->path );
- printf( " %-*s %.*s\n", (int)maxd, vp->devnam, (int)maxp,
- (n > maxp)? vp->path+(n-maxp): vp->path );
+ printf( " %-*s %-*.*s", (int)maxd, vp->devnam, (int)maxp,
+ (int)maxp, (n > maxp)? vp->path+(n-maxp): vp->path );
+#ifdef USE_VHD
+ if( vp->dev->access & PHY_VHDDSK )
+ phyvhd_show( vp->dev, 2 + maxd + 1 + maxp + 1 );
+#endif
+ putchar( '\n' );
}
} else {
- devlen = strlen( devnam );
- for( devsiz = 0; devsiz < devlen; devsiz++ ) {
- if( devnam[devsiz] == ':' ) {
- break;
- }
- }
+ devsiz = get_devsiz( devnam );
+
if( devsiz == 0 ) {
return;
}
@@ -129,15 +180,10 @@ static int virt_compare( unsigned keylen, const char *keynam,
char *virt_lookup( const char *devnam ) {
- unsigned devlen, devsiz;
+ unsigned devsiz;
struct VDEV *vp;
- devlen = strlen( devnam );
- for( devsiz = 0; devsiz < devlen; devsiz++ ) {
- if( devnam[devsiz] == ':' ) {
- break;
- }
- }
+ devsiz = get_devsiz( devnam );
if( devsiz == 0 ) {
return NULL;
}
@@ -149,66 +195,6 @@ char *virt_lookup( const char *devnam ) {
return NULL;
}
-/*********************************************************** virt_device() */
-
-/* virt_device() creates/deletes virtual devices... */
-
-unsigned virt_device( char *devnam, char **vname ) {
-
- unsigned devlen, devsiz;
- char *path = NULL;
-
- if( vname != NULL ) {
- char *p;
- struct VDEV **vpp;
-
- if( (p = strchr( devnam, '=' )) != NULL ) {
- *p = '\0';
- path = ++p;
- } else {
- path = devnam;
- devnam = autodev();
- }
- if( (p = phyio_path( path )) == NULL || strlen( p ) == 0 ) {
- printf( "%%ODS2-E-BADPATH, Invalid path: %s\n", path );
- free( p );
- return SS$_BADPARAM;
- }
- path = p;
-
- for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
- if( strcmp( (*vpp)->path, path ) == 0 ) {
- printf( "%%ODS2-E-MAPPED, %s is in use on virtual drive %s\n", path, (*vpp)->devnam );
- free( path );
- return SS$_DEVMOUNT;
- }
- }
- }
- devlen = strlen( devnam );
-
- for( devsiz = 0; devsiz < devlen; devsiz++ ) {
- if( devnam[devsiz] == ':' ) {
- break;
- }
- }
- if( devsiz == 0 ) {
- free( path );
- return SS$_BADPARAM;
- }
- virt_remove( devnam, devsiz );
- if( vname != NULL ) {
- struct VDEV *vp;
-
- vp = virt_insert( devnam, devsiz, path );
- free( path );
- if( vp == NULL )
- return SS$_INSFMEM;
-
- *vname = vp->devnam;
- }
- return SS$_NORMAL;
-}
-
/*********************************************************** virt_insert() */
static struct VDEV *virt_insert( const char *devnam, unsigned devsiz,
@@ -231,6 +217,7 @@ static struct VDEV *virt_insert( const char *devnam, unsigned devsiz,
}
vp->devnam = (char *) malloc( devsiz + 1 );
vp->path = (char *) malloc( (pathsiz = strlen( path )) + 1 );
+
if( vp->devnam == NULL || vp->path == NULL ) {
free( vp->devnam );
free( vp->path );
@@ -240,6 +227,7 @@ static struct VDEV *virt_insert( const char *devnam, unsigned devsiz,
memcpy( vp->devnam, devnam, devsiz );
vp->devnam[devsiz] = '\0';
memcpy( vp->path, path, pathsiz+1 );
+ vp->dev = NULL;
vp->next = *here;
*here = vp;
@@ -264,6 +252,118 @@ static void virt_remove( const char *devnam, unsigned devsiz ) {
}
}
+/*********************************************************** virt_open() */
+/* Wrapper for phyio that handles the mechanics of virtual
+ * devices. Calls phyio_init with everything straightend out.
+ */
+
+unsigned virt_open( char **devname, unsigned flags, struct DEV **dev ) {
+ unsigned sts;
+
+ flags &= ~PHY_VHDDSK;
+
+ if( flags & MOU_VIRTUAL ) {
+ char *p;
+ if( (p = strrchr( *devname, '.')) != NULL && ( !strcmp( p, ".vhd" ) ||
+ !strcmp( p, ".VHD" ) ) ) {
+#ifdef USE_VHD
+ flags |= PHY_VHDDSK;
+#else
+ printf( "%%ODS2-W-NOVHD, VHD disk support is not available in this version\n" );
+ return SS$_IVDEVNAM;
+#endif
+ }
+
+ sts = virt_makedev( *devname, devname );
+ if( !(sts & STS$M_SUCCESS) )
+ return sts;
+ } else {
+ if( virt_lookup( *devname ) != NULL ) {
+ int devsiz;
+
+ devsiz = get_devsiz( *devname );
+ printf( "%%ODS2-E-VIRTDEV, %.*s is a virtual device\n",
+ (int)devsiz, *devname );
+ return SS$_DEVMOUNT;
+ }
+ }
+ sts = device_lookup( strlen( *devname ), *devname, TRUE, dev );
+ if( !(sts & STS$M_SUCCESS) ) {
+ if( flags & MOU_VIRTUAL )
+ virt_remove( *devname, get_devsiz( *devname ) );
+ return sts;
+ }
+ (*dev)->access = flags; /* Requested mount options */
+
+ (*dev)->disktype = disktype+((flags & MOU_DEVTYPE) >> MOU_V_DEVTYPE);
+
+ if( flags & PHY_VHDDSK ) {
+#ifdef USE_VHD
+ sts = phyvhd_init( *dev );
+#else
+ return SS$_IVDEVNAM;
+#endif
+ } else {
+ sts = phyio_init( *dev );
+ }
+
+ if( (flags & MOU_VIRTUAL) ) {
+ if( sts & STS$M_SUCCESS ) {
+ if( !((sts = virt_assign( *devname, *dev )) & STS$M_SUCCESS) ) {
+#ifdef USE_VHD
+ if( flags & PHY_VHDDSK )
+ phyvhd_close( *dev );
+ else
+#endif
+ phyio_done( *dev );
+ device_done( *dev );
+ }
+ } else
+ virt_remove( *devname, get_devsiz( *devname ) );
+ }
+ return sts;
+}
+
+/************************************************************* virt_virt_makedev() */
+
+/* First part of device creation:
+ * assign a virtual device to whatever path we have.
+ * We can't resolve the path or see if it's a duplicate because the
+ * file might not exist yet. (initialize)
+ */
+
+static unsigned virt_makedev( char *devnam, char **vname ) {
+ struct VDEV *vp;
+ unsigned devsiz;
+ char *path = NULL;
+ char *p;
+
+ if( (p = strchr( devnam, '=' )) != NULL ) {
+ *p = '\0';
+ path = ++p;
+ if( (p = virt_lookup( devnam)) != NULL ) {
+ printf( "%%ODS2-E-INUSE, %s is in use by %s\n", devnam, p );
+ return SS$_DEVALLOC;
+ }
+ } else {
+ path = devnam;
+ devnam = autodev();
+ }
+
+ devsiz = get_devsiz( devnam );
+ if( devsiz == 0 ) {
+ return SS$_BADPARAM;
+ }
+
+ vp = virt_insert( devnam, devsiz, path );
+ if( vp == NULL )
+ return SS$_INSFMEM;
+
+ *vname = vp->devnam;
+
+ return SS$_NORMAL;
+}
+
/************************************************************* autodev() */
char *autodev( void ) {
@@ -330,3 +430,690 @@ char *autodev( void ) {
d++;
}
}
+
+/************************************************************* virt_assign() */
+/* Part two:
+ * Resolve the pathname and check for duplicate use.
+ * Delete the device if we have issues. Otherwise, resolve
+ * and record the full path.
+ *
+ * virt_open will close the physical device if we have problems.
+ */
+
+static unsigned virt_assign( char *devnam, struct DEV *dev ) {
+ unsigned devsiz;
+ char *p;
+ struct VDEV *vp, **vpp;
+
+ devsiz = get_devsiz( devnam );
+ if( devsiz == 0 ) {
+ return SS$_BADPARAM;
+ }
+
+ for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
+ if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 )
+ break;
+ }
+ if( vp == NULL )
+ return SS$_BADPARAM;
+
+ if( (p = phyio_path( vp->path )) == NULL || strlen( p ) == 0 ) {
+ printf( "%%ODS2-E-BADPATH, Invalid path: %s\n", vp->path );
+ free( p );
+ virt_remove( devnam, devsiz );
+ return SS$_BADPARAM;
+ }
+
+ for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
+ if( (*vpp != vp) && strcmp( (*vpp)->path, p ) == 0 ) {
+ printf( "%%ODS2-E-MAPPED, %s is in use on virtual drive %s\n", p, (*vpp)->devnam );
+ free( p );
+ virt_remove( devnam, devsiz );
+ return SS$_DEVALLOC;
+ }
+ }
+
+ free( vp->path );
+ vp->path = p;
+ vp->dev = dev;
+
+ return SS$_NORMAL;
+}
+
+/*********************************************************** virt_close() */
+
+/* Destroy a (virtual) device.
+ * Wraps phyio_done;
+ */
+
+unsigned virt_close( struct DEV *dev ) {
+ unsigned devsiz;
+ unsigned sts;
+
+ cache_flush();
+
+ if( dev->access & MOU_VIRTUAL ) {
+ devsiz = get_devsiz( dev->devnam );
+ virt_remove( dev->devnam, devsiz );
+ }
+#ifdef USE_VHD
+ if( dev->access & PHY_VHDDSK )
+ sts = phyvhd_close( dev );
+ else
+#endif
+ sts = phyio_done( dev );
+ device_done( dev );
+ return sts;
+}
+
+/*********************************************************** maplbn() */
+/* Map an LBN as viewed by the OS to each of its physical sectors.
+ */
+
+static unsigned maplbn( unsigned lbn, disktypep_t dp, unsigned sect ) {
+ unsigned c, t, s;
+ ldiv_t r;
+
+ lbn = (lbn * (512 / dp->sectorsize)) + sect;
+
+ r = ldiv( lbn, dp->sectors * dp->tracks );
+ c = r.quot;
+ r = ldiv( r.rem, dp->sectors );
+ t = r.quot;
+ s = r.rem;
+
+ if( s >= dp->sectors / dp->interleave )
+ s = (s * dp->interleave) - (dp->sectors -1);
+ else
+ s = s * dp->interleave;
+
+ s = (s + (dp->skew * c)) % dp->sectors;
+
+ return (c * dp->sectors * dp->tracks) + (t * dp->sectors) + dp->reserved + s;
+}
+
+/*********************************************************** virt_read() */
+
+unsigned virt_read( struct DEV *dev, unsigned lbn, unsigned length,
+ char *buffer ) {
+ disktypep_t dp;
+ char *lbnbuf = NULL;
+ unsigned status, secblk;
+ off_t devlimit, end, eofptr;
+#ifdef DEBUG_DISKIO
+ unsigned inlbn = lbn, inlen = length;
+ char *inbuf = buffer;
+#endif
+
+ dp = dev->disktype;
+
+ /* First pass - inefficient but should function.
+ * First bit of ugliness is that simulator files may be smaller than the
+ * device size (not sparse, EOF isn't set). The filesystem will happily
+ * read never-written data (not a security issue), so we have to emulate
+ * sparse file semantics up to the device size. (For write, the file will
+ * extend.)
+ *
+ * Second is that interleaved devices cause lots of seeks. This could be
+ * a lot smarter - but then the filesystem has a cache and those devices
+ * tend to be small. So there's no rush to do better.
+ *
+ * Third, disk ID by the user isn't reliable; especially for images of
+ * physical disks. This can cause file system accesses to valid data
+ * to exceed the limit established by (alleged) geometry.
+ *
+ * Fourth, the (virtual) size of VHD files is not necessarily what was
+ * requested; it may have been rounded up to a page boundary.
+ */
+
+ devlimit = ((off_t)dp->sectors) * dp->tracks * dp->cylinders * dp->sectorsize;
+ eofptr = dev->eofptr;
+
+ if( eofptr > devlimit )
+ devlimit = eofptr;
+
+ status = SS$_NORMAL;
+
+ if( dp->reserved == 0 && dp->interleave == 0 && dp->skew == 0 ) {
+ if( (dev->access & MOU_VIRTUAL) &&
+ (end = ((off_t)lbn * 512 + length)) > eofptr ) {
+ unsigned avail;
+ off_t start;
+
+ if( end > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Read from non-existent block %lu\n",
+ ((end + dp->sectorsize -1)/dp->sectorsize) );
+ return SS$_ILLBLKNUM;
+ }
+ start = (off_t)lbn * 512;
+
+ if( start < eofptr ) {
+ avail = (unsigned)( eofptr - start );
+
+ status = dev->devread( dev, lbn, avail, buffer );
+ if( !(status & STS$M_SUCCESS) )
+ return status;
+
+ length -= avail;
+ buffer += avail;
+ }
+ memset( buffer, 0, length );
+#ifdef DEBUG_DISKIO
+ dumpblock( inlbn, inlen, inbuf, "Virt Read with %u bytes of fill status %08X",
+ length, status );
+#endif
+ return status;
+ }
+ status = dev->devread( dev, lbn, length, buffer );
+#ifdef DEBUG_DISKIO
+ dumpblock( inlbn, inlen, inbuf, "Virt Read status %08X", status );
+#endif
+ return status;
+ }
+
+ status = SS$_NORMAL;
+
+ if( dp->sectorsize > 512 )
+ abort(); /* TODO *** Handle large sectors, e.g. CDROM 2K where multiple LBNs fit into one. */
+
+ secblk = 512 / dp->sectorsize;
+ if( (lbnbuf = malloc( 512 * 2 )) == NULL )
+ return SS$_INSFMEM;
+
+ while( length > 0 && (status & STS$M_SUCCESS) ) {
+ unsigned pbn;
+ unsigned s;
+
+ for( s = 0; s < secblk && length > 0; s++ ) {
+ unsigned n;
+ ldiv_t r;
+
+ pbn = maplbn( lbn, dp, s );
+
+ r = ldiv( (pbn * dp->sectorsize), 512 );
+
+ n = r.rem + (length > dp->sectorsize? dp->sectorsize: length);
+
+ if( (dev->access & MOU_VIRTUAL) &&
+ (end = ((off_t)r.quot * 512 + n)) > eofptr ) {
+ unsigned avail;
+ off_t start;
+
+ if( ((off_t)pbn * (long)dp->sectorsize) + (long)n - r.rem > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Read from non-existent block %lu\n",
+ (((pbn * dp->sectorsize + n) + dp->sectorsize -1) /
+ dp->sectorsize) -1 );
+ status = SS$_ILLBLKNUM;
+ break;
+ }
+
+ start = (off_t)r.quot * 512;
+
+ if( start < eofptr ) {
+ avail = (unsigned)( eofptr - start );
+
+ status = dev->devread( dev, r.quot, avail, lbnbuf );
+ if( !(status & STS$M_SUCCESS) )
+ return status;
+
+ memset( lbnbuf+avail, 0, n - avail );
+ } else
+ memset( lbnbuf, 0, n );
+ } else {
+ status = dev->devread( dev, r.quot, n, lbnbuf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+ }
+ n = (dp->sectorsize > length)? length: dp->sectorsize;
+ memcpy( buffer, lbnbuf+r.rem, n );
+ buffer += n;
+ length -= n;
+ }
+ ++lbn;
+ }
+ free( lbnbuf );
+#ifdef DEBUG_DISKIO
+ dumpblock( inlbn, inlen, inbuf, "Virt Read interleaved status %08X", status );
+#endif
+ return status;
+}
+
+/*********************************************************** virt_write() */
+
+unsigned virt_write( struct DEV *dev, unsigned lbn, unsigned length,
+ const char *buffer ) {
+ disktypep_t dp;
+ char *lbnbuf = NULL;
+ unsigned status, secblk;
+ off_t devlimit, start, end;
+#ifdef DEBUG_DISKIO
+ unsigned inlbn = lbn, inlen = length;
+ const char *inbuf = buffer;
+#endif
+
+ dp = dev->disktype;
+
+ devlimit = ((off_t)dp->sectors) * dp->tracks * dp->cylinders * dp->sectorsize;
+ if( dev->eofptr > devlimit )
+ devlimit = dev->eofptr;
+
+ end = ((off_t)lbn * 512) + length;
+
+ if( dp->reserved == 0 && dp->interleave == 0 && dp->skew == 0 ) {
+ if( (end + 511)/512 > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Write to non-existent block %lu\n",
+ ((end + dp->sectorsize -1)/dp->sectorsize) );
+ return SS$_ILLBLKNUM;
+ }
+ status = dev->devwrite( dev, lbn, length, buffer );
+#ifdef DEBUG_DISKIO
+ dumpblock( inlbn, inlen, inbuf, "Virt Write, status %08X", status );
+#endif
+ if( (status & STS$M_SUCCESS) && (dev->access & MOU_VIRTUAL) ) {
+ if( end > dev->eofptr ) {
+ dev->eofptr = end;
+ }
+ }
+ return status;
+ }
+
+ status = SS$_NORMAL;
+
+ if( dp->sectorsize > 512 )
+ abort(); /* TODO *** Handle large sectors, e.g. CDROM 2K where multiple LBNs fit into one. */
+
+ secblk = 512 / dp->sectorsize;
+ if( (lbnbuf = malloc( 512 * 2 )) == NULL )
+ return SS$_INSFMEM;
+
+ while( length > 0 && (status & STS$M_SUCCESS) ) {
+ unsigned pbn;
+ unsigned s;
+
+ for( s = 0; s < secblk && length > 0; s++ ) {
+ unsigned n, m;
+ ldiv_t r;
+
+ pbn = maplbn( lbn, dp, s );
+
+ r = ldiv( (pbn * dp->sectorsize), 512 );
+
+ n = r.rem + (length > dp->sectorsize? dp->sectorsize: length);
+
+ start = (off_t)r.quot * 512;
+ m = ((n + 511) / 512) * 512;
+ if( start < dev->eofptr && (off_t)(start + m) > dev->eofptr )
+ m = (unsigned)(dev->eofptr - start);
+
+ if( dev->access & MOU_VIRTUAL ) {
+ if( ((off_t)pbn * (long)dp->sectorsize) + ((long)n - r.rem) > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Write to non-existent block %lu\n",
+ (((pbn * dp->sectorsize) + (n - r.rem) +
+ dp->sectorsize -1) / dp->sectorsize ) -1 );
+ status = SS$_ILLBLKNUM;
+ break;
+ }
+ }
+ memset( lbnbuf, 0, 512 * 2 );
+ if( start < dev->eofptr ) {
+ status = dev->devread( dev, r.quot, m, lbnbuf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+ if( m < n )
+ memset( lbnbuf+m, 0, n - m );
+ }
+ memcpy( lbnbuf+r.rem, buffer, n - r.rem );
+ end = start + n;
+ if( end > dev->eofptr ) {
+ status = dev->devwrite( dev, r.quot, n, lbnbuf );
+ dev->eofptr = end;
+ } else
+ status = dev->devwrite( dev, r.quot, m, lbnbuf );
+
+ if( !(status & STS$M_SUCCESS) )
+ break;
+ n -= r.rem;
+ buffer += n;
+ length -= n;
+ }
+ ++lbn;
+ }
+#ifdef DEBUG_DISKIO
+ dumpblock( inlbn, inlen, inbuf, "Virt Write (interleaved) status %08X", status );
+#endif
+
+ free( lbnbuf );
+ return status;
+}
+
+/*********************************************************** virt_readp() */
+
+unsigned virt_readp( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer ) {
+ disktypep_t dp;
+ unsigned status;
+ off_t devlimit, eofptr;
+ off_t fp, offset;
+ char *buf;
+ unsigned avail;
+
+ dp = dev->disktype;
+
+ devlimit = ((off_t)dp->sectors) * dp->tracks * dp->cylinders * dp->sectorsize;
+ if( dev->eofptr > devlimit )
+ devlimit = dev->eofptr;
+
+ status = SS$_NORMAL;
+ fp = ((off_t)pbn) * dp->sectorsize;
+
+ if( fp + (off_t)length > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Read from non-existent block %lu\n",
+ ((fp + length + dp->sectorsize -1)/dp->sectorsize) );
+ return SS$_ILLBLKNUM;
+ }
+
+ if( dev->access & MOU_VIRTUAL ) {
+ eofptr = dev->eofptr;
+
+ if( fp >= eofptr ) {
+ memset( buffer, 0, length );
+#ifdef DEBUG_DISKIO
+ dumpblock( pbn, length, buffer, "Phys Read of unallocated block status %08X",
+ status );
+#endif
+ return status;
+ }
+ } else {
+ eofptr = devlimit;
+ }
+
+ offset = fp % 512;
+
+ avail = (unsigned)(eofptr - fp);
+ if( avail > length )
+ avail = length;
+
+ if( offset == 0 ) {
+ status = dev->devread( dev, (unsigned) (fp / 512), avail, buffer );
+ if( !(status & STS$M_SUCCESS) )
+ return status;
+
+ length -= avail;
+ buffer += avail;
+
+ if( length > 0 )
+ memset( buffer, 0, length );
+#ifdef DEBUG_DISKIO
+ dumpblock( pbn, avail+length, buffer-avail, "Phys Read with %u bytes of fill status %08X",
+ length, status );
+#endif
+ return status;
+ }
+ if( (buf = malloc( (size_t) (offset + avail) )) == NULL )
+ return SS$_INSFMEM;
+ status = dev->devread( dev, (unsigned) (fp / 512), (unsigned) (offset + avail), buf );
+
+ memcpy( buffer, buf+offset, avail );
+ free( buf );
+ length -= avail;
+ buffer += avail;
+ if( length > 0 )
+ memset( buffer, 0, length );
+#ifdef DEBUG_DISKIO
+ dumpblock( pbn, avail+length, buffer-avail, "Phys Read with %u bytes of fill status %08X",
+ length, status );
+#endif
+ return status;
+}
+
+/*********************************************************** virt_writep() */
+
+unsigned virt_writep( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer ) {
+ disktypep_t dp;
+ unsigned status;
+ off_t devlimit;
+ off_t fp, offset;
+ char *buf = NULL;
+ unsigned avail, n, m;
+#ifdef DEBUG_DISKIO
+ unsigned inpbn = pbn, inlen = length;
+ const char *inbuf = buffer;
+#endif
+
+ dp = dev->disktype;
+
+ devlimit = ((off_t)dp->sectors) * dp->tracks * dp->cylinders * dp->sectorsize;
+ if( dev->eofptr > devlimit )
+ devlimit = dev->eofptr;
+
+ status = SS$_NORMAL;
+ fp = ((off_t)pbn) * dp->sectorsize;
+
+ if( fp + (off_t)length > devlimit ) {
+ printf( "%%ODS2-E-BLK2BIG, Write to non-existent block %lu\n",
+ ((fp + length + dp->sectorsize -1)/dp->sectorsize) );
+ return SS$_ILLBLKNUM;
+ }
+
+ offset = fp % 512;
+
+ if( offset == 0 && length % 512 == 0 ) {
+ status = dev->devwrite( dev, (unsigned)(fp / 512), length, buffer );
+#ifdef DEBUG_DISKIO
+ dumpblock( inpbn, inlen, inbuf, "Phys Write, status %08X", status );
+#endif
+ if( dev->access & MOU_VIRTUAL ) {
+ fp += length;
+ if( fp > dev->eofptr )
+ dev->eofptr = fp;
+ }
+ return status;
+ }
+
+ if( (buf = malloc( 512 )) == NULL )
+ return SS$_INSFMEM;
+
+ do {
+ if( offset != 0 ) {
+ avail = (unsigned) ( devlimit - (fp -offset) );
+
+ n = (avail > 512)? 512: avail;
+
+ status = dev->devread( dev, (unsigned) (fp / 512), n, buf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+
+ m = (n > length)? length: n;
+
+ memcpy( buf+offset, buffer, m );
+ buffer += m;
+ length -= m;
+
+ status = dev->devwrite( dev, (unsigned) (fp / 512), n, buf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+ fp += n;
+ }
+
+ if( (n = length / 512) > 0 ) {
+ n *= 512;
+ status = dev->devwrite( dev, (unsigned) (fp / 512), n, buffer );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+
+ buffer += n;
+ length -= n;
+ fp += n;
+ }
+
+ if( length > 0 ) {
+ avail = (unsigned) ( devlimit - fp );
+
+ n = (avail > 512)? 512: avail;
+
+ status = dev->devread( dev, (unsigned) (fp / 512), n, buf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+
+ m = (n > length)? length: n;
+
+ memcpy( buf, buffer, m );
+ buffer += m;
+ length -= m;
+
+ status = dev->devwrite( dev, (unsigned) (fp / 512), n, buf );
+ if( !(status & STS$M_SUCCESS) )
+ break;
+
+ fp += n;
+ }
+ if( length != 0 )
+ status = SS$_BUGCHECK;
+ } while( 0 );
+
+ if( (dev->access & MOU_VIRTUAL) && fp > dev->eofptr )
+ dev->eofptr = fp;
+
+#ifdef DEBUG_DISKIO
+ dumpblock( inpbn, inlen, inbuf, "Phys Write, status %08X", status );
+#endif
+ free( buf );
+ return status;
+}
+
+/*********************************************************** vget_devsiz() */
+
+static size_t get_devsiz( const char *devnam ) {
+ const char *p;
+
+ if( (p = strchr( devnam, ':' )) == NULL )
+ return strlen( devnam );
+
+ return (size_t)( p - devnam );
+}
+
+/*********************************************************** disktype */
+
+#define DISK( name, sectors, tracks, cylinders, flags ) \
+ {#name, 512 ## ul, sectors ## ul, tracks ## ul, cylinders ## ul, \
+ 0 ## ul, 0 ## ul, 0 ## ul, (flags)},
+#define DISKS( name, sectorsize, sectors, tracks, cylinders, reserved, flags ) \
+ {#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul, \
+ reserved ## ul, 0 ## ul, 0 ## ul, (flags)},
+#define DISKI( name, sectorsize, sectors, tracks, cylinders, reserved, \
+ interleave, skew, flags ) \
+ {#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul, \
+ reserved ## ul, interleave ## ul, skew ## ul, (flags)},
+
+disktype_t disktype[] = {
+ DISK(UNKNOWN, 574, 1, 1,DISK_BADSW) /* First = short sequence delta = 1 */
+
+#if 0
+ DISK(RB02, 20, 2, 512, DISK_BAD144)
+ DISK(RB80, 31, 14, 559, DISK_BAD144)
+#endif
+
+ DISK(RK05, 12, 2, 203, DISK_BAD144)
+ DISK(RK06, 22, 3, 411, DISK_BAD144)
+ DISK(RK07, 22, 3, 815, DISK_BAD144)
+ DISK(RK11, 12, 2, 203, DISK_BAD144)
+
+ DISKS(RL01, 256, 40, 2, 256, 0, DISK_BAD144)
+ DISKS(RL02, 256, 40, 2, 512, 0, DISK_BAD144)
+
+ DISK(RM02, 32, 5, 823, DISK_BAD144)
+ DISK(RM03, 32, 5, 823, DISK_BAD144)
+ DISK(RP04, 22, 19, 411, DISK_BAD144)
+ DISK(RP05, 22, 19, 411, DISK_BAD144)
+ DISK(RM80, 31, 14, 559, DISK_BAD144)
+ DISK(RP06, 22, 19, 815, DISK_BAD144)
+ DISK(RM05, 32, 19, 823, DISK_BAD144)
+ DISK(RP07, 50, 32, 630, DISK_BAD144)
+
+#if 0 /* Not useful now as RSX20-F used ODS-1 */
+ DISKS(RM02-T, 576, 30, 5, 823, 0, DISK_BAD144)
+ DISKS(RM03-T, 576, 30, 5, 823, 0, DISK_BAD144)
+ DISKS(RP04-T, 576, 20, 19, 411, 0, DISK_BAD144)
+ DISKS(RP05-T, 576, 20, 19, 411, 0, DISK_BAD144)
+ DISKS(RM80-T, 576, 30, 14, 559, 0, DISK_BAD144)
+ DISKS(RP06-T, 576, 20, 19, 815, 0, DISK_BAD144)
+ DISKS(RM05-T, 576, 30, 19, 823, 0, DISK_BAD144)
+ DISKS(RP07-T, 576, 43, 32, 630, 0, DISK_BAD144)
+#endif
+
+ DISK(RX50, 10, 1, 80, DISK_BADSW)
+ DISK(RX33, 15, 2, 80, DISK_BADSW)
+
+#if 0
+ DISK(RD50, 99, 99, 9999,0)
+#endif
+ DISK(RD51, 18, 4, 306,0)
+ DISK(RD31, 17, 4, 615,0)
+ DISK(RD52, 17, 8, 512,0)
+ DISK(RD53, 17, 7, 1024,0)
+ DISK(RD54, 17, 15, 1225,0)
+
+ DISK(RA72, 51, 20, 1921,0)
+
+#if 0
+ DISK(RA80, 99, 99, 9999,0)
+
+#endif
+ DISK(RA81, 51, 14, 1258,0)
+ DISK(RA82, 57, 15, 1435,0)
+
+ DISK(RA90, 69, 13, 2649,0)
+ DISK(RA92, 73, 13, 3099,0)
+
+ DISK(RRD40,128, 1, 10400,0)
+ DISK(RRD50,128, 1, 10400,0)
+ DISKI(RX01, 128, 26, 1, 77, 26, 2, 6, DISK_BADSW)
+ DISKI(RX02, 256, 26, 1, 77, 26, 2, 6, DISK_BADSW)
+
+#if 0
+ DISK(RX23-SD, 99, 99, 9999, DISK_BADSW)
+ DISK(RX23-DD, 99, 99, 9999, DISK_BADSW)
+
+ DISK(RX33-SD, 10, 1, 80, DISK_BADSW)
+ DISK(RX33-DD, 99, 99, 9999, DISK_BADSW)
+#endif
+
+ DISK(RX50, 10, 1, 80, DISK_BADSW)
+#if 0
+ DISK(RC25, 99, 99, 9999, 0)
+
+ DISK(RF30, 99, 99, 9999, 0)
+ DISK(RF31, 99, 99, 9999, 0)
+ DISK(RF35, 99, 99, 9999, 0)
+ DISK(RF36, 99, 99, 9999, 0)
+ DISK(RF71, 99, 99, 9999, 0)
+ DISK(RF72, 99, 99, 9999, 0)
+ DISK(RF73, 99, 99, 9999, 0)
+ DISK(RF74, 99, 99, 9999, 0)
+
+ DISK(RZ22, 99, 99, 9999, 0)
+ DISK(RZ23, 99, 99, 9999, 0)
+ DISK(RZ24, 99, 99, 9999, 0)
+ DISK(RZ25, 99, 99, 9999, 0)
+ DISK(RZ26, 99, 99, 9999, 0)
+ DISK(RZ27, 99, 99, 9999, 0)
+ DISK(RZ28, 99, 99, 9999, 0)
+ DISK(RZ29, 99, 99, 9999, 0)
+ DISK(RZ31, 99, 99, 9999, 0)
+ DISK(RZ33, 99, 99, 9999, 0)
+ DISK(RZ35, 99, 99, 9999, 0)
+ DISK(RZ55, 99, 99, 9999, 0)
+ DISK(RZ56, 99, 99, 9999, 0)
+ DISK(RZ57, 99, 99, 9999, 0)
+ DISK(RZ58, 99, 99, 9999, 0)
+ DISK(RZ59, 99, 99, 9999, 0)
+
+ DISK(RZ72, 99, 99, 9999, 0)
+ DISK(RZ73, 99, 99, 9999, 0)
+ DISK(RZ74, 99, 99, 9999, 0)
+#endif
+
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+size_t max_disktype = (sizeof( disktype ) / sizeof( disktype[0] )) - 2;
diff --git a/extracters/ods2/phyvirt.h b/extracters/ods2/phyvirt.h
index 400fabb..6631956 100644
--- a/extracters/ods2/phyvirt.h
+++ b/extracters/ods2/phyvirt.h
@@ -1,20 +1,61 @@
-/* Phyvirt.h V2.1 Definitions for virtual device routines */
+/* Phyvirt.h Definitions for virtual device routines */
+
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
/*
- This is part of ODS2 written by Paul Nankervis,
- email address: Paulnank@au1.ibm.com
-
- ODS2 is distributed freely for all members of the
- VMS community to use. However all derived works
- must maintain comments in their source to acknowledge
- the contibution of the original author.
-*/
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
#ifndef _PHYVIRT_H
#define _PHYVIRT_H
+#include
+
+typedef struct disktype disktype_t;
+typedef disktype_t *disktypep_t;
+
+struct disktype {
+ const char *name;
+ unsigned long sectorsize, sectors, tracks, cylinders;
+ unsigned long reserved, interleave, skew;
+ unsigned int flags;
+#define DISK_BAD144 1
+#define DISK_BADSW 2
+};
+
+extern struct disktype disktype[];
+extern size_t max_disktype;
+
+struct DEV;
+
void virt_show( const char *devnam );
+unsigned virt_open( char **devname, unsigned flags, struct DEV **dev );
char *virt_lookup( const char *devnam );
-unsigned virt_device( char *devnam, char **vname );
+unsigned virt_close( struct DEV *dev );
+
+unsigned virt_read( struct DEV *dev, unsigned lbn, unsigned length,
+ char *buffer );
+unsigned virt_write( struct DEV *dev, unsigned lbn, unsigned length,
+ const char *buffer );
+
+unsigned virt_readp( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer );
+unsigned virt_writep( struct DEV *dev, unsigned pbn, unsigned length,
+ char *buffer );
+
+#ifdef USE_VHD
+int virt_vhdavailable( int needed );
+#endif
#endif /* # ifndef _PHYVIRT_H */
diff --git a/extracters/ods2/phyvms.c b/extracters/ods2/phyvms.c
index 2d7d963..2ca1fb2 100644
--- a/extracters/ods2/phyvms.c
+++ b/extracters/ods2/phyvms.c
@@ -1,4 +1,4 @@
-/* PHYVMS.c V2.1 Physical I/O module for VMS */
+/* PHYVMS.c Physical I/O module for VMS */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -30,6 +30,14 @@
* Negative handle -> Unix I/O; positive handle -> SYS$QIOW().
*/
+#if !defined( DEBUG ) && defined( DEBUG_PHYVMS )
+#define DEBUG DEBUG_PHYVMS
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
#include
#include
@@ -78,7 +86,12 @@ unsigned sys$dassgn();
#include "ods2.h"
#include "phyio.h"
-#include "virtual.h"
+#include "phyvirt.h"
+
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer );
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer );
struct ITMLST {
unsigned short length;
@@ -252,12 +265,60 @@ unsigned phyio_init( struct DEV *dev ) {
init_count++;
- dev->handle = 0;
+ dev->handle = -1;
+ dev->devread = phyio_read;
+ dev->devwrite = phyio_write;
dev->sectors = 0;
- dev->access &= ~MOU_VIRTUAL;
- virtual = virt_lookup( dev->devnam );
- if ( virtual == NULL ) {
+ if( dev->access & MOU_VIRTUAL ) {
+ int vmsfd;
+ struct FAB fab;
+
+ virtual = virt_lookup( dev->devnam );
+ if ( virtual == NULL ) {
+ return SS$_NOSUCHDEV;
+ }
+#define opnopts "ctx=stm", "rfm=udf", "shr=get,put"
+ vmsfd = open( virtual,
+ ((dev->access & MOU_WRITE )? O_RDWR : O_RDONLY) |
+ ((dev->access & (MOU_VIRTUAL|PHY_CREATE)) == (MOU_VIRTUAL|PHY_CREATE)?
+ O_CREAT | O_EXCL : 0),
+ 0666, opnopts );
+
+ if ( vmsfd < 0 && (dev->access & (MOU_WRITE|PHY_CREATE)) == MOU_WRITE ) {
+ dev->access &= ~MOU_WRITE;
+ vmsfd = open( virtual, O_RDONLY, 0444, opnopts );
+ }
+ if ( vmsfd < 0 ) {
+ switch( errno ) {
+ case EEXIST:
+ printf( "%%ODS2-E-EXISTS, File %s already exists, not superseded\n",
+ virtual );
+ sts = SS$_DUPFILENAME;
+ break;
+ default:
+ printf( "%%ODS2-E-OPENERR, Open %s: %s\n",
+ virtual, strerror( errno ) );
+ }
+ return SS$_NOSUCHFILE;
+ }
+
+ dev->handle = vmsfd;
+
+ fab = cc$rms_fab; /* Make this a real FAB (bid and bln) */
+ fab.fab$l_fna = (char *) virtual;
+ fab.fab$b_fns = strlen( virtual );
+ sts = sys$open( &fab ); /* Lookup file, get file size */
+ if ( sts & STS$M_SUCCESS ) {
+ dev->sectors = fab.fab$l_alq;
+ sys$close( &fab );
+ if ( sizeof( off_t ) < 8 && dev->sectors > 0x3FFFFF ) {
+ close( vmsfd );
+ dev->handle = -1;
+ return SS$_OFFSET_TOO_BIG; /* Sorry, need 64-bit off_t */
+ }
+ }
+ } else { /* Physical */
struct dsc$descriptor devdsc;
unsigned long devclass, cylinders, tracks, sectors;
char devname[65];
@@ -318,34 +379,8 @@ unsigned phyio_init( struct DEV *dev ) {
if ( sts & STS$M_SUCCESS ) {
sts = sys$assign( &devdsc, &dev->handle, 0, 0, 0, 0 );
}
- } else {
- int vmsfd;
- struct FAB fab;
- fab = cc$rms_fab; /* Make this a real FAB (bid and bln) */
- fab.fab$l_fna = (char *) virtual;
- fab.fab$b_fns = strlen( virtual );
- sts = sys$open( &fab ); /* Lookup file, get file size */
- if ( sts & STS$M_SUCCESS ) {
- dev->sectors = fab.fab$l_alq;
- sys$close( &fab );
- if ( sizeof( off_t ) < 8 && dev->sectors > 0x3FFFFF ) {
- return SS$_OFFSET_TOO_BIG; /* Sorry, need 64-bit off_t */
- }
- dev->access |= MOU_VIRTUAL;
- vmsfd = ( dev->access & MOU_WRITE ) ?
- open( virtual, O_RDWR, 0666 ) :
- open( virtual, O_RDONLY, 0444 );
- if ( vmsfd < 0 && dev->access & MOU_WRITE ) {
- dev->access &= ~MOU_WRITE;
- vmsfd = open( virtual, O_RDONLY, 0444 );
- }
- if ( vmsfd < 0 ) {
- return SS$_NOSUCHFILE;
- }
- }
- dev->handle = vmsfd;
- sts = SS$_NORMAL;
}
+
return sts;
}
@@ -365,10 +400,10 @@ unsigned phyio_done( struct DEV *dev ) {
/*************************************************************** phyio_read() */
-unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
- char *buffer ) {
+static unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
+ char *buffer ) {
-#ifdef DEBUG
+#if DEBUG
printf("Phyio read block: %d into %x (%d bytes)\n",block,buffer,length);
#endif
read_count++;
@@ -396,10 +431,10 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
/************************************************************** phyio_write() */
-unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
- const char *buffer ) {
+static unsigned phyio_write( struct DEV *dev, unsigned block, unsigned length,
+ const char *buffer ) {
-#ifdef DEBUG
+#if DEBUG
printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length);
#endif
write_count++;
diff --git a/extracters/ods2/rms.c b/extracters/ods2/rms.c
index a9f494f..ef96d55 100644
--- a/extracters/ods2/rms.c
+++ b/extracters/ods2/rms.c
@@ -1,5 +1,5 @@
/* check for cr - return terminator - update file length */
-/* RMS.c V2.1 RMS components */
+/* RMS.c RMS components */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -19,6 +19,14 @@
file opens, gets, etc... */
+#if !defined( DEBUG ) && defined( DEBUG_RMS )
+#define DEBUG DEBUG_RMS
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#define DEBUGx x
#include
@@ -33,19 +41,13 @@
#include "device.h"
#include "direct.h"
#include "fibdef.h"
+#include "ods2.h"
#include "rms.h"
#include "ssdef.h"
#include "stsdef.h"
#include "compat.h"
#include "sysmsg.h"
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
/* For file context info we use WCCDIR and WCCFILE structures...
Each WCCFILE structure contains one WCCDIR structure for file
@@ -73,7 +75,7 @@
struct WCCDIR {
struct WCCDIR *wcd_next;
struct WCCDIR *wcd_prev;
-#ifdef DEBUG
+#if DEBUG
size_t size;
#endif
int wcd_status;
@@ -186,7 +188,7 @@ unsigned name_delim(char *str,int len,int size[5])
} else {
size[4] = 0;
}
-#ifdef DEBUG
+#if DEBUG
printf("Name delim %d %d %d %d %d\n",
size[0],size[1],size[2],size[3],size[4]);
#endif
@@ -268,13 +270,13 @@ void cleanup_wcf(struct WCCFILE **wccfilep)
struct WCCDIR *next = wcc->wcd_next;
wcc->wcd_next = NULL;
wcc->wcd_prev = NULL;
-#ifdef DEBUG
+#if DEBUG
memset(wcc,0,wcc->size);
#endif
free(wcc);
wcc = next;
}
-#ifdef DEBUG
+#if DEBUG
memset(wccfile,0,WCFALLOC_SIZE);
#endif
free(wccfile);
@@ -297,13 +299,14 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
/* if first time through position at top directory... WCCDIR */
- while ((wcc->wcd_status & STATUS_INIT) == 0 && wcc->wcd_next != NULL) {
+ while( !(wcc->wcd_status & STATUS_INIT) && wcc->wcd_next != NULL) {
wcc = wcc->wcd_next;
}
fibdsc.dsc_w_length = sizeof(struct fibdef);
fibdsc.dsc_a_pointer = (char *) &fibblk;
+ fab->fab__w_verlimit = 0;
while (TRUE) {
- if ((wcc->wcd_status & STATUS_INIT) == 0 || wcc->wcd_wcc != 0) {
+ if( !(wcc->wcd_status & STATUS_INIT) || wcc->wcd_wcc != 0) {
wcc->wcd_status |= STATUS_INIT;
resdsc.dsc_w_length = 256 - wcc->wcd_prelen;
resdsc.dsc_a_pointer = wccfile->wcf_result + wcc->wcd_prelen;
@@ -315,7 +318,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
fibblk.fib$b_fid_rvn = 0;
fibblk.fib$b_fid_nmx = 0;
fibblk.fib$l_wcc = wcc->wcd_wcc;
-#ifdef DEBUG
+#if DEBUG
wcc->wcd_sernam[wcc->wcd_serdsc.dsc_w_length] = '\0';
wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0';
printf("Ser: '%s' (%d,%d,%d) WCC: %d Prelen: %d '%s'\n",
@@ -331,7 +334,8 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
sts = SS$_NOMOREFILES;
}
if (sts & STS$M_SUCCESS) {
-#ifdef DEBUG
+ fab->fab__w_verlimit = fibblk.fib$w_verlimit; /* Nees a better mechanism** */
+#if DEBUG
wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0';
printf("Fnd: '%s' (%d,%d,%d) WCC: %d\n",
wccfile->wcf_result + wcc->wcd_prelen,
@@ -388,12 +392,12 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
return SS$_NORMAL;
}
} else {
-#ifdef DEBUG
- printf("Err: %d\n",sts);
+#if DEBUG
+ printf("Err: %s\n", getmsg( sts, MSG_TEXT ));
#endif
if (sts == SS$_BADIRECTORY) {
if (wcc->wcd_next != NULL) {
- if (wcc->wcd_next->wcd_status & STATUS_INIT) {
+ if( wcc->wcd_next->wcd_status & STATUS_INIT ) {
sts = SS$_NOMOREFILES;
}
}
@@ -410,10 +414,10 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
if (wcc->wcd_prev != NULL) {
wcc->wcd_prev->wcd_next = wcc->wcd_next;
}
- wcc = wcc->wcd_next;
+ wcc = wcc->wcd_next; /* 6 lines back, this can be null, so how can we reference ->prelen ->reslen?? */
memcpy(wccfile->wcf_result + wcc->wcd_prelen +
wcc->wcd_reslen - 6,".DIR;1",6);
-#ifdef DEBUG
+#if DEBUG
memset(savwcc, 0, savwcc->size);
#endif
free(savwcc);
@@ -425,7 +429,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
if ( newwcc == NULL ) {
return SS$_INSFMEM;
}
-#ifdef DEBUG
+#if DEBUG
newwcc->size = WCDALLOC_SIZE(8);
#endif
newwcc->wcd_next = wcc->wcd_next;
@@ -446,7 +450,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
wcc = newwcc;
} else {
if (wcc->wcd_next != NULL) {
-#ifdef DEBUG
+#if DEBUG
if (wcc->wcd_next->wcd_prev != wcc) {
printf("wcd_NEXT corruption\n");
}
@@ -664,10 +668,11 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret)
struct WCCDIR *wcc;
struct DEV *dev;
sts = device_lookup(fna_size[0],wccfile->wcf_result,FALSE,&dev);
- if ((sts & STS$M_SUCCESS) == 0) {
+ if( !(sts & STS$M_SUCCESS) ) {
/** cleanup_wcf(&wccfile); **/
return sts;
}
+ device_done(dev);
if ((wccfile->wcf_vcb = dev->vcb) == NULL) {
/** cleanup_wcf(&wccfile); **/
return SS$_DEVNOTMOUNT;
@@ -713,7 +718,7 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret)
if ( wcd == NULL ) {
return SS$_INSFMEM;
}
-#ifdef DEBUG
+#if DEBUG
wcd->size = WCDALLOC_SIZE(seglen + 8);
#endif
/* calloc()
@@ -746,10 +751,11 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret)
}
memcpy(wcc->wcd_sernam,wccfile->wcf_result + fna_size[0] + fna_size[1],
wcc->wcd_serdsc.dsc_w_length);
-#ifdef DEBUG
+#if DEBUG
wcc->wcd_sernam[wcc->wcd_serdsc.dsc_w_length] = '\0';
printf("Parse spec is %s\n",wccfile->wcf_wcd.wcd_sernam);
- for (dirsiz = 0; dirsiz < 5; dirsiz++) printf(" %d",fna_size[dirsiz]);
+ for (dirsiz = 0; dirsiz < 5; dirsiz++)
+ printf( " %d",fna_size[dirsiz] );
printf("\n");
#endif
}
@@ -874,134 +880,162 @@ unsigned sys_get(struct RAB *rab)
unsigned delim,rfm,sts;
struct VIOC *vioc;
struct FCB *fcb = ifi_table[rab->rab$l_fab->fab$w_ifi]->wcf_fcb;
+ int span;
reclen = rab->rab$w_usz;
recbuff = rab->rab$l_ubf;
- delim = 0;
- switch (rfm = rab->rab$l_fab->fab$b_rfm) {
- case FAB$C_STMLF:
- delim = 1;
- break;
- case FAB$C_STMCR:
- delim = 2;
- break;
- case FAB$C_STM:
- delim = 3;
- break;
- case FAB$C_VFC:
- reclen += rab->rab$l_fab->fab$b_fsz;
- break;
- case FAB$C_FIX:
- if (reclen < rab->rab$l_fab->fab$w_mrs)
- return RMS$_RTB;
- reclen = rab->rab$l_fab->fab$w_mrs;
- break;
- }
offset = rab->rab$w_rfa[2] % 512;
block = (rab->rab$w_rfa[1] << 16) + rab->rab$w_rfa[0];
if (block == 0)
block = 1;
- {
- unsigned eofblk = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
- if (block > eofblk || (block == eofblk &&
- offset >= VMSWORD(fcb->head->fh2$w_recattr.fat$w_ffbyte))) {
- return RMS$_EOF;
- }
- }
- sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,0);
- if (!(sts & STS$M_SUCCESS)) {
- if (sts == SS$_ENDOFFILE) sts = RMS$_EOF;
- return sts;
- }
+ span = (rab->rab$l_fab->fab$b_rat & FAB$M_BLK) == 0;
- if (rfm == FAB$C_VAR || rfm == FAB$C_VFC) {
- vmsword *lenptr = (vmsword *) (buffer + offset);
- reclen = VMSWORD(*lenptr);
- offset += 2;
- if (reclen > rab->rab$w_usz) {
- sts = deaccesschunk(vioc,0,0,FALSE);
+ delim = 0;
+ switch( rfm = rab->rab$l_fab->fab$b_rfm ) {
+ case FAB$C_STMLF:
+ delim = 1;
+ span = 1;
+ break;
+ case FAB$C_STMCR:
+ delim = 2;
+ span = 1;
+ break;
+ case FAB$C_STM:
+ delim = 3;
+ span = 1;
+ break;
+ case FAB$C_VFC:
+ reclen += rab->rab$l_fab->fab$b_fsz;
+ break;
+ case FAB$C_FIX:
+ if (reclen < rab->rab$l_fab->fab$w_mrs)
return RMS$_RTB;
- }
+ reclen = rab->rab$l_fab->fab$w_mrs;
+ break;
}
+ do {
+ unsigned eofblk = F11SWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
+ if (block > eofblk || (block == eofblk &&
+ offset >= F11WORD(fcb->head->fh2$w_recattr.fat$w_ffbyte))) {
+ return RMS$_EOF;
+ }
+
+ sts = accesschunk( fcb, block, &vioc, &buffer, &blocks, 0 );
+ if( !(sts & STS$M_SUCCESS) ) {
+ if (sts == SS$_ENDOFFILE) sts = RMS$_EOF;
+ return sts;
+ }
+
+ if( rfm == FAB$C_VAR || rfm == FAB$C_VFC ) {
+ do {
+ f11word *lenptr = (f11word *) (buffer + offset);
+
+ reclen = F11WORD(*lenptr);
+ offset += 2;
+ if( !span && offset + reclen > 510 ) { /* N.B. Length words 0xFFFF are used for fill */
+ block++;
+ offset = 0;
+ blocks--;
+ buffer += 512;
+ } else
+ span = 1;
+ } while( !span && blocks > 0 &&
+ (block < eofblk ||
+ (block == eofblk && fcb->head->fh2$w_recattr.fat$w_ffbyte > 0)) );
+ if( !span ) {
+ sts = deaccesschunk( vioc, 0, 0, FALSE );
+ continue;
+ }
+ if( reclen > rab->rab$w_usz ) {
+ sts = deaccesschunk(vioc,0,0,FALSE);
+ return RMS$_RTB;
+ }
+ }
+ } while( !span );
+
cpylen = 0;
while (TRUE) {
int dellen = 0;
unsigned int seglen = blocks * 512 - offset;
- if (delim) {
- if (delim >= 3) {
- char *ptr = buffer + offset;
- if (dellen == 1 && *ptr != '\n') {
- if (cpylen >= reclen) {
- seglen = 0;
- sts = RMS$_RTB;
- } else {
- *recbuff++ = '\r';
- cpylen++;
- }
- }
- while (seglen-- > 0) {
- char ch = *ptr++;
- if (ch == '\n' || ch == '\f' || ch == '\v') {
- if (ch == '\n') {
- dellen++;
+
+ if( seglen > 0 ) {
+ if (delim) {
+ if (delim >= 3) {
+ char *ptr = buffer + offset;
+ if (dellen == 1 && *ptr != '\n') {
+ if (cpylen >= reclen) {
+ seglen = 0;
+ sts = RMS$_RTB;
} else {
- dellen = 0;
+ *recbuff++ = '\r';
+ cpylen++;
}
- delim = 99;
- break;
}
- dellen = 0;
- if (ch == '\r') dellen = 1;
+ while (seglen-- > 0) {
+ char ch = *ptr++;
+ if (ch == '\n' || ch == '\f' || ch == '\v') {
+ if (ch == '\n') {
+ dellen++;
+ } else {
+ dellen = 0;
+ }
+ delim = 99;
+ break;
+ }
+ dellen = 0;
+ if (ch == '\r') dellen = 1;
+ }
+ seglen = ptr - (buffer + offset) - dellen;
+ } else {
+ char *ptr = buffer + offset;
+ char term = '\r';
+ if (delim == 1)
+ term = '\n';
+ while (seglen-- > 0) {
+ if (*ptr++ == term) {
+ dellen = 1;
+ delim = 99;
+ break;
+ }
+ }
+ seglen = ptr - (buffer + offset) - dellen;
}
- seglen = ptr - (buffer + offset) - dellen;;
} else {
- char *ptr = buffer + offset;
- char term = '\r';
- if (delim == 1)
- term = '\n';
- while (seglen-- > 0) {
- if (*ptr++ == term) {
- dellen = 1;
- delim = 99;
- break;
- }
+ if (seglen > reclen - cpylen)
+ seglen = reclen - cpylen;
+ if (rfm == FAB$C_VFC && cpylen < rab->rab$l_fab->fab$b_fsz) {
+ unsigned fsz = rab->rab$l_fab->fab$b_fsz - cpylen;
+ if (fsz > seglen)
+ if (rab->rab$l_rhb) {
+ memcpy(rab->rab$l_rhb + cpylen,buffer + offset,fsz);
+ }
+ cpylen += fsz;
+ offset += fsz;
+ seglen -= fsz;
}
- seglen = ptr - (buffer + offset) - dellen;;
}
- } else {
- if (seglen > reclen - cpylen)
- seglen = reclen - cpylen;
- if (rfm == FAB$C_VFC && cpylen < rab->rab$l_fab->fab$b_fsz) {
- unsigned fsz = rab->rab$l_fab->fab$b_fsz - cpylen;
- if (fsz > seglen)
- if (rab->rab$l_rhb) {
- memcpy(rab->rab$l_rhb + cpylen,buffer + offset,fsz);
+ if (seglen) {
+ if (cpylen + seglen > reclen) {
+ seglen = reclen - cpylen;
+ sts = RMS$_RTB;
}
- cpylen += fsz;
- offset += fsz;
- seglen -= fsz;
+ memcpy(recbuff,buffer + offset,seglen);
+ recbuff += seglen;
+ cpylen += seglen;
}
+ offset += seglen + dellen;
+ if ((offset & 1) && (rfm == FAB$C_VAR || rfm == FAB$C_VFC)) offset++;
}
- if (seglen) {
- if (cpylen + seglen > reclen) {
- seglen = reclen - cpylen;
- sts = RMS$_RTB;
- }
- memcpy(recbuff,buffer + offset,seglen);
- recbuff += seglen;
- cpylen += seglen;
- }
- offset += seglen + dellen;
- if ((offset & 1) && (rfm == FAB$C_VAR || rfm == FAB$C_VFC)) offset++;
-/* ??? This was missing the "sts = ". Assumed to be an error. (LMB) ??? */
- { unsigned sts2;
+
+ { unsigned sts2;
sts2 = deaccesschunk(vioc,0,0,TRUE);
if( (sts & STS$M_SUCCESS) ) sts = sts2;
}
- if (!(sts & STS$M_SUCCESS)) return sts;
+ if( !(sts & STS$M_SUCCESS) )
+ return sts;
block += offset / 512;
offset %= 512;
if ((delim == 0 && cpylen >= reclen) || delim == 99) {
@@ -1073,15 +1107,15 @@ unsigned sys_put(struct RAB *rab)
break;
}
- block = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
- offset = VMSWORD(fcb->head->fh2$w_recattr.fat$w_ffbyte);
+ block = F11SWAP(fcb->head->fh2$w_recattr.fat$l_efblk);
+ offset = F11WORD(fcb->head->fh2$w_recattr.fat$w_ffbyte);
sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,1);
if (!(sts & STS$M_SUCCESS)) return sts;
if (rfm == FAB$C_VAR || rfm == FAB$C_VFC) {
- vmsword *lenptr = (vmsword *) (buffer + offset);
- *lenptr = VMSWORD(reclen);
+ f11word *lenptr = (f11word *) (buffer + offset);
+ *lenptr = F11WORD(reclen);
offset += 2;
}
@@ -1115,11 +1149,11 @@ unsigned sys_put(struct RAB *rab)
case 1:
*buffer = '\n';
delim = 0;
- break;
+ break;
case 2:
*buffer = '\r';
delim = 0;
- break;
+ break;
case 3:
*buffer = '\r';
if (offset < blocks * 512) {
@@ -1147,8 +1181,8 @@ unsigned sys_put(struct RAB *rab)
if ((offset & 1) && (rfm == FAB$C_VAR || rfm == FAB$C_VFC)) offset++;
block += offset / 512;
offset %= 512;
- fcb->head->fh2$w_recattr.fat$l_efblk = VMSSWAP(block);
- fcb->head->fh2$w_recattr.fat$w_ffbyte = VMSWORD(offset);
+ fcb->head->fh2$w_recattr.fat$l_efblk = F11SWAP(block);
+ fcb->head->fh2$w_recattr.fat$w_ffbyte = F11WORD(offset);
rab->rab$w_rfa[0] = block & 0xffff;
rab->rab$w_rfa[1] = block >> 16;
rab->rab$w_rfa[2] = offset;
@@ -1170,15 +1204,16 @@ unsigned sys_display(struct FAB *fab)
int ifi_no = fab->fab$w_ifi;
if (ifi_no == 0 || ifi_no >= IFI_MAX)
return RMS$_IFI;
- fab->fab$l_alq = VMSSWAP(head->fh2$w_recattr.fat$l_hiblk);
+ fab->fab$l_alq = F11SWAP(head->fh2$w_recattr.fat$l_hiblk);
fab->fab$b_bks = head->fh2$w_recattr.fat$b_bktsize;
- fab->fab$w_deq = VMSWORD(head->fh2$w_recattr.fat$w_defext);
+ fab->fab$w_deq = F11WORD(head->fh2$w_recattr.fat$w_defext);
fab->fab$b_fsz = head->fh2$w_recattr.fat$b_vfcsize;
- fab->fab$w_gbc = VMSWORD(head->fh2$w_recattr.fat$w_gbc);
- fab->fab$w_mrs = VMSWORD(head->fh2$w_recattr.fat$w_maxrec);
+ fab->fab$w_gbc = F11WORD(head->fh2$w_recattr.fat$w_gbc);
+ fab->fab$w_mrs = F11WORD(head->fh2$w_recattr.fat$w_maxrec);
fab->fab$b_org = head->fh2$w_recattr.fat$b_rtype & 0xf0;
fab->fab$b_rfm = head->fh2$w_recattr.fat$b_rtype & 0x0f;
fab->fab$b_rat = head->fh2$w_recattr.fat$b_rattrib;
+
while (xab != NULL) {
switch (xab->xab$b_cod) {
case XAB$C_DAT:
@@ -1196,31 +1231,31 @@ unsigned sys_display(struct FAB *fab)
struct XABFHC *fhc = (struct XABFHC *) xab;
fhc->xab$b_atr = head->fh2$w_recattr.fat$b_rattrib;
fhc->xab$b_bkz = head->fh2$w_recattr.fat$b_bktsize;
- fhc->xab$w_dxq = VMSWORD(head->fh2$w_recattr.fat$w_defext);
- fhc->xab$l_ebk = VMSSWAP(head->fh2$w_recattr.fat$l_efblk);
- fhc->xab$w_ffb = VMSWORD(head->fh2$w_recattr.fat$w_ffbyte);
+ fhc->xab$w_dxq = F11WORD(head->fh2$w_recattr.fat$w_defext);
+ fhc->xab$l_ebk = F11SWAP(head->fh2$w_recattr.fat$l_efblk);
+ fhc->xab$w_ffb = F11WORD(head->fh2$w_recattr.fat$w_ffbyte);
if (fhc->xab$l_ebk == 0) {
fhc->xab$l_ebk = fab->fab$l_alq;
if (fhc->xab$w_ffb == 0) fhc->xab$l_ebk++;
}
- fhc->xab$w_gbc = VMSWORD(head->fh2$w_recattr.fat$w_gbc);
- fhc->xab$l_hbk = VMSSWAP(head->fh2$w_recattr.fat$l_hiblk);
+ fhc->xab$w_gbc = F11WORD(head->fh2$w_recattr.fat$w_gbc);
+ fhc->xab$l_hbk = F11SWAP(head->fh2$w_recattr.fat$l_hiblk);
fhc->xab$b_hsz = head->fh2$w_recattr.fat$b_vfcsize;
- fhc->xab$w_lrl = VMSWORD(head->fh2$w_recattr.fat$w_maxrec);
- fhc->xab$w_verlimit =
- VMSWORD(head->fh2$w_recattr.fat$w_versions);
- }
- break;
+ fhc->xab$w_lrl = F11WORD(head->fh2$w_recattr.fat$w_maxrec);
+ fhc->xab$w_verlimit = (F11LONG( head->fh2$l_filechar ) & FH2$M_DIRECTORY)?
+ F11WORD(head->fh2$w_recattr.fat$w_versions): fab->fab__w_verlimit;
+ }
+ break;
case XAB$C_PRO:{
struct XABPRO *pro = (struct XABPRO *) xab;
- pro->xab$w_pro = VMSWORD(head->fh2$w_fileprot);
+ pro->xab$w_pro = F11WORD(head->fh2$w_fileprot);
memcpy(&pro->xab$l_uic,&head->fh2$l_fileowner,4);
- }
- break;
+ }
+ break;
case XAB$C_ITM:{
struct XABITM *itm = (struct XABITM *) xab;
struct item_list *list;
- vmslong fch = VMSLONG( head->fh2$l_filechar );
+ f11long fch = F11LONG( head->fh2$l_filechar );
if( itm->xab$b_mode != XAB$K_SENSEMODE )
break;
@@ -1275,6 +1310,7 @@ unsigned sys_close(struct FAB *fab)
fab->fab$w_ifi = 0;
ifi_table[ifi_no] = NULL;
}
+ cache_flush(); /* Excessive, but seems safe... */
return sts;
}
@@ -1309,7 +1345,7 @@ unsigned sys_open(struct FAB *fab)
sts = RMS$_WLD;
} else {
sts = do_search(fab,wccfile);
- if ((sts & 1) == 0)
+ if( !(sts & STS$M_SUCCESS) )
wcc_flag = 0;
}
wccfile->wcf_status |= STATUS_TMPWCC;
@@ -1350,21 +1386,24 @@ unsigned sys_erase(struct FAB *fab)
int wcc_flag = FALSE;
struct WCCFILE *wccfile = NULL;
struct NAM *nam = fab->fab$l_nam;
- if (fab->fab$w_ifi != 0) return RMS$_IFI;
- while (ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX) ifi_no++;
- if (ifi_no >= IFI_MAX) return RMS$_IFI;
- if (nam != NULL) {
+
+ if( fab->fab$w_ifi != 0 )
+ return RMS$_IFI;
+ while( ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX ) ifi_no++;
+ if( ifi_no >= IFI_MAX ) return RMS$_IFI;
+
+ if( nam != NULL ) {
wccfile = (struct WCCFILE *) fab->fab$l_nam->nam$l_wcc;
}
if (wccfile == NULL) {
sts = do_parse(fab,&wccfile);
- if (sts & STS$M_SUCCESS) {
+ if( sts & STS$M_SUCCESS ) {
wcc_flag = TRUE;
- if (wccfile->wcf_status & STATUS_WILDCARD) {
+ if( wccfile->wcf_status & STATUS_WILDCARD ) {
sts = RMS$_WLD;
} else {
- sts = do_search(fab,wccfile);
- if ((sts & 1) == 0)
+ sts = do_search( fab,wccfile );
+ if( !(sts & STS$M_SUCCESS) )
wcc_flag = 0;
}
}
@@ -1374,13 +1413,15 @@ unsigned sys_erase(struct FAB *fab)
if (sts & STS$M_SUCCESS) {
struct fibdef fibblk;
struct dsc_descriptor fibdsc,serdsc;
+
fibdsc.dsc_w_length = sizeof(struct fibdef);
fibdsc.dsc_a_pointer = (char *) &fibblk;
serdsc.dsc_w_length = wccfile->wcf_wcd.wcd_reslen;
serdsc.dsc_a_pointer = wccfile->wcf_result +
wccfile->wcf_wcd.wcd_prelen;
- memcpy(&fibblk.fib$w_did_num,&wccfile->wcf_wcd.wcd_dirid,
- sizeof(struct fiddef));
+
+ memcpy( &fibblk.fib$w_did_num, &wccfile->wcf_wcd.wcd_dirid,
+ sizeof(struct fiddef));
fibblk.fib$w_nmctl = 0;
fibblk.fib$l_acctl = 0;
fibblk.fib$w_fid_num = 0;
@@ -1388,15 +1429,17 @@ unsigned sys_erase(struct FAB *fab)
fibblk.fib$b_fid_rvn = 0;
fibblk.fib$b_fid_nmx = 0;
fibblk.fib$l_wcc = 0;
- sts = direct(wccfile->wcf_vcb,&fibdsc,&serdsc,NULL,NULL,TRUE);
+
+ sts = direct( wccfile->wcf_vcb, &fibdsc, &serdsc,
+ NULL, NULL, DIRECT_DELETE ) ;
if (sts & STS$M_SUCCESS) {
- sts = accesserase(wccfile->wcf_vcb,&wccfile->wcf_fid);
+ sts = accesserase( wccfile->wcf_vcb, &wccfile->wcf_fid );
} else {
- printf("Direct status is %d\n",sts);
+ printf( "%%ODS2-E-DIRENT, failed to remove directory entry: %sn", getmsg( sts, MSG_TEXT ) );
}
}
- if (wcc_flag) {
- cleanup_wcf(&wccfile);
+ if( wcc_flag ) {
+ cleanup_wcf( &wccfile );
if (nam != NULL) {
nam->nam$l_wcc = NULL;
}
@@ -1494,6 +1537,8 @@ static void sys_rundown( void ) {
access_rundown();
sysmsg_rundown();
+
+ cache_purge(TRUE);
}
/*************************************************************** sys_initialize() */
diff --git a/extracters/ods2/rms.h b/extracters/ods2/rms.h
index 5775a8e..dfa82c5 100644
--- a/extracters/ods2/rms.h
+++ b/extracters/ods2/rms.h
@@ -1,4 +1,4 @@
-/* RMS.h V2.1 RMS routine definitions */
+/* RMS.h RMS routine definitions */
/*
This is part of ODS2 written by Paul Nankervis,
@@ -282,10 +282,11 @@ struct FAB {
int fab$b_rfm;
int fab$b_fac;
void *fab$l_xab;
+ unsigned short fab__w_verlimit;
};
#ifdef RMS$INITIALIZE
-struct FAB cc$rms_fab = {NULL,0,NULL,NULL,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL};
+struct FAB cc$rms_fab = {NULL,0,NULL,NULL,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL,0};
#else
extern struct FAB cc$rms_fab;
#endif
diff --git a/extracters/ods2/searchcmd.c b/extracters/ods2/searchcmd.c
new file mode 100644
index 0000000..a26bc45
--- /dev/null
+++ b/extracters/ods2/searchcmd.c
@@ -0,0 +1,153 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_SEARCHCMD )
+#define DEBUG DEBUG_SEARCHCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+
+/***************************************************************** dosearch() */
+
+/* dosearch: a simple file search routine */
+
+param_t searchpars[] = { {"filespec", REQ, VMSFS, NOPA, "for file to search. Wildcards are allowed."},
+ {"string", REQ, STRING, NOPA, "string to search for."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(search) {
+ int sts = 0;
+ int filecount = 0;
+ int findcount = 0;
+ char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
+ register char firstch, *searstr, *searend, *s;
+ struct NAM nam = cc$rms_nam;
+ struct FAB fab = cc$rms_fab;
+ struct RAB rab = cc$rms_rab;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ searstr = argv[2]; /* unquote( argv[2] ); */
+
+ searend = searstr + strlen( searstr );
+ for ( s = searstr; s < searend; s++ ) {
+ *s = tolower( *s );
+ }
+ firstch = *searstr++;
+ filecount = 0;
+ findcount = 0;
+ nam = cc$rms_nam;
+ fab = cc$rms_fab;
+ nam.nam$l_esa = res;
+ nam.nam$b_ess = NAM$C_MAXRSS;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ fab.fab$l_dna = "";
+ fab.fab$b_dns = strlen(fab.fab$l_dna);
+ sts = sys_parse(&fab);
+ if ( sts & STS$M_SUCCESS ) {
+ nam.nam$l_rsa = rsa;
+ nam.nam$b_rss = NAM$C_MAXRSS;
+ fab.fab$l_fop = FAB$M_NAM;
+ while ( ( sts = sys_search( &fab ) ) & STS$M_SUCCESS ) {
+ sts = sys_open(&fab);
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ printf("%%SEARCH-F-OPENFAIL, Open error: %s\n",getmsg(sts, MSG_TEXT));
+ } else {
+ rab.rab$l_fab = &fab;
+ sts = sys_connect( &rab );
+ if ( sts & STS$M_SUCCESS ) {
+ int printname = 1;
+ char *rec;
+
+ if( (rec = malloc( MAXREC + 2 )) == NULL )
+ sts = SS$_INSFMEM;
+ else {
+ filecount++;
+ rab.rab$l_ubf = rec;
+ rab.rab$w_usz = MAXREC;
+ while( (sts = sys_get( &rab )) & STS$M_SUCCESS ) {
+ register char *strng = rec;
+ register char *strngend = strng + (rab.rab$w_rsz -
+ (searend - searstr));
+ while( strng < strngend ) {
+ register char ch = *strng++;
+ if( ch == firstch ||
+ (ch >= 'A' && ch <= 'Z' &&
+ ch + 32 == firstch) ) {
+ register char *str = strng;
+ register char *cmp = searstr;
+ while( cmp < searend ) {
+ register char ch2 = *str++;
+ ch = *cmp;
+ if( ch2 != ch &&
+ (ch2 < 'A' || ch2 > 'Z' ||
+ ch2 + 32 != ch) ) break;
+ cmp++;
+ }
+ if( cmp >= searend ) {
+ findcount++;
+ rec[rab.rab$w_rsz] = '\0';
+ if( printname ) {
+ rsa[nam.nam$b_rsl] = '\0';
+ printf(
+ "\n******************************\n"
+ );
+ printf( "%s\n\n", rsa );
+ printname = 0;
+ }
+ fputs( rec, stdout );
+ if( fab.fab$b_rat & PRINT_ATTR ) {
+ fputc( '\n', stdout );
+ }
+ break;
+ }
+ }
+ }
+ }
+ free( rec );
+ rec = NULL;
+ }
+ sys_disconnect(&rab);
+ }
+ if (sts == SS$_NOTINSTALL) {
+ printf(
+ "%%SEARCH-W-NOIMPLEM, file operation not implemented\n"
+ );
+ sts = SS$_NORMAL;
+ }
+ sys_close(&fab);
+ }
+ }
+ if (sts == RMS$_NMF || sts == RMS$_FNF) sts = SS$_NORMAL;
+ }
+ if ( sts & STS$M_SUCCESS ) {
+ if (filecount < 1) {
+ printf("%%SEARCH-W-NOFILES, no files found\n");
+ } else {
+ if (findcount < 1) {
+ printf("%%SEARCH-I-NOMATCHES, no strings matched\n");
+ }
+ }
+ } else {
+ printf("%%SEARCH-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
+
+
diff --git a/extracters/ods2/setcmd.c b/extracters/ods2/setcmd.c
new file mode 100644
index 0000000..456e722
--- /dev/null
+++ b/extracters/ods2/setcmd.c
@@ -0,0 +1,202 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_SETCMD )
+#define DEBUG DEBUG_SETCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+static hlpfunc_t sethelp;
+
+static unsigned setcwd( char *newdef );
+static unsigned setdef( char *newdef );
+
+
+/******************************************************************* doset() */
+
+static qual_t setkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
+ {"directory_qualifiers", 1, 0, NV, "Default qualifiers for DIRECTORY command" },
+ {"default", 2, 0, NV, "Default directory on VMS volume"},
+ {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)"},
+ {"verify", 4, 0, NV, "-Display commands in indirect files"},
+ {"noverify", 5, 0, NV, NULL },
+ {NULL, 0, 0, NV, NULL }
+};
+static qual_t setqskwds[] = {{"unix", 1, 0, NV, "Unix style options, '-option'"},
+ {"vms", 2, 0, NV, "VMS style qualifiers, '/qualifier'"},
+ {NULL, 0, 0, NV, NULL }
+};
+param_t setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), "" },
+ {"value" , CND, KEYWD, sethelp, setqskwds, "" },
+ {NULL, 0, 0, NOPA, NULL },
+};
+
+/*********************************************************** doset() */
+
+extern qual_t dirquals[];
+extern const int dir_defaults;
+extern int dir_defopt;
+
+DECL_CMD(set) {
+ int parnum;
+
+ UNUSED(argc);
+
+ parnum = checkquals( 0, setkwds, -1, argv+1 );
+ switch( parnum ) {
+ default:
+ return SS$_BADPARAM;
+ case 0: /* default */
+ case 2: /* current working directory */
+ if( qualc ) {
+ printf( "%%ODS2-E-NOQUAL, No qualifiers are permitted\n" );
+ return 0;
+ }
+ return (parnum == 0)? setcwd( argv[2] ) : setdef( argv[2] );
+ case 1:{ /* directory_qualifiers */
+ int options = checkquals(dir_defaults,dirquals,qualc,qualv);
+ if( options == -1 )
+ return SS$_BADPARAM;
+ dir_defopt = options;
+ return 1;
+ }
+ case 3: { /* qualifier_style */
+ int par = checkquals (0,setqskwds,1,argv+2);
+ if( par == -1 )
+ return SS$_BADPARAM;
+ switch(par) {
+ default:
+ abort();
+ case 2:
+ vms_qual = 1;
+ break;
+ case 1:
+ vms_qual = 0;
+ break;
+ }
+ return 1;
+ }
+ case 4:
+ verify_cmd = 1;
+ return 1;
+ case 5:
+ verify_cmd = 0;
+ return 1;
+ }
+}
+
+/************************************************************ sethelp() */
+
+static const char * sethelp( CMDSETp_t cmd, paramp_t p, int argc, char **argv ) {
+ int par;
+
+ UNUSED( cmd );
+ UNUSED( argc );
+
+ if( argc == 1 ) {
+ p->helpstr = "";
+ p->ptype = KEYWD;
+ p->arg = setkwds;
+ return "Type 'help set value ITEM' for item details\n";
+ }
+
+ par = checkquals( 0, setkwds, -1, argv+1 );
+ if( par == -1 )
+ return NULL;
+ switch( par ) {
+ case 0:
+ p->helpstr = "working directory for local files";
+ p->ptype = STRING;
+ break;
+ case 1:
+ p->helpstr = "default directory on volume";
+ p->ptype = VMSFS;
+ break;
+ case 2:
+ p->helpstr = "directory qualifier name ";
+ p->ptype = KEYWD;
+ p->arg = dirquals;
+ break;
+ case 3:
+ p->helpstr = "style ";
+ p->ptype = KEYWD;
+ p->arg = setqskwds;
+ break;
+ case 4:
+ case 5:
+ p->ptype = NONE;
+ break;
+
+ default:
+ abort();
+ }
+ return NULL;
+}
+
+/*********************************************************** setcwd() */
+
+static unsigned setcwd( char *newdef ) {
+ if( chdir( newdef ) != 0 ) {
+ printf( "%%ODS2-W-SETDEF, Error %s setting cwd to %s\n",
+ strerror( errno ), newdef );
+ return SS$_BADPARAM;
+ }
+ return SS$_NORMAL;
+}
+
+/*********************************************************** setdef() */
+
+static int default_set = FALSE;
+
+static unsigned setdef( char *newdef ) {
+ register unsigned sts;
+ struct dsc_descriptor defdsc;
+
+ defdsc.dsc_a_pointer = (char *) newdef;
+ defdsc.dsc_w_length = (unsigned short)strlen( defdsc.dsc_a_pointer );
+ sts = sys_setddir( &defdsc, NULL, NULL );
+ if ( sts & STS$M_SUCCESS ) {
+ default_set = TRUE;
+ } else {
+ printf( "%%ODS2-E-SETDEF, Error %s setting default to %s\n", getmsg(sts, MSG_TEXT), newdef );
+ }
+ return sts;
+}
+
+/*********************************************************** mountdef() */
+
+int mountdef( const char *devnam ) {
+ char *colon, *buf;
+ size_t len;
+
+ if( default_set )
+ return SS$_NORMAL;
+
+ len = strlen( devnam );
+ buf = (char *) malloc( len + sizeof( ":[000000]" ));
+ if( buf == NULL ) {
+ perror( "malloc" );
+ return SS$_INSFMEM;
+ }
+
+ colon = strchr( devnam, ':' );
+ if( colon != NULL )
+ len = (size_t)(colon - devnam);
+ memcpy( buf, devnam, len );
+ memcpy( buf+len, ":[000000]", sizeof( ":[000000]" ) );
+ setdef(buf);
+ free( buf );
+
+ return SS$_NORMAL;
+}
diff --git a/extracters/ods2/showcmd.c b/extracters/ods2/showcmd.c
new file mode 100644
index 0000000..caa734b
--- /dev/null
+++ b/extracters/ods2/showcmd.c
@@ -0,0 +1,206 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_SHOWCMD )
+#define DEBUG DEBUG_SHOWCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#ifdef USE_READLINE
+#ifndef _GNU_SOURCE
+#define _XOPEN_SOURCE
+#endif
+#include
+#endif
+
+#include "access.h"
+#include "cache.h"
+#include "direct.h"
+#include "phyio.h"
+#ifdef USE_VHD
+#include "phyvhd.h"
+#endif
+#include "phyvirt.h"
+#include "version.h"
+
+static unsigned show_stats( void );
+
+void show_version( void );
+
+static char *get_cwd( void );
+
+
+/******************************************************************* doshow() */
+
+static qual_t showkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
+ {"default", 1, 0, NV, "Default directory on VMS volume"},
+ {"devices", 2, 0, NV, "Devices"},
+ {"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)" },
+ {"statistics", 4, 0, NV, "Debugging statistics"},
+ {"time", 5, 0, NV, "Time"},
+ {"verify", 6, 0, NV, "Command file echo" },
+ {"version", 7, 0, NV, "Version"},
+ {"volumes", 8, 0, NV, "Mounted volume information" },
+ {NULL, 0, 0, NV, NULL }
+};
+param_t showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), "" },
+ {NULL, 0, 0, NOPA, NULL }
+};
+
+/*********************************************************** doshow() */
+
+DECL_CMD(show) {
+ int parnum;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ parnum = checkquals( 0, showkwds, -1, argv+1 );
+ switch( parnum ) {
+ default:
+ return SS$_BADPARAM;
+ case 0: {
+ char *cwd;
+
+ cwd = get_cwd();
+ if( cwd == NULL ) {
+ return SS$_BADPARAM;
+ }
+ printf( " Current working directory is %s\n", cwd );
+ free( cwd );
+ return SS$_NORMAL;
+ }
+ case 1: {
+ int sts;
+ unsigned short curlen;
+ char curdir[NAM$C_MAXRSS + 1];
+ struct dsc_descriptor curdsc;
+ curdsc.dsc_w_length = NAM$C_MAXRSS;
+ curdsc.dsc_a_pointer = curdir;
+ sts = sys_setddir( NULL, &curlen, &curdsc );
+ if ( sts & STS$M_SUCCESS ) {
+ curdir[curlen] = '\0';
+ puts( curdir );
+ } else {
+ printf("%%ODS2-E-GETDEF, Error %s getting default\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+ }
+ case 2:
+ phyio_show( SHOW_DEVICES );
+ virt_show( NULL );
+ return SS$_NORMAL;
+ case 3:
+ printf ( " Qualifier style: %s\n", vms_qual? "/VMS": "-unix" );
+ return SS$_NORMAL;
+ case 4:
+ return show_stats();
+ case 5: {
+ unsigned sts;
+ char timstr[24];
+ unsigned short timlen;
+ struct dsc_descriptor timdsc;
+
+ timdsc.dsc_w_length = 20;
+ timdsc.dsc_a_pointer = timstr;
+ sts = sys$asctim( &timlen, &timdsc, NULL, 0 );
+ if ( sts & STS$M_SUCCESS ) {
+ timstr[timlen] = '\0';
+ printf(" %s\n",timstr);
+ } else {
+ printf("%%SHOW-W-TIMERR error %s\n",getmsg(sts, MSG_TEXT));
+ }
+ }
+ return SS$_NORMAL;
+ case 6:
+ printf( "Command file verification is %s\n", (verify_cmd? "on": "off") );
+ return SS$_NORMAL;
+ case 7:
+ show_version();
+ return SS$_NORMAL;
+ case 8:
+ show_volumes();
+ return SS$_NORMAL;
+ }
+ return SS$_NORMAL;
+}
+
+
+/****************************************************************** show_stats() */
+
+/* dostats: print some simple statistics */
+
+static unsigned show_stats( void ) {
+ printf("Statistics:-\n");
+ direct_show();
+ cache_show();
+ phyio_show(SHOW_STATS);
+
+ return SS$_NORMAL;
+}
+
+/*********************************************************** show_version() */
+
+
+void show_version( void ) {
+ printf(" %s %s", MNAME(MODULE_NAME), MODULE_IDENT );
+ printf( " built %s %s", __DATE__, __TIME__ );
+#ifdef USE_READLINE
+ printf(" with readline version %s", rl_library_version );
+#endif
+#ifdef USE_WNASPI32
+# ifdef USE_READLINE
+ printf( " and" );
+# else
+ printf( " with" );
+# endif
+ printf( " direct SCSI access support");
+#endif
+ printf( "\n " );
+ phyio_show( SHOW_FILE64 );
+#ifdef USE_VHD
+ putchar( ' ');
+ (void) phyvhd_available( TRUE );
+#else
+ printf( " VHD format image files are not supported\n" );
+#endif
+
+ putchar( '\n' );
+ return;
+}
+
+/*********************************************************** get_cwd() */
+
+static char *get_cwd( void ) {
+ size_t size = 32;
+ char *buf = NULL;
+ while( 1 ) {
+ char *nbuf;
+ nbuf = (char *)realloc( buf, size );
+ if( nbuf == NULL ) {
+ free( buf );
+ return NULL;
+ }
+ buf = nbuf;
+ if( getcwd( buf, size ) != NULL )
+ break;
+ if( errno != ERANGE ) {
+ perror( "getcwd" );
+ return NULL;
+ }
+ size *= 2;
+ }
+ return buf;
+}
diff --git a/extracters/ods2/spawncmd.c b/extracters/ods2/spawncmd.c
new file mode 100644
index 0000000..d53a3fb
--- /dev/null
+++ b/extracters/ods2/spawncmd.c
@@ -0,0 +1,89 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_SPAWNCMD )
+#define DEBUG DEBUG_SPAWNCMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+#if !defined( _WIN32 ) && !defined( VMS )
+#include
+#else
+# ifdef _WIN32
+# include
+# endif
+# ifdef VMS
+# include
+# endif
+#endif
+
+
+/******************************************************************* dospawn() */
+
+DECL_CMD(spawn) {
+#ifdef VMS
+ unsigned sts;
+
+ UNUSED( argc );
+ UNUSED( argv );
+ UNUSED( qualc );
+ UNUSED( qualv );
+
+ sts = lib$spawn( 0,0,0,0,0,0,0,0,0,0,0,0,0 );
+ return sts;
+#else
+# ifdef _WIN32
+ UNUSED( argc );
+ UNUSED( argv );
+ UNUSED( qualc );
+ UNUSED( qualv );
+
+ if( system( "cmd" ) == -1 ) {
+ perror( "cmd" );
+ return SS$_NOSUCHFILE;
+ }
+ return SS$_NORMAL;
+# else
+ char *shell, *p;
+ pid_t pid;
+
+ UNUSED( argc );
+ UNUSED( argv );
+ UNUSED( qualc );
+ UNUSED( qualv );
+
+ if( (shell = getenv( "SHELL" )) == NULL )
+ shell = "/bin/sh";
+ if( (p = strrchr( shell, '/')) == NULL )
+ p = shell;
+ else
+ p++;
+
+ if( (pid = fork()) == 0 ) {
+ execlp( shell, p, (char *)NULL );
+ perror( "%s" );
+ exit(EXIT_FAILURE);
+ }
+ if( pid == -1 ) {
+ perror( shell );
+ return SS$_NOSUCHFILE;
+ }
+ waitpid( pid, NULL, 0 );
+
+ return SS$_NORMAL;
+# endif
+#endif
+
+}
+
diff --git a/extracters/ods2/ssdef.h b/extracters/ods2/ssdef.h
index 602f7f2..85a906f 100644
--- a/extracters/ods2/ssdef.h
+++ b/extracters/ods2/ssdef.h
@@ -26,6 +26,7 @@
#define SS$_DEVNOTMOUNT 124
#define SS$_DEVOFFLINE 132
#define SS$_DUPLICATE 148
+#define SS$_ILLBLKNUM 220
#define SS$_ILLEFC 236
#define SS$_INSFMEM 292
#define SS$_IVCHAN 316
@@ -37,6 +38,8 @@
#define SS$_DEVCMDERR 812
#define SS$_BADFILENAME 2072
#define SS$_BADIRECTORY 2088
+#define SS$_DEVALLOC 2112
+#define SS$_DEVASSIGN 2120
#define SS$_DEVICEFULL 2128
#define SS$_DEVNOTALLOC 2136
#define SS$_DUPFILENAME 2152
diff --git a/extracters/ods2/sysmsg.c b/extracters/ods2/sysmsg.c
index a4ad9f6..62d3e82 100644
--- a/extracters/ods2/sysmsg.c
+++ b/extracters/ods2/sysmsg.c
@@ -1,16 +1,30 @@
-/* Timothe Litt litt _at_ acm _ddot_ org */
-/*
- This is part of ODS2 written by Paul Nankervis,
- email address: Paulnank@au1.ibm.com
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
- ODS2 is distributed freely for all members of the
- VMS community to use. However all derived works
- must maintain comments in their source to acknowledge
- the contibution of the original author.
-*/
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
/* Message code translations for non-VMS systems */
+#if !defined( DEBUG ) && defined( DEBUG_SYSMSG )
+#define DEBUG DEBUG_SYSMSG
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
#include
#include
#include
@@ -36,6 +50,8 @@ const struct VMSFAC {
} fac2text[] = {
{ SYSTEM$_FACILITY, "SYSTEM" },
{ RMS$_FACILITY, "RMS" },
+ { COPY$_FACILITY, "COPY" },
+ { DELETE$_FACILITY, "DELETE" },
{ 0, NULL },
{ 0, "NONAME" }
};
@@ -58,6 +74,10 @@ const struct VMSMSG {
const char *const txtcode;
char *text;
} vms2text[] = {
+ MSG(DELETE$_DELVER, "explicit version number or wild card required")
+
+ MSG(COPY$_OPENIN, " error opening %s as input")
+
MSG(RMS$_BUG, "fatal RMS condition detected, process deleted")
MSG(RMS$_DIR, "error in directory name")
MSG(RMS$_DNF, "directory not found")
@@ -79,6 +99,8 @@ const struct VMSMSG {
MSG(SS$_BADPARAM, "bad parameter value")
MSG(SS$_BUGCHECK, "internal consistency failure")
MSG(SS$_DATACHECK, "write check error")
+ MSG(SS$_DEVALLOC, "device already allocated to another user")
+ MSG(SS$_DEVASSIGN, "device has channels assigned" )
MSG(SS$_DEVICEFULL, "device full - allocation failure")
MSG(SS$_DEVMOUNT, "device is already mounted")
MSG(SS$_DEVNOTALLOC, "device not allocated")
@@ -87,6 +109,7 @@ const struct VMSMSG {
MSG(SS$_DUPFILENAME, "duplicate file name")
MSG(SS$_DUPLICATE, "duplicate name")
MSG(SS$_ENDOFFILE, "end of file")
+ MSG(SS$_ILLBLKNUM, "illegal logical block number")
MSG(SS$_FILELOCKED, "file is deaccess locked")
MSG(SS$_FILESEQCHK, "file identification sequence number check")
MSG(SS$_ILLEFC, "illegal event flag cluster")
@@ -94,6 +117,7 @@ const struct VMSMSG {
MSG(SS$_ITEMNOTFOUND, "requested item cannot be returned")
MSG(SS$_NOMOREDEV, "no more devices")
MSG(SS$_IVCHAN, "invalid I/O channel")
+ MSG(SS$_DEVOFFLINE, "device is not in configuration or not available")
MSG(SS$_IVDEVNAM, "invalid device name")
MSG(SS$_NOIOCHAN, "no I/O channel available")
MSG(SS$_NOMOREFILES, "no more files")
@@ -238,7 +262,7 @@ const char *getmsg( unsigned int vmscode, unsigned int flags, ... ) {
fp = fac2text + (sizeof(fac2text)/sizeof(fac2text[0])) -1;
mp = vms2text + (sizeof(vms2text)/sizeof(vms2text[0])) -1;
- snprintf( notext, sizeof(notext), nofmt, vmscode );
+ (void) snprintf( notext, sizeof(notext), nofmt, vmscode );
}
}
diff --git a/extracters/ods2/sysmsg.h b/extracters/ods2/sysmsg.h
index b8f4a04..876a141 100644
--- a/extracters/ods2/sysmsg.h
+++ b/extracters/ods2/sysmsg.h
@@ -1,3 +1,20 @@
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ *
+ * Free for use with the ODS2 package. All other rights reserved.
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
#ifndef SYSMSG_H
#define SYSMSG_H
@@ -11,6 +28,15 @@
#define MSG_FULL (MSG_FACILITY|MSG_SEVERITY|MSG_NAME|MSG_TEXT)
+/* Some random non-system codes from VMS */
+
+#define COPY$_FACILITY 103
+#define DELETE$_FACILITY 147
+
+#define COPY$_OPENIN 0x109a
+#define COPY$_
+#define DELETE$_DELVER 0x120a
+
const char *getmsg( unsigned int vmscode, unsigned int flags, ... );
void sysmsg_rundown( void );
diff --git a/extracters/ods2/typecmd.c b/extracters/ods2/typecmd.c
new file mode 100644
index 0000000..f0898d6
--- /dev/null
+++ b/extracters/ods2/typecmd.c
@@ -0,0 +1,75 @@
+/* This is part of ODS2 written by Paul Nankervis,
+ * email address: Paulnank@au1.ibm.com
+
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+#if !defined( DEBUG ) && defined( DEBUG_TYPECMD )
+#define DEBUG DEBUG_TYPECMD
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
+
+#include "cmddef.h"
+
+/******************************************************************* dotype() */
+
+/* dotype: a file TYPE routine */
+
+param_t typepars[] = { {"filespec", REQ, VMSFS, NOPA, "for file on ODS-2 volume."},
+ { NULL, 0, 0, NOPA, NULL }
+};
+
+DECL_CMD(type) {
+ int sts;
+ int records;
+ struct FAB fab = cc$rms_fab;
+ struct RAB rab = cc$rms_rab;
+
+ UNUSED(argc);
+ UNUSED(qualc);
+ UNUSED(qualv);
+
+ records = 0;
+
+ fab.fab$l_fna = argv[1];
+ fab.fab$b_fns = strlen(fab.fab$l_fna);
+ sts = sys_open( &fab );
+ if ( sts & STS$M_SUCCESS ) {
+ rab.rab$l_fab = &fab;
+ sts = sys_connect( &rab );
+ if ( sts & STS$M_SUCCESS ) {
+ char *rec;
+
+ if( (rec = malloc( MAXREC + 2 )) == NULL )
+ sts = SS$_INSFMEM;
+ else {
+ rab.rab$l_ubf = rec;
+ rab.rab$w_usz = MAXREC;
+ while( (sts = sys_get( &rab )) & STS$M_SUCCESS ) {
+ unsigned rsz = rab.rab$w_rsz;
+ if( fab.fab$b_rat & PRINT_ATTR ) rec[rsz++] = '\n';
+ rec[rsz++] = '\0';
+ fputs( rec, stdout );
+ records++;
+ }
+ free( rec );
+ rec = NULL;
+ }
+ sys_disconnect(&rab);
+ }
+ sys_close(&fab);
+ if (sts == RMS$_EOF) sts = SS$_NORMAL;
+ }
+ if ( !( sts & STS$M_SUCCESS ) ) {
+ printf("%%TYPE-F-ERROR Status: %s\n",getmsg(sts, MSG_TEXT));
+ }
+ return sts;
+}
+
+
diff --git a/extracters/ods2/update.c b/extracters/ods2/update.c
index 87c3b47..4c140e8 100644
--- a/extracters/ods2/update.c
+++ b/extracters/ods2/update.c
@@ -1,4 +1,12 @@
-/* Update.c V2.1 */
+/* Update.c */
+
+#if !defined( DEBUG ) && defined( DEBUG_UPDATE )
+#define DEBUG DEBUG_UPDATE
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
#include
#include
@@ -6,6 +14,7 @@
#include "access.h"
#include "device.h"
+#include "ods2.h"
#include "phyio.h"
#include "ssdef.h"
#include "stsdef.h"
@@ -16,13 +25,6 @@
#include "vmstime.h"
#endif
-#ifndef TRUE
-#define TRUE ( 0 == 0 )
-#endif
-#ifndef FALSE
-#define FALSE ( 0 != 0 )
-#endif
-
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,
@@ -39,7 +41,7 @@ unsigned getwindow(struct FCB * fcb,unsigned vbn,struct VCBDEV **devptr,
#define WORK_MASK 0xff
#else
#define WORK_UNIT unsigned int
-#define WORK_MASK 0xffffffff
+#define WORK_MASK ((WORK_UNIT)~0)
#endif
#define WORK_BITS (sizeof(WORK_UNIT) * 8)
@@ -89,29 +91,48 @@ unsigned update_freecount(struct VCBDEV *vcbdev,unsigned *retcount)
/* 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)
-{
+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;
+ register unsigned clust_count;
+ register unsigned map_block;
+ register unsigned block_offset;
+
+ clust_count = count;
+ map_block = cluster / 4096 + 2;
+ block_offset = cluster % 4096;
+
+ if( clust_count < 1 )
+ return SS$_BADPARAM;
+
+ if (cluster + clust_count > vcbdev->max_cluster + 1)
+ return SS$_BADPARAM;
+
+ if( release_flag )
+ vcbdev->free_clusters += clust_count;
+ else
+ vcbdev->free_clusters -= clust_count;
+
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 & STS$M_SUCCESS)) return sts;
+ register unsigned bit_no;
+
+ sts = accesschunk( vcbdev->mapfcb, map_block, &vioc, (char **) &bitmap,
+ &blkcount, 1 );
+ if( !(sts & STS$M_SUCCESS) )
+ return sts;
+
work_ptr = bitmap + block_offset / WORK_BITS;
- if (block_offset % WORK_BITS) {
- register unsigned bit_no = block_offset % WORK_BITS;
+
+ if( (bit_no = block_offset % WORK_BITS) != 0 ) {
register WORK_UNIT bit_mask = WORK_MASK;
- if (bit_no + clust_count < WORK_BITS) {
+
+ if( bit_no + clust_count < WORK_BITS ) {
bit_mask = bit_mask >> (WORK_BITS - clust_count);
clust_count = 0;
} else {
@@ -119,14 +140,30 @@ unsigned bitmap_modify(struct VCBDEV *vcbdev,unsigned cluster,unsigned count,
}
bit_mask = bit_mask << bit_no;
if (release_flag) {
- *work_ptr++ |= bit_mask;
+#if DEBUG
+ if( !(*work_ptr & bit_mask) ) {
+ *work_ptr |= bit_mask;
+ } /* else BUGCHECK( freeing unallocated cluster(s) ) */
+ else abort();
+#else
+ *work_ptr |= bit_mask;
+#endif
} else {
- *work_ptr++ &= ~bit_mask;
+#if DEBUG
+ if( *work_ptr & bit_mask ) {
+ *work_ptr &= ~bit_mask;
+ } /* else BUGCHECK( allocating allocated cluster(s) ) */
+ else abort();
+#else
+ *work_ptr &= ~bit_mask;
+#endif
}
+ ++work_ptr;
block_offset += WORK_BITS - bit_no;
}
+
work_count = (blkcount * 4096 - block_offset) / WORK_BITS;
- if (work_count > clust_count / WORK_BITS) {
+ if( work_count > clust_count / WORK_BITS ) {
work_count = clust_count / WORK_BITS;
block_offset = 1;
} else {
@@ -134,29 +171,56 @@ unsigned bitmap_modify(struct VCBDEV *vcbdev,unsigned cluster,unsigned count,
}
clust_count -= work_count * WORK_BITS;
if (release_flag) {
- while (clust_count-- > 0) {
+ while( work_count-- > 0 ) {
+#if DEBUG
+ if( *work_ptr != 0 )
+ abort(); /* else BUGCHECK( freeing unallocated cluster(s) ) */
+#endif
*work_ptr++ = WORK_MASK;
}
} else {
- while (work_count-- > 0) {
+ while( work_count-- > 0 ) {
+#if DEBUG
+ if( *work_ptr != WORK_MASK )
+ abort(); /* else BUGCHECK( allocating allocated cluster(s) ) */
+#endif
*work_ptr++ = 0;
}
}
- if (clust_count != 0 && block_offset) {
+ if( clust_count != 0 && block_offset ) {
register WORK_UNIT bit_mask;
+
bit_mask = WORK_MASK >> (WORK_BITS - clust_count);
if (release_flag) {
- *work_ptr++ |= bit_mask;
+#if DEBUG
+ if( !(*work_ptr & bit_mask) ) {
+ *work_ptr |= bit_mask;
+ } /* else BUGCHECK( freeing unallocated cluster(s) ) */
+ else abort();
+#else
+ *work_ptr |= bit_mask;
+#endif
} else {
- *work_ptr++ &= ~bit_mask;
+#if DEBUG
+ if( *work_ptr & bit_mask ) {
+ *work_ptr &= ~bit_mask;
+ } /* else BUGCHECK( allocating allocated cluster(s) ) */
+ else abort();
+#else
+ *work_ptr &= ~bit_mask;
+#endif
}
+ ++work_ptr;
+
clust_count = 0;
}
- sts = deaccesschunk(vioc,map_block,blkcount,TRUE);
- if (!(sts & STS$M_SUCCESS)) return sts;
+ sts = deaccesschunk( vioc, map_block, blkcount, TRUE );
+ if( !(sts & STS$M_SUCCESS) )
+ return sts;
map_block += blkcount;
block_offset = 0;
- } while (clust_count != 0);
+ } while( clust_count != 0 );
+
return sts;
}
@@ -193,7 +257,7 @@ unsigned bitmap_search(struct VCBDEV *vcbdev,unsigned *position,unsigned *count)
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;
@@ -253,7 +317,7 @@ unsigned headmap_clear(struct VCBDEV *vcbdev,unsigned head_no)
register unsigned sts;
register unsigned map_block;
map_block = head_no / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
- if (head_no <= VMSWORD(vcbdev->home.hm2$w_resfiles)) return SS$_NOPRIV; /* Protect reserved files */
+ if (head_no <= F11WORD(vcbdev->home.hm2$w_resfiles)) return SS$_NOPRIV; /* Protect reserved files */
sts = accesschunk(vcbdev->idxfcb,map_block,&vioc,(char **) &bitmap,NULL,1);
if (sts & STS$M_SUCCESS) {
bitmap[(head_no % 4096) / WORK_BITS] &= ~(1 << (head_no % WORK_BITS));
@@ -294,8 +358,8 @@ unsigned update_findhead(struct VCBDEV *vcbdev,unsigned *rethead_no,
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);
+ F11WORD(vcbdev->home.hm2$w_ibmapvbn) +
+ F11WORD(vcbdev->home.hm2$w_ibmapsize);
sts = accesschunk(vcbdev->idxfcb,idxblk,retvioc,
(char **) headbuff,NULL,1);
if (sts & STS$M_SUCCESS) {
@@ -303,7 +367,7 @@ unsigned update_findhead(struct VCBDEV *vcbdev,unsigned *rethead_no,
modify_flag = TRUE;
if( (*headbuff)->fh2$w_checksum != 0 ||
(*headbuff)->fh2$w_fid.fid$w_num != 0 ||
- !(VMSLONG((*headbuff)->fh2$l_filechar) &
+ !(F11LONG((*headbuff)->fh2$l_filechar) &
FH2$M_MARKDEL) ) {
sts = deaccesschunk(*retvioc,0,0,FALSE);
} else {
@@ -322,7 +386,7 @@ unsigned update_findhead(struct VCBDEV *vcbdev,unsigned *rethead_no,
} while (--work_count != 0);
deaccesschunk(vioc,map_block,blkcount,modify_flag);
if (!(sts & STS$M_SUCCESS)) break;
- } while (head_no < VMSLONG(vcbdev->home.hm2$l_maxfiles));
+ } while (head_no < F11LONG(vcbdev->home.hm2$l_maxfiles));
return sts;
}
@@ -389,10 +453,10 @@ unsigned update_addhead(struct VCB *vcb,char *filename,struct fiddef *back,
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);
+ head->fh2$w_recattr.fat$l_efblk = F11SWAP(1);
{
- unsigned short check = checksum((vmsword *) head);
- head->fh2$w_checksum = VMSWORD(check);
+ unsigned short check = checksum((f11word *) head);
+ head->fh2$w_checksum = F11WORD(check);
}
if( rethead != NULL ) *rethead = head;
return SS$_NORMAL;
@@ -433,7 +497,7 @@ unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig)
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->status & FCB_WRITE) ) return SS$_WRITLCK;
if (fcb->hiblock > 0) {
unsigned mapblk,maplen;
sts = getwindow(fcb,fcb->hiblock,&vcbdev,&mapblk,&maplen,&hdrfid,
@@ -488,7 +552,7 @@ unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig)
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);
+ F11SWAP(fcb->hiblock * vcbdev->clustersize);
sts = bitmap_modify(vcbdev,start_pos,block_count,0);
}
}
@@ -498,25 +562,27 @@ unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig)
/************************************************************** deallocfile() */
-/* 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 = SS$_NORMAL;
/*
First mark all file clusters as free in BITMAP.SYS
*/
- register unsigned vbn = 1;
- while (vbn <= fcb->hiblock) {
+ register unsigned vbn;
+ for( vbn = 1; vbn <= fcb->hiblock; ) {
register unsigned sts;
unsigned phyblk,phylen;
struct VCBDEV *vcbdev;
- sts = getwindow(fcb,vbn,&vcbdev,&phyblk,&phylen,NULL,NULL);
- if (!(sts & STS$M_SUCCESS)) break;
- sts = bitmap_modify(vcbdev,phyblk,phylen,1);
- if (!(sts & STS$M_SUCCESS)) break;
+
+ sts = getwindow( fcb, vbn, &vcbdev, &phyblk, &phylen, NULL, NULL );
+ if( !(sts & STS$M_SUCCESS) )
+ break;
+ vbn += phylen;
+ phyblk /= vcbdev->clustersize;
+ phylen = (phylen + vcbdev->clustersize -1)/vcbdev->clustersize;
+ sts = bitmap_modify( vcbdev, phyblk, phylen, 1 );
+ if( !(sts & STS$M_SUCCESS) )
+ break;
}
/*
Now reset file header bit map in INDEXF.SYS and
@@ -527,6 +593,7 @@ unsigned deallocfile(struct FCB *fcb)
unsigned headvbn = fcb->headvbn;
struct HEAD *head = fcb->head;
struct VIOC *headvioc = fcb->headvioc;
+
while (TRUE) {
unsigned ext_seg_num = 0;
struct fiddef extfid;
@@ -543,7 +610,8 @@ unsigned deallocfile(struct FCB *fcb)
idxblk = filenum / 4096 + vcbdev->home.hm2$w_cluster * 4 + 1;
sts = accesschunk(vcbdev->idxfcb,idxblk,&vioc,(char **) &bitmap,
NULL,1);
- if (!(sts & STS$M_SUCCESS)) break;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
bitmap[(filenum % 4096) / WORK_BITS] &=
~(1 << (filenum % WORK_BITS));
sts = deaccesschunk(vioc,idxblk,1,TRUE);
@@ -554,7 +622,8 @@ unsigned deallocfile(struct FCB *fcb)
ext_seg_num++;
memcpy(&extfid,&fcb->head->fh2$w_ext_fid,sizeof(struct fiddef));
sts = deaccesshead(headvioc,NULL,headvbn);
- if (!(sts & STS$M_SUCCESS)) break;
+ if( !(sts & STS$M_SUCCESS) )
+ break;
if (extfid.fid$b_rvn == 0) {
extfid.fid$b_rvn = rvn;
} else {
@@ -585,10 +654,22 @@ unsigned accesserase(struct VCB * vcb,struct fiddef * fid)
{
struct FCB *fcb;
register int sts;
+ struct VCBDEV *vcbdev;
+
+ vcbdev = RVN_TO_DEV(vcb,fid->fid$b_rvn);
+ if (vcbdev == NULL)
+ return SS$_DEVNOTMOUNT;
+ if( (fid->fid$w_num | (fid->fid$b_nmx << 16)) <=
+ F11WORD( vcbdev->home.hm2$w_resfiles ) ) {
+ return SS$_NOPRIV;
+ }
+
sts = accessfile(vcb,fid,&fcb,1);
if (sts & STS$M_SUCCESS) {
fcb->head->fh2$l_filechar |= FH2$M_MARKDEL;
+#if DEBUG
printf("Accesserase ... \n");
+#endif
sts = deaccessfile(fcb);
}
return sts;
@@ -604,7 +685,7 @@ unsigned extend(struct FCB *fcb,unsigned blocks)
struct VCBDEV *vcbdev;
unsigned clusterno;
unsigned extended = 0;
- if ((fcb->status & FCB_WRITE) == 0) return SS$_WRITLCK;
+ if( !(fcb->status & FCB_WRITE) ) return SS$_WRITLCK;
if (fcb->hiblock > 0) {
unsigned phyblk,phylen;
sts = getwindow(fcb,fcb->hiblock,&vcbdev,&phyblk,&phylen,NULL,NULL);
@@ -673,7 +754,7 @@ 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;
+ if( wrtflg && !(vcb->status & VCB_WRITE) ) return SS$_WRITLCK;
sts = headmap_search(struct VCBDEV * vcbdev,struct fiddef * fid,
struct VIOC ** vioc,struct HEAD ** headbuff,unsigned *retidxblk,) {
@@ -710,7 +791,7 @@ unsigned access_create(struct VCB * vcb,struct FCB ** fcbadd,unsigned blocks)
sts = accesshead(vcb,fid,0,&fcb->headvioc,&fcb->head,&fcb->headvbn,
wrtflg);
if (sts & STS$M_SUCCESS) {
- fcb->hiblock = VMSSWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
+ fcb->hiblock = F11SWAP(fcb->head->fh2$w_recattr.fat$l_hiblk);
if (fcb->head->fh2$b_idoffset > 39) {
fcb->highwater = fcb->head->fh2$l_highwater;
} else {
diff --git a/extracters/ods2/valgrind_suppressions_readline b/extracters/ods2/valgrind_suppressions_readline
index 470c88e..a6f805a 100644
--- a/extracters/ods2/valgrind_suppressions_readline
+++ b/extracters/ods2/valgrind_suppressions_readline
@@ -44,3 +44,12 @@
fun:rl_set_prompt
fun:readline
}
+{
+ readline
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ ...
+ fun:readline_internal_charloop
+ fun:readline_internal
+ fun:readline
+}
diff --git a/extracters/ods2/version.h b/extracters/ods2/version.h
index e984b03..c179bcd 100644
--- a/extracters/ods2/version.h
+++ b/extracters/ods2/version.h
@@ -1,10 +1,66 @@
+/* Timothe Litt March 2016
+ * Copyright (C) 2016 Timothe litt
+ * litt at acm dot org
+ * Distribution per Paul's license below.
+ *
+ * Revision history at bottom of this file.
+ *
+ */
+
+/*
+ * This is distributed as part of ODS2, originally written by
+ * Paul Nankervis, email address: Paulnank@au1.ibm.com
+ *
+ * ODS2 is distributed freely for all members of the
+ * VMS community to use. However all derived works
+ * must maintain comments in their source to acknowledge
+ * the contibution of the original author.
+ */
+
+
#ifndef VERSION_H
#define VERSION_H
#ifdef DEBUG_BUILD
#define MODULE_IDENT "Debug build"
#else
-#define MODULE_IDENT "v2.1"
+#define MODULE_IDENT "v3.0"
#endif
+#define MODULE_NAME ODS2
+
+#define MNAMEX(n) #n
+#define MNAME(n) MNAMEX(n)
+
+
+/* Modified by:
+ * Feb 2016 Timothe Litt
+ * Bug fixes, readline support, build on NT without wnaspi32,
+ * Decode error messages, patch from vms2linux.de. VS project files.
+ * Rework command parsing and help. Bugs, bugs & bugs. Merge
+ * code from Larry Baker, USGS. Add initialize volume, spawn,
+ * and more. See git commit history for details.
+ *
+ * V3.0 - Merge and adapt code from Larry Baker's V2.0
+ *
+* 8-JUN-2005 Larry Baker
+ *
+ * Add #include guards in .h files.
+ * Use named constants in place of literals.
+ * Replace BIG_ENDIAN with ODS2_BIG_ENDIAN (Linux always #defines
+ * BIG_ENDIAN).
+ * Add SUBST DRIVE: FILE to "mount" a file (vs. a disk).
+ * Implement quoted arguments (paired " or '; no escape characters)
+ * in cmdsplit(), e.g., to specify a Unix path or a null argument.
+ * Remove VMSIO conditional code (need to "mount" a file now).
+ *
+ * Jul-2003, v1.3hb, some extensions by Hartmut Becker
+ *
+ * 31-AUG-2001 01:04 Hunter Goatley
+ *
+ * For VMS, added routine getcmd() to read commands with full
+ * command recall capabilities.
+ *
+ */
+
#endif
diff --git a/extracters/ods2/vmstime.c b/extracters/ods2/vmstime.c
index a30643d..d82e068 100644
--- a/extracters/ods2/vmstime.c
+++ b/extracters/ods2/vmstime.c
@@ -1,6 +1,6 @@
/*
- Vmstime.c V2.1
+ Vmstime.c
Author: Paul Nankervis
@@ -56,6 +56,13 @@
*/
+#if !defined( DEBUG ) && defined( DEBUG_VMSTIME )
+#define DEBUG DEBUG_VMSTIME
+#else
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+#endif
#include
#include
@@ -750,15 +757,16 @@ unsigned sys_asctim(unsigned short *timlen,struct dsc_descriptor *timbuf,
/* Generate two digit day... */
- if (chrptr < endptr) {
- if ((timval = timvec[2]) / 10 == 0) {
+ if( chrptr < endptr ) {
+ if( (timval = timvec[2]) / 10 == 0 ) {
*chrptr++ = ' ';
} else {
*chrptr++ = vmstime_digits[timval / 10];
}
- }
- if (chrptr < endptr) {
- *chrptr++ = vmstime_digits[timval % 10];
+
+ if( chrptr < endptr ) {
+ *chrptr++ = vmstime_digits[timval % 10];
+ }
}
/* Add month name with hyphen separators... */
diff --git a/extracters/ods2/vmstime.h b/extracters/ods2/vmstime.h
index c7f6d6a..a963374 100644
--- a/extracters/ods2/vmstime.h
+++ b/extracters/ods2/vmstime.h
@@ -1,6 +1,6 @@
/*
- Vmstime.h V2.1
+ Vmstime.h
Author: Paul Nankervis
diff --git a/putr/putr.com b/putr/putr.com
old mode 100644
new mode 100755