Measure: iso9660.py --compare for the extent sets and the path comparison;
tools/namespaces.py, written this session, for the derivation rule, the
collision analysis and the Level 1 conformance check. Every figure is over the
whole tree.
CLIC 02/97 had no Joliet descriptor, so --compare had nothing to compare and
the chapter that would have used it was never written. This disc has three
descriptors, and the answer is the other extreme:
python tools/iso9660.py Mico02CD.bin --compare
primary namespace : 1527 entries (1423 files, 104 dirs)
Joliet namespace : 1527 entries (1423 files, 104 dirs)
primary file bytes: 713496612
Joliet file bytes: 713496612 (delta 0)
extents in primary only : 0
extents in Joliet only : 0
extents in both : 1422
of which the two namespaces spell differently: 1422
... differing only by letter case : 779
... differing by more than case : 643
date bytes identical in both namespaces for every shared extent: True
Same files, same bytes, same dates, same extents. Every single path is spelled
differently. /CD_ROM/CREATIVI.HTM against /CD-ROM/creativita.htm;
/ABBONAME/MICO_ABB.PDF against /abbonamento/Mico_abbonamento.pdf.
Two namespaces that agree on everything except how to say it.
The 1,422 is a count of paths, and a path inherits its parent's spelling. At the level of the leaf name the picture is different, and the difference is worth having:
| how the primary name derives from the Joliet name | records | share |
|---|---|---|
| identical after uppercasing (exact) | 23 | 1.6163 % |
| differs by letter case only | 1,162 | 81.6585 % |
a character outside the d-characters mapped to _ (subst) |
7 | 0.4919 % |
| truncated to 8.3 | 145 | 10.1897 % |
| truncated plus a numeric disambiguator | 86 | 6.0436 % |
| unexplained | 0 | 0 % |
1,423 of 1,423 = 100.0000 %, explained by one mechanical rule with nothing left over.
So: 1,400 leaf names of 1,423 differ, and 23 are identical — files whose own
name already fitted 8.3 in upper case and whose path differs only because a
parent directory's does. /GIOCHI/OTHELLO/README.TXT is the same eleven
characters in both namespaces; only giochi and Othello moved.
ISO 9660 Level 1 (ECMA-119 §7.5, §7.6 and Annex A) allows d-characters A-Z,
0-9 and _; a file identifier of at most 8 characters, an optional . and at
most 3 more, then ; and a version; a directory identifier of at most 8
characters with no dot and no version.
What the standard does not say is what a writer should do with a name that
breaks those limits. That mapping is the writer's invention, and it is what
namespaces.py measures. Nero's rule, derived and then tested against all 1,423
records:
- upper-case the name;
- map every character outside
A-Z 0-9 _to_; - truncate the stem to 8 characters and the extension to 3;
- if that collides with a name already used in the same directory, overwrite trailing characters of the stem with digits.
creativita.htm → CREATIVI.HTM. Mico_abbonamento.pdf → MICO_ABB.PDF.
Archivio_off.gif → ARCHIVI2.GIF — where ARCHIVIO.GIF was already taken by
Archivio.gif, so the eighth character became a counter.
That last case is the whole of step 4 and there are 86 of them.
Truncate all 1,423 Joliet names to 8.3 with no disambiguator and count what collides, per directory:
| colliding groups | 29 |
| names inside those groups | 115 |
| names that owe their uniqueness to Joliet or to Nero's counter | 86 |
| primary names actually carrying a counter | 86 |
The two 86s are the same 86, which is the check: every name that would have collided got a counter, and no name that would not have collided got one.
The worst groups are all one product, and they are fonts and design sets:
| directory | truncates to | × |
|---|---|---|
/Creativita/PhotoClassic3/Gallery/Imports/ |
PRINTDES.SLD |
19 |
/Creativita/PhotoClassic3/Gallery/Data/ |
WORSTVEL.TTF |
16 |
/Creativita/PhotoClassic3/Gallery/Imports/ |
WEBDESIG.SLD |
12 |
/Creativita/PhotoClassic3/Gallery/Data/ |
CZARISTI.TTF |
6 |
/completi/OpenOffice/ |
OPENOFFI.CAB |
4 |
/Creativita/PhotoClassic3/Gallery/Data/ |
GOSMICKS.TTF |
4 |
/CD-ROM/Immagini/Interfaccia/ |
BOX_TEST.GIF |
4 |
/CD-ROM/ |
INDISPEN.HTM |
4 |
Worstveld Bold Condense Oblique.TTF, Worstveld Bold Condense.TTF,
Worstveld Bold Expand Oblique.TTF and thirteen more: sixteen weights of one
typeface family, all identical in their first eight characters. A typeface
family is exactly the thing 8.3 was worst at, and 2006 is nine years after
Windows 95 made that stop mattering — except on the primary descriptor of a CD,
where it still did.
openofficeorg1.cab through openofficeorg4.cab collide on OPENOFFI.CAB and
become OPENOFF1.CAB … OPENOFF4.CAB, so the counter and the original number
happen to agree. That is luck, not design.
python tools/namespaces.py Mico02CD.bin --dos
records violating Level 1 8.3: 0 of 1423
directory depth of records (path separators):
depth 1 4
depth 2 41
depth 3 834
depth 4 308
depth 5 199
depth 6 37
Zero violations. Every one of the 1,423 primary names is legal 8.3
upper-case with a ;1 version suffix, and the deepest record sits five levels
below the root where Level 1 permits eight. A machine running MS-DOS with
MSCDEX, in 2006, could mount this disc and open every file on it.
It would see a completely different disc. It would see CREATIVI.HTM and
CREATIV2.HTM and CREATIV3.HTM where a Windows machine sees creativita.htm,
creativita2.htm and creativita3.htm; it would see ARCHIVI2.GIF where the
HTML that references the image says Archivio_off.gif. So the files would all
open and the front end would not work at all: the shell's markup names its
images in Joliet spelling, and on the primary namespace those names do not
exist.
That is the practical content of "two namespaces that agree on nothing". The disc is fully readable in both. It is only usable in one.
Both namespaces extracted to separate directories:
python tools/iso9660.py Mico02CD.bin --extract _work/joliet --joliet
python tools/iso9660.py Mico02CD.bin --extract _work/primary
extracted 1423 files, 713496612 bytes, to _work/joliet
extracted 1423 files, 713496612 bytes, to _work/primary
Same count, same total, and — since every file in both trees is read from the same extent — the same bytes. Two directory trees with identical content and no name in common. Yesterday's session proved by extraction that five records became three files; here extraction proves the opposite, that 1,423 records become 1,423 files twice over, and the only thing that changes is what they are called.
--compare reports 1,422 shared extents and the tree reports 1,423 files. The
difference is one:
extent 346405
/UTILITY/REGSEEKE/HISTORY.TXT;1 0 bytes
/UTILITY/REGSEEKE/LANG.INI;1 80 bytes
history.txt is zero bytes long, and ISO 9660 gives a zero-length file an
extent anyway. Nero gave it the next sector it was about to use, which is the
one lang.ini occupies. Both namespaces do the same thing, so the pair is
symmetrical.
Yesterday's disc had two empty files pointing at LBA 136 and 137, two sectors that belonged to nobody. This one has an empty file pointing at a sector that belongs to somebody else. Same standard, same gap in it, two writers filling it two different ways — and this is the version where the arithmetic does not notice, because 1,422 distinct extents look exactly like 1,422 files unless you count the records too.