#!/usr/bin/perl # TP synchronisation de fichiers en perl # solution basée sur la question 4 et qui ne tient pas compte des méta-données # # Question 7 # # Antoine Miné # 26/01/2007 # ceci n'a pas changé depuis mirroir5.pl use File::Copy; $doit = 0; foreach (@ARGV) { if ($_ eq "--doit") { $doit = 1; } elsif (!defined($dirB)) { $dirB = $_; } elsif (!defined($dirA)) { $dirA = $_; } else { die "argument $_ en trop"; } } die "utilisation: $0 [--doit] repertoire-courant repertoire-archive" unless defined($dirA) && defined($dirB); sub parcours { my $dir = shift; opendir(DIR,"$root/$dir") or return; my @files = readdir(DIR) or return; closedir(DIR); foreach (@files) { next if /^\.\.?$/; next if /^\.etat$/; $filename = "$dir/$_"; $fullfilename = "$root/$filename"; if (-d $fullfilename) { parcours($filename); } elsif (-f $fullfilename) { $result = `sha1sum "$fullfilename"`; chomp $result; $result =~ s/ .*$//; $table{$filename} = $result; } } } sub sauvegarde { open(ETAT,">$root/.etat") or die "echec d'écriture de $root/.etat ($!)"; for (keys %table) { print ETAT "$table{$_} $_\n"; } close(ETAT); } sub charge { open(ETAT,"$root/.etat") or die "echec de lecture de $root/.etat ($!)"; while () { ($signature,$fichier) = /^([^ ]*) (.*)$/; $table{$fichier} = $signature; } close(ETAT); } # copy_safe(file,src,dst): copie src/file => dst/file sub copy_safe { my $file = shift; my $src = shift; my $dst = shift; print "copie $src/$file => $dst/$file\n"; if ($doit) { copy("$src/$file","$dst/$file") or warn "échec de la copie de $src/$file vers $dst/$file ($!)"; } } # unlik_safe(file,src): efface src/file sub unlik_safe { my $file = shift; my $src = shift; print "détruit $src/$file\n"; if ($doit) { unlink "$src/$file" or warn "échec de la destruction de $src/$file ($!)"; } } # place dans %newA, l'état courant de $dirA # et dans %oldA, l'ancien état de $dirA (ou vide si pas de .etat) $root = $dirA; %table = (); parcours("."); %newA = %table; %table = (); if (-f "$root/.etat") { charge(); } %oldA = %table; # même chose pour B $root = $dirB; %table = (); parcours("."); %newB = %table; %table = (); if (-f "$root/.etat") { charge(); } %oldB = %table; # unifie A et B en un état newC for $i (keys %newA, keys %newB) { # l'étant antérieur de $i doit être identique dans A et B die "fichiers .etat non synchronisés (fichier $i)" if ($oldA{$i} ne $oldB{$i}); # cas où le fichier est identique en A et B # gère le cas où le fichier a été modifié ni dans A ni dans B # et celui où il a été modifié de manière identique dans A et dans B if ($newA{$i} eq $newB{$i}) { $newC{$i} = $newA{$i}; } # cas où le fichier a été modifié seulement dans A ou dans B elsif ($newA{$i} eq $oldA{$i}) { $newC{$i} = $newB{$i}; } elsif ($newB{$i} eq $oldB{$i}) { $newC{$i} = $newA{$i}; } # cas où le fichier a été modifié de manière différente dans A et dans B else { die "fichier $i modifié dans $dirA et $dirB"; } } # copie A<->B for $i (keys %newC) { next if !defined($newC{$i}); # ceci peut arriver! if ($newB{$i} ne $newC{$i}) { copy_safe($i,$dirA,$dirB); } if ($newA{$i} ne $newC{$i}) { copy_safe($i,$dirB,$dirA); } } # nettoyage A for $i (keys %newA) { unlik_safe($i,$dirA) if !defined($newC{$i}); } # nettoyage B for $i (keys %newB) { unlik_safe($i,$dirB) if !defined($newC{$i}); } # mise à jour des .etat if ($doit) { %table = %newC; $root = $dirA; sauvegarde(); $root = $dirB; sauvegarde(); }