X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=examples%2Ffioc.pl;h=35115d5a37c2153c7e6c4724f38d68c6e106914a;hb=e6ca93074661d3d28f01d3cc96d00a252952803e;hp=1d76b2c7b0a2fa45f9969f92de4d213d4c185bf5;hpb=40aaef12a77d6a22b6d325afe8c4533645cf6ce0;p=perl-fuse.git diff --git a/examples/fioc.pl b/examples/fioc.pl index 1d76b2c..35115d5 100755 --- a/examples/fioc.pl +++ b/examples/fioc.pl @@ -1,33 +1,44 @@ #!/usr/bin/env perl +# fioc.pl: A Perl conversion of the fioc example IOCTL server program +# from the FUSE distribution. I've endeavored to stay pretty close +# structure-wise to the C version, while using Perl-specific features. +# I wrote this to provide a way to verify my ioctl() wrapper +# implementation would work properly. So far, it seems to, and it will +# interoperate with the C client as well. + use strict; no strict qw(refs); +use threads; +use threads::shared; + use Carp; local $SIG{'__WARN__'} = \&Carp::cluck; -use Fuse; +use Fuse qw(:all); use Fcntl qw(:mode); use POSIX; -my $fioc_size = 0; +my $fioc_size :shared = 0; use constant FIOC_NAME => 'fioc'; -my $fioc_buf = ''; +my $fioc_buf :shared = ''; use constant FIOC_NONE => 0; use constant FIOC_ROOT => 1; use constant FIOC_FILE => 2; require 'asm/ioctl.ph'; -our %sizeof = ('int' => 4); -sub FIOC_GET_SIZE { _IOR(ord 'E', 0, 'int'); } -sub FIOC_SET_SIZE { _IOW(ord 'E', 1, 'int'); } +our %sizeof = ('size_t' => length(pack('L!'))); +sub FIOC_GET_SIZE { _IOR(ord 'E', 0, 'size_t'); } +sub FIOC_SET_SIZE { _IOW(ord 'E', 1, 'size_t'); } +sub TCGETS { 0x5401; } sub fioc_resize { my ($size) = @_; print 'called ', (caller(0))[3], "\n"; return 0 if $size == $fioc_size; - + if ($size < $fioc_size) { $fioc_buf = substr($fioc_buf, 0, $size); } @@ -84,9 +95,7 @@ sub fioc_open { my ($path, $flags, $info) = @_; print 'called ', (caller(0))[3], "\n"; - if (fioc_file_type($path) != FIOC_NONE) { - return 0; - } + return 0 if fioc_file_type($path) != FIOC_NONE; return -&ENOENT; } @@ -95,10 +104,7 @@ sub fioc_read { print 'called ', (caller(0))[3], "\n"; return -&EINVAL if fioc_file_type($path) != FIOC_FILE; - - if ($offset > $fioc_size) { - return q{}; - } + return q{} if $offset > $fioc_size; if ($size > $fioc_size - $offset) { $size - $fioc_size - $offset; @@ -110,12 +116,10 @@ sub fioc_read { sub fioc_write { my ($path, $data, $offset) = @_; print 'called ', (caller(0))[3], "\n"; + lock($fioc_buf); return -&EINVAL if fioc_file_type($path) != FIOC_FILE; - - if (fioc_expand($offset + length($data))) { - return -&ENOMEM; - } + return -&ENOMEM if fioc_expand($offset + length($data)); substr($fioc_buf, $offset, length($data), $data); return length($data); @@ -124,6 +128,7 @@ sub fioc_write { sub fioc_truncate { my ($path, $size) = @_; print 'called ', (caller(0))[3], "\n"; + lock($fioc_buf); return -&EINVAL if fioc_file_type($path) != FIOC_FILE; @@ -142,19 +147,23 @@ sub fioc_readdir { sub fioc_ioctl { my ($path, $cmd, $flags, $data) = @_; print 'called ', (caller(0))[3], "\n"; - $cmd = unpack('L', pack('l', $cmd)); return -&EINVAL if fioc_file_type($path) != FIOC_FILE; - - return -&ENOSYS if $flags & 0x1; + return -&ENOSYS if $flags & FUSE_IOCTL_COMPAT; if ($cmd == FIOC_GET_SIZE) { - return(0, pack('L', $fioc_size)); + return(0, pack('L!', $fioc_size)); } elsif ($cmd == FIOC_SET_SIZE) { - fioc_resize(unpack('L', $data)); + lock($fioc_buf); + fioc_resize(unpack('L!', $data)); return 0; } + elsif ($cmd == TCGETS) { + # perl sends TCGETS as part of calling isatty() on opening a file; + # this appears to be a more canonical answer + return -&ENOTTY; + } return -&EINVAL; } @@ -169,4 +178,5 @@ Fuse::main( 'open' => 'main::fioc_open', 'read' => 'main::fioc_read', 'write' => 'main::fioc_write', - 'ioctl' => 'main::fioc_ioctl'); + 'ioctl' => 'main::fioc_ioctl', + 'threaded' => 1);