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