Module: Ext4

Included in:
FileObject
Defined in:
lib/fs/MiqFS/modules/Ext4.rb,
lib/fs/ext4/inode.rb,
lib/fs/ext4/extent.rb,
lib/fs/ext4/directory.rb,
lib/fs/ext4/superblock.rb,
lib/fs/ext4/alloc_bitmap.rb,
lib/fs/ext4/extent_index.rb,
lib/fs/ext4/extent_header.rb,
lib/fs/ext4/ex_attrib_name.rb,
lib/fs/ext4/directory_entry.rb,
lib/fs/ext4/hash_tree_entry.rb,
lib/fs/ext4/posix_acl_entry.rb,
lib/fs/ext4/ex_attrib_header.rb,
lib/fs/ext4/hash_tree_header.rb,
lib/fs/ext4/posix_acl_header.rb,
lib/fs/ext4/group_descriptor_entry.rb,
lib/fs/ext4/group_descriptor_table.rb

Overview

Ext4 file system interface to MiqFS.

Defined Under Namespace

Classes: AllocBitmap, Directory, DirectoryEntry, ExAttribHeader, ExAttribName, Extent, ExtentHeader, ExtentIndex, FileObject, GroupDescriptorEntry, GroupDescriptorTable, HashTreeEntry, HashTreeHeader, Inode, PosixAclEntry, PosixAclHeader, Superblock

Constant Summary collapse

INODE =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'S',  'file_mode',    # File mode (type and permission), see PF_ DF_ & FM_ below.
  'S',  'uid_lo',       # Lower 16-bits of user id.
  'L',  'size_lo',      # Lower 32-bits of size in bytes.
  'L',  'atime',        # Last access       time.
  'L',  'ctime',        # Last change       time.
  'L',  'mtime',        # Last modification time.
  'L',  'dtime',        # Time deleted.
  'S',  'gid_lo',       # Lower 16-bits of group id.
  'S',  'link_count',   # Link count.
  'L',  'blocks_lo',    # Lower 32-bits of Block count.
  'L',  'flags',        # Inode flags, see IF_ below.
  'L',  'version',      # Version.
  'a60', 'data',         # 60 bytes deciphered into data (symlink, indirect pointer, or extents)
  'L',  'gen_num',      # Generation number (NFS).
  'L',  'file_acl_lo',  # Lower 32-bits of File.
  'L',  'size_hi',      # Upper 32-bits of size in bytes or directory ACL.
  'L',  'obso_faddr',   # Obsoleted fragment address.
  'S',  'blocks_hi',    # Upper 16-bits of Block count.
  'S',  'file_acl_hi',  # Upper 16-bits of File ACL.
  'S',  'uid_hi',       # Upper 16-bits of user id.
  'S',  'gid_hi',       # Upper 16-bits of group id.
  'L',  'reserved2',    # Unused.
  'S',  'extra_isize',  #
  'S',  'pad1',         #
  'L',  'ctime_extra',  # extra Change             time (nsec << 2 | epoch)
  'L',  'mtime_extra',  # extra Modification       time (nsec << 2 | epoch)
  'L',  'atime_extra',  # extra Access             time (nsec << 2 | epoch)
  'L',  'crtime',       # File Creation time
  'L',  'crtime_extra', # extra File Creation Time time (nsec << 2 | epoch)
  'L',  'version_hi',   # Upper 32-bits of version (for 64-bit version)
])
SIZEOF_INODE =
INODE.size
SYM_LNK_SIZE =
60
MAX_READ =
4294967296
DEFAULT_BLOCK_SIZE =
1024
EXTENT =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'L',  'block',      # first logical block extent covers
  'S',  'length',     # number of blocks covered by extent
  'S',  'start_hi',   # high 16 bits of physical block
  'L',  'start_lo',   # low  32 bits of physical block
])
SIZEOF_EXTENT =
EXTENT.size
SUPERBLOCK =

//////////////////////////////////////////////////////////////////////////// // Data definitions. Linux 2.6.2 from Fedora Core 6.

