Class: VirtFS::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/virtfs/context.rb

Overview

FS-specific state under which FS calls occur.

VirtFS maps an independent context instance to each Ruby thread group, and internally switches to it before dispatching target FS calls from that thread. This class implements the core functionality behind the FS context

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeContext

Returns a new instance of Context.



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/virtfs/context.rb', line 11

def initialize
  @mount_points = []
  @fs_lookup    = {}
  @mount_mutex  = Mutex.new
  @dir_mutex    = Mutex.new
  @saved_root   = nil
  @saved_cwd    = nil
  @root         = VfsRealFile::SEPARATOR
  @cwd          = @root
  @key          = nil
end

Instance Attribute Details

#keyObject

Returns the value of attribute key.



9
10
11
# File 'lib/virtfs/context.rb', line 9

def key
  @key
end

Instance Method Details

#chdir(dir) ⇒ Object

Change virtual filesystem working directory

Parameters:

  • dir (String)

    new dir to assign to virtfs cwd



161
162
163
164
165
166
167
168
169
# File 'lib/virtfs/context.rb', line 161

def chdir(dir)
  fs = path = nil
  @dir_mutex.synchronize do
    nwd = remove_root(local_path(dir, @cwd, @root), @root)
    fs, path = mount_lookup(nwd)
    @cwd = nwd
  end
  fs.dir_chdir(path) if fs.respond_to?(:dir_chdir)
end

#chroot(dir) ⇒ Object

Change virtual file system root, after which all root calls to mount point will be mapped to specified dir

Parameters:

  • dir (String)

    new dir to assign as virtfs context root

Raises:

  • (SystemCallError)

    if specified dir does not exist



115
116
117
118
119
120
121
122
# File 'lib/virtfs/context.rb', line 115

def chroot(dir)
  raise SystemCallError.new(dir, Errno::ENOENT::Errno) unless dir_exist?(dir)
  @dir_mutex.synchronize do
    @root = full_path(dir, true, @cwd, @root)
    @cwd  = VfsRealFile::SEPARATOR
  end
  0
end

#cwd_rootObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper to change virtual filesystem working directory to filesystem root



236
237
238
239
240
# File 'lib/virtfs/context.rb', line 236

def cwd_root
  @dir_mutex.synchronize do
    return @cwd, @root
  end
end

#dir_exist?(dir) ⇒ Boolean

Returns indicating if specified dir exists.

Returns:

  • (Boolean)

    indicating if specified dir exists



149
150
151
152
153
154
155
156
# File 'lib/virtfs/context.rb', line 149

def dir_exist?(dir)
  begin
    fs, p = path_lookup(dir)
  rescue Errno::ENOENT
    return false
  end
  VirtFS.fs_call(fs) { dir_exist?(p) }
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Expand symbolic links in the path. This must be done here, because a symlink in one file system can point to a file in another filesystem.

Parameters:

  • p (String)

    path to lookup

  • include_last (Boolean) (defaults to: true)

    indicates if last path component should be returned



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/virtfs/context.rb', line 204

def expand_links(p, include_last = true)
  cp = VfsRealFile::SEPARATOR
  components = p.split(VfsRealFile::SEPARATOR)
  components.shift if components[0] == "" # root
  last_component = components.pop unless include_last

  #
  # For each component of the path, check to see
  # if it's a symbolic link. If so, expand it
  # relative to its base directory.
  #
  components.each do |c|
    ncp = VfsRealFile.join(cp, c)
    #
    # Each file system knows how to check for,
    # and read, its own links.
    #
    fs, lp = mount_lookup(ncp)
    if fs.file_symlink?(lp)
      sl = fs.file_readlink(lp)
      cp = sl[0, 1] == VfsRealFile::SEPARATOR ? sl : VfsRealFile.join(cp, sl)
    else
      cp = ncp
    end
  end
  return cp if include_last
  VfsRealFile.join(cp, last_component.to_s)
end

#fs_on(mount_point) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/virtfs/context.rb', line 97

def fs_on(mount_point)
  mp = full_path(mount_point, true, *cwd_root)
  mp += VfsRealFile::SEPARATOR unless mp.end_with?(VfsRealFile::SEPARATOR)
  @mount_mutex.synchronize do
    @fs_lookup[mp]
  end
end

#getwdString

Returns current filesystem working directory.

Returns:

  • (String)

    current filesystem working directory



172
173
174
# File 'lib/virtfs/context.rb', line 172

def getwd
  @cwd
end

#mount(fs_instance, mount_point) ⇒ Object

Mount the specified FS instance at the specified mount point. This registers specified fs to be accessed through the specified mount point via internal mechanisms. After this point any calls to this mount point through VirtFS under this context will be mapped through the specified fs instance

