📄 rsyncfileio.pm
字号:
} if ( $attr->{mode} & S_HLINK_TARGET ) { $attr->{hlink_self} = 1; $attr->{mode} &= ~S_HLINK_TARGET; } } return ($attr, $partial);}sub attribGet{ my($fio, $f, $doHardLink) = @_; my($attr) = $fio->attribGetWhere($f); if ( $doHardLink && $attr->{type} == BPC_FTYPE_HARDLINK ) { $fio->log("$attr->{fullPath}: opening for hardlink read" . " (name = $f->{name})") if ( $fio->{logLevel} >= 4 ); my $fh = BackupPC::FileZIO->open($attr->{fullPath}, 0, $attr->{compress}); my $target; if ( defined($fh) ) { $fh->read(\$target, 65536); $fh->close; $target =~ s/^\.?\/+//; } else { $fio->log("$attr->{fullPath}: can't open for hardlink read"); $fio->{stats}{errorCnt}++; $attr->{type} = BPC_FTYPE_FILE; return $attr; } $target = "/$target" if ( $target !~ /^\// ); $fio->log("$attr->{fullPath}: redirecting to $target") if ( $fio->{logLevel} >= 4 ); $target =~ s{^/+}{}; ($attr) = $fio->attribGetWhere($f, 1, $target); $fio->log(" ... now got $attr->{fullPath}") if ( $fio->{logLevel} >= 4 ); } return $attr;}sub mode2type{ my($fio, $f) = @_; my $mode = $f->{mode}; if ( ($mode & S_IFMT) == S_IFREG ) { if ( defined($f->{hlink}) && !$f->{hlink_self} ) { return BPC_FTYPE_HARDLINK; } else { return BPC_FTYPE_FILE; } } elsif ( ($mode & S_IFMT) == S_IFDIR ) { return BPC_FTYPE_DIR; } elsif ( ($mode & S_IFMT) == S_IFLNK ) { return BPC_FTYPE_SYMLINK; } elsif ( ($mode & S_IFMT) == S_IFCHR ) { return BPC_FTYPE_CHARDEV; } elsif ( ($mode & S_IFMT) == S_IFBLK ) { return BPC_FTYPE_BLOCKDEV; } elsif ( ($mode & S_IFMT) == S_IFIFO ) { return BPC_FTYPE_FIFO; } elsif ( ($mode & S_IFMT) == S_IFSOCK ) { return BPC_FTYPE_SOCKET; } else { return BPC_FTYPE_UNKNOWN; }}## Set the attributes for a file. Returns non-zero on error.#sub attribSet{ my($fio, $f, $placeHolder) = @_; my($dir, $file); return if ( $placeHolder && $fio->{phase} > 0 ); if ( $f->{name} =~ m{(.*)/(.*)}s ) { $file = $2; $dir = "$fio->{shareM}/" . $1; } elsif ( $f->{name} eq "." ) { $dir = ""; $file = $fio->{share}; } else { $dir = $fio->{shareM}; $file = $f->{name}; } if ( $dir ne "" && (!defined($fio->{attribLastDir}) || $fio->{attribLastDir} ne $dir) ) { # # Flush any directories that don't match the first part # of the new directory. Don't flush the top-level directory # (ie: $dir eq "") since the "." might get sorted in the middle # of other top-level directories or files. # foreach my $d ( keys(%{$fio->{attrib}}) ) { next if ( $d eq "" || "$dir/" =~ m{^\Q$d/} ); $fio->attribWrite($d); } $fio->{attribLastDir} = $dir; } if ( !exists($fio->{attrib}{$dir}) ) { $fio->log("attribSet: dir=$dir not found") if ( $fio->{logLevel} >= 4 ); $fio->{attrib}{$dir} = BackupPC::Attrib->new({ compress => $fio->{xfer}{compress}, }); my $dirM = $dir; $dirM = $1 . "/" . $fio->{bpc}->fileNameMangle($2) if ( $dirM =~ m{(.*?)/(.*)}s ); my $path = $fio->{outDir} . $dirM; if ( -f $fio->{attrib}{$dir}->fileName($path) ) { if ( !$fio->{attrib}{$dir}->read($path) ) { $fio->log(sprintf("Unable to read attribute file %s", $fio->{attrib}{$dir}->fileName($path))); } else { $fio->log(sprintf("attribRead file %s", $fio->{attrib}{$dir}->fileName($path))) if ( $fio->{logLevel} >= 4 ); } } } else { $fio->log("attribSet: dir=$dir exists") if ( $fio->{logLevel} >= 4 ); } $fio->log("attribSet(dir=$dir, file=$file, size=$f->{size}, placeholder=$placeHolder)") if ( $fio->{logLevel} >= 4 ); my $mode = $f->{mode}; $mode |= S_HLINK_TARGET if ( $f->{hlink_self} ); $fio->{attrib}{$dir}->set($file, { type => $fio->mode2type($f), mode => $mode, uid => $f->{uid}, gid => $f->{gid}, size => $placeHolder ? -1 : $f->{size}, mtime => $f->{mtime}, }); return;}sub attribWrite{ my($fio, $d) = @_; my($poolWrite); if ( !defined($d) ) { # # flush all entries (in reverse order) # foreach $d ( sort({$b cmp $a} keys(%{$fio->{attrib}})) ) { $fio->attribWrite($d); } return; } return if ( !defined($fio->{attrib}{$d}) ); # # Set deleted files in the attributes. Any file in the view # that doesn't have attributes is flagged as deleted for # incremental dumps. All files sent by rsync have attributes # temporarily set so we can do deletion detection. We also # prune these temporary attributes. # if ( $d ne "" ) { my $dir; my $share; $dir = $1 if ( $d =~ m{.+?/(.*)}s ); $fio->viewCacheDir(undef, $dir); ##print("attribWrite $d,$dir\n"); ##$Data::Dumper::Indent = 1; ##$fio->log("attribWrite $d,$dir"); ##$fio->log("viewCacheLogKeys = ", keys(%{$fio->{viewCache}})); ##$fio->log("attribKeys = ", keys(%{$fio->{attrib}})); ##print "viewCache = ", Dumper($fio->{attrib}); ##print "attrib = ", Dumper($fio->{attrib}); if ( defined($fio->{viewCache}{$d}) ) { foreach my $f ( keys(%{$fio->{viewCache}{$d}}) ) { my $name = $f; $name = "$1/$name" if ( $d =~ m{.*?/(.*)}s ); if ( defined(my $a = $fio->{attrib}{$d}->get($f)) ) { # # delete temporary attributes (skipped files) # if ( $a->{size} < 0 ) { $fio->{attrib}{$d}->set($f, undef); $fio->logFileAction("skip", { %{$fio->{viewCache}{$d}{$f}}, name => $name, }) if ( $fio->{logLevel} >= 2 && $a->{type} == BPC_FTYPE_FILE ); } } elsif ( $fio->{phase} == 0 && !$fio->{full} ) { ##print("Delete file $f\n"); $fio->logFileAction("delete", { %{$fio->{viewCache}{$d}{$f}}, name => $name, }) if ( $fio->{logLevel} >= 1 ); $fio->{attrib}{$d}->set($f, { type => BPC_FTYPE_DELETED, mode => 0, uid => 0, gid => 0, size => 0, mtime => 0, }); } } } } if ( $fio->{attrib}{$d}->fileCount || $fio->{phase} > 0 ) { my $data = $fio->{attrib}{$d}->writeData; my $dirM = $d; $dirM = $1 . "/" . $fio->{bpc}->fileNameMangle($2) if ( $dirM =~ m{(.*?)/(.*)}s ); my $fileName = $fio->{attrib}{$d}->fileName("$fio->{outDir}$dirM"); $fio->log("attribWrite(dir=$d) -> $fileName") if ( $fio->{logLevel} >= 4 ); my $poolWrite = BackupPC::PoolWrite->new($fio->{bpc}, $fileName, length($data), $fio->{xfer}{compress}); $poolWrite->write(\$data); $fio->processClose($poolWrite, $fio->{attrib}{$d}->fileName($dirM), length($data), 0); } delete($fio->{attrib}{$d});}sub processClose{ my($fio, $poolWrite, $fileName, $origSize, $doStats) = @_; my($exists, $digest, $outSize, $errs) = $poolWrite->close; $fileName =~ s{^/+}{}; $fio->log(@$errs) if ( defined($errs) && @$errs ); if ( $doStats ) { $fio->{stats}{TotalFileCnt}++; $fio->{stats}{TotalFileSize} += $origSize; } if ( $exists ) { if ( $doStats ) { $fio->{stats}{ExistFileCnt}++; $fio->{stats}{ExistFileSize} += $origSize; $fio->{stats}{ExistFileCompSize} += $outSize; } } elsif ( $outSize > 0 ) { my $fh = $fio->{newFilesFH}; print($fh "$digest $origSize $fileName\n") if ( defined($fh) ); } return $exists && $origSize > 0;}sub statsGet{ my($fio) = @_; return $fio->{stats};}## Make a given directory. Returns non-zero on error.#sub makePath{ my($fio, $f) = @_; my $name = $1 if ( $f->{name} =~ /(.*)/s ); my $path; if ( $name eq "." ) { $path = $fio->{outDirSh}; } else { $path = $fio->{outDirSh} . $fio->{bpc}->fileNameMangle($name); } $fio->logFileAction("create", $f) if ( $fio->{logLevel} >= 1 ); $fio->log("makePath($path, 0777)") if ( $fio->{logLevel} >= 5 ); $path = $1 if ( $path =~ /(.*)/s ); File::Path::mkpath($path, 0, 0777) if ( !-d $path ); return $fio->attribSet($f) if ( -d $path ); $fio->log("Can't create directory $path"); $fio->{stats}{errorCnt}++; return -1;}## Make a special file. Returns non-zero on error.#sub makeSpecial{ my($fio, $f) = @_; my $name = $1 if ( $f->{name} =~ /(.*)/s ); my $fNameM = $fio->{bpc}->fileNameMangle($name); my $path = $fio->{outDirSh} . $fNameM; my $attr = $fio->attribGet($f); my $str = ""; my $type = $fio->mode2type($f); $fio->log("makeSpecial($path, $type, $f->{mode})") if ( $fio->{logLevel} >= 5 ); if ( $type == BPC_FTYPE_CHARDEV || $type == BPC_FTYPE_BLOCKDEV ) { my($major, $minor, $fh, $fileData); if ( defined($f->{rdev_major}) ) { $major = $f->{rdev_major}; $minor = $f->{rdev_minor}; } else { $major = $f->{rdev} >> 8; $minor = $f->{rdev} & 0xff; } $str = "$major,$minor"; } elsif ( ($f->{mode} & S_IFMT) == S_IFLNK ) { $str = $f->{link}; } elsif ( ($f->{mode} & S_IFMT) == S_IFREG ) { # # this is a hardlink # if ( !defined($f->{hlink}) ) { $fio->log("Error: makeSpecial($path, $type, $f->{mode}) called" . " on a regular non-hardlink file"); return 1; } $str = $f->{hlink}; } # # Now see if the file is different, or this is a full, in which # case we create the new file. # my($fh, $fileData); if ( $fio->{full} || !defined($attr) || $attr->{type} != $type || $attr->{mtime} != $f->{mtime} || $attr->{size} != $f->{size} || $attr->{uid} != $f->{uid} || $attr->{gid} != $f->{gid} || $attr->{mode} != $f->{mode} || $attr->{hlink_self} != $f->{hlink_self} || !defined($fh = BackupPC::FileZIO->open($attr->{fullPath}, 0, $attr->{compress})) || $fh->read(\$fileData, length($str) + 1) != length($str) || $fileData ne $str ) { $fh->close if ( defined($fh) ); $fh = BackupPC::PoolWrite->new($fio->{bpc}, $path, length($str), $fio->{xfer}{compress}); $fh->write(\$str); my $exist = $fio->processClose($fh, "$fio->{shareM}/$fNameM", length($str), 1); $fio->logFileAction($exist ? "pool" : "create", $f) if ( $fio->{logLevel} >= 1 ); return $fio->attribSet($f); } else { $fio->logFileAction("skip", $f) if ( $fio->{logLevel} >= 2 ); } $fh->close if ( defined($fh) );}## Make a hardlink. Returns non-zero on error.# This actually gets called twice for each hardlink.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -