如何在不挂载的情况下在文件映像分区上运行 mkfs?

如何在不挂载的情况下在文件映像分区上运行 mkfs?

我正在创建一个空文件...

dd if=/dev/zero of=${SDCARD} bs=1 count=0 seek=$(expr 1024 \* ${SDCARD_SIZE})

...然后将其转换为驱动器映像...

parted -s ${SDCARD} mklabel msdos

...并在其上创建分区

parted -s ${SDCARD} unit KiB mkpart primary fat32 ${IMAGE_ROOTFS_ALIGNMENT} $(expr ${IMAGE_ROOTFS_ALIGNMENT} \+ ${BOOT_SPACE_ALIGNED})
parted -s ${SDCARD} unit KiB mkpart primary $(expr  ${IMAGE_ROOTFS_ALIGNMENT} \+ ${BOOT_SPACE_ALIGNED}) $(expr ${IMAGE_ROOTFS_ALIGNMENT} \+ ${BOOT_SPACE_ALIGNED} \+ $ROOTFS_SIZE)

我如何使用mkfs.extmkfs.vfat 没有安装这个图像?

答案1

要创建具有多个分区的映像,不需要任何高级工具或根访问权限的解决方案是首先创建文件系统,然后将它们连接起来。

truncate -s $IMAGE_ROOTFS_ALIGNMENT disk
truncate -s $BOOT_SPACE_ALIGNED part1
mkfs.fat part1
cat part1 >>disk
truncate -s $ROOTFS_SIZE part2
mkfs.ext4 part2
cat part2 >>disk

然后运行parted​​或fdisk创建分区。

这种方法的缺点是生成的图像不会稀疏。

答案2

为了扩展 @gilles 提供的答案,这里有一种创建包含格式化文件系统的磁盘映像的方法,首先在文件中创建一个文件系统(在本例中为 ESP 类型),然后将其组装为有效的磁盘映像;无需根、安装或循环设备:

diskimg=diskimg    # filename of resulting disk image
size=$((260*(1<<20))) # desired size in bytes, 260MB in this case
alignment=1048576  # align to next MB (https://www.thomas-krenn.com/en/wiki/Partition_Alignment)
size=$(( (size + alignment - 1)/alignment * alignment ))  # ceil(size, 1MB)

# mkfs.fat requires size as an (undefined) block-count; seem to be units of 1k
mkfs.fat -C -F32 -n "volname" "${diskimg}".fat $((size >> 10))

# insert the filesystem to a new file at offset 1MB
dd if="${diskimg}".fat of="${diskimg}" conv=sparse obs=512 seek=$((alignment/512))
# extend the file by 1MB
truncate -s "+${alignment}" "${diskimg}"

# apply partitioning
parted --align optimal "${diskimg}" mklabel gpt mkpart ESP "${offset}B" '100%' set 1 boot on

当在支持稀疏文件的文件系统上使用时,上述方法具有稀疏的副作用;生成的“262MB”文件在磁盘上占用的空间不到 200kB:

du -h --apparent diskimg; du -h diskimg
262M    diskimg
196K    diskimg

对于 FAT 文件系统工具实用程序支持对文件中的偏移量进行操作(ext2/4/等也可能这样做?)。这使得它变得更容易,您只需创建分区映像并直接处理它:

diskimg=diskimg
size=$((260*(1<<20))) # desired size in bytes, 260MB in this case
# align to next MB (https://www.thomas-krenn.com/en/wiki/Partition_Alignment)
alignment=1048576

size=$(( (size + alignment - 1)/alignment * alignment ))

# image size is gpt + filesystem size + gpt backup
truncate -s $((size + 2*alignment)) "${diskimg}"

parted --machine --script --align optimal "${diskimg}" mklabel gpt mkpart ESP "${alignment}B" '100%' set 1 boot on

mformat -i "${diskimg}"@@"${alignment}" -t $((size>>20)) -h 64 -s 32 -v "volname"

这是生成的图像文件的图表:

分区图像文件

答案3

您想要格式化磁盘映像文件中的一个分区,而不是整个映像文件。在这种情况下,您需要使用losetup来告诉 linux 使用该映像文件作为环回设备。

注意:losetup需要 root 权限,因此必须以 root 身份或使用 sudo 运行。它使用/创建的设备/dev/loop*也需要 root 权限才能访问和使用。

例如(作为根)

# losetup /dev/loop0 ./sdcard.img

# fdisk -l /dev/loop0
Disk /dev/loop0: 1 MiB, 1048576 bytes, 2048 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x54c246ab

Device       Boot Start   End Sectors   Size Id Type
/dev/loop0p1          1  1023    1023 511.5K  c W95 FAT32 (LBA)
/dev/loop0p2       1024  2047    1024   512K 83 Linux

# file -s /dev/loop0p1
/dev/loop0p1: data

# mkfs.vfat /dev/loop0p1 
mkfs.fat 3.0.28 (2015-05-16)
Loop device does not match a floppy size, using default hd params

# file -s /dev/loop0p1
/dev/loop0p1: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, root entries 512, sectors 1023 (volumes <=32 MB) , Media descriptor 0xf8, sectors/FAT 1, sectors/track 32, heads 64, serial number 0xfa9e3726, unlabeled, FAT (12 bit)

最后,从环回设备中分离图像:

# losetup -d /dev/loop0

请参阅man losetup了解更多详情。

答案4

由于 @user310346 的答案被证明特别棘手和脆弱,无法适应生成用于 Box86 的 FAT16 文件系统,所以我花了一段时间来研究它,并提出了三件有用的事情:

第一的, user310346 的答案中的大部分样板是为了允许您指定任意分割大小(以字节为单位),然后通过适当的舍入计算驱动器大小。如果您愿意指定图像/驱动器尺寸(我需要因为我正在尝试匹配 Box86 中的 CHS 预设),然后 pared 可以自动从中导出其余部分。

第二, 这分手手册从 2002 年开始,列表mkfsmkpartfs命令理论上应该能够执行此类操作,因此值得查看更改日志以了解它们的变化。也许它们只是变成了一些更晦涩的东西,但仍然不需要 root 权限。

第三, 感谢博克斯手册,我发现,如果你要使用 mtools,那么获得一个可用的文件系统会更容易全部工作。

#!/bin/sh
cd "$(dirname "$(readlink -f "$0")")" || exit

SRC_DIR="combined_disk"
IMG_NAME="combined_disk.img"

# Size for the hard drive image
# (Here's one that's in 86Box's CHS presets)
CYLINDERS=1036
HEADS=16
SECTORS=63

# Work around partition=1 not being possible on the command-line AFAIK
mtools_tmp="$(mktemp -d --tmpdir make_disk.XXXXXXXXXX)"
mtools_conf="${mtools_tmp}/mtoolsrc"
echo "drive c: file=\"${IMG_NAME}\" partition=1" >"$mtools_conf"
export MTOOLSRC="${mtools_conf}"
cleanup() {
    rm -rf "${mtools_tmp}"
}
trap cleanup EXIT

rm -f "${IMG_NAME}.img"
truncate -s "$((CYLINDERS * HEADS * SECTORS * 512))" "$IMG_NAME"

mpartition -I -t "$CYLINDERS" -h "$HEADS" -s "$SECTORS" c: 2>&1
mpartition -c -T 6 -t "$CYLINDERS" -h "$HEADS" -s "$SECTORS" c:
mformat c:
mcopy -s "$SRC_DIR"/* c:

相关内容