今天,因为弄错了磁盘顺序,不小心把移动硬盘的前 40M 左右的数据覆盖掉了。所幸发现的时候移动硬盘还接在电脑上,除了第一个分区外,后边的还可以正常挂载和读取,这说明内核还记得分区表。但是fdisk
已经读不到 MBR 了。
怎么办呢?我不想把几百 G 的数据拷一遍,而且理论上肯定是能够把分区表给完整的找回来的——内核不是还记得么?上网只搜到/proc/partitions
这个文件,其中的内容如下:
major minor #blocks name 8 0 312571224 sda 8 1 52436128 sda1 8 2 52428800 sda2 8 3 1 sda3 8 5 512000 sda5 8 6 41943040 sda6 8 7 161281024 sda7 8 8 3964928 sda8 11 0 1048575 sr0 7 0 71680 loop0 8 16 312571224 sdb 8 17 1048576 sdb1 8 18 209715200 sdb2 8 19 10485760 sdb3 8 20 91320320 sdb4
只有分区的大小信息,而且单位是块。我按移动硬盘的大小推算了下,这里的块大小是1KiB
(关于块大小,真够混乱的。ls
默认的也是 1K,但是dd
却是 512B)。
光知道了块大小不行啊。我先试了试著名的 testdisk 工具。它搜索了好久,最终只找到了两个分区,于是被我否决了。又继续找分区的更多信息。/proc
下看完了,我又去不怎么了解的/sys
下看,发现其下有个block
目录,里面正是系统已经识别的块设备!
进到出事故的sdb
下,再进入sdb1
,ls
一下,看到size
和start
都在呢!cat
出来各是一个整数。经过一番猜测和计算,可以确定其单位是512B
,也就是一个扇区。
好了,可以开始重建分区表了。当然,我可不想手工去算和写那64字节的二进制数据。试了试 Arch 安装时所用的cfdisk
。它有基于文本的图形化界面,比较友好。可是新建分区时才发现只能输入以1000进制MB为单位的大小,而我需要分毫不差的按原大小分区。只好退出,试试文本交互的fdisk
。在不断地按m键查看帮助的情况下,终于把分区重建好了:
Device Boot Start End Blocks Id System /dev/sdb1 2048 2099199 1048576 83 Linux /dev/sdb2 2099200 421529599 209715200 83 Linux /dev/sdb3 421529600 442501119 10485760 83 Linux /dev/sdb4 442501120 625141760 91320320+ 7 HPFS/NTFS/exFAT
前面几个的大小比较整,我是按+1G
等这样输入的。这里要注意下的是,G, M, K
等单位是1024进制,而GB, MB, KB
等单位是1000进制。最后那个给 Windows 留的 NTFS 分区不知道为什么并不是在磁盘的最后一个扇区结束的,我输入的是/sys/block/sdb/sdb4/size
里写的大小。
按p查看并确认分区表正确后,按w写入。然后使用partprobe
命令通知内核更新分区表信息。
这步做完后,后边的三个分区就安全了。第一个分区是一些启动文件,我已经打算重新弄一遍了。实际上fsck.ext2
跑完后也只是在lost+found
里出现了一堆垃圾文件。mkfs.ext2
重新格式化,却在安装 grub2 时遇到了问题。大致的错误信息是这样的:
/dev/sdb appears to contain a iso9660 filesystem which isn't known to reserve space for DOS-style boot. Installing GRUB there could result in FILESYSTEM DESTRUCTION if valuable data is overwritten by grub-setup (--skip-fs-probe disables this check, use at your own risk)
中文消息是:
/dev/sda 中似乎包含一个不为 DOS 引导保留空间的 iso9660 文件系统。在此处安装 GRUB 可能导致 grub-setup 覆盖重要数据从而损坏文件系统(--skip-fs-probe 参数可以禁用这个检查,使用该选项风险自负)
这个「iso9660」文件系统就是我误dd
过去的。使用grub-setup
并加上--skip-fs-probe
参数后依旧出错:
warn: Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. error: embedding is not possible, but this is required for cross-disk install.
中文消息是:
警告:正在试图将 GRUB 安装至有多个分区标签的磁盘,或同时有分区标签和文件系统的磁盘。这样的操作尚未被支持。 错误:无法嵌入,但在跨盘安装时是必须的
加上--force
参数也没有用。我尝试消除前446字节的数据,亦没有用。后来想起在使用fdisk
分区时,第一分区的起始扇区必须大于等于2048。难道是这些扇区中的内容影响了 grub2 的安装?head -c 1024 > a
然后用 bviplus 查看,发现果然如此,都看到那个已经不完整的 iso9660 文件系统的卷标了。果然给它 dd 掉:
sudo dd if=/dev/zero of=/dev/sdb seek=1 count=2047 bs=1b
再次尝试安装,一切顺利!