}
}
-# get a file, optionally saving it locally
+# get a file, optionally saving it locally.
+# if a local filename is given, return true if the file was
+# found on the server and undef otherwise
+#
+# if no local filename is given, return the content of the
+# file, or undef if it was not found on the server
+#
+# on all other errors, die
sub fetchFile($;$) {
my ($remotefile, $localfile) = @_;
my $req = new HTTP::Request(GET => "$remotefile");
- if ($localfile and -e $localfile) {
- # Don't fetch unless more recent than local copy
- my $stat = stat($localfile);
- $req->header("If-Modified-Since" => time2str($stat->mtime));
+ if ($localfile) {
+ if (-e $localfile) {
+ # Don't fetch unless more recent than local copy
+ my $stat = stat($localfile);
+ $req->header("If-Modified-Since" => time2str($stat->mtime));
+ }
+ else {
+ ensureDir(dirPart($localfile));
+ }
}
- my $resp = $ua->request($req);
+ my $resp = $ua->request($req, $localfile);
if ($resp->is_success) { # 2xx codes
my $mtime = str2time($resp->header("Last-Modified"));
- if ($localfile) {
- if ($verbose) {
- print STDERR " -> success";
- print STDERR "; mtime ".time2str($mtime) if $mtime;
- print STDERR "\n";
- }
- ensureDir(dirPart($localfile));
-
- open (LOCAL, ">", "$localfile") or die "Can't open $localfile for writing ($!)";
- print LOCAL $resp->content or die "Error writing $localfile ($!)";
- close LOCAL or die "Error writing $localfile ($!)";
+ if ($verbose) {
+ print STDERR " -> success";
+ print STDERR "; mtime ".time2str($mtime) if $mtime;
+ print STDERR "\n";
+ }
- if ($mtime) {
- utime $mtime, $mtime, $localfile;
- }
+ if ($localfile and $mtime) {
+ utime $mtime, $mtime, $localfile;
}
- return $resp->content;
+ return $localfile ? 1 : $resp->content;
}
elsif ($resp->is_redirect) { # 3xx codes
if ($resp->code == RC_NOT_MODIFIED) { # 304
print STDERR " -> not modified\n" if $verbose;
- open (LOCAL, "<", "$localfile") or die "Can't open $localfile ($!)";
- local $/; # slurp whole file
- my $content = <LOCAL>;
- close LOCAL;
- return $content;
+ die "Got 304 with no local file" if not $localfile;
+ return 1;
}
print STDERR " -> redirect (".$resp->code.")\n" if $verbose;
die "Can't fetch $remotefile (got redirect, not yet handled)";
}
# get the changes files
-my %changesfilecontent;
-foreach my $file (@changesfiles) { $changesfilecontent{$file} = getChangesFile($file); }
+foreach my $file (@changesfiles) { getChangesFile($file); }
-# if the file has not changed (response code 304) then ignore it
+# TODO: if the file has not changed (response code 304) then ignore it
# iterate over all the fetched files, building up a list of files
# to fetch/delete
my %files;
foreach my $changesfile (@changesfiles) {
- my $changesfilecontent = $changesfilecontent{$changesfile};
- if (not defined $changesfilecontent) {
- print STDERR "Skipping changes file $changesfile; not present at remote end\n" if $verbose;
+ if (! -e "$changesdir/$changesfile") {
+ print STDERR "Skipping changes file $changesfile; not present\n" if $verbose;
next;
}
print STDERR "Processing changes file $changesfile\n" if $verbose;
- my @changes = split /[\r\n]+/, $changesfilecontent;
- foreach my $change (@changes) {
+ open (CHANGES, "<", "$changesdir/$changesfile") or die "Can't open $changesfile";
+ while (my $change = <CHANGES>) {
my ($time, $op, $path) = split ' ', $change;
# Ignore malformed lines, especially wacky paths that could be malicious
}
elsif ($op eq "add" or $op eq "change" or $op eq "Modification") {
# add/change: re-fetch the file
- # FIXME: don't insist on reading entire file into memory
- my $content = fetchFile("$remoteroot/$file","$workingdir/$file");
- die "File $remoteroot/$file not found" if not defined $content;
+ fetchFile("$remoteroot/$file","$workingdir/$file") or die "File $remoteroot/$file not found";
}
else {
die "Unknown operation '$op'";