/[fuse_dbi]/trunk/DBI.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/DBI.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/fuse_dbi.pl revision 7 by dpavlin, Sat Aug 7 14:48:23 2004 UTC trunk/DBI.pm revision 9 by dpavlin, Sat Aug 7 19:06:03 2004 UTC
# Line 1  Line 1 
1  #!/usr/bin/perl  #!/usr/bin/perl
2    
3    package Fuse::DBI;
4    
5    use 5.008;
6    use strict;
7    use warnings;
8    
9  use POSIX qw(ENOENT EISDIR EINVAL ENOSYS O_RDWR);  use POSIX qw(ENOENT EISDIR EINVAL ENOSYS O_RDWR);
10  use Fuse;  use Fuse;
   
11  use DBI;  use DBI;
 use strict;  
12    
13  my $sql_filenames = q{  our $VERSION = '0.01';
         select  
                 oid as id,  
                 namespace||'/'||name||' ['||oid||']' as filename,  
                 length(template) as size,  
                 iseditable as writable  
         from template ;  
 };  
14    
15  my $sql_read = q{  =head1 NAME
         select template  
                 from template  
                 where oid = ?;  
 };  
16    
17  my $sql_update = q{  Fuse::DBI - mount your database as filesystem and use it
18          update template  
19                  set template = ?          =head1 SYNOPSIS
20                  where oid = ?;  
21  };    use Fuse::DBI;
22      Fuse::DBI->run( ... );
23    
24    See L<run> below for examples how to set parametars.
25    
26    =head1 DESCRIPTION
27    
28  my $connect = "DBI:Pg:dbname=webgui";  This module will use L<Fuse> module, part of C<FUSE (Filesystem in USErspace)>
29    available at L<http://sourceforge.net/projects/avf> to mount
30    your database as file system.
31    
32  my $dbh = DBI->connect($connect,"","", { AutoCommit => 0 }) || die $DBI::errstr;  That will give you posibility to use normal file-system tools (cat, grep, vi)
33    to manipulate data in database.
34    
35  print "start transaction\n";  It's actually opposite of Oracle's intention to put everything into database.
 #$dbh->begin_work || die $dbh->errstr;  
36    
 my $sth_filenames = $dbh->prepare($sql_filenames) || die $dbh->errstr();  
 $sth_filenames->execute() || die $sth_filenames->errstr();  
   
 my $sth_read = $dbh->prepare($sql_read) || die $dbh->errstr();  
 my $sth_update = $dbh->prepare($sql_update) || die $dbh->errstr();  
   
 my $ctime_start = time();  
   
 my (%files) = (  
         '.' => {  
                 type => 0040,  
                 mode => 0755,  
         },  
 #       a => {  
 #               cont => "File 'a'.\n",  
 #               type => 0100,  
 #               ctime => time()-2000  
 #       },  
 );  
