是否可以访问ZFS校验和来比较文件

我有一台FreeNAS 8机器(FreeBSD 8.2-RELEASE-p1),上面有两个不同的共享。 我正在将文件从Share1迁移到Share2。 这些共享有不同的目录结构和命名约定。 我正在寻找一种方法来validationShare1上的文件在Share2上实际存在(而且是准确的)。

我的计划基本上是对两个共享上的每个文件进行校验,并确保Share1集中的所有校验和存在于Share2集中。 我可以用bash脚本相对容易地做到这一点,但是生成每个校验和集会花费很长时间。 我的问题是:是否可以访问本机ZFS校验和使用它们进行比较?

我不认为有可能从ZFS文件系统中提取块级校验和,但是由于校验和位于块级,而不是文件级,所以它可能无法帮助您。

前一段时间,我编写了几个程序来生成文件系统清单,并将现有文件系统与该清单进行比较。

这是chksum.pl

#! /usr/bin/perl # # generate a system manifest # use strict; use File::Find; use Digest::MD5; our %config; $| = 1; &main; exit; sub initialize { my ($exclude_next, $include_next, @ex, @in, @ex_pats, @in_pats, %in, @x); # the exclude/include list looks like what you would pass to rsync my $elist = ['--exclude' => '/var/log', '--exclude' => '/var/tmp', '--exclude' => '/tmp', ]; foreach my $op (@$elist) { if ($op eq '--exclude') { $exclude_next = 1; } elsif ($op eq '--include') { $include_next = 1; } elsif ($op eq '--delete') { # ignore } else { if ($exclude_next) { push(@ex, $op); } elsif ($include_next) { push(@in, $op); } else { warn "don't know what to do with $op\n"; } $include_next = 0; $exclude_next = 0; } } $config{'exclude_list'} = \@ex; $config{'include_list'} = \@in; @ex_pats = map(glob($_), @ex); @in_pats = map(glob($_), @in); # print STDERR "exclusion patterns:\n", join("\n", @ex_pats), "\n\n"; # print STDERR "inclusion patterns:\n", join("\n", @in_pats), "\n\n"; # remove exclusions that exactly match inclusions foreach my $pat (@in_pats) { $in{$pat}++; } foreach my $pat (@ex_pats) { next if $in{$pat}; push(@x, $pat); } $config{'ex_pats'} = \@x; } sub wanted { my($type, $extra); my $path = $File::Find::name; my @ex = grep($path =~ m"^$_", @{$config{'ex_pats'}}); my($mode, $uid, $gid, $dev) = (lstat($path))[2,4,5,6]; if (scalar(@ex) > 0) { # if we're excluding, and it was a dir, don't bother to descend $File::Find::prune = -d _; return; } $mode &= 07777; # mask off mode bits if (-d _) { $type = "dir "; } elsif (-l _) { $type = "link"; $extra = "\"" . readlink($path) . "\""; } elsif (-f _) { $type = "file"; $extra = &md5sum($path); return unless defined($extra); } elsif (-p _) { $type = "pipe"; } elsif (-S _) { $type = "sock"; } elsif (-b _) { $type = "bdev"; $extra = "\"" . ($dev >> 8) . " " . ($dev & 0377) . "\""; } elsif (-c _) { $type = "cdev"; $extra = "\"" . ($dev >> 8) . " " . ($dev & 0377) . "\""; } else { $type = "unk "; } printf "%s 0%04o %d %d \"%s\"", $type, $mode, $uid, $gid, $path; print " $extra" if $extra; print "\n"; } sub md5sum { my $file = shift; my $context = Digest::MD5->new; unless(open(F, $file)) { warn "WARNING: couldn't open $file: $!\n"; return; } $context->addfile(*F); close(F); my $digest = $context->hexdigest; return($digest); } sub main { &initialize; &find({no_chdir => 1, wanted => \&wanted}, '/'); } 

