sub tags
{
- my($self, $path)=@_;
- my $sql="SELECT DISTINCT name FROM tags;";
- my $tags=$self->cmd_rows($sql);
+ my($self, @constraints)=@_;
+ if(!@constraints) # /
+ {
+ my $sql="SELECT DISTINCT name FROM tags;";
+ my $tags=$self->cmd_rows($sql);
+ return(map { $_->[0]; } @$tags);
+ }
+ my @file_ids=();
+ my @tag_ids=();
+ my $main_sql_start=("SELECT DISTINCT tags.name FROM files\n" .
+ "INNER JOIN files_x_tags ON files.id=files_x_tags.files_id\n" .
+ "INNER JOIN tags ON tags.id=files_x_tags.tags_id\n" .
+ "WHERE files.id in (" .
+ ("\tSELECT DISTINCT files.id FROM files\n" .
+ "\tINNER JOIN files_x_tags ON files.id=files_x_tags.files_id\n" .
+ "\tINNER JOIN tags ON tags.id=files_x_tags.tags_id\n" .
+ "\tWHERE tags.id in ("));
+ my $main_sql_mid=")\n) AND tags.id NOT IN (";
+ my $main_sql_end=")\n";
+ while(my $constraint=shift @constraints)
+ {
+ print "CONSTRAINT: $constraint->{name}\n";
+ my $cid=$constraint->{id};
+ push(@tag_ids, $cid);
+ }
+ my $sql = ($main_sql_start . join(", ", @tag_ids) .
+ $main_sql_mid . join(", ", @tag_ids) .
+ $main_sql_end);
+ print "SQL: $sql\n";
+ my $result=$self->cmd_rows($sql);
+ my @tagnames=map { $_->[0]; } @$result;
+ print "SUBNAMES: ", join(', ', @tagnames), "\n";
+ return(@tagnames);
+}
+
+sub tag_values
+{
+ my($self, $tag)=@_;
+ my $sql=("SELECT DISTINCT tagvals.name FROM tags\n" .
+ "INNER JOIN tags_x_tagvals ON tags.id=tags_x_tagvals.tags_id\n" .
+ "INNER JOIN tagvals ON tagvals.id=tags_x_tagvals.tagvals_id\n" .
+ "WHERE tags.name=?");
+ my $tags=$self->cmd_rows($sql, $tag);
return(map { $_->[0]; } @$tags);
}
+sub tag_id
+{
+ my($self, $tag)=@_;
+ my $sql='SELECT id FROM tags WHERE name=?';
+ my ($id)=$self->cmd_onerow($sql, $tag);
+ return($id);
+}
+
sub add
{
my($self,$path)=@_;
use warnings;
use ID3FS::Path;
use Fuse;
-use POSIX qw(EINVAL EROFS EOPNOTSUPP S_IRUSR S_IRGRP S_IROTH S_IXUSR S_IXGRP S_IXOTH);
+use POSIX qw(EINVAL EROFS ENOENT EOPNOTSUPP S_IRUSR S_IRGRP S_IROTH S_IXUSR S_IXGRP S_IXOTH);
use vars qw($TYPE_DIR $TYPE_SYMLINK);
($TYPE_DIR, $TYPE_SYMLINK)=(0040, 0120);
sub getattr
{
my($self, $filename)=@_;
- print "GETATTR: $filename\n";
+ print "**GETATTR: $filename\n";
+ my $path=ID3FS::Path->new($self->{db}, $filename);
+ return(-ENOENT()) unless($path->isvalid());
my($dev,$ino,$nlink)=(0,0,1);
my $uid=$<;
my $gid=(split(/ /, $( ))[0];
my($rdev,$size)=(0,1);
my($atime,$mtime,$ctime)=(0,0,0);
my($blksize,$blocks)=(512,1);
-
- my $path=ID3FS::Path->new($self->{db}, $filename);
my $mode=$self->mode( $path->isdir() ? $TYPE_DIR : $TYPE_SYMLINK );
return($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks);
sub readlink
{
my($self,$filename)=@_;
- print "READLINK: $filename\n";
+ print "**READLINK: $filename\n";
my $path=ID3FS::Path->new($self->{db}, $filename);
return(-EINVAL()) if($path->isdir());
return $path->dest();
sub getdir
{
my($self, $filename)=@_;
- print "GETDIR: $filename\n";
+ print "**GETDIR: $filename\n";
my $path=ID3FS::Path->new($self->{db}, $filename);
+ return(-ENOENT()) unless($path->isvalid());
if($path->isdir())
{
return(".", "..", $path->dirents(), 0);
use strict;
use warnings;
+use ID3FS::PathElement::Artist;
+use ID3FS::PathElement::Album;
+use ID3FS::PathElement::Boolean;
+use ID3FS::PathElement::File;
+use ID3FS::PathElement::Tag;
+use ID3FS::PathElement::Tagval;
+
+our ($STATE_INVALID, $STATE_ROOT, $STATE_WANTMORE, $STATE_TAG, $STATE_TAGVAL,
+ $STATE_BOOL, $STATE_ARTIST, $STATE_ALBUM, $STATE_FILE)=(0..8);
sub new
{
$self->{db}=shift;
$self->{path}=shift;
-
+ $self->parse();
+ print "STATE: ", $self->state(), "\n";
return $self;
}
sub isdir
{
my($self)=@_;
- return 1 if($self->{path} eq "/");
- return 0;
+ if(($self->state() eq $STATE_FILE) ||
+ ($self->state() eq $STATE_INVALID))
+ {
+ return 0;
+ }
+ return 1;
+}
+
+sub isvalid
+{
+ my($self)=@_;
+ return($self->state() != $STATE_INVALID);
}
sub dest
sub dirents
{
my($self)=@_;
- return $self->{db}->tags();
+ return $self->{db}->tags(@{$self->{elements}});
+# elsif($self->state() == $STATE_WANTMORE)
+# {
+# return(qw(AND OR ALL));
+# }
}
+sub parse
+{
+ my($self)=@_;
+ @{$self->{components}}=split(/\//, $self->{path});
+ shift @{$self->{components}}; # drop empty field before leading /
+ print "PATH: $self->{path}\n";
+ print "COMPONENTS: ", join(' | ', @{$self->{components}}), "\n";
+ $self->state($STATE_ROOT);
+ return if($self->{path} eq "/");
+ my @parts=@{$self->{components}};
+ my($tag, $tagval);
+ $self->{elements}=[];
+ while(my $name=shift @parts)
+ {
+ print "NAME: $name\n";
+ if ($self->state() == $STATE_INVALID)
+ {
+ print "SM: INVALID: $name\n";
+ return;
+ }
+ elsif($self->state() == $STATE_ROOT)
+ {
+ print "SM: ROOT: $name\n";
+ $tag=ID3FS::PathElement::Tag->new($self->{db}, $name);
+ if($tag)
+ {
+ push(@{$self->{elements}}, $tag);
+ $self->state($STATE_WANTMORE);
+ }
+ else
+ {
+ $self->state($STATE_INVALID);
+ }
+ }
+ elsif($self->state() == $STATE_WANTMORE)
+ {
+ print "SM: WANTMORE: $name\n";
+ $tag=ID3FS::PathElement::Tag->new($self->{db}, $name);
+ if($tag)
+ {
+ push(@{$self->{elements}}, $tag);
+# $self->state($STATE_TAG);
+ }
+ else
+ {
+ $self->state($STATE_INVALID);
+ }
+# if(($name eq "AND") || ($name eq "OR"))
+# {
+# $self->state($STATE_BOOL);
+# push(@{$self->{elements}}, ID3FS::PathElement::Boolean->new($name));
+# }
+# elsif($name eq "ALL")
+# {
+# $self->state($STATE_ARTIST);
+# }
+# else
+# {
+# $self->state($STATE_INVALID);
+# }
+ }
+ elsif($self->state() == $STATE_TAG)
+ {
+ print "SM: TAG: $name\n";
+ $self->state($STATE_WANTMORE);
+ next;
+ my @valid_tagvals=$self->{db}->tag_values($tag);
+ print "TAGVALUES: $name: ", join(', ', @valid_tagvals), "\n";
+ if(@valid_tagvals)
+ {
+ if(grep { $name eq $_; } @valid_tagvals)
+ {
+ print "TAGVAL VALID\n";
+ $self->state($STATE_TAGVAL);
+ push(@{$self->{elements}}, ID3FS::PathElement::Tagval($name));
+ }
+ else
+ {
+ print "ERROR: unknown tagval: $tagval\n";
+ $self->state($STATE_INVALID);
+ }
+ }
+ else
+ {
+ $self->state($STATE_INVALID);
+ }
+ }
+ elsif($self->state() == $STATE_TAGVAL)
+ {
+ print "SM: TAGVAL: $name\n";
+ }
+ elsif($self->state() == $STATE_BOOL)
+ {
+ print "SM: BOOL: $name\n";
+ }
+ elsif($self->state() == $STATE_ARTIST)
+ {
+ print "SM: ARTIST: $name\n";
+ }
+ elsif($self->state() == $STATE_ALBUM)
+ {
+ print "SM: ALBUM: $name\n";
+ }
+ elsif($self->state() == $STATE_FILE)
+ {
+ print "SM: FILE: $name\n";
+ }
+ else
+ {
+ print "SM: ERROR: UNKNOWN STATE: $self->{state}\n";
+ $self->state($STATE_INVALID);
+ }
+ }
+}
+
+sub state
+{
+ my($self, $newstate)=@_;
+ $self->{state}=$newstate if(defined($newstate));
+ return $self->{state};
+}
1;
--- /dev/null
+package ID3FS::PathElement::Album;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{name}=shift;
+
+ return $self;
+}
+
+1;
--- /dev/null
+package ID3FS::PathElement::Artist;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{name}=shift;
+
+ return $self;
+}
+
+1;
--- /dev/null
+package ID3FS::PathElement::Boolean;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{name}=shift;
+
+ return $self;
+}
+
+1;
--- /dev/null
+package ID3FS::PathElement::File;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{name}=shift;
+
+ return $self;
+}
+
+1;
--- /dev/null
+package ID3FS::PathElement::Tag;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{db}=shift;
+ $self->{name}=shift;
+ $self->{id}=($self->{db}->tag_id($self->{name}));
+ return(undef) unless(defined($self->{id}));
+ print "TAG ID: $self->{id}\n";
+ return($self);
+}
+
+1;
--- /dev/null
+package ID3FS::PathElement::Tagval;
+
+use strict;
+use warnings;
+
+sub new
+{
+ my $proto=shift;
+ my $class=ref($proto) || $proto;
+ my $self={};
+ bless($self,$class);
+
+ $self->{name}=shift;
+
+ return $self;
+}
+
+1;