From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  6-OCT-1990 16:30:26.66
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	Re: Given file ID only, can I determine file size?

Received:  by crdgw1.ge.com (5.57/GE 1.73)
	 id AA09569; Sat, 6 Oct 90 16:11:31 EDT
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Sat,  6 OCT 90 13:01:03 PDT
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA07068; Sat, 6 Oct 90 12:39:35 -0700
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 6 Oct 90 14:34:51 GMT
From: eru!hagbard!sunic!mcsun!ukc!strath-cs!ctssuk!VERKADE@bloom-beacon.mit.edu  (Herman Verkade)
Organization: CompuThoughts Software Solutions (UK) Ltd.
Subject: Re: Given file ID only, can I determine file size?
Message-Id: <901006153451.000009EA@MARVIN.CTSS.CO.UK>
References: <2699F96C509FA00390@moose.cccs.umn.edu>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

In article <2699F96C509FA00390@moose.cccs.umn.edu>, RAO@MOOSE.CCCS.UMN.EDU ("Rao V. Akella") writes:
>Given only a file ID -- in the format, for eg., (973,19,1) -- can I find out
>how big the file is?

Attached a program to do that. It was written under VMS V4.3, but still works.

Usage:

	$ ff :== $dev:[dir]find_file
	$ ff -f <first-nr-of-fid> <disk>

