manageiq-smartstate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (305) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +4 -0
  4. data/.rspec_ci +4 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +202 -0
  8. data/README.md +45 -0
  9. data/Rakefile +23 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
  13. data/lib/MiqVm/MiqLocalVm.rb +50 -0
  14. data/lib/MiqVm/MiqRhevmVm.rb +179 -0
  15. data/lib/MiqVm/MiqVm.rb +355 -0
  16. data/lib/MiqVm/miq_azure_vm.rb +96 -0
  17. data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
  18. data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
  19. data/lib/MiqVm/test/localVm.rb +45 -0
  20. data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
  21. data/lib/MiqVm/test/remoteVm.rb +65 -0
  22. data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
  23. data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
  24. data/lib/MiqVm/test/rhevmTest.rb +70 -0
  25. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
  26. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
  27. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
  28. data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
  29. data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
  30. data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
  31. data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
  32. data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
  33. data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
  34. data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
  35. data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
  36. data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
  37. data/lib/VolumeManager/LVM/parser.rb +138 -0
  38. data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
  39. data/lib/VolumeManager/LVM/scanner.rb +156 -0
  40. data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
  41. data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
  42. data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
  43. data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
  44. data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
  45. data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
  46. data/lib/VolumeManager/LVM/thin.rb +6 -0
  47. data/lib/VolumeManager/LVM/volume_group.rb +97 -0
  48. data/lib/VolumeManager/LVM.rb +8 -0
  49. data/lib/VolumeManager/MiqLdm.rb +546 -0
  50. data/lib/VolumeManager/MiqLvm.rb +17 -0
  51. data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
  52. data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
  53. data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
  54. data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
  55. data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
  56. data/lib/VolumeManager/test/blockDevTest.rb +40 -0
  57. data/lib/VolumeManager/test/ldm.rb +97 -0
  58. data/lib/blackbox/VmBlackBox.rb +103 -0
  59. data/lib/blackbox/xmlStorage.rb +180 -0
  60. data/lib/db/MiqBdb/MiqBdb.rb +309 -0
  61. data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
  62. data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
  63. data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
  64. data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
  65. data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
  66. data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
  67. data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
  68. data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
  69. data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
  70. data/lib/disk/DiskProbe.rb +68 -0
  71. data/lib/disk/MiqDisk.rb +317 -0
  72. data/lib/disk/camcorder_test.rb +90 -0
  73. data/lib/disk/dos_mbr.img +0 -0
  74. data/lib/disk/modules/AzureBlobDisk.rb +101 -0
  75. data/lib/disk/modules/LocalDevMod.rb +47 -0
  76. data/lib/disk/modules/LocalDevProbe.rb +6 -0
  77. data/lib/disk/modules/MSCommon.rb +352 -0
  78. data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
  79. data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
  80. data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
  81. data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
  82. data/lib/disk/modules/MiqLargeFile.rb +63 -0
  83. data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
  84. data/lib/disk/modules/QcowDisk.rb +692 -0
  85. data/lib/disk/modules/QcowDiskProbe.rb +34 -0
  86. data/lib/disk/modules/RawBlockIO.rb +116 -0
  87. data/lib/disk/modules/RawDisk.rb +45 -0
  88. data/lib/disk/modules/RawDiskProbe.rb +7 -0
  89. data/lib/disk/modules/RhevmDescriptor.rb +167 -0
  90. data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
  91. data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
  92. data/lib/disk/modules/VMWareDescriptor.rb +214 -0
  93. data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
  94. data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
  95. data/lib/disk/modules/VhdxDisk.rb +625 -0
  96. data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
  97. data/lib/disk/modules/VixDiskMod.rb +54 -0
  98. data/lib/disk/modules/VixDiskProbe.rb +6 -0
  99. data/lib/disk/modules/miq_disk_cache.rb +135 -0
  100. data/lib/disk/modules/miq_dummy_disk.rb +41 -0
  101. data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
  102. data/lib/disk/test.rb +66 -0
  103. data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
  104. data/lib/fs/MetakitFS/test/Makefile +14 -0
  105. data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
  106. data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
  107. data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
  108. data/lib/fs/MetakitFS/test/init.rb +3 -0
  109. data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
  110. data/lib/fs/MetakitFS/test/mk4test.c +92 -0
  111. data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
  112. data/lib/fs/MetakitFS/test/proto.rb +97 -0
  113. data/lib/fs/MiqFS/FsProbe.rb +39 -0
  114. data/lib/fs/MiqFS/MiqFS.rb +515 -0
  115. data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
  116. data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
  117. data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
  118. data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
  119. data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
  120. data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
  121. data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
  122. data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
  123. data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
  124. data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
  125. data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
  126. data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
  127. data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
  128. data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
  129. data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
  130. data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
  131. data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
  132. data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
  133. data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
  134. data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
  135. data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
  136. data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
  137. data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
  138. data/lib/fs/MiqFS/modules/XFS.rb +300 -0
  139. data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
  140. data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
  141. data/lib/fs/MiqFS/test.rb +59 -0
  142. data/lib/fs/MiqFsUtil.rb +383 -0
  143. data/lib/fs/MiqMountManager.rb +209 -0
  144. data/lib/fs/MiqNativeMountManager.rb +101 -0
  145. data/lib/fs/MountManagerProbe.rb +29 -0
  146. data/lib/fs/ReiserFS/block.rb +209 -0
  147. data/lib/fs/ReiserFS/directory.rb +136 -0
  148. data/lib/fs/ReiserFS/directory_entry.rb +140 -0
  149. data/lib/fs/ReiserFS/file_data.rb +111 -0
  150. data/lib/fs/ReiserFS/superblock.rb +140 -0
  151. data/lib/fs/ReiserFS/utils.rb +95 -0
  152. data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
  153. data/lib/fs/ext3/alloc_bitmap.rb +38 -0
  154. data/lib/fs/ext3/block_pointers_path.rb +130 -0
  155. data/lib/fs/ext3/directory.rb +51 -0
  156. data/lib/fs/ext3/directory_entry.rb +67 -0
  157. data/lib/fs/ext3/ex_attrib_header.rb +14 -0
  158. data/lib/fs/ext3/ex_attrib_name.rb +23 -0
  159. data/lib/fs/ext3/file_data.rb +130 -0
  160. data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
  161. data/lib/fs/ext3/group_descriptor_table.rb +54 -0
  162. data/lib/fs/ext3/hash_tree_entry.rb +18 -0
  163. data/lib/fs/ext3/hash_tree_header.rb +15 -0
  164. data/lib/fs/ext3/inode.rb +228 -0
  165. data/lib/fs/ext3/posix_acl_entry.rb +29 -0
  166. data/lib/fs/ext3/posix_acl_header.rb +11 -0
  167. data/lib/fs/ext3/superblock.rb +406 -0
  168. data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
  169. data/lib/fs/ext4/alloc_bitmap.rb +38 -0
  170. data/lib/fs/ext4/directory.rb +87 -0
  171. data/lib/fs/ext4/directory_entry.rb +77 -0
  172. data/lib/fs/ext4/ex_attrib_header.rb +14 -0
  173. data/lib/fs/ext4/ex_attrib_name.rb +23 -0
  174. data/lib/fs/ext4/extent.rb +35 -0
  175. data/lib/fs/ext4/extent_header.rb +40 -0
  176. data/lib/fs/ext4/extent_index.rb +33 -0
  177. data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
  178. data/lib/fs/ext4/group_descriptor_table.rb +54 -0
  179. data/lib/fs/ext4/hash_tree_entry.rb +58 -0
  180. data/lib/fs/ext4/hash_tree_header.rb +35 -0
  181. data/lib/fs/ext4/inode.rb +465 -0
  182. data/lib/fs/ext4/posix_acl_entry.rb +29 -0
  183. data/lib/fs/ext4/posix_acl_header.rb +11 -0
  184. data/lib/fs/ext4/superblock.rb +412 -0
  185. data/lib/fs/fat32/boot_sect.rb +379 -0
  186. data/lib/fs/fat32/directory.rb +222 -0
  187. data/lib/fs/fat32/directory_entry.rb +540 -0
  188. data/lib/fs/fat32/file_data.rb +128 -0
  189. data/lib/fs/iso9660/boot_sector.rb +170 -0
  190. data/lib/fs/iso9660/directory.rb +90 -0
  191. data/lib/fs/iso9660/directory_entry.rb +147 -0
  192. data/lib/fs/iso9660/file_data.rb +78 -0
  193. data/lib/fs/iso9660/rock_ridge.rb +329 -0
  194. data/lib/fs/iso9660/util.rb +57 -0
  195. data/lib/fs/modules/LinuxMount.rb +300 -0
  196. data/lib/fs/modules/LinuxMountProbe.rb +29 -0
  197. data/lib/fs/modules/WinMount.rb +97 -0
  198. data/lib/fs/modules/WinMountProbe.rb +24 -0
  199. data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
  200. data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
  201. data/lib/fs/ntfs/attrib_data.rb +74 -0
  202. data/lib/fs/ntfs/attrib_file_name.rb +110 -0
  203. data/lib/fs/ntfs/attrib_header.rb +194 -0
  204. data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
  205. data/lib/fs/ntfs/attrib_index_root.rb +247 -0
  206. data/lib/fs/ntfs/attrib_object_id.rb +40 -0
  207. data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
  208. data/lib/fs/ntfs/attrib_type.rb +49 -0
  209. data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
  210. data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
  211. data/lib/fs/ntfs/boot_sect.rb +253 -0
  212. data/lib/fs/ntfs/data_run.rb +358 -0
  213. data/lib/fs/ntfs/directory_index_node.rb +114 -0
  214. data/lib/fs/ntfs/index_node_header.rb +69 -0
  215. data/lib/fs/ntfs/index_record_header.rb +85 -0
  216. data/lib/fs/ntfs/mft_entry.rb +288 -0
  217. data/lib/fs/ntfs/utils.rb +43 -0
  218. data/lib/fs/test/camcorder_fs_test.rb +108 -0
  219. data/lib/fs/test/collect_files_direct.yaml +22 -0
  220. data/lib/fs/test/collect_files_in.yaml +24 -0
  221. data/lib/fs/test/collect_files_in_nc.yaml +22 -0
  222. data/lib/fs/test/collect_files_out.yaml +6 -0
  223. data/lib/fs/test/collect_files_rm.yaml +6 -0
  224. data/lib/fs/test/copyTest.rb +126 -0
  225. data/lib/fs/test/fsTest.rb +87 -0
  226. data/lib/fs/test/updateTest.rb +184 -0
  227. data/lib/fs/xfs/allocation_group.rb +160 -0
  228. data/lib/fs/xfs/bmap_btree_block.rb +125 -0
  229. data/lib/fs/xfs/bmap_btree_record.rb +80 -0
  230. data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
  231. data/lib/fs/xfs/directory.rb +133 -0
  232. data/lib/fs/xfs/directory2_data_header.rb +27 -0
  233. data/lib/fs/xfs/directory3_data_header.rb +34 -0
  234. data/lib/fs/xfs/directory_block_tail.rb +22 -0
  235. data/lib/fs/xfs/directory_data_header.rb +46 -0
  236. data/lib/fs/xfs/directory_entry.rb +106 -0
  237. data/lib/fs/xfs/inode.rb +532 -0
  238. data/lib/fs/xfs/inode_map.rb +100 -0
  239. data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
  240. data/lib/fs/xfs/short_form_header.rb +44 -0
  241. data/lib/fs/xfs/superblock.rb +556 -0
  242. data/lib/lib/tasks/azure.rake +52 -0
  243. data/lib/manageiq/smartstate/version.rb +5 -0
  244. data/lib/manageiq/smartstate.rb +7 -0
  245. data/lib/manageiq-smartstate.rb +1 -0
  246. data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
  247. data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
  248. data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
  249. data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
  250. data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
  251. data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
  252. data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
  253. data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
  254. data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
  255. data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
  256. data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
  257. data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
  258. data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
  259. data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
  260. data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
  261. data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
  262. data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
  263. data/lib/metadata/VMMount/VMMount.rb +81 -0
  264. data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
  265. data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
  266. data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
  267. data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
  268. data/lib/metadata/VmConfig/VmConfig.rb +947 -0
  269. data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
  270. data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
  271. data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
  272. data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
  273. data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
  274. data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
  275. data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
  276. data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
  277. data/lib/metadata/linux/InitProcHash.rb +632 -0
  278. data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
  279. data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
  280. data/lib/metadata/linux/LinuxPackages.rb +209 -0
  281. data/lib/metadata/linux/LinuxSystemd.rb +130 -0
  282. data/lib/metadata/linux/LinuxUsers.rb +289 -0
  283. data/lib/metadata/linux/LinuxUtils.rb +197 -0
  284. data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
  285. data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
  286. data/lib/metadata/linux/test/Name +0 -0
  287. data/lib/metadata/linux/test/Packages +0 -0
  288. data/lib/metadata/linux/test/rpoTest.rb +5 -0
  289. data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
  290. data/lib/metadata/util/event_log_filter.rb +61 -0
  291. data/lib/metadata/util/md5deep.rb +280 -0
  292. data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
  293. data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
  294. data/lib/metadata/util/win32/Win32Services.rb +86 -0
  295. data/lib/metadata/util/win32/Win32Software.rb +326 -0
  296. data/lib/metadata/util/win32/Win32System.rb +333 -0
  297. data/lib/metadata/util/win32/boot_info_win.rb +59 -0
  298. data/lib/metadata/util/win32/fleece_hives.rb +220 -0
  299. data/lib/metadata/util/win32/ms-registry.rb +650 -0
  300. data/lib/metadata/util/win32/peheader.rb +868 -0
  301. data/lib/metadata/util/win32/remote-registry.rb +142 -0
  302. data/lib/metadata/util/win32/system_path_win.rb +103 -0
  303. data/lib/metadata/util/win32/versioninfo.rb +17 -0
  304. data/manageiq-smartstate.gemspec +35 -0
  305. metadata +486 -0
