/[fuse.before_github]/perl-llin/examples/filter_attr_fs.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /perl-llin/examples/filter_attr_fs.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 116 - (show annotations)
Thu Dec 6 10:58:07 2007 UTC (16 years, 4 months ago) by dpavlin
File MIME type: text/plain
File size: 6378 byte(s)
Added contributed filesystem described in e-mail message below:

From: Reuben Thomas <rrt@sc3d.org>
To: dpavlin@rot13.org
Subject: Contribution of sample FS to Fuse

Hi,

I'm just putting the finishing touches to an FS I wrote with Fuse, which
was invaluable, as I couldn't contemplate writing it in C (it's just not
important enough for that much pain!).

I've called it filter_attr_t.pl. It is just loopback_t.pl, augmented with a
function and a little logic so that only files that possess extended
attribute given at mount time are visible. Further, if you try to write to
a file that exists but is not tagged (and hence invisible), you get
-EEXIST, and if you try to unlink a tagged file, it is merely untagged
rather than actually unlinked.

My use for this is to use the backup program Unison, which synchronises two
directory trees, to synch my PDA and my home directory, while excluding
most of the files in my home dir (which would simply not fit in my PDA's
16Mb of file space!). I was amazed to find I couldn't see a FUSE fs which
would do this already, and I was nearly in despair when I remembered Fuse,
and, sure enough, it looked a lot easier than writing a FUSE fs in C.

Of course, the example code was also invaluable, as without it I would have
taken much longer to write the code, and I wouldn't have known some of the
traps.

So, a big thank you, and I attach the current version.

--
http://rrt.sc3d.org/ | Slow Pedestrian Crossing (Anon)
1 #!/usr/bin/perl -w
2 # filter_attr_t.pl
3 # Loopback fs that shows only files with a particular xattr
4
5 # Reuben Thomas 29th November 2007, based on example code from Fuse package
6
7 use strict;
8 #use blib;
9
10 use Fuse;
11 use File::ExtAttr ':all';
12 use IO::File;
13 use POSIX qw(ENOENT ENOSYS EEXIST EPERM O_RDONLY O_RDWR O_APPEND O_CREAT O_ACCMODE);
14 use Fcntl qw(S_ISBLK S_ISCHR S_ISFIFO SEEK_SET);
15
16 # Debug flag
17 #my $debug = 1;
18
19 # Global settings
20 my ($tag, $real_root, $mountpoint);
21
22
23 sub debug {
24 print STDERR shift if $debug;
25 }
26
27 my $can_syscall = eval {
28 require 'syscall.ph'; # for SYS_mknod and SYS_lchown
29 };
30
31 if (!$can_syscall && open my $fh, '<', '/usr/include/sys/syscall.h') {
32 my %sys = do { local $/ = undef;
33 <$fh> =~ m/\#define \s+ (\w+) \s+ (\d+)/gxms;
34 };
35 close $fh;
36 if ($sys{SYS_mknod} && $sys{SYS_lchown}) {
37 *SYS_mknod = sub { $sys{SYS_mknod} };
38 *SYS_lchown = sub { $sys{SYS_lchown} };
39 $can_syscall = 1;
40 }
41 }
42
43 sub tagged {
44 my ($file) = @_;
45 $file =~ s|/$||;
46 my $ret = getfattr($file, $tag);
47 debug("tagged: $file $tag " . defined($ret) . "\n");
48 return $ret;
49 }
50
51 sub tag {
52 return setfattr(shift, $tag, "");
53 }
54
55 sub detag {
56 return delfattr(shift, $tag);
57 }
58
59 sub append_root {
60 return $real_root . shift;
61 }
62
63 sub err {
64 my ($err) = @_;
65 return $err ? 0 : -$!;
66 }
67
68 sub x_getattr {
69 debug("x_getattr ");
70 my ($file) = append_root(shift);
71 return -ENOENT() unless tagged($file);
72 my (@list) = lstat($file);
73 return -$! unless @list;
74 return @list;
75 }
76
77 sub x_readlink {
78 debug("x_readlink ");
79 return readlink(append_root(shift));
80 }
81
82 sub x_getdir {
83 debug("x_getdir ");
84 my ($dirname) = append_root(shift);
85 return -ENOENT() unless tagged($dirname) && opendir(DIRHANDLE, $dirname);
86 my (@files) = readdir(DIRHANDLE);
87 closedir(DIRHANDLE);
88 my @psifiles = grep {tagged("$dirname/$_")} @files;
89 return (@psifiles, 0);
90 }
91
92 sub x_mknod {
93 my ($file, $modes, $dev) = @_;
94 return -ENOSYS() if !$can_syscall;
95 debug("x_mknod ");
96 $file = append_root($file);
97 return -EEXIST() if -e $file && !tagged($file);
98 $! = 0;
99 syscall(&SYS_mknod, $file, $modes, $dev);
100 tag($file) if $! == 0;
101 return -$!;
102 }
103
104 sub x_mkdir {
105 debug("x_mkdir ");
106 my ($name, $perm) = @_;
107 $name = append_root($name);
108 return err(mkdir($name, $perm));
109 }
110
111 sub x_open {
112 my ($file) = append_root(shift);
113 my ($mode) = shift;
114 my $accmode = $mode & O_ACCMODE;
115 debug("x_open $accmode " . O_ACCMODE . " " . O_WRONLY . " " . O_RDWR . " ");
116 if ($accmode == O_WRONLY || $accmode == O_RDWR) {
117 return -EEXIST() if -e $file && !tagged($file);
118 } else {
119 return -ENOENT() unless tagged($file);
120 }
121 return -$! unless sysopen(FILE, $file, $mode);
122 close(FILE);
123 return 0;
124 }
125
126 sub x_read {
127 debug("x_read ");
128 my ($file, $bufsize, $off) = @_;
129 my ($rv) = -ENOSYS();
130 my ($handle) = new IO::File;
131 $file = append_root($file);
132 return -ENOENT() unless tagged($file);
133 my ($fsize) = -s $file;
134 return -ENOSYS() unless open($handle, $file);
135 if(seek($handle, $off, SEEK_SET)) {
136 read($handle, $rv, $bufsize);
137 }
138 return $rv;
139 }
140
141 sub x_write {
142 debug("x_write ");
143 my ($file, $buf, $off) = @_;
144 my ($rv);
145 $file = append_root($file);
146 return -ENOENT() unless tagged($file);
147 my ($fsize) = -s $file;
148 return -ENOSYS() unless open(FILE, '+<', $file);
149 if ($rv = seek(FILE, $off, SEEK_SET)) {
150 $rv = print(FILE $buf);
151 }
152 $rv = -ENOSYS() unless $rv;
153 close(FILE);
154 return length($buf);
155 }
156
157 sub x_unlink {
158 debug("x_unlink ");
159 my ($file) = append_root(shift);
160 return -ENOENT() unless tagged($file);
161 return err(detag($file));
162 }
163
164 sub x_symlink {
165 debug("x_symlink ");
166 my ($old) = shift;
167 my ($new) = append_root(shift);
168 return -EEXIST() if -e $new && !tagged($new);
169 return err(symlink($old, $new));
170 }
171
172 sub x_rename {
173 debug("x_rename ");
174 my ($old) = append_root(shift);
175 my ($new) = append_root(shift);
176 return -ENOENT() unless tagged($old);
177 return -EEXIST() unless !-e $new || tagged($new);
178 my ($err) = rename($old, $new) ? 0 : -ENOENT();
179 return $err;
180 }
181
182 sub x_link {
183 debug("x_link ");
184 my ($old) = append_root(shift);
185 my ($new) = append_root(shift);
186 return -ENOENT() unless tagged($old);
187 return -EEXIST() unless !-e $new || tagged($new);
188 return err(link($old, $new));
189 }
190
191 sub x_chown {
192 return -ENOSYS() if !$can_syscall;
193 debug("x_chown ");
194 my ($fn) = append_root(shift);
195 return -ENOENT() unless tagged($fn);
196 my ($uid, $gid) = @_;
197 # perl's chown() does not chown symlinks, it chowns the symlink's
198 # target. it fails when the link's target doesn't exist, because
199 # the stat64() syscall fails.
200 # this causes error messages when unpacking symlinks in tarballs.
201 my ($err) = syscall(&SYS_lchown, $fn, $uid, $gid, $fn) ? -$! : 0;
202 return $err;
203 }
204
205 sub x_chmod {
206 debug("x_chmod ");
207 my ($fn) = append_root(shift);
208 return -ENOENT() unless tagged($fn);
209 my ($mode) = shift;
210 return err(chmod($mode, $fn));
211 }
212
213 sub x_truncate {
214 debug("x_truncate ");
215 my ($fn) = append_root(shift);
216 return -ENOENT() unless tagged($fn);
217 return err(truncate($fn, shift));
218 }
219
220 sub x_utime {
221 debug("x_utime ");
222 my ($fn) = append_root($_[0]);
223 return -ENOENT() unless tagged($fn);
224 return err(utime($_[1], $_[2], $fn));
225 }
226
227 sub x_rmdir {
228 debug("x_rmdir ");
229 my $dir = append_root(shift);
230 return -ENOENT() unless tagged($dir);
231 return err(detag($dir));
232 }
233
234 sub x_statfs {
235 debug("x_statfs\n");
236 my $name = append_root(shift);
237 my($bsize, $frsize, $blocks, $bfree, $bavail,
238 $files, $ffree, $favail, $fsid, $basetype, $flag,
239 $namemax, $fstr) = statvfs($real_root) || return -$!;
240 return ($namemax, $files, $ffree, $blocks, $bavail, $bsize);
241 }
242
243 # If you run the script directly, it will run fusermount, which will in turn
244 # re-run this script. Hence the funky semantics.
245
246 # Parse command-line arguments
247 $mountpoint = "";
248 if (@ARGV) {
249 $tag = shift(@ARGV);
250 $real_root = shift(@ARGV);
251 $mountpoint = shift(@ARGV);
252 }
253
254 # Start up FUSE
255 Fuse::main(
256 mountpoint=>$mountpoint,
257 # debug => 1,
258 getattr =>"main::x_getattr",
259 readlink=>"main::x_readlink",
260 getdir =>"main::x_getdir",
261 mknod =>"main::x_mknod",
262 mkdir =>"main::x_mkdir",
263 unlink =>"main::x_unlink",
264 rmdir =>"main::x_rmdir",
265 symlink =>"main::x_symlink",
266 rename =>"main::x_rename",
267 link =>"main::x_link",
268 chmod =>"main::x_chmod",
269 chown =>"main::x_chown",
270 truncate=>"main::x_truncate",
271 utime =>"main::x_utime",
272 open =>"main::x_open",
273 read =>"main::x_read",
274 write =>"main::x_write",
275 statfs =>"main::x_statfs",
276 );

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26