3 # fioc.pl: A Perl conversion of the fioc example IOCTL server program
4 # from the FUSE distribution. I've endeavored to stay pretty close
5 # structure-wise to the C version, while using Perl-specific features.
6 # I wrote this to provide a way to verify my ioctl() wrapper
7 # implementation would work properly. So far, it seems to, and it will
8 # interoperate with the C client as well.
17 local $SIG{'__WARN__'} = \&Carp::cluck;
23 my $fioc_size :shared = 0;
24 use constant FIOC_NAME => 'fioc';
25 my $fioc_buf :shared = '';
26 use constant FIOC_NONE => 0;
27 use constant FIOC_ROOT => 1;
28 use constant FIOC_FILE => 2;
30 require 'asm/ioctl.ph';
32 our %sizeof = ('size_t' => length(pack('L!')));
33 sub FIOC_GET_SIZE { _IOR(ord 'E', 0, 'size_t'); }
34 sub FIOC_SET_SIZE { _IOW(ord 'E', 1, 'size_t'); }
35 sub TCGETS { 0x5401; }
36 use constant FUSE_IOCTL_COMPAT => 0x1;
40 print 'called ', (caller(0))[3], "\n";
41 return 0 if $size == $fioc_size;
43 if ($size < $fioc_size) {
44 $fioc_buf = substr($fioc_buf, 0, $size);
47 $fioc_buf .= "\0" x ($size - $fioc_size);
55 print 'called ', (caller(0))[3], "\n";
56 if ($size > $fioc_size) {
57 return fioc_resize($size);
64 print 'called ', (caller(0))[3], "\n";
65 return FIOC_ROOT if $path eq '/';
66 return FIOC_FILE if $path eq '/' . FIOC_NAME;
72 print 'called ', (caller(0))[3], "\n";
73 my @stbuf = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
76 $stbuf[5] = (split(/\s+/, $())[0];
77 $stbuf[8] = $stbuf[9] = time();
79 my $type = fioc_file_type($path);
80 if ($type == FIOC_ROOT) {
81 $stbuf[2] = S_IFDIR | 0755;
84 elsif ($type == FIOC_FILE) {
85 $stbuf[2] = S_IFREG | 0644;
87 $stbuf[7] = $fioc_size;
96 my ($path, $flags, $info) = @_;
97 print 'called ', (caller(0))[3], "\n";
99 return 0 if fioc_file_type($path) != FIOC_NONE;
104 my ($path, $size, $offset) = @_;
105 print 'called ', (caller(0))[3], "\n";
107 return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
108 return q{} if $offset > $fioc_size;
110 if ($size > $fioc_size - $offset) {
111 $size - $fioc_size - $offset;
114 return substr($fioc_buf, $offset, $size);
118 my ($path, $data, $offset) = @_;
119 print 'called ', (caller(0))[3], "\n";
122 return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
123 return -&ENOMEM if fioc_expand($offset + length($data));
125 substr($fioc_buf, $offset, length($data), $data);
126 return length($data);
130 my ($path, $size) = @_;
131 print 'called ', (caller(0))[3], "\n";
134 return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
136 return fioc_resize($size);
140 my ($path, $offset) = @_;
141 print 'called ', (caller(0))[3], "\n";
143 return -&EINVAL if fioc_file_type($path) != FIOC_ROOT;
145 return ('.', '..', FIOC_NAME, 0);
149 my ($path, $cmd, $flags, $data) = @_;
150 print 'called ', (caller(0))[3], "\n";
152 return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
153 return -&ENOSYS if $flags & FUSE_IOCTL_COMPAT;
155 if ($cmd == FIOC_GET_SIZE) {
156 return(0, pack('L!', $fioc_size));
158 elsif ($cmd == FIOC_SET_SIZE) {
160 fioc_resize(unpack('L!', $data));
163 elsif ($cmd == TCGETS) {
164 # perl sends TCGETS as part of calling isatty() on opening a file;
165 # this appears to be a more canonical answer
172 croak("Fuse doesn't have ioctl") unless Fuse::fuse_version() >= 2.8;
175 'mountpoint' => $ARGV[0],
176 'getattr' => 'main::fioc_getattr',
177 'readdir' => 'main::fioc_readdir',
178 'truncate' => 'main::fioc_truncate',
179 'open' => 'main::fioc_open',
180 'read' => 'main::fioc_read',
181 'write' => 'main::fioc_write',
182 'ioctl' => 'main::fioc_ioctl',