![]() |
![]() HP OpenVMS Systemsask the wizard |
![]() |
The Question is: I was wondering if you could tell me how I might program a "purge" program that will give the option to purge all files or give the options to purge a certain file and keep certain version numbers(for a VAX system.) The Answer is : Use of the existing PURGE command is the easiest approach, either directly, via lib$spawn, via C system, via DECnet task-to-task, via sys$sndjbc, or otherwise. API-level program implementations are possible using lib$find_file, lib$delete_file, and lib$find_file_end, or via RMS service calls such as sys$search and sys$erase/sys$remove, or via XQP (F11XQP, IO$_ACPCONTROL) calls (as described in the I/O User's Reference Manual). The following C example shows a directory tree-deletion operation using calls such as lib$find_file -- this example assumes that the getopt() call is available. -- /* ** COPYRIGHT (c) 1994-1999 BY ** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. ** ALL RIGHTS RESERVED. ** ** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE ** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER ** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY ** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY ** TRANSFERRED. ** ** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE ** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT ** CORPORATION. ** ** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS ** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. ** */ /* **++ ** Facility: ** ** DELETE_TREE ** ** Version: V1.0 ** ** Abstract: ** ** Deletes the specified directory tree. ** ** Author: ** Steve Hoffman ** ** Creation Date: 14-Mar-1994 ** ** Modification History: **-- */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <ssdef.h> #include <stsdef.h> #include <str$routines.h> #include <lib$routines.h> #include <descrip.h> #include <strdef.h> #include <starlet.h> #include <rms.h> #include <fiddef.h> #include <string.h> #include <unistd.h> typedef unsigned long int u_long; typedef unsigned short int u_short; typedef char u_char; typedef struct dsc$descriptor desc_t; /* ** ************************************************************************ ** common definitions ** ************************************************************************ */ typedef u_short fid_t[(FID$K_LENGTH/sizeof(u_short))]; typedef struct itemlist_s itemlist_t; struct itemlist_s { /* ** A standard VMS itemlist `il3' data structure... */ u_short itmlen; u_short itmcod; u_char *itmadr; u_short *itmrla; }; typedef struct hdr_s hdr_t; struct hdr_s { /* ** The common header; prefixes all heap-allocated internal ** data structures... Used by a couple of routines -- mostly ** in the area of memory management and corruption detection. */ u_short size; u_short type; void *core; }; typedef struct dir_s dir_t; struct dir_s { /* ** A standard VMS itemlist `il3' data structure... */ hdr_t hdr; dir_t *nextdir; u_short depth; char fna[NAM$C_MAXRSS+1]; u_long fnl; }; typedef struct core_s core_t; struct core_s { /* ** This is the core data structure for this application... */ hdr_t hdr; char fns; char fna[NAM$C_MAXRSS+1]; char dns; char dna[NAM$C_MAXRSS+1]; char esa[NAM$C_MAXRSS+1]; char rsa[NAM$C_MAXRSS+1]; desc_t userinput_d; struct { char *target_dirspec; u_long verbose; u_long quit; u_long confirm; u_long noconfirm; u_long errors; } options; u_short iosb[4]; u_long context; fid_t didx_old; dir_t *nextdir; struct FAB fab; struct NAM nam; struct RAB rab; }; /* ** ************************************************************************ ** The externals; used by and required for getopt(); ** ************************************************************************ */ extern char *optarg; extern int optind; extern int opterr; /* ** ************************************************************************ ** The function prototypes... ** ************************************************************************ */ u_long dt_parse_opt( core_t *, u_long, u_char ** ); u_long getopt( u_long, u_char **, u_char * ); u_long dt_file_scan( core_t * ); u_long dt_file_scan_ok( struct FAB * ); u_long dt_file_scan_ng( struct FAB * ); u_long dt_delete_confirm( desc_t *, struct FAB *, core_t * ); u_long dt_load_name( core_t *, char *, char * ); /* **++ ** FUNCTIONAL DESCRIPTION: ** ** parses the user-specified options via a getopt(). ** ** FORMAL PARAMETERS: ** ** {@subtags@} ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none ** ** DESIGN: ** ** This routine is highly UNIX-flavoured. This routine ** handles all argument parsing and processing. The key ** (and only) interface used by this routine to communicate ** with the rest of the program is the `options' substructure ** found within the core data structure. ** ** **-- */ u_long dt_parse_opt( core_t *core, u_long argc, u_char **argv ) { u_long retstat; u_long c; u_long asciw; u_char *validargs = (u_char *) "vcdf:"; u_long got_an_option = 0; while ((c = getopt( argc, argv, validargs )) != EOF) { got_an_option++; switch ( c ) { case 'f': /* ** Start processing at the specified file... */ asciw = strlen( (char *) optarg); if ( asciw <= NAM$C_MAXRSS ) { retstat = dt_load_name( core, optarg, 0 ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; } break; case 'd': /* ** Start processing at the specified default file... */ asciw = strlen( (char *) optarg); if ( asciw <= NAM$C_MAXRSS ) { retstat = dt_load_name( core, 0, optarg ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; } break; case 'v': /* ** The typical verbose (chatty) option... */ core->options.verbose++; break; case 'c': /* ** Confirm the deletion. */ core->options.confirm++; break; case '?': default: core->options.errors++; } } if ( !got_an_option ) core->options.errors++; if ( core->options.errors ) { fprintf (stderr, "RMS directory tree deletion utility.\n" ); fprintf (stderr, "Set up foreign command: dt :== $%s\n", argv[0]); fprintf (stderr, "usage: dt [-v] [-c] -f filespec [-d defspec]\n" ); fprintf (stderr, " -v\tverbose\n" ); fprintf (stderr, " -c\tconfirm\n" ); fprintf (stderr, " -f\tfile or directory tree to delete\n" ); fprintf (stderr, " -d\tdefault file specification\n" ); exit( SS$_NORMAL ); } return 1; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This initializes some fields in the core structure. ** ** FORMAL PARAMETERS: ** ** a pointer to the core structure. ** ** RETURN VALUE: ** ** SS$_NORMAL: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ dt_init( core_t *core ) { unsigned long int retstat; struct FAB *fab; struct NAM *nam; memset( core, 0, sizeof( core_t ) ); core->userinput_d.dsc$a_pointer = 0; core->userinput_d.dsc$w_length = 0; core->userinput_d.dsc$b_class = DSC$K_CLASS_D; core->userinput_d.dsc$b_dtype = DSC$K_DTYPE_T; core->dns = 0; core->dna[0] = 0; core->context = 0; core->nextdir = 0; memset( core->didx_old, 0, FID$K_LENGTH ); core->options.confirm = 0; core->options.errors = 0; fab = &core->fab; nam = &core->nam; core->fab = cc$rms_fab; core->nam = cc$rms_nam; fab->fab$l_fop = FAB$M_NAM; fab->fab$b_fac = 0; fab->fab$b_shr = 0; fab->fab$l_nam = nam; fab->fab$w_ifi = 0; fab->fab$l_fna = 0; fab->fab$b_fns = 0; fab->fab$l_dna = 0; fab->fab$b_dns = 0; fab->fab$l_ctx = (u_long) core; nam->nam$l_esa = core->esa; nam->nam$b_ess = NAM$C_MAXRSS; nam->nam$b_esl = 0; nam->nam$l_rsa = core->rsa; nam->nam$b_rss = NAM$C_MAXRSS; nam->nam$b_rsl = 0; return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This stuffs the directory specification or the default ** directory specification into the storage buffer. ** ** FORMAL PARAMETERS: ** ** the core, the file name, and the default file name. ** ** RETURN VALUE: ** ** SS$_NORMAL: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_load_name( core_t *core, char *filename, char *defname ) { unsigned long int retstat; struct FAB *fab; struct NAM *nam; fab = &core->fab; nam = &core->nam; if ( (int) filename ) { core->fns = strlen( filename ); strncpy( core->fna, filename, NAM$C_MAXRSS ); fab->fab$l_fna = core->fna; fab->fab$b_fns = core->fns; } if ( (int) defname ) { core->dns = strlen( defname ); strncpy( core->dna, defname, NAM$C_MAXRSS ); fab->fab$l_dna = core->dna; fab->fab$b_dns = strlen( defname ); } return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This scans for files, looking for the directories to be deleted. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_file_scan( core_t *core ) { u_long retstat; retstat = lib$file_scan( &core->fab, dt_file_scan_ok, dt_file_scan_ng, &core->context ); if ( retstat == RMS$_NMF ) retstat = SS$_NORMAL; if ( retstat == RMS$_DNF ) retstat = SS$_NORMAL; if ( retstat == RMS$_FNF ) retstat = SS$_NORMAL; if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This processes the specified file, and marks it for delete. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_file_scan_ok( struct FAB *fab ) { u_long retstat; char *wildcard = "*.*;*"; struct NAM *nam; core_t *core; fid_t fidx; dir_t *dir; u_long devdirsize; nam = fab->fab$l_nam; core = (core_t *) fab->fab$l_ctx; retstat = memcmp( &core->didx_old, nam->nam$w_did, FID$K_LENGTH ); if ( retstat ) { /* ** A new file. And the file is in a new directory file... */ dir = malloc( sizeof( dir_t )); dir->nextdir = core->nextdir; core->nextdir = dir; devdirsize = 0; memcpy( dir->fna + devdirsize, nam->nam$l_dev, nam->nam$b_dev ); devdirsize += nam->nam$b_dev; memcpy( dir->fna + devdirsize, nam->nam$l_dir, nam->nam$b_dir ); devdirsize += nam->nam$b_dir; memcpy( dir->fna + devdirsize, wildcard, strlen( wildcard )); devdirsize += strlen( wildcard ); dir->fnl = devdirsize; memcpy( &core->didx_old, nam->nam$w_did, FID$K_LENGTH ); } return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This processes the specified file. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_file_scan_ng( struct FAB *fab ) { u_long retstat; struct NAM *nam; nam = fab->fab$l_nam; printf("Unable to process %*.*s\n", nam->nam$b_rsl, nam->nam$b_rsl, nam->nam$l_rsa ); return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This scans for files, looking for the directories to be deleted. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_delete_confirm( desc_t *file_d, struct FAB *fab, core_t *core ) { u_long retstat; u_long delstat; u_short nyaq_len; char fao_b[NAM$C_MAXRSS]; desc_t fao_d; $DESCRIPTOR( file_prompt, "Delete !AS?" ); $DESCRIPTOR( vnodelete, "Not deleting !AS" ); $DESCRIPTOR( faclete, "Deleting !AS" ); $DESCRIPTOR( nyaq_prompt, "Delete? (Y/N/Q/A) " ); delstat = SS$_NORMAL; if ( core->options.quit ) { /* ** Skip any sort of delete. */ delstat = SS$_NODELETE; goto dt_delete_confirm_done; } if ( core->options.noconfirm ) { /* ** We were asked to confirm each deletion, then countermanded. */ delstat = SS$_NORMAL; goto dt_delete_confirm_done; } if ( core->options.confirm ) { /* ** Confirm each deletion. */ delstat = SS$_NODELETE; fao_d.dsc$a_pointer = fao_b; fao_d.dsc$w_length = NAM$C_MAXRSS; fao_d.dsc$b_class = DSC$K_CLASS_S; fao_d.dsc$b_dtype = DSC$K_DTYPE_T; retstat = sys$fao( &file_prompt, &fao_d.dsc$w_length, &fao_d, file_d ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) { core->options.quit++; delstat = SS$_NODELETE; goto dt_delete_confirm_done; } lib$put_output( &fao_d ); retstat = lib$get_input( &core->userinput_d, &nyaq_prompt, &nyaq_len ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) { core->options.quit++; delstat = SS$_NODELETE; goto dt_delete_confirm_done; } str$upcase( &core->userinput_d, &core->userinput_d ); /* ** What the user answer means... ** ** YES causes the file to be deleted. ** TRUE causes the file to be deleted. ** ALL causes all files to be deleted. ** QUIT quits; no more files are deleted. ** FALSE the current deletion is not performed. ** NO the current deletion is not performed. ** ** Any other answer from the user is treated as a FALSE or a NO. */ retstat = strncmp( core->userinput_d.dsc$a_pointer, "YES", nyaq_len ); if ( !retstat ) delstat = SS$_NORMAL; retstat = strncmp( core->userinput_d.dsc$a_pointer, "TRUE", nyaq_len ); if ( !retstat ) delstat = SS$_NORMAL; retstat = strncmp( core->userinput_d.dsc$a_pointer, "QUIT", nyaq_len ); if ( !retstat ) core->options.quit++; retstat = strncmp( core->userinput_d.dsc$a_pointer, "ALL", nyaq_len ); if ( !retstat ) delstat = core->options.noconfirm = SS$_NORMAL; goto dt_delete_confirm_done; } dt_delete_confirm_done: if ( core->options.verbose ) { fao_d.dsc$a_pointer = fao_b; fao_d.dsc$w_length = NAM$C_MAXRSS; fao_d.dsc$b_class = DSC$K_CLASS_S; fao_d.dsc$b_dtype = DSC$K_DTYPE_T; if ( $VMS_STATUS_SUCCESS( delstat ) ) retstat = sys$fao( &faclete, &fao_d.dsc$w_length, &fao_d, file_d ); else retstat = sys$fao( &vnodelete, &fao_d.dsc$w_length, &fao_d, file_d ); lib$put_output( &fao_d ); } return delstat; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This scans for files, looking for the directories to be deleted. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ u_long dt_delete_all( core_t *core ) { u_long retstat; dir_t *dir; dir_t *dir_old; desc_t dsc; dsc.dsc$b_dtype = DSC$K_DTYPE_T; dsc.dsc$b_class = DSC$K_CLASS_S; dir = core->nextdir; while ((int) dir ) { dsc.dsc$w_length = dir->fnl; dsc.dsc$a_pointer = dir->fna; retstat = lib$delete_file( &dsc, 0, 0, 0, 0, dt_delete_confirm, core, 0, 0 ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) break; dir_old = dir; dir = dir->nextdir; free( dir_old ); } return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This processes the specified file, and marks it for delete. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ dt_cleanup( core_t *core ) { u_long retstat; retstat = lib$file_scan_end( &core->fab, &core->context ); if ( !$VMS_STATUS_SUCCESS( retstat )) return retstat; return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** This is the mainline of the program. ** ** FORMAL PARAMETERS: ** ** the standard C main function arguments... ** ** RETURN VALUE: ** ** 1: happiness ** ** SIDE EFFECTS: ** ** none. ** ** DESIGN: ** **-- */ main( u_long argc, u_char **argv ) { u_long retstat; core_t core_buffer, *core; fid_t fid; core = &core_buffer; retstat = dt_init( core ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; retstat = dt_parse_opt( core, argc, argv ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; retstat = dt_file_scan( core ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; retstat = dt_delete_all( core ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; retstat = dt_cleanup( core ); if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat; return 1; }
|