/src/indirect_blocks.cc

http://ext3grep.googlecode.com/ · C++ · 395 lines · 302 code · 24 blank · 69 comment · 83 complexity · bafe57e5919e6ca6f06c24b261d2d573 MD5 · raw file

  1. // ext3grep -- An ext3 file system investigation and undelete tool
  2. //
  3. //! @file indirect_blocks.cc Implementation dealing with (double/tripple) indirect blocks.
  4. //
  5. // Copyright (C) 2008, by
  6. //
  7. // Carlo Wood, Run on IRC <carlo@alinoe.com>
  8. // RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
  9. // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
  10. //
  11. // Stanislaw T. Findeisen <sf181257 at students mimuw edu pl>
  12. //
  13. // This program is free software: you can redistribute it and/or modify
  14. // it under the terms of the GNU General Public License as published by
  15. // the Free Software Foundation, either version 2 of the License, or
  16. // (at your option) any later version.
  17. //
  18. // This program is distributed in the hope that it will be useful,
  19. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. // GNU General Public License for more details.
  22. //
  23. // You should have received a copy of the GNU General Public License
  24. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. //
  26. // ChangeLog
  27. //
  28. // 2008-07-07 STF
  29. // * (is_indirect_block): Add. Heuristic detection of indirect
  30. // blocks based solely on their content.
  31. //
  32. // 2008-07-10 Carlo Wood <carlo@alinoe.com>
  33. // * (is_indirect_block):
  34. // -Add SKIPZEROES.
  35. // - Call is_data_block_number.
  36. // - Return false if there are only ZEROES.
  37. // - Bug fix: Abort loops when reaching the ZEROES.
  38. // - Only use an array on the stack if the block numbers are less than the
  39. // size of one group apart (instead of allocating and clearing 32 MB on
  40. // the stack every time).
  41. // - Use return value of std::set<>::insert instead of calling std::set<>::count.
  42. //
  43. // 2008-10-13 Carlo Wood <carlo@alinoe.com>
  44. // * (is_indirect_block):
  45. // - SKIPZEROES must be 0: zeroes a completely legal in any indirect block.
  46. #ifndef USE_PCH
  47. #include "sys.h"
  48. #endif
  49. #include "indirect_blocks.h"
  50. #include "get_block.h"
  51. #include "is_blockdetection.h"
  52. #include "forward_declarations.h"
  53. #include "endian_conversion.h"
  54. #include "superblock.h"
  55. //-----------------------------------------------------------------------------
  56. //
  57. // Indirect blocks
  58. //
  59. void find_block_action(int blocknr, int, void* ptr)
  60. {
  61. find_block_data_st& data(*reinterpret_cast<find_block_data_st*>(ptr));
  62. if (blocknr == data.block_looking_for)
  63. data.found_block = true;
  64. }
  65. #ifdef CPPGRAPH
  66. void iterate_over_all_blocks_of__with__find_block_action(void) { find_block_action(0, 0, NULL); }
  67. #endif
  68. void print_directory_action(int blocknr, int, void*)
  69. {
  70. static bool using_static_buffer = false;
  71. ASSERT(!using_static_buffer);
  72. static unsigned char block_buf[EXT3_MAX_BLOCK_SIZE];
  73. unsigned char* block = get_block(blocknr, block_buf);
  74. using_static_buffer = true;
  75. ext3_dir_entry_2* dir_entry = reinterpret_cast<ext3_dir_entry_2*>(block);
  76. if (dir_entry->rec_len < block_size_) // The directory could be entirely empty (unused).
  77. print_directory(block, blocknr);
  78. using_static_buffer = false;
  79. }
  80. #ifdef CPPGRAPH
  81. void iterate_over_all_blocks_of__with__print_directory_action(void) { print_directory_action(0, 0, NULL); }
  82. #endif
  83. bool iterate_over_all_blocks_of_indirect_block(int block, int& file_block_nr, void (*action)(int, int, void*), void* data, unsigned int indirect_mask, bool diagnose)
  84. {
  85. if (diagnose)
  86. std::cout << "Processing indirect block " << block << ": " << std::flush;
  87. unsigned char block_buf[EXT3_MAX_BLOCK_SIZE];
  88. __le32* block_ptr = (__le32*)get_block(block, block_buf);
  89. unsigned int i = 0;
  90. while (i < block_size_ / sizeof(__le32))
  91. {
  92. if (block_ptr[i] || (indirect_mask & hole_bit))
  93. {
  94. if (!is_block_number(block_ptr[i]))
  95. {
  96. if (diagnose)
  97. std::cout << "entry " << i << " contains block number " << block_ptr[i] << ", which is too large." << std::endl;
  98. break;
  99. }
  100. if (!diagnose)
  101. action(block_ptr[i], file_block_nr, data);
  102. }
  103. ++i;
  104. ++file_block_nr;
  105. }
  106. bool result = (i < block_size_ / sizeof(__le32));
  107. if (diagnose && !result)
  108. std::cout << "OK" << std::endl;
  109. return result;
  110. }
  111. bool iterate_over_all_blocks_of_double_indirect_block(int block, int& file_block_nr, void (*action)(int, int, void*), void* data, unsigned int indirect_mask, bool diagnose)
  112. {
  113. if (diagnose)
  114. std::cout << "Start processing double indirect block " << block << '.' << std::endl;
  115. unsigned char block_buf[EXT3_MAX_BLOCK_SIZE];
  116. __le32* block_ptr = (__le32*)get_block(block, block_buf);
  117. unsigned int i = 0;
  118. unsigned int const limit = block_size_ >> 2;
  119. while (i < limit)
  120. {
  121. if (block_ptr[i] || (indirect_mask & hole_bit))
  122. {
  123. if (!is_block_number(block_ptr[i]))
  124. {
  125. if (diagnose)
  126. std::cout << "Entry " << i << " of double indirect block " << block << " contains block number " << block_ptr[i] << ", which is too large." << std::endl;
  127. break;
  128. }
  129. if ((indirect_mask & indirect_bit) && !diagnose)
  130. action(block_ptr[i], -1, data);
  131. if ((indirect_mask & direct_bit))
  132. {
  133. if (iterate_over_all_blocks_of_indirect_block(block_ptr[i], file_block_nr, action, data, indirect_mask, diagnose))
  134. break;
  135. }
  136. else
  137. file_block_nr += limit;
  138. }
  139. else
  140. file_block_nr += limit;
  141. ++i;
  142. }
  143. if (diagnose)
  144. std::cout << "End processing double indirect block " << block << '.' << std::endl;
  145. return i < block_size_ / sizeof(__le32);
  146. }
  147. bool iterate_over_all_blocks_of_tripple_indirect_block(int block, int& file_block_nr, void (*action)(int, int, void*), void* data, unsigned int indirect_mask, bool diagnose)
  148. {
  149. if (diagnose)
  150. std::cout << "Start processing tripple indirect block " << block << '.' << std::endl;
  151. unsigned char block_buf[EXT3_MAX_BLOCK_SIZE];
  152. __le32* block_ptr = (__le32*)get_block(block, block_buf);
  153. unsigned int i = 0;
  154. unsigned int const limit = block_size_ >> 2;
  155. while (i < limit)
  156. {
  157. if (block_ptr[i] || (indirect_mask & hole_bit))
  158. {
  159. if (!is_block_number(block_ptr[i]))
  160. {
  161. if (diagnose)
  162. std::cout << "Entry " << i << " of tripple indirect block " << block << " contains block number " << block_ptr[i] << ", which is too large." << std::endl;
  163. break;
  164. }
  165. if ((indirect_mask & indirect_bit) && !diagnose)
  166. action(block_ptr[i], -1, data);
  167. if (iterate_over_all_blocks_of_double_indirect_block(block_ptr[i], file_block_nr, action, data, indirect_mask, diagnose))
  168. break;
  169. }
  170. else
  171. file_block_nr += limit * limit;
  172. ++i;
  173. }
  174. if (diagnose)
  175. std::cout << "End processing tripple indirect block " << block << '.' << std::endl;
  176. return i < limit;
  177. }
  178. // Returns true if an indirect block was encountered that doesn't look like an indirect block anymore.
  179. bool iterate_over_all_blocks_of(Inode const& inode, int inode_number, void (*action)(int, int, void*), void* data, unsigned int indirect_mask, bool diagnose)
  180. {
  181. if (is_symlink(inode) && inode.blocks() == 0)
  182. return false; // Block pointers contain text.
  183. __le32 const* block_ptr = inode.block();
  184. if (diagnose)
  185. std::cout << "Processing direct blocks..." << std::flush;
  186. int file_block_nr = 0;
  187. unsigned int const limit = block_size_ >> 2;
  188. if ((indirect_mask & direct_bit))
  189. {
  190. for (int i = 0; i < EXT3_NDIR_BLOCKS; ++i, ++file_block_nr)
  191. if (block_ptr[i] || (indirect_mask & hole_bit))
  192. {
  193. if (diagnose)
  194. std::cout << ' ' << block_ptr[i] << std::flush;
  195. else
  196. action(block_ptr[i], file_block_nr, data);
  197. }
  198. }
  199. else
  200. file_block_nr += EXT3_NDIR_BLOCKS;
  201. if (diagnose)
  202. std::cout << std::endl;
  203. if (block_ptr[EXT3_IND_BLOCK] || (indirect_mask & hole_bit))
  204. {
  205. if (!is_block_number(block_ptr[EXT3_IND_BLOCK]))
  206. {
  207. std::cout << std::flush;
  208. std::cerr << "\nWARNING: The indirect block number of inode " << inode_number <<
  209. " (or a journal copy thereof) doesn't look like a block number (it is too large, "
  210. "block number " << EXT3_IND_BLOCK << " in it's block list is too large (" <<
  211. block_ptr[EXT3_IND_BLOCK] << ")). Treating this as if one of the indirect blocks "
  212. "were overwritten, although this is a more serious corruption." << std::endl;
  213. return true;
  214. }
  215. if ((indirect_mask & indirect_bit) && !diagnose)
  216. action(block_ptr[EXT3_IND_BLOCK], -1, data);
  217. if ((indirect_mask & direct_bit))
  218. {
  219. if (iterate_over_all_blocks_of_indirect_block(block_ptr[EXT3_IND_BLOCK], file_block_nr, action, data, indirect_mask, diagnose))
  220. return true;
  221. }
  222. }
  223. else
  224. file_block_nr += limit;
  225. if (block_ptr[EXT3_DIND_BLOCK] || (indirect_mask & hole_bit))
  226. {
  227. if (!is_block_number(block_ptr[EXT3_DIND_BLOCK]))
  228. {
  229. std::cout << std::flush;
  230. std::cerr << "WARNING: The double indirect block number of inode " << inode_number <<
  231. " (or a journal copy thereof) doesn't look like a block number (it is too large, "
  232. "block number " << EXT3_DIND_BLOCK << " in it's block list is too large (" <<
  233. block_ptr[EXT3_DIND_BLOCK] << ")). Treating this as if one of the indirect blocks "
  234. "were overwritten, although this is a more serious corruption." << std::endl;
  235. return true;
  236. }
  237. if ((indirect_mask & indirect_bit) && !diagnose)
  238. action(block_ptr[EXT3_DIND_BLOCK], -1, data);
  239. if (iterate_over_all_blocks_of_double_indirect_block(block_ptr[EXT3_DIND_BLOCK], file_block_nr, action, data, indirect_mask, diagnose))
  240. return true;
  241. }
  242. else
  243. file_block_nr += limit * limit;
  244. if (block_ptr[EXT3_TIND_BLOCK] || (indirect_mask & hole_bit))
  245. {
  246. if (!is_block_number(block_ptr[EXT3_TIND_BLOCK]))
  247. {
  248. std::cout << std::flush;
  249. std::cerr << "WARNING: The tripple indirect block number of inode " << inode_number <<
  250. " (or a journal copy thereof) doesn't look like a block number (it is too large, "
  251. "block number " << EXT3_TIND_BLOCK << " in it's block list is too large (" <<
  252. block_ptr[EXT3_TIND_BLOCK] << ")). Treating this as if one of the indirect blocks "
  253. "were overwritten, although this is a more serious corruption." << std::endl;
  254. return true;
  255. }
  256. if ((indirect_mask & indirect_bit) && !diagnose)
  257. action(block_ptr[EXT3_TIND_BLOCK], -1, data);
  258. if (iterate_over_all_blocks_of_tripple_indirect_block(block_ptr[EXT3_TIND_BLOCK], file_block_nr, action, data, indirect_mask, diagnose))
  259. return true;
  260. }
  261. return false;
  262. }
  263. // See header file for description.
  264. // Define this to return false if any [bi] is zero, otherwise
  265. // only false is returned when the first block is zero.
  266. // This must be 0.
  267. #define SKIPZEROES 0
  268. bool is_indirect_block(unsigned char* block_ptr, bool verbose)
  269. {
  270. // Number of 32-bit values per block.
  271. int const values_per_block = block_size_ / sizeof(__le32);
  272. // Block values.
  273. uint32_t blockVals[values_per_block];
  274. uint32_t vmin = 0xffffffff;
  275. uint32_t vmax = 0;
  276. bool hasZero = false;
  277. // Search for zeroes, min and max.
  278. for (int i = 0, offset = 0; i < values_per_block; ++i, offset += sizeof(__le32))
  279. {
  280. uint32_t v = __le32_to_cpu(read_le32(block_ptr + offset));
  281. blockVals[i] = v;
  282. if (v)
  283. {
  284. #if SKIPZEROES
  285. if (hasZero)
  286. {
  287. if (verbose)
  288. std::cout << "Found non-zero after zero!" << std::endl;
  289. // There already was 0, now it is not 0 --- this might be an indirect block of a file with 'holes'.
  290. // However, fail and return false.
  291. return false;
  292. }
  293. #endif
  294. if (!is_data_block_number(v))
  295. {
  296. // This is not a valid block pointer.
  297. if (verbose)
  298. std::cout << "Invalid block pointer!" << std::endl;
  299. return false;
  300. }
  301. #if !SKIPZEROES
  302. if (hasZero)
  303. continue;
  304. #endif
  305. if (v < vmin)
  306. vmin = v;
  307. if (vmax < v)
  308. vmax = v;
  309. }
  310. else
  311. hasZero = true;
  312. }
  313. if (vmax == 0)
  314. {
  315. if (verbose)
  316. {
  317. std::cout << "Block with only zeroes!" << std::endl;
  318. std::cout << std::flush;
  319. std::cerr << "WARNING: is_indirect_block() was called for a block with ONLY zeroes. "
  320. "The correct return value depends on where we were called from. This is not "
  321. "implemented yet!" << std::endl;
  322. }
  323. // This should return 'true' if we're called from is_double_indirect_block or is_tripple_indirect_block:
  324. // it should not lead to failure namely. In any case, we can definitely not be sure we return the
  325. // correct value; a block with only zeroes can theoretically be anything.
  326. return false; // Only zeroes.
  327. }
  328. // Maximum number of bytes to allocate in an array.
  329. uint32_t const max_array_size = blocks_per_group(super_block);
  330. // [2] Search for duplicate entries.
  331. if (vmax - vmin < max_array_size)
  332. {
  333. char t[max_array_size];
  334. std::memset(t, 0, sizeof(t));
  335. for (int i = 0; i < values_per_block; ++i)
  336. {
  337. uint32_t v = blockVals[i];
  338. if (!v)
  339. break;
  340. if (t[v - vmin])
  341. {
  342. // Value already present!
  343. if (verbose)
  344. std::cout << "Duplicated values!" << std::endl;
  345. return false;
  346. }
  347. t[v - vmin] = 1;
  348. }
  349. return true;
  350. }
  351. else
  352. {
  353. // Block is of the form [b1], [b2], ... [bk] ZEROES, but
  354. // [b1] ... [bk] spans more than one group.
  355. // Use a set<> to check if they are all different.
  356. std::set<uint32_t> bvSet;
  357. for (int i = 0; i < values_per_block; ++i)
  358. {
  359. uint32_t v = blockVals[i];
  360. if (!v)
  361. break;
  362. if (!bvSet.insert(v).second) // Was already inserted?
  363. {
  364. if (verbose)
  365. std::cout << "Duplicated values!" << std::endl;
  366. return false;
  367. }
  368. }
  369. return true;
  370. }
  371. }