Class: SlowFat::Filesystem

Inherits:
Object
  • Object
show all
Defined in:
lib/slowfat/filesystem.rb

Overview

Filesystem coordinates overall FAT filesystem access.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(backing:, base: 0x0000) ⇒ Filesystem

Set up a new filesystem connection

Parameters:

  • backing (IO)

    the storage containing the filesystem (e.g. open file)

  • base (Integer) (defaults to: 0x0000)

    the start of the filesystem within the backing device



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/slowfat/filesystem.rb', line 24

def initialize(backing:, base: 0x0000)
  @backing = backing
  @base = base

  fat_base = @base + 512
  fat_size = bios_parameter_block.bytes_per_logsect * bios_parameter_block.logsects_per_fat
  # TODO: shouldn't assume there's always two FATs
  @fats = []
  @fats[0] = FileAllocationTable.new(backing: backing, base: fat_base, size: fat_size)
  @fats[1] = FileAllocationTable.new(backing: backing, base: fat_base + fat_size, size: fat_size)

  # TODO: maybe shouldn't load the whole rootdir by default, I/O-wise?
  @rootdir_base = fat_base + fat_size*2
  @rootdir = Directory.new(backing: backing, base: rootdir_base, max_entries: bios_parameter_block.root_entries)
  @cluster_size = bios_parameter_block.bytes_per_logsect * bios_parameter_block.logsects_per_cluster
  @data_base = rootdir_base + bios_parameter_block.root_entries * 32 - @cluster_size*2
end

Instance Attribute Details

#backingIO (readonly)

Returns the backing IO object for this filesystem.

Returns:

  • (IO)

    the backing IO object for this filesystem



8
9
10
# File 'lib/slowfat/filesystem.rb', line 8

def backing
  @backing
end

#cluster_sizeInteger (readonly)

Returns the cluster size used on this filesystem.

Returns:

  • (Integer)

    the cluster size used on this filesystem



18
19
20
# File 'lib/slowfat/filesystem.rb', line 18

def cluster_size
  @cluster_size
end

#data_baseInteger (readonly)

Returns the location where the data starts within the backing.

Returns:

  • (Integer)

    the location where the data starts within the backing



14
15
16
# File 'lib/slowfat/filesystem.rb', line 14

def data_base
  @data_base
end

#fatsArray<FileAllocationTable> (readonly)

Returns array of file allocation tables.

Returns:



16
17
18
# File 'lib/slowfat/filesystem.rb', line 16

def fats
  @fats
end

#rootdirDirectory (readonly)

Returns the Directory object containing the root directory.

Returns:

  • (Directory)

    the Directory object containing the root directory



12
13
14
# File 'lib/slowfat/filesystem.rb', line 12

def rootdir
  @rootdir
end

#rootdir_baseInteger (readonly)

Returns the location where the root directory information starts within the backing.

Returns:

  • (Integer)

    the location where the root directory information starts within the backing



10
11
12
# File 'lib/slowfat/filesystem.rb', line 10

def rootdir_base
  @rootdir_base
end

Instance Method Details

#bios_parameter_blockBiosParameterBlock

Access the BIOS Parameter Block of this filesystem.

Returns:



53
54
55
# File 'lib/slowfat/filesystem.rb', line 53

def bios_parameter_block
  bootsect.bios_parameter_block
end

#bootsectBootSector

Access the boot sector of this filesystem.

Returns:

  • (BootSector)

    the boot sector on this filesystem



45
46
47
48
# File 'lib/slowfat/filesystem.rb', line 45

def bootsect
  @backing.seek @base
  BootSector.new @backing.read(512)
end

#dir(dirname) ⇒ Directory

Access a directory within this filesystem.

Parameters:

  • dirname (String)

    the path to retrieve a directory object for

Returns:

  • (Directory)

    the directory object matching the requested path



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/slowfat/filesystem.rb', line 68

def dir(dirname)
  # TODO: accept either / or    path_elements = dirname.split('/')
  current_dir_base = @rootdir_base
  next_dir = nil
  max_entries = 32
  path_elements.each do |path_element|
    this_dir = Directory.new(backing: @backing, base: current_dir_base, max_entries: max_entries)
    next_dir = this_dir.dir_entry(path_element)
    return nil if next_dir == nil
    next_dir_base = @data_base + next_dir.start_cluster*@cluster_size
    # all directories except the root have more entries available
    max_entries = @cluster_size/32
    current_dir_base = next_dir_base
  end

  Directory.new(backing: @backing, base: current_dir_base, max_entries: max_entries)
end

#extended_bios_parameter_blockExtendedBiosParameterBlock

Access the Extended BIOS Parameter Block of this filesystem.

Returns:



60
61
62
# File 'lib/slowfat/filesystem.rb', line 60

def extended_bios_parameter_block
  bootsect.extended_bios_parameter_block
end

#file(path) ⇒ FatFile

Access a file within this filesystem

Parameters:

  • path (String)

    the path to retrieve a file object for

Returns:

  • (FatFile)

    the file object matching the requested path



91
92
93
94
95
96
97
# File 'lib/slowfat/filesystem.rb', line 91

def file(path)
  path_components = path.split('/')
  dir_components = path_components[0..-2]
  filename = path_components[-1]
  dentry = dir(dir_components.join('/')).file_entry(filename)
  FatFile.new filesystem: self, dentry: dentry
end