Gives you the file header a la DUMP/HEADER. Leave out the `-f' and you get
a simple trace through the backlinks to find what directories a file is in.

--------------- find_file.c ----------------------
/*
 *	Module:		FIND_FILE.C
 *	Description:	Find a file on disk by its file ID
 *	Author:		Herman Verkade
 *
 *	Revision History:
 *
 *	002	20-jan-1988	- Implement -f switch to dump the full header
 *				- Loop through all the backlink pointers
 *	001	24-dec-1987	- Display more information
 *	000	25-mar-1987	- Adapted from INDEX.C
 */

#include stdio
#include iodef
#include ssdef
#include descrip
#include fibdef
#include "ods2def.h"

#define FILENAME_SIZE 87
#define TIME_SIZE 23

/*
 * Make life a bit more comfortable with a couple of macro's:
 */

#define $assign(a,b,c,d) \
    status = sys$assign(a,b,c,d);\
    if (!(status & 1)) lib$signal(status);

#define $qiow(a,b,c,d,e,f,g,h,i,j,k,l) \
    status = sys$qiow(a,b,c,d,e,f,g,h,i,j,k,l);\
    if (!(status & 1)) lib$signal(status);\
    if (!(iosb.iostat & 1)) lib$signal(iosb.iostat);

#define $asctim(a,b,c,d) \
    status = sys$asctim(a,b,c,d);\
    if (!(status & 1)) lib$signal(status);

#define usage() \
    fprintf (stderr, "usage: sfh [-f] filenumber [disk]\n");\
    exit();

/*
 * Define the I/O-status block.
 */

struct	IOSB	{
    short	iostat;
    unsigned : 16 ;
    int		iocount;
} ;


/*
 * Now, let's start the main program
 */

main(argc, argv)
int argc;
char *argv[];
{
    char	filename[FILENAME_SIZE],
		time[TIME_SIZE + 1];
    short	ch;
    int		status, i,
		sw_full = 0,
		argsdone = 0,
		file_number,
		rpsize,
		start_block,
		blocks;
    struct file_header	file_h;
    struct hm2		home_b;
    struct fh2		*hdarea;
    struct fi2		*idarea;
    struct fm2		*mparea;
    union  fp2		*rp;
    struct fibdef	fib;
    struct IOSB		iosb;

    $DESCRIPTOR(d_devnam, "SYS$DISK:");
    struct dsc$descriptor d_fib = 
		{ sizeof(fib), DSC$K_DTYPE_T, DSC$K_CLASS_S, &fib};
    struct dsc$descriptor d_time = 
		{ TIME_SIZE, DSC$K_DTYPE_T, DSC$K_CLASS_S, time};


/* Check arguments */
    for (i = 1; i < argc; i++) {
	if (argv[i][0] == '-') {
	    switch (argv[i][1]) {
	      case 'f':
		sw_full = 1;
		break;
	      default:
		usage();
	    }
	} else {
	    switch (argsdone++) {
	      case 0:
		sscanf(argv[i], "%d", &file_number);
		break;
	      case 1:
		d_devnam.dsc$a_pointer = argv[i];
		d_devnam.dsc$w_length = strlen(argv[i]);
		break;
	      default:
		usage();
	    }
	}
    }
    if (argsdone <= 0) {
	usage();
    }

/* Assign a channel to the device */
    $assign(&d_devnam, &ch, 0, 0);

/* Set up the FIB to read file (1,1,0), which is always INDEXF.SYS */
    fib.fib$r_acctl_overlay.fib$r_acctl_bits0.fib$v_norecord = 1;
    fib.fib$r_fid_overlay.fib$r_fid_fields.fib$w_fid_num = 1;
    fib.fib$r_fid_overlay.fib$r_fid_fields.fib$w_fid_seq = 1;
    fib.fib$r_fid_overlay.fib$r_fid_fields.fib$r_fid_rvn_overlay.fib$w_fid_rvn = 0;

/* Access the file */
    $qiow(0, ch, IO$_ACCESS | IO$M_ACCESS, &iosb, 0, 0, &d_fib, 0, 0, 0, 0, 0);

/* Read the home block, which is always in block 2 */
    $qiow(0, ch, IO$_READVBLK, &iosb, 0, 0, &home_b, BUFSIZ, 2, 0, 0, 0);

/* Check for ODS-2 structure */
    if (home_b.hm2$b_structlev != 2) {
	printf("This is not an ODS-2 disk\n");
	exit();
    }

/* Read the appropriate file header */
    while (file_number > 0) {
	$qiow(0, ch, IO$_READVBLK, &iosb, 0, 0, &file_h, BUFSIZ, 
	    home_b.hm2$w_ibmapvbn + home_b.hm2$w_ibmapsize + file_number - 1,
	    0, 0, 0);
	hdarea = (struct fh2 *) &file_h;
	idarea = (struct fi2 *) &file_h.word[hdarea->fh2$b_idoffset];
	mparea = (struct fm2 *) &file_h.word[hdarea->fh2$b_mpoffset];
	strncpy(filename, idarea->fi2$t_filename, 20);
	strncpy(&filename[20], idarea->fi2$t_filenamext, 66);
	filename[86] = '\0';
	for (i = 85; filename[i] == ' '; i--) {
	    filename[i] = '\0';
	}
	time[TIME_SIZE] = '\0';

	if (sw_full) {
	    printf ("\nHeader area\n");
	    printf ("    Identification area offset:           %d\n",
				hdarea->fh2$b_idoffset);
	    printf ("    Map area offset:                      %d\n",
				hdarea->fh2$b_mpoffset);
	    printf ("    Access control area offset:           %d\n",
				hdarea->fh2$b_acoffset);
	    printf ("    Reserved area offset:                 %d\n",
				hdarea->fh2$b_rsoffset);
	    printf ("    Extension segment number:             %d\n",
				hdarea->fh2$w_seg_num);
	    printf ("    Structure level and version:          %d, %d\n",
				hdarea->fh2$b_structlev,
				hdarea->fh2$b_structver);
	    printf ("    File identification:                  (%d,%d,%d)\n",
				hdarea->fh2$w_fid[0],
				hdarea->fh2$w_fid[1],
				hdarea->fh2$w_fid[2]);
	    printf ("    Extension file identification:        (%d,%d,%d)\n",
				hdarea->fh2$w_ext_fid[0],
				hdarea->fh2$w_ext_fid[1],
				hdarea->fh2$w_ext_fid[2]);
	    printf ("    File characteristics:                 %d\n",
				hdarea->fh2$l_filechar);
	    printf ("    Map area words in use:                %d\n",
				hdarea->fh2$b_map_inuse);
	    printf ("    Access mode:                          %d\n",
				hdarea->fh2$b_acc_mode);
	    printf ("    File owner UIC:                       [%o,%o]\n",
				hdarea->fh2$l_fileowner / 0x10000,
				hdarea->fh2$l_fileowner % 0x10000);
	    printf ("    File protection:                      %08X\n",
				hdarea->fh2$w_fileprot);
	    printf ("    Back link file identification:        (%d,%d,%d)\n",
				hdarea->fh2$w_backlink[0],
				hdarea->fh2$w_backlink[1],
				hdarea->fh2$w_backlink[2]);
	    printf ("    Journal control flags:                %d\n",
				hdarea->fh2$b_journal);
	    printf ("    Active recovery units:                %d\n",
				hdarea->fh2$b_ru_active);
	    printf ("    Highest block written:                %d\n",
				hdarea->fh2$l_highwater - 1);
	    printf ("\nIdentification area\n");
	    printf ("    File name:                            %s\n",
				filename);
	    printf ("    Revision number:                      %d\n",
				idarea->fi2$w_revision);
	    if (idarea->fi2$q_credate[1] !=  0) {
		$asctim(0, &d_time, idarea->fi2$q_credate, 0);
	    } else {
		strcpy(time, "<none specified>");
	    }
	    printf ("    Creation date:                        %s\n", time);
	    if (idarea->fi2$q_revdate[1] !=  0) {
		$asctim(0, &d_time, idarea->fi2$q_revdate, 0);
	    } else {
		strcpy(time, "<none specified>");
	    }
	    printf ("    Revision date:                        %s\n", time);
	    if (idarea->fi2$q_expdate[1] !=  0) {
		$asctim(0, &d_time, idarea->fi2$q_expdate, 0);
	    } else {
		strcpy(time, "<none specified>");
	    }
	    printf ("    Expiration date:                      %s\n", time);
	    if (idarea->fi2$q_bakdate[1] !=  0) {
		$asctim(0, &d_time, idarea->fi2$q_bakdate, 0);
	    } else {
		strcpy(time, "<none specified>");
	    }
	    printf ("    Backup date:                          %s\n", time);
	    printf ("\nMap area\n    Retrieval pointers\n");
	    for (rp = mparea; rp < &file_h.word[hdarea->fh2$b_mpoffset + hdarea->fh2$b_map_inuse]; 
			rp = (union fp2 *) (((char *) rp) + rpsize)) {
		switch (rp->fm2$c_placement.fm2$v_format) {
		  case FM2$C_PLACEMENT:
		    printf("Placement pointer found\n");
		    rpsize = sizeof(rp->fm2$c_placement);
		    continue;
		  case FM2$C_FORMAT1:
		    start_block = rp->fm2$c_format1.fm2$v_highlbn * 0x10000 + 
			    rp->fm2$c_format1.fm2$w_lowlbn;
		    blocks = rp->fm2$c_format1.fm2$b_count1 + 1;
		    rpsize = sizeof(rp->fm2$c_format1);
		    break;
		  case FM2$C_FORMAT2:
		    start_block = rp->fm2$c_format2.fm2$l_lbn2;
		    blocks = rp->fm2$c_format2.fm2$v_count2 + 1;
		    rpsize = sizeof(rp->fm2$c_format2);
		    break;
		  case FM2$C_FORMAT3:
		    start_block = rp->fm2$c_format3.fm2$l_lbn3;
		    blocks = rp->fm2$c_format3.fm2$v_count3 * 0x10000 + 
			    rp->fm2$c_format3.fm2$w_lowcount + 1;
		    rpsize = sizeof(rp->fm2$c_format3);
		    break;
		}
		printf("        Count:   %8d        LBN:   %8d\n", blocks, start_block);
	    }
	    file_number = hdarea->fh2$w_ext_fid[0];
	} else {
	    printf ("File (%d,%d,%d) owned by [%o,%o] has backlink pointer to (%d,%d,%d)\n",
				hdarea->fh2$w_fid[0],
				hdarea->fh2$w_fid[1],
				hdarea->fh2$w_fid[2],
				hdarea->fh2$l_fileowner / 0x10000,
				hdarea->fh2$l_fileowner % 0x10000,
				hdarea->fh2$w_backlink[0],
				hdarea->fh2$w_backlink[1],
				hdarea->fh2$w_backlink[2]);
	    printf ("    File name is \"%s\"\n",
				filename);
	    if (file_number == hdarea->fh2$w_backlink[0]) {
		file_number = 0;
	    } else {
		file_number = hdarea->fh2$w_backlink[0];
	    }
	}
    }
    exit();
}
----------------------- ods2def.h ---------------------------
/*
 *	Module:		ODS2DEF.H
 *	Description:	Structure definitions for ODS-2 (Files-11 Structure 2)
 *	Author:		Herman Verkade
 *
 *	Revision History:
 *
 *	001	21-oct-1988	- Changed record attributes field in FH2
 *	000	25-mar-1987	- Build according to DEC Files-11 document
 *
 *
 * Since Files-11 is not part of the VMS-architecture, but an architecture on
 * its own, the VMS documentation does not tell you anything about it. The
 * micro fiche tells something (Try INIT), but there is some internal DEC
 * document describing ODS-2 (the official name for Files-11 Level 2). It's 
 * hard to get it from TSC, but we got a part of it. All the structures 
 * described in that document are in this file. It is subject to change 
 * without notice, so they say at DEC, so I'll have to check the version 
 * of the file-structure and will abort running this program, if it's not 
 * level 2 version 1.
 *
 * A little update: the definitions of the various blocks are available in
 * SYS$LIBRARY:LIB.MLB in $HM2DEF, $FH2DEF, etc, but without any comments.
 * The comments in this piece of code come out of the DEC document. Check 
 * the definitions in LIB.MLB with each new VMS version to see if anything's 
 * changed.
 */

#ifndef __ODS2DEF_LOADED
#define __ODS2DEF_LOADED 1

#include <fatdef.h>

/*
 * This is the structure of the homeblock. This block is there a couple 
 * of times. It's always in blocks 2 and 3 and fills out the first three 
 * clusters of INDEXF.SYS.
 */

struct	HM2	{
    unsigned int hm2$l_homelbn;		/* Home Block LBN */
    unsigned int hm2$l_alhomelbn;	/* Alternate Home Block LBN */
    unsigned int hm2$l_altidxlbn;	/* Backup Index File header LBN */
    unsigned char hm2$b_strucver;	/* Structure Version */
    unsigned char hm2$b_struclev;	/* Structure Level */
    unsigned short hm2$w_cluster;	/* Storage Bitmap Cluster Factor */
    unsigned short hm2$w_homevbn;	/* Home Block VBN */
    unsigned short hm2$w_alhomevbn;	/* Backup Home Block VBN */
    unsigned short hm2$w_altidxvbn;	/* Backup Index File Header VBN */
    unsigned short hm2$w_ibmapvbn;	/* Index File Bitmap VBN */
    unsigned int hm2$l_ibmaplbn;	/* Index File Bitmap LBN */
    unsigned int hm2$l_maxfiles;	/* Maximum Number of Files */
    unsigned short hm2$w_ibmapsize;	/* Index File Bitmap Size */
    unsigned short hm2$w_resfiles;	/* Number Of Reserved Files */
    unsigned short hm2$w_devtype;	/* Disk Device Type (unused) */
    unsigned short hm2$w_rvn;		/* Relative Volume number */
    unsigned short hm2$w_setcount;	/* Number Of Volumes */
    unsigned short hm2$w_volchar;	/* Volume Characteristics */
#define HM2$V_READCHECK		0
#define HM2$M_READCHECK		(1 << HM2$V_READCHECK)
#define HM2$V_WRITECHECK	1
#define HM2$M_WRITECHECK	(1 << HM2$V_WRITECHECK)
#define HM2$V_ERASE		2
#define HM2$M_ERASE		(1 << HM2$V_ERASE)
#define HM2$V_NOHIGHWATER	3
#define HM2$M_NOHIGHWATER	(1 << HM2$V_NOHIGHWATER)
#define HM2$V_CLASS_PROT	4
#define HM2$M_CLASS_PROT	(1 << HM2$V_CLASS_PROT)
    unsigned int hm2$l_volowner;	/* Volume Owner UIC */
    unsigned : 32 ;			/* (Unused) */
    unsigned short hm2$w_protect;	/* Volume Protection Code */
    unsigned short hm2$w_fileprot;	/* Default File Protection */
    unsigned short hm2$w_recprot;	/* (Unused) */
    unsigned short hm2$w_checksum1;	/* First Checksum */
    unsigned int hm2$q_credate[2];	/* Volume Creation Date */
    unsigned char hm2$b_window;		/* Default Window Size */
    unsigned char hm2$b_lru_lim;		/* Directory Pre-access Limit */
    unsigned short hm2$w_extend;		/* Default File Extend */
    unsigned int hm2$q_retainmin[2];	/* Minimum File Retention Period */
    unsigned int hm2$q_retainmax[2];	/* Maximum File Retention Period */
    unsigned int hm2$q_revdate[2];	/* Volume Revision Date */
#define	HM2$S_MIN_CLASS		20
    unsigned char hm2$r_min_class[HM2$S_MIN_CLASS];
					/* Minimum Security Class */
#define	HM2$S_MAX_CLASS		20
    unsigned char hm2$r_max_class[HM2$S_MAX_CLASS];
					/* Maximum Security Class */
    unsigned char hm2_reserved[320];	/* (Unused) */
    unsigned int hm2$l_serialnum;	/* Media Serial Number */
#define	HM2$S_STRUCNAME		12
    unsigned char hm2$t_strucname[HM2$S_STRUCNAME];
					/* Structure Name */
#define	HM2$S_VOLNAME		12
    unsigned char hm2$t_volname[HM2$S_VOLNAME];
					/* Volume Name */
#define	HM2$S_OWNERNAME		12
    unsigned char hm2$t_ownername[HM2$S_OWNERNAME];
					/* Owner Name */
#define	HM2$S_FORMAT		12
    unsigned char hm2$t_format[HM2$S_FORMAT];
					/* Format Type */
    unsigned : 16;			/* (Unused) */
    unsigned short hm2$w_checksum2;	/* Second Checksum */
} ;

/*
 * A file header is in fact just an array if 255 words plus a checksum. It 
 * contains 5 area's, whose sizes are not necessarily constant. The first 
 * area is the header area, starts always in word 0 and contains offsets 
 * to the other 4 areas.
 */

struct	file_header {
    unsigned short word[255];
    unsigned short checksum;
} ;

/*
 * This is the structure of the header area of the file header.
 */

struct	FH2	{
    unsigned char fh2$b_idoffset;	/* Ident Area Offset (in words) */
    unsigned char fh2$b_mpoffset;	/* Map Area Offset (in words) */
    unsigned char fh2$b_acoffset;	/* Access Control List Ofsset */
    unsigned char fh2$b_rsoffset;	/* Reserved Area Offset */
    unsigned short fh2$w_seg_num;	/* Extension Segment Number */
    unsigned char fh2$b_strucver;	/* Structure Version */
    unsigned char fh2$b_struclev;	/* Structure Level */
    unsigned short fh2$w_fid[3];	/* File ID */
    unsigned short fh2$w_ext_fid[3];	/* Extension file ID */
/*
 * This next area is not part of ODS-2. It is "used by the record manager, 
 * or any other higher level access mechanism, to store information necessary 
 * for processing the file, e.g., record control data, end of file mark, etc.".
 * In the I/O User's Guide the ACP Record Attributes Area is described in 
 * more detail.
 */
    struct FAT fh2$w_recattr;		/* Record Attributes */

    unsigned int fh2$l_filechar;	/* File Characteristics */
#define FCH$V_NOBACKUP		1
#define FCH$M_NOBACKUP		(1 << FCH$V_NOBACKUP)
#define FCH$V_WRITEBACK		2
#define FCH$M_WRITEBACK		(1 << FCH$V_WRITEBACK)
#define FCH$V_READCHECK		3
#define FCH$M_READCHECK		(1 << FCH$V_READCHECK)
#define FCH$V_WRITCHECK		4
#define FCH$M_WRITCHECK		(1 << FCH$V_WRITCHECK)
#define FCH$V_CONTIGB		5
#define FCH$M_CONTIGB		(1 << FCH$V_CONTIGB)
#define FCH$V_LOCKED		6
#define FCH$M_LOCKED		(1 << FCH$V_LOCKED)
#define FCH$V_CONTIG		7
#define FCH$M_CONTIG		(1 << FCH$V_CONTIG)
#define FCH$V_BADACL		11
#define FCH$M_BADACL		(1 << FCH$V_BADACL)
#define FCH$V_SPOOL		12
#define FCH$M_SPOOL		(1 << FCH$V_SPOOL)
#define FCH$V_DIRECTORY		13
#define FCH$M_DIRECTORY		(1 << FCH$V_DIRECTORY)
#define FCH$V_BADBLOCK		14
#define FCH$M_BADBLOCK		(1 << FCH$V_BADBLOCK)
#define FCH$V_MARKDEL		15
#define FCH$M_MARKDEL		(1 << FCH$V_MARKDEL)
#define FCH$V_NOCHARGE		16
#define FCH$M_NOCHARGE		(1 << FCH$V_NOCHARGE)
#define FCH$V_ERASE		17
#define FCH$M_ERASE		(1 << FCH$V_ERASE)
    unsigned short fh2$w_recprot;	/* Record Protection */
    unsigned char fh2$b_map_inuse;	/* Map Words in Use */
    unsigned char fh2$b_acc_mode;	/* Accessor Privilege Level */
    unsigned int fh2$l_fileowner;	/* File Owner UIC */
    unsigned short fh2$w_fileprot;	/* File Protection Code */
    unsigned short fh2$w_backlink[3];	/* Back Link File ID */
    unsigned char fh2$b_journal;	/* Journal Control Flags */
#define FJN$V_ONLY_RU		0
#define FJN$M_ONLY_RU		(1 << FJN$V_ONLY_RU)
#define FJN$V_RUJNL		1
#define FJN$M_RUJNL		(1 << FJN$V_RUJNL)
#define FJN$V_BIJNL		2
#define FJN$M_BIJNL		(1 << FJN$V_BIJNL)
#define FJN$V_AIJNL		3
#define FJN$M_AIJNL		(1 << FJN$V_AIJNL)
#define FJN$V_ATJNL		4
#define FJN$M_ATJNL		(1 << FJN$V_ATJNL)
#define FJN$V_NEVER_RU		5
#define FJN$M_NEVER_RU		(1 << FJN$V_NEVER_RU)
#define FJN$V_JOURNAL_FILE	6
#define FJN$M_JOURNAL_FILE	(1 << FJN$V_JOURNAL_FILE)
    unsigned char fh2$b_ru_active;	/* Number of Recovery Units active */
    unsigned : 16;
    unsigned int fh2$l_highwater;	/* File Highwater Mark */
#define	FH2$S_CLASS_PROT	20
    unsigned char fh2$r_class_prot[FH2$S_CLASS_PROT];
    					/* Not used by VMS */
} ;

/*
 * Structure of the identification area.
 */

struct	FI2	{
#define		FI2$S_FILENAME		20
    unsigned char fi2$t_filename[FI2$S_FILENAME];
					/* File name */
    unsigned short fi2$w_revision;	/* Revision Number */
    unsigned int fi2$q_credate[2];	/* Creation Date and Time */
    unsigned int fi2$q_revdate[2];	/* Revision Date and Time */
    unsigned int fi2$q_expdate[2];	/* Expiration Date and Time */
    unsigned int fi2$q_bakdate[2];	/* Backup Date and Time */
#define		FI2$S_FILENAMEXT	66
    unsigned char fi2$t_filenamext[FI2$S_FILENAMEXT];
					/* File Name Extension */
#define		FI2$S_USERLABEL		80
    unsigned char fi2$t_userlabel[FI2$S_USERLABEL];
					/* Found in V4.5 */
} ;

/*
 * The map area contains the retrieval pointers. There are four types
 * of pointers. Format 0 (Placement) only gives some attributes for
 * the next pointer and does not contain any block numbers and such.
 * The other three formats contain real pointers. These pointers are
 * 4, 6 and 8 bytes long respectively. Bits 14 and 15 of the first word
 * of each pointer determine what type of pointer it is
 */

#define	FM2$C_PLACEMENT		0
#define	FM2$C_FORMAT1		1
#define	FM2$C_FORMAT2		2
#define	FM2$C_FORMAT3		3

struct FM2 {
    union FP2 {
	struct {
	    unsigned       fm2$w_word0   : 14;
#define	FM2$V_EXACT	0
#define	FM2$M_EXACT	(1 << FM2$V_EXACT)
#define	FM2$V_ONCYL	1
#define	FM2$M_ONCYL	(1 << FM2$V_ONCYL)
#define	FM2$V_LBN	12
#define	FM2$M_LBN	(1 << FM2$V_LBN)
#define	FM2$V_RVN	13
#define	FM2$M_RVN	(1 << FM2$V_RVN)
	    unsigned       fm2$v_format  :  2;
	} fm2$c_placement;
	struct {
	    unsigned char  fm2$b_count1;
	    unsigned       fm2$v_highlbn :  6;
	    unsigned       fm2$v_format  :  2;
	    unsigned short fm2$w_lowlbn;
	} fm2$c_format1;
	struct {
	    unsigned       fm2$v_count2  : 14;
	    unsigned       fm2$v_format  :  2;
	    unsigned int   fm2$l_lbn2;
	} fm2$c_format2;
	struct {
	    unsigned       fm2$v_count3  : 14;
	    unsigned       fm2$v_format  :  2;
	    unsigned short fm2$w_lowcount;
	    unsigned int   fm2$l_lbn3;
	} fm2$c_format3;
    } pointer[];
} ;
#endif

