home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
assemblr
/
04
/
undel.asm
< prev
next >
Wrap
Assembly Source File
|
1986-02-05
|
12KB
|
248 lines
COMMENT*--------------------------------------------------------
This program will undelete files. To use, type UNDEL FILE.EXT or
UNDEL DRIVE:FILE.EXT where DRIVE is A or B. For ASCII files use UNDEL/A
FILE.EXT or UNDEL/A DRIVE:FILE.EXT; this prints out what is in each
cluster before it adds it to the file and asks (Y/N) if it's correct.
Only for use with DOS 2.0 and 2.10 double sided disks.
---------------------------------------------------------------*
FCB_LOC EQU 5CH ;Location of FCB for deleted file in the PSP
SWITCH_LOC EQU 81H ;Location of text typed after 'UNDEL'
BIG_A EQU 412FH ;Test chars for /A
SMALL_A EQU 612FH ;Test chars for /a
CR EQU 13 ;ASCII carriage return
LF EQU 10 ;ASCII line feed
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG,DS:CODE_SEG,ES:CODE_SEG
ORG 100H ;To make this a .com file
ENTRY: JMP FIRST ;Skip over data area
COPY_RIGHT DB '(C) 1984 S HOLZNER'
I_O_FLAG DW ? ;Selects read or write of cluster
START_CLUSTER DW ? ;Beginning cluster of deleted file
FILE_SIZE DW ? ;File size in clusters (1 cluster=2 sectors)
DISK_DRIVE DB 0 ;Drive of deleted file
NOT_FOUND_MSG DB 13,'File not found deleted$' ;Messages
WRITTEN_OVER_MSG DB 13,'File already written over$'
IS_IT_MSG DB 13,10,'Is part of your file here? (Y/N) $'
DATA DB 1024 DUP(0) ;Space for disk directory and FAT
PROMPT_SECTOR DB 512 DUP(0) ;/A option uses for parts of file
FIRST: ;Start the process
UNDEL PROC NEAR
MOV AL,CS:FCB_LOC ;Get the drive specified - 0 if none given
SUB AL,1 ;Was it a 1 (A:) or 2 (B:)?
JNC DRIVE_KNOWN ;Yes, store drive number
MOV AH,19H ;No, get default drive from INT 21H
INT 21H
DRIVE_KNOWN:
MOV DISK_DRIVE,AL ;Store drive
MOV DX,3 ;Start to search dir, starts at sector 5
LOOP: ADD DX,2 ;Add two to point at correct dir cluster
CMP DX,11 ;Past end of directory?
JB READ_DIR ;If not, read dir into data area
MOV AH,9 ;Past end of dir & no match, exit with error
LEA DX,NOT_FOUND_MSG
INT 21H
JMP OUT ;Exit
READ_DIR:
AND I_O_FLAG,0 ;Select read
CALL CLUSTER_I_O ;Get two sectors into data area
LEA DI,DATA ;Prepare to search for deleted entry
MOV AL,0E5H ;DOS set first char of deleted entry to E5H
MOV CX,400H ;Counter=1024 to search this entire dir cluster
SEARCH: ;Look-for-next-deleted-entry loop
REPNE SCASB
JCXZ LOOP ;If no match (Counter=0), get next dir cluster
MOV SI,FCB_LOC+2 ;Possible match, point to 2nd char of file name
MOV BX,11 ;Compare all chars in name
CMPLOOP:DEC BX ;Decrement the name comparison loop counter
CMPS [DI],[SI] ;Compare dir entry and deleted file name
JZ CMPLOOP ;If match, check next char
CMP BX,0 ;Compare done, all chars matched perfectly?
JNZ SEARCH ;No, keep checking through this dir cluster
MOV AX,CS:FCB_LOC+1 ;Yes, get file's first letter
MOV [DI-12],AX ;Move it into deleted entry (replace E5H)
OR I_O_FLAG,1 ;Select a write of 1 cluster
CALL CLUSTER_I_O ;Write directory with undeleted name to disk
MOV AX,[DI+14] ;Get starting cluster to use in FAT
MOV START_CLUSTER,AX ;Store it
MOV AX,[DI+16] ;Get low word of file size (in bytes)
TEST AX,1023 ;Find # of clusters - is MOD(size,1024)=0?
JZ EVEN_K ;Yes, don't add 1 cluster before SHR
ADD AX,1024 ;No, need another cluster
EVEN_K: MOV CL,10 ;Divide by 1024 (=cluster size)
SHR AX,CL
MOV DX,[DI+18] ;High word of file size
MOV CL,6 ;Multiply by 2^16=65536, divide by 2^10=1024
SHL DX,CL
ADD AX,DX ;Add high word clusters to low word clusters
MOV FILE_SIZE,AX ;And store in FILE_SIZE
MOV DX,1 ;Read in File Allocation Table (FAT)
AND I_O_FLAG,0 ;Select a read of 1 cluster
CALL CLUSTER_I_O
MOV CX,FILE_SIZE ;Counter to loop over # of clusters
MOV AX,START_CLUSTER ;Check if written over already
DEC AX ;Move back one cluster from beginning of file
CALL GET_NEXT_ZERO ;Is next empty space in FAT the START_CLUSTER?
CMP DX,START_CLUSTER
JE FILL ;Yes, OK to start filling FAT
MOV AH,13H ;No, file written over
MOV DX,FCB_LOC ;Delete restored dir entry; point to file name
INT 21H ;And delete it
MOV AH,9 ;Exit with error
LEA DX,WRITTEN_OVER_MSG
INT 21H
JMP OUT ;So long
FILL: MOV AX,DX ;Set old empty space in FAT to one just found
MOV DX,0FFFH ;Assume this is last entry (FFFH=End of file)
CMP CX,1 ;Is it the last entry? (CX=cluster counter)
JZ LAST ;Yes, don't need to find next empty entry (zero)
CALL GET_NEXT_ZERO ;Call with AX=old zero, returns DX=new zero
LAST: CALL PUT_FAT_ENTRY ;Call with AX=old zero, DX=new zero, changes FAT
LOOP FILL ;Work on next cluster
MOV DX,1 ;Prepare to write new FAT, 1st copy
OR I_O_FLAG,1 ;Select to write 1 cluster
CALL CLUSTER_I_O ;Write the cluster
MOV DX,3 ;Prepare to write new FAT, 2nd copy
CALL CLUSTER_I_O
OUT: INT 20H ;And leave
UNDEL ENDP
CLUSTER_I_O PROC NEAR ;Reads specified cluster (dir, FAT etc.)
COMMENT* Put start sector in DX, loads Cluster into 'DATA' area*
PUSH AX ;Save the used registers
PUSH BX ;INT 25H destroys all reg.s
PUSH CX
PUSH DX
PUSH DI
MOV AL,DISK_DRIVE ;Get disk drive
MOV CX,2 ;Request 2 sectors (1 cluster) to be read
LEA BX,DATA ;Point to DATA area
TEST I_O_FLAG,1
JNZ WRITE
INT 25H ;Read sector interrupt
JMP POPOUT
WRITE: INT 26H
POPOUT: POPF ;Pop the extra push of flags
POP DI ;Pop used (destroyed) registers
POP DX
POP CX
POP BX
POP AX
RET ;Return
CLUSTER_I_O ENDP
GET_NEXT_ZERO PROC NEAR ;Unravel FAT and find next empty space in it
COMMENT* FAT entry number (cluster #) in AX, returns next zero in DX*
PUSH AX ;Push used reg.s
PUSH BX
PUSH CX
CHECK_NEXT: ;Entry by entry loop
INC AX ;AX is entry pointer, start with next entry
MOV BX,AX ;Get 3/2*AX for actual offset into FAT
SHL BX,1 ; (Since each entry is 1.5 bytes)
ADD BX,AX
SHR BX,1 ;BX has FAT offset value for entry # in AX
MOV DX,WORD PTR DATA[BX] ;DX now has FAT entry's value
TEST AX,1 ;Is the entry # even?
JZ EVEN_ENTRY ;Yes, use bottom 12 bits
MOV CL,4 ;No, use top 12 bits
SHR DX,CL
EVEN_ENTRY:
AND DX,0FFFH ;Get bottom 12 bits (OK now for even or odd)
CMP DX,0 ;Is the value for the given cluster # 0?
JNE CHECK_NEXT ;No, look for next cluster
MOV DX,AX ;Move entry value of zero into AX
CMP AX,START_CLUSTER ;If this is the 1st one, skip /A option
JE POPS
MOV BX,SWITCH_LOC ;Was /A specified? Check data area in PSP
MOV CX,[BX]
CMP CX,SMALL_A ;Check for /a
JE A_OPTION ;Yes, do /A
CMP CX,BIG_A ;No, maybe a /A?
JNE POPS ;No, leave.
A_OPTION: ;/A was specified
CALL PRINT_OUT ;Print out prompt sector
JCXZ CHECK_NEXT ;If CX set to 0, sector wasn't right
POPS: POP CX ;The pops before going
POP BX
POP AX
RET
GET_NEXT_ZERO ENDP
PRINT_OUT PROC NEAR ;Print out a prompt sector
COMMENT* Returns CX=1 if found the right sector, 0 otherwise *
PUSH DX ;Push used reg
ADD DX,DX ;Get 2*DX for sector number
ADD DX,8 ;Add 8 to skip boot, FATs and dir
MOV AL,DISK_DRIVE ;Get disk drive
MOV CX,1 ;Ask for only 1 sector
LEA BX,PROMPT_SECTOR ;Load into PROMPT_SECTOR area
INT 25H ;Read the sector
POPF ;Pop extra flags put on by INT 25H
MOV AH,2 ;Prepare to print
MOV DL,CR ;Send a carriage return
INT 21H
MOV DL,LF ;Send a line feed
INT 21H
MOV BX,0 ;Initialize char printout counter
PRINT_LOOP: ;Like it says
MOV DL,PROMPT_SECTOR[BX] ;Get char from read-in cluster
INT 21H ;Print char
INC BX ;Go on to next char
CMP BX,160 ;Done 160 Chars yet?
JBE PRINT_LOOP ;No; go back for more
MOV AH,9 ;Yes, print Prompt message
LEA DX,IS_IT_MSG
INT 21H
MOV AH,1 ;Get a char from keyboard
INT 21H
MOV CX,1 ;Assume found right sector (always optimistic)
CMP AL,'Y' ;Was typed char a 'Y'?
JE FOUND ;Yes, found right sector exit with CX still=0
CMP AL,'y' ;No; was it a 'y'?
JE FOUND ;Yes, leave with CX still = 0
MOV CX,0 ;Not found, exit with CX=1
FOUND: POP DX ;Pop destroyed DX reg
RET
PRINT_OUT ENDP
PUT_FAT_ENTRY PROC NEAR ;Writes new FAT entry into FAT in DATA area
COMMENT* Pass FAT cluster number in AX and new entry in DX*
PUSH AX ;The requisite Pushes
PUSH BX
PUSH CX
PUSH DX
MOV BX,AX ;Get offset into FAT, 3*AX/2
SHL BX,1 ;Multiply by 2
ADD BX,AX ;Add AX to get 3*AX
SHR BX,1 ;Divide by 2 -- BX has FAT offset value
TEST AX,1 ;Do we have an even entry number?
JZ P_EVEN_ENTRY ;Yes, use bottom 12 bits
MOV CL,4 ;No, use top 12 bits
SHL DX,CL
P_EVEN_ENTRY:
OR WORD PTR DATA[BX],DX ;Put Cluster # into FAT
POP DX ;Do the Pops
POP CX
POP BX
POP AX
RET ;Return and you're done
PUT_FAT_ENTRY ENDP
CODE_SEG ENDS
END ENTRY ;This sets the starting address to ENTRY