mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-26 20:21:45 +00:00
Too much to list all, but includes (in no particular order): - Cleanup for 64-bit builds, MSVC warnings. - Structured help - Help file compiler. - Supports volsets, writes/create work. - Support for I18n in messages, help. - Makefiles. - Initialize volume/volset - Command line editing/history Builds and works on Linux and Windows (VS). Not recently built or tested on other platforms, but not intentinonally broken.
822 lines
34 KiB
C
822 lines
34 KiB
C
/* 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;
|
|
}
|
|
|