这里是verify_sum.pl

 #! /usr/bin/perl # verify that a system matches the sum file produced by chksum.pl use strict; use File::Find; use Digest::MD5; use Text::ParseWords; our %config; $| = 1; &main; exit; sub initialize { my ($exclude_next, $include_next, @ex, @in, @ex_pats, @in_pats, %in, @x); my $elist = ['--exclude' => '/var/log', '--exclude' => '/var/tmp', '--exclude' => '/tmp', ]; foreach my $op (@$elist) { if ($op eq '--exclude') { $exclude_next = 1; } elsif ($op eq '--include') { $include_next = 1; } elsif ($op eq '--delete') { # ignore } else { if ($exclude_next) { push(@ex, $op); } elsif ($include_next) { push(@in, $op); } else { warn "don't know what to do with $op\n"; } $include_next = 0; $exclude_next = 0; } } $config{'exclude_list'} = \@ex; $config{'include_list'} = \@in; @ex_pats = map(glob($_), @ex); @in_pats = map(glob($_), @in); # print STDERR "exclusion patterns:\n", join("\n", @ex_pats), "\n\n"; # print STDERR "inclusion patterns:\n", join("\n", @in_pats), "\n\n"; # remove exclusions that exactly match inclusions foreach my $pat (@in_pats) { $in{$pat}++; } foreach my $pat (@ex_pats) { next if $in{$pat}; push(@x, $pat); } $config{'ex_pats'} = \@x; } sub md5sum { my $file = shift; my $context = Digest::MD5->new; unless(open(F, $file)) { warn "WARNING: couldn't open $file: $!\n"; return; } $context->addfile(*F); close(F); my $digest = $context->hexdigest; return($digest); } sub wanted { my $path = $File::Find::name; my @ex = grep($path =~ m"^$_", @{$config{'ex_pats'}}); if (scalar(@ex) > 0) { # if we're excluding, and it was a dir, don't bother to descend $file::Find::prune = -d $path; return; } if (! $config{'seen'}->{$path}) { warn "new file: $path\n"; $config{'new'}++; } } sub main { $config{'mismatch'} = 0; $config{'missing'} = 0; $config{'new'} = 0; &initialize; while (<>) { chomp; my ($type, $mode, $uid, $gid, $path, $extra) = &shellwords($_); my ($etype, $eextra); $mode = oct($mode); my($emode, $euid, $egid, $edev) = (lstat($path))[2,4,5,6]; if (! -e _) { warn "missing file: $path\n"; $config{'missing'}++; next; } $emode &= 07777; if (-d _) { $etype = "dir"; } elsif (-l _) { $etype = "link"; $eextra = readlink($path); } elsif (-f _) { $etype = "file"; $eextra = &md5sum($path); return unless defined($eextra); } elsif (-p _) { $etype = "pipe"; } elsif (-S _) { $etype = "sock"; } elsif (-b _) { $etype = "bdev"; $eextra = ($edev >> 8) . " " . ($edev & 0377); } elsif (-c _) { $etype = "cdev"; $eextra = ($edev >> 8) . " " . ($edev & 0377); } else { $etype = "unk"; } if ($type ne $etype) { warn "mismatch file type ($type vs $etype): $path\n"; $config{'mismatch'}++; } else { # types are the same, compare other factors if ($mode != $emode) { warn sprintf("mismatch mode (0%o vs 0%o): %s\n", $mode, $emode, $path); $config{'mismatch'}++; } if ($uid != $euid) { warn "mismatch uid ($uid vs $euid): $path\n"; $config{'mismatch'}++; } if ($gid != $egid) { warn "mismatch gid ($gid vs $egid): $path\n"; $config{'mismatch'}++; } if ($extra ne $eextra) { if ($etype eq 'link') { warn "mismatch link target ($extra vs $eextra): $path\n"; } elsif ($etype eq 'file') { warn "mismatch file checksum ($extra vs $eextra): $path\n"; } elsif ($etype eq 'bdev' or $etype eq 'cdev') { warn "mismatch device node ($extra vs $eextra): $path\n"; } $config{'mismatch'}++; } } $config{'seen'}->{$path}++; } # now walk the filesystem looking for "new" files &find({no_chdir => 1, wanted => \&wanted}, '/'); print "$config{'mismatch'} files changed\n"; print "$config{'missing'} files missing\n"; print "$config{'new'} new files\n"; if ($config{'mismatch'} > 0 or $config{'missing'} > 0 or $config{'new'} > 0) { exit 1; } exit 0; } 

您可能需要稍微调整这些脚本,比如排除列表,比较的根目录等。