rfusefs 1.0.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.yardopts +2 -0
- data/CHANGES.md +43 -0
- data/LICENSE +24 -0
- data/README.md +83 -0
- data/TODO.md +7 -0
- data/lib/fuse/fusedir.rb +17 -2
- data/lib/fuse/rfusefs-fuse.rb +446 -414
- data/lib/fusefs/metadir.rb +5 -5
- data/lib/fusefs/pathmapper.rb +7 -7
- data/lib/fusefs/sqlitemapper.rb +7 -2
- data/lib/rfusefs.rb +20 -48
- data/lib/rfusefs/version.rb +1 -1
- metadata +35 -53
- data/.gitignore +0 -9
- data/.travis.yml +0 -8
- data/Gemfile +0 -4
- data/History.rdoc +0 -28
- data/README.rdoc +0 -107
- data/Rakefile +0 -22
- data/TODO.txt +0 -6
- data/rfusefs.gemspec +0 -31
- data/samples/demo.rb +0 -57
- data/samples/dictfs.rb +0 -74
- data/samples/hello.rb +0 -20
- data/samples/openurifs.rb +0 -53
- data/samples/railsfs.rb +0 -77
- data/samples/sqlfs.rb +0 -134
- data/samples/yamlfs.rb +0 -168
- data/spec-fusefs/fusefs_spec.rb +0 -12
- data/spec/metadir_spec.rb +0 -364
- data/spec/mount_unmount_spec.rb +0 -21
- data/spec/pathmapper_spec.rb +0 -417
- data/spec/rfusefs_spec.rb +0 -497
- data/spec/sample_spec.rb +0 -30
- data/spec/spec_helper.rb +0 -42
- data/spec/sqlitemapper_spec.rb +0 -135
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YWRhODkyYzJjZGNjYzc2YzM4ZTc5NjJhYWUyNjlkM2FiYzNjMGI4Nw==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7b262bbb9de179cfa71cc8b7c6c1b2e879557f364c2c6f923176fb607b7abeb0
|
4
|
+
data.tar.gz: 29566f13a740362789004fa7d865f0a9e6c3a75cd0f70551033a9b7b9b2ea092
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MWU1NTI5M2IyMjU2Y2Q2MjU3ZTQwNzcwN2EzYmQ2MzAwNzI1ZmFlNWJlYTll
|
11
|
-
Y2FkMDY5NmNkYThjNmZhYWUzMDQ2ZWQ4YmRkMmMwNTRkNzYxMWY=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
OTgxN2NmMWQ3MjBlZTQwODU4NTBlMTdiNjQ3NTMwNTZiYjUzMjUxMTZhZDg4
|
14
|
-
MTllMGUwODliMGJjMDkzNTQwNDhiYTZhNzUzMzg0MjNiNmRjZWUwNGE1Yjdh
|
15
|
-
NWY2NmE2YzYwNDg4NWJhNGRmYzI5MjZiYjhjZjZhNzUwOTZiZWM=
|
6
|
+
metadata.gz: ed3bf064022e69c006714709755d49848fda697bfdc1bf3b27126d9fdf7db1aee724ca71ddd3c44d621a8b8411904675c2f6e2b9559032cf229007ec7a5e2adf
|
7
|
+
data.tar.gz: cdcdde923e4ce54e0eafc909a67c275b57f8b354baa3fe3c02976163201fcfe0049b35d7e8ea00aa3b016dd4b60fe8fd76d0b97b1bb89bf74678aa3055265bdd
|
data/.yardopts
ADDED
data/CHANGES.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
1.1.1 / 2020-11
|
2
|
+
---------------
|
3
|
+
* fix gemspec
|
4
|
+
|
5
|
+
1.1.0 / 2020-10
|
6
|
+
---------------
|
7
|
+
|
8
|
+
* With rfuse ~> 1.2
|
9
|
+
* Requires Ruby 2.5+
|
10
|
+
* Release via Travis CI
|
11
|
+
|
12
|
+
1.0.3 / 2014-12-22
|
13
|
+
----------------------
|
14
|
+
|
15
|
+
* Pushed some internals up to RFuse
|
16
|
+
* Allow filesystems to implement signal handlers
|
17
|
+
|
18
|
+
1.0.1 / 2013-12-19
|
19
|
+
------------------
|
20
|
+
|
21
|
+
* Add FuseFS.main to create pretty usage messages
|
22
|
+
* Support extended attributes in filesystems
|
23
|
+
* Updates and cleanup of PathMapperFS
|
24
|
+
* Provide SqliteMapperFS
|
25
|
+
|
26
|
+
1.0.0 / 2012-08-07
|
27
|
+
------------------
|
28
|
+
|
29
|
+
* Depend on new rfuse 1.0.0, Ruby 1.9
|
30
|
+
* API breaking changes
|
31
|
+
* order of arguments to {FuseFS.mount}, {FuseFS.start} changed
|
32
|
+
to account for better option handling in RFuse
|
33
|
+
|
34
|
+
0.8.0 / 2011-02-19
|
35
|
+
------------------
|
36
|
+
|
37
|
+
* Initial port from fusefs
|
38
|
+
|
39
|
+
* Improved raw methods
|
40
|
+
* new "times" api for including atime,mtime,ctime in stat results
|
41
|
+
* metadir allow mv directories
|
42
|
+
* includes PathMapperFS
|
43
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
* Copyright (c) 2005 Greg Millam. (FuseFS)
|
4
|
+
* Copyright (c) 2009 Kyle Maxwell. (FuseFS)
|
5
|
+
* Copyright (c) 2012 - 2020 Grant Gardner. (RFuseFS)
|
6
|
+
|
7
|
+
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
of this software and associated documentation files (the 'Software'), to deal
|
10
|
+
in the Software without restriction, including without limitation the rights
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
13
|
+
furnished to do so, subject to the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
16
|
+
copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# rfusefs
|
2
|
+
|
3
|
+
* https://rubygems.org/gems/rfusefs
|
4
|
+
* https://github.com/lwoggardner/rfusefs
|
5
|
+
|
6
|
+
[<img src="https://badge.fury.io/rb/rfusefs.png" alt="Gem Version"
|
7
|
+
/>](http://badge.fury.io/rb/rfusefs)
|
8
|
+
## DESCRIPTION
|
9
|
+
|
10
|
+
RFuseFS is a port of the [FuseFS](http://rubygems.org/gems/fusefs/) library
|
11
|
+
aimed at allowing Ruby programmers to quickly and easily create virtual
|
12
|
+
filesystems with little more than a few lines of code.
|
13
|
+
|
14
|
+
RFuseFS is api compatible with FuseFS (0.7.0)
|
15
|
+
|
16
|
+
## SYNOPSIS
|
17
|
+
|
18
|
+
FuseFS provides a layer of abstraction to a programmer who wants to create a
|
19
|
+
virtual filesystem via FUSE.
|
20
|
+
|
21
|
+
First define a virtual directory by subclassing {FuseFS::FuseDir}
|
22
|
+
|
23
|
+
See samples under /samples and also the following starter classes
|
24
|
+
|
25
|
+
* {FuseFS::FuseDir}
|
26
|
+
* {FuseFS::MetaDir}
|
27
|
+
* {FuseFS::DirLink}
|
28
|
+
* {FuseFS::PathMapperFS}
|
29
|
+
* {FuseFS::SqliteMapperFS}
|
30
|
+
|
31
|
+
|
32
|
+
Then start your filesystem with
|
33
|
+
|
34
|
+
* {FuseFS.main} or {FuseFS.start}
|
35
|
+
|
36
|
+
|
37
|
+
Finally to use the filesystem open up your favourite file browser/terminal and
|
38
|
+
explore the contents under <mountpoint>
|
39
|
+
|
40
|
+
Happy Filesystem Hacking!
|
41
|
+
|
42
|
+
### the hello world filesystem in 14 LOC
|
43
|
+
|
44
|
+
require 'rfusefs'
|
45
|
+
|
46
|
+
class HelloDir
|
47
|
+
|
48
|
+
def contents(path)
|
49
|
+
['hello.txt']
|
50
|
+
end
|
51
|
+
|
52
|
+
def file?(path)
|
53
|
+
path == '/hello.txt'
|
54
|
+
end
|
55
|
+
|
56
|
+
def read_file(path)
|
57
|
+
"Hello, World!\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
# Usage: #{$0} mountpoint [mount_options]
|
63
|
+
FuseFS.main() { |options| HelloDir.new }
|
64
|
+
|
65
|
+
## REQUIREMENTS:
|
66
|
+
|
67
|
+
* FUSE (http://fuse.sourceforge.net)
|
68
|
+
* Ruby (>= 2.5)
|
69
|
+
* rfuse (~> 1.2)
|
70
|
+
|
71
|
+
|
72
|
+
## INSTALL:
|
73
|
+
|
74
|
+
* gem install rfusefs
|
75
|
+
|
76
|
+
## DEVELOPERS:
|
77
|
+
|
78
|
+
After checking out the source, run:
|
79
|
+
|
80
|
+
$ bundle install # install dependencies
|
81
|
+
$ rake spec # run tests
|
82
|
+
$ rake yard # generate docs
|
83
|
+
|
data/TODO.md
ADDED
data/lib/fuse/fusedir.rb
CHANGED
@@ -120,7 +120,21 @@ module FuseFS
|
|
120
120
|
# * {#file?}(from), {#can_write?}(to), {#can_delete?}(from) and if all true
|
121
121
|
# * {#read_file}(from), {#write_to}(to), {#delete}(from)
|
122
122
|
# * otherwise reject the rename
|
123
|
+
#
|
124
|
+
# === Signals
|
125
|
+
#
|
126
|
+
# The filesystem can handle a signal by providing a `sig<name>` method. eg 'sighup'
|
127
|
+
# {#sigint} and {#sigterm} are handled by default to provide a means to exit the filesystem
|
123
128
|
class FuseDir
|
129
|
+
|
130
|
+
# @!method sigint()
|
131
|
+
# @return [void]
|
132
|
+
# Handle the INT signal and exit the filesystem
|
133
|
+
|
134
|
+
# @!method sigterm()
|
135
|
+
# @return [void]
|
136
|
+
# Handle the TERM signal and exit the filesystem
|
137
|
+
|
124
138
|
INIT_TIMES = Array.new(3,0)
|
125
139
|
|
126
140
|
# base,rest = split_path(path)
|
@@ -258,7 +272,7 @@ module FuseFS
|
|
258
272
|
# @param [Integer] size
|
259
273
|
# @param [Object] raw the filehandle returned by {#raw_open}
|
260
274
|
# @abstract FuseFS api
|
261
|
-
# @return [
|
275
|
+
# @return [String] _sz_ bytes contents from file at path (or filehandle raw) starting at offset off
|
262
276
|
def raw_read(path,offset,size,raw=nil);end
|
263
277
|
|
264
278
|
# Write _sz_ bytes from file at path (or filehandle raw) starting at offset off
|
@@ -269,7 +283,7 @@ module FuseFS
|
|
269
283
|
|
270
284
|
# Sync buffered data to your filesystem
|
271
285
|
# @param [String] path
|
272
|
-
# @param [
|
286
|
+
# @param [Boolean] datasync only sync user data, not metadata
|
273
287
|
# @param [Object] raw the filehandle return by {#raw_open}
|
274
288
|
def raw_sync(path,datasync,raw=nil);end
|
275
289
|
|
@@ -307,6 +321,7 @@ module FuseFS
|
|
307
321
|
# @return [void]
|
308
322
|
def unmounted();end
|
309
323
|
|
324
|
+
|
310
325
|
end
|
311
326
|
|
312
327
|
DEFAULT_FS = FuseDir.new()
|
data/lib/fuse/rfusefs-fuse.rb
CHANGED
@@ -1,508 +1,540 @@
|
|
1
1
|
# RFuseFS - FuseFS over RFuse
|
2
2
|
require 'rfuse'
|
3
3
|
require 'fcntl'
|
4
|
+
require 'forwardable'
|
4
5
|
|
5
6
|
module FuseFS
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
7
|
+
#Which raw api should we use?
|
8
|
+
RFUSEFS_COMPATIBILITY = true unless FuseFS.const_defined?(:RFUSEFS_COMPATIBILITY)
|
9
|
+
|
10
|
+
class FileHandle
|
11
|
+
@@fh = 0
|
12
|
+
attr_reader :id,:flags,:path
|
13
|
+
attr_accessor :raw,:contents
|
14
|
+
def initialize(path,flags)
|
15
|
+
@id = (@@fh += 1)
|
16
|
+
@flags = flags
|
17
|
+
@path = path
|
18
|
+
@modified = false
|
19
|
+
@contents = ""
|
20
|
+
@size = 0
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def read(offset,size)
|
24
|
+
contents[offset,size]
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def create
|
28
|
+
@contents = ""
|
29
|
+
@modified = true
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
def write(offset,data)
|
33
|
+
# TODO: why append?
|
34
|
+
if append? || offset >= contents.length
|
35
|
+
#ignore offset
|
36
|
+
#TODO: should this zero fill?
|
37
|
+
contents << data
|
38
|
+
else
|
39
|
+
contents[offset,data.length]=data
|
40
|
+
end
|
41
|
+
@modified = true
|
42
|
+
return data.length
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
def flush
|
46
|
+
@modified = false
|
47
|
+
contents
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
def modified?
|
51
|
+
@modified
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
def accmode
|
55
|
+
flags & Fcntl::O_ACCMODE
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
def rdwr?
|
59
|
+
accmode == Fcntl::O_RDWR
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
def wronly?
|
63
|
+
accmode == Fcntl::O_WRONLY
|
64
|
+
end
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
def rdonly?
|
67
|
+
accmode == Fcntl::O_RDONLY
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
def append?
|
71
|
+
writing? && (flags & Fcntl::O_APPEND != 0)
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
74
|
+
def reading?
|
75
|
+
rdonly? || rdwr?
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
78
|
+
def writing?
|
79
|
+
wronly? || rdwr?
|
80
|
+
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
82
|
+
def raw_mode
|
83
|
+
mode_str = case accmode
|
84
|
+
when Fcntl::O_RDWR; "rw"
|
85
|
+
when Fcntl::O_RDONLY; "r"
|
86
|
+
when Fcntl::O_WRONLY; "w"
|
87
|
+
end
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
end
|
89
|
+
mode_str << "a" if append?
|
90
|
+
return mode_str
|
91
91
|
end
|
92
|
+
end
|
92
93
|
|
93
|
-
|
94
|
+
# The real RFuse::Fuse object used by FuseFS
|
95
|
+
class Fuse < RFuse::FuseDelegator
|
96
|
+
def initialize(fs,*args)
|
97
|
+
@fs = fs
|
98
|
+
super
|
99
|
+
end
|
100
|
+
|
101
|
+
def run
|
102
|
+
begin
|
103
|
+
@fs.mounted
|
104
|
+
super
|
105
|
+
ensure
|
106
|
+
@fs.unmounted
|
107
|
+
end if mounted?
|
108
|
+
end
|
109
|
+
|
110
|
+
# Implements RFuseFS via RFuse
|
94
111
|
# The path supplied to these methods is generally validated by FUSE itself
|
95
112
|
# with a prior "getattr" call so we do not revalidate here.
|
96
113
|
# http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FuseInvariants
|
97
|
-
class
|
98
|
-
CHECK_FILE="/._rfuse_check_"
|
99
|
-
|
100
|
-
def initialize(root)
|
101
|
-
@root = root
|
102
|
-
@created_files = { }
|
103
|
-
|
104
|
-
# Keep track of changes to file counts and sizes made via Fuse - for #statfs
|
105
|
-
@adj_nodes = 0
|
106
|
-
@adj_size = 0
|
107
|
-
|
108
|
-
#Define method missing for our filesystem
|
109
|
-
#so we can just call all the API methods as required.
|
110
|
-
def @root.method_missing(method,*args)
|
111
|
-
# our filesystem might implement method_missing itself
|
112
|
-
super
|
113
|
-
rescue NoMethodError
|
114
|
-
DEFAULT_FS.send(method,*args)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def readdir(ctx,path,filler,offset,ffi)
|
114
|
+
class Root
|
119
115
|
|
120
|
-
|
116
|
+
# We forward some methods
|
117
|
+
include Forwardable
|
121
118
|
|
122
|
-
|
123
|
-
filler.push(".",nil,0)
|
124
|
-
filler.push("..",nil,0)
|
119
|
+
CHECK_FILE="/._rfuse_check_"
|
125
120
|
|
126
|
-
|
121
|
+
def initialize(root)
|
122
|
+
@root = root
|
123
|
+
@created_files = { }
|
127
124
|
|
128
|
-
|
129
|
-
|
130
|
-
|
125
|
+
# Keep track of changes to file counts and sizes made via Fuse - for #statfs
|
126
|
+
@adj_nodes = 0
|
127
|
+
@adj_size = 0
|
131
128
|
|
129
|
+
#Define method missing for our filesystem
|
130
|
+
#so we can just call all the API methods as required.
|
131
|
+
def @root.method_missing(method,*args)
|
132
|
+
# our filesystem might implement method_missing itself
|
133
|
+
super
|
134
|
+
rescue NoMethodError
|
135
|
+
DEFAULT_FS.send(method,*args)
|
132
136
|
end
|
133
137
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
uid = Process.uid
|
139
|
-
gid = Process.gid
|
140
|
-
|
141
|
-
if path == "/" || @root.directory?(path)
|
142
|
-
#set "w" flag based on can_mkdir? || can_write? to path + "/._rfuse_check"
|
143
|
-
write_test_path = (path == "/" ? "" : path) + CHECK_FILE
|
144
|
-
|
145
|
-
mode = (@root.can_mkdir?(write_test_path) || @root.can_write?(write_test_path)) ? 0777 : 0555
|
146
|
-
atime,mtime,ctime = @root.times(path)
|
147
|
-
#nlink is set to 1 because apparently this makes find work.
|
148
|
-
return RFuse::Stat.directory(mode,{ :uid => uid, :gid => gid, :nlink => 1, :atime => atime, :mtime => mtime, :ctime => ctime })
|
149
|
-
elsif @created_files.has_key?(path)
|
150
|
-
return @created_files[path]
|
151
|
-
elsif @root.file?(path)
|
152
|
-
#Set mode from can_write and executable
|
153
|
-
mode = 0444
|
154
|
-
mode |= 0222 if @root.can_write?(path)
|
155
|
-
mode |= 0111 if @root.executable?(path)
|
156
|
-
size = size(path)
|
157
|
-
atime,mtime,ctime = @root.times(path)
|
158
|
-
return RFuse::Stat.file(mode,{ :uid => uid, :gid => gid, :size => size, :atime => atime, :mtime => mtime, :ctime => ctime })
|
159
|
-
else
|
160
|
-
raise Errno::ENOENT.new(path)
|
161
|
-
end
|
138
|
+
# Define sig<name> methods to handle signals
|
139
|
+
sigmethods = Signal.list.keys.map { |sn| "sig#{sn.downcase}".to_sym }.select { |sm| @root.respond_to?(sm) }
|
140
|
+
def_delegators(:@root,*sigmethods)
|
141
|
+
end
|
162
142
|
|
163
|
-
|
143
|
+
def readdir(ctx,path,filler,offset,ffi)
|
164
144
|
|
165
|
-
|
145
|
+
return wrap_context(ctx,__method__,path,filler,offset,ffi) if ctx
|
166
146
|
|
167
|
-
|
147
|
+
#Always have "." and ".."
|
148
|
+
filler.push(".",nil,0)
|
149
|
+
filler.push("..",nil,0)
|
168
150
|
|
169
|
-
|
170
|
-
raise Errno::EACCES.new(path)
|
171
|
-
end
|
151
|
+
files = @root.contents(path)
|
172
152
|
|
173
|
-
|
174
|
-
|
175
|
-
end
|
176
|
-
|
177
|
-
def mknod(ctx,path,mode,major,minor)
|
178
|
-
|
179
|
-
return wrap_context(ctx,__method__,path,mode,major,minor) if ctx
|
180
|
-
|
181
|
-
unless ((RFuse::Stat::S_IFMT & mode) == RFuse::Stat::S_IFREG ) && @root.can_write?(path)
|
182
|
-
raise Errno::EACCES.new(path)
|
183
|
-
end
|
153
|
+
files.each do | filename |
|
154
|
+
filler.push(filename,nil,0)
|
155
|
+
end
|
184
156
|
|
185
|
-
|
186
|
-
stat = RFuse::Stat.file(mode,{ :uid => Process.uid, :gid => Process.gid, :atime => now, :mtime => now, :ctime => now })
|
157
|
+
end
|
187
158
|
|
188
|
-
|
189
|
-
@adj_nodes += 1
|
190
|
-
end #mknod
|
159
|
+
def getattr(ctx,path)
|
191
160
|
|
192
|
-
|
193
|
-
#sizes are adjusted at file close
|
194
|
-
def ftruncate(ctx,path,offset,ffi)
|
161
|
+
return wrap_context(ctx,__method__,path) if ctx
|
195
162
|
|
196
|
-
|
163
|
+
uid = Process.uid
|
164
|
+
gid = Process.gid
|
197
165
|
|
198
|
-
|
166
|
+
if path == "/" || @root.directory?(path)
|
167
|
+
#set "w" flag based on can_mkdir? || can_write? to path + "/._rfuse_check"
|
168
|
+
write_test_path = (path == "/" ? "" : path) + CHECK_FILE
|
199
169
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
170
|
+
mode = (@root.can_mkdir?(write_test_path) || @root.can_write?(write_test_path)) ? 0777 : 0555
|
171
|
+
atime,mtime,ctime = @root.times(path)
|
172
|
+
#nlink is set to 1 because apparently this makes find work.
|
173
|
+
return RFuse::Stat.directory(mode,{ :uid => uid, :gid => gid, :nlink => 1, :atime => atime, :mtime => mtime, :ctime => ctime })
|
174
|
+
elsif @created_files.has_key?(path)
|
175
|
+
return @created_files[path]
|
176
|
+
elsif @root.file?(path)
|
177
|
+
#Set mode from can_write and executable
|
178
|
+
mode = 0444
|
179
|
+
mode |= 0222 if @root.can_write?(path)
|
180
|
+
mode |= 0111 if @root.executable?(path)
|
181
|
+
size = size(path)
|
182
|
+
atime,mtime,ctime = @root.times(path)
|
183
|
+
return RFuse::Stat.file(mode,{ :uid => uid, :gid => gid, :size => size, :atime => atime, :mtime => mtime, :ctime => ctime })
|
184
|
+
else
|
185
|
+
raise Errno::ENOENT.new(path)
|
208
186
|
end
|
209
187
|
|
210
|
-
|
211
|
-
def truncate(ctx,path,offset)
|
212
|
-
return wrap_context(ctx,__method__,path,offset) if ctx
|
213
|
-
|
214
|
-
unless @root.can_write?(path)
|
215
|
-
raise Errno::EACESS.new(path)
|
216
|
-
end
|
188
|
+
end #getattr
|
217
189
|
|
218
|
-
|
219
|
-
unless @root.raw_truncate(path,offset)
|
220
|
-
contents = @root.read_file(path)
|
221
|
-
if (offset <= 0)
|
222
|
-
@root.write_to(path,"")
|
223
|
-
elsif offset < contents.length
|
224
|
-
@root.write_to(path,contents[0..offset] )
|
225
|
-
end
|
226
|
-
end
|
227
|
-
@adj_size = @adj_size - current_size + (offset <= 0 ? 0 : offset)
|
228
|
-
end #truncate
|
229
|
-
|
230
|
-
# Open. Create a FileHandler and store in fuse file info
|
231
|
-
# This will be returned to us in read/write
|
232
|
-
# No O_CREATE (mknod first?), no O_TRUNC (truncate first)
|
233
|
-
def open(ctx,path,ffi)
|
234
|
-
return wrap_context(ctx,__method__,path,ffi) if ctx
|
235
|
-
fh = FileHandle.new(path,ffi.flags)
|
236
|
-
|
237
|
-
#Save the value return from raw_open to be passed back in raw_read/write etc..
|
238
|
-
if (FuseFS::RFUSEFS_COMPATIBILITY)
|
239
|
-
fh.raw = @root.raw_open(path,fh.raw_mode,true)
|
240
|
-
else
|
241
|
-
fh.raw = @root.raw_open(path,fh.raw_mode)
|
242
|
-
end
|
190
|
+
def mkdir(ctx,path,mode)
|
243
191
|
|
244
|
-
|
245
|
-
if fh.rdonly?
|
246
|
-
fh.contents = @root.read_file(path)
|
247
|
-
elsif fh.writing?
|
248
|
-
unless @root.can_write?(path)
|
249
|
-
raise Errno::EACCES.new(path)
|
250
|
-
end
|
251
|
-
|
252
|
-
if @created_files.has_key?(path)
|
253
|
-
fh.create
|
254
|
-
else
|
255
|
-
if fh.rdwr? || fh.append?
|
256
|
-
fh.contents = @root.read_file(path)
|
257
|
-
else #wronly && !append
|
258
|
-
#We should get a truncate 0, but might as well play it safe
|
259
|
-
fh.contents = ""
|
260
|
-
end
|
261
|
-
end
|
262
|
-
else
|
263
|
-
raise Errno::ENOPERM.new(path)
|
264
|
-
end
|
265
|
-
end
|
192
|
+
return wrap_context(ctx,__method__,path,mode) if ctx
|
266
193
|
|
267
|
-
|
268
|
-
|
194
|
+
unless @root.can_mkdir?(path)
|
195
|
+
raise Errno::EACCES.new(path)
|
269
196
|
end
|
270
197
|
|
271
|
-
|
272
|
-
|
198
|
+
@root.mkdir(path)
|
199
|
+
@adj_nodes += 1
|
200
|
+
end #mkdir
|
273
201
|
|
274
|
-
|
202
|
+
def mknod(ctx,path,mode,major,minor)
|
275
203
|
|
276
|
-
|
277
|
-
if FuseFS::RFUSEFS_COMPATIBILITY
|
278
|
-
return @root.raw_read(path,offset,size,fh.raw)
|
279
|
-
else
|
280
|
-
return @root.raw_read(path,offset,size)
|
281
|
-
end
|
282
|
-
elsif offset >= 0
|
283
|
-
return fh.read(offset,size)
|
284
|
-
else
|
285
|
-
#TODO: Raise? what does a negative offset mean
|
286
|
-
return ""
|
287
|
-
end
|
288
|
-
rescue EOFError
|
289
|
-
return ""
|
290
|
-
end
|
204
|
+
return wrap_context(ctx,__method__,path,mode,major,minor) if ctx
|
291
205
|
|
292
|
-
|
293
|
-
|
294
|
-
fh = ffi.fh
|
295
|
-
|
296
|
-
if fh.raw
|
297
|
-
if FuseFS::RFUSEFS_COMPATIBILITY
|
298
|
-
return @root.raw_write(path,offset,buf.length,buf,fh.raw)
|
299
|
-
else
|
300
|
-
@root.raw_write(path,offset,buf.length,buf)
|
301
|
-
return buf.length
|
302
|
-
end
|
303
|
-
else
|
304
|
-
return fh.write(offset,buf)
|
305
|
-
end
|
206
|
+
unless ((RFuse::Stat::S_IFMT & mode) == RFuse::Stat::S_IFREG ) && @root.can_write?(path)
|
207
|
+
raise Errno::EACCES.new(path)
|
306
208
|
end
|
307
209
|
|
308
|
-
|
309
|
-
|
310
|
-
fh = ffi.fh
|
210
|
+
now = Time.now
|
211
|
+
stat = RFuse::Stat.file(mode,{ :uid => Process.uid, :gid => Process.gid, :atime => now, :mtime => now, :ctime => now })
|
311
212
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
else
|
316
|
-
@root.raw_sync(path,datasync != 0)
|
317
|
-
end
|
318
|
-
else
|
319
|
-
flush(nil,path,ffi)
|
320
|
-
end
|
321
|
-
end
|
213
|
+
@created_files[path] = stat
|
214
|
+
@adj_nodes += 1
|
215
|
+
end #mknod
|
322
216
|
|
323
|
-
|
324
|
-
|
325
|
-
|
217
|
+
#ftruncate - eg called after opening a file for write without append
|
218
|
+
#sizes are adjusted at file close
|
219
|
+
def ftruncate(ctx,path,offset,ffi)
|
326
220
|
|
327
|
-
|
328
|
-
#write contents to the file and mark it unmodified
|
329
|
-
@root.write_to(path,fh.flush())
|
330
|
-
#if it was created with mknod it now exists in the filesystem...
|
331
|
-
@created_files.delete(path)
|
332
|
-
end
|
333
|
-
end
|
221
|
+
return wrap_context(ctx,__method__,path,offset,ffi) if ctx
|
334
222
|
|
335
|
-
|
336
|
-
return wrap_context(ctx,__method__,path,ffi) if ctx
|
223
|
+
fh = ffi.fh
|
337
224
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
end
|
346
|
-
# if was handled as raw, then assume the file has now been created (or not)
|
347
|
-
@created_files.delete(path)
|
348
|
-
else
|
349
|
-
# Probably just had flush called, but no harm calling it again
|
350
|
-
flush(nil,path,ffi)
|
351
|
-
end
|
225
|
+
if fh.raw
|
226
|
+
@root.raw_truncate(path,offset,fh.raw)
|
227
|
+
if (offset <= 0)
|
228
|
+
fh.contents = ""
|
229
|
+
else
|
230
|
+
fh.contents = fh.contents[0..offset]
|
231
|
+
end
|
352
232
|
end
|
233
|
+
end
|
353
234
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
#def chown(path,uid,gid)
|
358
|
-
#end
|
359
|
-
|
360
|
-
def utime(ctx,path,actime,modtime)
|
361
|
-
return wrap_context(ctx,__method__,path,actime,modtime) if ctx
|
235
|
+
#truncate a file outside of open files
|
236
|
+
def truncate(ctx,path,offset)
|
237
|
+
return wrap_context(ctx,__method__,path,offset) if ctx
|
362
238
|
|
363
|
-
|
364
|
-
|
239
|
+
unless @root.can_write?(path)
|
240
|
+
raise Errno::EACESS.new(path)
|
365
241
|
end
|
366
242
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
@created_files.delete(path)
|
377
|
-
@root.delete(path)
|
243
|
+
current_size = size(path)
|
244
|
+
unless @root.raw_truncate(path,offset)
|
245
|
+
contents = @root.read_file(path)
|
246
|
+
if (offset <= 0)
|
247
|
+
@root.write_to(path,"")
|
248
|
+
elsif offset < contents.length
|
249
|
+
@root.write_to(path,contents[0..offset] )
|
250
|
+
end
|
378
251
|
end
|
252
|
+
@adj_size = @adj_size - current_size + (offset <= 0 ? 0 : offset)
|
253
|
+
end #truncate
|
379
254
|
|
380
|
-
|
381
|
-
|
255
|
+
# Open. Create a FileHandler and store in fuse file info
|
256
|
+
# This will be returned to us in read/write
|
257
|
+
# No O_CREATE (mknod first?), no O_TRUNC (truncate first)
|
258
|
+
def open(ctx,path,ffi)
|
259
|
+
return wrap_context(ctx,__method__,path,ffi) if ctx
|
260
|
+
fh = FileHandle.new(path,ffi.flags)
|
382
261
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
262
|
+
#Save the value return from raw_open to be passed back in raw_read/write etc..
|
263
|
+
if (FuseFS::RFUSEFS_COMPATIBILITY)
|
264
|
+
fh.raw = @root.raw_open(path,fh.raw_mode,true)
|
265
|
+
else
|
266
|
+
fh.raw = @root.raw_open(path,fh.raw_mode)
|
387
267
|
end
|
388
268
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
269
|
+
unless fh.raw
|
270
|
+
if fh.rdonly?
|
271
|
+
fh.contents = @root.read_file(path)
|
272
|
+
elsif fh.writing?
|
273
|
+
unless @root.can_write?(path)
|
274
|
+
raise Errno::EACCES.new(path)
|
275
|
+
end
|
394
276
|
|
395
|
-
if @
|
396
|
-
|
397
|
-
elsif @root.file?(from) && @root.can_write?(to) && @root.can_delete?(from)
|
398
|
-
contents = @root.read_file(from)
|
399
|
-
@root.write_to(to,contents)
|
400
|
-
@root.delete(from)
|
277
|
+
if @created_files.has_key?(path)
|
278
|
+
fh.create
|
401
279
|
else
|
402
|
-
|
280
|
+
if fh.rdwr? || fh.append?
|
281
|
+
fh.contents = @root.read_file(path)
|
282
|
+
else #wronly && !append
|
283
|
+
#We should get a truncate 0, but might as well play it safe
|
284
|
+
fh.contents = ""
|
285
|
+
end
|
403
286
|
end
|
404
|
-
|
287
|
+
else
|
288
|
+
raise Errno::ENOPERM.new(path)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
#If we get this far, save our filehandle in the FUSE structure
|
293
|
+
ffi.fh=fh
|
294
|
+
end
|
295
|
+
|
296
|
+
def read(ctx,path,size,offset,ffi)
|
297
|
+
return wrap_context(ctx,__method__,path,size,offset,ffi) if ctx
|
298
|
+
|
299
|
+
fh = ffi.fh
|
405
300
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
return
|
411
|
-
|
301
|
+
if fh.raw
|
302
|
+
if FuseFS::RFUSEFS_COMPATIBILITY
|
303
|
+
return @root.raw_read(path,offset,size,fh.raw)
|
304
|
+
else
|
305
|
+
return @root.raw_read(path,offset,size)
|
306
|
+
end
|
307
|
+
elsif offset >= 0
|
308
|
+
return fh.read(offset,size)
|
309
|
+
else
|
310
|
+
#TODO: Raise? what does a negative offset mean
|
311
|
+
return ""
|
412
312
|
end
|
313
|
+
rescue EOFError
|
314
|
+
return ""
|
315
|
+
end
|
413
316
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
raise Errno::ENODATA.new("No attribute #{name}") unless result
|
418
|
-
result.to_s
|
419
|
-
end
|
317
|
+
def write(ctx,path,buf,offset,ffi)
|
318
|
+
return wrap_context(ctx,__method__,path,buf,offset,ffi) if ctx
|
319
|
+
fh = ffi.fh
|
420
320
|
|
421
|
-
|
422
|
-
|
423
|
-
@root.
|
321
|
+
if fh.raw
|
322
|
+
if FuseFS::RFUSEFS_COMPATIBILITY
|
323
|
+
return @root.raw_write(path,offset,buf.length,buf,fh.raw)
|
324
|
+
else
|
325
|
+
@root.raw_write(path,offset,buf.length,buf)
|
326
|
+
return buf.length
|
327
|
+
end
|
328
|
+
else
|
329
|
+
return fh.write(offset,buf)
|
424
330
|
end
|
331
|
+
end
|
425
332
|
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
end
|
333
|
+
def fsync(ctx,path,datasync,ffi)
|
334
|
+
return wrap_context(ctx,__method__,path,datasync,ffi) if ctx
|
335
|
+
fh = ffi.fh
|
430
336
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
#end
|
440
|
-
|
441
|
-
# Some random numbers to show with df command
|
442
|
-
# bsize preferred block size = 1K unless @root provides something different
|
443
|
-
# frsize = bsize (but apparently unused)
|
444
|
-
# blocks = total number of blocks
|
445
|
-
# bfree = number of free blocks
|
446
|
-
# bavail = bfree if mounted -o allow_other
|
447
|
-
# files = count of all files
|
448
|
-
# ffree - count of free file inode
|
449
|
-
#
|
450
|
-
def statfs(ctx,path)
|
451
|
-
return wrap_context(ctx,__method__,path) if ctx
|
452
|
-
block_size = 1024
|
453
|
-
|
454
|
-
stats = @root.statistics(path)
|
455
|
-
case stats
|
456
|
-
when Array
|
457
|
-
used_space, used_files, total_space, total_files = stats
|
458
|
-
used_files ||= 0
|
459
|
-
used_space ||= 0
|
460
|
-
total_files ||= used_files
|
461
|
-
total_space ||= used_space
|
462
|
-
result = RFuse::StatVfs.new(
|
463
|
-
"bsize" => block_size,
|
464
|
-
"frsize" => block_size,
|
465
|
-
"blocks" => total_space / block_size,
|
466
|
-
"bfree" => (total_space - used_space)/block_size,
|
467
|
-
"bavail" => (total_space - used_space)/block_size,
|
468
|
-
"files" => total_files,
|
469
|
-
"ffree" => (total_files - used_files)
|
470
|
-
)
|
471
|
-
return result
|
472
|
-
else
|
473
|
-
#expected to quack like rfuse:statvfs
|
474
|
-
return stats
|
475
|
-
end
|
337
|
+
if fh && fh.raw
|
338
|
+
if FuseFS::RFUSEFS_COMPATIBILITY
|
339
|
+
@root.raw_sync(path,datasync != 0,fh.raw)
|
340
|
+
else
|
341
|
+
@root.raw_sync(path,datasync != 0)
|
342
|
+
end
|
343
|
+
else
|
344
|
+
flush(nil,path,ffi)
|
476
345
|
end
|
477
|
-
|
478
|
-
|
346
|
+
end
|
347
|
+
|
348
|
+
def flush(ctx,path,ffi)
|
349
|
+
return wrap_context(ctx,__method__,path,ffi) if ctx
|
350
|
+
fh = ffi.fh
|
351
|
+
|
352
|
+
if fh && !fh.raw && fh.modified?
|
353
|
+
#write contents to the file and mark it unmodified
|
354
|
+
@root.write_to(path,fh.flush())
|
355
|
+
#if it was created with mknod it now exists in the filesystem...
|
356
|
+
@created_files.delete(path)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def release(ctx,path,ffi)
|
361
|
+
return wrap_context(ctx,__method__,path,ffi) if ctx
|
362
|
+
|
363
|
+
|
364
|
+
fh = ffi.fh
|
365
|
+
if fh && fh.raw
|
366
|
+
if (FuseFS::RFUSEFS_COMPATIBILITY)
|
367
|
+
@root.raw_close(path,fh.raw)
|
368
|
+
else
|
369
|
+
@root.raw_close(path)
|
370
|
+
end
|
371
|
+
# if was handled as raw, then assume the file has now been created (or not)
|
372
|
+
@created_files.delete(path)
|
373
|
+
else
|
374
|
+
# Probably just had flush called, but no harm calling it again
|
375
|
+
flush(nil,path,ffi)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
#def chmod(path,mode)
|
380
|
+
#end
|
381
|
+
|
382
|
+
#def chown(path,uid,gid)
|
383
|
+
#end
|
384
|
+
|
385
|
+
def utime(ctx,path,actime,modtime)
|
386
|
+
return wrap_context(ctx,__method__,path,actime,modtime) if ctx
|
387
|
+
|
388
|
+
#Touch...
|
389
|
+
@root.touch(path,modtime) if @root.respond_to?(:touch)
|
390
|
+
end
|
391
|
+
|
392
|
+
def unlink(ctx,path)
|
393
|
+
return wrap_context(ctx,__method__,path) if ctx
|
394
|
+
|
395
|
+
unless @root.can_delete?(path)
|
396
|
+
raise Errno::EACCES.new(path)
|
397
|
+
end
|
398
|
+
|
399
|
+
@adj_size = @adj_size - size(path)
|
400
|
+
|
401
|
+
@created_files.delete(path)
|
402
|
+
@root.delete(path)
|
403
|
+
end
|
404
|
+
|
405
|
+
def rmdir(ctx,path)
|
406
|
+
return wrap_context(ctx,__method__,path) if ctx
|
407
|
+
|
408
|
+
unless @root.can_rmdir?(path)
|
409
|
+
raise Errno::EACCES.new(path)
|
410
|
+
end
|
411
|
+
@root.rmdir(path)
|
412
|
+
end
|
413
|
+
|
414
|
+
#def symlink(path,as)
|
415
|
+
#end
|
416
|
+
|
417
|
+
def rename(ctx,from,to)
|
418
|
+
return wrap_context(ctx,__method__,from,to) if ctx
|
419
|
+
|
420
|
+
if @root.rename(from,to)
|
421
|
+
# nothing to do
|
422
|
+
elsif @root.file?(from) && @root.can_write?(to) && @root.can_delete?(from)
|
423
|
+
contents = @root.read_file(from)
|
424
|
+
@root.write_to(to,contents)
|
425
|
+
@root.delete(from)
|
426
|
+
else
|
427
|
+
raise Errno::EACCES.new("Unable to move directory #{from}")
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
#def link(path,as)
|
432
|
+
#end
|
433
|
+
|
434
|
+
def setxattr(ctx,path,name,value,flags)
|
435
|
+
return wrap_context(ctx,__method__,path,name,value,flags) if ctx
|
436
|
+
@root.xattr(path)[name]=value
|
437
|
+
end
|
438
|
+
|
439
|
+
def getxattr(ctx,path,name)
|
440
|
+
return wrap_context(ctx,__method__,path,name) if ctx
|
441
|
+
result = @root.xattr(path)[name]
|
442
|
+
raise Errno::ENODATA.new("No attribute #{name}") unless result
|
443
|
+
result.to_s
|
444
|
+
end
|
445
|
+
|
446
|
+
def listxattr(ctx,path)
|
447
|
+
return wrap_context(ctx,__method__,path) if ctx
|
448
|
+
@root.xattr(path).keys
|
449
|
+
end
|
450
|
+
|
451
|
+
def removexattr(ctx,path,name)
|
452
|
+
return wrap_context(ctx,__method__,path,name) if ctx
|
453
|
+
@root.xattr(path).delete(name)
|
454
|
+
end
|
455
|
+
|
456
|
+
#def opendir(path,ffi)
|
457
|
+
#end
|
458
|
+
|
459
|
+
#def releasedir(path,ffi)
|
460
|
+
#end
|
461
|
+
|
462
|
+
#
|
463
|
+
#def fsyncdir(path,meta,ffi)
|
464
|
+
#end
|
465
|
+
|
466
|
+
# Some random numbers to show with df command
|
467
|
+
# bsize preferred block size = 1K unless @root provides something different
|
468
|
+
# frsize = bsize (but apparently unused)
|
469
|
+
# blocks = total number of blocks
|
470
|
+
# bfree = number of free blocks
|
471
|
+
# bavail = bfree if mounted -o allow_other
|
472
|
+
# files = count of all files
|
473
|
+
# ffree - count of free file inode
|
474
|
+
#
|
475
|
+
def statfs(ctx,path)
|
476
|
+
return wrap_context(ctx,__method__,path) if ctx
|
477
|
+
block_size = 1024
|
478
|
+
|
479
|
+
stats = @root.statistics(path)
|
480
|
+
case stats
|
481
|
+
when Array
|
482
|
+
used_space, used_files, total_space, total_files = stats
|
483
|
+
used_files ||= 0
|
484
|
+
used_space ||= 0
|
485
|
+
total_files ||= used_files
|
486
|
+
total_space ||= used_space
|
487
|
+
result = RFuse::StatVfs.new(
|
488
|
+
"bsize" => block_size,
|
489
|
+
"frsize" => block_size,
|
490
|
+
"blocks" => total_space / block_size,
|
491
|
+
"bfree" => (total_space - used_space)/block_size,
|
492
|
+
"bavail" => (total_space - used_space)/block_size,
|
493
|
+
"files" => total_files,
|
494
|
+
"ffree" => (total_files - used_files)
|
495
|
+
)
|
496
|
+
return result
|
497
|
+
else
|
498
|
+
#expected to quack like rfuse:statvfs
|
499
|
+
return stats
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
def mounted()
|
479
504
|
@root.mounted()
|
480
|
-
|
505
|
+
end
|
481
506
|
|
482
|
-
|
507
|
+
def unmounted()
|
483
508
|
@root.unmounted()
|
484
|
-
|
509
|
+
end
|
485
510
|
|
486
|
-
|
511
|
+
def self.context(ctx,&block)
|
487
512
|
begin
|
488
|
-
|
489
|
-
|
490
|
-
|
513
|
+
Thread.current[:fusefs_reader_uid] = ctx.uid
|
514
|
+
Thread.current[:fusefs_reader_gid] = ctx.gid
|
515
|
+
yield
|
491
516
|
ensure
|
492
|
-
|
493
|
-
|
517
|
+
Thread.current[:fusefs_reader_uid] = nil
|
518
|
+
Thread.current[:fusefs_reader_gid] = nil
|
494
519
|
end
|
495
|
-
|
520
|
+
end
|
521
|
+
|
522
|
+
# @private - no doc
|
523
|
+
def to_s
|
524
|
+
"RFuseFS::#{@root}"
|
525
|
+
end
|
496
526
|
|
497
|
-
|
527
|
+
private
|
498
528
|
|
499
|
-
|
529
|
+
def wrap_context(ctx,method,*args)
|
500
530
|
self.class.context(ctx) { send(method,nil,*args) }
|
501
|
-
|
531
|
+
end
|
502
532
|
|
503
|
-
|
533
|
+
def size(path)
|
504
534
|
@root.respond_to?(:size) ? @root.size(path) : @root.read_file(path).length
|
505
|
-
|
535
|
+
end
|
536
|
+
|
537
|
+
end #class Root
|
506
538
|
|
507
|
-
|
539
|
+
end #class Fuse
|
508
540
|
end #Module FuseFS
|