ffb3950440ff4e26b45fa8a6739180499ad99a9b
[id3fs.git] / lib / ID3FS / Fuse.pm
1 # id3fs - a FUSE-based filesystem for browsing audio metadata
2 # Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 package ID3FS::Fuse;
18
19 use strict;
20 use warnings;
21 use ID3FS::Path;
22 use Fuse;
23 use Cwd;
24 use POSIX qw(EINVAL EROFS ENOENT EOPNOTSUPP S_IRUSR S_IRGRP S_IROTH S_IXUSR S_IXGRP S_IXOTH);
25
26 our ($TYPE_DIR, $TYPE_SYMLINK)=(0040, 0120);
27 our $DEFAULT_MAXTAGDEPTH = 10;
28 sub new
29 {
30     my $proto=shift;
31     my $class=ref($proto) || $proto;
32     my $self={};
33     bless($self,$class);
34
35     $self->{db}=shift;
36     $self->{source}=shift;
37     $self->{mountpoint}=Cwd::abs_path(shift);
38     $self->{verbose}=shift;
39     $self->{tagdepth}=shift;
40     $self->{tagdepth}=$DEFAULT_MAXTAGDEPTH unless($self->{tagdepth});
41     $self->{perms} = S_IRUSR() | S_IXUSR() | S_IRGRP() | S_IXGRP() | S_IROTH() | S_IXOTH();
42
43     return $self;
44 }
45
46 sub run
47 {
48     my($self)=@_;
49     Fuse::main(
50         mountpoint  => $self->{mountpoint},
51         threaded    => 0,
52         debug       => ($self->{verbose} > 1),
53         mountopts   => "allow_other,ro",
54         getattr     => sub { $self->getattr(@_); },
55         readlink    => sub { $self->readlink(@_); },
56         getdir      => sub { $self->getdir(@_); },
57
58         # Not used
59 #       mknod       => sub { $self->mknod(@_);       },
60 #       mkdir       => sub { $self->mkdir(@_);       },
61 #       unlink      => sub { $self->unlink(@_);      },
62 #       rmdir       => sub { $self->rmdir(@_);       },
63 #       symlink     => sub { $self->symlink(@_);     },
64 #       rename      => sub { $self->rename(@_);      },
65 #       link        => sub { $self->link(@_);        },
66 #       chmod       => sub { $self->chmod(@_);       },
67 #       chown       => sub { $self->chown(@_);       },
68 #       truncate    => sub { $self->truncate(@_);    },
69 #       utime       => sub { $self->utime(@_);       },
70 #       open        => sub { $self->open(@_);        },
71 #       read        => sub { $self->read(@_);        },
72 #       write       => sub { $self->write(@_);       },
73 #       statfs      => sub { $self->statfs(@_);      },
74 #       release     => sub { $self->release(@_);     },
75 #       fsync       => sub { $self->fsync(@_);       },
76 #       setxattr    => sub { $self->setxattr(@_);    },
77 #       getxattr    => sub { $self->getxattr(@_);    },
78 #       listxattr   => sub { $self->listxattr(@_);   },
79 #       removexattr => sub { $self->removexattr(@_); },
80         );
81 }
82
83 sub getattr
84 {
85     my($self, $filename)=@_;
86 #    print "**GETATTR: $filename\n";
87     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
88     my $last_update=$self->{db}->last_update();
89     return(-ENOENT()) unless($path->isvalid());
90     my($dev,$ino,$nlink)=(0,0,1);
91     my $uid=$<;
92     my $gid=(split(/ /, $( ))[0];
93     my($rdev,$size)=(0,1);
94     my($atime,$mtime,$ctime)=($last_update) x 3;
95     my($blksize,$blocks)=(512,1);
96     my $mode=$self->mode( $path->isdir() ? $TYPE_DIR : $TYPE_SYMLINK );
97     return($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
98            $atime, $mtime, $ctime, $blksize, $blocks);
99 }
100
101 sub readlink
102 {
103     my($self,$filename)=@_;
104 #    print "**READLINK: $filename\n";
105     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
106     return(-EINVAL()) unless($path->isfile());
107     return $path->dest($self->{mountpoint});
108 }
109
110 sub getdir
111 {
112     my($self, $filename)=@_;
113 #    print "**GETDIR: $filename\n";
114     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
115     return(-ENOENT()) unless($path->isvalid());
116     return(-ENOTDIR()) unless($path->isdir());
117     my @dents=();
118     my($dirs, $files)=$path->dirents();
119     # too slow
120 #    push(@dents, $path->filter(@$dirs));
121     push(@dents, @$dirs);
122     push(@dents, @$files);
123     if(@dents)
124     {
125         return( (".", "..", @dents, 0) );
126     }
127     return(0);
128 }
129
130 # unused stubs
131 sub mknod       { print "FUSE: mknod\n";       return -EROFS();      }
132 sub mkdir       { print "FUSE: mkdir\n";       return -EROFS();      }
133 sub unlink      { print "FUSE: unlink\n";      return -EROFS();      }
134 sub rmdir       { print "FUSE: rmdir\n";       return -EROFS();      }
135 sub symlink     { print "FUSE: symlink\n";     return -EROFS();      }
136 sub rename      { print "FUSE: rename\n";      return -EROFS();      }
137 sub link        { print "FUSE: link\n";        return -EROFS();      }
138 sub chmod       { print "FUSE: chmod\n";       return -EROFS();      }
139 sub chown       { print "FUSE: chown\n";       return -EROFS();      }
140 sub truncate    { print "FUSE: truncate\n";    return -EROFS();      }
141 sub utime       { print "FUSE: utime\n";       return -EINVAL();     }
142 sub open        { print "FUSE: open\n";        return -EINVAL();     }
143 sub read        { print "FUSE: read\n";        return -EINVAL();     }
144 sub write       { print "FUSE: write\n";       return -EROFS();      }
145 sub statfs      { print "FUSE: statfs\n";      return -EINVAL();     }
146 sub release     { print "FUSE: release\n";     return 0;             }
147 sub fsync       { print "FUSE: fsync\n";       return 0;             }
148 sub setxattr    { print "FUSE: setxattr\n";    return -EOPNOTSUPP(); }
149 sub getxattr    { print "FUSE: getxattr\n";    return -EOPNOTSUPP(); }
150 sub listxattr   { print "FUSE: listxattr\n";   return -EOPNOTSUPP(); }
151 sub removexattr { print "FUSE: removexattr\n"; return -EOPNOTSUPP(); }
152
153 sub mode
154 {
155     my($self, $type)=@_;
156     return(($type << 9) | $self->{perms});
157 }
158
159 1;