Classic Computer Magazine Archive COMPUTE! ISSUE 59 / APRIL 1985 / PAGE 115

Commodore File Protector

John Dearinger

You won't have to worry about accidentally erasing important files off your disks with "Commodore File Protector." It lets you protect individual files or entire disks. The program works on any Commodore 64, VIC-20 with at least 3K RAM expansion, Plus/4, or 16 with a 1541 or 1541-compatible disk drive.


Have you ever scratched a program on a disk and then realized you just deleted the wrong one? Perhaps it was a mental error, or maybe you used a filename with a wild card (* or ?) and got rid of more than you bargained for.
    Some computers, such as Apple and Atari, allow you to lock and unlock disk files, offering some protection. Commodore computers, however, don't have any such commands. Neither does the Commodore 1541 disk drive. Yet, interestingly enough, the 1541 does have the routine built into its Disk Operating System (DOS). In fact, the disk drive actually uses the routine to check for a locked file during a write operation.
    Here's what happens. Whenever the 1541 starts to scratch a file, it first must find the file on the disk to make sure it exists. Once it is found, the disk drive knows several things about the file, because this information is stored with the filename in the directory on track 18. It knows the track and sector where the first block of the file is stored on the disk. It knows how long the file is and the file type (PRG, SEQ, etc.) by reading the byte stored in the first location of each file entry. The first byte normally is a number from 128 to 132 decimal. (See the charts on pages 56 and 57 of the 1541 User Guide.) Another DOS routine also checks this location to tell if a file is locked or not. If bit 6 is set, DOS knows the file is locked and won't modify it in any way. For example, if the 1541 finds the number 194 decimal instead of 130 decimal, it knows that a PRG file is locked.
    "Commodore File Protector" uses the direct access disk commands to lock the files on a disk so they cannot be deleted-until, of course, they've been unlocked.

Disk Command Menu
To make File Protector compatible with your computer, only one line must be added to the program listing. If you have a Commodore 64, add this line:

20 F1=4:F7=3:POKE53281,12:POKE53280,6

If you have a VIC-20, add this line:

20 F1=39:F7=63:NS=4:U$=LEFT$(U$,23)

If you have a Plus/4 or 16, add this line:

20 FORA=1TO8:KEYA,"":NEXT:KB=239:SF=1347:
   KL=198:F1=4:F7=3

    Once File Protector is running, you'll have several options on a menu. First, you can view a directory. This option is offered within several of the routines as well.
    You have the option to lock all the files on a disk at once. This will save you a great deal of typing and time when you first use the program on a disk.
    You can choose to lock or unlock one specific file at a time, in case you later want to scratch a file or modify a file and replace the old version.
    When a file is locked, a less-than sign appears to the right of the file type whenever you list the directory-whether you LOAD "$",8, use DOS 5.1, or choose option 1 on the File Protector menu.
    Scratching a file is another option on the menu, and the only one that allows wild cards (* or ?). All the other options require you to enter the exact filename. Some interesting possibilities arise from this. For example, by locking some files and not others, you could clear a disk of unwanted files with many different names (and save a lot of typing) just by specifying an asterisk (*) for a filename to delete.
    The last option on the File Protector menu allows you to lock or unlock the entire disk itself. It's best to use this command only on full or completed disks, though, because once the disk is locked, it cannot be written on again until it is unlocked. Locked files on a disk don't prevent the rest of the disk from being used.

Not Totally Foolproof
There are three normal ways to remove files from a disk:

1. Scratch the file
2. Clear the directory with OPEN15,8,15,"N0:flename"
3. Reformat the disk with OPEN15,8,15,"N0:filename, ID#"

    Files locked with Commodore File Protector will withstand number 1 but not numbers 2 and 3. A locked disk will withstand numbers 1 and 2 but not number 3.
    One final word of warning: I strongly recommend that you do not use this program on any commercial software. These programs often use parts of track 18 in their copy protection, and since File Protector alters that track, it may change something that shouldn't have been changed.

No More Sticky Tabs
The method for locking the entire disk is similar to that for locking a file. In track 18, sector 0, the Block Allocation Map (BAM) is stored. The first two locations (bytes 0 and 1) tell the 1541 where it can find the first directory block containing the first eight filenames on the disk. The third location (byte 2) denotes on which drive this particular disk was formatted. This location should contain the hexadecimal number $41 (65 decimal), which indicates 1541 and 4040 format. If it doesn't, the 1541 will assume that the disk was formatted on a different disk drive and will read the disk, but refuse to write on it.
    So, by writing a different number at this location, the disk can be effectively writeprotected. No more of those sticky little tabs that are always coming off anyway.
    The program also changes location 166 from a $41 (65 decimal) to a $42 (66 decimal). This has no effect on whether the disk is write protected or not, but is done only to visually indicate a locked disk. The directory header will read 0 "Diskname" ID 2B-note the 2B instead of the normal 2A.

Commodore File Protector
Please refer to "COMPUTE!'s Guide To Typing in Programs" before entering this listing.

5 PRINT"{CLR}":Q$=CHR$(13)        :rem 59
10 U$="{RVS}{40 SPACES}":KB=198:SF=653:KL
   =203:NS=12                    :rem 223
50 GOSUB1240:GOTO1080            :rem 232
60 PRINT#15,"U1";2;0;T;S:GOTO670 :rem 119
70 PRINT#15,"B-P 2 0":PRINT#15,"U2";2;0;T
   ;S:GOTO670                     :rem 90
80 T=PEEK(681):S=PEEK(682):RETURN  :rem 8
90 REM:::LOCK ALL FILES:::        :rem 30
100 PRINT"{CLR}"SPC(NS)"LOCK ALL FILES":P
    RINTU$:GOSUB660:T=18:S=1      :rem 75
110 P=2:GOSUB60                  :rem 113
120 GET#2,A$:Tl=ASC(A$+CHR$(0)):GET#2,A$:
    Sl=ASC(A$+CHR$(0))           :rem 196
130 FORI=0TO7:PRINT#15,"B-P";2;P+32*I
                                 :rem 133
140 GET#2,A$:A=ASC(A$+CHR$(0)):IFA=.THEN1
    70                           :rem 137
150 IFAAND64THEN170              :rem 106
160 PRINT#15,"B-P";2;P+32*I:PRINT#2,CHR$(
    AOR64);                      :rem 248
170 NEXT:GOSUB70:IFETHENRETURN    :rem 21
180 PRINT"TRACK"T"SECTOR"S"IS LOCKED":T=T
    1:S=SI:IFTTHEN110            :rem 168
190 GOSUB730:GOSUB740:RETURN      :rem 35
200 REM:::READ DIRECTORY:::      :rem 163
210 H$=CHR$(18):PRINT"{CLR}{RVS}HOLD [SHI
    FT] TO PAUSE{DOWN}            :rem 20
220 GOSUB660:PRINT#15,"M-R"CHR$(144)CHR$(
    7)CHR$(23)                   :rem 103
230 FORI=0T022:GET#15,A$:H$=H$+(A$+CHR$(0
    )):NEXT:PRINTH$"{BLK}":POKE140,1:T=18
    :S=1                          :rem 84
240 GOSUB60:SYS828:GOSUB80:IFPEEK(SF)THEN
    WAITSF,1,1                     :rem 8
250 IFTTHEN240                    :rem 63
260 PRINT#15,"M-R"CHR$(250)CHR$(2):GET#15
    ,LO$:PRINT#15,"M-R"CHR$(252)CHR$(2)
                                 :rem 224
270 GET#15,HI$:PRINTASC(LO$+CHR$(0))+256*
    ASC(HI$+CHR$(0))" BLOCKS FREE:rem 188
280 GOSUB730:GOSUB740:POKE140,0:RETURN
                                 :rem 125
290 REM:::INPUT NAME:::          :rem 140
300 PRINT"{DOWN}[F1] EXIT{13 SPACES}[F7]
    {SPACE}DIRECTORY             :rem 166
310 PRINT"{DOWN}FILENAME? "CU$;:POKEKB,0:
    F$=""                        :rem 100
320 KQ=PEEK(KL):GETA$:IFA$=""ANDKQ=64THEN
    320                          :rem 131
330 IFKQ=FIORKQ=F7THENPRINTCHR$(20):RETUR
    N                            :rem 246
340 IFA$=CHR$(20)ANDF$=""THEN320 :rem 254
350 IFA$=CHR$(13)ANDF$<>""THENPRINTCHR$(2
    0):RETURN                      :rem 4
360 IFA$=CHR$(13)ANDF$=""THEN320   :rem 2
370 IFA$=CHR$(20)THENPRINTCHR$(20)A$CU$;:
    F$=LEFT$(F$,LEN(F$)-1):GOTO320:rem 98
380 PRINTCHR$(20)A$CU$;:F$=F$+A$:GOTO320
                                  :rem 27
390 REM:::LOCK A FILE:::         :rem 102
400 PRINT"{CLR}";                 :rem 51
405 PRINTSPC(NS)"LOCK A FILE":PRINTU$
                                  :rem 12
410 GOSUB300:IFKQ=FITHENRETURN   :rem 208
420 IFKQ=F7THENGOSUB210:GOTO405  :rem 201
430 POKE679,1:GOSUB780:GOSUB660:T=18:S=1
                                 :rem 167
440 GOSUB60:SYS828:A=PEEK(252):IFATHEN470
                                 :rem 244
450 GOSUB80:IFTTHEN440           :rem 101
460 PRINT"{DOWN}{RED}FILE NOT FOUND{BLK}
    {DOWN}":GOTO410              :rem 206