BinaryStruct.new([
  'L',  'num_inodes',         # Number of inodes in file system.
  'L',  'num_blocks',         # Number of blocks in file system.
  'L',  'reserved_blocks',    # Number of reserved blocks to prevent file system from filling up.
  'L',  'unallocated_blocks', # Number of unallocated blocks.
  'L',  'unallocated_inodes', # Number of unallocated inodes.
  'L',  'block_group_zero',   # Block where block group 0 starts.
  'L',  'block_size',         # Block size (saved as num bits to shift 1024 left).
  'L',  'fragment_size',      # Fragment size (saved as num bits to shift 1024 left).
  'L',  'blocks_in_group',    # Number of blocks in each block group.
  'L',  'fragments_in_group', # Number of fragments in each block group.
  'L',  'inodes_in_group',    # Number of inodes in each block group.
  'L',  'last_mount_time',    # Time FS was last mounted.
  'L',  'last_write_time',    # Time FS was last written to.
  'S',  'mount_count',        # Current mount count.
  'S',  'max_mount_count',    # Maximum mount count.
  'S',  'signature',          # Always 0xef53
  'S',  'fs_state',           # File System State: see FSS_ below.
  'S',  'err_method',         # Error Handling Method: see EHM_ below.
  'S',  'ver_minor',          # Minor version number.
  'L',  'last_check_time',    # Last consistency check time.
  'L',  'forced_check_int',   # Forced check interval.
  'L',  'creator_os',         # Creator OS: see CO_ below.
  'L',  'ver_major',          # Major version: see MV_ below.
  'S',  'uid_res_blocks',     # UID that can use reserved blocks.
  'S',  'gid_res_blocks',     # GID that can uss reserved blocks.
  # Begin dynamic version fields
  'L',  'first_inode',        # First non-reserved inode in file system.
  'S',  'inode_size',         # Size of each inode.
  'S',  'block_group',        # Block group that this superblock is part of (if backup copy).
  'L',  'compat_flags',       # Compatible feature flags (see CFF_ below).
  'L',  'incompat_flags',     # Incompatible feature flags (see ICF_ below).
  'L',  'ro_flags',           # Read Only feature flags (see ROF_ below).
  'a16',  'fs_id',            # File system ID (UUID or GUID).
  'a16',  'vol_name',         # Volume name.
  'a64',  'last_mnt_path',    # Path where last mounted.
  'L',  'algo_use_bmp',       # Algorithm usage bitmap.
  # Performance hints
  'C',  'file_prealloc_blks', # Blocks to preallocate for files.
  'C',  'dir_prealloc_blks',  # Blocks to preallocate for directories.
  'S',  'unused1',            # Unused.
  # Journal support
  'a16',  'jrnl_id',          # Joural ID (UUID or GUID).
  'L',  'jrnl_inode',         # Journal inode.
  'L',  'jrnl_device',        # Journal device.
  'L',  'orphan_head',        # Head of orphan inode list.
  'a16',  'hash_seed',        # HTREE hash seed. This is actually L4 (__u32 s_hash_seed[4])
  'C',  'hash_ver',           # Default hash version.
  'C',  'unused2',
  'S',  'group_desc_size',    # Group descriptor size.
  'L',  'mount_opts',         # Default mount options.
  'L',  'first_meta_blk_grp', # First metablock block group.
  'a360', 'reserved'          # Unused.
])
SUPERBLOCK_SIG =
0xef53
SUPERBLOCK_OFFSET =
1024
SUPERBLOCK_SIZE =
1024
GDE_SIZE =

default group descriptor size.

32
INODE_SIZE =

Default inode size.

128
EXTENT_INDEX =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'L',  'block',      # index covers logical blocks from 'block'
  'L',  'leaf_lo',    # low  32 bits of physical block of the next level. leaf or next index could be there
  'S',  'leaf_hi',    # high 16 bits of physical block
  'S',  'unused',     #
])
SIZEOF_EXTENT_INDEX =
EXTENT_INDEX.size
DEF_CACHE_SIZE =

Default directory cache size.

50
EXTENT_HEADER =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'S',  'magic',      # Signature.
  'S',  'entries',    # Number of Valid Entries
  'S',  'max',        # Capacity of Store in Entries
  'S',  'depth',      # Has tree real underlying blocks?
  'L',  'generation', # Generation of the tree.
])
SIZEOF_EXTENT_HEADER =
EXTENT_HEADER.size
EX_ATTRIB_NAME =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

[
  'C',  'name_len',       # Length of name
  'C',  'type',           # Type of attribute, see AT_ below.
  'S',  'offset_to_val',  # Offset to value.
  'L',  'blk_loc',        # Block location of value (not used).
  'L',  'size_of_val',    # Size in bytes of value.
  'L',  'hash_of_val',    # Hash of value.
]
DIR_ENTRY_ORIGINAL =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'L',  'inode_val',  # Inode address of metadata.
  'S',  'entry_len',  # Length of entry.
  'S',  'name_len',   # Length of name.
])
SIZEOF_DIR_ENTRY_ORIGINAL =

