[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

475.0. "File's size info from a program" by MELANG::HEINZER (Dieter Heinzer, PC Hacker, Colorado Springs) Tue May 19 1987 12:41

                 Help regarding a file's size (in blocks)...

I am currently writing a utility (VAX FORTRAN) which needs to know the size
of a given file. Below is an extract from that program which shows how I am
currently getting that information. (Yes it works, but...)  The problem:  I
need to explicitly open and close every single file in order to get the FHC
information, and this is SLOW and seems to somehow be wrong and NON-optimal.
After all, the DCL DIRECTORY command does it, and I doubt seriously that IT
opens and then closes every single file!!!

Can anyone point me to the place inside the Doc-set where there is a better
way?  Or perhaps even show me a short hack?  I would certainly appreciate it.

Thanks. 

					  --> Dieter <--
					  He Who Hacketh (or at least tries)

	  ...
	  ...
	  ...
	  file_spec = Sub_Dir(j) // '*.*.*'	! Init file-spec to "any file"
40	  continue				!    in a given sub-directory
	  stat = LIB$FIND_FILE (file_spec,Sub_Dir_spec,context) ! Who's there?
	  if (stat .ne. RMS$_NORMAL) then
	    goto 30	! Go and see what's wrong...might be done or hosed...
	  else
	    stat = STR$POSITION (Sub_Dir_spec,']')
	    file_name = Sub_Dir_spec(stat+1:)	! Remove leading DIR spec stuff
	    count = count + 1			! Yup, this is called "counting"
C *****************************************************************************
C *	This is where the "PAIN" starts, because I have to OPEN any found     *
C *	file just to ascertain its block size...this sucks...there has to     *
C *	be a better way...I hope...                                           *
C *****************************************************************************
	    myfab.FAB$B_BID = FAB$C_BID		! Set up my FAB for RMS access
	    myfab.FAB$B_BLN = FAB$C_BLN		!    first two fields required
	    myfab.FAB$B_FAC = FAB$M_GET		! All I want is to READ
	    stat = STR$TRIM(Sub_Dir_spec, Sub_Dir_spec, len)   ! Get f-name len
	    myfab.FAB$L_FNA = %LOC(Sub_Dir_spec)	! Set address of f-name
	    myfab.FAB$B_FNS = len			! Set its length value
	    myfab.FAB$L_XAB = %LOC(myxab)		! Point to XAB
	    myxab.myxabdef2.xab$b_cod = XAB$C_FHC	! Define XAB type (FHC)
	    myxab.myxabdef2.xab$b_bln = XAB$C_FHCLEN	! It's "this" big...
	    stat = SYS$OPEN (myfab)		! Yo, RMS...do it to it...open
	    if (.not. stat) call LIB$STOP (%VAL(stat))	! Hmmm, what happened...
	    !
	    ! Actually, there's much more intelligent error trapping/analysis
	    ! going on at this point, but it isn't relevant to my current goal.
	    !
C******************************************************************************
C******************************************************************************
C******************************************************************************
C
C	    ||||||||||||||||||||||||||||||||
C	    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

	    fsize = myxab.myxabdef.xab$l_ebk	! This is all I really want!!!

C	    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
C	    ||||||||||||||||||||||||||||||||
C
C******************************************************************************
C******************************************************************************
C******************************************************************************
	    stat = SYS$CLOSE (myfab)		! Yoohoo, RMS, I'm all done...
	    if (.not. stat) call LIB$STOP (%VAL(stat))	! Die the Ugly Death...
	    ...
	    ...
	    ...
T.RTitleUserPersonal
Name
DateLines
475.1SET WATCH FILEFROST::W_PIPERbill piperTue May 19 1987 12:5410
    Try
    
    	$ SET PROC/PRIV=CMEXEC
    	$ SET WATCH FILE /CLASS=MAJOR
    	$ DIRECTORY/SIZE
    
    Looks like DIRECTORY is doing a LOOKUP on every file to get the
    size.  Don't know how helpful that is, but
    
    -piper
475.2see$faoVMSDEV::DICKINSONTue May 19 1987 16:1222
    
    Dieter,
    
    I'm without documentation at the moment, but here is an idea: 
    
    The online help for f$fao claims it works by invoking the $fao service,
    now you can get the size of file within a command prodedure by invoking
    invoking f$fao with f$attribute or something like tat. You can find
    it
    in the docs, I've done it so I know it's possible - what I don't
    know without looking in the docs is if you can also get  that same
    info with the $fao system service. If thats possible then your golden
    since all you will have to do is invoke $fao from your fortran code
    and give it the file name and the correct item and it will return
    the file lengt.
    
    sorry this looks so shity, lots of line noise.
    
    peter
    
    
    
475.3TLE::BRETTTue May 19 1987 16:214
    The info. is only in the file header.  DIRECTORY must be doing a
    $OPEN.
    
    /Bevin
475.4PASTIS::MONAHANWed May 20 1987 06:0026
    	The directory itself just contains a file name to file ID mapping
    (and a version limit). To get file size you must read the file header,
    which is what an open does.
    
    	DIRECTORY does what you are doing, and it is slow because every
    file header means a disk access, and almost certainly a head seek
    too.
    
    	The only VMS utility that sometimes does better is BACKUP. If
    you specify either /IMAGE or /FAST then it reads [000000]INDEXF.SYS
    sequentially, to get all file headers on the disk. This allows it
    to read many file headers in a single I/O request, and also avoids
    many head seeks. However, since it reads the header of *every* file
    on the disk, it only really wins if it would need many of them.
    
    	Depending on the characteristics of file creation of your
    application you might get some of this sort of advantage by reading
    the directory file, sorting on file ID, and then trying to block
    reads of the index file to get several of the headers you want at
    a time.
    
    	(Sorry I have only just found time - I have been out of the
    office - so I decided to reply here rather than directly to your
    mail).
    
    		Dave
475.5Thanks for the quick answersPIKES::HEINZERDieter Heinzer, Colorado HackerWed May 20 1987 14:1555
================================================================================
Note 475.1               File's size info from a program                  1 of 4
FROST::W_PIPER "bill piper"                          10 lines  19-MAY-1987 11:54
                              -< SET WATCH FILE >-
--------------------------------------------------------------------------------
Thanks Bill,

	I tried that and haven't figured out just exactly what it means either,
but judging from Bevin Brett (#3) and Dave Monahan's (#4) reply, I just might
be doing what DIRECTORY is also doing....Norm Lastovica (coworker and regular
contributor of kinky hack type stuff) also pointed me to the VMS/DCL sources,
but I haven't taken time to snoop through them YET!!! 

================================================================================
Note 475.2               File's size info from a program                  2 of 4
VMSDEV::DICKINSON                                    22 lines  19-MAY-1987 15:12
                                  -< see$fao >-
--------------------------------------------------------------------------------
Thanks Peter,

	I have successfully obtained that info via DCL (boy, talk about SLOW!)
but couldn't find anything similar in my Sys. Services doc....oh well...
Below are the non-complex (but VERY slow...) two DCL lines that are the meat
of this capability; I was not, however, in need of the Formatted ASCII Output's
services, just doing some number crunching on duplicate (i.e. wasted) files.

$	FN = F$SEARCH(P1)
$	SIZE = F$FILE_ATTRIBUTES("''FN'","ALQ")
    
================================================================================
Note 475.3               File's size info from a program                  3 of 4
TLE::BRETT                                            4 lines  19-MAY-1987 15:21
--------------------------------------------------------------------------------
Thanks Bevin,

	Methinks you're right...

================================================================================
Note 475.4               File's size info from a program                  4 of 4
PASTIS::MONAHAN                                      26 lines  20-MAY-1987 05:00
--------------------------------------------------------------------------------
Thanks Dave,

	No problem with the "busy" - I can relate to that problem myself...and
I appreciate the provided insight; maybe, just maybe, I will actually find the
time to include a hack routine to read the INDEXF.SYS like BACKUP!  I should be
so lucky....In the mean time, I'll be content doing it the way DIRECTORY and I
seem to already be doing it.

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Thanks again to all of you,

				--> Dieter <--
				He Who Hacketh [as best he can when he can...]
475.6the magic of $QIO and BLISSYALI::LASTOVICAStuck in a Lather-Rinse-Repeat loopThu May 21 1987 02:48152
    RE: .0
    	The place in the doc set is in the I/O user's guide on disks
    talking about the ACP QIO's (aren't these REALLY XQP QIO's these
    days ;-).  Anyhow:
    
Here is a bit of the directory sources.  What DIR does is to use LIB$FILE_SCAN
to loop through all matches of the file spec.  Then, the success action
routine does the ACP QIO to return all the information about each file.
then DIR does all sorts of things depending on what you wanted to see.  That
is the long and short of it.

	< bunches of setup and paramter checking, etc.>

LIB$FILE_SCAN (INPUT_FAB,
	   DIR$GET_INFO,		! File found action routine
	   DIR$INPUT_ERROR,		! Input error action routine
	   SCAN_CONTEXT);		! Context for stickyness

< the success action routine contains... >

IF CH$NEQ (NAM$C_DVI, FILE_NAM[NAM$T_DVI], NAM$C_DVI, DEVICE_NAME, 0)
OR .CHANNEL EQL 0
THEN			! assign a channel to the device
    BEGIN
    IF .CHANNEL NEQ 0 THEN $DASSGN (CHAN = .CHANNEL);
    CH$MOVE (NAM$C_DVI, FILE_NAM[NAM$T_DVI], DEVICE_NAME);
    CH$FILL (0, DSC$C_S_BLN, DEVICE_DESC);
    DEVICE_DESC[DSC$W_LENGTH] = .DEVICE_NAME[0];
    DEVICE_DESC[DSC$A_POINTER] = DEVICE_NAME[1];
    STATUS = $ASSIGN (DEVNAM = DEVICE_DESC,
		      CHAN = CHANNEL);
    IF NOT .STATUS
    THEN
	BEGIN
	CH$FILL (0, NAM$C_DVI, DEVICE_NAME);
	CHANNEL = 0;
	RETURN .STATUS;
	END;
    END;

! Build the ACP attribute list for the needed information.

CH$FILL (0, NUM_ATTR*8, ATTRIBUTES);
ATTRIBUTES [0, ATR$W_TYPE] = ATR$C_RECATTR;
ATTRIBUTES [0, ATR$W_SIZE] = ATR$S_RECATTR;
ATTRIBUTES [0, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_R_RECATTR];
ATTRIBUTES [1, ATR$W_TYPE] = ATR$C_CREDATE;
ATTRIBUTES [1, ATR$W_SIZE] = ATR$S_CREDATE;
ATTRIBUTES [1, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_Q_CREDATE];
ATTRIBUTES [2, ATR$W_TYPE] = ATR$C_REVDATE;
ATTRIBUTES [2, ATR$W_SIZE] = ATR$S_REVDATE;
ATTRIBUTES [2, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_Q_REVDATE];
ATTRIBUTES [3, ATR$W_TYPE] = ATR$C_EXPDATE;
ATTRIBUTES [3, ATR$W_SIZE] = ATR$S_EXPDATE;
ATTRIBUTES [3, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_Q_EXPDATE];
ATTRIBUTES [4, ATR$W_TYPE] = ATR$C_BAKDATE;
ATTRIBUTES [4, ATR$W_SIZE] = ATR$S_BAKDATE;
ATTRIBUTES [4, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_Q_BAKDATE];
ATTRIBUTES [5, ATR$W_TYPE] = ATR$C_STATBLK;
ATTRIBUTES [5, ATR$W_SIZE] = ATR$S_STATBLK;
ATTRIBUTES [5, ATR$L_ADDR] = ACP_STATISTICS;
ATTRIBUTES [6, ATR$W_TYPE] = ATR$C_UIC;
ATTRIBUTES [6, ATR$W_SIZE] = ATR$S_UIC;
ATTRIBUTES [6, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_L_FILEOWNER];
ATTRIBUTES [7, ATR$W_TYPE] = ATR$C_FPRO;
ATTRIBUTES [7, ATR$W_SIZE] = ATR$S_FPRO;
ATTRIBUTES [7, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_W_FILEPROT];
ATTRIBUTES [8, ATR$W_TYPE] = ATR$C_UCHAR;
ATTRIBUTES [8, ATR$W_SIZE] = ATR$S_UCHAR;
ATTRIBUTES [8, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_L_FILECHAR];
ATTRIBUTES [9, ATR$W_TYPE] = ATR$C_ASCDATES;
ATTRIBUTES [9, ATR$W_SIZE] = 2;
ATTRIBUTES [9, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_W_REVISION];
ATTRIBUTES [10, ATR$W_TYPE] = ATR$C_JOURNAL;
ATTRIBUTES [10, ATR$W_SIZE] = ATR$S_JOURNAL;
ATTRIBUTES [10, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_B_JOURNAL];
ATTRIBUTES [11, ATR$W_TYPE] = ATR$C_FNDACETYP;
ATTRIBUTES [11, ATR$W_SIZE] = ATR$S_FNDACETYP;
ATTRIBUTES [11, ATR$L_ADDR] = AI_JNLACE;
ATTRIBUTES [12, ATR$W_TYPE] = ATR$C_FNDACETYP;
ATTRIBUTES [12, ATR$W_SIZE] = ATR$S_FNDACETYP;
ATTRIBUTES [12, ATR$L_ADDR] = BI_JNLACE;
ATTRIBUTES [13, ATR$W_TYPE] = ATR$C_FNDACETYP;
ATTRIBUTES [13, ATR$W_SIZE] = ATR$S_FNDACETYP;
ATTRIBUTES [13, ATR$L_ADDR] = AT_JNLACE;
ATTRIBUTES [14, ATR$W_TYPE] = ATR$C_ACLLENGTH;
ATTRIBUTES [14, ATR$W_SIZE] = ATR$S_ACLLENGTH;
ATTRIBUTES [14, ATR$L_ADDR] = ACL_LENGTH;
ATTRIBUTES [15, ATR$W_TYPE] = ATR$C_FNDACETYP;
ATTRIBUTES [15, ATR$W_SIZE] = ATR$S_FNDACETYP;
ATTRIBUTES [15, ATR$L_ADDR] = RU_JNLACE;
ATTRIBUTES [16, ATR$W_TYPE] = ATR$C_RU_ACTIVE;
ATTRIBUTES [16, ATR$W_SIZE] = ATR$S_RU_ACTIVE;
ATTRIBUTES [16, ATR$L_ADDR] = DISPLAY_BLOCK[DIR_B_RU_FACILITY];

! Set up for the ACE locate operation necessary to get the RMS journal
! information.

AI_JNLACE[ACE$B_SIZE] = 0;
AI_JNLACE[ACE$B_TYPE] = ACE$C_RMSJNL_AI;
BI_JNLACE[ACE$B_SIZE] = 0;
BI_JNLACE[ACE$B_TYPE] = ACE$C_RMSJNL_BI;
AT_JNLACE[ACE$B_SIZE] = 0;
AT_JNLACE[ACE$B_TYPE] = ACE$C_RMSJNL_AT;
RU_JNLACE[ACE$B_SIZE] = 0;
RU_JNLACE[ACE$B_TYPE] = ACE$C_RMSJNL_RU_DEFAULT;

! Issue the ACP QIO to get the needed information.

CH$FILL (0, FIB$C_LENGTH, FIB);
CH$FILL (0, DSC$C_S_BLN, FIB_DESC);
FIB_DESC[DSC$W_LENGTH] = FIB$C_LENGTH;
FIB_DESC[DSC$A_POINTER] = FIB;

IF .QUAL_FLAGS[DIR_V_QUAL_FULL]
AND NOT .DISPLAY_BLOCK[DIR_V_SQD]
THEN
    BEGIN
    FIB[FIB$W_DID_NUM] = .FILE_NAM[NAM$W_DID_NUM];
    FIB[FIB$W_DID_SEQ] = .FILE_NAM[NAM$W_DID_SEQ];
    FIB[FIB$W_DID_RVN] = .FILE_NAM[NAM$W_DID_RVN];
    CH$FILL (0, DSC$C_S_BLN, FILE_DESC);
    FILE_DESC[DSC$W_LENGTH] = .FILE_NAM[NAM$B_NAME] +
			      .FILE_NAM[NAM$B_TYPE] +
			      .FILE_NAM[NAM$B_VER];
    FILE_DESC[DSC$A_POINTER] = .FILE_NAM[NAM$L_NAME];
    END
ELSE
    BEGIN
    FIB[FIB$W_FID_NUM] = .FILE_NAM[NAM$W_FID_NUM];
    FIB[FIB$W_FID_SEQ] = .FILE_NAM[NAM$W_FID_SEQ];
    FIB[FIB$W_FID_RVN] = .FILE_NAM[NAM$W_FID_RVN];
    END;

STATUS = $QIOW (FUNC = IO$_ACCESS,
		CHAN = .CHANNEL,
		IOSB = IOSTS,
		P1 = FIB_DESC,
		P2 = (IF .QUAL_FLAGS[DIR_V_QUAL_FULL]
		      AND NOT .DISPLAY_BLOCK[DIR_V_SQD]
		      THEN FILE_DESC ELSE 0),
		P5 = ATTRIBUTES);
IF .STATUS THEN STATUS = .IOSTS[0];
IF NOT .STATUS
THEN
    BEGIN
    $DASSGN (CHAN = .CHANNEL);
    CHANNEL = 0;
    RETURN .STATUS;
    END;

    
475.7Another (related) question...FDCV01::NICOLAZZOFri May 22 1987 08:506
    I understand how DIRECTORY gets the blocks allocated to a file,
    (from the statistics block returned by the $QIO), but how does
    it get the # of blocks used for a file?
    
    		Robert.
    
475.8BISTRO::HEINIf We don&#039;t Have it,You don&#039;t Need it!Fri May 22 1987 11:146
    Re .7,
    
    	Robert, in the RECATTR area the HIBLK and EFBLK which indicate
    Allocated resp. Used block counts. RTFM: IO USER Part I Chapter 1.4
    
    Hein.
475.9Many thanks!FDCV01::NICOLAZZOFri May 22 1987 11:539
    RE: .8
    	Hein, Thanks! I had just (out of desperation) begun to examine
    	 HIBLK and EFBLK. You saved me from wondering if I was heading
    	 down a rathole.
    
    			Robert.
    
    P.S. - I was beginning to think DIRECTORY did this by magic!