Linux 可以挂载普通的 Time Machine 稀疏捆绑磁盘映像目录吗?

Linux 可以挂载普通的 Time Machine 稀疏捆绑磁盘映像目录吗?

我想看看 Linux 是否可以通过网络共享安装和读取 Time Capsule 上本地存储的文件。比如这个问题,我正在寻找至少可以复制只读功能的东西錯誤连接并安装稀疏捆绑磁盘映像。

SMB 安装非常简单,因为 Time Capsule 可以使用这两种方式共享法新社中小企业,但我不太确定稀疏磁盘包是否可以作为重建的 HFS+ 目录安装。

对于能够解析此 DMG 格式的有效挂载命令或指向适当包的指针,将获得加分。

如果不清楚的话 - 这就是从 Mac 的终端安装时波段文件在我看来的样子,也是我期望 Linux 在无法安装以大量二进制波段文件编码的实际文件系统的情况下所看到的样子。

host:iMac.sparsebundle mike$ ls -la
total 24
drwxrwxrwx@     7 mike  staff      264 Jul  5 10:01 .
drwx------      6 mike  staff      264 Mar 26 13:11 ..
-rwxrwxrwx      1 mike  staff      499 Feb 24 15:33 Info.bckup
-rwxrwxrwx      1 mike  staff      499 Feb 24 15:33 Info.plist
drwxrwxrwx  31101 mike  staff  1057390 Jun 17 20:19 bands
-rwxrwxrwx      1 mike  staff      532 Jun 24 22:06 com.apple.TimeMachine.MachineID.plist
-rwxrwxrwx      1 mike  staff        0 Feb 24 15:33 token
host:iMac.sparsebundle mike$ ls -la bands | head -10
total 1582092552
-rwxrwxrwx  1 mike  staff  8388608 Jul  5 08:33 0
-rwxrwxrwx  1 mike  staff  8388608 May 31 13:02 1
-rwxrwxrwx  1 mike  staff  8388608 Jun 24 22:16 10
-rwxrwxrwx  1 mike  staff  8388608 Mar 19 17:15 1000
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 10000
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 10001
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 10002
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 10003
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 10004
host:iMac.sparsebundle mike$ ls -la bands | tail -10
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:51 fff6
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:51 fff7
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:51 fff8
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:51 fff9
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:51 fffa
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 fffb
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 fffc
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 fffd
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 fffe
-rwxrwxrwx  1 mike  staff  8388608 May 31 00:50 ffff
host:~ mike$ ls -la bands|wc -l
   96636

答案1

较新的 MacOS 版本不使用 HFS+ 作为 Time Machine 稀疏包的底层 FS,而是使用 APFS。APFS 的优势在于它本身(即:在 FS 本身内部)支持快照。

这是在 Fedora Workstation 33 上测试并运行的完整教程,介绍如何在 SMB 上挂载 MacOS Time Machine 备份文件夹,然后挂载 sparsebundle,然后挂载 APFS 文件系统并访问所有快照。

如何在 Linux 上将 Mac Time Machine 备份稀疏包目录(在 SMB 上)挂载为可浏览的文件系统

本指南在 Fedora 33 上测试。

先决条件

我们需要sparsebundlefs将 sparsebundle 目录挂载为 DMG 磁盘映像。此外,我们需要 APFS fuse 驱动程序和用户空间实用程序来将 Mac APFS 分区挂载到 DMG 文件中。使用二进制文件apfsutil,我们甚至可以浏览 APFS 分区内的快照。

# we assume the directory /usr/local/bin exists and is in the path

# become root
sudo su

# install sparsebundlefs (https://github.com/torarnv/sparsebundlefs)
yum -y install fuse-devel
cd
git clone https://github.com/torarnv/sparsebundlefs.git
cd sparsebundlefs
make
mv sparsebundlefs /usr/local/bin