@@ -0,0 +1,406 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'fs/ext3/group_descriptor_table'
4
+ require 'fs/ext3/inode'
5
+
6
+ require 'binary_struct'
7
+ require 'util/miq-uuid'
8
+ require 'stringio'
9
+ require 'memory_buffer'
10
+
11
+ require 'rufus/lru'
12
+
13
+ module Ext3
14
+ # ////////////////////////////////////////////////////////////////////////////
15
+ # // Data definitions. Linux 2.6.2 from Fedora Core 6.
16
+
17
+ SUPERBLOCK = BinaryStruct.new([
18
+ 'L', 'num_inodes', # Number of inodes in file system.
19
+ 'L', 'num_blocks', # Number of blocks in file system.
20
+ 'L', 'reserved_blocks', # Number of reserved blocks to prevent file system from filling up.
21
+ 'L', 'unallocated_blocks', # Number of unallocated blocks.
22
+ 'L', 'unallocated_inodes', # Number of unallocated inodes.
23
+ 'L', 'block_group_zero', # Block where block group 0 starts.
24
+ 'L', 'block_size', # Block size (saved as num bits to shift 1024 left).
25
+ 'L', 'fragment_size', # Fragment size (saved as num bits to shift 1024 left).
26
+ 'L', 'blocks_in_group', # Number of blocks in each block group.
27
+ 'L', 'fragments_in_group', # Number of fragments in each block group.
28
+ 'L', 'inodes_in_group', # Number of inodes in each block group.
29
+ 'L', 'last_mount_time', # Time FS was last mounted.
30
+ 'L', 'last_write_time', # Time FS was last written to.
31
+ 'S', 'mount_count', # Current mount count.
32
+ 'S', 'max_mount_count', # Maximum mount count.
33
+ 'S', 'signature', # Always 0xef53
34
+ 'S', 'fs_state', # File System State: see FSS_ below.
35
+ 'S', 'err_method', # Error Handling Method: see EHM_ below.
36
+ 'S', 'ver_minor', # Minor version number.
37
+ 'L', 'last_check_time', # Last consistency check time.
38
+ 'L', 'forced_check_int', # Forced check interval.
39
+ 'L', 'creator_os', # Creator OS: see CO_ below.
40
+ 'L', 'ver_major', # Major version: see MV_ below.
41
+ 'S', 'uid_res_blocks', # UID that can use reserved blocks.
42
+ 'S', 'gid_res_blocks', # GID that can uss reserved blocks.
43
+ # Begin dynamic version fields
44
+ 'L', 'first_inode', # First non-reserved inode in file system.
45
+ 'S', 'inode_size', # Size of each inode.
46
+ 'S', 'block_group', # Block group that this superblock is part of (if backup copy).
47
+ 'L', 'compat_flags', # Compatible feature flags (see CFF_ below).
48
+ 'L', 'incompat_flags', # Incompatible feature flags (see ICF_ below).
49
+ 'L', 'ro_flags', # Read Only feature flags (see ROF_ below).
50
+ 'a16', 'fs_id', # File system ID (UUID or GUID).
51
+ 'a16', 'vol_name', # Volume name.
52
+ 'a64', 'last_mnt_path', # Path where last mounted.
53
+ 'L', 'algo_use_bmp', # Algorithm usage bitmap.
54
+ # Performance hints
55
+ 'C', 'file_prealloc_blks', # Blocks to preallocate for files.
56
+ 'C', 'dir_prealloc_blks', # Blocks to preallocate for directories.
57
+ 'S', 'unused1', # Unused.
58
+ # Journal support
59
+ 'a16', 'jrnl_id', # Joural ID (UUID or GUID).
60
+ 'L', 'jrnl_inode', # Journal inode.
61
+ 'L', 'jrnl_device', # Journal device.
62
+ 'L', 'orphan_head', # Head of orphan inode list.
63
+ 'a16', 'hash_seed', # HTREE hash seed. This is actually L4 (__u32 s_hash_seed[4])
64
+ 'C', 'hash_ver', # Default hash version.
65
+ 'C', 'unused2',
66
+ 'S', 'unused3',
67
+ 'L', 'mount_opts', # Default mount options.
68
+ 'L', 'first_meta_blk_grp', # First metablock block group.
69
+ 'a360', 'reserved' # Unused.
70
+ ])
71
+
72
+ SUPERBLOCK_SIG = 0xef53
73
+ SUPERBLOCK_OFFSET = 1024
74
+ SUPERBLOCK_SIZE = 1024
75
+ GDE_SIZE = 32
76
+ INODE_SIZE = 128 # Default inode size.
77
+
78
+ # Simpler structure for just validating the presence of a superblock
79
+ SUPERBLOCK_VALIDATE = BinaryStruct.new([
80
+ 'x56', nil,
81
+ 'S', 'signature', # Always 0xef53
82
+ 'S', 'fs_state', # File System State: see FSS_ below.
83
+ 'S', 'err_method', # Error Handling Method: see EHM_ below.
84
+ ])
85
+ SUPERBLOCK_VALIDATE_SIZE = SUPERBLOCK_VALIDATE.size
86
+
87
+ # ////////////////////////////////////////////////////////////////////////////
88
+ # // Class.
89
+
90
+ class Superblock
91
+ # Default cache sizes.
92
+ DEF_BLOCK_CACHE_SIZE = 50
93
+ DEF_INODE_CACHE_SIZE = 50
94
+
95
+ # File System State.
96
+ FSS_CLEAN = 0x0001 # File system is clean.
97
+ FSS_ERR = 0x0002 # File system has errors.
98
+ FSS_ORPHAN_REC = 0x0004 # Orphan inodes are being recovered.
99
+ # NOTE: Recovered NOT by this software but by the 'NIX kernel.
100
+ # IOW start the VM to repair it.
101
+ FSS_END = FSS_CLEAN | FSS_ERR | FSS_ORPHAN_REC
102
+
103
+ # Error Handling Method.
104
+ EHM_CONTINUE = 1 # No action.
105
+ EHM_RO_REMOUNT = 2 # Remount file system as read only.
106
+ EHM_PANIC = 3 # Don't mount? halt? - don't know what this means.
107
+
108
+ # Creator OS.
109
+ CO_LINUX = 0 # NOTE: FS creation tools allow setting this value.
110
+ CO_GNU_HURD = 1 # These values are supposedly defined.
111
+ CO_MASIX = 2
112
+ CO_FREE_BSD = 3
113
+ CO_LITES = 4
114
+
115
+ # Major Version.
116
+ MV_ORIGINAL = 0 # NOTE: If version is not dynamic, then values from
117
+ MV_DYNAMIC = 1 # first_inode on may not be accurate.
118
+
119
+ # Compatible Feature Flags.
120
+ CFF_PREALLOC_DIR_BLKS = 0x0001 # Preallocate directory blocks to reduce fragmentation.
121
+ CFF_AFS_SERVER_INODES = 0x0002 # AFS server inodes exist in system.
122
+ CFF_JOURNAL = 0x0004 # File system has journal (Ext3).
123
+ CFF_EXTENDED_ATTRIBS = 0x0008 # Inodes have extended attributes.
124
+ CFF_BIG_PART = 0x0010 # File system can resize itself for larger partitions.
125
+ CFF_HASH_INDEX = 0x0020 # Directories use hash index (another modified b-tree).
126
+ CFF_FLAGS = (CFF_PREALLOC_DIR_BLKS | CFF_AFS_SERVER_INODES | CFF_JOURNAL | CFF_EXTENDED_ATTRIBS | CFF_BIG_PART | CFF_HASH_INDEX)
127
+
128
+ # Incompatible Feature flags.
129
+ ICF_COMPRESSION = 0x0001 # Not supported on Linux?
130
+ ICF_FILE_TYPE = 0x0002 # Directory entries contain file type field.
131
+ ICF_RECOVER_FS = 0x0004 # File system needs recovery.
132
+ ICF_JOURNAL = 0x0008 # File system uses journal device.
133
+ ICF_META_BG = 0x0010 #
134
+ ICF_EXTENTS = 0x0040 # File system uses extents (ext4)
135
+ ICF_64BIT = 0x0080 # File system uses 64-bit
136
+ ICF_MMP = 0x0100 #
137
+ ICF_FLEX_BG = 0x0200 #
138
+ ICF_EA_INODE = 0x0400 # EA in inode
139
+ ICF_DIRDATA = 0x1000 # data in dirent
140
+ ICF_FLAGS = (ICF_COMPRESSION | ICF_FILE_TYPE | ICF_RECOVER_FS | ICF_JOURNAL | ICF_META_BG | ICF_EXTENTS | ICF_64BIT | ICF_MMP | ICF_FLEX_BG | ICF_EA_INODE | ICF_DIRDATA)
141
+
142
+ # ReadOnly Feature flags.
143
+ ROF_SPARSE = 0x0001 # Sparse superblocks & group descriptor tables.
144
+ ROF_LARGE_FILES = 0x0002 # File system contains large files (over 4G).
145
+ ROF_BTREES = 0x0004 # Directories use B-Trees (not implemented?).
146
+ ROF_FLAGS = (ROF_SPARSE | ROF_LARGE_FILES | ROF_BTREES)
147
+
148
+ # /////////////////////////////////////////////////////////////////////////
149
+ # // initialize
150
+ attr_reader :numGroups, :fsId, :stream, :numBlocks, :numInodes, :fsId, :volName
151
+ attr_reader :sectorSize, :blockSize
152
+
153
+ @@track_inodes = false
154
+
155
+ def self.isSuperblock?(buf)
156
+ sb = SUPERBLOCK_VALIDATE.decode(buf)
157
+ sb['signature'] == SUPERBLOCK_SIG &&
158
+ sb['fs_state'] <= FSS_END &&
159
+ sb['err_method'] <= EHM_PANIC
160
+ end
161
+
162
+ def initialize(stream)
163
+ raise "Ext3::Superblock.initialize: Nil stream" if stream.nil?
164
+ @stream = stream
165
+
166
+ # Seek, read & decode the superblock structure
167
+ @stream.seek(SUPERBLOCK_OFFSET)
168
+ @sb = SUPERBLOCK.decode(@stream.read(SUPERBLOCK_SIZE))
169
+
170
+ # Grab some quick facts & make sure there's nothing wrong. Tight qualification.
171
+ raise "Ext3::Superblock.initialize: Invalid signature=[#{@sb['signature']}]" if @sb['signature'] != SUPERBLOCK_SIG
172
+ state = @sb['fs_state']
173
+ raise "Ext3::Superblock.initialize: Invalid file system state" if state > FSS_END
174
+ if state != FSS_CLEAN
175
+ $log.warn("Ext3 file system has errors") if $log && gotBit?(state, FSS_ERR)
176
+ $log.warn("Ext3 orphan inodes being recovered") if $log && gotBit?(state, FSS_ORPHAN_REC)
177
+ end
178
+ raise "Ext3::Superblock.initialize: Invalid error handling method=[#{@sb['err_method']}]" if @sb['err_method'] > EHM_PANIC
179
+ raise "Ext3::Superblock.initialize: Filesystem has extents (ext4)" if gotBit?(@sb['incompat_flags'], ICF_EXTENTS)
180
+
181
+ @blockSize = 1024 << @sb['block_size']
182
+
183
+ @block_cache = LruHash.new(DEF_BLOCK_CACHE_SIZE)
184
+ @inode_cache = LruHash.new(DEF_INODE_CACHE_SIZE)
185
+
186
+ # expose for testing.
187
+ @numBlocks = @sb['num_blocks']
188
+ @numInodes = @sb['num_inodes']
189
+
190
+ # Inode file size members can't be trusted, so use sector count instead.
191
+ # MiqDisk exposes blockSize, which for our purposes is sectorSize.
192
+ @sectorSize = @stream.blockSize
193
+
194
+ # Preprocess some members.
195
+ @sb['vol_name'].delete!("\000")
196
+ @sb['last_mnt_path'].delete!("\000")
197
+ @numGroups, @lastGroupBlocks = @sb['num_blocks'].divmod(@sb['blocks_in_group'])
198
+ @numGroups += 1 if @lastGroupBlocks > 0
199
+ @fsId = UUIDTools::UUID.parse_raw(@sb['fs_id'])
200
+ @volName = @sb['vol_name']
201
+ @jrnlId = UUIDTools::UUID.parse_raw(@sb['jrnl_id'])
202
+ end
203
+
204
+ # ////////////////////////////////////////////////////////////////////////////
205
+ # // Class helpers & accessors.
206
+
207
+ def gdt
208
+ @gdt ||= GroupDescriptorTable.new(self)
209
+ end
210
+
211
+ def isDynamic?
212
+ @sb['ver_major'] == MV_DYNAMIC
213
+ end
214
+
215
+ def isNewDirEnt?
216
+ gotBit?(@sb['incompat_flags'], ICF_FILE_TYPE)
217
+ end
218
+
219
+ def fragmentSize
220
+ 1024 << @sb['fragment_size']
221
+ end
222
+
223
+ def blocksPerGroup
224
+ @sb['blocks_in_group']
225
+ end
226
+
227
+ def fragmentsPerGroup
228
+ @sb['fragments_in_group']
229
+ end
230
+
231
+ def inodesPerGroup
232
+ @sb['inodes_in_group']
233
+ end
234
+
235
+ def inodeSize
236
+ isDynamic? ? @sb['inode_size'] : INODE_SIZE
237
+ end
238
+
239
+ def freeBytes
240
+ @sb['unallocated_blocks'] * @blockSize
241
+ end
242
+
243
+ def blockNumToGroupNum(block)
244
+ raise "Ext3::Superblock.blockNumToGroupNum: block is nil" if block.nil?
245
+ group = (block - @sb['block_group_zero']) / @sb['blocks_in_group']
246
+ offset = block.modulo(@sb['blocks_in_group'])
247
+ return group, offset
248
+ end
249
+
250
+ def firstGroupBlockNum(group)
251
+ group * @sb['blocks_in_group'] + @sb['block_group_zero']
252
+ end
253
+
254
+ def inodeNumToGroupNum(inode)
255
+ (inode - 1).divmod(inodesPerGroup)
256
+ end
257
+
258
+ def blockToAddress(block)
259
+ address = block * @blockSize
260
+ address += (SUPERBLOCK_SIZE + GDE_SIZE * @numGroups) if address == SUPERBLOCK_OFFSET
261
+ address
262
+ end
263
+
264
+ def isValidInode?(inode)
265
+ group, offset = inodeNumToGroupNum(inode)
266
+ gde = gdt[group]
267
+ gde.inodeAllocBmp[offset]
268
+ end
269
+
270
+ def isValidBlock?(block)
271
+ group, offset = blockNumToGroupNum(block)
272
+ gde = gdt[group]
273
+ gde.blockAllocBmp[offset]
274
+ end
275
+
276
+ # Ignore allocation is for testing only.
277
+ def getInode(inode, _ignore_alloc = false)
278
+ unless @inode_cache.key?(inode)
279
+ group, offset = inodeNumToGroupNum(inode)
280
+ gde = gdt[group]
281
+ # raise "Inode #{inode} is not allocated" if (not gde.inodeAllocBmp[offset] and not ignore_alloc)
282
+ @stream.seek(blockToAddress(gde.inodeTable) + offset * inodeSize)
283
+ @inode_cache[inode] = Inode.new(@stream.read(inodeSize))
284
+ $log.info "Inode num: #{inode}\n#{@inode_cache[inode].dump}\n\n" if $log && @@track_inodes
285
+ end
286
+
287
+ @inode_cache[inode]
288
+ end
289
+
290
+ # Ignore allocation is for testing only.
291
+ def getBlock(block, _ignore_alloc = false)
292
+ raise "Ext3::Superblock.getBlock: block is nil" if block.nil?
293
+
294
+ unless @block_cache.key?(block)
295
+ if block == 0
296
+ @block_cache[block] = MemoryBuffer.create(@blockSize)
297
+ else
298
+ group, offset = blockNumToGroupNum(block)
299
+ gde = gdt[group]
300
+ # raise "Block #{block} is not allocated" if (not gde.blockAllocBmp[offset] and not ignore_alloc)
301
+
302
+ address = blockToAddress(block) # This function will read the block into our cache
303
+
304
+ @stream.seek(address)
305
+ @block_cache[block] = @stream.read(@blockSize)
306
+ end
307
+ end
308
+ @block_cache[block]
309
+ end
310
+
311
+ def getFeatureStrings
312
+ out = "Compatible Feature Flags:\n"
313
+ cff = @sb['compat_flags']
314
+ out << " CFF_PREALLOC_DIR_BLKS\n" if gotBit?(cff, CFF_PREALLOC_DIR_BLKS)
315
+ out << " CFF_AFS_SERVER_INODE\n" if gotBit?(cff, CFF_AFS_SERVER_INODES)
316
+ out << " CFF_JOURNAL\n" if gotBit?(cff, CFF_JOURNAL)
317
+ out << " CFF_EXTENDED_ATTRIBS\n" if gotBit?(cff, CFF_EXTENDED_ATTRIBS)
318
+ out << " CFF_BIG_PART\n" if gotBit?(cff, CFF_BIG_PART)
319
+ out << " CFF_HASH_INDEX\n" if gotBit?(cff, CFF_HASH_INDEX)
320
+ extra = cff - (cff & CFF_FLAGS)
321
+ out << " Extra Flags: 0x%08X\n" % extra if extra != 0
322
+ out << "Incompatible Feature Flags:\n"
323
+ icf = @sb['incompat_flags']
324
+ out << " ICF_COMPRESSION\n" if gotBit?(icf, ICF_COMPRESSION)
325
+ out << " ICF_FILE_TYPE\n" if gotBit?(icf, ICF_FILE_TYPE)
326
+ out << " ICF_RECOVER_FS\n" if gotBit?(icf, ICF_RECOVER_FS)
327
+ out << " ICF_JOURNAL\n" if gotBit?(icf, ICF_JOURNAL)
328
+ out << " ICF_META_BG\n" if gotBit?(icf, ICF_META_BG)
329
+ out << " ICF_EXTENTS\n" if gotBit?(icf, ICF_EXTENTS)
330
+ out << " ICF_64BIT\n" if gotBit?(icf, ICF_64BIT)
331
+ out << " ICF_MMP\n" if gotBit?(icf, ICF_MMP)
332
+ out << " ICF_FLEX_BG\n" if gotBit?(icf, ICF_FLEX_BG)
333
+ out << " ICF_EA_INODE\n" if gotBit?(icf, ICF_EA_INODE)
334
+ out << " ICF_DIRDATA\n" if gotBit?(icf, ICF_DIRDATA)
335
+ extra = icf - (icf & ICF_FLAGS)
336
+ out << " Extra Flags: 0x%08X\n" % extra if extra != 0
337
+ out << "Read Only Feature Flags:\n"
338
+ rof = @sb['ro_flags']
339
+ out << " ROF_SPARSE\n" if gotBit?(rof, ROF_SPARSE)
340
+ out << " ROF_LARGE_FILES\n" if gotBit?(rof, ROF_LARGE_FILES)
341
+ out << " ROF_BTREES\n" if gotBit?(rof, ROF_BTREES)
342
+ extra = rof - (rof & ROF_FLAGS)
343
+ out << " Extra Flags: 0x%08X\n" % extra if extra != 0
344
+ out
345
+ end
346
+
347
+ # ////////////////////////////////////////////////////////////////////////////
348
+ # // Utility functions.
349
+
350
+ def gotBit?(field, bit)
351
+ field & bit == bit
352
+ end
353
+
354
+ # Dump object.
355
+ def dump
356
+ out = "\#<#{self.class}:0x#{'%08x' % object_id}>\n"
357
+ out << "Number of inodes : #{@sb['num_inodes']}\n"
358
+ out << "Number of blocks : #{@sb['num_blocks']}\n"
359
+ out << "Reserved blocks : #{@sb['reserved_blocks']}\n"
360
+ out << "Unallocated blocks : #{@sb['unallocated_blocks']}\n"
361
+ out << "Unallocated inodes : #{@sb['unallocated_inodes']}\n"
362
+ out << "Block group 0 : #{@sb['block_group_zero']}\n"
363
+ out << "Block size : #{@sb['block_size']} (#{@blockSize} bytes)\n"
364
+ out << "Fragment size : #{@sb['fragment_size']} (#{fragmentSize} bytes)\n"
365
+ out << "Blocks per group : #{@sb['blocks_in_group']} (#{blocksPerGroup} blocks per group)\n"
366
+ out << "Fragments per group : #{@sb['fragments_in_group']} (#{fragmentsPerGroup} fragments per group)\n"
367
+ out << "Inodes per group : #{@sb['inodes_in_group']} (#{inodesPerGroup} inodes per group)\n"
368
+ out << "Last mount time : #{Time.at(@sb['last_mount_time'])}\n"
369
+ out << "Last write time : #{Time.at(@sb['last_write_time'])}\n"
370
+ out << "Current mount count : #{@sb['mount_count']}\n"
371
+ out << "Maximum mount count : #{@sb['max_mount_count']}\n"
372
+ out << "Signature : #{@sb['signature']}\n"
373
+ out << "File system state : #{@sb['fs_state']}\n"
374
+ out << "Error hndling methd : #{@sb['err_method']}\n"
375
+ out << "Minor version : #{@sb['ver_minor']}\n"
376
+ out << "Last consistency check: #{Time.at(@sb['last_check_time'])}\n"
377
+ out << "Forced check interval : #{@sb['forced_check_int']} sec\n"
378
+ out << "Creator OS : #{@sb['creator_os']}\n"
379
+ out << "Major version : #{@sb['ver_major']}\n"
380
+ out << "UID can use res blocks: #{@sb['uid_res_blocks']}\n"
381
+ out << "GID can use res blocks: #{@sb['gid_res_blocks']}\n"
382
+ if isDynamic?
383
+ out << "First non-res inode : #{@sb['first_inode']}\n"
384
+ out << "Size of inode : #{@sb['inode_size']}\n"
385
+ out << "Block group of this SB: #{@sb['block_group']}\n"
386
+ out << "Compatible features : 0x#{'%08x' % @sb['compat_flags']}\n"
387
+ out << "Incompatible features : 0x#{'%08x' % @sb['incompat_flags']}\n"
388
+ out << "Read Only features : 0x#{'%08x' % @sb['ro_flags']}\n"
389
+ out << "File system id : #{@fsId}\n"
390
+ out << "Volume name : #{@sb['vol_name']}\n"
391
+ out << "Last mount path : #{@sb['last_mnt_path']}\n"
392
+ out << "Algorithm usage bitmap: 0x#{'%08x' % @sb['algo_use_bmp']}\n"
393
+ out << "Blocks prealloc files : #{@sb['file_prealloc_blks']}\n"
394
+ out << "Blocks prealloc dirs : #{@sb['dir_prealloc_blks']}\n"
395
+ out << "Journal id : #{@jrnlId}\n"
396
+ out << "Journal inode : #{@sb['jrnl_inode']}\n"
397
+ out << "Journal device : #{@sb['jrnl_device']}\n"
398
+ out << "Orphan inode head : #{@sb['orphan_head']}\n"
399
+ end
400
+ out << "Number of groups : #{numGroups}\n"
401
+ out << "Free bytes : #{freeBytes}\n"
402
+ out << getFeatureStrings
403
+ out
404
+ end
405
+ end
406
+ end # moule Ext3
@@ -0,0 +1,74 @@
1
+ require 'minitest/unit'
2
+ require 'enumerator'
3
+
4
+ require 'fs/ext3/block_pointers_path'
5
+ include Ext3
6
+
7
+ class TestBlockPointersPath < MiniTest::Unit::TestCase
8
+ NUM_INDIRECTS = 15
9
+ MAX_BLOCK = 3626
10
+
11
+ EXPECTED = [
12
+ 0, [0, nil, nil, nil], :direct,
13
+
14
+ 11, [11, nil, nil, nil], :direct,
15
+ 12, [12, 0, nil, nil], :single_indirect,
16
+ 13, [12, 1, nil, nil], :single_indirect,
17
+
18
+ 26, [12, 14, nil, nil], :single_indirect,
19
+ 27, [13, 0, 0, nil], :double_indirect,
20
+ 28, [13, 0, 1, nil], :double_indirect,
21
+
22
+ 41, [13, 0, 14, nil], :double_indirect,
23
+ 42, [13, 1, 0, nil], :double_indirect,
24
+
25
+ 251, [13, 14, 14, nil], :double_indirect,
26
+ 252, [14, 0, 0, 0], :triple_indirect,
27
+ 253, [14, 0, 0, 1], :triple_indirect,
28
+
29
+ 266, [14, 0, 0, 14], :triple_indirect,
30
+ 267, [14, 0, 1, 0], :triple_indirect,
31
+
32
+ 476, [14, 0, 14, 14], :triple_indirect,
33
+ 477, [14, 1, 0, 0], :triple_indirect,
34
+
35
+ MAX_BLOCK, [14, 14, 14, 14], :triple_indirect
36
+ ]
37
+
38
+ def test_block_set
39
+ path = BlockPointersPath.new(NUM_INDIRECTS)
40
+
41
+ assert_raise(ArgumentError) { path.block = -1 }
42
+ assert_raise(ArgumentError) { path.block = MAX_BLOCK + 1 }
43
+
44
+ EXPECTED.each_slice(3) do |block, path_a, type|
45
+ path.block = block
46
+ assert_equal block, path.block
47
+ assert_equal path_a, path.to_a
48
+ assert_equal type, path.index_type
49
+ end
50
+ end
51
+
52
+ def test_succ!
53
+ path = BlockPointersPath.new(NUM_INDIRECTS)
54
+
55
+ EXPECTED.each_slice(3) do |block, path_a, type|
56
+ path.succ! until path.block == block
57
+ assert_equal block, path.block
58
+ assert_equal path_a, path.to_a
59
+ assert_equal type, path.index_type
60
+ break if block == MAX_BLOCK
61
+ end
62
+
63
+ assert_raise(RangeError) { path.succ! }
64
+ end
65
+
66
+ def test_path_to_block
67
+ path = BlockPointersPath.new(NUM_INDIRECTS)
68
+
69
+ EXPECTED.each_slice(3) do |block, _path_a, _type|
70
+ path.block = block
71
+ assert_equal block, path.send(:path_to_block)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,38 @@
1
+ module Ext4
2
+ class AllocBitmap
3
+ def initialize(data)
4
+ raise "Ext4::AllocBitmap.initialize: Nil data" if data.nil?
5
+ @data = data
6
+ end
7
+
8
+ def isAllocated?(number)
9
+ getStatus(number)
10
+ end
11
+
12
+ def [](number)
13
+ getStatus(number)
14
+ end
15
+
16
+ def dump
17
+ @data.hex_dump
18
+ end
19
+
20
+ private
21
+
22
+ def getStatus(number)
23
+ byte, mask = index(number)
24
+ @data[byte] & mask == mask
25
+ end
26
+
27
+ def index(number)
28
+ byte, bit = number.divmod(8)
29
+ if byte > @data.size - 1
30
+ msg = "AllocBitmap#index: "
31
+ msg += "byte index #{byte} is out of range for data[0:#{@data.size - 1}]"
32
+ raise msg
33
+ end
34
+ mask = 128 >> bit
35
+ return byte, mask
36
+ end
37
+ end # class
38
+ end # module
@@ -0,0 +1,87 @@
1
+ require 'fs/ext4/directory_entry'
2
+ require 'fs/ext4/hash_tree_header'
3
+ require 'fs/ext4/hash_tree_entry'
4
+
5
+ module Ext4
6
+ class Directory
7
+ ROOT_DIRECTORY = 2
8
+
9
+ attr_reader :inodeNum
10
+
11
+ def initialize(sb, inodeNum = ROOT_DIRECTORY)
12
+ log_prefix = "Ext4::Directory.initialize"
13
+ raise "#{log_prefix}: Nil superblock" if sb.nil?
14
+ raise "#{log_prefix}: Nil inode number" if inodeNum.nil?
15
+ @sb = sb
16
+ @inodeNum = inodeNum
17
+ @inodeObj = sb.getInode(inodeNum)
18
+ raise "#{log_prefix}: INODE=#{inodeNum} is NOT a DIRECTORY" unless @inodeObj.isDir?
19
+ @data = @inodeObj.read
20
+ end
21
+
22
+ def globNames
23
+ @ent_names ||= globEntries.keys.compact.sort
24
+ end
25
+
26
+ def findEntry(name, type = nil)
27
+ return nil unless globEntries.key?(name)
28
+
29
+ globEntries[name].each do |ent|
30
+ unless @sb.isNewDirEnt?
31
+ inode = @sb.getInode(ent.inode)
32
+ ent.fileType = inode.fileModeToFileType
33
+ end
34
+
35
+ return ent if (ent.fileType == type) || type.nil?
36
+ end
37
+ nil
38
+ end
39
+
40
+ private
41
+
42
+ def globEntries
43
+ @ents_by_name ||= globEntriesByLinkedList
44
+ end
45
+
46
+ def globEntriesByLinkedList
47
+ ents_by_name = {}
48
+ return ents_by_name if @data.nil?
49
+ newEnt = @sb.isNewDirEnt?
50
+ p = 0
51
+ loop do
52
+ break if p > @data.length - 4
53
+ break if @data[p, 4].nil?
54
+ de = DirectoryEntry.new(@data[p..-1], newEnt)
55
+ raise "Ext4::Directory.globEntriesByLinkedList: DirectoryEntry length cannot be 0" if de.len == 0
56
+ ents_by_name[de.name] ||= []
57
+ ents_by_name[de.name] << de
58
+ p += de.len
59
+ end
60
+ ents_by_name
61
+ end
62
+
63
+ #
64
+ # If the inode has the IF_HASH_INDEX bit set,
65
+ # then the first directory block is to be interpreted as the root of an HTree index.
66
+ def globEntriesByHashTree
67
+ ents_by_name = {}
68
+ offset = 0
69
+ # Chomp fake '.' and '..' directories first
70
+ 2.times do
71
+ de = DirectoryEntry.new(@data[offset..-1], @sb.isNewDirEnt?)
72
+ ents_by_name[de.name] ||= []
73
+ ents_by_name[de.name] << de
74
+ offset += 12
75
+ end
76
+
77
+ $log.info("Ext4::Directory.globEntriesByHashTree (inode=#{@inodeNum}) >>\n#{@data[0, 256].hex_dump}")
78
+ header = HashTreeHeader.new(@data[offset..-1])
79
+ $log.info("Ext4::Directory.globEntriesByHashTree --\n#{header.dump}")
80
+ $log.info("Ext4::Directory.globEntriesByHashTree (inode=#{@inodeNum}) <<#{ents_by_name.inspect}")
81
+ offset += header.length
82
+ root = HashTreeEntry.new(@data[offset..-1], true)
83
+ $log.info("Ext4::Directory.globEntriesByHashTree --\n#{root.dump}")
84
+ ents_by_name
85
+ end
86
+ end # class
87
+ end # module
@@ -0,0 +1,77 @@
1
+ require 'binary_struct'
2
+
3
+ module Ext4
4
+ # ////////////////////////////////////////////////////////////////////////////
5
+ # // Data definitions.
6
+
7
+ DIR_ENTRY_ORIGINAL = BinaryStruct.new([
8
+ 'L', 'inode_val', # Inode address of metadata.
9
+ 'S', 'entry_len', # Length of entry.
10
+ 'S', 'name_len', # Length of name.
11
+ ])
12
+ # Here follows the name in ASCII.
13
+ SIZEOF_DIR_ENTRY_ORIGINAL = DIR_ENTRY_ORIGINAL.size
14
+
15
+ DIR_ENTRY_NEW = BinaryStruct.new([
16
+ 'L', 'inode_val', # Inode address of metadata.
17
+ 'S', 'entry_len', # Length of entry.
18
+ 'C', 'name_len', # Length of name.
19
+ 'C', 'file_type', # Type of file (see FT_ below).
20
+ ])
21
+ # Here follows the name in ASCII.
22
+ SIZEOF_DIR_ENTRY_NEW = DIR_ENTRY_NEW.size
23
+
24
+ class DirectoryEntry
25
+ FT_UNKNOWN = 0
26
+ FT_FILE = 1
27
+ FT_DIRECTORY = 2
28
+ FT_CHAR = 3
29
+ FT_BLOCK = 4
30
+ FT_FIFO = 5
31
+ FT_SOCKET = 6
32
+ FT_SYM_LNK = 7
33
+
34
+ attr_reader :inode, :len, :name
35
+ attr_accessor :fileType
36
+
37
+ def initialize(data, new_entry = true)
38
+ raise "Ext4::DirectoryEntry.initialize: Nil directory entry data" if data.nil?
39
+ @isNew = new_entry
40
+ siz = @isNew ? SIZEOF_DIR_ENTRY_NEW : SIZEOF_DIR_ENTRY_ORIGINAL
41
+ @de = @isNew ? DIR_ENTRY_NEW.decode(data[0..siz]) : DIR_ENTRY_ORIGINAL.decode(data[0..siz])
42
+ # If there's a name get it.
43
+ @name = data[siz, @de['name_len']] if @de['name_len'] != 0
44
+ @inode = @de['inode_val']
45
+ @len = @de['entry_len']
46
+ @fileType = @de['file_type'] if @isNew
47
+ end
48
+
49
+ def isDir?
50
+ @fileType == FT_DIRECTORY
51
+ end
52
+
53
+ def isSymLink?
54
+ @fileType == FT_SYM_LNK
55
+ end
56
+
57
+ def fileTypeString
58
+ return "UNKNOWN" if @fileType == FT_UNKNOWN
59
+ return "FILE" if @fileType == FT_FILE
60
+ return "DIRECTORY" if @fileType == FT_DIRECTORY
61
+ return "CHAR" if @fileType == FT_CHAR
62
+ return "BLOCK" if @fileType == FT_BLOCK
63
+ return "FIFO" if @fileType == FT_FIFO
64
+ return "SOCKET" if @fileType == FT_SOCKET
65
+ return "SYMLINK" if @fileType == FT_SYM_LNK
66
+ end
67
+
68
+ def dump
69
+ out = "\#<#{self.class}:0x#{'%08x' % object_id}>\n"
70
+ out += "Inode : #{inode}\n"
71
+ out += "Len : #{len}\n"
72
+ out += "Name len: 0x#{'%04x' % @de['name_len']}\n"
73
+ out += "Type : #{fileTypeString}\n" if @isNew
74
+ out += "Name : #{name}\n"
75
+ end
76
+ end # class
77
+ end # module