virtfs 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +5 -0
- data/lib/virtfs-nativefs-thick.rb +1 -0
- data/lib/virtfs-nativefs-thin.rb +1 -0
- data/lib/virtfs.rb +38 -0
- data/lib/virtfs/activation.rb +97 -0
- data/lib/virtfs/block_io.rb +140 -0
- data/lib/virtfs/byte_range.rb +71 -0
- data/lib/virtfs/context.rb +300 -0
- data/lib/virtfs/context_manager.rb +175 -0
- data/lib/virtfs/context_switch_class_methods.rb +96 -0
- data/lib/virtfs/delegate_module.rb +40 -0
- data/lib/virtfs/dir_instance_delegate.rb +3 -0
- data/lib/virtfs/exception.rb +13 -0
- data/lib/virtfs/file_instance_delegate.rb +3 -0
- data/lib/virtfs/file_modes_and_options.rb +293 -0
- data/lib/virtfs/find_class_methods.rb +106 -0
- data/lib/virtfs/io_buffer.rb +133 -0
- data/lib/virtfs/io_instance_delegate.rb +3 -0
- data/lib/virtfs/kernel.rb +146 -0
- data/lib/virtfs/nativefs/thick.rb +30 -0
- data/lib/virtfs/nativefs/thick/dir_class_methods.rb +38 -0
- data/lib/virtfs/nativefs/thick/file_class_methods.rb +178 -0
- data/lib/virtfs/nativefs/thin.rb +32 -0
- data/lib/virtfs/nativefs/thin/dir.rb +30 -0
- data/lib/virtfs/nativefs/thin/dir_class_methods.rb +41 -0
- data/lib/virtfs/nativefs/thin/file.rb +112 -0
- data/lib/virtfs/nativefs/thin/file_class_methods.rb +181 -0
- data/lib/virtfs/protofs/protofs.rb +7 -0
- data/lib/virtfs/protofs/protofs_base.rb +12 -0
- data/lib/virtfs/protofs/protofs_dir.rb +13 -0
- data/lib/virtfs/protofs/protofs_dir_class.rb +31 -0
- data/lib/virtfs/protofs/protofs_file.rb +27 -0
- data/lib/virtfs/protofs/protofs_file_class.rb +136 -0
- data/lib/virtfs/stat.rb +100 -0
- data/lib/virtfs/thin_dir_delegator.rb +79 -0
- data/lib/virtfs/thin_file_delegator.rb +77 -0
- data/lib/virtfs/thin_io_delegator_methods.rb +301 -0
- data/lib/virtfs/thin_io_delegator_methods_bufferio.rb +337 -0
- data/lib/virtfs/v_dir.rb +238 -0
- data/lib/virtfs/v_file.rb +480 -0
- data/lib/virtfs/v_io.rb +243 -0
- data/lib/virtfs/v_pathname.rb +128 -0
- data/lib/virtfs/version.rb +3 -0
- data/spec/activate_spec.rb +202 -0
- data/spec/chroot_spec.rb +120 -0
- data/spec/context_manager_class_spec.rb +246 -0
- data/spec/context_manager_instance_spec.rb +255 -0
- data/spec/context_spec.rb +335 -0
- data/spec/data/UTF-16LE-data.txt +0 -0
- data/spec/data/UTF-8-data.txt +212 -0
- data/spec/dir_class_spec.rb +506 -0
- data/spec/dir_instance_spec.rb +208 -0
- data/spec/file_class_spec.rb +2106 -0
- data/spec/file_instance_spec.rb +154 -0
- data/spec/file_modes_and_options_spec.rb +1556 -0
- data/spec/find_spec.rb +142 -0
- data/spec/io_bufferio_size_shared_examples.rb +371 -0
- data/spec/io_bufferio_size_spec.rb +861 -0
- data/spec/io_bufferio_spec.rb +801 -0
- data/spec/io_class_spec.rb +145 -0
- data/spec/io_instance_spec.rb +516 -0
- data/spec/kernel_spec.rb +285 -0
- data/spec/mount_spec.rb +186 -0
- data/spec/nativefs_local_root_spec.rb +132 -0
- data/spec/path_spec.rb +39 -0
- data/spec/spec_helper.rb +126 -0
- data/tasks/rspec.rake +3 -0
- data/tasks/yard.rake +7 -0
- data/test/UTF-8-demo.txt +212 -0
- data/test/bench.rb +18 -0
- data/test/bio_internal_test.rb +45 -0
- data/test/delegate_io.rb +31 -0
- data/test/delegate_module.rb +62 -0
- data/test/encode_test.rb +42 -0
- data/test/enoent_test.rb +30 -0
- data/test/namespace_test.rb +42 -0
- data/test/read_block_valid_encoding.rb +44 -0
- data/test/read_test.rb +78 -0
- data/test/stream_readers.rb +46 -0
- data/test/utf-16-demo.txt +0 -0
- data/test/utf8_to_utf16.rb +77 -0
- data/test/wrapper_test.rb +34 -0
- data/virtfs.gemspec +29 -0
- metadata +230 -0
data/lib/virtfs/v_dir.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
module VirtFS
|
2
|
+
# VirtFS Dir representation - implements the core Ruby Dir methods, dispatching
|
3
|
+
# to underlying mounted VirtFS filesystems
|
4
|
+
class VDir # rubocop:disable ClassLength
|
5
|
+
attr_accessor :fs_mod_obj
|
6
|
+
|
7
|
+
include DirInstanceDelegate
|
8
|
+
|
9
|
+
VfsRealDir.constants.each { |cn| const_set(cn, VfsRealDir.const_get(cn)) }
|
10
|
+
|
11
|
+
# VDir initializer
|
12
|
+
#
|
13
|
+
# @param dir_obj [VirtFS::FS::Dir] handle to filesystem specific dir obj
|
14
|
+
# @param path [String] path at which the dir resides
|
15
|
+
#
|
16
|
+
def initialize(dir_obj, path)
|
17
|
+
@open_path = path
|
18
|
+
__setobj__(dir_obj)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Some methods need to return the Dir object. Methods in the delegator
|
23
|
+
# object can't do that, so we intercept them and do it here.
|
24
|
+
#
|
25
|
+
|
26
|
+
def each
|
27
|
+
return self if (rv = super) == __getobj__
|
28
|
+
rv
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String] path which dir resides
|
32
|
+
def path
|
33
|
+
@open_path
|
34
|
+
end
|
35
|
+
alias_method :to_path, :path
|
36
|
+
|
37
|
+
def rewind
|
38
|
+
super
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def seek(*args)
|
43
|
+
super
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Class methods
|
48
|
+
class << self
|
49
|
+
# Return dir entries matching the specified glob pattern
|
50
|
+
#
|
51
|
+
# @param glob_pattern [String,Regex] dir entry pattern to match
|
52
|
+
# @see Dir.[]
|
53
|
+
#
|
54
|
+
def [](glob_pattern)
|
55
|
+
glob(glob_pattern, 0)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Change working directory to specified dir
|
59
|
+
#
|
60
|
+
# @param dir [String] path to change working directory to
|
61
|
+
# @see Dir.chdir
|
62
|
+
#
|
63
|
+
def chdir(dir = nil)
|
64
|
+
dir ||= VfsRealDir.home
|
65
|
+
raise SystemCallError.new(dir, Errno::ENOENT::Errno) unless exist?(dir)
|
66
|
+
if block_given?
|
67
|
+
pwd = getwd
|
68
|
+
begin
|
69
|
+
VirtFS.dir_chdir(dir)
|
70
|
+
return yield(getwd)
|
71
|
+
ensure
|
72
|
+
VirtFS.dir_chdir(pwd)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
VirtFS.dir_chdir(dir)
|
76
|
+
0
|
77
|
+
end
|
78
|
+
|
79
|
+
# Change root dir to specified dir
|
80
|
+
#
|
81
|
+
# @param dir [String] dir to change root dir to
|
82
|
+
# @see Dir.chroot
|
83
|
+
#
|
84
|
+
def chroot(dir)
|
85
|
+
VirtFS.dir_chroot(dir)
|
86
|
+
0
|
87
|
+
end
|
88
|
+
|
89
|
+
# Delete specified dir
|
90
|
+
#
|
91
|
+
# @param dir [String] dir to delete
|
92
|
+
# @see Dir.delete
|
93
|
+
#
|
94
|
+
def delete(dir)
|
95
|
+
VirtFS.fs_lookup_call(dir, true) { |p| dir_delete(p) }
|
96
|
+
0
|
97
|
+
end
|
98
|
+
alias_method :unlink, :delete
|
99
|
+
alias_method :rmdir, :delete
|
100
|
+
|
101
|
+
# Return array containing entries in specified dir
|
102
|
+
#
|
103
|
+
# @param dir [String] dir which to enumerate entries
|
104
|
+
#
|
105
|
+
# @return [Array<DirEntry>] array of dir entry instances
|
106
|
+
#
|
107
|
+
# @see Dir.entries
|
108
|
+
#
|
109
|
+
def entries(dir)
|
110
|
+
VirtFS.fs_lookup_call(dir) { |p| dir_entries(p) }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Return bool indicating if specified dir exists
|
114
|
+
#
|
115
|
+
# @param dir [String] directory path to verify
|
116
|
+
# @return [Boolean] indicating if dir exists
|
117
|
+
#
|
118
|
+
def exist?(dir)
|
119
|
+
begin
|
120
|
+
fs, p = VirtFS.path_lookup(dir)
|
121
|
+
rescue Errno::ENOENT
|
122
|
+
return false
|
123
|
+
end
|
124
|
+
VirtFS.fs_call(fs) { dir_exist?(p) }
|
125
|
+
end
|
126
|
+
alias_method :exists?, :exist?
|
127
|
+
|
128
|
+
# Invoke block for each entry in dir
|
129
|
+
#
|
130
|
+
# @param dir [String] dir which to lookup entries
|
131
|
+
# @yield block to invoke
|
132
|
+
def foreach(dir, &block)
|
133
|
+
VirtFS.fs_lookup_call(dir) { |p| dir_foreach(p, &block) }
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [String] current working directory
|
137
|
+
def getwd
|
138
|
+
VirtFS.dir_getwd
|
139
|
+
end
|
140
|
+
alias_method :pwd, :getwd
|
141
|
+
|
142
|
+
# Return directory entries matching specified glob pattern
|
143
|
+
#
|
144
|
+
# @param glob_pattern [String] pattern to match
|
145
|
+
# @param flags [Integer] file match flags
|
146
|
+
# @yield block invoked with each match if specified
|
147
|
+
#
|
148
|
+
# @see VfsRealFile.fnmatch
|
149
|
+
# @see FindClassMethods#dir_and_glob which does most of the work regarding globbing
|
150
|
+
# @see FindClassMethods#find which retrieves stats information & dir entries for found files
|
151
|
+
#
|
152
|
+
def glob(glob_pattern, flags = 0)
|
153
|
+
search_path, specified_path, glob = VirtFS.dir_and_glob(glob_pattern)
|
154
|
+
|
155
|
+
unless exist?(search_path)
|
156
|
+
return [] unless block_given?
|
157
|
+
return false
|
158
|
+
end
|
159
|
+
|
160
|
+
ra = [] unless block_given?
|
161
|
+
VirtFS.find(search_path, VirtFS.glob_depth(glob)) do |p|
|
162
|
+
next if p == search_path
|
163
|
+
|
164
|
+
if search_path == VfsRealFile::SEPARATOR
|
165
|
+
p.sub!(VfsRealFile::SEPARATOR, "")
|
166
|
+
else
|
167
|
+
p.sub!("#{search_path}#{VfsRealFile::SEPARATOR}", "")
|
168
|
+
end
|
169
|
+
|
170
|
+
next if p == ""
|
171
|
+
next unless VfsRealFile.fnmatch(glob, p, flags)
|
172
|
+
|
173
|
+
p = VfsRealFile.join(specified_path, p) if specified_path
|
174
|
+
block_given? ? yield(p) : ra << p
|
175
|
+
end
|
176
|
+
block_given? ? false : ra.sort_by(&:downcase)
|
177
|
+
end
|
178
|
+
|
179
|
+
def home(*args)
|
180
|
+
VfsRealDir.home(*args)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Make new dir at specified path
|
184
|
+
#
|
185
|
+
# @param dir [String] path to create
|
186
|
+
# @param permissions [Integer] initial permission to assign to dir
|
187
|
+
#
|
188
|
+
def mkdir(dir, permissions = 0700)
|
189
|
+
VirtFS.fs_lookup_call(dir, true) { |p| dir_mkdir(p, permissions) }
|
190
|
+
0
|
191
|
+
end
|
192
|
+
|
193
|
+
# Instantiate new directory instance.
|
194
|
+
#
|
195
|
+
# @param dir [String] path to dir to instantiate
|
196
|
+
# @param hash_args [Hash] args to use when creating Dir instance
|
197
|
+
#
|
198
|
+
# @see VirtFS.fs_call
|
199
|
+
# @see ThinDirDelegator
|
200
|
+
#
|
201
|
+
def new(dir, hash_args = {})
|
202
|
+
fs, p = VirtFS.path_lookup(dir)
|
203
|
+
fs_obj = VirtFS.fs_call(fs) { dir_new(p, hash_args, dir, VDir.getwd) }
|
204
|
+
|
205
|
+
obj = allocate
|
206
|
+
if fs.thin_interface?
|
207
|
+
obj.send(:initialize, ThinDirDelegator.new(fs_obj, dir, p, hash_args), dir)
|
208
|
+
else
|
209
|
+
obj.send(:initialize, fs_obj, dir)
|
210
|
+
end
|
211
|
+
|
212
|
+
# fs_mod_obj always points to the fs module's file object
|
213
|
+
# for use by fs-specific extension modules
|
214
|
+
obj.fs_mod_obj = fs_obj
|
215
|
+
obj.extend(fs_obj.extension_module) if fs_obj.respond_to?(:extension_module) # fs-specific extension module
|
216
|
+
obj
|
217
|
+
end
|
218
|
+
|
219
|
+
# Open specified existing dir and invoke block with it before closing
|
220
|
+
#
|
221
|
+
# @param dir [String] path to dir to instantiate
|
222
|
+
# @param hash_args [Hash] args to use when creating Dir instance
|
223
|
+
#
|
224
|
+
# @yield the directory instance
|
225
|
+
# @see .new
|
226
|
+
#
|
227
|
+
def open(dir, hash_args = {})
|
228
|
+
dir_obj = new(dir, hash_args)
|
229
|
+
return dir_obj unless block_given?
|
230
|
+
begin
|
231
|
+
return yield(dir_obj)
|
232
|
+
ensure
|
233
|
+
dir_obj.close
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end # class methods
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,480 @@
|
|
1
|
+
module VirtFS
|
2
|
+
# VirtFS File representation - implements the core Ruby File methods, dispatching
|
3
|
+
# to underlying mounted VirtFS filesystems
|
4
|
+
#
|
5
|
+
class VFile < VIO # rubocop:disable ClassLength
|
6
|
+
attr_accessor :fs_mod_obj
|
7
|
+
|
8
|
+
include FileInstanceDelegate
|
9
|
+
|
10
|
+
VfsRealFile.constants.each { |cn| const_set(cn, VfsRealFile.const_get(cn)) }
|
11
|
+
|
12
|
+
# VFile initializer
|
13
|
+
#
|
14
|
+
# @param file_obj [VirtFS::FS::File] handle to filesystem specific file obj
|
15
|
+
# @param path [String] path at which the file resides
|
16
|
+
#
|
17
|
+
def initialize(file_obj, path)
|
18
|
+
@open_path = path
|
19
|
+
__setobj__(file_obj)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Some methods need to return the File object. Methods in the delegator
|
24
|
+
# object can't do that, so we intercept them and do it here.
|
25
|
+
#
|
26
|
+
|
27
|
+
def <<(obj)
|
28
|
+
super
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def binmode
|
33
|
+
super
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def each(*args)
|
38
|
+
return self if (rv = super) == __getobj__
|
39
|
+
rv
|
40
|
+
end
|
41
|
+
|
42
|
+
def each_byte
|
43
|
+
return self if (rv = super) == __getobj__
|
44
|
+
rv
|
45
|
+
end
|
46
|
+
|
47
|
+
def each_char
|
48
|
+
return self if (rv = super) == __getobj__
|
49
|
+
rv
|
50
|
+
end
|
51
|
+
|
52
|
+
def each_codepoint
|
53
|
+
return self if (rv = super) == __getobj__
|
54
|
+
rv
|
55
|
+
end
|
56
|
+
|
57
|
+
def flush
|
58
|
+
return self if (rv = super) == __getobj__
|
59
|
+
rv
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String] path which dir resides
|
63
|
+
def path
|
64
|
+
@open_path
|
65
|
+
end
|
66
|
+
alias_method :to_path, :path
|
67
|
+
|
68
|
+
# Reopens file with the given args
|
69
|
+
def reopen(*args)
|
70
|
+
new_path = nil
|
71
|
+
if !args[0].respond_to?(:to_str) && args[0].respond_to?(:__getobj__)
|
72
|
+
# Given an IO object.
|
73
|
+
to_obj = args[0]
|
74
|
+
args = [to_obj.__getobj__]
|
75
|
+
new_path = to_obj.path
|
76
|
+
end
|
77
|
+
new_obj = __getobj__.reopen(*args)
|
78
|
+
__setobj__(new_obj)
|
79
|
+
@open_path = new_path || new_obj.path
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_encoding(*args)
|
84
|
+
super
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_io
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
def min_read_buf_sz=(val)
|
93
|
+
__getobj__.send(:min_read_buf_sz=, val)
|
94
|
+
rescue
|
95
|
+
# ignore
|
96
|
+
end
|
97
|
+
private :min_read_buf_sz=
|
98
|
+
|
99
|
+
# Class methods
|
100
|
+
class << self
|
101
|
+
# @return absolute path of file (across mounted filesystems)
|
102
|
+
def absolute_path(f, dirstring = nil)
|
103
|
+
dir = dirstring || VirtFS.dir_getwd
|
104
|
+
VfsRealFile.absolute_path(f, dir)
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [Time] access time of the file
|
108
|
+
def atime(f)
|
109
|
+
VirtFS.fs_lookup_call(f) { |p| file_atime(p) }
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [String] base name of the file
|
113
|
+
def basename(*args)
|
114
|
+
VfsRealFile.basename(*args)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Boolean] indicating if file is a block device
|
118
|
+
def blockdev?(f)
|
119
|
+
VirtFS.fs_lookup_call(f) { |p| file_blockdev?(p) }
|
120
|
+
end
|
121
|
+
|
122
|
+
# @return [Boolean] indicating if file is a char device
|
123
|
+
def chardev?(f)
|
124
|
+
VirtFS.fs_lookup_call(f) { |p| file_chardev?(p) }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Change File ACLs
|
128
|
+
#
|
129
|
+
# @param permission [Integer] new acl to assign to file(s)
|
130
|
+
def chmod(permission, *files)
|
131
|
+
nfp = 0
|
132
|
+
files.each do |f|
|
133
|
+
nfp += VirtFS.fs_lookup_call(f) { |p| file_chmod(permission, p) }
|
134
|
+
end
|
135
|
+
nfp
|
136
|
+
end
|
137
|
+
|
138
|
+
# Change ownership / group ownership of file
|
139
|
+
#
|
140
|
+
# @param owner [Integer,String] new owner of the file(s)
|
141
|
+
# @param group [Integer,String] new group owner of the file(s)
|
142
|
+
def chown(owner, group, *files)
|
143
|
+
owner = owner.to_int
|
144
|
+
group = group.to_int
|
145
|
+
nfp = 0
|
146
|
+
files.each do |f|
|
147
|
+
nfp += VirtFS.fs_lookup_call(f) { |p| file_chown(owner, group, p) }
|
148
|
+
end
|
149
|
+
nfp
|
150
|
+
end
|
151
|
+
|
152
|
+
# @return ]Time] change time of time
|
153
|
+
def ctime(f)
|
154
|
+
VirtFS.fs_lookup_call(f) { |p| file_ctime(p) }
|
155
|
+
end
|
156
|
+
|
157
|
+
# Delete specified files
|
158
|
+
def delete(*files)
|
159
|
+
nfp = 0
|
160
|
+
files.each do |f|
|
161
|
+
nfp += VirtFS.fs_lookup_call(f, false, false) { |p| file_delete(p) }
|
162
|
+
end
|
163
|
+
nfp
|
164
|
+
end
|
165
|
+
alias_method :unlink, :delete
|
166
|
+
|
167
|
+
# @return [Boolean] indiciating if file is a directory
|
168
|
+
def directory?(f)
|
169
|
+
VirtFS.fs_lookup_call(f) { |p| file_directory?(p) }
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [String] containg file directory name
|
173
|
+
def dirname(*args)
|
174
|
+
VfsRealFile.dirname(*args)
|
175
|
+
end
|
176
|
+
|
177
|
+
# @return [Boolean] indiciating if file is executable
|
178
|
+
def executable?(f)
|
179
|
+
VirtFS.fs_lookup_call(f) { |p| file_executable?(p) }
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [Boolean] indiciating if file is executable and real
|
183
|
+
def executable_real?(f)
|
184
|
+
VirtFS.fs_lookup_call(f) { |p| file_executable_real?(p) }
|
185
|
+
end
|
186
|
+
|
187
|
+
# @return [Boolean] indiciating if file exists
|
188
|
+
def exist?(f)
|
189
|
+
VirtFS.fs_lookup_call(f) { |p| file_exist?(p) }
|
190
|
+
end
|
191
|
+
alias_method :exists?, :exist?
|
192
|
+
|
193
|
+
# @return [String] full expanded path to file
|
194
|
+
def expand_path(f, dirstring = nil)
|
195
|
+
dir = dirstring || VirtFS.dir_getwd
|
196
|
+
VfsRealFile.expand_path(f, dir)
|
197
|
+
end
|
198
|
+
|
199
|
+
# @return [String] containg file extension name
|
200
|
+
def extname(*args)
|
201
|
+
VfsRealFile.extname(*args)
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [Boolean] indiciating if file is a regular file
|
205
|
+
def file?(f)
|
206
|
+
VirtFS.fs_lookup_call(f) { |p| file_file?(p) }
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [Array<String>] names of files matching given args
|
210
|
+
def fnmatch(*args)
|
211
|
+
VfsRealFile.fnmatch(*args)
|
212
|
+
end
|
213
|
+
alias_method :fnmatch?, :fnmatch
|
214
|
+
|
215
|
+
# @return type of file specified
|
216
|
+
def ftype(f)
|
217
|
+
VirtFS.fs_lookup_call(f) { |p| file_ftype(p) }
|
218
|
+
end
|
219
|
+
|
220
|
+
# @return [Boolean] indicating if file is group owned
|
221
|
+
def grpowned?(f)
|
222
|
+
VirtFS.fs_lookup_call(f) { |p| file_grpowned?(p) }
|
223
|
+
end
|
224
|
+
|
225
|
+
# @return [Boolean] indicating if files are identical
|
226
|
+
def identical?(fname1, fname2)
|
227
|
+
fs1, p1 = VirtFS.path_lookup(fname1)
|
228
|
+
fs2, p2 = VirtFS.path_lookup(fname2)
|
229
|
+
return false unless fs1 == fs2
|
230
|
+
VirtFS.fs_call(fs1) { file_identical?(p1, p2) }
|
231
|
+
end
|
232
|
+
|
233
|
+
# @return [String] containing joined path components
|
234
|
+
def join(*args)
|
235
|
+
VfsRealFile.join(*args)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Invoke a 'lchmod' on the given files
|
239
|
+
#
|
240
|
+
# @param permission [Integer] new permission to assign to file(s)
|
241
|
+
#
|
242
|
+
def lchmod(permission, *files)
|
243
|
+
nfp = 0
|
244
|
+
files.each do |f|
|
245
|
+
nfp += VirtFS.fs_lookup_call(f) { |p| file_lchmod(permission, p) }
|
246
|
+
end
|
247
|
+
nfp
|
248
|
+
end
|
249
|
+
|
250
|
+
# Invoke a 'lchown' on the given files
|
251
|
+
#
|
252
|
+
# @param owner [String] new owner to assign to file(s)
|
253
|
+
# @param group [String] new group to assign to file(s)
|
254
|
+
#
|
255
|
+
def lchown(owner, group, *files)
|
256
|
+
nfp = 0
|
257
|
+
files.each do |f|
|
258
|
+
nfp += VirtFS.fs_lookup_call(f, false, false) { |p| file_lchown(owner, group, p) }
|
259
|
+
end
|
260
|
+
nfp
|
261
|
+
end
|
262
|
+
|
263
|
+
# Create a symbol link between files
|
264
|
+
#
|
265
|
+
# @param oname [String] file to link to
|
266
|
+
# @param nname [String] symbolic link to create
|
267
|
+
#
|
268
|
+
def link(oname, nname)
|
269
|
+
fs1, p1 = VirtFS.path_lookup(oname)
|
270
|
+
fs2, p2 = VirtFS.path_lookup(nname)
|
271
|
+
raise SystemCallError, "Can't hard link between filesystems" unless fs1 == fs2 # TODO: check exception
|
272
|
+
VirtFS.fs_call(fs1) { file_link(p1, p2) }
|
273
|
+
end
|
274
|
+
|
275
|
+
# @return [Stat] file stat for specified file
|
276
|
+
def lstat(f)
|
277
|
+
VirtFS.fs_lookup_call(f, false, false) { |p| file_lstat(p) }
|
278
|
+
end
|
279
|
+
|
280
|
+
# @return [Time] modification time of the specified file
|
281
|
+
def mtime(f)
|
282
|
+
VirtFS.fs_lookup_call(f) { |p| file_mtime(p) }
|
283
|
+
end
|
284
|
+
|
285
|
+
# @return [Boolean] indicating if file is owned
|
286
|
+
def owned?(f)
|
287
|
+
VirtFS.fs_lookup_call(f) { |p| file_owned?(p) }
|
288
|
+
end
|
289
|
+
|
290
|
+
# @return path to specified file object
|
291
|
+
def path(obj)
|
292
|
+
VfsRealFile.path(obj) # will check obj.to_path
|
293
|
+
end
|
294
|
+
|
295
|
+
# @return [Boolean] indicating if file is pipe
|
296
|
+
def pipe?(f)
|
297
|
+
VirtFS.fs_lookup_call(f) { |p| file_pipe?(p) }
|
298
|
+
end
|
299
|
+
|
300
|
+
# @return [Boolean] indicating if file is readable
|
301
|
+
def readable?(f)
|
302
|
+
VirtFS.fs_lookup_call(f) { |p| file_readable?(p) }
|
303
|
+
end
|
304
|
+
|
305
|
+
# @return [Boolean] indicating if file is real and readable
|
306
|
+
def readable_real?(f)
|
307
|
+
VirtFS.fs_lookup_call(f) { |p| file_readable_real?(p) }
|
308
|
+
end
|
309
|
+
|
310
|
+
# @return [String] name of file references by link
|
311
|
+
def readlink(f)
|
312
|
+
VirtFS.fs_lookup_call(f, false, false) { |p| file_readlink(p) }
|
313
|
+
end
|
314
|
+
|
315
|
+
# @return [String] real directory containing file
|
316
|
+
def realdirpath(path, relative_to = nil) # ???
|
317
|
+
VirtFS.expand_links(VirtFS.normalize_path(path, relative_to))
|
318
|
+
end
|
319
|
+
|
320
|
+
# @return [String] real path of the file
|
321
|
+
def realpath(path, relative_to = nil) # ???
|
322
|
+
VirtFS.expand_links(VirtFS.normalize_path(path, relative_to))
|
323
|
+
end
|
324
|
+
|
325
|
+
# Rename file
|
326
|
+
#
|
327
|
+
# @param oname [String] file to rename
|
328
|
+
# @param nname [String] new name to assign to file
|
329
|
+
#
|
330
|
+
def rename(oname, nname)
|
331
|
+
fs1, p1 = VirtFS.path_lookup(oname)
|
332
|
+
fs2, p2 = VirtFS.path_lookup(nname)
|
333
|
+
raise SystemCallError, "Can't rename between filesystems" unless fs1 == fs2 # TODO: check exception
|
334
|
+
VirtFS.fs_call(fs1) { file_rename(p1, p2) }
|
335
|
+
end
|
336
|
+
|
337
|
+
# @return [Boolean] indicating if file GID is set
|
338
|
+
def setgid?(f)
|
339
|
+
VirtFS.fs_lookup_call(f) { |p| file_setgid?(p) }
|
340
|
+
end
|
341
|
+
|
342
|
+
# @return [Boolean] indicating if file UID is set
|
343
|
+
def setuid?(f)
|
344
|
+
VirtFS.fs_lookup_call(f) { |p| file_setuid?(p) }
|
345
|
+
end
|
346
|
+
|
347
|
+
# @return [Integer] size of the file in bytes
|
348
|
+
def size(f)
|
349
|
+
VirtFS.fs_lookup_call(f) { |p| file_size(p) }
|
350
|
+
end
|
351
|
+
|
352
|
+
# @return [Integer,nil] same as #size but return nil if empty
|
353
|
+
def size?(f)
|
354
|
+
sz = size(f)
|
355
|
+
return nil if sz == 0
|
356
|
+
sz
|
357
|
+
end
|
358
|
+
|
359
|
+
# @return [Boolean] indicating if file is a socket
|
360
|
+
def socket?(f)
|
361
|
+
VirtFS.fs_lookup_call(f) { |p| file_socket?(p) }
|
362
|
+
end
|
363
|
+
|
364
|
+
# @return [Array<String>] split file path
|
365
|
+
def split(f)
|
366
|
+
VfsRealFile.split(f)
|
367
|
+
end
|
368
|
+
|
369
|
+
# @return [Stat] file stat correspond to file
|
370
|
+
def stat(f)
|
371
|
+
VirtFS.fs_lookup_call(f) { |p| file_stat(p) }
|
372
|
+
end
|
373
|
+
|
374
|
+
# @return [Boolean] indicating if file is sticky
|
375
|
+
def sticky?(f)
|
376
|
+
VirtFS.fs_lookup_call(f) { |p| file_sticky?(p) }
|
377
|
+
end
|
378
|
+
|
379
|
+
# Create new symlink to file
|
380
|
+
#
|
381
|
+
# @param oname [String] file to link to
|
382
|
+
# @param nname [String] symbollic link to create
|
383
|
+
#
|
384
|
+
def symlink(oname, nname)
|
385
|
+
#
|
386
|
+
# oname is the path to the original file in the global FS namespace.
|
387
|
+
# It is not modified and used as the link target.
|
388
|
+
#
|
389
|
+
VirtFS.fs_lookup_call(nname) { |p| file_symlink(oname, p) }
|
390
|
+
end
|
391
|
+
|
392
|
+
# @return [Boolean] indicating if file is symlink
|
393
|
+
def symlink?(f)
|
394
|
+
VirtFS.fs_lookup_call(f, false, false) { |p| file_symlink?(p) }
|
395
|
+
end
|
396
|
+
|
397
|
+
# Truncate file to the specified len
|
398
|
+
#
|
399
|
+
# @param f [String] file to truncate
|
400
|
+
# @param len [Integer] length to truncate file to (in bytes)
|
401
|
+
def truncate(f, len)
|
402
|
+
VirtFS.fs_lookup_call(f) { |p| file_truncate(p, len) }
|
403
|
+
end
|
404
|
+
|
405
|
+
# @return [Integer] umake of file
|
406
|
+
def umask(*args)
|
407
|
+
VfsRealFile.umask(*args)
|
408
|
+
end
|
409
|
+
|
410
|
+
# Update file time
|
411
|
+
#
|
412
|
+
# @param atime [Time] new access time to assign to file(s)
|
413
|
+
# @param mtime [Time] new modification time to assign to file(s)
|
414
|
+
def utime(atime, mtime, *files)
|
415
|
+
nfp = 0
|
416
|
+
files.each do |f|
|
417
|
+
nfp += VirtFS.fs_lookup_call(f) { |p| file_utime(atime, mtime, p) }
|
418
|
+
end
|
419
|
+
nfp
|
420
|
+
end
|
421
|
+
|
422
|
+
# @return [Boolean] indicating if file is world readable
|
423
|
+
def world_readable?(f)
|
424
|
+
VirtFS.fs_lookup_call(f) { |p| file_world_readable?(p) }
|
425
|
+
end
|
426
|
+
|
427
|
+
# @return [Boolean] indicating if file is world writable
|
428
|
+
def world_writable?(f)
|
429
|
+
VirtFS.fs_lookup_call(f) { |p| file_world_writable?(p) }
|
430
|
+
end
|
431
|
+
|
432
|
+
# @return [Boolean] indicating if file is writable
|
433
|
+
def writable?(f)
|
434
|
+
VirtFS.fs_lookup_call(f) { |p| file_writable?(p) }
|
435
|
+
end
|
436
|
+
|
437
|
+
# @return [Boolean] indicating if file is writable and real
|
438
|
+
def writable_real?(f)
|
439
|
+
VirtFS.fs_lookup_call(f) { |p| file_writable_real?(p) }
|
440
|
+
end
|
441
|
+
|
442
|
+
def zero?(f)
|
443
|
+
fs, p = VirtFS.path_lookup(f)
|
444
|
+
begin
|
445
|
+
VirtFS.fs_call(fs) { file_chardev?(p) }
|
446
|
+
return fs.file_size(p) == 0
|
447
|
+
rescue Errno::ENOENT
|
448
|
+
return false
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
# Instantiate new file instance.
|
453
|
+
#
|
454
|
+
# @param file_id [String] file identifier (usually path)
|
455
|
+
# @param args args to forward to file initializer
|
456
|
+
def new(file_id, *args) # rubocop:disable AbcSize
|
457
|
+
if file_id.respond_to?(:to_int)
|
458
|
+
fs_obj = VfsRealIO.new(file_id, *args)
|
459
|
+
else
|
460
|
+
parsed_args = FileModesAndOptions.new(*args)
|
461
|
+
fs, p = VirtFS.path_lookup(file_id, false, false)
|
462
|
+
fs_obj = VirtFS.fs_call(fs) { file_new(p, parsed_args, file_id, VDir.getwd) }
|
463
|
+
end
|
464
|
+
|
465
|
+
obj = allocate
|
466
|
+
if fs.thin_interface?
|
467
|
+
obj.send(:initialize, ThinFileDelegator.new(fs_obj, file_id, p, parsed_args), file_id)
|
468
|
+
else
|
469
|
+
obj.send(:initialize, fs_obj, file_id)
|
470
|
+
end
|
471
|
+
|
472
|
+
# fs_mod_obj always points to the fs module's file object
|
473
|
+
# for use by fs-specific extension modules
|
474
|
+
obj.fs_mod_obj = fs_obj
|
475
|
+
obj.extend(fs_obj.extension_module) if fs_obj.respond_to?(:extension_module) # fs-specific extension module
|
476
|
+
obj
|
477
|
+
end
|
478
|
+
end # class methods
|
479
|
+
end
|
480
|
+
end
|