Subject: Re: RMS provide API to directory files? From: Hein van den Heuvel Date: Thu, 02 Oct 2003 18:35:18 GMT Newsgroups: comp.os.vms Charles Gilley wrote: >> I want to be able to do a dir/total via code. I know I can use system >> to execute dir/total. Is there an API call to do this? How does the >> DCL dir/total command execute so quickly? lib$find_file is just too >> slow. Lib$find_file is not too slow. The subsequent SYS$OPEN might be, specially if you just use the returned name, making RMS walk the directories again. you can 'cheat' and look in the CONTEXT variable from lib$find_file. You'll find it pointing to a FAB with attached and filled in NAM block. This allows for an OPEN BY FILE_ID, you may want to hookup up an XABFHC. Now I'm pretty sure that this FAB even had ALQ filled in, so you'd be all done. However, the (BASIC!) test program below shows this is not (no longer) the case. Still, it show how you can get to the FAB. From C this is even easier. Directory uses LIB$FILE_SCAN (through succes routines). It then uses RMS for network file and direct XQP calls throgh the public APIs. Check the OpenVMS I/O Users's Reference manual for deatils (hey, that's twice in one day I refer to this book, and also twice this decade!) http://h71000.www7.hp.com/doc/731FINAL/6136/6136pro.html#file_info Unlike RMS, the ACP interface allows one to bypass locking: FIB$V_NOLOCK Also, it only reads the header, no file data (RMS will read prologue for REL and IDX). I'll also include an (untested) QIO example (Thanks Stuart, hope you don't mind!) Enjoy. 1 OPTION TYPE = EXPLICIT EXTERNAL LONG FUNCTION LIB$GET_FOREIGN, LIB$FIND_FILE, & LIB$FIND_FILE_END, LIB$TRIM_FILESPEC DECLARE STRING FILE_SPEC, RESULT_SPEC, TMP DECLARE LONG CONTEXT, I, J, STAT, FILE_COUNT EXTERNAL LONG CONSTANT RMS$_NORMAL, RMS$_NMF STAT = LIB$GET_FOREIGN (FILE_SPEC, "File specification: ") GO TO 2 IF FILE_SPEC = "" CONTEXT = 0% I = 0% STAT = LIB$FIND_FILE (FILE_SPEC, RESULT_SPEC, CONTEXT) WHILE (STAT AND 1%) AND (I < 15%) CALL Process_one_more_file (CONTEXT BY VALUE, RESULT_SPEC) STAT = LIB$FIND_FILE (FILE_SPEC, RESULT_SPEC, CONTEXT) NEXT FILE_COUNT = I CALL SYS$EXIT(STAT BY VALUE) UNLESS (STAT = RMS$_NMF) CALL LIB$FIND_FILE_END (CONTEXT) 2 END 3 SUB Process_one_more_file(fake_FAB FAB, STRING file_name) RECORD fake_FAB long START, FOP, STS, STV, ALQ END RECORD PRINT FAB::ALQ, file_name END SUB ================================================================================ Note 1900.5 help with file size 5 of 7 171 lines 5-SEP-1991 07:59 -< FILE_SIZE.C uses ACP $QIO interface >- -------------------------------------------------------------------------------- /* I have included a short main to show the use of this routine. It uses the ACP $QIO interface with an attributes block pointing to a statistics block to get the number of blocks allocated to a file... Stuart */ #include fibdef #include atrdef #include sbkdef #include iodef #include rms #include descrip unsigned int file_size(char *filename, unsigned int *filesize); main() { unsigned int status; char filename[] = "SYS$LOGIN:LOGIN.COM"; unsigned int filesize; if ( (status = file_size(filename,&filesize)) == 1) printf("File %s has %d blocks allocated\n",filename,filesize); else LIB$SIGNAL(status,0); } unsigned int file_size(char *filename, unsigned int *filesize) { struct FAB fab; /* File attributes block */ struct NAM nam; /* Name block */ struct fibdef fib; /* File information block */ struct FIB_DESC { int length; /* Length of file information block */ struct fibdef *fib; /* Address of file information block */ } fib_desc = { FIB$C_LENGTH, &fib }; struct sbkdef sbk; /* File statistics block */ struct atrdef atr[2] = /* File attributes block */ { {ATR$S_STATBLK, ATR$C_STATBLK, &sbk}, /* Statistics */ {0,0,0} /* End of atr */ }; char full_name[NAM$C_MAXRSS]; /* Full filename returned by RMS */ char nam_esa[NAM$C_MAXRSS]; /* Needed by search and parse */ $DESCRIPTOR(fullname_desc, full_name); /* Needed by $ASSIGN */ /* Used by $QIO system service... */ unsigned long iosb[2], status, function; unsigned short channel; /* Initialise the fab block */ fab = cc$rms_fab; fab.fab$l_nam = &nam; fab.fab$l_fop = FAB$M_NAM; fab.fab$l_fna = filename; fab.fab$b_fns = strlen(filename); /* Initialise the nam block */ nam = cc$rms_nam; nam.nam$l_rsa = &full_name; /* Full filename wanted at this address */ nam.nam$b_rss = NAM$C_MAXRSS; /* maximum size of full filename */ nam.nam$l_esa = &nam_esa; /* Expanded string address */ nam.nam$b_ess = NAM$C_MAXRSS; /* maximum size of expanded filename str */ /* Use RMS to find the file and fill in the NAM and FAB blocks */ if ( ((status=sys$parse(&fab,0,0)) & 1) == 1) status = sys$search(&fab,0,0); if ((status & 1) == 0) return status; /* Initialise the fib block */ memset(&fib,0,FIB$C_LENGTH); /* Copy the File ID from the nam block to the fib block */ memcpy( &fib.fib$r_fid_overlay.fib$w_fid , &nam.nam$w_fid[0], 6 ); /* Set the fib to allow file access even if the file is locked */ fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NOLOCK; /* Fill in the length of the filename in the descriptor */ fullname_desc.dsc$w_length = nam.nam$b_rsl; /* Assign a channel to the file so it can be opened */ status = SYS$ASSIGN( &fullname_desc, /* Device Name */ &channel, /* Returned Channel number */ 0, /* Access Mode */ 0 /* Mailbox Name */ ); if ((status & 1) == 0) return status; /************************************************************************* * We must now issue an ACCESS QIO to open the file. We need to specify * * a file attributes block and a statistics block in order to obtain * * the allocation count for the file * *************************************************************************/ function = IO$_ACCESS | IO$M_ACCESS; status = SYS$QIOW( 0, /* Event Flag Number */ channel, /* I/O channel */ function, /* I/O function code */ iosb, /* I/O status block address */ 0, /* AST Address */ 0, /* AST Parameter */ &fib_desc, /* P1, fib descriptor */ 0, /* P2, not used */ 0, /* P3, not used */ 0, /* P4, not used */ atr, /* P5, Attributes block */ 0); /* P6, not used */ if ((status & 1) == 0) return status; if ((iosb[0] & 1) == 0) return iosb[0]; /* Get the file allocation from the statistics block */ *filesize = sbk.sbk$w_filesizl + (sbk.sbk$w_filesizh << 16); /* Now close the file again */ function = IO$_DEACCESS; status = SYS$QIOW( 0, /* Event Flag Number */ channel, /* I/O channel */ function, /* I/O function code */ iosb, /* I/O status block address */ 0, /* AST Address */ 0, /* AST Parameter */ &fib_desc, /* P1, fib descriptor */ 0, /* P2, not used */ 0, /* P3, not used */ 0, /* P4, not used */ 0, /* P5, Attributes block */ 0); /* P6, not used */ if ((status & 1) == 0) return status; if ((iosb[0] & 1) == 0) return iosb[0]; return 1; } 1 OPTION TYPE = EXPLICIT EXTERNAL LONG FUNCTION LIB$GET_FOREIGN, LIB$FIND_FILE, & LIB$FIND_FILE_END, LIB$TRIM_FILESPEC DECLARE STRING FILE_SPEC, RESULT_SPEC, TMP DECLARE LONG CONTEXT, I, J, STAT, FILE_COUNT EXTERNAL LONG CONSTANT RMS$_NORMAL, RMS$_NMF STAT = LIB$GET_FOREIGN (FILE_SPEC, "File specification: ") GO TO 2 IF FILE_SPEC = "" CONTEXT = 0% I = 0% STAT = LIB$FIND_FILE (FILE_SPEC, RESULT_SPEC, CONTEXT) WHILE (STAT AND 1%) AND (I < 15%) CALL Process_one_more_file (CONTEXT BY VALUE, RESULT_SPEC) STAT = LIB$FIND_FILE (FILE_SPEC, RESULT_SPEC, CONTEXT) NEXT FILE_COUNT = I CALL SYS$EXIT(STAT BY VALUE) UNLESS (STAT = RMS$_NMF) CALL LIB$FIND_FILE_END (CONTEXT) 2 END 3 SUB Process_one_more_file(fake_FAB FAB, STRING file_name) RECORD fake_FAB long START, FOP, STS, STV, ALQ END RECORD PRINT FAB::ALQ, file_name END SUB ================================================================================ Note 1900.5 help with file size 5 of 7 171 lines 5-SEP-1991 07:59 -< FILE_SIZE.C uses ACP $QIO interface >- -------------------------------------------------------------------------------- /* I have included a short main to show the use of this routine. It uses the ACP $QIO interface with an attributes block pointing to a statistics block to get the number of blocks allocated to a file... Stuart */ #include fibdef #include atrdef #include sbkdef #include iodef #include rms #include descrip unsigned int file_size(char *filename, unsigned int *filesize); main() { unsigned int status; char filename[] = "SYS$LOGIN:LOGIN.COM"; unsigned int filesize; if ( (status = file_size(filename,&filesize)) == 1) printf("File %s has %d blocks allocated\n",filename,filesize); else LIB$SIGNAL(status,0); } unsigned int file_size(char *filename, unsigned int *filesize) { struct FAB fab; /* File attributes block */ struct NAM nam; /* Name block */ struct fibdef fib; /* File information block */ struct FIB_DESC { int length; /* Length of file information block */ struct fibdef *fib; /* Address of file information block */ } fib_desc = { FIB$C_LENGTH, &fib }; struct sbkdef sbk; /* File statistics block */ struct atrdef atr[2] = /* File attributes block */ { {ATR$S_STATBLK, ATR$C_STATBLK, &sbk}, /* Statistics */ {0,0,0} /* End of atr */ }; char full_name[NAM$C_MAXRSS]; /* Full filename returned by RMS */ char nam_esa[NAM$C_MAXRSS]; /* Needed by search and parse */ $DESCRIPTOR(fullname_desc, full_name); /* Needed by $ASSIGN */ /* Used by $QIO system service... */ unsigned long iosb[2], status, function; unsigned short channel; /* Initialise the fab block */ fab = cc$rms_fab; fab.fab$l_nam = &nam; fab.fab$l_fop = FAB$M_NAM; fab.fab$l_fna = filename; fab.fab$b_fns = strlen(filename); /* Initialise the nam block */ nam = cc$rms_nam; nam.nam$l_rsa = &full_name; /* Full filename wanted at this address */ nam.nam$b_rss = NAM$C_MAXRSS; /* maximum size of full filename */ nam.nam$l_esa = &nam_esa; /* Expanded string address */ nam.nam$b_ess = NAM$C_MAXRSS; /* maximum size of expanded filename str */ /* Use RMS to find the file and fill in the NAM and FAB blocks */ if ( ((status=sys$parse(&fab,0,0)) & 1) == 1) status = sys$search(&fab,0,0); if ((status & 1) == 0) return status; /* Initialise the fib block */ memset(&fib,0,FIB$C_LENGTH); /* Copy the File ID from the nam block to the fib block */ memcpy( &fib.fib$r_fid_overlay.fib$w_fid , &nam.nam$w_fid[0], 6 ); /* Set the fib to allow file access even if the file is locked */ fib.fib$r_acctl_overlay.fib$l_acctl = FIB$M_NOLOCK; /* Fill in the length of the filename in the descriptor */ fullname_desc.dsc$w_length = nam.nam$b_rsl; /* Assign a channel to the file so it can be opened */ status = SYS$ASSIGN( &fullname_desc, /* Device Name */ &channel, /* Returned Channel number */ 0, /* Access Mode */ 0 /* Mailbox Name */ ); if ((status & 1) == 0) return status; /************************************************************************* * We must now issue an ACCESS QIO to open the file. We need to specify * * a file attributes block and a statistics block in order to obtain * * the allocation count for the file * *************************************************************************/ function = IO$_ACCESS | IO$M_ACCESS; status = SYS$QIOW( 0, /* Event Flag Number */ channel, /* I/O channel */ function, /* I/O function code */ iosb, /* I/O status block address */ 0, /* AST Address */ 0, /* AST Parameter */ &fib_desc, /* P1, fib descriptor */ 0, /* P2, not used */ 0, /* P3, not used */ 0, /* P4, not used */ atr, /* P5, Attributes block */ 0); /* P6, not used */ if ((status & 1) == 0) return status; if ((iosb[0] & 1) == 0) return iosb[0]; /* Get the file allocation from the statistics block */ *filesize = sbk.sbk$w_filesizl + (sbk.sbk$w_filesizh << 16); /* Now close the file again */ function = IO$_DEACCESS; status = SYS$QIOW( 0, /* Event Flag Number */ channel, /* I/O channel */ function, /* I/O function code */ iosb, /* I/O status block address */ 0, /* AST Address */ 0, /* AST Parameter */ &fib_desc, /* P1, fib descriptor */ 0, /* P2, not used */ 0, /* P3, not used */ 0, /* P4, not used */ 0, /* P5, Attributes block */ 0); /* P6, not used */ if ((status & 1) == 0) return status; if ((iosb[0] & 1) == 0) return iosb[0]; return 1; } alq.bas Content-Type: text/plain Content-Encoding: 7bit file_size.c Content-Type: text/plain Content-Encoding: 7bit