Classic Computer Magazine Archive COMPUTE! ISSUE 80 / JANUARY 1987 / PAGE 83

Unsplat
Ronald Cornell

Finding an asterisk (*) next to a file's entry in the disk directory is an unsettling experience for any Commodore computer user. The asterisk denotes an unclosed or splat file, which can corrupt other files or even an entire disk if ignored. This Commodore 64 utility allows you recover all the readable information from a splat file-a feat that's otherwise very difficult to perform.


Has this ever happened to you? You're listing a Commodore disk directory and notice an asterisk (*) next to the name of one of the files. A glance at the disk drive manual tells you that this is an unclosed file, commonly known as a splat file (after the asterisk's resemblance to a splat of ink or paint). Other people use the term poison file, referring to an unclosed file's nasty ability to corrupt other files on the same disk. The asterisk stands as a warning that something went wrong when you created or wrote to the file. A splat file confuses the disk's organization, so it's important not to write to any file on the disk until the unclosed file has been cleaned up. Even worse, the file is unreadable by normal means as long as it remains unclosed.
    What can you do about a splat file? According to the disk drive manual, one course is to validate the disk immediately. Validation prevents damage to other files on the disk, but at the cost of losing everything contained in the splat file itself. If you list the directory after validation, you'll notice that the splat file has completely disappeared. Unless you had a backup copy of that file, its contents are lost.

Help Is On The Way
"Unsplat" serves those occasions when you need to recover the information in a splat file. It's a machine language program whose only function is to let you restore a splat file (no machine language expertise is needed to use the program). Notice the use of the term you. Unsplat can't recover a file without some direction from you; only a human has the intelligence to recognize the end of the file. But it does make the recovery process as painless as possible.
    Type in and save Unsplat with the "MLX" machine language entry program listed elsewhere in this issue. Follow the MLX instructions carefully. When you run MLX, you'll be asked for the starting and ending addresses of the data you'll be entering. Here are the addresses you'll need to enter Unsplat:

Starting address:  0801
Ending address:    0C00

    Although it's written in machine language, Unsplat is designed to load and run just like an ordinary BASIC program. When you run Unsplat, it begins by asking you to indicate the type of the file you wish to recover. This is the type which appears when you list the disk directory. Enter an S, P, or U to indicate a sequential (SEQ), program (PRG), or user (USR) file, respectively. Unsplat doesn't work with relative (REL) files; that's not a serious limitation, since relative files are rarely corrupted.
    The second prompt asks you to enter the filename. If you omit the 0: in front of the filename, Unsplat adds it for you automatically.
    Once Unsplat knows the file type and filename, it asks whether you wish to autocycle through the file or examine each sector of the file individually. If you don't know the file's size, look at each file individually (no autocycling). In this mode, Unsplat displays the contents of each file sector in turn and proceeds to the next sector only when you indicate that it has not yet reached the end of the file.
    Autocycling is appropriate for large files which you believe to be mainly intact. When this option is selected, Unsplat reads automatically through a designated number of file sectors before asking you to look at an individual sector to determine whether it contains the file's end. Unsplat can autocycle through as many as 200 blocks (50715 bytes). Of course, to use this option you must have some idea of the file's length. The directory won't help, since it always shows zero blocks for a splat file. However, you may have some other means of guessing at the length (for instance, a file containing graphics bitmap data must be at least 8000 bytes long).
    It's usually best to be conservative when estimating the file's length for autocycling. The major characteristic of a splat file is that it lacks the end-of-file marker that normally tells the drive not to read any more sectors. If you order the drive to read sectors past this point, it may interpret garbage bytes as track and sector information and attempt to access a nonexistent track or sector. If the disk drive locks up during an autocycle, you have probably overshot the file's end. No harm is done, since Unsplat does not write to the disk. Simply turn the drive off and on; then repeat the operation using a smaller number of sectors.