Here follows the name in ASCII.

DIR_ENTRY_ORIGINAL.size
DIR_ENTRY_NEW =
BinaryStruct.new([
  'L',  'inode_val',  # Inode address of metadata.
  'S',  'entry_len',  # Length of entry.
  'C',  'name_len',   # Length of name.
  'C',  'file_type',  # Type of file (see FT_ below).
])
SIZEOF_DIR_ENTRY_NEW =

Here follows the name in ASCII.

DIR_ENTRY_NEW.size
HASH_TREE_ENTRY_FIRST =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'S',  'max_descriptors',  # Maximum number of node descriptors.
  'S',  'cur_descriptors',  # Current number of node descriptors.
  'L',  'first_node',       # Block address of first node.
])
SIZEOF_HASH_TREE_ENTRY_FIRST =
HASH_TREE_ENTRY_FIRST.size
HASH_TREE_ENTRY_NEXT =
BinaryStruct.new([
  'L',  'min_hash',   # Minimum hash value in node.
  'L',  'next_node',  # Block address of next node.
])
SIZEOF_HASH_TREE_ENTRY_NEXT =
HASH_TREE_ENTRY_NEXT.size
SIZEOF_HASH_TREE_ENTRY =
SIZEOF_HASH_TREE_ENTRY_NEXT
POSIX_ACL_ENTRY =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

[
  'S',  'type',         # Entry type, see ET_ below.
  'S',  'permissions',  # Permissions, see EP_ below.
  'L',  'u_g_id',       # User / Group id (not defined for some types).
]
EX_ATTRIB_HEADER =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

[
  'L',  'signature',  # Always 0xea020000
  'L',  'ref_count',
  'L',  'num_blks',
  'L',  'hash',
]
HASH_TREE_HEADER =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'L',  'unused1',    # Unused.
  'C',  'hash_ver',   # Hash version.
  'C',  'length',     # Length of this structure.
  'C',  'leaf_level', # Levels of leaves.
  'C',  'unused2',    # Unused.
])
SIZEOF_HASH_TREE_HEADER =
HASH_TREE_HEADER.size
POSIX_ACL_HEADER =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

[
  'L',  'version',  # Always 1, or 1 is all that's supported.
]
GDE =

//////////////////////////////////////////////////////////////////////////// // Data definitions.

BinaryStruct.new([
  'L',  'blk_bmp',        # Starting block address of block bitmap.
  'L',  'inode_bmp',      # Starting block address of inode bitmap.
  'L',  'inode_table',    # Starting block address of inode table.
  'S',  'unalloc_blks',   # Number of unallocated blocks in group.
  'S',  'unalloc_inodes', # Number of unallocated inodes in group.
  'S',  'num_dirs',       # Number of directories in group.
  'a14',  'unused1',      # Unused.
])

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cache_hitsObject

Members (these become members of an MiqFS instance).



16
17
18
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 16

def cache_hits
  @cache_hits
end

#dir_cacheObject

Members (these become members of an MiqFS instance).



16
17
18
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 16

def dir_cache
  @dir_cache
end

#entry_cacheObject

Members (these become members of an MiqFS instance).



16
17
18
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 16

def entry_cache
  @entry_cache
end

#rootDirObject

Members (these become members of an MiqFS instance).



16
17
18
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 16

def rootDir
  @rootDir
end

#superblockObject

Members (these become members of an MiqFS instance).



16
17
18
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 16

def superblock
  @superblock
end

Instance Method Details

#fs_dirEntries(p) ⇒ Object

Returns String array of all names, sans path.



69
70
71
72
73
74
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 69

def fs_dirEntries(p)
  # Get path directory.
  dir = ifs_getDir(p)
  return nil if dir.nil?
  dir.globNames
end

#fs_dirMkdir(_p) ⇒ Object

Make a directory. Parent must exist.



77
78
79
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 77

def fs_dirMkdir(_p)
  raise "Write functionality is not yet supported on Ext4."
end

#fs_dirRmdir(_p) ⇒ Object

Remove a directory.



82
83
84
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 82

def fs_dirRmdir(_p)
  raise "Write functionality is not yet supported on Ext4."