# install apfs-fuse (https://github.com/sgan81/apfs-fuse, https://linuxnewbieguide.org/how-to-mount-macos-apfs-disk-volumes-in-linux/)
yum -y install bzip2-devel fuse3-devel
cd
git clone https://github.com/sgan81/apfs-fuse.git
cd apfs-fuse
git submodule init
git submodule update
mkdir build
cd build
cmake ..
make
mv apfs* /usr/local/bin
ln -s /usr/local/bin/apfs-fuse /usr/sbin/mount.apfs

脚本

创建一个包含以下内容的文件mount_timebackup.sh。别忘了chmod +x

#!/usr/bin/env bash

# mount_timebackup.sh

## CHANGE VARIABLES HERE
SMB_PATH="\\\\server_name_or_ip_address/share"
SMB_USERNAME="some_username"
SMB_PASSWORD="some_password"
## --END--

SMB_MNT="/mnt/timebackup_sparsebundle"
SMB_OPTIONS="user=${SMB_USERNAME},pass=${SMB_PASSWORD},ro"
SB_MNT="/mnt/sparsebundlefs"
SB_DMG="${SB_MNT}/sparsebundle.dmg"
APFS_MNT="/mnt/apfs"

# Check availability of binaries
SBFS_BIN="$(which sparsebundlefs)"
if [[ -z "${SBFS_BIN}" ]]; then echo "[!] sparsebundlefs binary not found, aborting."; exit 1; fi

PARTED_BIN="$(which parted)"
if [[ -z "${PARTED_BIN}" ]]; then echo "[!] parted binary not found, aborting."; exit 1; fi

LOSETUP_BIN="$(which losetup)"
if [[ -z "${LOSETUP_BIN}" ]]; then echo "[!] losetup binary not found, aborting."; exit 1; fi

APFSUTIL_BIN="$(which apfsutil)"
if [[ -z "${APFSUTIL_BIN}" ]]; then echo "[!] apfsutil binary not found, aborting."; exit 1; fi

# Make directories
mkdir -p "${SMB_MNT}" 2>/dev/null
mkdir -p "${SB_MNT}" 2>/dev/null
mkdir -p "${APFS_MNT}" 2>/dev/null

# Mount SMB share
if ! grep -q ${SMB_MNT} /proc/mounts
then
    echo "[i] Mounting share \"${SMB_PATH}\" as user ${SMB_USERNAME} on ${SMB_MNT}..."
    if ! mount.cifs "${SMB_PATH}" "${SMB_MNT}" -o "${SMB_OPTIONS}"
    then
        echo "[!] Error mounting SMB share, check output. Aborting."
        exit 1
    fi
else
    echo "[i] SMB share ${SMB_PATH} found on ${SMB_MNT}..."
fi

# Mount the sparse bundle
if ! grep -q ${SB_MNT} /proc/mounts
then
    echo "[i] Finding sparsebundle directory..."
    SB="$(find "${SMB_MNT}" -maxdepth 1 -type d -name '*.sparsebundle')"

    if [[ -z "${SB}" ]]
    then
        echo "[!] Sparsebundle directory not found under $SMB_MNT, aborting."
        exit 1
    fi

    echo "[i] Mounting sparsebundle directory \"${SB}\" as sparsebundle filesystem on ${SB_MNT}..."
    if ! "${SBFS_BIN}" "$SB" "$SB_MNT"
    then
        echo "[!] Error mounting sparsebundlefs, check output. Aborting."
        exit 1
    fi
else
    echo "[i] Sparsebundle mount found on ${SB_MNT}..."
fi

# Mount the APFS partition as loopback device
LO="$("${LOSETUP_BIN}" | grep "${SB_MNT}" | awk '{print $1}')"
if [[ -z "${LO}" ]]
then
    echo "[i] Determining characteristics of APFS filesystem inside ${SB_DMG}..."
    OFF="$("${PARTED_BIN}" "${SB_DMG}" unit B print 2>/dev/null | tr 'B' ' ' | awk '/disk image/ {print $2}')"
    SZ="$("${PARTED_BIN}" "${SB_DMG}" unit B print 2>/dev/null | tr 'B' ' ' | awk '/disk image/ {print $4}')"

    if [[ -z "${OFF}" ]] || [[ -z "${SZ}" ]]
    then
        echo "[!] Unable to determine APFS filesystem offset and size characteristics, aborting."
        exit 1
    fi

    echo "Mounting APFS filesystem inside ${SB_DMG} from offset ${OFF} with max size ${SZ} on loopback device..."
    LO="$("${LOSETUP_BIN}" -f "${SB_DMG}" --offset ${OFF} --sizelimit ${SZ} --show)"
    if [[ -z "${LO}" ]]
    then
        echo "[!] Error mounting APFS filesystem, aborting."
        exit 1
    fi
