I've written more of mkfs7 but not tested it yet.
This commit is contained in:
+162
-29
@@ -7,6 +7,9 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
Getopt::Long::Configure qw(gnu_getopt);
|
||||
|
||||
# Constants
|
||||
use constant NUMBLOCKS => 8000; # Number of blocks on a surface
|
||||
@@ -38,6 +41,7 @@ use constant I_USED => 0400000;
|
||||
use constant I_LARGE => 0200000;
|
||||
use constant I_SPECIAL => 0000040;
|
||||
use constant I_DIRECTORY => 0000020;
|
||||
use constant I_FILE => 0000000;
|
||||
use constant I_OWNERREAD => 0000010;
|
||||
use constant I_OWNERWRITE => 0000004;
|
||||
use constant I_WORLDREAD => 0000010;
|
||||
@@ -49,7 +53,6 @@ use constant D_NAME => 1;
|
||||
use constant D_UNIQ => 5;
|
||||
use constant D_NUMWORDS => 8; # Eight words in a direntry
|
||||
|
||||
|
||||
# Globals
|
||||
my $debug = 0;
|
||||
my @Block; # Array of blocks and words in each block
|
||||
@@ -63,11 +66,11 @@ my @Dirstack; # Stack of directories. Each value is a ref
|
||||
sub dprint {
|
||||
print(@_) if ($debug);
|
||||
}
|
||||
|
||||
sub dprintf {
|
||||
printf(@_) if ($debug);
|
||||
}
|
||||
|
||||
|
||||
# Given a size in words, allocate and return a set of block numbers
|
||||
# for the entity
|
||||
sub allocate_blocks {
|
||||
@@ -79,7 +82,8 @@ sub allocate_blocks {
|
||||
foreach my $b ( 1 .. $numblocks ) {
|
||||
push( @blklist, $nextblknum++ );
|
||||
}
|
||||
dprint("Allocated blocks for size $numwords: $blklist[0] .. $blklist[-1]\n");
|
||||
dprint(
|
||||
"Allocated blocks for size $numwords: $blklist[0] .. $blklist[-1]\n");
|
||||
return (@blklist);
|
||||
}
|
||||
|
||||
@@ -113,7 +117,8 @@ sub build_indirect_blocks {
|
||||
foreach my $datablock (@blklist) {
|
||||
$Block[$indblock][ $offset++ ] = $datablock;
|
||||
if ( $offset == WORDSPERBLK ) {
|
||||
$offset=0; $indblock++;
|
||||
$offset = 0;
|
||||
$indblock++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +166,8 @@ sub fill_inode {
|
||||
$flags |= I_LARGE if ( $size > WORDSPERBLK * I_NUMBLKS );
|
||||
$Block[$blocknum][ $offset + I_FLAGS ] = $flags;
|
||||
|
||||
dprintf("fill inum %d: flags %06o uid %06o size %d\n", $inum, $flags, $uid, $size);
|
||||
dprintf( "fill inum %d: flags %06o uid %06o size %d\n",
|
||||
$inum, $flags, $uid, $size );
|
||||
return ($inum);
|
||||
}
|
||||
|
||||
@@ -188,7 +194,7 @@ sub add_block_to_inode {
|
||||
my ( $iblock, $offset ) = get_inode_block_offset($inum);
|
||||
|
||||
foreach my $i ( 1 .. I_NUMBLKS ) {
|
||||
next if ($Block[$iblock][$offset+$i]!=0); # Skip in-use blocks
|
||||
next if ( $Block[$iblock][ $offset + $i ] ); # Skip in-use blocks
|
||||
$Block[$iblock][ $offset + $i ] = $blknum;
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +212,7 @@ sub add_direntry {
|
||||
my $dirref = $Dirstack[-1];
|
||||
|
||||
if ( !defined($dirref) ) {
|
||||
print("Empty dirstack, we must be building the root dir\n");
|
||||
dprint("Empty dirstack, we must be building the root dir\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -268,12 +274,11 @@ sub make_dir {
|
||||
# Return -1 on EOF
|
||||
sub read_word {
|
||||
my $FH = shift;
|
||||
|
||||
# Convert three bytes into one 18-bit word
|
||||
return (-1) if ( read( $FH, my $three, 3 ) != 3 ); # Not enough bytes read
|
||||
my ( $b1, $b2, $b3 ) = unpack( "CCC", $three );
|
||||
return ((($b1 & 077) << 12 ) |
|
||||
(($b2 & 077) << 6 ) |
|
||||
($b3 & 077));
|
||||
return ( ( ( $b1 & 077 ) << 12 ) | ( ( $b2 & 077 ) << 6 ) | ( $b3 & 077 ) );
|
||||
}
|
||||
|
||||
# Given a filename, perms, user-id and an external file, add a file to the
|
||||
@@ -299,12 +304,12 @@ sub add_file {
|
||||
|
||||
while (1) {
|
||||
if ($isbinary) {
|
||||
|
||||
# Convert three bytes into one 18-bit word
|
||||
my $result = read_word($IN);
|
||||
last if ( $result == -1 );
|
||||
$buf[ $size++ ] = $result;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
# Convert two ASCII characters into one 18-bit word
|
||||
my $c1 = getc($IN);
|
||||
last if ( !defined($c1) ); # No character, leave the loop
|
||||
@@ -329,9 +334,9 @@ sub add_file {
|
||||
# Allocate and fill in the i-node
|
||||
my $inum = allocate_inode();
|
||||
if ($large) {
|
||||
fill_inode($inum, $perms, 0, $uid, $size, @indblocks);
|
||||
fill_inode( $inum, $perms, I_FILE, $uid, $size, @indblocks );
|
||||
} else {
|
||||
fill_inode($inum, $perms, 0, $uid, $size, @blklist);
|
||||
fill_inode( $inum, $perms, I_FILE, $uid, $size, @blklist );
|
||||
}
|
||||
|
||||
# and add the entry in the directory
|
||||
@@ -345,7 +350,7 @@ sub add_special {
|
||||
my ( $name, $perms, $uid, $inum ) = @_;
|
||||
|
||||
# Allocate and fill in the i-node
|
||||
my $inum= allocate_inode($inum);
|
||||
$inum = allocate_inode($inum);
|
||||
fill_inode( $inum, $perms, I_SPECIAL, $uid, 0 );
|
||||
|
||||
# Add the entry in the directory
|
||||
@@ -353,19 +358,147 @@ sub add_special {
|
||||
dprint("Done adding special file $name inum $inum\n\n");
|
||||
}
|
||||
|
||||
# Parse the perms word from the proto file.
|
||||
# Return filetype and perms as a number.
|
||||
sub parse_perms {
|
||||
my $permstring = shift;
|
||||
my ( $filetype, $perms ) = ( I_FILE, 0 );
|
||||
|
||||
die("perms word $permstring is not 5 characters long\n")
|
||||
if ( length($permstring) != 5 );
|
||||
|
||||
$filetype = I_DIRECTORY if ( $permstring =~ m{^d} );
|
||||
$filetype = I_SPECIAL if ( $permstring =~ m{^i} );
|
||||
|
||||
$perms |= I_OWNERREAD if ( $permstring =~ m{^.r} );
|
||||
$perms |= I_OWNERWRITE if ( $permstring =~ m{^..w} );
|
||||
$perms |= I_WORLDREAD if ( $permstring =~ m{^...r} );
|
||||
$perms |= I_WORLDWRITE if ( $permstring =~ m{^....w} );
|
||||
return ( $filetype, $perms );
|
||||
}
|
||||
|
||||
# Open the named proto file and parse it
|
||||
sub parse_proto_file {
|
||||
my $file = shift;
|
||||
open( my $IN, "<", $file ) || die("Can't one $file: $!\n");
|
||||
while (<$IN>) {
|
||||
chomp;
|
||||
|
||||
# Skip comments
|
||||
s{#.*}{};
|
||||
|
||||
# Get the words on the line;
|
||||
my @words = split( /\s+/, $_ );
|
||||
|
||||
# Skip if no words on this line
|
||||
# but lose any empty word
|
||||
next if ( @words == 0 );
|
||||
shift(@words) if ( $words[0] eq '' );
|
||||
|
||||
# If the first word is a $, then pop a directory from the stack
|
||||
if ( $words[0] eq '$' ) {
|
||||
pop(@Dirstack);
|
||||
next;
|
||||
}
|
||||
|
||||
# Get the filetype and permissions
|
||||
my ( $type, $perms ) = parse_perms( $words[1] );
|
||||
|
||||
if ( $type eq I_DIRECTORY ) {
|
||||
my ( $name, $permstr, $uid, $inum ) = @words;
|
||||
make_dir( $name, $perms, $uid, $inum );
|
||||
next;
|
||||
}
|
||||
if ( $type eq I_FILE ) {
|
||||
my ( $name, $permstr, $uid, $extfile ) = @words;
|
||||
add_file( $name, $perms, $uid, $extfile );
|
||||
next;
|
||||
}
|
||||
if ( $type eq I_SPECIAL ) {
|
||||
my ( $name, $permstr, $uid, $inum ) = @words;
|
||||
add_special( $name, $perms, $uid, $inum );
|
||||
next;
|
||||
}
|
||||
}
|
||||
close($IN);
|
||||
}
|
||||
|
||||
# Convert an 18-bit word into a scalar which has three sixbit
|
||||
# values in three bytes. Set the msb in the first byte
|
||||
sub word2three {
|
||||
my $val = shift;
|
||||
|
||||
my $b1 = ( ( $val >> 12 ) & 077 ) | 0x80;
|
||||
my $b2 = ( $val >> 6 ) & 077;
|
||||
my $b3 = $val & 077;
|
||||
return ( pack( "CCC", $b1, $b2, $b3 ) );
|
||||
}
|
||||
|
||||
# Dump the image to the output file
|
||||
sub dump_image {
|
||||
my ( $format, $output ) = @_;
|
||||
open( my $OUT, ">", $output ) || die("Can't write to $output: $!\n");
|
||||
|
||||
# list: Octal output with block comments
|
||||
if ( $format eq "list" ) {
|
||||
foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) {
|
||||
printf( $OUT "Block %d (%06o)\n", $blocknum, $blocknum )
|
||||
if ($debug);
|
||||
foreach my $line ( 0 .. 7 ) {
|
||||
foreach my $offset ( 0 .. 7 ) {
|
||||
printf( $OUT "%06o ",
|
||||
$Block[$blocknum][ 8 * $line + $offset ] || 0
|
||||
);
|
||||
}
|
||||
print( $OUT "\n" ) if ($debug);
|
||||
}
|
||||
print( $OUT "\n" ) if ($debug);
|
||||
}
|
||||
}
|
||||
|
||||
# ptr: Each word into three bytes, a sixbit in each one
|
||||
if ( $format eq "ptr" ) {
|
||||
foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) {
|
||||
foreach my $offset ( 0 .. WORDSPERBLK ) {
|
||||
print( $OUT word2three( $Block[$blocknum][$offset] || 0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# simh: Each word into four bytes, little endian
|
||||
if ( $format eq "simh" ) {
|
||||
foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) {
|
||||
foreach my $offset ( 0 .. WORDSPERBLK ) {
|
||||
my $word = $Block[$blocknum][$offset] || 0;
|
||||
my $packedword = pack( "CCCC",
|
||||
( $word >> 24 ) & 0xff,
|
||||
( $word >> 16 ) & 0xff,
|
||||
( $word >> 8 ) & 0xff,
|
||||
$word & 0xff );
|
||||
print( $OUT $packedword );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close($OUT);
|
||||
}
|
||||
|
||||
# Keep this near the GetOptions call to make it easy to add documentation!
|
||||
sub usage {
|
||||
die("Usage: $0 [--debug] [--format=list|ptr|simh] [--out file] protofile\n");
|
||||
}
|
||||
|
||||
### MAIN PROGRAM
|
||||
|
||||
$debug=1;
|
||||
make_dir("dd", 014, -1, 2);
|
||||
make_dir("system", 014, -1, 3);
|
||||
add_file("init", 014, -1, "proto");
|
||||
pop(@Dirstack);
|
||||
add_special("ttyin", 014, -1, 6);
|
||||
add_special("keyboard", 014, -1, 7);
|
||||
add_special("pptin", 014, -1, 8);
|
||||
add_special("ttyout", 014, -1, 10);
|
||||
add_special("display", 014, -1, 11);
|
||||
add_special("pptout", 014, -1, 12);
|
||||
add_file("as", 014, -1, "b.c");
|
||||
add_file("a7out", 014, -1, "a7out");
|
||||
add_file("oflow", 014, -1, "a7out");
|
||||
my ( $format, $output ) = ( "list", "image.fs" );
|
||||
|
||||
GetOptions(
|
||||
'debug|d' => \$debug,
|
||||
'format|f=s' => \$format,
|
||||
'output|o=s' => \$output,
|
||||
) or usage();
|
||||
|
||||
usage() if ( @ARGV < 1 );
|
||||
parse_proto_file( $ARGV[0] );
|
||||
dump_image( $format, $output );
|
||||
exit(0);
|
||||
|
||||
Reference in New Issue
Block a user