end

#fs_fileAtime(p) ⇒ Object

Returns Ruby Time object.



124
125
126
127
128
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 124

def fs_fileAtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.getInode(de.inode).aTime
end

#fs_fileAtime_obj(fobj) ⇒ Object

Returns a Ruby Time object.



157
158
159
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 157

def fs_fileAtime_obj(fobj)
  fobj.inode.aTime
end

#fs_fileClose(fobj) ⇒ Object

Write changes & destroy.



197
198
199
200
201
202
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 197

def fs_fileClose(fobj)
  # TODO: unrem when write is supported.
  # fobj.inode.close
  fobj.inode.rewind
  fobj = nil
end

#fs_fileCtime(p) ⇒ Object

Returns Ruby Time object.



131
132
133
134
135
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 131

def fs_fileCtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.getInode(de.inode).cTime
end

#fs_fileCtime_obj(fobj) ⇒ Object

Returns a Ruby Time object.



162
163
164
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 162

def fs_fileCtime_obj(fobj)
  fobj.inode.cTime
end

#fs_fileDelete(_p) ⇒ Object

Delete file.



119
120
121
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 119

def fs_fileDelete(_p)
  raise "Write functionality is not yet supported on Ext4."
end

#fs_fileDirectory?(p) ⇒ Boolean

Returns true if name is a directory.

Returns:

  • (Boolean)


105
106
107
108
109
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 105

def fs_fileDirectory?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.fileType == DirectoryEntry::FT_DIRECTORY
end

#fs_fileExists?(p) ⇒ Boolean

Returns true if name exists, false if not.

Returns:

  • (Boolean)


91
92
93
94
95
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 91

def fs_fileExists?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  true
end

#fs_fileFile?(p) ⇒ Boolean

Returns true if name is a regular file.

Returns:

  • (Boolean)


98
99
100
101
102
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 98

def fs_fileFile?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.fileType == DirectoryEntry::FT_FILE
end

#fs_fileMtime(p) ⇒ Object

Returns Ruby Time object.



138
139
140
141
142
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 138