else
    echo "[i] APFS filesystem found at ${LO}."
fi

# List snapshots
echo "[i] Listing available snapshots in the APFS filesystem at ${LO}:"
"${APFSUTIL_BIN}" "${LO}"

echo "[i] To mount the latest available snapshot, run:"
echo "    mount.apfs \"${LO}\" \"${APFS_MNT}\""
echo
echo "[i] To mount a specific snapshot, run:"
echo "    mount.apfs -o snap=XXXXX \"${LO}\" \"${APFS_MNT}\""

用法

编辑mount_timebackup.sh文件并输入 SMB 路径、用户名和密码。然后运行脚本。它将显示如下内容:

14:07 ★root(su)@fedora /root/bin
0» ./mount_timebackup.sh
[i] Mounting share "\\192.168.1.1/My_Timebackup" as user edward on /mnt/timebackup_sparsebundle...
[i] Finding sparsebundle directory...
[i] Mounting sparsebundle directory "/mnt/timebackup_sparsebundle/edward.sparsebundle" as sparsebundle filesystem on /mnt/sparsebundlefs...
[i] Determining characteristics of APFS filesystem inside /mnt/sparsebundlefs/sparsebundle.dmg...
Mounting APFS filesystem inside /mnt/sparsebundlefs/sparsebundle.dmg from offset 209735680 with max size 22685610287104 on loopback device...
[i] Listing available snapshots in the APFS filesystem at /dev/loop0:
Volume 0 B2853571-BC03-4DCC-91B7-295D046776BF
---------------------------------------------
Role:               Backup
Name:               Reservekopieën van Edward (Case-sensitive)
Capacity Consumed:  177614307328 Bytes
FileVault:          No
Snapshots:
    587 : 'com.apple.TimeMachine.2021-05-27-131216.backup'
    3122 : 'com.apple.TimeMachine.2021-06-03-142024.backup'
    5354 : 'com.apple.TimeMachine.2021-06-10-185257.backup'
    7193 : 'com.apple.TimeMachine.2021-06-17-210159.backup'
    8278 : 'com.apple.TimeMachine.2021-06-24-135457.backup'
    10556 : 'com.apple.TimeMachine.2021-07-01-221410.backup'
    12345 : 'com.apple.TimeMachine.2021-07-09-155806.backup'
    13326 : 'com.apple.TimeMachine.2021-07-17-074435.backup'
    13747 : 'com.apple.TimeMachine.2021-07-24-112952.backup'
    16670 : 'com.apple.TimeMachine.2021-07-31-085515.backup'
    17164 : 'com.apple.TimeMachine.2021-08-25-112049.backup'
    19466 : 'com.apple.TimeMachine.2021-09-01-202809.backup'
    21613 : 'com.apple.TimeMachine.2021-09-08-200654.backup'
    24023 : 'com.apple.TimeMachine.2021-09-15-202105.backup'
    25807 : 'com.apple.TimeMachine.2021-09-23-194219.backup'
    27372 : 'com.apple.TimeMachine.2021-09-30-161110.backup'
    29229 : 'com.apple.TimeMachine.2021-10-08-064900.backup'
    30021 : 'com.apple.TimeMachine.2021-10-14-222820.backup'
    30260 : 'com.apple.TimeMachine.2021-10-22-132638.backup'
    33163 : 'com.apple.TimeMachine.2021-10-30-141729.backup'
    36728 : 'com.apple.TimeMachine.2021-11-06-102305.backup'
    40140 : 'com.apple.TimeMachine.2021-11-13-201741.backup'
    41362 : 'com.apple.TimeMachine.2021-11-21-100951.backup'
    42977 : 'com.apple.TimeMachine.2021-11-28-212032.backup'
    45488 : 'com.apple.TimeMachine.2021-12-06-155539.backup'
    48657 : 'com.apple.TimeMachine.2021-12-13-154439.backup'
    50554 : 'com.apple.TimeMachine.2021-12-20-084732.backup'
    51856 : 'com.apple.TimeMachine.2022-02-06-105522.backup'
    54178 : 'com.apple.TimeMachine.2022-02-13-215427.backup'
    57082 : 'com.apple.TimeMachine.2022-02-21-151624.backup'
    58494 : 'com.apple.TimeMachine.2022-03-06-155624.backup'
    60265 : 'com.apple.TimeMachine.2022-03-13-124536.backup'
    64198 : 'com.apple.TimeMachine.2022-03-20-160040.backup'
    67262 : 'com.apple.TimeMachine.2022-03-25-173848.backup'
    68136 : 'com.apple.TimeMachine.2022-03-26-233827.backup'
    69024 : 'com.apple.TimeMachine.2022-03-28-165918.backup'
    69886 : 'com.apple.TimeMachine.2022-03-29-164136.backup'
    70515 : 'com.apple.TimeMachine.2022-03-30-194139.backup'
    70869 : 'com.apple.TimeMachine.2022-04-01-014510.backup'
    72140 : 'com.apple.TimeMachine.2022-04-02-082134.backup'
    72965 : 'com.apple.TimeMachine.2022-04-08-204109.backup'
    73092 : 'com.apple.TimeMachine.2022-04-10-194926.backup'
    73745 : 'com.apple.TimeMachine.2022-04-11-204535.backup'
    74595 : 'com.apple.TimeMachine.2022-04-12-204033.backup'
    75319 : 'com.apple.TimeMachine.2022-04-13-190833.backup'
    75971 : 'com.apple.TimeMachine.2022-04-14-222526.backup'
    77237 : 'com.apple.TimeMachine.2022-04-16-083710.backup'
    77319 : 'com.apple.TimeMachine.2022-04-17-094739.backup'
    77619 : 'com.apple.TimeMachine.2022-04-18-090536.backup'
    77705 : 'com.apple.TimeMachine.2022-04-18-104921.backup'
    77825 : 'com.apple.TimeMachine.2022-04-19-225314.backup'
    78369 : 'com.apple.TimeMachine.2022-04-20-171232.backup'
    78469 : 'com.apple.TimeMachine.2022-04-20-190918.backup'
    78598 : 'com.apple.TimeMachine.2022-04-20-203829.backup'
    78668 : 'com.apple.TimeMachine.2022-04-20-220645.backup'
    78794 : 'com.apple.TimeMachine.2022-04-21-155554.backup'
    79746 : 'com.apple.TimeMachine.2022-04-30-101539.backup'
    79836 : 'com.apple.TimeMachine.2022-04-30-112852.backup'
    79863 : 'com.apple.TimeMachine.2022-04-30-114329.backup'
    79937 : 'com.apple.TimeMachine.2022-04-30-122935.backup'
    80049 : 'com.apple.TimeMachine.2022-05-01-083701.backup'
    80131 : 'com.apple.TimeMachine.2022-05-01-093828.backup'
    80253 : 'com.apple.TimeMachine.2022-05-01-110758.backup'
    80289 : 'com.apple.TimeMachine.2022-05-01-122415.backup'

