From: Ian Beckwith Date: Tue, 21 Sep 2010 03:43:28 +0000 (+0100) Subject: basic tag path traversal X-Git-Tag: debian/1.0-1~197 X-Git-Url: http://erislabs.net/gitweb/?p=id3fs.git;a=commitdiff_plain;h=f942509a4e86a7f7b32d5575d8df6707e6f75660 basic tag path traversal --- diff --git a/lib/ID3FS/DB.pm b/lib/ID3FS/DB.pm index b8a2c8c..fe660d5 100644 --- a/lib/ID3FS/DB.pm +++ b/lib/ID3FS/DB.pm @@ -83,12 +83,60 @@ sub cmd_sth 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)=@_; diff --git a/lib/ID3FS/Fuse.pm b/lib/ID3FS/Fuse.pm index 68a1b52..de81df9 100644 --- a/lib/ID3FS/Fuse.pm +++ b/lib/ID3FS/Fuse.pm @@ -4,7 +4,7 @@ use strict; 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); @@ -63,15 +63,15 @@ sub run 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); @@ -80,7 +80,7 @@ sub getattr 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(); @@ -89,8 +89,9 @@ sub readlink 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); diff --git a/lib/ID3FS/Path.pm b/lib/ID3FS/Path.pm index b2202c2..7ceb45b 100644 --- a/lib/ID3FS/Path.pm +++ b/lib/ID3FS/Path.pm @@ -2,6 +2,15 @@ package ID3FS::Path; 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 { @@ -12,15 +21,26 @@ 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 @@ -32,8 +52,133 @@ 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; diff --git a/lib/ID3FS/PathElement/Album.pm b/lib/ID3FS/PathElement/Album.pm new file mode 100644 index 0000000..1a4b7d5 --- /dev/null +++ b/lib/ID3FS/PathElement/Album.pm @@ -0,0 +1,18 @@ +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; diff --git a/lib/ID3FS/PathElement/Artist.pm b/lib/ID3FS/PathElement/Artist.pm new file mode 100644 index 0000000..9a6c669 --- /dev/null +++ b/lib/ID3FS/PathElement/Artist.pm @@ -0,0 +1,18 @@ +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; diff --git a/lib/ID3FS/PathElement/Boolean.pm b/lib/ID3FS/PathElement/Boolean.pm new file mode 100644 index 0000000..8f2f35f --- /dev/null +++ b/lib/ID3FS/PathElement/Boolean.pm @@ -0,0 +1,18 @@ +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; diff --git a/lib/ID3FS/PathElement/File.pm b/lib/ID3FS/PathElement/File.pm new file mode 100644 index 0000000..2ec2f3b --- /dev/null +++ b/lib/ID3FS/PathElement/File.pm @@ -0,0 +1,18 @@ +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; diff --git a/lib/ID3FS/PathElement/Tag.pm b/lib/ID3FS/PathElement/Tag.pm new file mode 100644 index 0000000..7113b43 --- /dev/null +++ b/lib/ID3FS/PathElement/Tag.pm @@ -0,0 +1,21 @@ +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; diff --git a/lib/ID3FS/PathElement/Tagval.pm b/lib/ID3FS/PathElement/Tagval.pm new file mode 100644 index 0000000..43c2f49 --- /dev/null +++ b/lib/ID3FS/PathElement/Tagval.pm @@ -0,0 +1,18 @@ +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;