def fs_fileMtime(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.getInode(de.inode).mTime
end

#fs_fileMtime_obj(fobj) ⇒ Object

Returns a Ruby Time obect.



167
168
169
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 167

def fs_fileMtime_obj(fobj)
  fobj.inode.mTime
end

#fs_fileOpen(p, mode = "r") ⇒ Object

New FileObject instance. NOTE: FileObject must have access to Ext4 members. This is kind of like a ‘skip this’ thing. Ext4 methods use stuff owned by MiqFS, so this is necessary.



175
176
177
178
179
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 175

def fs_fileOpen(p, mode = "r")
  fobj = FileObject.new(p, self)
  fobj.open(mode)
  fobj
end

#fs_fileRead(fobj, len) ⇒ Object

Returns a Ruby String object.



187
188
189
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 187

def fs_fileRead(fobj, len)
  fobj.inode.read(len)
end

#fs_fileSeek(fobj, offset, whence) ⇒ Object

Returns current file position.



182
183
184
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 182

def fs_fileSeek(fobj, offset, whence)
  fobj.inode.seek(offset, whence)
end

#fs_fileSize(p) ⇒ Object

Returns size in bytes.



112
113
114
115
116
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 112

def fs_fileSize(p)
  de = ifs_getFile(p)
  return nil if de.nil?
  @superblock.getInode(de.inode).length
end

#fs_fileSize_obj(fobj) ⇒ Object

In these, fobj is a FileObject.



152
153
154
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 152

def fs_fileSize_obj(fobj)
  fobj.inode.length
end

#fs_fileWrite(_fobj, _buf, _len) ⇒ Object



191
192
193
194
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 191

def fs_fileWrite(_fobj, _buf, _len)
  raise "Write functionality is not yet supported on Ext4."
  # fobj.inode.write(buf, len)
end

#fs_freeBytesObject

Returns free space on file system in bytes.



60
61
62
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 60

def fs_freeBytes
  @superblock.freeBytes
end

#fs_initObject

File system interface.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 44

def fs_init
  # puts "Ext4::fs_init(#{@dobj.dInfo.fileName})"
  self.fsType = "Ext4"

  # Initialize bs & read root dir.
  @dobj.seek(0, IO::SEEK_SET)
  self.superblock  = Superblock.new(@dobj)
  @fsId            = superblock.fsId.to_s
  @volName         = superblock.volName
  self.rootDir     = Directory.new(superblock)
  self.entry_cache = LruHash.new(DEF_CACHE_SIZE)
  self.dir_cache   = LruHash.new(DEF_CACHE_SIZE)
  self.cache_hits  = 0
end

#fs_isSymLink?(p) ⇒ Boolean

Return true if p is a path to a symbolic link.

Returns:

  • (Boolean)


145
146
147
148
149
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 145

def fs_isSymLink?(p)
  de = ifs_getFile(p)
  return false if de.nil?
  de.isSymLink?
end

#ifs_getDir(p, miqfs = nil) ⇒ Object

Return a Directory object for a path. Raise error if path doesn’t exist.



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 264

def ifs_getDir(p, miqfs = nil)
  # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # If this is being called from an Ext4 module method, then self owns contained instance members.
  miqfs = self if miqfs.nil?

  # Wack leading drive.
  p = unnormalizePath(p)

  # Get an array of directory names, kill off the first (it's always empty).
  names = p.split(/[\\\/]/)
  names.shift

  dir = ifs_getDirR(names, miqfs)
  raise MiqFsDirectoryNotFound, p if dir.nil?
  dir
end

#ifs_getDirR(names, miqfs) ⇒ Object

Return Directory recursively for given directory or nil if not exist.



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 282

def ifs_getDirR(names, miqfs)
  return miqfs.rootDir if names.empty?

  # Check for this path in the cache.
  fname = names.join('/')
  if miqfs.dir_cache.key?(fname)
    miqfs.cache_hits += 1
    return miqfs.dir_cache[fname]
  end

  name = names.pop
  pdir = ifs_getDirR(names, miqfs)
  return nil if pdir.nil?

  de = pdir.findEntry(name, DirectoryEntry::FT_DIRECTORY)
  return nil if de.nil?
  miqfs.entry_cache[fname] = de

  dir = Directory.new(miqfs.superblock, de.inode)
  return nil if dir.nil?

  miqfs.dir_cache[fname] = dir
end

#ifs_getFile(p, miqfs = nil) ⇒ Object

Return a DirectoryEntry for a given file or nil if not exist.



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
232
233
234
235
236
237
238
239
240
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 207

def ifs_getFile(p, miqfs = nil)
  # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # If this is being called from an Ext4 module method, then self owns contained instance members.
  miqfs = self if miqfs.nil?

  # Preprocess path.
  p = unnormalizePath(p)
  dir, fname = File.split(p)
  # Fix for FB#835: if fil == root then fil needs to be "."
  fname = "." if fname == "/" || fname == "\\"

  # Check for this file in the cache.
  cache_name = "#{dir == '/' ? '' : dir}/#{fname}"
  if miqfs.entry_cache.key?(cache_name)
    miqfs.cache_hits += 1
    return miqfs.entry_cache[cache_name]
  end

  # Look for file in dir, but don't error if it doesn't exist.
  # NOTE: if p is a directory that's ok, find it.
  begin
    dirObj = ifs_getDir(dir, miqfs)
    dirEnt = dirObj.nil? ? nil : dirObj.findEntry(fname)

  rescue MiqFsDirectoryNotFound => err
    dirEnt = nil

  rescue RuntimeError => err
    $log.error err.message.to_s if $log
    dirEnt = nil
  end

  miqfs.entry_cache[cache_name] = dirEnt
end

#ifs_putFile(p, miqfs = nil) ⇒ Object

Create a directory entry.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 243

def ifs_putFile(p, miqfs = nil)
  raise "Write functionality is not yet supported on Ext4."

  # Commented out for now to avoid unreachable code
  #
  # # If this is being called from a FileObject instance, then MiqFS owns contained instance members.
  # # If this is being called from an Ext4 module method, then self owns contained instance members.
  # miqfs = self if miqfs.nil?

  # # Preprocess path.
  # p = unnormalizePath(p)
  # dir, fil = File.split(p)

  # # Parent directory must exist.
  # dirObj = ifs_getDir(dir, miqfs)
  # return nil if dir.nil?
  # dirObj.createFile(fil)
end

#unnormalizePath(p) ⇒ Object

Wack leading drive letter & colon.



307
308
309
# File 'lib/fs/MiqFS/modules/Ext4.rb', line 307

def unnormalizePath(p)
  p[1] == 58 ? p[2, p.size] : p
end