Human Brain Required
Sooner or later, you'll need to examine the contents of a sector to determine whether or not it contains the last sector in the file. Since the file's normal pointer system has been confused, there's no rational way for a program to do this for you. It's up to you to locate the file's end as best as you can, based on the file's contents.
    Some files are easy to handle. In a word processing document which you created, look for the last sentence in the document. If the file contains a BASIC program, the task will be a bit more difficult, since BASIC keywords such as PRINT are compressed into one-byte tokens when you save the program to disk. However, characters in REM, DATA, and PRINT statements are stored exactly as they are typed in. Every BASIC program ends with a marker consisting of three zero bytes in a row. In Unsplat's display, this endof-program marker appears as three @ characters in a row (@@@).
    When you tell Unsplat that you've found the end, it asks whether you want to fine-tune the last file sector. In many cases, the final block will contain garbage beyond the spot where actual file data ends. Fine-tuning allows you to remove this garbage, one character at a time, until the last block holds only data from the original file. If you tell Unsplat to fine-tune, it displays the last two characters of the previous block and the first 254 characters of the final block. Just press N to remove a character from the end of the display. When the block looks right, press Y.
    After the final block has been identified (and fine-tuned if necessary), Unsplat directs you to insert a fresh disk and press RETURN. When you do so, the recovered file is written to disk. You can breathe a sigh of relief at last.
    In some cases, you simply won't be able to recover the entire file. Splat files are most commonly caused by failing to close a file properly. Under circumstances that create such a file, it's common for the drive to fail to write the final segment of data from its internal memory to the disk. Depending on what's happening at the time of the interruption, the drive buffer may contain anywhere from 1-255 characters. Thus, it's very common for the very last sector of the file to be incomplete. You can't recover data that was never put on the disk in the first place. In the most extreme case (for instance, if you lose power while saving a program), only a small part of the file may remain.
    Data can also disappear as a result of disk operations performed after the splat file comes into existence. Each sector of a normal disk file begins with a pointer that tells the drive where to find the next sector in the file. If you write to a splat file, or write to other files on the same disk, one or more of these pointers may be corrupted. Dire results can occur when the disk's pointer system gets confused. Instead of saving new data on an unused part of the disk, the drive may put it in a sector that already contains data, destroying what was previously there. In the worst case, several files can become crosslinked, garbling large amounts of data.

Unsplat

Please refer to the "MLX" article in this issue before entering the following program.

