disk.csv (c) 2009 ub880d */ // file types in sense of having header/body or not.. $headbody = array ("--","H-", "-B", "HB"); // open disk $fp = fopen("disk","rb"); // print csv header print "disk;dir;loc;headbody;type;name;start;len;vars;altaddr;altlen;date;time\n"; $dnum = 0; while (!feof($fp)) { // drive (image) number are '1' based $dnum++; // free memory .. not really needed, but without this script will use more than 4MB of memory for a while and it is not necessary ;] if (isset($disk)) unset($disk); // read image if there is less than 2MB to read, finish (maybe it won't work over network.. but who cares? ;]) $disk = fread($fp, 2*1024*1024); if (strlen($disk)<2*1024*1024) break; // mb02 format checks.. this is only simple check, maybe we could check also diskette ID if (ord($disk[3]) != 2 || ord($disk[32]) != 0 || ord($disk[37]) != 0) continue; // geometry values.. we don't need them for our csv, but we will check them $trcks = ord($disk[4]) + 256*ord($disk[5]); $sects = ord($disk[6]) + 256*ord($disk[7]); $sides = ord($disk[8]) + 256*ord($disk[9]); $clust = ord($disk[10]) + 256*ord($disk[11]); // check also some reasonable values for geometry if ($sides>2 || $sects>16 || $trcks>255) continue; // this is directory map sector $dirmap = ord($disk[12]) + 256*ord($disk[13]); // size of 1 fat.. we don't need this, it is here just for curious people ;] $fatsz = ord($disk[14]) + 256*ord($disk[15]); // addresses of first and second fat, but we will use first one only $fat1 = ord($disk[18]) + 256*ord($disk[19]); $fat2 = ord($disk[20]) + 256*ord($disk[21]); // diskette can contain up to 256 directories for ($dir = 0;$dir<256;$dir++) { // is this valid bsdos directory? (is it used?) if (ord($disk[$dirmap*1024 + $dir*4]) != 0x80) continue; // get directory sector $dirsec = ord($disk[$dirmap*1024 + $dir*4 + 2]) + 256*((ord($disk[$dirmap*1024 + $dir*4 + 3])) & 0x1f); // order of directory sector $dirsecnum = 0; while (1) { // in 1 directory sector can lay up to 32 files for ($j = 0;$j<32;$j++) { // first in directory list is name of directory, so we skip that one if (($j + 32*$dirsecnum) == 0) continue; // skip unused/erased directory entries $f = ord($disk[$dirsec*1024 + $j*32]); if (($f & 0xcf) != 0x80) continue; // count file location in directory $loc = $j + 32*$dirsecnum; // get header/body string $hb = $headbody[($f/16) & 3]; // file type.. 0-basic, 3-bytes .. and many others ;] $type = ord($disk[$dirsec*1024 + $j*32 + 5]); // filename $name = substr($disk, $dirsec*1024 + $j*32 + 6, 10); // this part is to substitute nasty characters with theirs ascii value in brackets $n = ""; for ($i = 0;$i<10;$i++) if (ord($name[$i])<32 || ord($name[$i])>127) $n .= "[".ord($name[$i])."]"; else $n .= $name[$i]; $name = $n; // get various sizes and addresses of file, bsdos seems to use $start and $altlen in CAT print $len = ord($disk[$dirsec*1024 + $j*32 + 16]) + 256*ord($disk[$dirsec*1024 + $j*32 + 17]); $start = ord($disk[$dirsec*1024 + $j*32 + 18]) + 256*ord($disk[$dirsec*1024 + $j*32 + 19]); $vars = ord($disk[$dirsec*1024 + $j*32 + 20]) + 256*ord($disk[$dirsec*1024 + $j*32 + 21]); $altaddr = ord($disk[$dirsec*1024 + $j*32 + 22]) + 256*ord($disk[$dirsec*1024 + $j*32 + 23]); $altlen = ord($disk[$dirsec*1024 + $j*32 + 24]) + 256*ord($disk[$dirsec*1024 + $j*32 + 25]) + 65536*(ord($disk[$dirsec*1024 + $j*32 + 26]) + 256*ord($disk[$dirsec*1024 + $j*32 + 27])); // get date and time $tim = ord($disk[$dirsec*1024 + $j*32 + 1]) + 256*ord($disk[$dirsec*1024 + $j*32 + 2]); $dat = ord($disk[$dirsec*1024 + $j*32 + 3]) + 256*ord($disk[$dirsec*1024 + $j*32 + 4]); $hod = ($tim >> 11) & 0x1f; $min = ($tim >> 5) & 0x3f; $sec = ($tim << 1) & 0x3f; $yr = ($dat >> 9) + 1980; $mon = (($dat >> 5) & 0x0f); $day = ($dat & 0x1f); // if $day==0 or $mon==0 .. date is not valid if ($day*$mon != 0) $date = sprintf("%02d.%02d.%04d", $day, $mon, $yr); else $date = ""; // maybe we can also assume that time is wrong when $day==0 or $mon==0, but for now.. $time = sprintf("%02d:%02d", $hod, $min); // and finaly print collected data print "$dnum;$dir;$loc;$hb;$type;\"$name\";$start;$len;$vars;$altaddr;$altlen;$date;$time\n"; } // get next directory sector from fat1 $next1 = ord($disk[$fat1*1024 + $dirsec*2]); $next2 = ord($disk[$fat1*1024 + $dirsec*2 + 1]); // if it was last directory sector then exit loop if (($next2 & 0xe0) != 0xc0) break; // advance to next directory sector $dirsec = $next1 + 256*($next2 & 0x0f); $dirsecnum++; } } } // we are done.. fclose($fp); ?>