/* 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 contributions of the original author and * subsequent contributors. This is free software; no * warranty is offered, and while we believe it to be useful, * you use it at your own risk. */ #if !defined( DEBUG ) && defined( DEBUG_DIRCMD ) #define DEBUG DEBUG_DIRCMD #else #ifndef DEBUG #define DEBUG 0 #endif #endif #include "cmddef.h" #include "f11def.h" struct dirstats { uint32_t filecount; uint32_t totblocks, totalloc, dircount; }; static vmscond_t dir_1_arg( FILE *of, options_t options, struct dirstats *stats, char *filespec ); static void dirtotal( FILE *of, options_t options, uint32_t size, uint32_t alloc ); static vmscond_t get_fileheader( FILE *of, struct dsc$descriptor *devname, struct fiddef *fid, uint32_t *clustersize, struct HEAD **buf ); static void print_fileheader( FILE *of, struct HEAD *fhd, uint32_t *vbn, uint32_t clustersize ); /******************************************************************* dodir() */ #define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size) #define dir_date OPT_SHARED_1 #define dir_fileid OPT_SHARED_2 #define dir_owner OPT_SHARED_3 #define dir_prot OPT_SHARED_4 #define dir_size OPT_SHARED_5 #define dir_grand OPT_SHARED_6 #define dir_heading OPT_SHARED_7 #define dir_names OPT_SHARED_8 #define dir_trailing OPT_SHARED_9 #define dir_full OPT_SHARED_10 #define dir_total OPT_SHARED_11 #define dir_backup OPT_SHARED_12 #define dir_created OPT_SHARED_13 #define dir_expired OPT_SHARED_14 #define dir_modified OPT_SHARED_15 #define dir_dates (dir_backup | dir_created | dir_expired | dir_modified) #define dir_allocated OPT_SHARED_16 #define dir_used OPT_SHARED_17 #define dir_sizes (dir_allocated | dir_used) #define dir_mappings OPT_SHARED_19 #define dir_pack OPT_SHARED_20 #define dir_default (dir_heading|dir_names|dir_trailing|dir_pack) const int dir_defaults = dir_default; static char *outfile; static qual_t datekwds[] = { {"created", dir_created, 0, NV, "commands directory qual_date date_created"}, {"modified", dir_modified, 0, NV, "commands directory qual_date date_modified"}, {"expired", dir_expired, 0, NV, "commands directory qual_date date_expired"}, {"backup", dir_backup, 0, NV, "commands directory qual_date date_backup"}, {NULL, 0, 0, NV, NULL} }; static qual_t sizekwds[] = { {"all", dir_used|dir_allocated, 0, NV, "commands directory qual_size size_both" }, {"allocation", dir_allocated, 0, NV, "commands directory qual_size size_alloc" }, {"used", dir_used, 0, NV, "commands directory qual_size size_used" }, {NULL, 0, 0, NV, NULL} }; qual_t dirquals[] = { {"brief", dir_default, ~dir_default, NV, "commands directory qual_brief"}, {"date", dir_date, dir_dates, VOPT(KV(datekwds)), "-commands directory qual_date", }, {"nodate", 0, dir_date, NV, NULL, }, {"file_id", dir_fileid, 0, NV, "-commands directory qual_fileid"}, {"nofile_id", 0, dir_fileid, NV, NULL }, {"full", dir_full|dir_heading|dir_trailing, ~(dir_full|dir_pack), NV, "commands directory qual_full"}, {"grand_total", dir_grand, ~dir_grand & ~(dir_size|dir_sizes), NV, "-commands directory qual_grand"}, {"nogrand_total", 0, dir_grand, NV, NULL}, {"heading", dir_heading, 0, NV, "-commands directory qual_heading"}, {"noheading", 0, dir_heading, NV, NULL}, {"owner", dir_owner, 0, NV, "-commands directory qual_owner"}, {"noowner", 0, dir_owner, NV, NULL, }, {"output", 0, 0, SV(&outfile), "commands directory qual_output"}, {"pack", dir_pack, 0, NV, "-commands directory qual_pack"}, {"nopack", dir_full, dir_pack|dir_heading|dir_trailing|dir_grand, NV, NULL, }, {"protection", dir_prot, 0, NV, "-commands directory qual_protection"}, {"noprotection", 0, dir_prot, NV, NULL, }, {"size", dir_size, dir_sizes, VOPT(KV(sizekwds)), "-commands directory qual_size"}, {"nosize", 0, dir_size|dir_sizes, NV, NULL, }, {"total", dir_total|dir_heading, ~dir_total & ~(dir_size|dir_sizes), NV, "commands directory qual_total",}, {"trailing", dir_trailing, 0, NV, "-commands directory qual_trailing",}, {"notrailing", 0, dir_trailing, NV, NULL}, {"map_area", dir_mappings|dir_full|dir_heading|dir_trailing, 0, NV, "-commands directory qual_map"}, {"nomap_area", 0, dir_mappings, NV, NULL}, {NULL, 0, 0, NV, NULL} }; defqualsp_t dir_defopt = NULL; param_t dirpars[] = { {"filespec", OPT | NOLIM, FSPEC, NOPA, "commands directory filespec"}, { NULL, 0, 0, NOPA, NULL } }; /************************************************************ dodir() */ DECL_CMD(dir) { FILE *of = stdout; options_t options; vmscond_t status; struct dirstats stats; memset( &stats, 0, sizeof( stats ) ); outfile = NULL; if( dir_defopt != NULL ) { if( $FAILS(status = checkquals( &options, dir_defaults, dirquals, dir_defopt->qualc, dir_defopt->qualv )) ) { return status; } } else options = dir_defaults; if( $FAILS(status = checkquals( &options, options, dirquals, qualc, qualv )) ) { return status; } if( outfile != NULL ) { of = openf( outfile, "w" ); if( of == NULL ) { int err; err = errno; printmsg( DIRECT_OPENOUT, 0, outfile ); return printmsg( ODS2_OSERROR, MSG_CONTINUE, DIRECT_OPENOUT, strerror( err ) ); } } 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; --argc; ++argv; do { status = dir_1_arg( of, options, &stats, argv++[0] ); } while( argc && --argc ); if( (options & dir_grand) || (stats.dircount > 1 && (options & dir_trailing)) ) { printmsg( DIRECT_GRANDTOT, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, stats.dircount, stats.filecount ); dirtotal( of, options, stats.totblocks, stats.totalloc ); fputs( ".\n", of ); } if( options & dir_pack ) { if( $SUCCESSFUL( status ) ) { if( stats.filecount < 1 ) status = printmsg( DIRECT_NOFILES, MSG_TOFILE, of ); } else { status = printmsg( status, MSG_TOFILE, of ); } } if( outfile != NULL ) fclose( of ); return status; } /***********************************************************dir_1_arg() */ static vmscond_t dir_1_arg( FILE *of, options_t options, struct dirstats *stats, char *filespec ) { char res[NAM$C_MAXRSS + 1] = { "" }, rsa[NAM$C_MAXRSS + 1] = { "" }; vmscond_t status; uint32_t nobackup = 0, contigb = 0, contig = 0, directory = 0, writeback = 0, readcheck = 0, writecheck = 0, locked = 0, spool = 0, badblock = 0, markdel = 0; uint16_t retlen = 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(nobackup), NULL, 0 }, { XAB$_UCHAR_CONTIG, sizeof(contig), NULL, 0 }, { XAB$_UCHAR_CONTIGB, sizeof(contigb), NULL, 0 }, { XAB$_UCHAR_DIRECTORY, sizeof(directory), NULL, 0 }, { XAB$_UCHAR_WRITEBACK, sizeof(writeback), NULL, 0 }, { XAB$_UCHAR_READCHECK, sizeof(readcheck), NULL, 0 }, { XAB$_UCHAR_WRITECHECK, sizeof(writecheck), NULL, 0 }, { XAB$_UCHAR_LOCKED, sizeof(locked), NULL, 0 }, { XAB$_UCHAR_SPOOL, sizeof(spool), NULL, 0 }, { XAB$_UCHAR_MARKDEL, sizeof(markdel), NULL, 0 }, { XAB$_UCHAR_BADBLOCK, sizeof(badblock), NULL, 0 }, { 0, 0, NULL, 0 } }; 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[0].retlen = &retlen; xitems[1].buffer = &contig; xitems[1].retlen = &retlen; xitems[2].buffer = &contigb; xitems[2].retlen = &retlen; xitems[3].buffer = &directory; xitems[3].retlen = &retlen; xitems[4].buffer = &writeback; xitems[4].retlen = &retlen; xitems[5].buffer = &readcheck; xitems[5].retlen = &retlen; xitems[6].buffer = &writecheck; xitems[6].retlen = &retlen; xitems[7].buffer = &locked; xitems[7].retlen = &retlen; xitems[8].buffer = &spool; xitems[8].retlen = &retlen; xitems[9].buffer = &markdel; xitems[9].retlen = &retlen; xitems[10].buffer = &badblock; xitems[10].retlen = &retlen; itm.xab$b_mode = XAB$K_SENSEMODE; itm.xab$l_itemlist = xitems; fab.fab$l_fna = filespec; fab.fab$b_fns = filespec? (uint8_t)strlen(fab.fab$l_fna): 0; fab.fab$l_dna = "*.*;*"; fab.fab$b_dns = (uint8_t)strlen(fab.fab$l_dna); if( $SUCCESSFUL(status = sys_parse(&fab)) ) { char dir[NAM$C_MAXRSS + 1] = { "" }; size_t namelen; size_t dirlen = 0; uint32_t dirfiles = 0; uint32_t dirblocks = 0, diralloc = 0; size_t printcol = 0; nam.nam$l_rsa = rsa; nam.nam$b_rss = NAM$C_MAXRSS; fab.fab$l_fop = 0; while( $SUCCESSFUL(status) && $SUCCESSFUL(status = sys_search( &fab )) ) { if (dirlen != (size_t)nam.nam$b_dev + nam.nam$b_dir || memcmp(rsa, dir, (size_t)nam.nam$b_dev + nam.nam$b_dir) != 0) { if (dirfiles > 0 && (options & dir_trailing)) { if (printcol > 0) fputc( '\n', of ); printmsg( DIRECT_FILETOTAL, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, dirfiles ); dirtotal( of, options, dirblocks, diralloc ); fputs(".\n", of); } dirlen = (size_t)nam.nam$b_dev + nam.nam$b_dir; memcpy(dir, rsa, dirlen); dir[dirlen] = '\0'; if( options & dir_heading) printmsg( DIRECT_DIRHEAD, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, dir ); stats->filecount += dirfiles; stats->totblocks += dirblocks; stats->totalloc += diralloc; stats->dircount++; dirfiles = 0; dirblocks = 0; diralloc = 0; printcol = 0; } rsa[nam.nam$b_rsl] = '\0'; namelen = (size_t)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) { size_t newcol = (printcol + 20) / 20 * 20; if (newcol + namelen >= 80) { fputs( "\n", of ); printcol = 0; } else { fprintf( of, "%*s", (int)(newcol - printcol), " " ); printcol = newcol; } } fputs( rsa + dirlen, of ); printcol += namelen; } } else { if (options & dir_names) { if ( (options & dir_heading) == 0 ) fprintf( of, "%s", dir ); if( options & dir_pack ) { if( namelen > 18 ) { fprintf( of, "%s", rsa + dirlen ); if( options & dir_extra ) fprintf( of, "\n " ); } else { fprintf( of, "%-19s", rsa + dirlen ); } } else fprintf( of, "%s\n", rsa + dirlen ); } if( $FAILS(status = sys_open(&fab)) ) { printmsg( status, MSG_TOFILE, of ); status = SS$_NORMAL; } else { status = 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) fprintf( of, "%sFile ID:", (options & dir_pack)? " ": "" ); (void) snprintf(fileid, sizeof(fileid), "(%u,%u,%u)", (nam.nam$w_fid.fid$b_nmx << 16) | nam.nam$w_fid.fid$w_num, nam.nam$w_fid.fid$w_seq, nam.nam$w_fid.fid$b_rvn ); fprintf( of, " %-22s", fileid ); } diralloc += fab.fab$l_alq; if (options & dir_used) { uint32_t filesize; filesize = fhc.xab$l_ebk; /* VBN of eof */ if( filesize == 0 ) /* none, use allocated size */ filesize = fab.fab$l_alq; else { 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) printmsg( DIRECT_FULLSIZE, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, filesize ); else fprintf( of, "%9u", filesize ); if( options & (dir_allocated|dir_full)) fprintf( of, "/%-9u", fab.fab$l_alq ); if( options & (dir_allocated | dir_full) ) { if( options & dir_pack ) fputs( " ", of ); else fputc( '\n', of ); } } } else { if ( (options & (dir_allocated|dir_names)) == (dir_allocated|dir_names)) { fprintf( of, "%9u", fab.fab$l_alq ); } } #define pprot(val, pos, del) do { \ unsigned int v = ~(((val) >> (pos)) & xab$m_prot); \ if( v & xab$m_noread ) fprintf( of, "R" ); \ if( v & xab$m_nowrite ) fprintf( of, "W" ); \ if( v & xab$m_noexe ) fprintf( of, "E" ); \ if( v & xab$m_nodel ) fprintf( of, "D" ); \ fprintf( of, del ); \ } while( 0 ) if (options & dir_full) { int pos = 0; printmsg( DIRECT_OWNER, MSG_TEXT|MSG_TOFILE, of, ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF); printmsg( DIRECT_CREATED, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of ); prvmstime( of, dat.xab$q_cdt, "\n" ); printmsg( DIRECT_REVISED, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of ); prvmstime( of, dat.xab$q_rdt, " (" ); fprintf( of, "%u)\n", dat.xab$w_rvn ); printmsg( DIRECT_EXPIRES, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of ); prvmstime( of, dat.xab$q_edt, "\n" ); printmsg( DIRECT_BACKUP, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of ); prvmstime( of, dat.xab$q_bdt, "\n" ); #define MSG(x) getmsg( DIRECT_ ## x, MSG_TEXT|MSG_NOCRLF ) pwrap( of, &pos, MSG( FILEORG ) ); switch( fab.fab$b_org ) { case FAB$C_SEQ: pwrap( of, &pos, MSG( SEQORG) ); break; case FAB$C_REL: pwrap( of, &pos, MSG( RELORG ) /*, Maximum record number %u", fab.fab$l_mrn*/ ); break; case FAB$C_IDX: pwrap( of, &pos, MSG( IDXORG ) ); break; /*, Prolog: 3, Using 4 keys\nIn 3 areas */ default: pwrap( of, &pos, MSG( UNKORG ), fab.fab$b_org ); break; } pwrap( of, &pos, MSG( FILEATT ) ); pwrap( of, &pos, MSG( ALLOC ), fab.fab$l_alq ); pwrap( of, &pos, MSG( EXTEND ), fab.fab$w_deq ); /* Missing: , Maximum bucket size: n*/ pwrap( of, &pos, MSG( GBC ), fab.fab$w_gbc ); if( fhc.xab$w_verlimit == 0 || fhc.xab$w_verlimit == 32767 ) { if( directory ) pwrap( of, &pos, MSG(NODIRLIMIT) ); else pwrap( of, &pos, MSG(NOVERLIMIT ) ); } else { if( directory ) pwrap( of, &pos, MSG(DIRLIMIT), fhc.xab$w_verlimit ); else pwrap( of, &pos, MSG(VERLIMIT), fhc.xab$w_verlimit ); } #define pattr(bit, text) \ if( bit ) \ pwrap( of, &pos, MSG(text) ) pattr( contig, CONTIG ); pattr( contigb, CONTIGB ); pattr( nobackup, NOBACKUP ); pattr( directory, DIRECTORY ); pattr( writeback, WRITEBACK ); pattr( readcheck, READCHECK ); pattr( writecheck, WRITECHECK ); pattr( locked, LOCKED ); pattr( spool, SPOOL ); pattr( markdel, MARKDEL ); pattr( badblock, BADBLOCK ); pwrap( of, &pos, "\n" ); #undef pattr pwrap( of, &pos, MSG(EOFPOS), fhc.xab$l_ebk, fhc.xab$w_ffb ); pwrap( of, &pos, MSG(RECFMT) ); switch( fab.fab$b_rfm ) { default: case FAB$C_UDF: pwrap( of, &pos, MSG(RECUDF) ); break; case FAB$C_FIX: pwrap( of, &pos, MSG(RECFIX), fab.fab$w_mrs ); break; case FAB$C_VAR: pwrap( of, &pos, MSG(RECVAR), fhc.xab$w_lrl ); break; case FAB$C_VFC: pwrap( of, &pos, MSG(RECVFC), (fab.fab$b_fsz? fab.fab$b_fsz: 2), fhc.xab$w_lrl ); break; case FAB$C_STM: pwrap( of, &pos, MSG(RECSTM) ); break; case FAB$C_STMLF: pwrap( of, &pos, MSG(RECSTMLF) ); break; case FAB$C_STMCR: pwrap( of, &pos, MSG(RECSTMCR) ); break; } pwrap( of, &pos, "\n" ); pwrap( of, &pos, MSG(RECATT) ); if( fab.fab$b_rat == 0 ) pwrap( of, &pos, MSG(RECATT_NONE) ); else { const char *more = ""; if( fab.fab$b_rat & FAB$M_FTN ) { pwrap( of, &pos, MSG(RECATT_FTN), more ); more = ", "; } if( fab.fab$b_rat & FAB$M_CR ) { pwrap( of, &pos, MSG(RECATT_CR), more ); more = ", "; } if( fab.fab$b_rat & FAB$M_PRN ) { pwrap( of, &pos, MSG(RECATT_PRN), more ); more = ", "; } if( fab.fab$b_rat & FAB$M_BLK ) { pwrap( of, &pos, MSG(RECATT_BLK), more ); } } fprintf( of, "\n" ); /* * RMS attributes: None * Journaling enabled: None */ fprintf( of, MSG(PROT_SYS) ); pprot(pro.xab$w_pro, xab$v_system, MSG(PROT_OWNER) ); pprot(pro.xab$w_pro, xab$v_owner, MSG(PROT_GROUP) ); pprot(pro.xab$w_pro, xab$v_group, MSG(PROT_WORLD) ); pprot(pro.xab$w_pro, xab$v_world, "\n"); if( options & dir_mappings ) { struct dsc$descriptor devnam; unsigned clustersize = 0; struct HEAD *buf = NULL; struct fiddef lastfid, fid; unsigned vbn = 1; memset( &devnam, 0, sizeof( devnam ) ); devnam.dsc$b_dtype = DSC$K_DTYPE_T; devnam.dsc$b_class = DSC$K_CLASS_S; devnam.dsc$w_length = nam.nam$b_dev; devnam.dsc$a_pointer = nam.nam$l_dev; fid = nam.nam$w_fid; do { if( $SUCCESSFUL(status = get_fileheader( of, &devnam, &fid, &clustersize, &buf )) ) { print_fileheader( of, buf, &vbn, clustersize ); } lastfid = fid; fid = buf->fh2$w_ext_fid; free( buf ); buf = NULL; } while( $SUCCESSFUL(status) && (fid.fid$w_num | fid.fid$w_seq | fid.fid$b_rvn | fid.fid$b_nmx) != 0 && memcmp( &fid, &lastfid, sizeof( fid ) ) != 0 ); } } else { /* !full */ if (options & dir_date) { if( options & dir_created ) status = prvmstime( of, dat.xab$q_cdt, NULL ); if( options & dir_modified ) status = prvmstime( of, dat.xab$q_rdt, NULL ); if( options & dir_expired ) status = prvmstime( of, dat.xab$q_edt, NULL ); if( options & dir_backup ) status = prvmstime( of, dat.xab$q_bdt, NULL ); } if (options & dir_owner) { printmsg( DIRECT_UIC, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, ((pro.xab$l_uic>>16)&0xFFFF), pro.xab$l_uic&0xFFFF ); } if (options & dir_prot) { fprintf( of, " (" ); 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) fprintf( of, "\n" ); } } dirfiles++; } if( status == RMS$_NMF ) status = SS$_NORMAL; if( printcol > 0 ) fprintf( of, "\n" ); if (options & dir_trailing) { printmsg( DIRECT_FILETOTAL, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, dirfiles ); dirtotal( of, options, dirblocks, diralloc ); fputs( ".\n", of ); } stats->filecount += dirfiles; stats->totblocks += dirblocks; stats->totalloc += diralloc; } fab.fab$b_fns = nam.nam$b_ess = fab.fab$b_dns = 0; nam.nam$b_nop = NAM$M_SYNCHK; (void) sys_parse( &fab ); return status; } /*********************************************************** dirtotal() */ static void dirtotal( FILE *of, options_t options, uint32_t size, uint32_t alloc ) { if ( !(options & dir_size) ) return; fputs( ", ", of ); switch( options & (dir_used | dir_allocated) ) { case dir_used: printmsg( DIRECT_USEDTOT, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, size ); break; case dir_allocated: printmsg( DIRECT_ALLOCTOT, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, alloc ); break; case dir_used | dir_allocated: printmsg( DIRECT_BOTHSIZE, MSG_TEXT|MSG_NOCRLF|MSG_TOFILE, of, size, alloc ); break; default: return; } } /*********************************************************** get_fileheader() */ static unsigned get_fileheader( FILE *of, struct dsc$descriptor *devname, struct fiddef *fid, unsigned *clustersize, struct HEAD **buf ) { unsigned status; char *idxbuf; struct HOME *hom; long vbn; struct FAB idxfab = cc$rms_fab; struct RAB idxrab = cc$rms_rab; struct NAM idxnam = cc$rms_nam; char rsbuf[NAM$C_MAXRSS + 1] = { "" }; if( devname->dsc$w_length > NAM$S_DVI ) return RMS$_FNM; idxbuf = (char *)malloc( 512 ); *buf = (struct HEAD *) idxbuf; if( idxbuf == NULL ) return SS$_INSFMEM; idxfab.fab$l_fna = NULL; idxfab.fab$b_fns = 0; idxfab.fab$l_dna = NULL; idxfab.fab$b_dns = 0; idxfab.fab$b_fac = FAB$M_GET; idxfab.fab$l_fop = FAB$M_NAM; idxnam.nam$t_dvi[0] = (char)devname->dsc$w_length; memcpy( idxnam.nam$t_dvi + 1, devname->dsc$a_pointer, devname->dsc$w_length ); idxnam.nam$w_did.fid$w_num = 4; idxnam.nam$w_did.fid$w_seq = 4; idxnam.nam$w_did.fid$b_nmx = 0; idxnam.nam$w_did.fid$b_rvn = fid->fid$b_rvn; idxnam.nam$w_fid.fid$w_num = 1; idxnam.nam$w_fid.fid$w_seq = 1; idxnam.nam$w_fid.fid$b_nmx = 0; idxnam.nam$w_fid.fid$b_rvn = fid->fid$b_rvn; idxnam.nam$l_rsa = rsbuf; idxnam.nam$b_rss = NAM$C_MAXRSS; do { idxfab.fab$l_nam = &idxnam; if( $FAILS(status = sys_open(&idxfab)) ) break; idxrab.rab$l_fab = &idxfab; if( $FAILS(status = sys_connect( &idxrab )) ) { sys_close( &idxfab ); break; } idxrab.rab$l_ubf = idxbuf; idxrab.rab$w_usz = 512; idxrab.rab$w_rfa[2] = 0; idxrab.rab$w_rfa[1] = (uint16_t) (2 >> 16); /* HOMVBN */ idxrab.rab$w_rfa[0] = (uint16_t) (2); if( $FAILS(status = sys_get( &idxrab )) ) break; hom = (struct HOME *)idxbuf; vbn = ( F11WORD( hom->hm2$w_ibmapvbn ) + F11WORD( hom->hm2$w_ibmapsize ) + ((fid->fid$b_nmx << 16) | fid->fid$w_num) -1 ); *clustersize = F11WORD( hom->hm2$w_cluster ); idxrab.rab$w_rfa[2] = 0; idxrab.rab$w_rfa[1] = (uint16_t) (vbn >> 16); idxrab.rab$w_rfa[0] = (uint16_t) (vbn); status = sys_get( &idxrab ); } while( 0 ); sys_disconnect( &idxrab ); sys_close( &idxfab ); if( $FAILED(status) ) { printmsg( ODS2_FILHDRACC, 0 ); status = printmsg( status, MSG_CONTINUE|MSG_NOARGS|MSG_TOFILE, of, ODS2_FILHDRACC ); } return status; } /*********************************************************** print_fileheader() */ static void print_fileheader( FILE *of, struct HEAD *fhd, uint32_t *vbn, uint32_t clustersize ) { f11word *mp, *ep; f11long hiblk; struct IDENT *id; size_t idsize; char fname[ sizeof( id->fi2$t_filename ) + sizeof( id->fi2$t_filenamext ) + 1 ]; id = (struct IDENT *)(((f11word *)fhd) + fhd->fh2$b_idoffset); idsize = (size_t)(fhd->fh2$b_mpoffset - fhd->fh2$b_idoffset) * 2; if( idsize >= sizeof( id->fi2$t_filename ) ) { char *p; memset( fname, ' ', sizeof( fname ) ); memcpy( fname, id->fi2$t_filename, sizeof( id->fi2$t_filename )); idsize -= offsetof( struct IDENT, fi2$t_filenamext ); if( idsize ) { if( idsize > sizeof( id->fi2$t_filenamext ) ) idsize = sizeof( id->fi2$t_filenamext ); memcpy( fname + sizeof( id->fi2$t_filename ), id->fi2$t_filenamext, idsize ); } for( p = fname + sizeof(fname); p > fname && p[-1] == ' '; --p ) p[-1] = '\0'; fname[sizeof(fname) -1] = '\0'; printmsg( DIRECT_IDNAME, MSG_TEXT|MSG_TOFILE, of, fname ); } hiblk = F11SWAP( fhd->fh2$w_recattr.fat$l_hiblk ); if( fhd->fh2$w_seg_num != 0 ) printmsg( DIRECT_EXTNHDR, MSG_TEXT|MSG_TOFILE, of, F11WORD( fhd->fh2$w_seg_num ), (((uint32_t)fhd->fh2$w_ext_fid.fid$b_nmx) << 16 | F11WORD(fhd->fh2$w_ext_fid.fid$w_num)), F11WORD(fhd->fh2$w_ext_fid.fid$w_seq), fhd->fh2$w_ext_fid.fid$b_rvn ); printmsg( DIRECT_HDROFFSETS, MSG_TEXT|MSG_TOFILE, of, fhd->fh2$b_idoffset, fhd->fh2$b_mpoffset, fhd->fh2$b_acoffset, fhd->fh2$b_rsoffset ); printmsg( DIRECT_MAPSIZE, MSG_TEXT|MSG_TOFILE, of, fhd->fh2$b_acoffset - fhd->fh2$b_mpoffset, fhd->fh2$b_map_inuse, clustersize, hiblk ); if( fhd->fh2$b_idoffset >= 40 && fhd->fh2$l_highwater ) printmsg( DIRECT_MAPHIGHWATER, MSG_TEXT|MSG_TOFILE, of, F11LONG( fhd->fh2$l_highwater ) - 1 ); printmsg( DIRECT_STRUCLEVEL, MSG_TEXT|MSG_TOFILE, of, fhd->fh2$w_struclev >> 8, fhd->fh2$w_struclev & 0xFFu ); mp = ((f11word *)fhd) + fhd->fh2$b_mpoffset; ep = mp + fhd->fh2$b_map_inuse; if( mp >= ep ) return; printmsg( DIRECT_MAPHEADER, MSG_TEXT|MSG_TOFILE, of ); while( mp < ep ) { f11word e0; uint32_t 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: printmsg( DIRECT_MAPFMT0, MSG_TEXT|MSG_TOFILE, of, e0 ); continue; } ++count; printmsg( DIRECT_MAPENTRY, MSG_TEXT|MSG_TOFILE, of, *vbn, (e0 >> 14), count, pbn, pbn + count -1 ); *vbn += count; } printmsg( DIRECT_MAPFREE, MSG_TEXT|MSG_TOFILE, of, *vbn ); return; }