.TITLE TREEDEL - Correctly delete a directory tree .IDENT /1.00/ ;++ ; Title: ; TREEDEL - Correctly delete a directory tree ; ; Facility: ; General utility to delete a directory tree without ; creating lost files. ; ; Abstract: ; TREEDEL is a general utility for deleting files, particularly ; an entire directory tree. It is run as a foreign command and ; accepts one parameter: a file spec specifying the file(s) to be ; deleted. The filespec can contain wildcards. TREEDEL performs ; a standard wildcard scan and uses the $ERASE service to ; delete a file. To avoid the problem of deleting a non-empty ; directory, TREEDEL does not delete any directories when they ; are encountered during the scan. Rather it stacks the filespec ; information. The stack of directory files is only processed after ; the remainder of the wildcard scan has been completed. Note this ; scheme does not prevent you from explicitly deleting a non-empty ; directory. It only eliminates the problem as it occurs when ; deleting a tree. If file name, type, or version information is ; omitted, TREEDEL assumes "*". ; ; Environment: ; Native Mode. No other considerations. ; ; Author: ; Gary L. Grebus, Creation date: 09-Mar-1982 ; Battelle Columbus Labs ; ; Modified by: ; ;-- .PAGE .SBTTL Symbol definitions ; System symbols $NAMDEF ; NAM block symbols $STSDEF ; Status value fields ; Local symbols STACK_SIZE = 30000 ; Nr of bytes available for storing ; directory filespecs. .PAGE .SBTTL Read/write data .PSECT RWDATA RD,WRT,NOEXE,NOSHR,LONG ; Read/write data ; RMS control blocks DEL_FAB: $FAB DNM=<*.*;*>,- FOP=NAM,- FAC=GET,- NAM=DEL_NAM ; FAB used for searching for file DEL_NAM: $NAM ESA=DEL_ES,- ESS=NAM$C_MAXRSS,- RSA=DEL_RS,- RSS=NAM$C_MAXRSS ; NAM block used for searchin for file DEL_ES: .BLKB NAM$C_MAXRSS ; Expanded string buffer for wildcard ; processing DEL_RS: .BLKB NAM$C_MAXRSS ; Resultant string buffer for wildcard ; processing FILE_TO_DELETE: .BLKB NAM$C_MAXRSS ; Space for file spec to delete FILE_TO_DELETE_BD: .LONG NAM$C_MAXRSS .ADDRESS FILE_TO_DELETE ; Descriptor for above buffer FILE_TO_DELETE_DESC: .LONG 0 ; Descriptor for contents of above .ADDRESS FILE_TO_DELETE FILE_PROMPT: .ASCID /$_File: / ; Prompt to be issued if no parameter. RS_DESC: .LONG 0 ; Skeleton descriptor .ADDRESS DEL_RS ; for resultant file spec ; Stack used to hold identification of files for later deletion. STACK: .BLKB STACK_SIZE END_STACK: .PAGE .SBTTL TREEDEL - Main program .PSECT CODE RD,NOWRT,EXE,SHR,LONG .ENTRY TREEDEL,^M ; Register usage: ; R0-R5 - Scratch. ; R6 - Stack pointer of STACK. Address of next free byte in stack ; Get the command line so we know what to delete. CALL LIB$GET_FOREIGN - FILE_TO_DELETE_BD,- FILE_PROMPT,- FILE_TO_DELETE_DESC ; Get foreign command line IF THEN SIGNAL - CODE1=#TREE_CMDERR ; Signal an error RET ; and return with status. ENDIF $FAB_STORE - FAB=DEL_FAB,- FNA=FILE_TO_DELETE,- FNS=FILE_TO_DELETE_DESC ; Point the FAB at the file spec MOVAL STACK,R6 ; Initialize stack pointer $PARSE - FAB=DEL_FAB ; Try to parse the file spec IF THEN SIGNAL - CODE1=#TREE_PARSERR,- F1=,- CODE2=R0 ; Signal any error BISL2 #STS$M_INHIB_MSG,R0 ; Inhibit duplicate message RET ENDIF ; Loop processing any files which match the spec ENB_LONG ;; Enable long branches in macros REPEAT $SEARCH - FAB=DEL_FAB ; Search for next file BREAK IF ; Stop when last file processed IF THEN ; If a problem with this search, signal the error and stop MOVZBL DEL_NAM+NAM$B_RSL,- RS_DESC ; Finish descriptor to full file spec SIGNAL - CODE1=<#TREE_SEARCHERR>,- F1=,- CODE2=R0 ; Signal the error BISL2 #STS$M_INHIB_MSG,R0 ; Inhibit duplicate message RET ELSE ; The search was successful. Is this file a .DIR? MOVZBL DEL_NAM+NAM$B_RSL,R0 ; Get length of resultant string LOCC #^A/;/,- R0,DEL_RS ; Look for version number ";". ; R1 will point to it IF THEN ; File type is .DIR. Assume this is a directory and save it for later. BSBW PUSH_DIR ; Save filespec ELSE ; File is not a directory. $ERASE it. $ERASE - FAB=DEL_FAB ; Zappppppp! IF THEN MOVZBL DEL_NAM+NAM$B_RSL,- RS_DESC ; Store length in descriptor SIGNAL - CODE1=#TREE_ERASERR,- F1=,- CODE2=R0 ; Signal the error ENDIF ENDIF ENDIF UNTIL ; Loop if there are wildcards DSB_LONG ;; Disable long branch mode ; Done with wildcard scan. Now go back and process saved directory files. CLRL DEL_FAB+FAB$L_NAM ; Disconnect the NAM block since ; we are done with it. MOVAL DEL_RS,- DEL_FAB+FAB$L_FNA ; All filespecs will be placed into ; DEL_RS REPEAT BSBW POP_DIR ; Restore filespec into DEL_RS BREAK IF ; Done if no more saved context $ERASE - FAB=DEL_FAB ; Delete this file IF THEN MOVZBL DEL_FAB+FAB$B_FNS,- RS_DESC ; Put filespec length in descriptor SIGNAL - CODE1=#TREE_ERASERR,- F1=,- CODE2=R0 ; Signal the error ENDIF UNTIL ; Loop until done MOVZWL #SS$_NORMAL,R0 ; Return success RET .PAGE .SBTTL Directory STACK Routines ;++ ; Functional Description: ; These two routines are used to save and restore the filespec ; of a file as contained in the NAM block. The filespec is used to ; reaccess the file. The data is stored as a text string followed ; by a one byte length. R6 contains the stack pointer which is ; the address of the next free byte in the stack. ; The spec to store is taken from DEL_RS and its length from the ; DEL_NAM. The spec is restored into DEL_RS and its length is ; restored into DEL_FAB. ; If the stack overflows, an error message is generated ; and the stack is reset. This is done to prevent the previously ; stacked files from being deleted. Otherwise, when they were ; deleted, the files which could not be stacked would be lost. ; ; Calling Sequence: ; BSBW PUSH_DIR ; BSBW POP_DIR ; ; Input Parameters: NONE ; ; Output Parameters: NONE ; ; Implicit Inputs: ; DEL_NAM - NAM block ; DEL_RS - Resultant file spec ; STACK - Directory stack space ; R6 - Directory stack pointer ; ; Implicit Outputs: ; DEL_FAB ; ; Procedures called: NONE ; ; Completion Status: ; POP_DIR returns R0 as non-zero if a directory was successfully ; popped. ; ; Side Effects: NONE ; ;-- ; Register usage: ; R0 -R5 - Scratch. ; R6 - Address of next free byte on stack ; ; Save a directory file spec ; PUSH_DIR:: MOVZBL DEL_NAM+NAM$B_RSL,R0 ; Get length of file spec INCL R0 ; Plus one for byte count ADDL3 R0,R6,R1 ; Compute new stack pointer IF THEN ; If this entry overflows the stack MOVZBL DEL_NAM+NAM$B_RSL,- RS_DESC ; Fill in descriptor SIGNAL - CODE1=#TREE_STKOVFL,- ; Signal the error F1= MOVAL STACK,R6 ; Reset the stack ADDL3 R0,R6,R1 ; Compute new stack pointer ENDIF MOVL R6,R2 ; Get pointer to beginning of this ; stack allocation MOVL R1,R6 ; Update stack pointer to next entry MOVB R0,- -1(R2)[R0] ; Store the one byte length DECL R0 ; Get actual string length MOVC3 R0,DEL_RS,(R2) ; Store the string RSB ; ; Restore a directory file spec into the FAB ; POP_DIR:: IF THEN MOVZBL -1(R6),R0 ; Get byte count from entry SUBL2 R0,R6 ; Adjust stack pointer DECL R0 ; Compute length of file spec MOVB R0,DEL_FAB+FAB$B_FNS ; Store length in FAB MOVC3 R0,(R6),DEL_RS ; Move the file spec MOVZBL #1,R0 ; Return success ELSE CLRL R0 ; Stack empty ENDIF RSB .END TREEDEL