PAGE ,132 TITLE File Chain Program, Version 2.16, 24-Dec-1986 ; Bug Fix Version 2.17, 28 May 1989 by David Gwillim ; Subdirectories were reported as using 0 clusters with 100% waste ; Also corrected typo for pgm lines storing file size to SIZEMSB ; Changed/Added lines marked with a comment starting with ;!! ; ; Written By Steven Georgiades ; ; File Chain Program ; Will respond with a list of the disk clusters that make up the file chain ; for the requested file. ; ; If you are using this program and find it of value, your ; contribution in any amount ($5.00 suggested) will be greatly ; appreciated. Makes checks payable to Steven M. Georgiades. ; Thank you. ; ; If you have any questions or comments about this or any other ; SMG program, call or write: ; ; Steven M. Georgiades ; 701-H South Hayward Street ; Anaheim, CA 92804 ; (714) 826-9549 ; CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE ORG 5CH FCB LABEL BYTE ORG 80H PARAM LABEL BYTE ORG 100H CHAIN: JMP BEGIN CHAINMSG1 DB "The Chain for $" CHAINMSG2 DB " is:",13,10,10,"$" CHAINMSG3 DB 13,10,10 CHAINMSG4 DB "Total Clusters in File = XXXXX",13,10,10 CHAINMSG5 DB "Physical File Length = XXXXXXXX",13,10,"$" ;!! CHAINMSG6 DB "Logical File Length = XXXXXXXX (" PERCENT DB " 0.00% Waste)",13,10,"$" ISDIR DB 'File is a SUBDIRECTORY',13,10,"$" ;!! LOGSZMSG DW OFFSET CHAINMSG6 CLSTSTR DB "XXXXX$" PRCNT100 DB "100.0" ANDSTR DB " , $" THRUSTR DB " to$" SPECERR DB "Invalid File or Path Specification",7,": $" CRLF DB 13,10,"$" SIGNON DB "File Chain Program, Version 2.17",13,10 ;!! DB "SMG Software",13,10 DB "(C) Copyright 1986, 1989 Steven M. Georgiades" ;!! DB 13,10,13,10,"$" ;!! USAGE DB 13,10,"Usage:",13,10,13,10 ;!! DB " CHAIN [d:][path]filename[.ext]",13,10,13,10 ;!! DB " Will respond with a list of the disk clusters that make up the specified",13,10 DB " file. Note that wildcards are NOT allowed.",13,10,"$" CLSTSEC DW ? DIR_LEN DW ? DIRBUF DW ? DIRSEC DW ? DRIVE DB ? EOF DW 0FF8H FATSEC DW ? FATSIZE DB 3 FILENAME DB 13 DUP(0) PREV DW ? RANGE DB 0 SECSIZE DW ? SIZLSB DW ? SIZMSB DW ? STARTSEC DW ? FILESPEC DB "$",79 DUP(0) BEGIN: MOV AH,9 ; Output Sign-On Message MOV DX,OFFSET SIGNON INT 21H MOV AH,19H ; Get Default Drive INT 21H MOV DRIVE,AL ; and Save MOV SI,OFFSET PARAM ; Set up Pointer to Parameter LODSB ; Read Parameter Length CBW MOV BX,AX MOV BYTE PTR [SI][BX],0 ; Terminate Parameter String STRIP: LODSB ; Strip Off Leading Whitespace CMP AL,' ' JE STRIP CMP AL,9 JE STRIP OR AL,AL ; If End-of-Parameter, Error JNZ NO_ERR1 MOV DX,OFFSET USAGE JMP ERROUT NO_ERR1: DEC SI ; ReUse Last Character MOV DI,OFFSET FILESPEC ; Point to FileSpec Buffer CMP BYTE PTR [SI+1],':' ; If 2nd Character is Colon, JNE GET_PATH AND AL,0DFH SUB AL,'A' ; Get Drive Number MOV DRIVE,AL ADD SI,2 ; and Scan Past GET_PATH: MOV AL,DRIVE ; Get Drive Number ADD AL,'A' ; Convert to Drive Number STOSB ; in FileSpec MOV AL,':' ; Add Colon to FileSpec STOSB CMP BYTE PTR [SI],'\' ; If Next Character is not '\', JE COPYPATH MOV AL,'\' STOSB PUSH SI ; Get Current Path to FileSpec MOV SI,DI MOV AH,47H MOV DL,DRIVE INC DL INT 21H POP SI MOV AL,0 ; Find End-of-FileSpec MOV CX,64 REPNE SCASB JE NO_ERR2 JMP ERROR NO_ERR2: DEC DI CMP BYTE PTR [DI-1],'\' ; If Root DIR, Skip JE COPYPATH MOV AL,'\' ; End-of-FileSpec = '\' STOSB COPYPATH: LODSB ; Copy Rest of Parameter OR AL,AL ; to FileSpec JZ COPYDONE STOSB JMP SHORT COPYPATH COPYDONE: MOV AL,'$' ; Set End-of-FileSpec STOSB MOV DX,OFFSET FILESPEC ; Convert to Upper Case CALL UPPER MOV AL,DRIVE ; Read Boot Record MOV CX,1 MOV DX,0 MOV BX,OFFSET FATBUF INT 25H POPF MOV AX,FATBUF[11] ; Read Sector Size MOV SECSIZE,AX ; and Save MOV AL,BYTE PTR FATBUF[13] ; Read Sectors per Cluster XOR AH,AH MOV CLSTSEC,AX ; and Save MOV CX,FATBUF[14] ; Read # of Reserved Sectors MOV AL,BYTE PTR FATBUF[16] ; Read # of FAT's XOR AH,AH ; Convert to Word MOV BX,FATBUF[22] ; Read Sectors per FAT MOV FATSEC,BX MUL BX ; Calculate Total FAT Sectors ADD CX,AX ; Add to Reserved Sectors MOV AX,FATBUF[17] ; Read Number of DIR Entries MOV DIR_LEN,AX PUSH CX ; Calculate DIR Sectors MOV CL,5 SHL AX,CL POP CX MOV BX,SECSIZE XOR DX,DX DIV BX OR DX,DX ; Adjust for Partial Sector JZ NO_ADD INC AX NO_ADD: MOV DIRSEC,AX ; Save DIR Sectors ADD CX,AX ; Add DIR Sectors to Reserved MOV STARTSEC,CX ; Save in STARTSEC MOV AX,FATSEC ; Calculate FAT Buffer Size MOV BX,SECSIZE MUL BX MOV BX,AX LEA AX,FATBUF[BX] ; Get DIR Buffer Pointer MOV DIRBUF,AX MOV AX,FATBUF[19] ; Read Total Sectors on Media SUB AX,CX ; Calculate Total Data Clusters MOV BX,CLSTSEC XOR DX,DX DIV BX CMP AX,4079 ; If Necessary, Adjust FAT Size JLE FAT_OK MOV FATSIZE,4 MOV EOF,0FFF8H FAT_OK: MOV AL,DRIVE ; Read FAT MOV CX,FATSEC MOV DX,1 MOV BX,OFFSET FATBUF INT 25H POPF MOV AL,DRIVE ; Read Root Directory MOV CX,DIRSEC MOV DX,STARTSEC SUB DX,CX MOV BX,DIRBUF INT 25H POPF MOV SI,OFFSET FILESPEC[3] ; Point to First Element of Path NEXT_FLD: MOV DI,OFFSET FILENAME ; Point to FileName Buffer NEXTCHAR: LODSB ; Copy Path Element to FileName CMP AL,'\' ; until '\' or '$' JE GOT_DIR CMP AL,'$' JE GOT_FNM STOSB JMP SHORT NEXTCHAR GOT_DIR: MOV AL,0 ; If '\', Read Subdirectory STOSB CALL READDIR JNC NEXT_FLD ; If No Error, Get Next Dir JMP ERROR ; Else Flag Error GOT_FNM: MOV AL,0 ; If '$', STOSB CALL SRCHFILE ; Read File DIR Info JNC NO_ERR3 JMP ERROR ; If Error, Say So NO_ERR3: MOV AX,[BX+28] ; Read File Length MOV SIZLSB,AX MOV DX,[BX+30] MOV SIZMSB,DX ;!! was mov sizmsb,ax MOV DI,OFFSET CHAINMSG6[31] ; Convert to ASCII CALL DEC8OUT ; Strip Off Leading Zeroes CALL STRIP0 MOV AH,9 ; Output FileSpec Message MOV DX,OFFSET CHAINMSG1 INT 21H MOV AH,9 MOV DX,OFFSET FILESPEC INT 21H MOV AH,9 MOV DX,OFFSET CHAINMSG2 INT 21H MOV BX,[BX+26] ; Read Starting Cluster Number XOR CX,CX ; Cluster Count = 0 OR BX,BX ; If Start Cluster = 0, Done JZ LASTCLST MOV AX,BX ; Output First Cluster Number CALL OUT_CLST MOV PREV,BX ; Previous Cluster = First INC CX ; Cluster Count = 1 CALL NEXTCLST ; Get Next Cluster Number CMP BX,EOF ; If Last, Skip JNB LASTCLST CLSTLOOP: INC CX ; Increment Cluster Count MOV AX,PREV ; If Cluster is Previous + 1, INC AX CMP AX,BX JNE CLSTOUT MOV RANGE,-1 ; Set Range Flag JMP SHORT NEXTONE CLSTOUT: CMP RANGE,0 ; Else JE NORANGE ; If Range Flag is Set, MOV AH,9 ; Output " - " MOV DX,OFFSET THRUSTR INT 21H MOV AX,PREV ; Output Last Clstr in Range CALL OUT_CLST MOV RANGE,0 ; Reset Range Flag NORANGE: MOV AH,9 ; Output ", " MOV DX,OFFSET ANDSTR INT 21H MOV AX,BX ; Output Cluster Number CALL OUT_CLST NEXTONE: MOV PREV,BX ; Previous = Current CALL NEXTCLST ; Get Next Cluster Number CMP BX,EOF ; If Not EOF, Repeat JB CLSTLOOP CMP RANGE,0 ; If Range Flag is Set, JE LASTCLST MOV AH,2 ; Output " - " MOV DL,'-' INT 21H MOV AX,PREV ; Output Last Cluster of Range CALL OUT_CLST LASTCLST: MOV AX,SIZMSB ; If Size = 0, 100% Waste OR AX,SIZLSB JNZ NOT_ZERO JCXZ LC1 ;!! allow for