/*
* $Id$
*
* Copyright (C) 2003-2013 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.fs.jfat.command;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.log4j.Logger;
import org.jnode.driver.block.BlockDeviceAPI;
import org.jnode.partitions.ibm.MasterBootRecord;
import org.jnode.util.FileUtils;
/**
* The MBRFormatter is the main class for writing the stage1 and stage1.5 to the
* MBR.
*
* @author tango
*/
class MBRFormatter {
private static final Logger log = Logger.getLogger(MBRFormatter.class);
private MasterBootRecord stage1;
static final String GRUB_HOME = "/devices/sg0/boot/grub/";
/**
* The Source path for the Grub in CD://devices/sg0/boot/grub/STAGE1.
* Because the grub can installed from the Live Boot CD.
*/
private final String stageResourceName1 = GRUB_HOME + "grub.s1";
/**
* Reading the Grub stages from the Rescue Device.
*
* @param stage1ResourceName
* @return
* @throws java.io.IOException
*/
private MasterBootRecord getStage1(String stage1ResourceName) throws GrubException {
if (stage1 == null) {
try {
File file = new File(stage1ResourceName);
InputStream is = new FileInputStream(file);
byte[] buf = new byte[512];
FileUtils.copy(is, buf);
is.close();
stage1 = new MasterBootRecord(buf);
} catch (IOException e) {
throw new GrubException("error while reading stage1", e);
}
}
return stage1;
}
/**
*
* @param devApi
* @throws GrubException
*/
public void format(BlockDeviceAPI devApi) throws GrubException {
log.info("Checking the old MBR...");
MasterBootRecord oldMbr;
try {
oldMbr = new MasterBootRecord(devApi);
} catch (IOException e) {
throw new GrubException("error while reading MBR", e);
}
if (!oldMbr.containsPartitionTable()) {
throw new GrubException("This device doesn't contain a valid MBR.");
}
log.info("done.");
/*
* int add=LittleEndian.getInt32(MBR.array(),0x44);
* System.out.println("The value at the position 0x44 is-> "
* +Integer.toHexString(add));
*/
stage1 = getStage1(stageResourceName1);
/**
* The BPB stands for the Bios Parameter Block.As the BPB of a disk is
* fixed and it is written to the disk during the partitioning of the
* disk. The BPB is present between the position of 0x3 to 0x48
* position.
*
* NOTE: 1) Here need to make the BPB more independently(ie without
* array of the BPB using it in MBR)
*
* 2)The next Important matter is here that in the MBR's <b> 0x44 th</b>
* position we setting the position of the stage1.5 or Stage2.here as i
* used the Stage1.5 at the Sector 1(second sector) so The Value is set
* here as 01 00 00 00
*
* 3)In the Position of the 0x40: The boot drive. If it is 0xFF, use a
* drive passed by BIOS. The value is 0x80 for HDD.I kept it default
* here.
*
* 4)0x42: The starting address of Stage 2 or Stage1.5. As here i used
* the Stage1.5;hence the value i set here 0x2000 If it is Stage2 then
* it will be 0x8000.
*
* 5)0x48: The starting segment of Stage 2 or Stage1.5. Here for
* stage1.5 i used the value 0x20 For stage2 it will be 0x80.
*
* TODO: In this portion we need to use dynamically the BPB values. And,
* that time at the stage1 buffer the EMBEDDED variables need to set
* here individually.
*
* BUGs REPORT: Using statically the value of the BPB.and setted the
* EMBEDDED variables in that array statically.It is not good. ;-)
*
*/
stage1.setBPB(BPB);
/**
* The Partition table is the cruisal part of the HDD formatted with
* different FS.For the grub disk the Stage1 is kept upto the first
* 446bytes to the MBR.Then after the 64 bytes are kept for Setting the
* PArtition table.
*
* N.B. : The grub will be written actually always after the Partition
* Table written to the HDD.IT is very IMPORTANT.
*
*/
stage1.copyPartitionTableFrom(oldMbr);
/**
* Checking the BootSector is Valid or not. Actually here need to check
* the Sector Signature. 0x55AA --->
*
*/
if (!stage1.containsPartitionTable()) {
throw new GrubException("The new boot sector is not valid");
}
try {
/**
* write the GRUB's stage1 to the MBR
*/
System.out.print("Writing stage 1 ... ");
stage1.write(devApi);
System.out.println("done.");
} catch (IOException e) {
throw new GrubException("Failed writing boot sector");
}
System.out.println("Writing stage 1 has been completed.");
}
/**
* The BPB-Bios Parameter Block is kept here. I am Confusing yet with That.I
* will Change it soon.
*/
private static final byte[] BPB = {
(byte) 0xD0, (byte) 0xBC, (byte) 0x00, (byte) 0x7C, (byte) 0xFB, (byte) 0x50,
(byte) 0x07, (byte) 0x50, (byte) 0x1F, (byte) 0xFC, (byte) 0xBE, (byte) 0x1B,
(byte) 0x7C, (byte) 0xBF, (byte) 0x1B, (byte) 0x06, (byte) 0x50, (byte) 0x57,
(byte) 0xB9, (byte) 0xE5, (byte) 0x01, (byte) 0xF3, (byte) 0xA4, (byte) 0xCB,
(byte) 0xBE, (byte) 0xBE, (byte) 0x07, (byte) 0xB1, (byte) 0x04, (byte) 0x38,
(byte) 0x2C, (byte) 0x7C, (byte) 0x09, (byte) 0x75, (byte) 0x15, (byte) 0x83,
(byte) 0xC6, (byte) 0x10, (byte) 0xE2, (byte) 0xF5, (byte) 0xCD, (byte) 0x18,
(byte) 0x8B, (byte) 0x14, (byte) 0x8B, (byte) 0xEE, (byte) 0x83, (byte) 0xC6,
(byte) 0x10, (byte) 0x49, (byte) 0x74, (byte) 0x16, (byte) 0x38, (byte) 0x2C,
(byte) 0x74, (byte) 0xF6, (byte) 0xBE, (byte) 0x10, (byte) 0x07, (byte) 0x03,
(byte) 0x02, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x01,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02
};
}