37    
38    =head1 METHODS
39    
40    =cut
41    
42    =head2 run
43    
44    Mount your database as filesystem.
45    
46      Fuse::DBI->run({
47            filenames => 'select name from filenamefilenames,
48            read => 'sql read',
49            update => 'sql update',
50            dsn => 'DBI:Pg:dbname=webgui',
51            user => 'database_user',
52            password => 'database_password'
53      });
54    
55    =cut
56    
57    my $dbh;
58    my $sth;
59    my $ctime_start;
60    
61    sub run {
62            my $self = shift
63    
64            my $arg = {@_};
65    
66            carp "run needs 'dsn' to connect to (e.g. dsn => 'DBI:Pg:dbname=test')" unless ($arg->{'dsn'});
67            carp "run needs 'mount' as mountpoint" unless ($arg->{'mount'});
68    
69            foreach (qw(filenames read update)) {
70                    carp "run needs '$_' SQL" unless ($arg->{$_});
71            }
72    
73            $dbh = DBI->connect($arg->{'dsn'},$arg->{'user'},$arg->{'password'}, { AutoCommit => 0 }) || die $DBI::errstr;
74    
75            print "start transaction\n";
76            #$dbh->begin_work || die $dbh->errstr;
77    
78            $sth->{filenames} = $dbh->prepare($arg->{'filenames'}) || die $dbh->errstr();
79    
80            $sth->{'read'} = $dbh->prepare($arg->{'read'}) || die $dbh->errstr();
81            $sth->{'update'} = $dbh->prepare($arg->{'update'}) || die $dbh->errstr();
82    
83            $ctime_start = time();
84    
85            read_filenames;
86    
87            Fuse::main(
88                    mountpoint=>$arg->{'mount'},
89                    getattr=>\&e_getattr,
90                    getdir=>\&e_getdir,
91                    open=>\&e_open,
92                    statfs=>\&e_statfs,
93                    read=>\&e_read,
94                    write=>\&e_write,
95                    utime=>\&e_utime,
96                    truncate=>\&e_truncate,
97                    debug=>0,
98            );
99    };
100    
101    my %files;
102  my %dirs;  my %dirs;
103    
104  while (my $row = $sth_filenames->fetchrow_hashref() ) {  sub read_filenames {
105          $files{$row->{'filename'}} = {          # create empty filesystem
106                  size => $row->{'size'},          (%files) = (
107                  mode => $row->{'writable'} ? 0644 : 0444,                  '.' => {
108                  id => $row->{'id'} || 99,                          type => 0040,
109          };                          mode => 0755,
110                    },
111          my $d;          #       a => {
112          foreach (split(m!/!, $row->{'filename'})) {          #               cont => "File 'a'.\n",
113                  # first, entry is assumed to be file          #               type => 0100,
114                  if ($d) {          #               ctime => time()-2000
115                          $files{$d} = {          #       },
116                                          size => $dirs{$d}++,          );
117                                          mode => 0755,  
118                                          type => 0040          # fetch new filename list from database
119                          };          $sth->{'filenames'}->execute() || die $sth->{'filenames'}->errstr();
120                          $files{$d.'/.'} = {  
121                                          mode => 0755,          # read them in with sesible defaults
122                                          type => 0040          while (my $row = $sth->{'filenames'}->fetchrow_hashref() ) {
123                          };                  $files{$row->{'filename'}} = {
124                          $files{$d.'/..'} = {                          size => $row->{'size'},
125                                          mode => 0755,                          mode => $row->{'writable'} ? 0644 : 0444,
126                                          type => 0040                          id => $row->{'id'} || 99,
127                          };                  };
128    
129                    my $d;
130                    foreach (split(m!/!, $row->{'filename'})) {
131                            # first, entry is assumed to be file
132                            if ($d) {
133                                    $files{$d} = {
134                                                    size => $dirs{$d}++,
135                                                    mode => 0755,
136                                                    type => 0040
137                                    };
138                                    $files{$d.'/.'} = {
139                                                    mode => 0755,
140                                                    type => 0040
141                                    };
142                                    $files{$d.'/..'} = {
143                                                    mode => 0755,
144                                                    type => 0040
145                                    };
146                            }
147                            $d .= "/" if ($d);
148                            $d .= "$_";
149                  }                  }
                 $d .= "/" if ($d);  
                 $d .= "$_";  
150          }          }
151    
152            print "found ",scalar(keys %files)-scalar(keys %dirs)," files, ",scalar(keys %dirs), " dirs\n";
153  }  }
154    
 print "found ",scalar(keys %files)-scalar(keys %dirs)," files, ",scalar(keys %dirs), " dirs\n";  
