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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +154 -0
  8. data/Rakefile +5 -0
  9. data/lib/virtfs-nativefs-thick.rb +1 -0
  10. data/lib/virtfs-nativefs-thin.rb +1 -0
  11. data/lib/virtfs.rb +38 -0
  12. data/lib/virtfs/activation.rb +97 -0
  13. data/lib/virtfs/block_io.rb +140 -0
  14. data/lib/virtfs/byte_range.rb +71 -0
  15. data/lib/virtfs/context.rb +300 -0
  16. data/lib/virtfs/context_manager.rb +175 -0
  17. data/lib/virtfs/context_switch_class_methods.rb +96 -0
  18. data/lib/virtfs/delegate_module.rb +40 -0
  19. data/lib/virtfs/dir_instance_delegate.rb +3 -0
  20. data/lib/virtfs/exception.rb +13 -0
  21. data/lib/virtfs/file_instance_delegate.rb +3 -0
  22. data/lib/virtfs/file_modes_and_options.rb +293 -0
  23. data/lib/virtfs/find_class_methods.rb +106 -0
  24. data/lib/virtfs/io_buffer.rb +133 -0
  25. data/lib/virtfs/io_instance_delegate.rb +3 -0
  26. data/lib/virtfs/kernel.rb +146 -0
  27. data/lib/virtfs/nativefs/thick.rb +30 -0
  28. data/lib/virtfs/nativefs/thick/dir_class_methods.rb +38 -0
  29. data/lib/virtfs/nativefs/thick/file_class_methods.rb +178 -0
  30. data/lib/virtfs/nativefs/thin.rb +32 -0
  31. data/lib/virtfs/nativefs/thin/dir.rb +30 -0
  32. data/lib/virtfs/nativefs/thin/dir_class_methods.rb +41 -0
  33. data/lib/virtfs/nativefs/thin/file.rb +112 -0
  34. data/lib/virtfs/nativefs/thin/file_class_methods.rb +181 -0
  35. data/lib/virtfs/protofs/protofs.rb +7 -0
  36. data/lib/virtfs/protofs/protofs_base.rb +12 -0
  37. data/lib/virtfs/protofs/protofs_dir.rb +13 -0
  38. data/lib/virtfs/protofs/protofs_dir_class.rb +31 -0
  39. data/lib/virtfs/protofs/protofs_file.rb +27 -0
  40. data/lib/virtfs/protofs/protofs_file_class.rb +136 -0
  41. data/lib/virtfs/stat.rb +100 -0
  42. data/lib/virtfs/thin_dir_delegator.rb +79 -0
  43. data/lib/virtfs/thin_file_delegator.rb +77 -0
  44. data/lib/virtfs/thin_io_delegator_methods.rb +301 -0
  45. data/lib/virtfs/thin_io_delegator_methods_bufferio.rb +337 -0
  46. data/lib/virtfs/v_dir.rb +238 -0
  47. data/lib/virtfs/v_file.rb +480 -0
  48. data/lib/virtfs/v_io.rb +243 -0
  49. data/lib/virtfs/v_pathname.rb +128 -0
  50. data/lib/virtfs/version.rb +3 -0
  51. data/spec/activate_spec.rb +202 -0
  52. data/spec/chroot_spec.rb +120 -0
  53. data/spec/context_manager_class_spec.rb +246 -0
  54. data/spec/context_manager_instance_spec.rb +255 -0
  55. data/spec/context_spec.rb +335 -0
  56. data/spec/data/UTF-16LE-data.txt +0 -0
  57. data/spec/data/UTF-8-data.txt +212 -0
  58. data/spec/dir_class_spec.rb +506 -0
  59. data/spec/dir_instance_spec.rb +208 -0
  60. data/spec/file_class_spec.rb +2106 -0
  61. data/spec/file_instance_spec.rb +154 -0
  62. data/spec/file_modes_and_options_spec.rb +1556 -0
  63. data/spec/find_spec.rb +142 -0
  64. data/spec/io_bufferio_size_shared_examples.rb +371 -0
  65. data/spec/io_bufferio_size_spec.rb +861 -0
  66. data/spec/io_bufferio_spec.rb +801 -0
  67. data/spec/io_class_spec.rb +145 -0
  68. data/spec/io_instance_spec.rb +516 -0
  69. data/spec/kernel_spec.rb +285 -0
  70. data/spec/mount_spec.rb +186 -0
  71. data/spec/nativefs_local_root_spec.rb +132 -0
  72. data/spec/path_spec.rb +39 -0
  73. data/spec/spec_helper.rb +126 -0
  74. data/tasks/rspec.rake +3 -0
  75. data/tasks/yard.rake +7 -0
  76. data/test/UTF-8-demo.txt +212 -0
  77. data/test/bench.rb +18 -0
  78. data/test/bio_internal_test.rb +45 -0
  79. data/test/delegate_io.rb +31 -0
  80. data/test/delegate_module.rb +62 -0
  81. data/test/encode_test.rb +42 -0
  82. data/test/enoent_test.rb +30 -0
  83. data/test/namespace_test.rb +42 -0
  84. data/test/read_block_valid_encoding.rb +44 -0
  85. data/test/read_test.rb +78 -0
  86. data/test/stream_readers.rb +46 -0
  87. data/test/utf-16-demo.txt +0 -0
  88. data/test/utf8_to_utf16.rb +77 -0
  89. data/test/wrapper_test.rb +34 -0
  90. data/virtfs.gemspec +29 -0
  91. metadata +230 -0
@@ -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