better output, read fixes, ctime preserved (so that vi won't complain that
[Fuse-DBI] / fuse_dbi.pl
index a0a2fdf..e4570bf 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 
-use POSIX qw(ENOENT EISDIR EINVAL);
+use POSIX qw(ENOENT EISDIR EINVAL ENOSYS O_RDWR);
 use Fuse;
 
 use DBI;
@@ -8,32 +8,38 @@ use strict;
 
 my $sql_filenames = q{
        select
-               templateid as id,
-               namespace||'/'||name||' ['||templateid||']' as filename,
+               oid as id,
+               namespace||'/'||name||' ['||oid||']' as filename,
                length(template) as size,
                iseditable as writable
        from template ;
 };
 
-my $sql_content = q{
+my $sql_read = q{
        select template
-       from template
-       where templateid = ?;
+               from template
+               where oid = ?;
+};
+
+my $sql_update = q{
+       update template
+               set template = ?        
+               where oid = ?;
 };
 
 
 my $connect = "DBI:Pg:dbname=webgui";
 
-my $dbh = DBI->connect($connect,"","") || die $DBI::errstr;
+my $dbh = DBI->connect($connect,"","", { AutoCommit => 0 }) || die $DBI::errstr;
 
-print STDERR "$sql_filenames\n";
+print "start transaction\n";
+#$dbh->begin_work || die $dbh->errstr;
 
 my $sth_filenames = $dbh->prepare($sql_filenames) || die $dbh->errstr();
 $sth_filenames->execute() || die $sth_filenames->errstr();
 
-my $sth_content = $dbh->prepare($sql_content) || die $dbh->errstr();
-
-print "#",join(",",@{ $sth_filenames->{NAME} }),"\n";
+my $sth_read = $dbh->prepare($sql_read) || die $dbh->errstr();
+my $sth_update = $dbh->prepare($sql_update) || die $dbh->errstr();
 
 my $ctime_start = time();
 
@@ -81,7 +87,7 @@ while (my $row = $sth_filenames->fetchrow_hashref() ) {
        }
 }
 
-print scalar (keys %dirs), " dirs:",join(" ",keys %dirs),"\n";
+print "found ",scalar(keys %files)-scalar(keys %dirs)," files, ",scalar(keys %dirs), " dirs\n";
 
 sub filename_fixup {
        my ($file) = shift;
@@ -123,38 +129,125 @@ sub e_getdir {
                } else {
                        $out{$f}++ if ($f =~ /^[^\/]+$/);
                }
-               print "f: $_ -> $f\n";
        }
        if (! %out) {
                $out{'no files? bug?'}++;
        }
-       print scalar keys %out," files found for '$dirname': ",keys %out,"\n";
+       print scalar keys %out," files in dir '$dirname'\n";
        return (keys %out),0;
 }
 
 sub e_open {
        # VFS sanity check; it keeps all the necessary state, not much to do here.
-       my ($file) = filename_fixup(shift);
-       print("open called\n");
+       my $file = filename_fixup(shift);
+       my $flags = shift;
+
        return -ENOENT() unless exists($files{$file});
        return -EISDIR() unless exists($files{$file}{id});
+
        if (!exists($files{$file}{cont})) {
-               $sth_content->execute($files{$file}{id});
-               ($files{$file}{cont}) = $sth_content->fetchrow_array;
+               $sth_read->execute($files{$file}{id}) || die $sth_read->errstr;
+               $files{$file}{cont} = $sth_read->fetchrow_array;
+               print "file '$file' content read in cache\n";
        }
-       print("open ok\n");
+       print "open '$file' ",length($files{$file}{cont})," bytes\n";
        return 0;
 }
 
 sub e_read {
-       # return an error numeric, or binary/text string.  (note: 0 means EOF, "0" will
-       # give a byte (ascii "0") to the reading program)
+       # return an error numeric, or binary/text string.
+       # (note: 0 means EOF, "0" will give a byte (ascii "0")
+       # to the reading program)
        my ($file) = filename_fixup(shift);
-       my ($buf,$off) = @_;
+       my ($buf_len,$off) = @_;
+
+       return -ENOENT() unless exists($files{$file});
+
+       my $len = length($files{$file}{cont});
+
+       print "read '$file' [$len bytes] offset $off length $buf_len\n";
+
+       return -EINVAL() if ($off > $len);
+       return 0 if ($off == $len);
+
+       $buf_len = $buf_len-$off if ($off+$buf_len > $len);
+
+       return substr($files{$file}{cont},$off,$buf_len);
+}
+
+sub clear_cont {
+       print "transaction rollback\n";
+       $dbh->rollback || die $dbh->errstr;
+       print "invalidate all cached content\n";
+       foreach my $f (keys %files) {
+               delete $files{$f}{cont};
+       }
+       print "begin new transaction\n";
+       $dbh->begin_work || die $dbh->errstr;
+}
+
+
+sub update_db {
+       my $file = shift || die;
+
+       $files{$file}{ctime} = time();
+
+       if (!$sth_update->execute($files{$file}{cont},$files{$file}{id})) {
+               print "update problem: ",$sth_update->errstr;
+               clear_cont;
+               return 0;
+       } else {
+               if (! $dbh->commit) {
+                       print "ERROR: commit problem: ",$sth_update->errstr;
+                       clear_cont;
+                       return 0;
+               }
+               print "updated '$file' [",$files{$file}{id},"]\n";
+       }
+       return 1;
+}
+
+sub e_write {
+       my $file = filename_fixup(shift);
+       my ($buf_len,$off) = @_;
+
        return -ENOENT() unless exists($files{$file});
-       return -EINVAL() if $off > length($files{$file}{cont});
-       return 0 if $off == length($files{$file}{cont});
-       return substr($files{$file}{cont},$off,$buf);
+
+       my $len = length($files{$file}{cont});
+
+       print "write '$file' [$len bytes] offset $off length\n";
+
+       $files{$file}{cont} =
+               substr($files{$file}{cont},0,$off) .
+               $buf_len .
+               substr($files{$file}{cont},$off+length($buf_len));
+
+       if (! update_db($file)) {
+               return -ENOSYS();
+       } else {
+               return length($buf_len);
+       }
+}
+
+sub e_truncate {
+       my $file = filename_fixup(shift);
+       my $size = shift;
+
+       $files{$file}{cont} = substr($files{$file}{cont},0,$size);
+       return 0
+};
+
+
+sub e_utime {
+       my ($atime,$mtime,$file) = @_;
+       $file = filename_fixup($file);
+
+       return -ENOENT() unless exists($files{$file});
+
+       print "utime '$file' $atime $mtime\n";
+
+       $files{$file}{time} = $mtime;
+       return 0;
 }
 
 sub e_statfs { return 255, 1, 1, 1, 1, 2 }
@@ -170,5 +263,8 @@ Fuse::main(
        open=>\&e_open,
        statfs=>\&e_statfs,
        read=>\&e_read,
-       debug=>1,
+       write=>\&e_write,
+       utime=>\&e_utime,
+       truncate=>\&e_truncate,
+       debug=>0,
 );