155    
156  sub filename_fixup {  sub filename_fixup {
157          my ($file) = shift;          my ($file) = shift;
# Line 133  sub e_getdir { Line 197  sub e_getdir {
197          if (! %out) {          if (! %out) {
198                  $out{'no files? bug?'}++;                  $out{'no files? bug?'}++;
199          }          }
200          print scalar keys %out," files found for '$dirname': ",keys %out,"\n";          print scalar keys %out," files in dir '$dirname'\n";
201          return (keys %out),0;          return (keys %out),0;
202  }  }
203    
# Line 146  sub e_open { Line 210  sub e_open {
210          return -EISDIR() unless exists($files{$file}{id});          return -EISDIR() unless exists($files{$file}{id});
211    
212          if (!exists($files{$file}{cont})) {          if (!exists($files{$file}{cont})) {
213                  $sth_read->execute($files{$file}{id}) || die $sth_read->errstr;                  $sth->{'read'}->execute($files{$file}{id}) || die $sth->{'read'}->errstr;
214                  $files{$file}{cont} = $sth_read->fetchrow_array;                  $files{$file}{cont} = $sth->{'read'}->fetchrow_array;
215                  print "file '$file' content read in cache\n";                  print "file '$file' content read in cache\n";
216          }          }
217          print "open '$file' ",length($files{$file}{cont})," bytes\n";          print "open '$file' ",length($files{$file}{cont})," bytes\n";
# Line 159  sub e_read { Line 223  sub e_read {
223          # (note: 0 means EOF, "0" will give a byte (ascii "0")          # (note: 0 means EOF, "0" will give a byte (ascii "0")
224          # to the reading program)          # to the reading program)
225          my ($file) = filename_fixup(shift);          my ($file) = filename_fixup(shift);
226          my ($buf,$off) = @_;          my ($buf_len,$off) = @_;
227    
228          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
229    
230          my $len = length($files{$file}{cont});          my $len = length($files{$file}{cont});
231    
232          print "read '$file' [$len bytes] offset $off length $buf\n";          print "read '$file' [$len bytes] offset $off length $buf_len\n";
233    
234          return -EINVAL() if ($off > $len);          return -EINVAL() if ($off > $len);
235          return 0 if ($off == $len);          return 0 if ($off == $len);
236    
237          $buf = $len-$off if ($off+$buf > $len);          $buf_len = $buf_len-$off if ($off+$buf_len > $len);
238    
239          return substr($files{$file}{cont},$off,$buf);          return substr($files{$file}{cont},$off,$buf_len);
240  }  }
241    
242  sub clear_cont {  sub clear_cont {
# Line 190  sub clear_cont { Line 254  sub clear_cont {
254  sub update_db {  sub update_db {
255          my $file = shift || die;          my $file = shift || die;
256    
257          if (!$sth_update->execute($files{$file}{cont},$files{$file}{id})) {          $files{$file}{ctime} = time();
258                  print "update problem: ",$sth_update->errstr;  
259            if (!$sth->{'update'}->execute($files{$file}{cont},$files{$file}{id})) {
260                    print "update problem: ",$sth->{'update'}->errstr;
261                  clear_cont;                  clear_cont;
262                  return 0;                  return 0;
263          } else {          } else {
264                  if (! $dbh->commit) {                  if (! $dbh->commit) {
265                          print "ERROR: commit problem: ",$sth_update->errstr;                          print "ERROR: commit problem: ",$sth->{'update'}->errstr;
266                          clear_cont;                          clear_cont;
267                          return 0;                          return 0;
268                  }                  }
# Line 207  sub update_db { Line 273  sub update_db {
273    
274  sub e_write {  sub e_write {
275          my $file = filename_fixup(shift);          my $file = filename_fixup(shift);
276          my ($buf,$off) = @_;          my ($buf_len,$off) = @_;
277    
278          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
279    
280          my $len = length($files{$file}{cont});          my $len = length($files{$file}{cont});
281    
282          print "write '$file' [$len bytes] offset $off length $buf\n";          print "write '$file' [$len bytes] offset $off length\n";
283    
284          $files{$file}{cont} =          $files{$file}{cont} =
285                  substr($files{$file}{cont},0,$off) .                  substr($files{$file}{cont},0,$off) .
286                  $buf .                  $buf_len .
287                  substr($files{$file}{cont},$off+length($buf));                  substr($files{$file}{cont},$off+length($buf_len));
288    
289          if (! update_db($file)) {          if (! update_db($file)) {
290                  return -ENOSYS();                  return -ENOSYS();
291          } else {          } else {
292                  return length($buf);                  return length($buf_len);
293          }          }
294  }  }
295    
# Line 242  sub e_utime { Line 308  sub e_utime {
308    
309          return -ENOENT() unless exists($files{$file});          return -ENOENT() unless exists($files{$file});
310    
311            print "utime '$file' $atime $mtime\n";
312    
313          $files{$file}{time} = $mtime;          $files{$file}{time} = $mtime;
314          return 0;          return 0;
315  }  }
316    
317  sub e_statfs { return 255, 1, 1, 1, 1, 2 }  sub e_statfs { return 255, 1, 1, 1, 1, 2 }
318    
319  # If you run the script directly, it will run fusermount, which will in turn  1;
320  # re-run this script.  Hence the funky semantics.  __END__
321  my ($mountpoint) = "";  
322  $mountpoint = shift(@ARGV) if @ARGV;  =head1 EXPORT
323  Fuse::main(  
324          mountpoint=>$mountpoint,  Nothing.
325          getattr=>\&e_getattr,  
326          getdir=>\&e_getdir,  =head1 SEE ALSO
327          open=>\&e_open,  
328          statfs=>\&e_statfs,  C<FUSE (Filesystem in USErspace)> website
329          read=>\&e_read,  L<http://sourceforge.net/projects/avf>
330          write=>\&e_write,  
331          utime=>\&e_utime,  =head1 AUTHOR
332          truncate=>\&e_truncate,  
333          debug=>0,  Dobrica Pavlinusic, E<lt>dpavlin@rot13.orgE<gt>
334  );  
335    =head1 COPYRIGHT AND LICENSE
336    
337    Copyright (C) 2004 by Dobrica Pavlinusic
338    
339    This library is free software; you can redistribute it and/or modify
340    it under the same terms as Perl itself, either Perl version 5.8.4 or,
341    at your option, any later version of Perl 5 you may have available.
342    
343    
344    =cut
345    

Legend:
Removed from v.7  
changed lines
  Added in v.9

  ViewVC Help
Powered by ViewVC 1.1.26