virtfs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|