0801:0C 08 0A 00 9E 20 32 30 64
0809:36 32 00 00 00 A9 01 8D F6
0811:86 02 A9 D0 A0 0A 20 lE B2
0819:AB 20 49 08 20 C7 09 A5 88
0821:03 C9 30 F0 0F A9 0D 20 93
0829:D2 FF A9 3C A0 03 20 lE 0B
0831:AB 4C 43 08 20 33 09 20 13
0839:08 0A A9 02 20 C3 FF 20 55
0841:6A 0A A9 02 20 C3 FF 60 CE
0849:A9 F3 A0 0A 20 lE AB 20 D0
0851:B3 09 C9 50 F0 0B C9 53 56
0859:F0 07 C9 55 F0 03 4C 50 AE
0861:08 20 D2 FF 8D 6A 0B A9 AD
0869:09 A0 0B 20 lE AS A0 00 6A
0871:84 F9 20 B3 09 20 D2 FF EF
0879:C9 0D F0 16 C9 14 D0 09 7A
0881:A4 F9 F0 EE C6 F9 4C 73 99
0889:08 A4 F9 99 55 0B E6 F9 3E
0891:D0 E0 A4 F9 C0 10 90 04 El
0899:A0 10 84 F9 A2 00 BD 69 28
08A1:0B 99 55 0B C8 E8 E0 04 A8
08A9:D0 F4 C8 C8 84 F9 A9 00 64
0881:85 06 85 F7 85 F8 85 04 55
08B9:A9 17 A0 0B 20 lE AS 20 IA
08C1:B3 09 20 D2 FF C9 4E F0 D3
08C9:68 C9 59 F0 14 A9 14 20 4A
08D1:D2 FF 4C C0 08 A6 04 F0 B4
08D9:0F C6 04 20 D2 FF 4C E9 BE
08E1:08 A9 2B A0 0B 20 lE AS 90
08E9:20 B3 09 C9 14 F0 E6 C9 S0
08Fl:0D F0 14 C9 30 90 Fl C9 55
08F9:3A B0 ED 20 D2 FF A6 04 FA
0901:9D lE 02 E6 04 D0 El 20 5F
0909:D2 FF A9 00 A6 04 9D lE 58
0911:02 A5 7A 48 A5 7B 48 A9 B6
0919:1D 85 7A A9 02 85 7B 20 42
0921:83 AE 20 AA B1 84 F7 85 64
0929:FB E6 06 68 85 7B 68 85 29
0931:7A 60 A9 93 20 D2 FF A2 F5
0939:00 8A 9D 00 D8 E8 D0 FA A8
0941:A9 00 85 FB A9 0C 85 FC lE
0949:A9 6D A0 0B 20 lE AB A2 C3
0951:02 20 C6 FF A2 02 A0 00 A3
0959:86 04 84 05 20 E4 FF A4 C9
0961:05 91 FB 48 29 80 4A 85 C3
0969:03 68 29 3F 05 03 A6 04 B5
0971:9D 00 04 E6 05 E6 04 D0 DD
0979:E3 20 CC FF A5 05 18 65 F5
0981:FB 85 FB 90 02 E6 FC A5 C6
0989:06 F0 15 38 A5 F7 E9 01 E2
0991:85 F7 B0 02 C6 F8 A5 F7 F7
0999:D0 AE A5 FB D0 AA 85 06 46
09Al:A9 BA A0 0B 20 lE AB 20 E0
09A9:B3 09 20 D2 FF C9 59 D0 B3
09B1:97 60 A9 00 85 CC 20 E4 61
09B9:FF F0 FB A2 02 86 CD A6 lE
09Cl:CF D0 FC E6 CC 60 A9 02 3B
09C9:A8 A2 08 20 BA FF A2 53 4A
09Dl:A0 0B A5 F9 20 BD FF 20 63
09D9:C0 FF A0 00 A9 08 20 B4 C2
09El:FF A9 6F 20 96 FF 20 A5 E8
09E9:FF 85 03 20 A5 FF 20 A5 D2
09F1:FF 20 A5 FF C9 2C F0 06 A7
09F9:99 3C 03 C8 D0 F3 A9 00 7E
0A01:99 3C 03 20 AB FF 60 A9 1B
0A09:A9 A0 0B 20 lE AB 20 B3 11
0A11:09 20 D2 FF C9 59 F0 0D AE
0A19:C9 4E F0 4C A9 14 20 D2 39
0A21:FF 4C 0F 0A 60 C6 FC A0 83
0A29:00 84 05 C6 05 A0 00 A9 BF
0A31:20 99 00 04 C8 D0 F8 Bl 29
0A39:FB 48 29 80 4A 85 03 68 61
0A41:29 3F 05 03 99 00 04 C8 28
0A49:C4 05 D0 EB A9 8A A0 0B 9D
0A51:20 lE AB 20 B3 09 20 D2 49
0A59:FF C9 59 D0 CE 18 A5 FB 36
0A61:65 05 85 FB 90 02 E6 FC 31
0A69:60 A9 C8 A0 0B 20 lE AB FB
0A71:20 E4 FF C9 0D D0 F9 A4 AF
0A79:F9 88 A9 57 99 53 0B 20 A7
0A81:C7 09 A5 03 C9 30 D0 3F 90
0A89:A9 F0 A0 0B 20 lE AB 78 BC
0A91:A9 36 85 01 58 A2 02 20 3A
0A99:C9 FF A9 00 85 FD A9 0C 4B
0AA1:85 FE A0 00 Bl FD 20 D2 E4
0AA9:FF E6 FD D0 02 E6 FE A5 93
0AB1:FB C5 FD D0 ED A5 FC C5 C7
0AB9:FE D0 E7 20 CC FF 78 A9 81
0AC1:37 85 01 58 20 DB 09 A9 A4
0AC9:3C A0 03 20 1E AB 60 93 7A
0AD1:11 2A 55 4E 53 50 4C 41 3E
0AD9:54 2A 0D 11 12 49 4E 53 FA
0AE1:45 52 54 20 27 53 50 4C 2D
0AE9:41 54 27 20 44 49 53 4B D3
0AF1:20 00 0D 0D 46 49 4C 45 BD
0AF9:20 54 59 50 45 20 28 50 AE
0B01:2F 53 2F 55 29 3F 20 00 45
0B09:0D 0D 46 49 4C 45 20 4E 4C
0B11:41 4D 45 3F 20 00 0D 41 14
0B19:55 54 4F 2D 43 59 43 4C FD
0B21:45 20 28 59 2F 4E 29 3F C0
0B29:20 00 0D 0D 42 45 20 43 6C
0B31:41 52 45 46 55 4C 21 0D B4
0B39:48 4F 57 20 4D 41 4E 59 99
0B41:20 43 59 43 4C 45 53 20 D5
0B49:28 3C 3D 32 30 30 29 3F 21
0B51:20 00 30 3A 31 32 33 34 0E
0B59:35 36 37 38 39 30 31 32 21
0B61:33 34 35 36 37 38 39 30 65
0B69:2C 53 2C 4D 13 11 11 11 D4
0B71:11 11 11 11 11 52 45 41 25
0B79:44 49 4E 47 2E 2E 2E 20 E8
0B81:20 20 20 20 20 20 20 20 97
0B89:00 13 11 11 11 11 11 11 97
0B91:11 11 49 53 20 54 48 49 FE
0B99:53 20 54 48 45 20 45 4E F3
0BA1:44 3F 20 20 20 14 14 00 29
0BA9:13 11 11 11 11 11 11 11 C0
0BB1:11 46 49 4E 45 2D 54 55 CC
0BB9:4E 45 20 54 48 49 53 3F DE
0BC1:20 20 20 20 14 14 00 93 7A
0BC9:49 4E 53 45 52 54 20 44 3F
0BD1:45 53 54 49 4E 41 54 49 E7
0SD9:4F 4E 20 44 49 53 4B 0D AE
0BE1:50 52 45 53 53 20 52 45 97
0BE9:54 55 52 4E 0D 0D 00 57 A2
0BF1:52 49 54 49 4E 47 2E 2E BC
0BF9:2E 0D 00 00 00 00 00 00 6A