[i] To mount the latest available snapshot, run:
    mount.apfs "/dev/loop0" "/mnt/apfs"

[i] To mount a specific snapshot, run:
    mount.apfs -o snap=XXXXX "/dev/loop0" "/mnt/apfs"

卸载

# as root, in this specific order
umount /mnt/apfs
losetup -D
umount /mnt/sparsebundlefs
umount /mnt/timebackup_sparsebundle

答案2

您可以将以下两者结合使用:

用于读取 Mac OS 稀疏捆绑磁盘映像的 FUSE 文件系统

苹果的 Time Machine 融合只读文件系统

第一个负责处理 .sparsebundle 格式,将其呈现为 dmg 文件,然后可以像平常一样安装。第二个负责处理 Time Machine 使用的目录硬链接。

答案3

这是@TorArneVestbø 答案的扩展。

安装完成后https://github.com/torarnv/sparsebundlefshttps://github.com/abique/tmfs您需要在 Bash 中运行以下脚本。确保将开头的两个变量更新为源和目标。

SB="/path/to/your/Backup.sparsebundle"
TM_MNT="/path/to/where/to/mount"

# Make directories
mkdir -p "$TM_MNT"
SB_MNT=`mktemp --tmpdir -d sparsebundle_mnt.XXX`
SB_DMG="$SB_MNT/sparsebundle.dmg"
HFS_MNT=`mktemp --tmpdir -d hfsx_mnt.XXX`

