346118086725c2368095d8d1ecf69a882dc93037
[perl-fuse.git] / examples / fioc.pl
1 #!/usr/bin/env perl
2
3 use strict;
4 no strict qw(refs);
5
6 use threads;
7 use threads::shared;
8
9 use Carp;
10 local $SIG{'__WARN__'} = \&Carp::cluck;
11
12 use Fuse;
13 use Fcntl qw(:mode);
14 use POSIX;
15
16 my $fioc_size :shared = 0;
17 use constant FIOC_NAME => 'fioc';
18 my $fioc_buf :shared = '';
19 use constant FIOC_NONE  => 0;
20 use constant FIOC_ROOT  => 1;
21 use constant FIOC_FILE  => 2;
22
23 require 'asm/ioctl.ph';
24
25 our %sizeof = ('int' => 4);
26 sub FIOC_GET_SIZE { _IOR(ord 'E', 0, 'int'); }
27 sub FIOC_SET_SIZE { _IOW(ord 'E', 1, 'int'); }
28
29 sub fioc_resize {
30     my ($size) = @_;
31     print 'called ', (caller(0))[3], "\n";
32     return 0 if $size == $fioc_size;
33
34     if ($size < $fioc_size) {
35         $fioc_buf = substr($fioc_buf, 0, $size);
36     }
37     else {
38         $fioc_buf .= "\0" x ($size - $fioc_size);
39     }
40     $fioc_size = $size;
41     return 0;
42 }
43
44 sub fioc_expand {
45     my ($size) = @_;
46     print 'called ', (caller(0))[3], "\n";
47     if ($size > $fioc_size) {
48         return fioc_resize($size);
49     }
50     return 0;
51 }
52
53 sub fioc_file_type {
54     my ($path) = @_;
55     print 'called ', (caller(0))[3], "\n";
56     return FIOC_ROOT if $path eq '/';
57     return FIOC_FILE if $path eq '/' . FIOC_NAME;
58     return FIOC_NONE;
59 }
60
61 sub fioc_getattr {
62     my ($path) = @_;
63     print 'called ', (caller(0))[3], "\n";
64     my @stbuf = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
65
66     $stbuf[4] = $<;
67     $stbuf[5] = (split(/\s+/, $())[0];
68     $stbuf[8] = $stbuf[9] = time();
69
70     my $type = fioc_file_type($path);
71     if ($type == FIOC_ROOT) {
72         $stbuf[2] = S_IFDIR | 0755;
73         $stbuf[3] = 2;
74     }
75     elsif ($type == FIOC_FILE) {
76         $stbuf[2] = S_IFREG | 0644;
77         $stbuf[3] = 1;
78         $stbuf[7] = $fioc_size;
79     }
80     else {
81         return -&ENOENT;
82     }
83     return @stbuf;
84 }
85
86 sub fioc_open {
87     my ($path, $flags, $info) = @_;
88     print 'called ', (caller(0))[3], "\n";
89
90     if (fioc_file_type($path) != FIOC_NONE) {
91         return 0;
92     }
93     return -&ENOENT;
94 }
95
96 sub fioc_read {
97     my ($path, $size, $offset) = @_;
98     print 'called ', (caller(0))[3], "\n";
99
100     return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
101
102     if ($offset > $fioc_size) {
103         return q{};
104     }
105
106     if ($size > $fioc_size - $offset) {
107         $size - $fioc_size - $offset;
108     }
109
110     return substr($fioc_buf, $offset, $size);
111 }
112
113 sub fioc_write {
114     my ($path, $data, $offset) = @_;
115     print 'called ', (caller(0))[3], "\n";
116     lock($fioc_buf);
117
118     return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
119
120     if (fioc_expand($offset + length($data))) {
121         return -&ENOMEM;
122     }
123
124     substr($fioc_buf, $offset, length($data), $data);
125     return length($data);
126 }
127
128 sub fioc_truncate {
129     my ($path, $size) = @_;
130     print 'called ', (caller(0))[3], "\n";
131     lock($fioc_buf);
132
133     return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
134
135     return fioc_resize($size);
136 }
137
138 sub fioc_readdir {
139     my ($path, $offset) = @_;
140     print 'called ', (caller(0))[3], "\n";
141
142     return -&EINVAL if fioc_file_type($path) != FIOC_ROOT;
143
144     return ('.', '..', FIOC_NAME, 0);
145 }
146
147 sub fioc_ioctl {
148     my ($path, $cmd, $flags, $data) = @_;
149     print 'called ', (caller(0))[3], "\n";
150     $cmd = unpack('L', pack('l', $cmd));
151
152     return -&EINVAL if fioc_file_type($path) != FIOC_FILE;
153
154     return -&ENOSYS if $flags & 0x1;
155
156     if ($cmd == FIOC_GET_SIZE) {
157         return(0, pack('L', $fioc_size));
158     }
159     elsif ($cmd == FIOC_SET_SIZE) {
160         lock($fioc_buf);
161         fioc_resize(unpack('L', $data));
162         return 0;
163     }
164
165     return -&EINVAL;
166 }
167
168 croak("Fuse doesn't have ioctl") unless Fuse::fuse_version() >= 2.8;
169
170 Fuse::main(
171     'mountpoint' => $ARGV[0],
172     'getattr'   => 'main::fioc_getattr',
173     'readdir'   => 'main::fioc_readdir',
174     'truncate'  => 'main::fioc_truncate',
175     'open'      => 'main::fioc_open',
176     'read'      => 'main::fioc_read',
177     'write'     => 'main::fioc_write',
178     'ioctl'     => 'main::fioc_ioctl',
179     'threaded'  => 1);