470 IF(AAND64)THENPRINTF$:PRINT" IS ALREA
    DY LOCKED":GOSUB730:GOSUB740:GOTO510
                                  :rem 44
480 P=PEEK(255):GOSUB60:PRINT#15,"B-P";2;
    P:PRINT#2,CHR$(AOR64);       :rem 243
490 GOSUB70:IFETHEN400            :rem 85
500 GOSUB730:PRINTF$:PRINT"IS LOCKED":GOS
    UB740                        :rem 142
510 POKE679,0:GOTO400            :rem 206
520 REM:::UNLOCK A FILE:::         :rem 4
530 PRINT"{CLR}";                 :rem 55
535 PRINTSPC(NS)"UNLOCK A FILE":PRINTU$
                                 :rem 179
540 GOSUB300:IFKQ=FITHENRETURN   :rem 212
550 IFKQ=F7THENGOSUB210:GOTO535  :rem 209
560 POKE679,1:GOSUB780:GOSUB660:T=18:S=1
                                 :rem 171
570 GOSUB60:SYS828:A=PEEK(252):IFATHEN600
                                 :rem 243
580 GOSUB80:IFTTHEN570           :rem 109
590 PRINT"{DOWN}{RED}FILE NOT FOUND{BLK}
    {DOWN}":GOTO540              :rem 214
600 IF(AAND64)=.THENPRINTF$Q$"IS ALREADY
    {SPACE}UNLOCKED":GOSUB730:GOSUB740:GO
    T0640                        :rem 231
610 P=PEEK(255):GOSUB60:PRINT#15,"B-P";2;
    P:PRINT#2,CHR$(AAND135);      :rem 79
620 GOSUB70:IFETHEN530            :rem 84
630 GOSUB730:PRINTF$:PRINT"IS UNLOCKED":G
    OSUB740                       :rem 53
640 POKE679,0:GOTO530            :rem 214
650 REM:::OPEN FILE:::            :rem 45
660 CLOSE2:CLOSE15:OPEN15,8,15,"IO":OPEN2
    ,8,2,"#"                     :rem 254
670 INPUT#15,E,EM$,ET,ES         :rem 146
680 IFE=730RE=26THENGOSUB730:GOTO710
                                 :rem 248
690 IFETHENPRINT"{RED}{RVS}ERROR:":PRINTE
    ","EM$","ET","ES"{BLK}":GOSUB730:END
                                 :rem 225
700 RETURN                       :rem 119
710 IFE=73THENPRINT"DISK IS LOCKED":GOSUB
    740:RETURN                   :rem 251
720 PRINT"REMOVE WRITE PROTECT TAB":GOSUB
    740:RETURN                    :rem 42
730 CLOSE2:CLOSE15:RETURN        :rem 114
740 PRINT"{RVS}{DOWN}PRESS ANY KEY{DOWN}"
    :POKEKB,0                     :rem 80
750 KQ=PEEK(KL):GETA$:IFA$=""ANDKQ=64THEN
    750                          :rem 145
760 RETURN                       :rem 125
770 REM:::STORE NAME FOR ML:::    :rem 12
780 IFLEN(F$)<16THENF$=F$+CHR$(160):GOTO7
    80                           :rem 209
790 FORI=ITOLEN(F$):POKE683+I,ASC(MID$(F$
    ,I,1)):NEXT:POKE700,0:RETURN :rem 199
800 REM:::LOCK ENTIRE DISK:::    :rem 243
810 PRINT"{CLR}"SPC(NS)"LOCK ENTIRE DISK"
    :PRINTU$                     :rem 116
820 PRINT"{DOWN}INSERT DISK IN DRIVE
    {2 SPACES}[F1] TO ABORT":FORTD=1TO900
    :NEXT:GOSUB740                 :rem 8
830 IFKQ=FITHENRETURN            :rem 137
840 GOSUB660:T=18:S=0:GOSUB60:PRINT#15,"B
    -P 2 2"                      :rem 233
850 PRINT#2,CHR$(66);:PRINT#15,"B-P 2 166
    ":PRINT#2,CHR$(66);:GOSUB70:IFETHEN81
    0                             :rem 42
860 GOSUB730:GOSUB660:GOSUB730    :rem 98
870 PRINT"THE DISK IS NOW WRITE PROTECTED
    ":GOSUB740:RETURN            :rem 176
880 REM:::SCRATCH A FILE:::       :rem 73
890 PRINT"{CLR}";                 :rem 64
895 PRINTSPC(NS)"SCRATCH A FILE":PRINTU$
                                 :rem 248
900 GOSUB300:IFKQ=FITHENRETURN   :rem 212
910 IFKQ=F7THENGOSUB210:GOTO895  :rem 218
920 INPUT"{DOWN}ARE YOU SURE";A$:IFA$<>"Y
    "THEN890                      :rem 73
