Re: Аналог offline files от MS
On Thu, Nov 02, 2006 at 02:34:33PM +0300, Виталий Ищенко wrote:
> Думаю, что основная проблема в выборе софта для синхронизации (чтобы это
> было не просто копирование целиком папки при каждом подключении)
Если речь идет о локальной папке, и она на linux-е - у меня есть
perl скриптик на тему отбора изменившихся по snapshoot-файлу. Отберет
только изменившееся (зато все изменившееся в отличие от find). Работает
чуть медленнее чем File::Find в perl. Кстати - кто бы поругал :)
===============
#!/usr/bin/perl -w
use strict;
use integer;
sub cmpnames {
no locale;
return $a->{name} cmp $b->{name};
};
sub cmppaths($$)
{
no locale;
return $_[0] cmp $_[1];
};
sub filestats($$) {
my ($filename,$oldtime) = @_;
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat($filename);
my $cnewer = $ctime >= $oldtime;
my $filetype = 'o';
$filetype = (-r _ && -x _) ? 'd' : 'D' if -d _;
$filetype = 'f' if -f _;
$filetype = 'l' if -l _;
return ($filetype,$cnewer,$ino);
};
sub setgetentries($$$) {
my($path2tree,$oldtime,$fileproc) = @_;
$path2tree .= '/' unless ($path2tree eq '/' || $path2tree eq '' );
return sub ($$) {
my ($dirname,$dirunknown) = @_;
my @dirs=();
my @others=();
my ($dir,$entry,$filetype,$cnewer);
my $dirpath = $path2tree . $dirname;
opendir($dir,$dirpath);
if ($dirname ne '') {
$dirpath .= '/';
$dirname .= '/';
};
while ($entry = readdir($dir)) {
next if ($entry eq '..' || $entry eq '.');
my $filepath = $dirpath . $entry;
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)
= lstat($filepath);
$cnewer = $dirunknown || $ctime >= $oldtime;
$filetype = 'o';
$filetype = (-r _ && -x _) ? 'd' : 'D' if -d _;
$filetype = 'f' if -f _;
$filetype = 'l' if -l _;
if ($filetype eq 'd') {
push(@dirs,{name => $entry, ino => $ino, cnewer => $cnewer}); }
else {
&$fileproc(($dirname . $entry),$cnewer,$filetype);
};
};
closedir($dir);
return [ sort cmpnames @dirs ];
};
};
sub getlevel ($$$$) {
my ($dirunknown,$Dirname,$getentries,$parent) = @_[0..3];
# my $parent = (scalar @_ > 3) ? $_[3] : 0;
my $level = { name => $Dirname,
entries => &$getentries($Dirname,$dirunknown),
unknown => $dirunknown,
entnum => 0,
entindex => 0,
parent => $parent
};
# $level->{entries} = &$getentries($Dirname,$dirunknown);
$level->{entnum} = scalar @{$level->{entries}};
# $level->{name} = $level->{name} . '/' if $level->{name} gt '';
return $level;
};
sub setfileproc ($$:$) {
my ($TypeMask,$NewerFilesListName) = @_[0,1];
my ($FullFilesList,$NewerFilesList);
my $FullFilesListName = '';
if (scalar @_ > 2) {
$FullFilesListName = shift @_;
open $FullFilesList,">$FullFilesListName";
};
open $NewerFilesList,">$NewerFilesListName";
return sub ($$$) {
my ($filename,$fileisnewer,$filetype) = @_;
if ((index $TypeMask,$filetype,0) >= $[ ) {
print $FullFilesList "$filename\n" if ($FullFilesListName ne '');
print $NewerFilesList "$filename\n" if $fileisnewer;
};
};
};
sub findnewer ($$$:$) {
my ($treepath,$NewSnapshootName,$fileproc) = @_[0..2];
$treepath =~ s@/$@@ if ($treepath =~ m@.+/$@);
my $WorkSnapshoot;
my ($oldname,$oldino,$oldtime,$WorkSnapshootName,$troldname) = ('',0,0,'','');
if (scalar @_ > 3) {
$WorkSnapshootName= $_[3];
($oldtime,$oldino)= <$WorkSnapshoot> =~ m@^(.+)/(\d+)$@o if (open $WorkSnapshoot,"<$WorkSnapshootName");
};
open my $NewSnapshoot, ">$NewSnapshootName" or die "Can't open file to write new snapshoot";
my ($filetype,$cnewer,$ino) = filestats($treepath,$oldtime);
my $newtime = time;
print $NewSnapshoot "${newtime}/$ino\n";
my $dirunknown = $ino != $oldino;
my $getentries = &setgetentries($treepath,$oldtime,$fileproc);
my $curparent = &getlevel($dirunknown,'',$getentries,0);
$treepath .= '/' unless ($treepath eq '' || $treepath eq '/');
while (($curparent->{entindex} < $curparent->{entnum}) || ref $curparent->{parent}) {
while ($curparent->{entindex} < $curparent->{entnum}) {
my $file = $curparent->{entries}[$curparent->{entindex}++];
my ($filename,$fileisnewer,$ino) = ($curparent->{name} . $file->{name},$file->{cnewer},$file->{ino});
&$fileproc($filename,$fileisnewer,'d');
print $NewSnapshoot "${filename}/$ino\n";
(my $trfilename = $filename) =~ tr[/][\x00];
my $dircmp = cmppaths($troldname,$trfilename);
while ($dircmp < 0 && ($WorkSnapshootName ne '') && (not eof($WorkSnapshoot))) {
($oldname,$oldino) = <$WorkSnapshoot> =~ m@^(.+)/(\d+)$@o;
($troldname = $oldname) =~ tr[/][\x00];
$dircmp = cmppaths($troldname,$trfilename);
};
$dirunknown = ($dircmp != 0 || $ino != $oldino);
$curparent = &getlevel($dirunknown,$filename,$getentries,$curparent);
$curparent->{name} .= '/';
};
$curparent = $curparent->{parent} if (ref $curparent->{parent});
};
};
my $WorkSnapshootName = 'wsnsh';
my $NewSnapshootName = 'nsnsh';
my $treepath = '/home/dima';
my $types = 'dflo';
my $fileproc = &setfileproc($types,'-');
my $fullsort = (1 == 0);
&findnewer($treepath,$NewSnapshootName,$fileproc,$WorkSnapshootName);
====================
Отбор файлов происходит из каталога $treepath по snapshoot-файлу
$WorkSnapshootName (создается новый snapshoot $NewSnapshootName),
Функция, на которую указывает $fileproc, выполняет реальные действия.
Она получает в качестве аргументов:
1. путь к файлу относительно $treepath (без / впереди)
2. булево значение - изменился ли файл с ее точки зрения
3. тип файла - символ: d - каталог, f - обычный файл, l - симв. ссылка,
o - другой.
Поругайте плиз :)
WBR
Dmitri Ivanov
Reply to: