Class: FuseFS::MetaDir

Inherits:
Object
  • Object
show all
Defined in:
lib/fusefs/metadir.rb

Overview

A full in-memory filesystem defined with hashes. It is writable to the user that mounted it may create and edit files within it, as well as the programmer

Usage

root = Metadir.new()
root.mkdir("/hello")
root.write_to("/hello/world","Hello World!\n")
root.write_to("/hello/everybody","Hello Everyone!\n")

FuseFS.start(mntpath,root)

Because Metadir is fully recursive, you can mount your own or other defined directory structures under it. For example, to mount a dictionary filesystem (see samples/dictfs.rb), use:

root.mkdir("/dict",DictFS.new())

Constant Summary collapse

DEFAULT_FS =
FuseDir.new()

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stats = nil) ⇒ MetaDir

Returns a new instance of MetaDir.



27
28
29
30
31
32
33
# File 'lib/fusefs/metadir.rb', line 27

def initialize(stats = nil)
    @subdirs  = Hash.new(nil)
    @files    = Hash.new(nil)
    @xattr   = Hash.new() { |h,k| h[k] = Hash.new }
    @stats = stats || StatsHelper.new()
    @stats.adjust(0,1)
end

Instance Attribute Details

#statsStatsHelper (readonly)

Returns helper for filesystem accounting (df etc).

Returns:

  • (StatsHelper)

    helper for filesystem accounting (df etc)



25
26
27
# File 'lib/fusefs/metadir.rb', line 25

def stats
  @stats
end

Instance Method Details

#can_delete?(path) ⇒ Boolean

Delete a file

Returns:

  • (Boolean)


107
108
109
110
111
# File 'lib/fusefs/metadir.rb', line 107

def can_delete?(path)
    pathmethod(:can_delete?,path) do |filename|
        return mount_user?
    end
end

#can_mkdir?(path) ⇒ Boolean

mkdir - does not make intermediate dirs!

Returns:

  • (Boolean)


121
122
123
124
125
# File 'lib/fusefs/metadir.rb', line 121

def can_mkdir?(path)
    pathmethod(:can_mkdir?,path) do |dirname|
        return mount_user?
    end
end

#can_rmdir?(path) ⇒ Boolean

Delete an existing directory make sure it is not empty

Returns:

  • (Boolean)


135
136
137
138
139
# File 'lib/fusefs/metadir.rb', line 135

def can_rmdir?(path)
    pathmethod(:can_rmdir?,path) do |dirname|
        return mount_user? && @subdirs.has_key?(dirname) && @subdirs[dirname].contents("/").empty?
    end
end

#can_write?(path) ⇒ Boolean

can_write only applies to files… see can_mkdir for directories…

Returns:

  • (Boolean)


86
87
88
89
90
# File 'lib/fusefs/metadir.rb', line 86

def can_write?(path)
    pathmethod(:can_write?,path) do |filename|
        return mount_user?
    end
end

#contents(path) ⇒ Object

List directory contents



56
57
58
59
60
61
62
63
64
# File 'lib/fusefs/metadir.rb', line 56

def contents(path)
    pathmethod(:contents,path) do | filename |
        if !filename
            (@files.keys + @subdirs.keys).sort.uniq
        else
            @subdirs[filename].contents("/")
        end
    end
end

#delete(path) ⇒ Object



113
114
115
116
117
118
# File 'lib/fusefs/metadir.rb', line 113

def delete(path)
    pathmethod(:delete,path) do |filename|
        contents = @files.delete(filename)
        @stats.adjust(-contents.to_s.length,-1)
    end
end

#directory?(path) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
46
47
# File 'lib/fusefs/metadir.rb', line 43

def directory?(path)
    pathmethod(:directory?,path) do |filename|
        !filename || filename == "/" || @subdirs.has_key?(filename)
    end
end

#file?(path) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
52
53
# File 'lib/fusefs/metadir.rb', line 49

def file?(path)
    pathmethod(:file?,path) do |filename|
        @files.has_key?(filename)
    end
end

#mkdir(path, dir = nil) ⇒ Object



127
128
129
130
131
132
# File 'lib/fusefs/metadir.rb', line 127

def mkdir(path,dir=nil)
    pathmethod(:mkdir,path,dir) do | dirname,dirobj |
        dirobj ||= MetaDir.new(@stats)
        @subdirs[dirname] = dirobj
    end
end

#read_file(path) ⇒ Object



73
74
75
76
77
# File 'lib/fusefs/metadir.rb', line 73

def read_file(path)
    pathmethod(:read_file,path) do |filename|
        @files[filename].to_s
    end
