****************************************************************** * * * CATALOG Command Hanlder * * * *----------------------------------------------------------------* * * * The CATALOG command displays the volume number and a list * * of file information. For each file on the disk, the following * * data are printed: lock/unlock symbol, file type code, file * * size in sectors and file name. Drive and slot parameters are * * optional with the CATALOG command. * * * * Execution pattern: * * The execution pattern is fairly straight forward. After * * loading the accumulator with the catalog opcode, the common * * file manager handler code (HNDLCMD1, $A2AA) is called to find * * a free DOS buffer and customize the FM parameter list. The * * file manager is then used to do the catalog function (FNCATLOG,* * $AD98). FNCATLOG first sets up the FM work area. A volume * * number of #$FF is stored in the work area to enable any volume * * to be cataloged. (When RWTS is eventually entered, this value * * is EORed with #$FF to simulate a complemented disk volume * * number of zero (#$FF EOR #$FF = 0). After RWTS reads the * * address checksum, it checks to see if the correct volume was * * read off the disk. If the complement of the volume number * * wanted is zero, or if it matches the number read off the disk, * * execution proceeds as if the correct volume was found.) * * After setting the complemented volume number, FNCATLOG * * reads in the VTOC (so it can get the link bytes to the first * * directory sector). Next, an index is set to allow up to 22 * * screen lines to be displayed before the screen is frozen. * * (This index is used in the CRCATLOG routine ($A2EF) to print a * * carriage return and check if a pause is required.) After * * CRCATLOG is called twice to print two carriage returns, the * * words "DISK VOLUME " are displayed. The bug-ridden PRVOLNMB * * routine ($AE42) is then called to print the volume number as a * * 3-digit decimal number (with leading zeroes if applicable). * * Next, the RDDIRECT routine is used to read in a directory * * sector. If no more directory sectors are available, the carry * * is set and the function handler is exited. A clear carry * * signals that a directory sector was successfully read in. The * * file information in the directory sector is subsequently * * displayed. * * Each directory sector can contain up to seven different * * file descriptions. An example of the data contained in a * * selected file description is shown below: * * FIL1TSTK DS 1 ;Track # of first T/S list for file 1 * * FIL1TSSC DS 1 ;Sector # of first T/S list for file 1 * * FIL1TYPE DS 1 ;File type code for file 1. ($00=Text, * * ;$01=Integer, $02=Applesoft, $04=Binary, * * ;$08=S-type, $10=Relocatable, $20=A-type, * * ;and $40=B-type.) If the hi bit is set, * * ;the files are considered to be locked. * * ;For example, $02 = unlocked Applesoft and * * ;$82 = locked Applesoft. * * FIL1NAME DS 30 ;Name of file 1. If a file name less than * * ;30 bytes is used, trailing spaces are * * ;are added to the name to fill the buffer. * * FIL1SIZE DS 2 ;Size of file 1 in terms of the number of * * ;sectors used. * * (If a file was deleted, the track # of the first T/S list sec * * was copied to the last char position of the name field. The * * original track # byte (FIL1TSK) was then overwritten with an * * #$FF.) * * After reading in a directory sector, the index to the * * file description entries is initialized. The track number of * * the file's first T/S list is then analyzed. If this byte is a * * zero, no more file descriptions are present in the directory * * sector and the catalog function is exited (BEQ TOFMXTOK). A * * negative value denotes that the description entry pertains to * * a deleted file. The "BMI NXDESCRP" instruction is then taken * * to skip the deleted file. A positive non-zero value means * * that the file information should be processed. * * After the type code is checked to determine if the file * * is locked (negative) or unlocked (positive), an asterisk * * (locked) or a space (unlocked) is printed. The lock bit (bit * * 7) is then dropped from the file type code and the remaining * * six bits are shifted until the carry is set. The number of * * shifts needed to set the carry is used to index the table of * * file type character symbols (FTYPETBL, $B3A7). After printing * * the type symbol and a trailing space, the file size (in * * sectors) is read from the description entry. PRVOLNMB ($AE42) * * is then used to print the size as a 3-digit decimal number * * (with leading zeroes if applicable). Because this routine * * does not process the high byte of the file size correctly, * * files greater than 255 sectors are expressed as 256 modular. * * Thus a file that is actually 256 bytes long will be displayed * * in the catalog as being "000" sectors in length. (Special * * note should be taken of files that appear to be "001" sectors * * long. Either these files are actually 257 sectors long (or * * some multiple thereof) or else they were written to the disk * * incorrectly. All valid files must be at least two sectors * * because each file requires at least one T/S list sector and * * one data sector. A file that is only one sector long was * * opened but never closed properly. Such files are useless and * * should be deleted from the disk.) * * A space and the file name are printed after the file size.* * Next the CRCATLOG ($AE2F) is again called to print a carriage * * return and test for a screen pause. Finally, the index into * * the current directory is kicked up by 35 bytes to point to the * * next potential entry in the directory sector. If the resulting* * index is 245 or greater, the carry is set. A set carry means * * that the index points beyond the end of the current directory. * * As a result, the "BCS RDDIRSEC" instruction is taken to read * * in the next directory sector. If there is enough space left * * on the directory sector for another file entry, the "BCC * * DESCRPTK" is executed to process the next potential file * * description. * * Because the catalog's command and function handlers are * * easy to relate to, almost everybody and his dog has taken a * * crack at customizing the catalog with certain enhancements or * * protection schemes. Most major Apple-orientated magazines * * have printed articles which explain how to patch a free-space- * * left-on-disk utility to the catalog or how to repair the bugs * * in the PRVOLNMB routine ($AE42). Many commercial programs put * * the real catalog on a different track and supply a phony * * catalog on track #$11 (dec 17). Other developers zap the * * file name fields of the description entries with names * * containing "illegal" characters. For instance, you can insert * * backspaces into a name in order to hide preceeding characters. * * You can even zap the name field with a return, ctrl-D and a * * DOS command to trick the catalog routine into doing some other * * function if a person gets past earlier defence techniques. * * Some developers are even silly (or paranoid) enough to zap the * * sector size bytes with enlarged values in the hope that you * * will think you're getting more bytes/buck. Some programs, * * such as the word processor I am presently using, make it a * * policy to always set the file size bytes to 0. * * Data files are often protected from user abuse by simply * * zapping the first byte of the file's description entry with an * * illegal track number that is negative but less than #$FF. * * (Obviously the driver routines must modify this code before * * and after each access.) The illegal track # prevents the file * * from being displayed on the catalog (via the BMI NXDESCRP" * * instruction at $ADD9). However because the byte is less than * * $FF, the corresponding file entry space is not considered to * * be available by the write subfunctions. (When a new file is * * being added to the disk, the first available space in a * * directory is used for the new file description. Only potential* * entry spaces that start with a $00 or a $FF are considered fair* * game.) * * Other "enchancements" that are commonly used include * * changing the "LDA #22" instruction at $ADA3 to set the screen * * line counter to a different value, modifying the lock symbol * * ("LDY "*", $AD2E), changing the file type character codes in * * the FTYPETBL table at $B3A7, changing the contents of the * * DSKVOLUM table at $B3AF to print something other than "DISK * * VOLUME ", NOPing out the "BMI NXDESCRP" instruction at $ADD9 * * to list both active and deleted files, or changing "BMI * * NXDESCRP" to "BPL NXDESCRP" to force the catalog to display * * deleted files only. * * Protection techniques that rely on modified file * * descriptions are easy to discover. If you suspect that the * * file description entries have been tampered with, simply * * catalog the disk and inspect the directory sector buffer. If * * the disk contains more than 7 files, only the last few entries * * will be listed in the buffer. However, whenever DOS performs * * a specific operation of a file, the description of the file is * * left in the directory sector buffer. Therefore, if the file * * of interest does not appear in the buffer when you do a * * catalog, simply lock, unlock or verify a file listed above or * * below the particular file of interest. You can then inspect * * the file description entry belonging to the file you are * * interested in. * * * ****************************************************************** * On entry - CUMLOPTN ($AA65) has been updated * to reflect any parsed option words. * - the validity of the options issued * with the command (and their numeric * values) have been checked. (Only * drive and slot parameters are optional.) * - the first byte of the primary file name * buffer (PRIMFNBF, $AA75) has been zeroed * out. (A56E) CMCATLG LDA #6 ;Catalog opcode. (A570) JSR HNDLCMD1 ;Call command handler to do the catalog. * Part of common file manager command handler code. (A2AA) HNDLCMD1 STA TEMPBYT ;Store catalog opcode in temporary location. LDA LENPRSD ;Get L-parameter from parsed table. BNE SAVLENFM ;Was a non-zero L-parm issued with cmd? LDA LENPRSD+1 BNE SAVLENFM LDA #1 ;Length was 0 so make it 1 instead. STA LENPRSD SAVLENFM LDA LENPRSD ;Put length in FM parameter list. STA RECLENFM LDA LENPRSD+1 STA RECLENFM+1 CLSLOCBF JSR CMDCLOSE ;Use close cmd to find a free DOS buffer. (A2C8) * NOTE: ONLY A MINOR PORTION OF THE CLOSE * COMMAND IS SHOWN BELOW because only part of * it is applicable to the catalog command. * When accessed from the catalog command, * the close command is actually only used to * find a free DOS buffer. (A2EA) CMDCLOSE LDA PRIMFNBF ;Get 1rst char from primary name buffer. CMP #" " ;Don't allow leading in name. (A2EF) BEQ CLOSEALL ;Leading = signal to close all files. ;(A close cmd was issued with no ;accompanying file name.) (A2F1) JSR GETBUFF ;Locate a DOS file buffer. * Attempt to locate highest numbered (lowest * in memory) free DOS name buffer. * * NOTE: Because a filename field is not * applicable to the catalog command, earlier * processing by DOS (at FNOTAPPL, $A0A0) has * stuck a $00 in the first byte of the primary * filename field buffer (PRIMFNBF, $AA75). * This insures that: * 1) Execution falls thru to the GETBUFF * routine. * 2) The GETBUFF routine never finds a DOS * filename buffer with a filename that * matches the "name" in the primary * filename buffer. Instead, the GETBUFF * routine is exited with A5L/H pointing to * the filename field of the highest numbered * (lowest in memory) free DOS buffer. If a * free buffer can't be found, A5L+1 is left * containing a default value of $00. (A764) GETBUFF LDA #0 ;Default hi-byte of pointer to 0 STA A5L+1 ;(ie. assume no free buff available). (A768) JSR GETFNBF1 ;Get ptr to 1rst name buffer in chain. * Point A3L/H at 1rst (ie. lowest numbered, * highest in memory) DOS filename buffer. * (Addr of this buf is kept in ADOSFNB1 * which occupies the 1rst two bytes of the * table of relocatable address constants.) (A792) GETFNBF1 LDA ADOSFNB1 ;First link to chain LDX ADOSFNB1+1 ;of DOS buffers. (A798) BNE SETNXPTR ;ALWAYS. (A7A4) SETNXPTR STX A3L+1 ;Put addr of 1rst STA A3L ;buffer in ptr. TXA ;(a)= hi-byte of adr. GETNXRTN RTS (A7A9) (A76B) JMP FNCHAR1 ;Get first byte of DOS name buffer. ------------ (A76E) GETFNLNK JSR GETNXBUF * Get addr of next filename buffer in chain * from chain pointers buffer offset 37 & 36 * bytes from 1rst char of present filename * buffer. (A79A) GETNXBUF LDY #37 ;Point at chain buf (A79C) LDA (A3L),Y ;Pick up addr of nxt ;filename buffer. (A79E) BEQ GETNXRTN ;If hi byte = 0 then ;link zeroed out. (A7A0) TAX ;Save hi-byte in (x). DEY ;Pick up low-byte. LDA (A3L),Y SETNXPTR STX A3L+1 ;Put adr of filename STA A3L ;buf in pointer. TXA ;Put hi-byte in (a). GETNXRTN RTS (A7A9) (A771) BEQ NOFNMTCH ;Link zeroed out, end of chain. FNCHAR1 JSR GETFNBY1 ;Get 1rst char of name from buf in chain. (A773) * Get 1rst char of name from current * filename buffer in DOS buffer chain. * (If first byte is $00, then buffer is * free. Otherwise, it is the 1rst char * in the name of the file which owns the * DOS buffer.) (A7AA) GETFNBY1 LDY #0 LDA (A3L),Y (A7AE) RTS (A776) BNE NXFNBUF ;Take branch if buffer wasn't free. LDA A3L ;Buffer was free, there4 put ptrs to free STA A5L ;buffer in A5L/H. LDA A3L+1 STA A5L+1 (A780) BNE GETFNLNK ;ALWAYS. (A782) NXFNBUF LDY #29 ;Buffer not free there4 compare name CMPFNCHR LDA (A3L),Y ;of owner with name of file in primary CMP PRIMFNBF,Y ;name buf. (Start with last char 1rst.) (A789) BNE GETFNLNK ;Char doesn't match, there4 look for another ;buffer that might have same name. (A78B) DEY ;That char matched, how bout rest of name? BPL CMPFNCHR ;30 chars in name (ie. 0 to 29). CLC ;Clr carry to signal match. (A78F) RTS ============ (A790) NOFNMTCH SEC ;Link zeroed out. ALWAYS TAKE THIS (A791) RTS ;ROUTE WITH CATALOG CMD. ============ (A2F4) EVENTXIT BCS CLOSERTS ;ALWAYS TAKE WITH CATALOG CMD. CLOSERTS RTS (A330) ============ (A2CB) LDA A5L+1 ;Hi byte of A5L/H pointer which points at the highest ;numbered (lowest in memory) free DOS name buffer (in chain). (A2CD) BNE SAVFNPTR ;Branch if found a free buffer. (A2CF) JMP NOBUFERR ;Go issue an out-of-buffers message. ------------ ;(See dis'mbly of errors.) (A2D2) SAVFNPTR STA A3L+1 ;Reset A3L/H to point at DOS buffer that we LDA A5L ;will use for file name field buffer (chain). STA A3L (A2D8) JSR CPYPFN * NOTE: THIS ROUTINE IS ACTUALLY SUPERFULOUS TO * THE CATALOG COMMAND because the first byte of * the primary name buf (PRIMFNBF, $AA75) was * previously zeroed out. (A743) CPYPFN LDY #29 ;30 bytes to copy (0 to 29). CPYPRIM LDA PRIMFNBF,Y ;Copy the name of the file wanted from STA (A3L),Y ;the primary filename buffer into the DEY ;filename field buffer (in DOS chain). BPL CPYRIM ;More chars to get. (A74D) RTS (A2DB) JSR BUFS2PRM * Get addresses of the various DOS buffers from the * chain buffer & put them in the FM parameter list. (A74E) BUFS2PRM LDY #30 ;Get addr of FM work buf, T/S list ADRINPRM LDA (A3L),Y ;buf, data sector buf & next DOS STA WRKBUFFM-30,Y ;filename buf from chain INY ;pointer buffer & put them in FM parm list. CPY #38 ;(P.S. Adr of next DOS file name buf is BNE ADRINPRM ;not used by DOS.) (A75A) RTS (A2DE) JSR CPY2PARM * Put volume, drive, & slot values plus the * address of the primary filename buffer * in the FM parameter list. (A71A) CPY2PARM LDA VOLPRSD ;From parsed table. STA VOLFM LDA DRVPRSD ;From parsed table. STA DRVFM LDA SLOTPRSD ;From parsed table. STA SLOTFM LDA ADRPFNBF ;Get the adr of the primary file STA FNAMBUFM ;name buf from the constants tbl LDA ADRPFNBF+1 ;and put it in the FM parm list. STA FNAMBUFM+1 LDA A3L ;Save adr of current DOS file name STA CURFNADR ;buf in table of DOS variables. LDA A3L+1 STA CURFNADR+1 (A742) RTS (A2E1) LDA TEMPBYT ;Get catalog opcode back from the temporary STA OPCODEFM ;buffer and put it in the FM parameter list. (A2E7) JMP FMDRIVER ------------- * Use the file manager driver * to do the CATALOG FUNCTION. (A6A8) FMDRIVER JSR FILEMGR ;Call the file manager to do the function. * File manager proper. (AB06) FILEMGR TSX ;Save stk pointer so can later rtn to caller of FM. STX STKSAV (AB0A) JSR RSTRFMWA * Copy FM work buf (in DOS chain) to * FM work area (not in DOS chain). (AE6A) RSTRFMWA JSR SELWKBUF ;Point A4L/H at FM work buf. * Get addr of FM work buff from * the FM parm list & put it in * the A4L/H pointer. (AF08) SELWKBUF LDX #0 ;Offset to select ;work buffer. (AF0A) BEQ PT2FMBUF ;ALWAYS. (AF12) PT2FMBUF LDA WRKBUFFM,X STA A4L LDA WRKBUFFM+1,X STA A4L+1 (AF1C) RTS (AE6D) LDY #0 ;Zero out return code in FM parm list to STY RTNCODFM ;signal no errors as default condition. STORFMWK LDA (A4L),Y ;Copy FM work buf to FM work area. STA FMWKAREA,Y INY CPY #45 ;45 bytes to copy (0 to 44). BNE STORFMWK CLC ;WHY????? (AE7D) RTS (AB0D) LDA OPCODEFM ;Check if opcode is legal. CMP #13 ;(Must be less than 13.) BCS TOERROP ;Opcode too large so got range error. ASL ;Double val of opcode & put it in (x) TAX ;so it indexes tables of adrs. LDA FMFUNCTB+1,X ;Stick adr of appropriate function PHA ;handler on stack (hi byte first). LDA FMFUNCTB,X PHA (AB1E) RTS ;DO STACK JUMP TO FUNCTION ENTRY POINT. . . (AD98) FNCATLOG . . (See dis'mbly of CATALOG function.) . . - initializes the FM work area (non chain) & then copies volume #, etc from the FM parameter list into the FM work area. (The vol # is set to 0 so any vol of disk can be cataloged.) - reads in the VTOC. - sets SCRNSRCH ($B39D) to allow 22 screen lines before pause & subsequent scrolling. - reads in all necessary directory secs - for @ non-deleted file description entry in @ directory sec, prints the following file information: locked or unlocked, file type code, file size in sectors & file name. . . (RTS) ============ TOERROP JMP RNGERROP ;Go handle range error. (AB1F) ------------ ;(See dis'mbly of errors.) * Return here after doing the CATALOG FUNCTION. * (Cause after @ function is done, use stack * to get back to the original caller.) (A6AB) AFTRFUNC BCC FMDRVRTN ;(c) = 0 = no errors. LDA RTNCODFM ;Get error code from FM parameter list. CMP #$5 ;End-of-data error? (A6B2) BEQ TOAPPTCH ;Yes - Encountered a zeroed-out T/S link or ;a zeroed-out data pair (trk/sec vals) ;listed in the T/S list. (Not applicable to ;the catalog function.) (A6B4) JMP OTHRERR ;No. See dis'mbly of errors. ------------ (A6C3) FMDRVRTN RTS (A573) LDA VOLFM ;Get volume # from FM parm list. STA VOLPRSD ;Put it in the parsed table. (A579) RTS ;Return to caller of the catalog command. ============ ;(Normally returns to AFTRCMD ($A17D) ;located in the command parsing and ;processing routines.)