Updated 2012-01-18 18:07:47 by RLE

Not realy nice yet just quick and splashes of blood.

The scanning could be replaced with "binary scan".

Unix <> Dos path handling is nonexistent.

The DateTimes in the archive format are ignored.

Files are extracted to uppercase names.

Files split across multiple archive parts are patched together in the right way if one expands into an empty filepath.

Start with dumping all files from the disk set into the current directory.

The archive format description is taken from "Technical Documentation for FreeDOS Backup & Restore" [1]
 #!/usr/bin/tclsh

 set ptype U
 set pre_path ".\\restore\\"
 set do 1
        set idx 0

 while {1} {
        set bidx [ format %03d [ incr idx ] ]
        set backup  backup.$bidx
        set control control.$bidx

        set stfd [ open $backup r ]
        fconfigure $stfd -encoding binary -translation binary

        set ctrlfd [ open $control r ]
        fconfigure $ctrlfd -encoding binary -translation binary
        set index [ read $ctrlfd ]

        set len [string length $index] ; puts stderr indexlen:$len

        set pos 0

        while {$pos < $len} {
                set act [string index $index $pos ]
                scan $act %c val
                puts -nonewline stderr [format "0x%02x " $val]
                switch -- $act  \
                  \x8b {
                        puts stderr "Header"
                        set headerentry [ string range $index $pos [ incr pos 0x8b ] ]
                        set hd_signature [ string range $headerentry 1 7 ]
                        scan [ string range $headerentry 9 9 ] %c hd_backno
                        set hd_filler    [ string range $headerentry 10 137 ]
                        scan [ string range $headerentry 138 138 ] %c hd_lastdisk
                        puts stderr [format "\t\"%s\" %d %d\n" $hd_signature $hd_backno $hd_lastdisk]
                } \x46 {
                        puts stderr "Dir Entry"
                        set direntry [ string range $index $pos [ incr pos 0x46 ] ]
                        set dir_path [ string range $direntry 1 63 ]
                        set dir_path [ string trimright ${pre_path}$dir_path \x0 ]
                        set dir_fcnt [ string range $direntry 64 65 ]
                        binary scan  $dir_fcnt s dir_fcnt
                        set dir_dummy [ string range $direntry 66 69 ]
                        puts stderr [format "\t\"%s\" %d \n" $dir_path $dir_fcnt ]
                        if {$do} {
                                if { $ptype== "U" } {
                                        set dir_path [ string map [ list \\ /] $dir_path ]
                                }
                                puts stderr "trying: mkdir $dir_path"
                                catch [ file mkdir $dir_path ]
                        }
                } \x22 {
                        puts stderr "File Entry"
                        set fileentry [ string range $index $pos [ incr pos 0x22 ] ]
                        set file_name [ string range $fileentry 1 12 ]
                        set file_name [ string trimright $file_name \x0 ]
                        scan [string range $fileentry 13 13 ] %c file_split
                        set file_size [ string range $fileentry 14 17 ]
                          binary scan  $file_size i file_size

                        set file_cidx [ string range $fileentry 18 19 ]
                          binary scan  $file_cidx s file_cidx
                        set file_coffs [ string range $fileentry 20 23 ]
                          binary scan  $file_coffs i file_coffs
                        set file_clen [ string range $fileentry 24 27 ]
                          binary scan  $file_clen i file_clen
                        scan [ string range $fileentry 28 28 ] %c file_attrib
                        set file_dummy [ string range $fileentry 29 29 ]
                        set file_dtime [ string range $fileentry 30 33 ]
                          binary scan  $file_dtime i file_dtime
                        puts stderr [format "\t\"%s\" %d %d %08x:%08x %02x %08x\n" \
                                        $file_name $file_size $file_cidx \
                                        $file_coffs $file_clen $file_attrib \
                                        $file_dtime \
                        ]
                        if {$do} {
                                seek $stfd $file_coffs start
                                set file_cont [ read $stfd $file_clen ]
                                puts stderr "trying: open [ file join $dir_path $file_name ]"
                                set fd [ open [ file join $dir_path $file_name ] a ]
                                fconfigure $fd -encoding binary -translation binary
                                puts -nonewline $fd $file_cont
                                close $fd
                        }
                } \x00 {
                        puts stderr "End of File"
                        incr pos
                }
                puts -nonewline stderr next? ; # gets stdin
        }
        close $stfd
        close $ctrlfd

 }