end

#rename(from_path, to_path, to_fusefs = self) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/fusefs/metadir.rb', line 148

def rename(from_path,to_path,to_fusefs = self)

    from_base,from_rest = split_path(from_path)

    case
    when !from_base
        # Shouldn't ever happen.
        raise Errno::EACCES.new("Can't move root")
    when !from_rest
        # So now we have a file or directory to move
        if @files.has_key?(from_base)
            return false unless can_delete?(from_base) && to_fusefs.can_write?(to_path)
            to_fusefs.write_to(to_path,@files[from_base])
            to_fusefs.xattr(to_path).merge!(@xattr[from_base])
            @xattr.delete(from_base)
            @files.delete(from_base)
        elsif @subdirs.has_key?(from_base)
            # we don't check can_rmdir? because that would prevent us 
            # moving non empty directories
            return false unless mount_user? && to_fusefs.can_mkdir?(to_path)
            begin
                to_fusefs.mkdir(to_path,@subdirs[from_base])
                to_fusefs.xattr(to_path).merge!(@xattr[from_base])
                @xattr.delete(from_base)
                @subdirs.delete(from_base)
                @stats.adjust(0,-1)
                return true
            rescue ArgumentError
                # to_rest does not support mkdir with an arbitrary object
                return false
            end
        else
            #We shouldn't get this either
            return false
        end
    when @subdirs.has_key?(from_base)
        begin
            if to_fusefs != self
                #just keep recursing..
                return @subdirs[from_base].rename(from_rest,to_path,to_fusefs)
            else
                to_base,to_rest = split_path(to_path)
                if from_base == to_base
                    #mv within a subdir, just pass it on
                    return @subdirs[from_base].rename(from_rest,to_rest)
                else
                    #OK, this is the tricky part, we want to move something further down
                    #our tree into something in another part of the tree.
                    #from this point on we keep a reference to the fusefs that owns
                    #to_path (ie us) and pass it down, but only if the eventual path
                    #is writable anyway!
                    if (file?(to_path))
                        return false unless can_write?(to_path)
                    else
                        return false unless can_mkdir?(to_path)
                    end

                    return @subdirs[from_base].rename(from_rest,to_path,self)
                end
            end
        rescue NoMethodError
            #sub dir doesn't support rename
            return false
        rescue ArgumentError
            #sub dir doesn't support rename with additional to_fusefs argument
            return false
        end
    else
        return false
    end
end

#rmdir(path) ⇒ Object



141
142
143
144
145
146
# File 'lib/fusefs/metadir.rb', line 141

def rmdir(path)
    pathmethod(:rmdir,path) do |dirname|
        @subdirs.delete(dirname)
        @stats.adjust(0,-1)
    end
end

#scan_pathObject



39
40
41
# File 'lib/fusefs/metadir.rb', line 39

def scan_path
    DEFAULT_FS.scan_path(path)
end

#size(path) ⇒ Object



79
80
81
82
83
# File 'lib/fusefs/metadir.rb', line 79

def size(path)
    pathmethod(:size,path) do | filename |
        return @files[filename].to_s.length
    end
end

#split_path(path) ⇒ Object



35
36
37
# File 'lib/fusefs/metadir.rb', line 35

def split_path(path)
    DEFAULT_FS.split_path(path)
end

#statistics(path) ⇒ Object

path is ignored? - recursively calculate for all subdirs - but cache and then rely on fuse to keep count



221
222
223
224
225
226
227
228
229
230
231
# File 'lib/fusefs/metadir.rb', line 221

def statistics(path)
    pathmethod(:statistics,path) do |stats_path|
        if @subdirs.has_key?(stats_path)
            #unlike all the other functions where this metadir applies
            #the function to @subdirs - we need to pass it on
            @subdirs[stats_path].statistics("/")
        else
            @stats.to_statistics
        end
    end
end

#write_to(path, contents) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/fusefs/metadir.rb', line 92

def write_to(path,contents)
    pathmethod(:write_to,path,contents) do |filename, filecontents |
        adj_size = filecontents.to_s.length
        adj_nodes = 1
        if @files.has_key?(filename)
            adj_size = adj_size - @files[filename].to_s.length
            adj_nodes = 0
        end
        @stats.adjust(adj_size,adj_nodes)

        @files[filename] = filecontents
    end
end

#xattr(path) ⇒ Object

Extended attributes



67
68
69
70
71
# File 'lib/fusefs/metadir.rb', line 67

def xattr(path)
    pathmethod(:xattr,path) do | path |
       @xattr[path]
    end
end