930 GOSUB660:PRINT#15,"S0:"+F$:INPUT#15,E
    ,EM$,ET,ES:IFE>lTHENGOSUB680:GOTO890
                                 :rem 215
940 GOSUB730:IFET=.THENPRINT"{RED}FILE IS
     LOCKED OR NOT ON DISK{BLK}":GOSUB740
    :GOTO890                      :rem 97
950 IFET>1THENPRINTET;EM$:GOSUB740:GOTO89
    0                            :rem 228
960 PRINTF$:PRINT"IS SCRATCHED":GOSUB740:
    GOTO890                       :rem 55
970 REM:::UNLOCK A DISK:::        :rem 24
980 PRINT"{CLR}"SPC(NS)" UNLOCK{2 SPACES)
    DISK":PRINTU$                 :rem 88
990 PRINT"{DOWN}INSERT DISK IN DRIVE
    {3 SPACES}[F1] TO ABORT":FORTD=1TO900
    :NEXT:GOSUB740                :rem 16
1000 IFKQ=FITHENRETURN           :rem 175
1010 GOSUB660:T=18:S=0:GOSUB60    :rem 44
1020 PRINT#15,"M-W",CHR$(1);CHR$(1);CHR$(
     1);CHR$(65);                :rem 135
1030 PRINT#15,"B-P 2 2":PRINT#2,CHR$(65),
     :PRINT#15,"B-P 2 166"       :rem 251
1040 PRINT#2,CHR$(65);:GOSUB70:IFETHEN980
                                 :rem 202
1050 GOSUB60:GOSUB730:PRINT"DISK IS UNLOC
     KED                           :rem 5
1060 GOSUB740:RETURN             :rem 252
1070 REM:::MAIN MENU:::           :rem 98
1080 PRINT"{CLR}{BLK}{DOWN}"SPC(NS-2)"<<F
     ILE PROTECTOR>>"             :rem 31
1090 PRINT"{DOWN} 1) DIRECTORY   :rem 153
1100 PRINT" 2) LOCK ALL FILES     :rem 65
1110 PRINT" 3) LOCK A FILE        :rem 88
1120 PRINT" 4) UNLOCK A FILE     :rem 253
1130 PRINT" 5) LOCK ENTIRE DISK  :rem 237
1140 PRINT" 6) UNLOCK A DISK      :rem 12
1150 PRINT" 7) SCRATCH A FILE     :rem 63
1160 PRINT" 8) QUIT               :rem 27
1170 PRINT"{2 DOWN} ENTER YOUR CHOICE"
                                  :rem 52
1180 GETA$:IFA$=""THEN1180       :rem 183
1190 C=VAL(A$):IFC<1ORC>8THEN1180:rem 176
1200 ONCGOSUB210,100,400,530,810,980,890,
     1220                         :rem 71
1210 GOTO1080                    :rem 198
1220 CLOSE2:CLOSE15:END          :rem 148
1230 REM:::VARIABLES & M/L:::    :rem 141
1240 POKE679,0:POKE140,0:CU$=CHR$(31)+CHR
     $(161)+CHR$(144)            :rem 102
1250 FORQZ=828TO1006:READZQ:POKEQZ,ZQ:NEX
     T:RETURN                     :rem 34
1260 DATA 169,0,141,168,2,133,253,162,2,3
     2,198,255,32                 :rem 46
1270 DATA 228,255,141,169,2,32,228,255,14
     1,170,2,230,253             :rem 192
1280 DATA 230,253,32,228,255,133,252,165,
     253,133,255,32,228           :rem 91
1290 DATA 255,32,228,255,230,253,230,253,
     160,0,32,228,255            :rem 241
1300 DATA 230,253,153,189,2,200,24,192,16
     ,144,242,160,243            :rem 230
1310 DATA 32,228,255,230,253,165,144,240,
     3,141,168,2,200             :rem 178
1320 DATA 208,241,165,252,208,7,173,168,2
     ,208,22,240,191             :rem 194
1330 DATA 165,140,240,3,32,199,3,173,167,
     2,240,3,32                  :rem 191
1340 DATA 175,3,173,168,2,240,171,32,204,
     255,96,160,0                 :rem 42
1350 DATA 185,172,2,240,8,217,189,2,208,7
     ,200,208,243                 :rem 47
1360 DATA 238,168,2,96,169,0,133,252
                                 :rem 245
1370 DATA 96,160,0,185,189,2,240,6,32,210
     ,255,200,208                 :rem 41
1380 DATA 245,165,252,41,64,240,10,169,14
     4,32,210,255,169,60,32,210,255,169
                                 :rem 111
1390 DATA 13,32,210,255,169,144,32,210,25
     5,96                        :rem 167