specify max tag depth (default: 15)
[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
10 our ($TYPE_DIR, $TYPE_SYMLINK)=(0040, 0120);
11 our $DEFAULT_MAXTAGDEPTH = 15;
12 sub new
13 {
14     my $proto=shift;
15     my $class=ref($proto) || $proto;
16     my $self={};
17     bless($self,$class);
18
19     $self->{db}=shift;
20     $self->{source}=shift;
21     $self->{mountpoint}=Cwd::abs_path(shift);
22     $self->{verbose}=shift;
23     $self->{tagdepth}=shift;
24     $self->{tagdepth}=$DEFAULT_MAXTAGDEPTH unless($self->{tagdepth});
25     $self->{perms} = S_IRUSR() | S_IXUSR() | S_IRGRP() | S_IXGRP() | S_IROTH() | S_IXOTH();
26
27     return $self;
28 }
29
30 sub run
31 {
32     my($self)=@_;
33     Fuse::main(
34         mountpoint  => $self->{mountpoint},
35         threaded    => 0,
36         debug       => ($self->{verbose} > 1),
37         mountopts   => "allow_other,ro",
38         getattr     => sub { $self->getattr(@_); },
39         readlink    => sub { $self->readlink(@_); },
40         getdir      => sub { $self->getdir(@_); },
41
42         # Not used
43 #       mknod       => sub { $self->mknod(@_);       },
44 #       mkdir       => sub { $self->mkdir(@_);       },
45 #       unlink      => sub { $self->unlink(@_);      },
46 #       rmdir       => sub { $self->rmdir(@_);       },
47 #       symlink     => sub { $self->symlink(@_);     },
48 #       rename      => sub { $self->rename(@_);      },
49 #       link        => sub { $self->link(@_);        },
50 #       chmod       => sub { $self->chmod(@_);       },
51 #       chown       => sub { $self->chown(@_);       },
52 #       truncate    => sub { $self->truncate(@_);    },
53 #       utime       => sub { $self->utime(@_);       },
54 #       open        => sub { $self->open(@_);        },
55 #       read        => sub { $self->read(@_);        },
56 #       write       => sub { $self->write(@_);       },
57 #       statfs      => sub { $self->statfs(@_);      },
58 #       release     => sub { $self->release(@_);     },
59 #       fsync       => sub { $self->fsync(@_);       },
60 #       setxattr    => sub { $self->setxattr(@_);    },
61 #       getxattr    => sub { $self->getxattr(@_);    },
62 #       listxattr   => sub { $self->listxattr(@_);   },
63 #       removexattr => sub { $self->removexattr(@_); },
64         );
65 }
66
67 sub getattr
68 {
69     my($self, $filename)=@_;
70 #    print "**GETATTR: $filename\n";
71     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
72     my $last_update=$self->{db}->last_update();
73     return(-ENOENT()) unless($path->isvalid());
74     my($dev,$ino,$nlink)=(0,0,1);
75     my $uid=$<;
76     my $gid=(split(/ /, $( ))[0];
77     my($rdev,$size)=(0,1);
78     my($atime,$mtime,$ctime)=($last_update) x 3;
79     my($blksize,$blocks)=(512,1);
80     my $mode=$self->mode( $path->isdir() ? $TYPE_DIR : $TYPE_SYMLINK );
81     return($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
82            $atime, $mtime, $ctime, $blksize, $blocks);
83 }
84
85 sub readlink
86 {
87     my($self,$filename)=@_;
88 #    print "**READLINK: $filename\n";
89     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
90     return(-EINVAL()) unless($path->isfile());
91     return $path->dest($self->{mountpoint});
92 }
93
94 sub getdir
95 {
96     my($self, $filename)=@_;
97 #    print "**GETDIR: $filename\n";
98     my $path=ID3FS::Path->new($self->{db}, $filename, $self->{verbose}, $self->{tagdepth});
99     return(-ENOENT()) unless($path->isvalid());
100     return(-ENOTDIR()) unless($path->isdir());
101     my @dents=();
102     my($dirs, $files)=$path->dirents();
103     # too slow
104 #    push(@dents, $path->filter(@$dirs));
105     push(@dents, @$dirs);
106     push(@dents, @$files);
107     if(@dents)
108     {
109         return( (".", "..", @dents, 0) );
110     }
111     return(0);
112 }
113
114 # unused stubs
115 sub mknod       { print "FUSE: mknod\n";       return -EROFS();      }
116 sub mkdir       { print "FUSE: mkdir\n";       return -EROFS();      }
117 sub unlink      { print "FUSE: unlink\n";      return -EROFS();      }
118 sub rmdir       { print "FUSE: rmdir\n";       return -EROFS();      }
119 sub symlink     { print "FUSE: symlink\n";     return -EROFS();      }
120 sub rename      { print "FUSE: rename\n";      return -EROFS();      }
121 sub link        { print "FUSE: link\n";        return -EROFS();      }
122 sub chmod       { print "FUSE: chmod\n";       return -EROFS();      }
123 sub chown       { print "FUSE: chown\n";       return -EROFS();      }
124 sub truncate    { print "FUSE: truncate\n";    return -EROFS();      }
125 sub utime       { print "FUSE: utime\n";       return -EINVAL();     }
126 sub open        { print "FUSE: open\n";        return -EINVAL();     }
127 sub read        { print "FUSE: read\n";        return -EINVAL();     }
128 sub write       { print "FUSE: write\n";       return -EROFS();      }
129 sub statfs      { print "FUSE: statfs\n";      return -EINVAL();     }
130 sub release     { print "FUSE: release\n";     return 0;             }
131 sub fsync       { print "FUSE: fsync\n";       return 0;             }
132 sub setxattr    { print "FUSE: setxattr\n";    return -EOPNOTSUPP(); }
133 sub getxattr    { print "FUSE: getxattr\n";    return -EOPNOTSUPP(); }
134 sub listxattr   { print "FUSE: listxattr\n";   return -EOPNOTSUPP(); }
135 sub removexattr { print "FUSE: removexattr\n"; return -EOPNOTSUPP(); }
136
137 sub mode
138 {
139     my($self, $type)=@_;
140     return(($type << 9) | $self->{perms});
141 }
142
143 1;