I am grateful for the help and advice of John Hall and Daniele Terdina in the explanation of the QLWA hard disc format.
A hard disc has the following physical layout :
Header | Group Map | Data |
The following is the header block structure for the first sector on a QDOS hard disc, or a QPC or QXL QXL.WIN file. To avoid confusion, I shall refer to it as a QLWA format hard disc.
Mnemonic | Offset | Size | Description |
---|---|---|---|
qwa.id | $0000 | 4 bytes | 'QLWA' - Identification bytes. |
qwa.pflg | $01 & 'QWA' | 4 bytes | QWA partition flag. (Any comments on what this means exactly?) |
qwa_name | $0004 | 22 bytes | up to 20 characters, space padded name. Word count first then bytes. |
qwa_spr0 | $001A | 2 bytes | spare - set to zero. |
qwa_rndm1 | $001C | word | format random number. |
qwa_uchk | $001E | word | update check2. |
qwa_intl | $0020 | word | interleave factor (0 = SCSI/QXL.WIN). |
qwa_sctg | $0022 | word | sectors per group. |
qwa_sctt | $0024 | word | sectors per track (0 = SCSI/QXL.WIN). |
qwa_trkc | $0026 | word | tracks per cylinder (number of heads) (0 = SCSI/QXL.WIN). |
qwa_cyld | $0028 | word | cylinders per drive. |
qwa_ngrp | $002A | word | number of groups. |
qwa_fgrp | $002C | word | number of free groups. |
qwa_sctm | $002E | word | sectors per map. |
qwa_nmap | $0030 | word | number of maps. |
qwa_free | $0032 | word | first free group. |
qwa_root | $0034 | word | root directory number. |
qwa_rlen | $0036 | long | root directory length. |
qwa_fcyl | $003A | word | first cylinder number (ST506 only = Miracle Hard Disc?). OR |
qwa_fsct | $003A | long | first sector for this partition (SCSI/QXL.WIN). |
qwa_park | $003E | word | park cylinder. |
qwa_gmap | $0040 | words | group map: each entry is one word and is number of next group or zero. |
Notes:
1. This is my own name for this field as, previously, it was undocumented and lumped in with the access counter just as the high word.
2. The update check is incremented by 1 every time a file is created, deleted etc. If you open a file in over mode and then close it again without doing anything, this number will increment, this is because you have (just) overwritten the file!
The following is an initial attempt at an analysis of my QPC win1_ hard disc file.
00000000 51 4c 57 41 00 04 57 49 4e 32 20 20 20 20 20 20 |QLWA..WIN2 | 00000010 20 20 20 20 20 20 20 20 20 20 00 00 ee 8c 00 ce | ......| 00000020 00 00 00 04 00 00 00 00 00 00 3c 00 08 71 00 3d |..........<..q.=| 00000030 00 01 33 8f 00 10 00 00 0a 00 00 00 00 00 00 00 |..3.............|
If we decode the above dump into something a bit more meaningful, we get the following.
Mnemonic | Offset | Value | Comments |
---|---|---|---|
qwa.id | $0000 | 'QLWA' | QDOS hard disc identifier |
qwa_name | $0004 | DC.W $0004, DC.B 'WIN2' | Disc label |
qwa_spr0 | $001A | DC.W $0000 | Spare |
qwa_rndm | $001C | DC.W $EE8C | format random number. |
qwa_uchk | $001E | DC.W $00CE | update check. |
qwa_intl | $0020 | DC.W $0000 | interleave factor. |
qwa_sctg | $0022 | DC.W $0004 | sectors per group. |
qwa_sctt | $0024 | DC.W $0000 | sectors per track. |
qwa_trkc | $0026 | DC.W $0000 | tracks per cylinder (number of heads). |
qwa_cyld | $0028 | DC.W $0000 | cylinders per drive. |
qwa_ngrp | $002A | DC.W $3C00 | number of groups. |
qwa_fgrp | $002C | DC.W $0871 | number of free groups. |
qwa_sctm | $002E | DC.W $003D | sectors per map. |
qwa_nmap | $0030 | DC.W $0001 | number of maps. |
qwa_free | $0032 | DC.W $338F | first free group. |
qwa_root | $0034 | DC.W $0010 | root directory number. |
qwa_rlen | $0036 | DC.L $00000A00 | root directory length. |
qwa_fsct | $003A | DC.L $00000000 | first sector for this partition. |
qwa_park | $003E | DC.W $0000 | park cylinder. |
A 'STAT' against Win1_ in QPC returns the following :
WIN2 QDOS 8644/61440 sectors
So the disc label for Win1_ is actually 'WIN2' for some reason - I suspect I may have copied it at some point in the past! The 61,440 total sectors works out as the number of groups from the first sector. The 8644 free sectors does not appear in the heading fields, but the number of free groups * sectors per group comes out at exactly 8644 when converted to decimal.
Update: ok, when I formatted the drive I created it as the second drive, hence the WIN2 name. Had it been the third drive, it would be called WIN3 and so on. At present, there isn't a way to name a drive at format time similar to a floppy format
From the above we can derive the following information :
Total Size in MB = ((qwa_ngrp * qwa_sctg) * 512) / 1,048,576
Free Space in MB = ((qwa_fgrp * qwa_sctg) * 512) / 1,048,576
Following on from the 'disc' header, we find the map at address $0040. The map is a series of words (16 bit) which define whether a 'group' is in use or free. When the drive is formatted initially, the words are all set to point to the next free group. This means that we have a linked list where group zero points at group one which points to group two and so on. The end of all the groups is a word of zero.
A 'group' as described above is a number of sectors, a sector being 512 bytes, as defined by the value in qwa_sctg - number of sectors per group. In the example I'm using, this is 4 giving me a group size of 4 * 512 or 2,048 bytes. This implies that the smallest files that physically exists on a disc of this kind are at least 2,048 bytes in size.
I presume here that the group size is defined by the maximum number of groups that we have in the map - limited to 65,536 by the word sized entries - and/or the size that we format the disc to. My example is a 30 MB file and has a group size of 2,048 bytes. With 65,536 groups allowed in total, this implies a maximum size of 128 MB.
Formatting a disc to 130 MB works - so obviously something is happening internally - and in this case, the group size is changed from 4 sectors, 2,048 bytes to 5 sectors or 2,560 bytes.
The smallest disc I have formatted is a 1 MB file, and it has a group size of 4 sectors as well, so it appears that 4 sectors is the minimum size of a file on a 'qlwa' formatted hard disc.
Qwa_ngrp defines the number of groups that physically exist on this medium. It is possible that there may be additional entries in the group map above this number, but these cannot be accessed within the QLWA disc itself.
There are not always 65,536 entries in the map - it can be smaller according to the size of the QLWA disc.
Given that only (!) 65536 map entries are allowed, this makes an upper limit on the size of a QXL file. This works out at 255.9 MB which gives an actual maximum size of 255 Mb which results in 8 sectors per group.
Each entry in the group has two purposes. The first is to determine where the data is located on disc and the second is to determine if there are any more groups of sectors containing data for this file.
The entry's index number is used to determine where on the disc the data starts :
index_number * qwa_sgrp * 512
The actual entry itself determines if more data exists for this file. If the word in the group map is zero, then the current entry is the last one for the file.
The following is the first few entries from my example group map :
00000040 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 |................| 00000050 00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 00 |................| 00000060 00 5c 01 4e 0b ff 00 00 06 93 04 58 08 50 08 e5 |.\.N.......X.P..| 00000070 09 93 00 00 00 00 00 00 09 f3 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 13 06 00 00 |................|
Starting at address $40, we see that the first entry (entry zero) has the word $0001 in it. So whichever file begins at entry zero on the map has a linked list of 'groups' that extends up to the zero word at address $5e. These groups of sectors belong to the map itself. The map is always the first group of entries in itself (recursive or what?) and the first real file after the map is always the root directory.
The data sectors contain the date that makes up user files plus the root directory and any sub-directories created by the user.
To find out where on the physical disc a file begins is actually quite simple :
sector number.
So that's the first bit, we have the first 'n' sectors of the file, where are the next 'n' sectors?
Where does the File Id come from in the first place? It comes from the directory entry for the file we are interested in. This is discussed below.
The root directory on QDOS floppy discs was always file zero. This allowed its place on the physical medium to be easily determined. With the QLWA format, this is not so easy. The map can take up more or less of the disc and the root directory cannot be found as simply the first file on disc, so we need to have a pointer to the beginning of the root directory in the disc header. This pointer is the qwa_root field and simply holds the file id, or group map index, for the root directory's first group of 'n' sectors.
Looking back at the header details above, we see that the root directory begins in block $10. To find where our first chunk of the root directory is located we use the following :
The First 'n' sectors of the root directory begins on disc at address $8000. Looking there in my hex dump shows the following :
00008000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00008010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00008020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00008030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Hmm, not much of interest there, but just after this we see the following:
00008040 00 00 12 80 00 ff 00 00 00 00 00 00 00 00 00 03 |................| 00008050 70 65 6b 00 00 00 00 00 00 00 00 00 00 00 00 00 |pek.............| 00008060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00008070 00 00 00 00 00 00 00 00 00 01 00 11 00 00 00 00 |................| 00008080 00 00 0d c0 00 ff 00 00 00 00 00 00 00 00 00 03 |................| 00008090 63 36 38 00 00 00 00 00 00 00 00 00 00 00 00 00 |c68.............| 000080a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000080b0 00 00 00 00 00 00 00 00 00 01 00 12 00 00 00 00 |................| 000080c0 00 00 07 c0 00 ff 00 00 00 00 00 00 00 00 00 06 |................| 000080d0 73 6f 75 72 63 65 00 00 00 00 00 00 00 00 00 00 |source..........| 000080e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000080f0 00 00 00 00 00 00 00 00 00 01 00 1d 00 00 00 00 |................| 00008100 00 00 01 80 00 ff 00 00 00 00 00 00 00 00 00 05 |................|
This looks much better. It appears that the root directory's own entry in itself, is all zeros. Then following on from that we have the actual entries of the other files and sub- directories in the normal 64 byte file header format.
So we have found the first chunk of the root directory but where are the rest of it, assuming more exists? The Group Map tells us this.
Our File Id was originally $10 and that told us where the first chunk of directory was on disc. Looking at the group map again we can see :
Block $10 is at offset $40 + ($10 * 2) or address $60.
Looking into our map at that address we see the word $005c - this is the file id of the second chunk of the root directory. We can calculate the start address of the second chunk of the directory in the same manner as above where we found where the beginning of the root directory was on disc :
This means that the second 2,048 bytes of the root directory should be at the above address. Looking at the file again, we see the following there :
0002e000 00 00 02 c0 00 ff 00 00 00 00 00 00 00 00 00 05 |................| 0002e010 71 6d 6f 6e 32 00 00 00 00 00 00 00 00 00 00 00 |qmon2...........| 0002e020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0002e030 00 00 00 00 00 00 00 00 00 01 00 5d 00 00 00 00 |...........]....| 0002e040 00 00 01 c0 00 ff 00 00 00 00 00 00 00 00 00 04 |................| 0002e050 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00 |test............| 0002e060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0002e070 00 00 00 00 00 00 00 00 00 01 00 5e 00 00 00 00 |...........^....| 0002e080 00 00 06 c0 00 ff 00 00 00 00 00 00 00 00 00 09 |................| 0002e090 7a 69 70 5f 66 69 6c 65 73 00 00 00 00 00 00 00 |zip_files.......|
And indeed, this is the second part of my root directory. Is there any more?
Back in the group map at offset $40 + (File Id * 2) and using this for our File Id of $5c for the root directory, we find an address of $f8. The word there points to the third group of 'n' sectors for this file. We look at the word in that location and find a word of zero. This means that there is no third chunk of root directory. We have read it all in two chunks of 2,048 bytes.
000000f0 00 00 00 00 00 00 2b aa 00 00 00 00 00 00 00 00 |......+.........| ^^^^^
Mnemonic | Offset | Size | Description |
---|---|---|---|
hdr_flen | $00 | long | File length1 |
hdr_accs | $04 | byte | access control byte |
hdr_type | $05 | byte | file type |
hdr_data | $06 | long | program dataspace |
hdr_xtra | $0a | long | extra info |
hdr_name | $0e | file name (up to 36 characters long) Word length2 then bytes of name. Space filled. |
|
hdr_date | $34 | long | update date |
hdr_vers | $38 | word | version number |
hdr_flid | $3a | word | File id |
hdr_bkup | $3c | long | backup date |
Notes
1. The hdr_flen field includes an extra 64 bytes for the copy of the directory header at the start of the file in storage. This is not shown when you wstat the drive. Also, I created a single byte file and the directory entry showed 66 bytes in size. wstat showed the file as only two bytes. This rounding to even is not consistent as I have a file with 107 bytes in it! (And no, there is not a linefeed at the end!)
2. If the length of the file name is zero, this is not a valid directory entry. It may be one for a file that has been deleted.
Sub-directories are exactly the same as the root directory. They have an entry in their parent directory which includes a file id number. This is used in exactly the same manner as for the root directory to find the location on disk.
As with the root directory, all sub-directories hold a blank entry (all zeros) as the very first one in the directory.
User files are identical to directories in as much as finding where they are on disc and so on, so the above calculations apply.
There is a 64 byte copy of the directory entry for the file, stored at the beginning of each file in the actual data sectors on disc. Application programs do not see these 64 bytes. The following example shows this dummy 64 bytes.
This is the beginning of my boot file on my QPC hard disc :
1000 TK2_EXT 1005 WTV 4 1010 PROG_USE 'win1_' 1015 DATA_USE 'win1_' 1020 : 1025 REMark LRESPR 'qpac2_ptr_gen' 1030 REMark LRESPR 'qpac2_wman' 1035 REMark LRESPR 'qpac2_hot_rext' 1040 LRESPR 'qpac2_qpac2' 1045 LRESPR 'qmenu_menu_rext' 1050 LRESPR 'source_djtk_DJToolkit_bin' 1052 LRESPR 'turbo415_turbo_tk_code'
The directory entry for this file is as follows, I have highlighted the File Id in the directory entry.
0002e0c0 00 00 04 6b 00 00 00 00 00 00 00 00 00 00 00 04 |...k............| 0002e0d0 62 6f 6f 74 00 00 00 00 00 00 00 00 00 00 00 00 |boot............| 0002e0e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0002e0f0 00 00 00 00 4e 4e a6 e6 00 01 00 60 57 c5 9f 16 |....NN.....`W...| ^^^^^
Using the calculations to locate the start of the file on the sectors of the disc, we have :
File Id = $60 Sectors In Group = $04 Sector Size = $200 So, $60 * $04 * $200 = $30000
Looking at the disc file at that location, we see the following :
00030000 65 78 74 20 3d 3d 20 6c 69 66 6f 6e 6f 64 65 29 |ext == lifonode)| 00030010 0a 20 20 20 20 20 20 20 20 7b 0a 20 20 20 20 20 |. {. | 00030020 20 20 20 20 20 20 20 62 72 65 61 6b 3b 0a 20 20 | break;. | 00030030 20 20 20 20 20 20 7d 0a 20 20 20 20 7d 0a 20 20 | }. }. |
The 4 rows above make up the dummy 64 byte file header. It looks like a load of garbage to me and is probably left over from whatever file was using this sector in the past, before my boot file was created. Following on from the above, we see this :
00030040 31 30 30 30 20 54 4b 32 5f 45 58 54 0a 31 30 30 |1000 TK2_EXT.100| 00030050 35 20 57 54 56 20 34 0a 31 30 31 30 20 50 52 4f |5 WTV 4.1010 PRO| 00030060 47 5f 55 53 45 20 27 77 69 6e 31 5f 27 0a 31 30 |G_USE 'win1_'.10| 00030070 31 35 20 44 41 54 41 5f 55 53 45 20 27 77 69 6e |15 DATA_USE 'win| 00030080 31 5f 27 0a 31 30 32 30 20 3a 0a 31 30 32 35 20 |1_'.1020 :.1025 | 00030090 52 45 4d 61 72 6b 20 4c 52 45 53 50 52 20 27 71 |REMark LRESPR 'q| 000300a0 70 61 63 32 5f 70 74 72 5f 67 65 6e 27 0a 31 30 |pac2_ptr_gen'.10| 000300b0 33 30 20 52 45 4d 61 72 6b 20 4c 52 45 53 50 52 |30 REMark LRESPR| 000300c0 20 27 71 70 61 63 32 5f 77 6d 61 6e 27 0a 31 30 | 'qpac2_wman'.10| 000300d0 33 35 20 52 45 4d 61 72 6b 20 4c 52 45 53 50 52 |35 REMark LRESPR| 000300e0 20 27 71 70 61 63 32 5f 68 6f 74 5f 72 65 78 74 | 'qpac2_hot_rext| 000300f0 27 0a 31 30 34 30 20 4c 52 45 53 50 52 20 27 71 |'.1040 LRESPR 'q| 00030100 70 61 63 32 5f 71 70 61 63 32 27 0a 31 30 34 35 |pac2_qpac2'.1045| 00030110 20 4c 52 45 53 50 52 20 27 71 6d 65 6e 75 5f 6d | LRESPR 'qmenu_m| 00030120 65 6e 75 5f 72 65 78 74 27 0a 31 30 35 30 20 4c |enu_rext'.1050 L| 00030130 52 45 53 50 52 20 27 73 6f 75 72 63 65 5f 64 6a |RESPR 'source_dj| 00030140 74 6b 5f 44 4a 54 6f 6f 6c 6b 69 74 5f 62 69 6e |tk_DJToolkit_bin| 00030150 27 0a 31 30 35 32 20 4c 52 45 53 50 52 20 27 74 |'.1052 LRESPR 't| 00030160 75 72 62 6f 34 31 35 5f 74 75 72 62 6f 5f 74 6b |urbo415_turbo_tk| 00030170 5f 63 6f 64 65 27 0a 31 30 35 35 20 3a 0a 31 30 |_code'.1055 :.10|
We can see from the above that the first 64 bytes of each file are total garbage. The so called copy of the directory header is not reliable in the slightest and cannot be used for any purpose what-so-ever by applications running on QDOSMSQ. However, applications running on Linux, Windows or Macs might be able to make use of these additional 64 bytes, if they really needed to.
Creating a directory is easy. The length of the directory is always 64 bytes.
Normally you are not allowed to delete a directory unless it is empty. However, if you are deleting an empty directory, the process is exactly as described below for deleting a file.
I suppose if we wanted to delete a directory that was full, we should do something like the following :
Procedure DeleteDirectoryTree(FileId, FileType) # Entry is with a FileId & FileType representing the root or the directory tree we wish to delete. If FileType is not a directory then return End If For each entry in FileId's contents Find the FileId and FileType for the (next) entry in the directory If FileType is not a directory then DeleteFile(FileId) Else DeleteDirectoryTree(FileId, FileType) End If End For Return End.
Creating a file is easy too.
The process to delete a file is quite simple, assuming the FileId you are attempting to delete belongs to a file and not to a directory. If it is a directory, you'll have to go recursive and delete all the files in the directory first. I leave that as an exercise for the reader! . Normally, however, you are not permitted to delete a directory that has any contents, so a recursive delete might not be needed.
Assuming that the FileId is indeed for a file, we can delete it as follows :
So given this situation for a file called Win1_testfile :
FileId | $0003 |
FileLength | $0000507C bytes |
FileNameLength | $0008 |
FirstFreeGroup | $0009 |
Map Entries for FileId $0003 | $0004,$0005,$0006,$0007,$0008,$0000 |
FreeList Map Entries (start at group $0009) | $000A,$000B,$000C,…. |
FreeGroupsInMap | $03FD |
UpdateCounter | $085E0002 |
Deleting the file with Id 3 frees up the space on the disc corresponding to the linked list of Map Entries from entry 3 through to entry 8 - the file is a 'big' one of 6 groups of 4 (in this example) sectors. After the deletion, the situation is this :
FileId | $0003 |
FileLength | $00000000 bytes |
FileNameLength | $0000 |
FirstFreeGroup | $0003 |
FreeList Map Entries (start at group $0003 now) | $0004,$0005,$0006,$0007,$0008,$0009,$000A,$000B,$000C,…. |
FreeGroupsInMap | $0403 |
UpdateCounter | $085E0003 |
So the 6 groups of sectors that used to make up FileId 3 are now tagged onto the front of the free list and the header of the disc has been updated to reflect an additional 6 groups of free space. The update counter has been incremented as well.
It appears then that an undelete utility for QLWA format discs would not be of very much use as the space used by the file just deleted will be the first space used when any file is created or extended. Basically, if you delete a file, you need to undelete it almost immediately and certainly before updating or creating any files - including directories!
The before and after directory entries are as follows :
00001040 : 00 00 50 7C 00 00 00 00 00 00 00 00 00 00 00 08 [..P|............] 00001050 : 54 45 53 54 46 49 4C 45 00 00 00 00 00 00 00 00 [TESTFILE........] 00001060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] 00001070 : 00 00 00 00 59 19 7E 15 00 01 00 03 00 00 00 00 [....Y.~.........]
00001040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] ^^^^^^^^^^^ ^^^^^ 00001050 : 54 45 53 54 46 49 4C 45 00 00 00 00 00 00 00 00 [TESTFILE........] 00001060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] 00001070 : 00 00 00 00 59 19 7E 15 00 01 00 03 00 00 00 00 [....Y.~.........]
Formatting a QXL.WIN file as a new hard disc is quite a simple process. From a few tests of various sizes of hard disc, I have determined the following process. Each and every sector group in the formatted disc has an entry in the map.
On a 32 bit system, the maximum size of a single disc file is limited to 4 Gb which is 4,096 Mb. A qxl.win file of this size, would use a group size of 128 sectors or 64 Kb.
Formatting a file, for use as WIN2, to 30Mb would create a header as follows :
Mnemonic | Offset | Value | Comments |
---|---|---|---|
qwa.id | $0000 | 'QLWA' | Identifier. |
qwa_name | $0004 | DC.W $0004, DC.B 'WIN2' | Disc name. |
qwa_spr0 | $001A | DC.W $0000 | Spare. |
qwa_uchk | $001C | DC.L $xxxx0001 | Update check. The high word is set to the value in the SV_RAND system variable. |
qwa_intl | $0020 | DC.W $0000 | Interleave factor. |
qwa_sctg | $0022 | DC.W $0004 | Sectors per group. |
qwa_sctt | $0024 | DC.W $0000 | Sectors per track. |
qwa_trkc | $0026 | DC.W $0000 | Tracks per cylinder (number of heads). |
qwa_cyld | $0028 | DC.W $0000 | Cylinders per drive. |
qwa_ngrp | $002A | DC.W $3C00 | Number of groups. |
qwa_fgrp | $002C | DC.W $3bf0 | Number of free groups. (qwa_ngrp - qwa_root). |
qwa_sctm | $002E | DC.W $003D | Sectors per map. |
qwa_nmap | $0030 | DC.W $0001 | Number of maps. |
qwa_free | $0032 | DC.W $0011 | First free group. (qwa_root + 1). |
qwa_root | $0034 | DC.W $0010 | Root directory number. (qwa_sctm / qwa_sctg) + 1. |
qwa_rlen | $0036 | DC.L $00000040 | Root directory length. |
qwa_fsct | $003A | DC.L $00000000 | First sector for this partition. |
qwa_park | $003E | DC.W $0000 | Park cylinder. |
The header takes up the first $0040 bytes of the first sector of the qxl.win disc.
Following the header is the map. The map starts with the groups required for the map itself. In a 30Mb file, as calculated above, the map requires $003D sectors (from qwa_sctm) which means 15 groups of qwa_sctg (4) sectors. Then we have the zero word (indicated below) for the first, and only, sector group for the root directory.
00000040 : 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 [................] 00000050 : 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 00 [................] ^^^^^
Following the entries for the map itself and the root directory, every other entry in the map is a free group.
00000060 : 00 11 00 12 00 13 00 14 00 15 00 16 00 17 00 18 [................] ... 00007830 : 3B F9 3B FA 3B FB 3B FC 3B FD 3B FE 3B FF 00 00 [................]
The remainder of the file is simply filled with CHR$(0).
The table below shows a list of all the group sizes (in sectors) and the maximum size of a qxl.win file with that group size.
Group Size | Disc size (Mb) -----------|--------------- | 4 | 128 | | 5 | 160 | | 6 | 192 | | 7 | 224 | | 8 | 256 |