enable filter
[id3fs.git] / lib / ID3FS / Fuse.pm
1 package ID3FS::Fuse;
2
3 use strict;
4 use warnings;
5 use ID3FS::Path;
6 use Fuse;
7 use Cwd;
8 use POSIX qw(EINVAL EROFS ENOENT EOPNOTSUPP S_IRUSR S_IRGRP S_IROTH S_IXUSR S_IXGRP S_IXOTH);
9 our ($TYPE_DIR, $TYPE_SYMLINK)=(0040, 0120);
10
11 sub new
12 {
13     my $proto=shift;
14     my $class=ref($proto) || $proto;
15     my $self={};
16     bless($self,$class);
17
18     $self->{db}=shift;
19     $self->{source}=shift;
20     $self->{mountpoint}=Cwd::abs_path(shift);
21     $self->{debug}=shift;
22     $self->{perms} = S_IRUSR() | S_IXUSR() | S_IRGRP() | S_IXGRP() | S_IROTH() | S_IXOTH();
23
24     return $self;
25 }
26
27 sub run
28 {
29     my($self)=@_;
30     Fuse::main(
31         mountpoint  => $self->{mountpoint},
32         threaded    => 0,
33         debug       => $self->{debug},
34         mountopts   => "allow_other,ro",
35         getattr     => sub { $self->getattr(@_); },
36         readlink    => sub { $self->readlink(@_); },
37         getdir      => sub { $self->getdir(@_); },
38
39         # Not used
40 #       mknod       => sub { $self->mknod(@_);       },
41 #       mkdir       => sub { $self->mkdir(@_);       },
42 #       unlink      => sub { $self->unlink(@_);      },
43 #       rmdir       => sub { $self->rmdir(@_);       },
44 #       symlink     => sub { $self->symlink(@_);     },
45 #       rename      => sub { $self->rename(@_);      },
46 #       link        => sub { $self->link(@_);        },
47 #       chmod       => sub { $self->chmod(@_);       },
48 #       chown       => sub { $self->chown(@_);       },
49 #       truncate    => sub { $self->truncate(@_);    },
50 #       utime       => sub { $self->utime(@_);       },
51 #       open        => sub { $self->open(@_);        },
52 #       read        => sub { $self->read(@_);        },
53 #       write       => sub { $self->write(@_);       },
54 #       statfs      => sub { $self->statfs(@_);      },
55 #       release     => sub { $self->release(@_);     },
56 #       fsync       => sub { $self->fsync(@_);       },
57 #       setxattr    => sub { $self->setxattr(@_);    },
58 #       getxattr    => sub { $self->getxattr(@_);    },
59 #       listxattr   => sub { $self->listxattr(@_);   },
60 #       removexattr => sub { $self->removexattr(@_); },
61         );
62 }
63
64 sub getattr
65 {
66     my($self, $filename)=@_;
67 #    print "**GETATTR: $filename\n";
68     my $path=ID3FS::Path->new($self->{db}, $filename);
69     my $last_update=$self->{db}->last_update();
70     return(-ENOENT()) unless($path->isvalid());
71     my($dev,$ino,$nlink)=(0,0,1);
72     my $uid=$<;
73     my $gid=(split(/ /, $( ))[0];
74     my($rdev,$size)=(0,1);
75     my($atime,$mtime,$ctime)=($last_update) x 3;
76     my($blksize,$blocks)=(512,1);
77     my $mode=$self->mode( $path->isdir() ? $TYPE_DIR : $TYPE_SYMLINK );
78     return($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
79            $atime, $mtime, $ctime, $blksize, $blocks);
80 }
81
82 sub readlink
83 {
84     my($self,$filename)=@_;
85 #    print "**READLINK: $filename\n";
86     my $path=ID3FS::Path->new($self->{db}, $filename);
87     return(-EINVAL()) unless($path->isfile());
88     return $path->dest($self->{mountpoint});
89 }
90
91 sub getdir
92 {
93     my($self, $filename)=@_;
94 #    print "**GETDIR: $filename\n";
95     my $path=ID3FS::Path->new($self->{db}, $filename);
96     return(-ENOENT()) unless($path->isvalid());
97     return(-ENOTDIR()) unless($path->isdir());
98     my @dents=();
99     my($dirs, $files)=$path->dirents();
100     push(@dents, $self->filter($filename, @$dirs));
101     push(@dents, @$files);
102     if(@dents)
103     {
104         return( (".", "..", @dents, 0) );
105     }
106     return(0);
107 }
108
109 sub filter
110 {
111     my($self, $base, @dirs)=@_;
112     my @outdirs=();
113     for my $dir (@dirs)
114     {
115         print "hascontents: $base / $dir\n";
116         my $path=ID3FS::Path->new($self->{db}, "$base/$dir");
117         next unless($path->isvalid());
118         my($subdirs,$subfiles)=$path->dirents();
119         print "SUBDENTS: ", join(", ", @$subdirs, @$subfiles), "\n";
120         next unless(@$subdirs || @$subfiles);
121         if(!@$subfiles || scalar(@$subdirs) < 3)
122         {
123             my $subdirents=0;
124             for my $subdir (@$subdirs)
125             {
126                 if(grep { $_ eq $subdir; } qw(AND OR NOT))
127                 {
128                     my $subsubpath=ID3FS::Path->new($self->{db}, "$base/$dir/$subdir");
129                     if($path->isvalid())
130                     {
131                         my($subsubdirs,$subsubfiles)=$subsubpath->dirents();
132                         $subdirents++ if(@$subsubdirs || @$subsubfiles);
133                     }
134                 }
135                 else
136                 {
137                     $subdirents++;
138                 }
139             }
140             next unless($subdirents);
141         }
142         push(@outdirs, $dir);
143     }
144     return(@outdirs)
145 }
146
147 # unused stubs
148 sub mknod       { print "FUSE: mknod\n";       return -EROFS();      }
149 sub mkdir       { print "FUSE: mkdir\n";       return -EROFS();      }
150 sub unlink      { print "FUSE: unlink\n";      return -EROFS();      }
151 sub rmdir       { print "FUSE: rmdir\n";       return -EROFS();      }
152 sub symlink     { print "FUSE: symlink\n";     return -EROFS();      }
153 sub rename      { print "FUSE: rename\n";      return -EROFS();      }
154 sub link        { print "FUSE: link\n";        return -EROFS();      }
155 sub chmod       { print "FUSE: chmod\n";       return -EROFS();      }
156 sub chown       { print "FUSE: chown\n";       return -EROFS();      }
157 sub truncate    { print "FUSE: truncate\n";    return -EROFS();      }
158 sub utime       { print "FUSE: utime\n";       return -EINVAL();     }
159 sub open        { print "FUSE: open\n";        return -EINVAL();     }
160 sub read        { print "FUSE: read\n";        return -EINVAL();     }
161 sub write       { print "FUSE: write\n";       return -EROFS();      }
162 sub statfs      { print "FUSE: statfs\n";      return -EINVAL();     }
163 sub release     { print "FUSE: release\n";     return 0;             }
164 sub fsync       { print "FUSE: fsync\n";       return 0;             }
165 sub setxattr    { print "FUSE: setxattr\n";    return -EOPNOTSUPP(); }
166 sub getxattr    { print "FUSE: getxattr\n";    return -EOPNOTSUPP(); }
167 sub listxattr   { print "FUSE: listxattr\n";   return -EOPNOTSUPP(); }
168 sub removexattr { print "FUSE: removexattr\n"; return -EOPNOTSUPP(); }
169
170 sub mode
171 {
172     my($self, $type)=@_;
173     return(($type << 9) | $self->{perms});
174 }
175
176 1;