# Mount the sparse bundle
sudo `which sparsebundlefs` "$SB" "$SB_MNT"

# Mount the HFS+ partition
OFF=`sudo parted "$SB_DMG" unit B print | tr 'B' ' ' | awk '/hfsx/ {print $2}'`
SZ=`sudo parted "$SB_DMG" unit B print | tr 'B' ' ' | awk '/hfsx/ {print $4}'`
LO=`sudo losetup -f "$SB_DMG" --offset $OFF --sizelimit $SZ --show`
sudo mount -t hfsplus -r "$LO" "$HFS_MNT"

# Mount the Time Machine filesystem
sudo `which tmfs` "$HFS_MNT" "$TM_MNT" -ouid=$(id -u $USER),gid=$(id -g $USER),allow_other

最终的安装将由您访问(只要$TM_MNT您可以访问)。如果 FUSE 未设置为允许其他用户,则最后一行可能会失败,它会告诉您如何修复它。

要卸载您需要执行以下操作:

sudo umount "$TM_MNT"
sudo rmdir "$TM_MNT"
sudo umount "$HFS_MNT"
sudo rmdir "$HFS_MNT"
sudo losetup -d "$LO"
sudo umount "$SB_MNT"
sudo rmdir "$SB_MNT"

这已在 Fedora 28 系统上测试并且运行良好。

答案4

上述来自 Alexandre Bicque 的帖子提供了一个 Linux(?unix)程序,该程序将打开存储在 Mac 格式的 HFS+ 磁盘或磁盘分区上的 Time Machine sparsebundle,从而允许读取 Linux 服务器上的文件。

将它设置起来并不容易。它是用 C++ 编写的,需要 3 个 C++ 库 - cmake、FUSE 和 Boost,并具有特定的最低版本(可能不是我的 Ubuntu Server 10.04 的默认最新版本)。它还需要查找和安装 g++ 编译器和上述库。

我使用 Ubuntu 服务器 10.04,并不是一名优秀的程序员。然而,经过大量的工作和时间,我终于成功安装了所有必要的库,编译并链接了 tmfs 包,并开始使用它。它确实可以工作,允许安装 TimeMachine Time Capsule。但是,它要求写入 sparsebundle 映像的磁盘是 HFS+ 磁盘或分区。如果映像是在 Linux 服务器上的 NTFS 或 ext2/ext3/ext4 文件系统上写入的,它将无法工作。

从 Apple 的 OS X 10.7(Lion)开始,如果将 Time Machine(sparsebundle)映像安装在 Windows(smb/Samba)Linux 共享上,它将不再起作用,并且需要运行 Linux/Unix Netatalk(afpdplus avahi-daemon)服务才能将 Linux 用作 Time Machine 服务器。

我花了很多时间寻找另一种解决方案。我认为 Linux/Unix C++ 程序员可以做得比我更好,扩展 Alexandre Bicque 的工作以允许使用 ext4 或 ntfs 文件系统。我正在尝试弄清楚如何做到这一点,但还有很长的路要走。

我认为这需要我更好地理解保险丝(用户空间文件系统)以及boost::filesystem系统开发助手才能继续前进。

相关内容