Parameters:

  • fs_instance (VirtFS::FS)

    instance of VirtFS implementation corresponding to filesystem to mount

  • mount_point (String)

    path which to mount filesystem under

Raises:

  • (SystemCallError)

    if mount point cannot be resolved

  • (RuntimeError)

    if mount point is being used



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/virtfs/context.rb', line 46

def mount(fs_instance, mount_point)
  mp_display  = mount_point

  raise "mount: invalid filesystem object #{fs_instance.class.name}" unless fs_instance.respond_to?(:mount_point)
  raise "mount: filesystem is busy" if fs_instance.mount_point

  begin
    mount_point = full_path(mount_point, true, *cwd_root)
  rescue Errno::ENOENT
    raise SystemCallError.new(mp_display, Errno::ENOENT::Errno)
  end
  mount_point += VfsRealFile::SEPARATOR unless mount_point.end_with?(VfsRealFile::SEPARATOR)

  @mount_mutex.synchronize do
    raise "mount: mount point #{mp_display} is busy" if @fs_lookup[mount_point]
    fs_instance.mount_point = mount_point
    @fs_lookup[mount_point] = fs_instance
    @mount_points.push(mount_point).sort_by!(&:length).reverse!
  end
  nil
end

#mount_pointsArray<String>

Returns array of mount points.

Returns:

  • (Array<String>)

    array of mount points



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/virtfs/context.rb', line 85

def mount_points
  @mount_mutex.synchronize do
    @mount_points.collect do |p|
      if p == VfsRealFile::SEPARATOR
        VfsRealFile::SEPARATOR
      else
        p.chomp(VfsRealFile::SEPARATOR)
      end
    end
  end
end

#mounted?(mount_point) ⇒ Boolean

Returns indicating if mount point is mounted.

Returns:

  • (Boolean)

    indicating if mount point is mounted



106
107
108
# File 'lib/virtfs/context.rb', line 106

def mounted?(mount_point)
  !fs_on(mount_point).nil?
end

#path_lookup(path, raise_full_path = false, include_last = true) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Expand symbolic links and perform mount indirection look up.

Parameters:

  • path (String)

    path to lookup

  • raise_full_path (Boolean) (defaults to: false)

    indicates if error should be raised if lookup fails

  • include_last (Boolean) (defaults to: true)

    indicates if last path component should be returned

Raises:

  • (RunTimeError)

    if path could not be looked up and raise_full_path is true

  • (SystemCallError)

    if path could not be looked up

See Also:



189
190
191
192
193
194
195
# File 'lib/virtfs/context.rb', line 189

def path_lookup(path, raise_full_path = false, include_last = true)
  mount_lookup(full_path(path, include_last, *cwd_root))
rescue Errno::ENOENT
  raise if raise_full_path
  # so we report the original path.
  raise SystemCallError.new(path, Errno::ENOENT::Errno)
end

#restore_cwd_root(cwd, root) ⇒ Object



242
243
244
245
246
247
# File 'lib/virtfs/context.rb', line 242

def restore_cwd_root(cwd, root)
  @dir_mutex.synchronize do
    @cwd  = cwd  if cwd
    @root = root if root
  end
end

#umount(mount_point) ⇒ Object

Unmount the FS mounted at the specified mount point

Parameters:

  • mount_point (String)

    mount point to unmount

Raises:

  • (RuntimeError)

    if mount point is not mounted



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/virtfs/context.rb', line 72

def umount(mount_point)
  mount_point = full_path(mount_point, true, *cwd_root)
  @mount_mutex.synchronize do
    mp_display = mount_point
    mount_point += VfsRealFile::SEPARATOR unless mount_point.end_with?(VfsRealFile::SEPARATOR)
    raise "umount: nothing mounted on #{mp_display}" unless @fs_lookup[mount_point]
    @fs_lookup.delete(mount_point).umount
    @mount_points.delete(mount_point)
  end
  nil
end

#with_root(dir) ⇒ Object

Invoke block with the specified root, restoring before returning

Raises:

  • (SystemCallError)

See Also:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/virtfs/context.rb', line 127

def with_root(dir)
  raise SystemCallError.new(dir, Errno::ENOENT::Errno) unless dir_exist?(dir)
  @dir_mutex.synchronize do
    raise "Cannot nest with_root blocks" unless @saved_root.nil?
    @saved_root = @root
    @saved_cwd  = @cwd
    @root = full_path(dir, true, @cwd, @root)
    @cwd  = VfsRealFile::SEPARATOR
  end
  begin
    yield
  ensure
    @dir_mutex.synchronize do
      @root       = @saved_root
      @cwd        = @saved_cwd
      @saved_root = nil
      @saved_cwd  = nil
    end
  end
end