从 tar -c 恢复部分覆盖的磁带

从 tar -c 恢复部分覆盖的磁带

我有一个情况。我本来应该运行 tar -x 从磁带恢复 tar 文件,但我按了“c”并忘记将磁带设置为只读。文件位于 fsf 位置 23,但磁带有 27 个文件。我知道文件 23 丢失了,但是由于我按 ctrl+c 取消了 tar 命令,我是否仍然希望以某种方式恢复其他 tar 文件?我尝试了 fsf过去的文件 23,但我得到的只是输入/输出错误。

我在想也许可以使用 dd 从文件 23 进行转储,然后获取该文件并使用签名文件恢复工具,例如 photorec。这可行吗?

答案1

这个问题完全是特定于设备的,具体取决于驱动器硬件及其关联的驱动程序。

当搞砸磁带操作(例如中断写入)时,您可以轻松地在磁带上制作不可读的符号,甚至不可读的延伸。您已经表明您的驱动程序无法读取中止写入留下的垃圾,因为mt fsf仅发出一个 ioctl 要求驱动程序跳到下一个 EOF 标记。由于驱动程序返回 EIO,您可能无法让它做得更好。

根据该磁带对您的重要性,下一步可能是将其发送到精通磁带技术的法医恢复公司。您的数据可能在那里,但大多数驱动程序不知道如何应对您引入的标记缺陷。

答案2

尝试从磁带的另一端开始读取:

#! /bin/sh
set -e
TAPE=/dev/... # change me, you must use a non-rewinding device.
export TAPE

# Wind to the end of the tape.
mt eod

# Rewind to the beginning of the last file and then list it.
# It's possible I misunderstood the way end-of-data is signaled
# on the tape and if so perhaps this command should be mt bsfm 2,
# in which case you can just combine this with the loop below.
# For context here you can look at the entry for MT_ST_TWO_FM
# in "man st".
mt bsfm 1
tar -f "$TAPE" -t

# We just read a file so we're  going to need to rewind over it
# and then rewind more to get to the beginning of the previous file.
# I forget whether tar leaves the tape at EOF or just after it. I'm
# assuming here just after, but if it leaves the tape at the EOF
# mark, the 2 on the next line would need to be a 1.
while mt bsfm 2 
do
  tar -f "$TAPE" -t
done

那会列表我们可以从磁带末尾到达的所有 tar 存档的内容。当然,磁带开头也有档案,但您可以更轻松地列出这些档案:

while tar -f "$TAPE" -t
do
  true
done

mt eod操作要求驱动程序通过缠绕文件标记来缠绕到磁带的末尾。如果您只是用 SIGINT (Ctrl-C) 终止 tar 进程来中断磁带写入,那么这应该可以正常工作。从 SCSI 磁带驱动程序的角度来看,这看起来就像用户空间程序关闭了文件描述符,因此该位置应该有一个 EOF 标记,但没有实际的“损坏”。

但是,如果此处发生其他情况和/或上述方法不起作用,您可以通过向磁带驱动程序发送 SCSI 命令来要求磁带驱动程序将空间分配到介质末尾,从而获得不同的结果。磁带机要求它这样做。这与默认行为不同(即磁带驱动程序通过在文件上前移间距,以便它可以跟踪当前文件编号(以在mt status和等操作中报告mt tell)。要配置此功能,您可以使用MT_ST_FAST_EOMioctl。我不知道如何从命令行进行设置,您可能需要创建一个小型 C 程序,有点像这样:

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>

int main(int argc, char *argv[]) {
  (void)argc;
  (void)argv;
  struct mtop mt_cmd;
  mt_cmd.mt_op = MTSETDRVBUFFER;
  mt_cmd.mt_count = MT_ST_BOOLEANS | MT_ST_FAST_MTEOM;
  if (0 != ioctl(1, MTIOCTOP, &mt_cmd)) {
    perror("MTSETDRVBUFFER on stdout");
    return 1;
  }
  return 0;
}

为了节省样板,我假设磁带设备已经在该程序的标准输出上打开(即您像这样运行它:)./myprog >"$TAPE"

我没有测试过该代码,请谨慎使用。如果它告诉你的孩子他们可以养一只小狗,请不要责怪我。您可以使用另一个 C 程序来反转设置,但如果不关心持续的服务可用性,您也可以简单地重新启动计算机。

相关内容