2
28
2012
8

拯救分区表

今天,因为弄错了磁盘顺序,不小心把移动硬盘的前 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下,再进入sdb1ls一下,看到sizestart都在呢!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

再次尝试安装,一切顺利!

Category: Linux | Tags: linux 失误 数据恢复
9
16
2010
9

Vim的hidden选项真是好东西!

我在编辑一些HTML文件。写得觉得差不多了,浏览器里看过还不满足,竟然想到去W3C验证一下。这一验证,差点出大事了!

因为需要使用程序来处理,所以这些HTML文档全部都是合格的XML文件,所以我给它们加上了<?xml version="1.0" encoding="UTF-8"?>。但W3C却告诉我HTML里不能写这个。好吧,我把它们都删掉:

sed -i '/<\?/d'  *.html

我想的是,凡是有<?的行全部删掉。命令执行完后忽然有点不好的感觉,于是ll一下,结果看到了一堆长度为0的HTML文件!我愣了一下,随即欲哭无泪!虽然这些文件在SVN里,但是自我这次开始编辑后我就没提交过!sed也是危险的命令啊!

我只想到火狐里还保留着改动最多的一个页面,赶紧先把它的源代码复制出来。直接“查看源代码”还不管用,因为本地文件是没有缓存的,查看时火狐会去磁盘上找文件。于是打开Firebug,在<html>元素上点右键,复制HTML,然后手工整理。剩下的文件没办法,只有SVN和Vim的*~备份文件了,555……

好吧,我认命。于是我在Vim里打开另一个文件,想趁着还记得改了些什么赶紧重做一遍,却意外地发现打开的文件显示着我sed之前的内容。来不及多想,我赶紧:w保存了,然后想了下,才恍然大悟——

我现在习惯于一直开着一个GVim实例,而又经常只是挂起或者休眠,几天才shutdown一次,所以经常会有100多个buffer。虽然我通常是把hidden选项关闭的,但有时候为方便切换buffer,会去se hidden一下,然后一直忘记再设置回来。这次,不记得什么时候设置了hidden选项,于是,那些被我关闭的buffer都还在内存里!终于知道了hidden在文件已保存的情况下有什么重要作用了!怀着对Vim的感激,我在buffer找到了所有被sed误删的文本,泪流满面~~


2011年3月17日更新:

现在才知道,sed 原来是支持备份的,只要告诉它备份文件的后缀就行了,像这样-i~

另外,Perl 也支持类似的操作,但用的是PCRE,功能强大许多我也熟悉许多。用法是

perl -pin -e 'print /regex/' #相当于 sed -i '/regex/d'
perl -pi -e 's/regex/replacement/g' #相当于 sed -i 's/regex/replacement/g'

 

Category: Vim | Tags: vim 失误 perl sed

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com