iconv 模块(与 rsync 一起使用)以避免本地 NTFS 分区中的 Windows 非法文件名

iconv 模块(与 rsync 一起使用)以避免本地 NTFS 分区中的 Windows 非法文件名

我想将一个 NTFS 卷本地附加到我的 unix (Ubuntu) 计算机,并使用 rsync 将一些 unix 目录复制到其中,以便结果在 Windows 下可读。

我不关心所有权和权限。如果能保留修改日期就好了。我只需要目录和文件(符号链接也很好;但如果它们无法复制则不是问题)。

两个明显的问题是:区分大小写,以及 Windows 文件名中的非法字符。例如,在Linux中我可以有两个文件“a”和“A”;我可以将它们复制到 NTFS 卷,但在 Windows 中我将能够访问(最多?)其中之一。但我很高兴忽略这个问题。我感兴趣的是Windows文件名中的非法字符,它们是<、>、:、"、/、\、|、?和*(好吧,实际上也是ascii 0-31,但我不关心这个。以“.”结尾的文件也可能存在问题?)。

我希望 rsync 自动“重命名”,例如,将一个名为“a:”的文件改名为 a(COLON),最终得到一个合法名称(理想情况下,将 a(COLON) 翻译回 a:)

rsync 是否可以自动重命名文件以避免 Windows 中禁止的字符?

  • 据我了解 rsync 可以使用图标执行此类任务; Windows 文件名有标准的 iconv 模块吗? (我简要地研究了自己的 gconv 模块的编程,但缺乏 C 知识,这似乎太复杂了)。
  • 有人告诉我rdiff 备份可以做一些类似的转换,但主页只是提到“自动”完成一些事情,我不确定本地安装的 NTFS vomlume 是否会以可靠的方式触发重命名?
  • 我知道有保险丝 posixovl,但这对于我的目的来说似乎有点矫枉过正,而且似乎没有很好的记录(哪些字符将以哪种方式翻译?所有文件名都会被截断为 8.3 或其他什么吗?我可以避免携带所有者/的附加文件吗?权限信息,我不需要这些信息等等)
  • 我知道我可以通过使用例如柏油文件;但这不是我想要的。 (特别是,我想在Windows中进一步从NTFS卷复制到另一个备份分区,仅复制更改的文件)
  • 我知道“窗口名称" 安装 NTFS 时的选项;但这将防止创建有问题的文件,而不是重命名它们。

更新:看来我的问题不太清楚,让我举一个更明确的例子:例如,WINDOWS-1251 对我来说没有用。iconv -f utf-8 -t WINDOWS-1251//TRANSLIT 转变

123 abc ABC äö &:<!|

进入

123 abc ABC ao &:<!|

我需要一个代码页,例如 windows-filenams(它不存在),它将字符串转换为类似的内容

123 abc ABC äö &(COLON)(LT)!(PIPE)

更新2:我现在放弃了并将有问题的文件重命名为“手动”(即通过脚本)。从现在开始,每次运行 rsync 之前,我都会运行一个脚本来检查是否存在违规文件名(但不会自动处理重命名任何内容);我只是用

# find stuff containing forbidden chars
find $MYDIR -regex '.*/[^/]*[<>:*"\\|?][^/]*'
# find stuff containing dot as last character (supposedly bad for windows)
find $MYDIR -regex '.*\.'
# find stuff that is identical case insensitive
find $MYDIR -print0 | sort -z | uniq -diz | tr '\0' '\n'

(最后一行来自不区分大小写地搜索重复文件名

答案1

一个务实的解决方案是使用原始文件的硬链接在本地重现具有所需转换文件名的源目录,然后将此副本按原样 rsync 到 ntfs 文件系统。

例如,这个 Perl 脚本演示将层次结构复制到不需要的字符/tmp/a/中,并对不需要的字符/tmp/b/进行 url 编码(使用2 个十六进制数字),使其变为(硬链接),目录变为目录,依此类推:%file:bfile%3ab%b<ha>%25b%3cha%3e

#!/usr/bin/perl
use strict;
use File::Find;
my $startdir = '/tmp/a';
my $copydir = '/tmp/b';
sub handlefile{
    my $name = substr($File::Find::name,1);
    my $oldname = $startdir.$name;
    $name =~ s/([;, \t+%&<>:\"\\|?*])/sprintf('%%%02x',ord($1))/ge;
    $name = $copydir.$name;
    printf "from %s to %s\n",$oldname,$name;
    if(!-l and -d){ mkdir($name) or die $!; }
    else{ link($oldname,$name) or die $!; }
}
chdir($startdir) or die;
find(\&handlefile, '.');

然后你就可以rsync /tmp/b到你的ntfs了。这只是一个演示,需要解决 unicode 和 ntfs 的其他限制(例如最大文件名长度)。您还可以检查小写/大写冲突,并使用您喜欢的编码(:toCOLON等)。您可以进行第二遍来修复目录上的时间戳。除非您有数百万个文件,否则创建带有文件硬链接的目录结构副本所需的工作应该不会那么繁重。

相关内容