[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: