+\f
+# Prepare the scratch disk for gets and puts.
+sub prepare_scratch_disk {
+ # Copy the files to put onto the scratch disk.
+ put_scratch_file ($_->[0]) foreach @puts;
+
+ # Make sure the scratch disk is big enough to get big files.
+ extend_disk ($disks{SCRATCH}, @gets * 1024 * 1024) if @gets;
+}
+
+# Read "get" files from the scratch disk.
+sub finish_scratch_disk {
+ # We need to start reading the scratch disk from the beginning again.
+ if (@gets) {
+ close ($disks{SCRATCH}{HANDLE});
+ undef ($disks{SCRATCH}{HANDLE});
+ }
+
+ # Read each file.
+ get_scratch_file (defined ($_->[1]) ? $_->[1] : $_->[0]) foreach @gets;
+}
+
+# put_scratch_file($file).
+#
+# Copies $file into the scratch disk.
+sub put_scratch_file {
+ my ($put_filename) = @_;
+ my ($disk_handle, $disk_filename) = open_disk ($disks{SCRATCH});
+
+ print "Copying $put_filename into $disk_filename...\n";
+
+ # Write metadata sector, which consists of a 4-byte signature
+ # followed by the file size.
+ stat $put_filename or die "$put_filename: stat: $!\n";
+ my ($size) = -s _;
+ my ($metadata) = pack ("a4 V x504", "PUT\0", $size);
+ write_fully ($disk_handle, $disk_filename, $metadata);
+
+ # Copy file data.
+ my ($put_handle);
+ sysopen ($put_handle, $put_filename, O_RDONLY)
+ or die "$put_filename: open: $!\n";
+ copy_file ($put_handle, $put_filename, $disk_handle, $disk_filename,
+ $size);
+ close ($put_handle);
+
+ # Round up disk data to beginning of next sector.
+ write_fully ($disk_handle, $disk_filename, "\0" x (512 - $size % 512))
+ if $size % 512;
+}
+
+# get_scratch_file($file).
+#
+# Copies from the scratch disk to $file.
+sub get_scratch_file {
+ my ($get_filename) = @_;
+ my ($disk_handle, $disk_filename) = open_disk ($disks{SCRATCH});
+
+ print "Copying $get_filename out of $disk_filename...\n";
+
+ # Read metadata sector, which has a 4-byte signature followed by
+ # the file size.
+ my ($metadata) = read_fully ($disk_handle, $disk_filename, 512);
+ my ($signature, $size) = unpack ("a4 V", $metadata);
+ die "bad signature reading scratch disk--did Pintos run correctly?\n"
+ if $signature ne "GET\0";
+
+ # Copy file data.
+ my ($get_handle);
+ sysopen ($get_handle, $get_filename, O_WRONLY | O_CREAT | O_EXCL, 0666)
+ or die "$get_filename: create: $!\n";
+ copy_file ($disk_handle, $disk_filename, $get_handle, $get_filename,
+ $size);
+ close ($get_handle);
+
+ # Skip forward in disk up to beginning of next sector.
+ read_fully ($disk_handle, $disk_filename, 512 - $size % 512)
+ if $size % 512;
+}
+\f
+# Prepares the arguments to pass to the Pintos kernel,
+# and then write them into Pintos bootloader.
+sub prepare_arguments {
+ my (@args);
+ push (@args, shift (@kernel_args))
+ while @kernel_args && $kernel_args[0] =~ /^-/;
+ push (@args, 'put', defined $_->[1] ? $_->[1] : $_->[0]) foreach @puts;
+ push (@args, @kernel_args);
+ push (@args, 'get', $_->[0]) foreach @gets;
+ write_cmd_line ($disks{OS}, @args);
+}