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,46 @@
1
+ require 'fs/xfs/directory'
2
+ require 'fs/xfs/directory2_data_header'
3
+ require 'fs/xfs/directory3_data_header'
4
+ require 'fs/xfs/superblock'
5
+
6
+ module XFS
7
+ DIRECTORY_DATA_FREE = BinaryStruct.new([
8
+ 'S>', 'offset', # start of freespace
9
+ 'S>', 'length', # length of freespace
10
+ ])
11
+ SIZEOF_DIRECTORY_DATA_FREE = DIRECTORY_DATA_FREE.size
12
+
13
+ class DirectoryDataHeader
14
+ XFS_DIR2_DATA_FD_COUNT = 3
15
+
16
+ attr_reader :data_header, :header_end, :version_3
17
+
18
+ def decode_directory_header(data, header)
19
+ template = header.template
20
+ @data_header = template.decode(data)
21
+ header.magic_numbers.each { |magic_number| return template.size if @data_header['magic'] == magic_number }
22
+ raise "XFS::DirectoryDataHeader: Invalid Magic Number #{@data_header['magic']}"
23
+ end
24
+
25
+ def initialize(data, sb)
26
+ @sb = sb
27
+ if @sb.version_has_crc?
28
+ version_header = Directory3DataHeader.new
29
+ else
30
+ version_header = Directory2DataHeader.new
31
+ end
32
+ @version_3 = version_header.version_3
33
+ header_size = decode_directory_header(data, version_header)
34
+ free_offset = header_size
35
+ @data_free = []
36
+ @free_end = 0
37
+ (1..XFS_DIR2_DATA_FD_COUNT).each do |i|
38
+ @free_end = header_size + SIZEOF_DIRECTORY_DATA_FREE * i
39
+ @data_free[i] = DIRECTORY_DATA_FREE.decode(data[free_offset..@free_end])
40
+ free_offset = @free_end
41
+ end
42
+ @header_end = @free_end
43
+ @header_end += version_header.pad
44
+ end
45
+ end # class DirectoryDataHeader
46
+ end # module XFS
@@ -0,0 +1,106 @@
1
+ require 'binary_struct'
2
+
3
+ module XFS
4
+ # ////////////////////////////////////////////////////////////////////////////
5
+ # // Data definitions.
6
+ #
7
+ # Active entry in a data block.
8
+ # Aligned to 8 bytes. A variable length name field follows the length.
9
+ # After the name there is a 2 byte tag field.
10
+ # For dir3 structures, there is a 1 byte file type field between the name
11
+ # and the tag. It is packed hard against the end of the name so any padding
12
+ # for rounding is between the file type and the tag.
13
+ DIRECTORY2_DATA_ENTRY = BinaryStruct.new([
14
+ 'Q>', 'inumber', # inode number
15
+ 'C', 'name_len', # name length
16
+ ])
17
+ SIZEOF_DIRECTORY2_DATA_ENTRY = DIRECTORY2_DATA_ENTRY.size
18
+
19
+ DIRECTORY2_DATA_TAG = BinaryStruct.new([
20
+ 'S>', 'tag', # tag
21
+ ])
22
+ SIZEOF_DIRECTORY2_DATA_TAG = DIRECTORY2_DATA_TAG.size
23
+
24
+ DIRECTORY2_UNUSED_ENTRY = BinaryStruct.new([
25
+ 'S>', 'freetag', # 0xFFFF if unused
26
+ 'S>', 'length', # length of this free entry
27
+ ])
28
+ SIZEOF_DIRECTORY2_UNUSED_ENTRY = DIRECTORY2_UNUSED_ENTRY.size
29
+
30
+ class DirectoryEntry
31
+ XFS_DIR2_DATA_FREE_TAG = 0xffff
32
+ XFS_DIR2_DATA_ALIGN_LOG = 3
33
+ XFS_DIR2_DATA_ALIGN = 1 << XFS_DIR2_DATA_ALIGN_LOG
34
+ XFS_DIR2_SPACE_SIZE = 1 << (32 + XFS_DIR2_DATA_ALIGN_LOG)
35
+ XFS_DIR2_LEAF_SPACE = 1
36
+ XFS_DIR2_LEAF_OFFSET = XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE
37
+
38
+ # 16 is the smallest directory entry size but hard-coding is not nice
39
+ SIZEOF_SMALLEST_DIRECTORY_ENTRY = 16
40
+
41
+ def symlink?
42
+ @file_type == Inode::FT_SYM_LNK
43
+ end
44
+
45
+ def directory?
46
+ @file_type == Inode::FT_DIRECTORY
47
+ end
48
+
49
+ def file?
50
+ @file_type == Inode::FT_FILE
51
+ end
52
+
53
+ def device?
54
+ @file_type == Inode::FT_CHAR || @file_type == Inode::FT_BLOCK ||
55
+ @file_type == Inode::FT_FIFO || @file_type == Inode::FT_SOCKET
56
+ end
57
+
58
+ def round_up(num, base)
59
+ return num if num % base == 0
60
+ num + base - (num % base)
61
+ end
62
+
63
+ def dir_data_entsize(n, version_3_header)
64
+ if version_3_header
65
+ return round_up(SIZEOF_DIRECTORY2_DATA_ENTRY + n + SIZEOF_DIRECTORY2_DATA_TAG + 1, XFS_DIR2_DATA_ALIGN)
66
+ end
67
+ round_up(SIZEOF_DIRECTORY2_DATA_ENTRY + n + SIZEOF_DIRECTORY2_DATA_TAG, XFS_DIR2_DATA_ALIGN)
68
+ end
69
+
70
+ attr_reader :inode, :length, :name, :tag, :name_length
71
+ attr_accessor :file_type
72
+
73
+ def initialize(data, version_3_header)
74
+ raise "XFS::DirectoryEntry.initialize: Nil directory entry data" if data.nil?
75
+ size = SIZEOF_DIRECTORY2_UNUSED_ENTRY
76
+ start = @length = @name_length = 0
77
+ unused_entry = DIRECTORY2_UNUSED_ENTRY.decode(data[start..size])
78
+ if unused_entry['freetag'] == XFS_DIR2_DATA_FREE_TAG
79
+ @length = unused_entry['length']
80
+ @name = ""
81
+ return
82
+ end
83
+ free_size = start
84
+ size = SIZEOF_DIRECTORY2_DATA_ENTRY
85
+ @de = DIRECTORY2_DATA_ENTRY.decode(data[start..(start + size)])
86
+ @inode = @de['inumber']
87
+ @name_length = @de['name_len']
88
+ start += size
89
+ # If there's a name get it.
90
+ unless @name_length == 0
91
+ @name = data[start, @name_length]
92
+ @tag = DIRECTORY2_DATA_TAG.decode(data[start])
93
+ @length = free_size + dir_data_entsize(@name_length, version_3_header)
94
+ end
95
+ raise "XFS::Directory: DirectoryEntry length cannot be 0" if @length == 0
96
+ end
97
+
98
+ def dump
99
+ out = "\#<#{self.class}:0x#{format('%08x', object_id)}>\n"
100
+ out += "Inode : #{inode}\n"
101
+ out += "Len : #{length}\n"
102
+ out += "Name : #{name}\n"
103
+ out
104
+ end
105
+ end # class
106
+ end # module
@@ -0,0 +1,532 @@
1
+ require 'binary_struct'
2
+ require 'memory_buffer'
3
+ require 'more_core_extensions/all'
4
+ require 'fs/xfs/superblock'
5
+ require 'fs/xfs/bmap_btree_record'
6
+ require 'fs/xfs/bmap_btree_block'
7
+ require 'fs/xfs/bmap_btree_root_node'
8
+
9
+ module XFS
10
+ TIMESTAMP = BinaryStruct.new([
11
+ 'I', 'seconds', # timestamp seconds
12
+ 'I', 'nanoseconds', # timestamp nanoseconds
13
+ ])
14
+
15
+ INODE = BinaryStruct.new([
16
+ 'S>', 'magic', # Inode Magic Number
17
+ 'S>', 'file_mode', # Mode and Type of file
18
+ 'C', 'version', # Inode Version
19
+ 'C', 'format', # Format of Data Fork Data
20
+ 'S>', 'old_num_links', # Old Number of Links to File
21
+ 'I>', 'uid', # Owner's User Id
22
+ 'I>', 'gid', # Owner's Group Id
23
+ 'I>', 'num_links', # Number of Links to File
24
+ 'S>', 'projid_low', # Lower Part of Owner's Project Id
25
+ 'S>', 'projid_high', # Higher Part of Owner's Project Id
26
+ 'a6', 'pad', # Unused, Zeroed Space
27
+ 'S>', 'flush_iterator', # Incremented on Flush
28
+ 'I>', 'atime_secs', # time last accessed seconds
29
+ 'I>', 'atime_nsecs', # time last accessed nanoseconds
30
+ 'I>', 'mtime_secs', # time last modified seconds
31
+ 'I>', 'mtime_nsecs', # time last modified nanoseconds
32
+ 'I>', 'ctime_secs', # time created / inode modified seconds
33
+ 'I>', 'ctime_nsecs', # time created / inode modified nanoseconds
34
+ 'Q>', 'size', # number of bytes in file
35
+ 'Q>', 'nblocks', # Number of direct & btree blocks used
36
+ 'I>', 'extent_size', # Basic/Minimum extent size for file
37
+ 'I>', 'num_extents', # Number of extents in data fork
38
+ 'S>', 'attr_num_extents', # Number of extents in attribute fork
39
+ 'C', 'attr_fork_offset', # Attribute Fork Offset, <<3 for 64b align
40
+ 'c', 'attr_fork_format', # Format of Attribute Fork's Data
41
+ 'I>', 'dmig_event_mask', # DMIG event mask
42
+ 'S>', 'dmig_state_info', # DMIG state info
43
+ 'S>', 'flags', # random flags, XFS_DIFLAG_...
44
+ 'I>', 'gen_num', # generation number
45
+ 'I>', 'next_unlinked', # agi unlinked list ptr
46
+ ])
47
+
48
+ EXTENDED_INODE = BinaryStruct.new([
49
+ 'S>', 'magic', # Inode Magic Number
50
+ 'S>', 'file_mode', # Mode and Type of file
51
+ 'C', 'version', # Inode Version
52
+ 'C', 'format', # Format of Data Fork Data
53
+ 'S>', 'old_num_links', # Old Number of Links to File
54
+ 'I>', 'uid', # Owner's User Id
55
+ 'I>', 'gid', # Owner's Group Id
56
+ 'I>', 'num_links', # Number of Links to File
57
+ 'S>', 'projid_low', # Lower Part of Owner's Project Id
58
+ 'S>', 'projid_high', # Higher Part of Owner's Project Id
59
+ 'a6', 'pad', # Unused, Zeroed Space
60
+ 'S>', 'flush_iterator', # Incremented on Flush
61
+ 'I>', 'atime_secs', # time last accessed seconds
62
+ 'I>', 'atime_nsecs', # time last accessed nanoseconds
63
+ 'I>', 'mtime_secs', # time last modified seconds
64
+ 'I>', 'mtime_nsecs', # time last modified nanoseconds
65
+ 'I>', 'ctime_secs', # time created / inode modified seconds
66
+ 'I>', 'ctime_nsecs', # time created / inode modified nanoseconds
67
+ 'Q>', 'size', # number of bytes in file
68
+ 'Q>', 'nblocks', # Number of direct & btree blocks used
69
+ 'I>', 'extent_size', # Basic/Minimum extent size for file
70
+ 'I>', 'num_extents', # Number of extents in data fork
71
+ 'S>', 'attr_num_extents', # Number of extents in attribute fork
72
+ 'C', 'attr_fork_offset', # Attribute Fork Offset, <<3 for 64b align
73
+ 'c', 'attr_fork_format', # Format of Attribute Fork's Data
74
+ 'I>', 'dmig_event_mask', # DMIG event mask
75
+ 'S>', 'dmig_state_info', # DMIG state info
76
+ 'S>', 'flags', # random flags, XFS_DIFLAG_...
77
+ 'I>', 'gen_num', # generation number
78
+ 'I>', 'next_unlinked', # agi unlinked list ptr
79
+ 'I>', 'crc', # CRC of the inode
80
+ 'Q>', 'change_count', # number of attribute changes
81
+ 'Q>', 'lsn', # flush sequence
82
+ 'Q>', 'flags2', # more random flags
83
+ 'a16', 'pad2', # more padding for future expansion
84
+ 'I>', 'crtime_secs', # time created seconds
85
+ 'I>', 'crtime_nsecs', # time created nanoseconds
86
+ 'Q>', 'inode_number', # inode number
87
+ 'a16', 'uuid', # UUID of the filesystem
88
+ ])
89
+
90
+ SIZEOF_INODE = INODE.size
91
+ SIZEOF_EXTENDED_INODE = EXTENDED_INODE.size
92
+
93
+ # ////////////////////////////////////////////////////////////////////////////
94
+ # // Class.
95
+
96
+ class Inode
97
+ MAX_READ = 4_294_967_296
98
+ XFS_DINODE_MAGIC = 0x494e
99
+
100
+ # Bits 0 to 8 of file mode.
101
+ PF_O_EXECUTE = 0x0001 # owner execute
102
+ PF_O_WRITE = 0x0002 # owner write
103
+ PF_O_READ = 0x0004 # owner read
104
+ PF_G_EXECUTE = 0x0008 # group execute
105
+ PF_G_WRITE = 0x0010 # group write
106
+ PF_G_READ = 0x0020 # group read
107
+ PF_U_EXECUTE = 0x0040 # user execute
108
+ PF_U_WRITE = 0x0080 # user write
109
+ PF_U_READ = 0x0100 # user read
110
+
111
+ # For accessor convenience.
112
+ MSK_PERM_OWNER = (PF_O_EXECUTE | PF_O_WRITE | PF_O_READ)
113
+ MSK_PERM_GROUP = (PF_G_EXECUTE | PF_G_WRITE | PF_G_READ)
114
+ MSK_PERM_USER = (PF_U_EXECUTE | PF_U_WRITE | PF_U_READ)
115
+
116
+ # Bits 12 to 15 of file mode.
117
+ FM_FIFO = 0x1000 # fifo device (pipe)
118
+ FM_CHAR = 0x2000 # char device
119
+ FM_DIRECTORY = 0x4000 # directory
120
+ FM_BLOCK_DEV = 0x6000 # block device
121
+ FM_FILE = 0x8000 # regular file
122
+ FM_SYM_LNK = 0xa000 # symbolic link
123
+ FM_SOCKET = 0xc000 # socket device
124
+
125
+ # Values our callers may know
126
+ FT_UNKNOWN = 0
127
+ FT_FILE = 1
128
+ FT_DIRECTORY = 2
129
+ FT_CHAR = 3
130
+ FT_BLOCK = 4
131
+ FT_FIFO = 5
132
+ FT_SOCKET = 6
133
+ FT_SYM_LNK = 7
134
+
135
+ FILE_MODE_TO_FILE_TYPE_LOOKUP_TABLE = {
136
+ FM_FIFO => FT_FIFO,
137
+ FM_CHAR => FT_CHAR,
138
+ FM_DIRECTORY => FT_DIRECTORY,
139
+ FM_BLOCK_DEV => FT_BLOCK,
140
+ FM_FILE => FT_FILE,
141
+ FM_SYM_LNK => FT_SYM_LNK,
142
+ FM_SOCKET => FT_SOCKET
143
+ }
144
+
145
+ # For accessor convenience.
146
+ MSK_FILE_MODE = 0xf000
147
+ MSK_IS_DEV = (FM_FIFO | FM_CHAR | FM_BLOCK_DEV | FM_SOCKET)
148
+
149
+ # For Data Fork Data Format
150
+ XFS_DINODE_FMT_DEV = 0 # Device Type
151
+ XFS_DINODE_FMT_LOCAL = 1 # Bulk Data
152
+ XFS_DINODE_FMT_EXTENTS = 2 # xfs_bmbt_rec
153
+ XFS_DINODE_FMT_BTREE = 3 # xfs_bmdr_block
154
+ XFS_DINODE_FMT_UUID = 4 # uuid
155
+
156
+ XFS_DATA_FORK = 0
157
+ XFS_ATTR_FORK = 1
158
+
159
+ def dinode_good_version(version)
160
+ version >= 1 && version <= 3
161
+ end
162
+
163
+ def dinode_size(version)
164
+ if version == 3
165
+ SIZEOF_EXTENDED_INODE
166
+ else
167
+ SIZEOF_INODE
168
+ end
169
+ end
170
+
171
+ def dfork_q
172
+ @in['attr_fork_offset'] != 0
173
+ end
174
+
175
+ def dfork_boff
176
+ @in['attr_fork_offset'] << 3
177
+ end
178
+
179
+ def dfork_dsize
180
+ dfork_q ? dfork_boff : litino
181
+ end
182
+
183
+ def dfork_asize
184
+ dfork_q ? litino - dfork_boff : 0
185
+ end
186
+
187
+ def dfork_size(which_fork)
188
+ which_fork == XFS_DATA_FORK ? dfork_dsize : dfork_asize
189
+ end
190
+
191
+ def dfork_dptr
192
+ start = @offset + dinode_size(@version)
193
+ @disk_buffer[start..start + @sb.inode_size]
194
+ end
195
+
196
+ def dfork_aptr
197
+ dfork_dptr + dfork_boff
198
+ end
199
+
200
+ def litino
201
+ @sb.inode_size - dinode_size(@version)
202
+ end
203
+
204
+ attr_reader :mode, :flags, :length, :disk_buffer, :version, :inode_number, :sb, :data_method, :in
205
+ attr_accessor :data_fork, :attribute_fork
206
+
207
+ def valid_inode?
208
+ $log.error "XFS::Inode: Bad Magic # inode #{@inode_number}" unless @in['magic'] == XFS_DINODE_MAGIC
209
+ raise "XFS::Inode: Invalid Magic Number for inode #{@inode_number}" unless @in['magic'] == XFS_DINODE_MAGIC
210
+ raise "XFS::Inode: Invalid Inode Version for inode #{@inode_number}" unless dinode_good_version(@in['version'])
211
+ true
212
+ end
213
+
214
+ def inode_format
215
+ if @format == XFS_DINODE_FMT_LOCAL
216
+ data_method = :local
217
+ elsif @format == XFS_DINODE_FMT_EXTENTS
218
+ data_method = :extents
219
+ else
220
+ data_method = :btree
221
+ end
222
+ data_method
223
+ end
224
+
225
+ def initialize(buffer, offset, superblock, inode_number)
226
+ raise "XFS::Inode: Nil buffer for inode #{inode_number}" if buffer.nil?
227
+ @sb = superblock
228
+ @inode_number = inode_number
229
+ @offset = offset
230
+ if @sb.inode_size < SIZEOF_EXTENDED_INODE
231
+ @in = INODE.decode(buffer[offset..(offset + SIZEOF_INODE)])
232
+ else
233
+ @in = EXTENDED_INODE.decode(buffer[offset..(offset + SIZEOF_EXTENDED_INODE)])
234
+ end
235
+ valid_inode? || return
236
+ rewind
237
+ @disk_buffer = buffer
238
+ @mode = @in['file_mode']
239
+ @flags = @in['flags']
240
+ @version = @in['version']
241
+ @length = @in['size']
242
+ @format = @in['format']
243
+ @block_offset = 1
244
+ @data_method = inode_format
245
+ end
246
+
247
+ # ////////////////////////////////////////////////////////////////////////////
248
+ # // Method for data access
249
+ def rewind
250
+ @pos = 0
251
+ end
252
+
253
+ def seek(offset, method = IO::SEEK_SET)
254
+ @pos = case method
255
+ when IO::SEEK_SET then offset
256
+ when IO::SEEK_CUR then @pos + offset
257
+ when IO::SEEK_END then @length - offset
258
+ end
259
+ @pos = 0 if @pos < 0
260
+ @pos = @length if @pos > @length
261
+ @pos
262
+ end
263
+
264
+ def read(nbytes = @length)
265
+ raise "XFS::Inode.read: Can't read 4G or more at a time (use a smaller read size)" if nbytes >= MAX_READ
266
+ return nil if @pos >= @length
267
+
268
+ nbytes = @length - @pos if @pos + nbytes > @length
269
+ return read_short_form(nbytes) if @data_method == :local
270
+
271
+ # get data.
272
+ start_block, start_byte, nblocks = pos_to_block(@pos, nbytes)
273
+ out = read_blocks(start_block, nblocks)
274
+ @pos += nbytes
275
+ out[start_byte, nbytes]
276
+ end
277
+
278
+ def write(buf, _len = buf.length)
279
+ raise "XFS::Inode.write: Write functionality is not yet supported on XFS."
280
+ end
281
+
282
+ # ////////////////////////////////////////////////////////////////////////////
283
+ # // Class helpers & accessors.
284
+
285
+ def directory?
286
+ mode_set?(FM_DIRECTORY)
287
+ end
288
+
289
+ def file?
290
+ mode_set?(FM_FILE)
291
+ end
292
+
293
+ def device?
294
+ (@mode & MSK_IS_DEV) > 0
295
+ end
296
+
297
+ def symlink?
298
+ mode_set?(FM_SYM_LNK)
299
+ end
300
+
301
+ def access_time
302
+ @access_time ||= Time.at(@in['atime_secs'])
303
+ end
304
+
305
+ def create_time
306
+ @create_time ||= Time.at(@in['ctime_secs'])
307
+ end
308
+
309
+ def modification_time
310
+ @modification_time ||= Time.at(@in['mtime_secs'])
311
+ end
312
+
313
+ def permissions
314
+ @permissions ||= @in['file_mode'] & (MSK_PERM_OWNER | MSK_PERM_GROUP | MSK_PERM_USER)
315
+ end
316
+
317
+ def owner_permissions
318
+ @owner_permissions ||= @in['file_mode'] & MSK_PERM_OWNER
319
+ end
320
+
321
+ def group_permissions
322
+ @group_permissions ||= @in['file_mode'] & MSK_PERM_GROUP
323
+ end
324
+
325
+ def user_permissions
326
+ @user_permissions ||= @in['file_mode'] & MSK_PERM_USER
327
+ end
328
+
329
+ # ////////////////////////////////////////////////////////////////////////////
330
+ # // Utility functions.
331
+
332
+ def file_mode_to_file_type
333
+ FILE_MODE_TO_FILE_TYPE_LOOKUP_TABLE[@mode & MSK_FILE_MODE]
334
+ end
335
+
336
+ def mode_set?(bit)
337
+ (@mode & bit) == bit
338
+ end
339
+
340
+ def flag_set?(bit)
341
+ (@flags & bit) == bit
342
+ end
343
+
344
+ def dump
345
+ out = "\#<#{self.class}:0x#{format('%08x', object_id)}>\n"
346
+ out += "Inode Number : #{@inode_number}\n"
347
+ out += "File mode : 0x#{format('%04x', @in['file_mode'])}\n"
348
+ out += "UID : #{@in['uid']}\n"
349
+ out += "Size : #{@in['size']}\n"
350
+ out += "ATime Secs/NSecs: #{@in['atime_secs']}/#{@in['atime_nsecs']}\n"
351
+ out += "CTime Secs/NSecs: #{@in['ctime_secs']}/#{@in['ctime_nsecs']}\n"
352
+ out += "MTime Secs/NSecs: #{@in['mtime_secs']}/#{@in['mtime_nsecs']}\n"
353
+ out += "GID : #{@in['gid']}\n"
354
+ out += "Link count : #{@in['num_links']}\n"
355
+ out += "Old Link cnt : #{@in['old_num_links']}\n"
356
+ out += "Block count : #{@in['nblocks']}\n"
357
+ out += "Extent size : #{@in['extent_size']}\n"
358
+ out += "Num extents : #{@in['num_extents']}\n"
359
+ out += "Data Fork Fmt : #{@data_method}\n"
360
+ out += "Attr Fork Exts: #{@in['attr_num_extents']}\n"
361
+ out += "Attr Fork Off : #{@in['attr_fork_offset']}\n"
362
+ out += "Attr Fork Fmt : #{@in['attr_fork_format']}\n"
363
+ out += "Flags : #{format('%04x', @in['flags'])}\n"
364
+ out += "Version : #{@in['version']}\n"
365
+ out += "Flush Iter : #{@in['flush_iterator']}\n"
366
+ out += "Generation : #{@in['gen_num']}\n"
367
+ out
368
+ end
369
+
370
+ private
371
+
372
+ def read_short_form(len)
373
+ unless self.directory? || self.symlink?
374
+ raise "XFS::Inode.read: Invalid ShortForm Directory for inode #{@inode_number}"
375
+ end
376
+ if @pos + len > @sb.inode_size
377
+ raise "XFS::Inode.read_short_form: Invalid length #{len} for Shortform Inode #{@inode_number}"
378
+ end
379
+ fork = dfork_dptr
380
+ data = fork[@pos..(@pos + len - 1)]
381
+ @pos += len
382
+ data
383
+ end
384
+
385
+ # NB: pos is 0-based, while len is 1-based
386
+ def pos_to_block(pos, len)
387
+ start_block, start_byte = pos.divmod(@sb.block_size)
388
+ end_block, _end_byte = (pos + len - 1).divmod(@sb.block_size)
389
+ nblocks = end_block - start_block + 1
390
+ return start_block, start_byte, nblocks
391
+ end
392
+
393
+ def read_blocks(startBlock, nblocks = 1)
394
+ out = MemoryBuffer.create(nblocks * @sb.block_size)
395
+ dbp_len = data_block_pointers.length
396
+ raise "XFS::Inode.read_blocks: startBlock=<#{startBlock}> is greater than #{dbp_len}" if startBlock > dbp_len - 1
397
+ 1.upto(nblocks) do |i|
398
+ block_index = startBlock + i - 1
399
+ dbp_len = data_block_pointers.length
400
+ if block_index > dbp_len - 1
401
+ raise "XFS::Inode.read_blocks: block_index=<#{block_index}> is greater than #{dbp_len}"
402
+ end
403
+ block = data_block_pointers[block_index]
404
+ data = @sb.get_block(block)
405
+ out[(i - 1) * @sb.block_size, @sb.block_size] = data
406
+ end
407
+ out
408
+ end
409
+
410
+ #
411
+ # This method is used for both extents and BTree leaf nodes
412
+ #
413
+ def bmap_btree_record_to_block_pointers(record, block_pointers_length)
414
+ block_pointers = []
415
+ # Fill in the missing blocks with 0-blocks
416
+ block_pointers << 0 while (block_pointers_length + block_pointers.length) < record.start_offset
417
+ 1.upto(record.block_count) { |i| block_pointers << record.start_block + i - 1 }
418
+ @block_offset += record.block_count
419
+ block_pointers
420
+ end
421
+
422
+ def expected_blocks
423
+ @expected_blocks ||= begin
424
+ quotient, remainder = @length.divmod(@sb.block_size)
425
+ quotient + ((remainder > 0) ? 1 : 0)
426
+ end
427
+ end
428
+
429
+ def block_pointers_via_bmap_btree_block_node(btree_block, data, block_pointers_length)
430
+ block_pointers = []
431
+ return block_pointers unless (block_pointers_length + block_pointers.length) < expected_blocks
432
+ maximum_records = (@sb.block_size - btree_block.header_size) / SIZEOF_BMAP_BTREE_ROOT_NODE_ENTRIES
433
+ return if maximum_records == 0
434
+ offset_size = SIZEOF_BMAP_BTREE_ROOT_NODE_OFFSET
435
+ block_size = SIZEOF_BMAP_BTREE_ROOT_NODE_BLOCK
436
+ 1.upto(btree_block.number_records) do |i|
437
+ start = maximum_records * offset_size + (i - 1) * block_size
438
+ block = (data[start..start + block_size]).unpack('Q>').shift
439
+ agbno = @sb.fsb_to_agbno(block)
440
+ agno = @sb.fsb_to_agno(block)
441
+ real_block = sb.agbno_to_real_block(agno, agbno)
442
+ block_pointers.concat block_pointers_via_bmap_btree_block(real_block,
443
+ block_pointers.length + block_pointers_length)
444
+ end
445
+ block_pointers
446
+ end
447
+
448
+ def block_pointers_via_bmap_btree_block_leaf(data, block_pointers_length, number_records)
449
+ block_pointers = []
450
+ return block_pointers unless (block_pointers_length + block_pointers.length) < expected_blocks
451
+ 1.upto(number_records) do |i|
452
+ bmap_btree_record = BmapBTreeRecord.new(data[(SIZEOF_BMAP_BTREE_REC * (i - 1))..(SIZEOF_BMAP_BTREE_REC * i)],
453
+ @sb)
454
+ break if @sb.fsb_to_b(bmap_btree_record.start_offset) >= DirectoryEntry::XFS_DIR2_LEAF_OFFSET
455
+ if (block_pointers_length + block_pointers.length) < expected_blocks
456
+ block_pointers.concat bmap_btree_record_to_block_pointers(bmap_btree_record,
457
+ block_pointers.length + block_pointers_length)
458
+ end
459
+ end
460
+ block_pointers
461
+ end
462
+
463
+ def block_pointers_via_bmap_btree_block(block_number, block_pointers_length)
464
+ block_pointers = []
465
+ if block_pointers_length < expected_blocks
466
+ data = @sb.get_block(block_number)
467
+ btree_block = BmapBTreeBlock.new(data, @sb)
468
+ if btree_block.level == 0
469
+ block_pointers.concat block_pointers_via_bmap_btree_block_leaf(data[btree_block.header_size..-1],
470
+ block_pointers.length + block_pointers_length,
471
+ btree_block.number_records)
472
+ else
473
+ block_pointers.concat block_pointers_via_bmap_btree_block_node(btree_block, data[btree_block.header_size..-1],
474
+ block_pointers.length + block_pointers_length)
475
+ end
476
+ end
477
+ block_pointers
478
+ end
479
+
480
+ def block_pointers_via_btree
481
+ block_pointers = []
482
+ fork = dfork_dptr
483
+ root_node = BmapBTreeRootNode.new(fork, self)
484
+ root_node.blocks.each do |block_number|
485
+ block_pointers.concat block_pointers_via_bmap_btree_block(block_number, block_pointers.length)
486
+ end
487
+ block_pointers
488
+ end
489
+
490
+ def extent_to_block_pointers(extent, bplen)
491
+ block_pointers = []
492
+ # Fill in the missing blocks with 0-blocks
493
+ block_pointers << 0 while (bplen + block_pointers.length) < extent.start_offset
494
+ 1.upto(extent.block_count) { |i| block_pointers << extent.start_block + i - 1 }
495
+ @block_offset += extent.block_count
496
+ block_pointers
497
+ end
498
+
499
+ def block_pointers_via_extents
500
+ block_pointers = []
501
+ fork = dfork_dptr
502
+ extent_count = @in['num_extents']
503
+ return block_pointers if extent_count == 0
504
+ 1.upto(extent_count) do |i|
505
+ bmap_btree_record = BmapBTreeRecord.new(fork[(SIZEOF_BMAP_BTREE_REC * (i - 1))..(SIZEOF_BMAP_BTREE_REC * i)],
506
+ @sb)
507
+ #
508
+ # The following test is to weed out Leaf Metadata Blocks that have no directory content
509
+ #
510
+ break if @sb.fsb_to_b(bmap_btree_record.start_offset) >= DirectoryEntry::XFS_DIR2_LEAF_OFFSET
511
+ block_pointers.concat extent_to_block_pointers(bmap_btree_record, block_pointers.length)
512
+ end
513
+ block_pointers
514
+ end
515
+
516
+ def read_block_pointers(block)
517
+ @sb.get_block(block).unpack('L*')
518
+ end
519
+
520
+ def data_block_pointers
521
+ if @data_block_pointers.nil?
522
+ @data_block_pointers = block_pointers_via_extents if @data_method == :extents
523
+ @data_block_pointers = block_pointers_via_btree if @data_method == :btree
524
+ dbp_len = @data_block_pointers.length
525
+ if expected_blocks != dbp_len
526
+ raise "XFS::Inode.block_pointers: Block Pointers <#{dbp_len}> does not match Expected <#{expected_blocks}>"
527
+ end
528
+ end
529
+ @data_block_pointers
530
+ end
531
+ end # Class Inode
532
+ end # Module XFS