迁移Windows分区

2022-06-04
4分钟阅读时长

目前在使用 Arch + Windows 双系统进行工作,但由于是先安装的 Windows,所以默认分配的 efi 分区只有 100MB,而 /boot 这个目录我也挂载到这个分区上,故内核更新时经常空间不足,所以需要对 efi 进行扩容。不过 efi、保留分区以及 Windows 的基本数据分区是紧密相连的,所以需要对后面的分区向右移动才能进行扩容。

准备工作

  1. 首先需要对分区进行一个压缩,此处主要是数据分区。先在 Windows 里面用磁盘工具,把原来分区的尾部裁出来(右键此电脑 > 管理 > 磁盘管理 > 右键磁盘 > 压缩卷),大小选择为最大。

  2. 可以准备一个 Linux 的 Live CD,当然直接用磁盘上的 Linux 也可以,不过操作前记得卸载相应的分区(下面的操作基于 Live CD 环境)。

使用 dd 拷贝分区

dd 是一个简单粗暴的工具,不基于文件系统拷贝文件,而是直接复制硬盘上的 0 和 1,可以把分区整个拷贝下来。

fdisk -l	# 查看硬盘上的分区信息
mount /dev/nvme0n1p5 /mnt						# 挂载Linux主分区
dd if=/dev/nvme0n1p3 of=/mnt/opt/windows.img	# 拷贝分区3(数据分区),保存在/opt/windows.img(请根据你实际的分区更改)
dd if=/dev/nvme0n1p2 of=/mnt/opt/msr.img status=progress	# 拷贝分区2(保留分区),并且可查看进度

可以把输出进行压缩

dd if=/dev/nvme0n1p3 | gzip > windows.img

使用 fdisk 重新分区

fdisk /dev/nvme0n1	# 选中要操作的磁盘

进入交互环境后,可以用 m 获得帮助。我需要对 efi 进行扩容,所以用 p 先查看原来的情况。

Device				Start       End   Sectors   Size Type
/dev/nvme0n1p1       2048    206847    204800   100M EFI System
/dev/nvme0n1p2	   206848    239615     32768    16M Microsoft reserved
/dev/nvme0n1p3     239616       ...       ...    ... Microsoft basic data
/dev/nvme0n1p4        ...       ...       ...    ... Windows recovery environment
/dev/nvme0n1p5        ...       ...       ...    ... Linux filesystem

记住 efi 起始扇区号,然后 d 删除第一个、第二个和第三个分区。再按 n 新建分区,number 是 1,起始扇区号填回原来的,大小选择 +1G,这样相当于把原来的分区扩容到了 1 GB。

选择大小后会提示是否移除原有签名,选择“否”。

Do you want to remove the signature? [Y]es/[N]o: n

分区 2 的起始扇区号可以紧接着上一个分区,大小 +16M,不过新建出来的分区默认类型是 Linux filesystem,可以用 t 更改成 Microsoft reserved。分区 3 也是同理。需要注意的是新建的分区不能比原来的小,不然 dd 无法写入

修改完成后,先用 p 查看是否有误,无误后可以用 w 写入磁盘。

但是出去用 df -h 查看的话,会发现 efi 还是只有原来的大小,因为文件系统并没有进行扩容,需要单独用 fatresize 进行调整。

fatresize -s max /dev/nvme0n1p1

但是却提示。。。

GNU Parted cannot resize this partition to this size.We're working on it.

查了一下,好像是这个工具存在的 bug,我们直接挂载 efi,备份里面的文件,再重新格式化好了。

mkdir /mnt/part1
mount /dev/nvme0n1p1 /mnt/part1
cp -r /mnt/part1 /mnt/opt/
umount /mnt/part1

mkfs.fat -F32 /dev/nvme0n1p1	# 把efi格式化成FAT32
mkfs.ntfs /dev/nvme0n1p3		# 顺便把分区3格式化成NTFS

mount /dev/nvme0n1p1 /mnt/part1
cp -r /mnt/opt/part1/* /mnt/part1/
umount /mnt/part1 

dd 复原分区

dd if=/mnt/opt/windows.img of=/dev/nvme0n1p3	# 复原Windows数据分区
dd if=/mnt/opt/msr.img of=/dev/nvme0n1p2	    # 复原保留分区

gzip -dc windows.img | dd of=/dev/nvme0n1p3		# 从压缩过的文件进行复原

检查文件系统

fsck -r /dev/nvme0n1p3	# -r参数,如果检查有错则由使用者回答是否修复

修复 GRUB 引导

因为分区的 uuid 已经变了,所以需要更新 grub 配置。

检查一下 /mnt/etc/fstab,正常来说如果扩容时没移除签名,fstab 则不用更新,否则 /boot 部分要更改成 efi 的新 uuid。

arch-chroot /mnt			# 因为grub不在Live CD,需要chroot
mount /dev/nvme0n1p3 /mnt	# 挂载Windows分区,不然探测不到。注意这里的/mnt目录是chroot之后的(原本Linux filesystem里面的)
grub-mkconfig -o /boot/grub/grub.cfg	# 重新生成grub配置

如果没有探测到,请查看 /etc/default/grub 中是否已经取消下面的注释

GRUB_DISABLE_OS_PROBER=false

修复 Windows 引导

这时候还是不能进入 Windows,查看了一下 bcd 信息,发现 device 的路径丢失了 QAQ

下面的操作都在 Windows 恢复环境中进行

bcdedit /enum

输出如下

Windows 启动管理器
--------------------
标识符                  {bootmgr}
device                  partition=\Device\HarddiskVolume3
path                    \EFI\Microsoft\Boot\bootmgfw.efi
description             Windows Boot Manager
locale                  zh-CN
inherit                 {globalsettings}
default                 {current}
resumeobject            {a3d......}
displayorder            {current}
toolsdisplayorder       {memdiag}
timeout                 30

Windows 启动加载器
-------------------
标识符                  {current}
device                  Unknown
path                    \Windows\system32\winload.efi
description             Windows 10
locale                  zh-CN
inherit                 {bootloadersettings}
recoverysequence        {a3d......}
displaymessageoverride  Recovery
recoveryenabled         Yes
isolatedcontext         Yes
allowedinmemorysettings 0x15000075
osdevice                Unknown
systemroot              \Windows
resumeobject            {a3d......}
nx                      OptIn
bootmenupolicy          Standard

可以看见启动加载器的 device 和 osdevice 的值丢失了,需要手动重设。

打开 diskpart,查看盘符

diskpart	# 进入交互模式

DISKPART> list vol	# 列出所有卷

卷    ###   LTR  标签         FS     类型        大小     状态       信息
----------  ---  -----------  -----  ----------  -------  ---------  --------
卷     0     C                NTFS   磁盘分区    228 GB   正常       启动
...   ...   ...               ...    ...         ...      ...        ...

DISKPART> exit

我的卷 0 是系统分区,分配了卷标 C,所以需要重设为 partition=C:

bcdedit /set {current} device partition=C:
bcdedit /set {current} osdevice partition=C:

至此 bcd 修复完成,重启即可恢复正常引导。

参考文档

  1. UEFI 的 BCD 系统存储设置
  2. BCDEdit 命令行选项
  3. failure to move / resize fat32 partitions less than 256 MB in size