/src/init_directories.cc

http://ext3grep.googlecode.com/ · C++ · 671 lines · 545 code · 43 blank · 83 comment · 143 complexity · b74304c633086cc60c415ee6503205f8 MD5 · raw file

  1. // ext3grep -- An ext3 file system investigation and undelete tool
  2. //
  3. //! @file init_directories.cc Implementation of init_directories (stage 2).
  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. // This program is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 2 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. #ifndef USE_PCH
  24. #include "sys.h"
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <unistd.h>
  28. #include <cerrno>
  29. #include <sstream>
  30. #endif
  31. #include "locate.h"
  32. #include "init_directories.h"
  33. #include "blocknr_vector_type.h"
  34. #include "Parent.h"
  35. #include "forward_declarations.h"
  36. #include "commandline.h"
  37. #include "get_block.h"
  38. #include "journal.h"
  39. #include "dir_inode_to_block.h"
  40. all_directories_type all_directories;
  41. inode_to_directory_type inode_to_directory;
  42. Directory::Directory(uint32_t inode_number, int first_block) : M_inode_number(inode_number), M_blocks(1)
  43. #ifdef DEBUG
  44. , M_extended_blocks_added(false)
  45. #endif
  46. {
  47. std::list<DirectoryBlock>::iterator iter = M_blocks.begin();
  48. iter->read_block(first_block, iter);
  49. }
  50. typedef std::map<uint32_t, blocknr_vector_type> inode_to_extended_blocks_map_type;
  51. bool init_directories_action(ext3_dir_entry_2 const& dir_entry, Inode const&, bool, bool, bool, bool, bool, bool, Parent* parent, void*)
  52. {
  53. // Get the inode number.
  54. uint32_t const inode_number = dir_entry.inode;
  55. // If this is a new directory, skip iterating into it if we already processed it.
  56. // If it's directory '.' we need to continue with this function.
  57. if (dir_entry.name_len != 1 || dir_entry.name[0] != '.')
  58. {
  59. inode_to_directory_type::iterator iter = inode_to_directory.find(inode_number);
  60. return iter != inode_to_directory.end();
  61. }
  62. // If we get here then that means that 'inode_number' is a directory that
  63. // we have a first block for (dir_entry is for entry "."). We possibly found
  64. // more directory start blocks for this inode number in which case we'll
  65. // get here more than once for this inode number.
  66. // Get the first block.
  67. int first_block = dir_inode_to_block(inode_number);
  68. if (first_block == -1)
  69. {
  70. std::cout << std::flush;
  71. std::cerr << "ERROR: dir_inode_to_block(" << inode_number << ") returned -1.\n";
  72. }
  73. ASSERT(first_block != -1);
  74. // Store a new entry in the all_directories container.
  75. std::pair<all_directories_type::iterator, bool> res =
  76. all_directories.insert(all_directories_type::value_type(parent->dirname(false), Directory(inode_number, first_block)));
  77. if (!res.second) // Did we already see this path before? Make sure the inode is consistent.
  78. {
  79. if (inode_number == res.first->second.inode_number() && first_block == res.first->second.first_block())
  80. {
  81. //std::cout << "Aborting recursion of " << parent->dirname(commandline_show_path_inodes) << '\n';
  82. return true; // Abort recursion.
  83. }
  84. std::cout << "Directory \"" << parent->dirname(commandline_show_path_inodes) << "\" is linked to both inode/block " <<
  85. inode_number << '/' << first_block << " as well as " << res.first->second.inode_number() << '/' << res.first->second.first_block() << "\n";
  86. // If we don't do anything here, the assertion `directory.inode_number() == iter->first' in init_directories() will fail.
  87. // See http://groups.google.com/group/ext3grep/browse_thread/thread/38bbcc9bba214240/987815a7bba17190?hl=en#987815a7bba17190
  88. // Lets call inode_number/first_block 'new', and inode_number()/first_block() 'old'.
  89. int sequence_number_new = last_undeleted_directory_inode_refering_to_block(inode_number, first_block);
  90. int sequence_number_old = last_undeleted_directory_inode_refering_to_block(res.first->second.inode_number(), res.first->second.first_block());
  91. if (sequence_number_new == sequence_number_old)
  92. {
  93. std::cout << std::endl;
  94. std::cerr << "WARNING: ext3grep currently does not support this situation:\n";
  95. std::cerr << " last_undeleted_directory_inode_refering_to_block(" << inode_number << ", " << first_block << ") = " << sequence_number_new << '\n';
  96. std::cerr << " last_undeleted_directory_inode_refering_to_block(" << res.first->second.inode_number() << ", " << res.first->second.first_block() << ") = " << sequence_number_old << '\n';
  97. std::cerr << "Since most people don't like it if ext3grep aborts; we'll randomly pick one of them. It could be the WRONG one though." << std::endl;
  98. sequence_number_new = 0; // Drop the new one.
  99. }
  100. if (sequence_number_new > sequence_number_old)
  101. {
  102. // The new inode/block pair is newer, therefore we keep 'inode_number' and replace all_directories element.
  103. std::cout << "Replacing " << res.first->second.inode_number() << '/' << res.first->second.first_block() <<
  104. " (sequence " << sequence_number_old << ") with " << inode_number << '/' << first_block;
  105. if (sequence_number_new == std::numeric_limits<int>::max())
  106. std::cout << " (allocated";
  107. else
  108. std::cout << " (sequence " << sequence_number_new;
  109. std::cout << ").\n";
  110. inode_to_directory_type::iterator iter = inode_to_directory.find(res.first->second.inode_number());
  111. ASSERT(iter != inode_to_directory.end());
  112. ASSERT(iter->second == res.first);
  113. inode_to_directory.erase(iter);
  114. all_directories.erase(res.first);
  115. res = all_directories.insert(all_directories_type::value_type(parent->dirname(false), Directory(inode_number, first_block)));
  116. ASSERT(res.second);
  117. }
  118. else
  119. {
  120. // The old inode/block pair is newer, therefore we keep the all_directories element
  121. // and do not insert the new inode in inode_to_directory. Moreover, we consider
  122. // the current directory block to unusable, so we abort recursion of it.
  123. std::cout << "Keeping " << res.first->second.inode_number() << '/' << res.first->second.first_block();
  124. if (sequence_number_old == std::numeric_limits<int>::max())
  125. std::cout << " (allocated";
  126. else
  127. std::cout << " (sequence " << sequence_number_old;
  128. std::cout << ") over " << inode_number << '/' << first_block << " (sequence " << sequence_number_new << ").\n";
  129. return true; // Abort recursion.
  130. }
  131. // Consistency check:
  132. ASSERT(inode_number == res.first->second.inode_number());
  133. }
  134. std::pair<inode_to_directory_type::iterator, bool> res2 =
  135. inode_to_directory.insert(inode_to_directory_type::value_type(inode_number, res.first));
  136. if (!res2.second) // Did we get here with this inode number before? Make sure the path is consistent!
  137. {
  138. if (inode_number == res2.first->second->second.inode_number() && res.first == res2.first->second)
  139. {
  140. //std::cout << "Aborting recursion of " << parent->dirname(commandline_show_path_inodes) << '\n';
  141. return true; // Abort recursion.
  142. }
  143. std::cout << "Inode number " << inode_number << " is linked to both, " << parent->dirname(commandline_show_path_inodes) << " as well as " << res2.first->second->first << "!\n";
  144. bool new_path = path_exists(parent->dirname(false));
  145. bool old_path = path_exists(res2.first->second->first);
  146. if (new_path && !old_path)
  147. {
  148. std::cout << "Using \"" << parent->dirname(commandline_show_path_inodes) << "\" as \"" << res2.first->second->first << " doesn't exist in the locate database.\n";
  149. inode_to_directory.erase(res2.first);
  150. std::pair<inode_to_directory_type::iterator, bool> res3 =
  151. inode_to_directory.insert(inode_to_directory_type::value_type(inode_number, res.first));
  152. ASSERT(res3.second);
  153. }
  154. else if (!new_path && old_path)
  155. std::cout << "Keeping \"" << res2.first->second->first << "\" as \"" << parent->dirname(commandline_show_path_inodes) << " doesn't exist in the locate database.\n";
  156. else if (!new_path && !old_path)
  157. std::cout << "WARNING: Neither exist in the locate database (you might want to add one). Keeping \"" << res2.first->second->first << "\".\n";
  158. ASSERT(!(new_path && old_path));
  159. }
  160. return false;
  161. }
  162. struct extended_directory_action_data_st {
  163. int blocknr;
  164. std::map<uint32_t, int> linked; // inode to count (number of times a linked dir_entry refers to it).
  165. std::map<uint32_t, int> unlinked; // inode to count (number of times an unlinked dir_entry refers to it).
  166. };
  167. bool filename_heuristics_action(ext3_dir_entry_2 const& dir_entry, Inode const& UNUSED(inode),
  168. bool UNUSED(deleted), bool UNUSED(allocated), bool UNUSED(reallocated), bool UNUSED(zero_inode), bool UNUSED(linked), bool UNUSED(filtered),
  169. Parent*, void* data)
  170. {
  171. std::set<std::string>* filesnames = reinterpret_cast<std::set<std::string>*>(data);
  172. std::string filename(dir_entry.name, dir_entry.name_len);
  173. filesnames->insert(filename);
  174. return false;
  175. }
  176. #ifdef CPPGRAPH
  177. void iterate_over_directory__with__filename_heuristics_action(void) { (void)filename_heuristics_action(*(ext3_dir_entry_2 const*)NULL, *(Inode const*)NULL, 0, 0, 0, 0, 0, 0, NULL, NULL); }
  178. #endif
  179. bool extended_directory_action(ext3_dir_entry_2 const& dir_entry, Inode const& inode,
  180. bool UNUSED(deleted), bool UNUSED(allocated), bool reallocated, bool zero_inode, bool linked, bool UNUSED(filtered), Parent*, void* ptr)
  181. {
  182. extended_directory_action_data_st* data = reinterpret_cast<extended_directory_action_data_st*>(ptr);
  183. bool is_maybe_directory = true; // Maybe, because if !feature_incompat_filetype then it isn't
  184. // garanteed that the contents of the inode still belong to this entry.
  185. if (feature_incompat_filetype)
  186. is_maybe_directory = (dir_entry.file_type & 7) == EXT3_FT_DIR;
  187. else if (!zero_inode && !reallocated)
  188. is_maybe_directory = is_directory(inode);
  189. if (is_maybe_directory && !zero_inode)
  190. {
  191. int blocknr2 = dir_inode_to_block(dir_entry.inode);
  192. if (blocknr2 == -1)
  193. {
  194. // Don't print this message if !feature_incompat_filetype && reallocated
  195. // because it more likely to just not being a directory inode.
  196. if (feature_incompat_filetype || !reallocated)
  197. std::cout << "Cannot find a directory block for inode " << dir_entry.inode << ".\n";
  198. return true;
  199. }
  200. static unsigned char block_buf[EXT3_MAX_BLOCK_SIZE];
  201. get_block(blocknr2, block_buf);
  202. ext3_dir_entry_2 const* dir_entry2 = reinterpret_cast<ext3_dir_entry_2 const*>(block_buf);
  203. ASSERT(dir_entry2->inode == dir_entry.inode);
  204. dir_entry2 = reinterpret_cast<ext3_dir_entry_2 const*>(block_buf + dir_entry2->rec_len);
  205. ASSERT(dir_entry2->name_len == 2 && dir_entry2->name[0] == '.' && dir_entry2->name[1] == '.');
  206. ASSERT(dir_entry2->inode);
  207. std::map<uint32_t, int>& inode_to_count(linked ? data->linked : data->unlinked);
  208. std::map<uint32_t, int>::iterator iter = inode_to_count.find(dir_entry2->inode);
  209. if (iter == inode_to_count.end())
  210. inode_to_count[dir_entry2->inode] = 1;
  211. else
  212. ++(inode_to_count[dir_entry2->inode]);
  213. }
  214. return false;
  215. }
  216. #ifdef CPPGRAPH
  217. void iterate_over_directory__with__extended_directory_action(void) { (void)extended_directory_action(*(ext3_dir_entry_2 const*)NULL, *(Inode const*)NULL, 0, 0, 0, 0, 0, 0, NULL, NULL); }
  218. #endif
  219. bool find_inode_number_of_extended_directory_block(int blocknr, unsigned char* block_buf, uint32_t& inode_number, uint32_t& inode_from_journal)
  220. {
  221. block_to_dir_inode_map_type::iterator iter = block_to_dir_inode_map.find(blocknr);
  222. inode_from_journal = (iter == block_to_dir_inode_map.end()) ? 0 : iter->second;
  223. get_block(blocknr, block_buf);
  224. extended_directory_action_data_st data;
  225. data.blocknr = blocknr;
  226. #ifdef CPPGRAPH
  227. // Let cppgraph know that we call extended_directory_action from here.
  228. iterate_over_directory__with__extended_directory_action();
  229. #endif
  230. ++no_filtering;
  231. iterate_over_directory(block_buf, blocknr, extended_directory_action, NULL, &data);
  232. --no_filtering;
  233. bool linked = (data.linked.size() > 0);
  234. std::map<uint32_t, int>& inode_to_count(linked ? data.linked : data.unlinked);
  235. inode_number = 0;
  236. if (inode_to_count.size() > 0)
  237. {
  238. if (inode_to_count.size() > 1)
  239. {
  240. if (inode_from_journal)
  241. std::cout << "Extended directory at " << blocknr << " has entries that appear to be directories, but their parent directory inode is not consistent.\n";
  242. else
  243. {
  244. std::cout << "WARNING: extended directory at " << blocknr << " has entries that appear to be directories, "
  245. "but their parent directory inode is not consistent! I can't make this decision for you. "
  246. "You will have to manually pick an inode for this block number. The inodes that I found are (although ALL could be wrong):\n";
  247. for (std::map<uint32_t, int>::iterator iter = inode_to_count.begin(); iter != inode_to_count.end(); ++iter)
  248. {
  249. std::cout << " " << iter->first << " (" << iter->second;
  250. if (iter->second == 1)
  251. std::cout << " time)\n";
  252. else
  253. std::cout << " times)\n";
  254. }
  255. }
  256. }
  257. else
  258. {
  259. inode_number = inode_to_count.begin()->first;
  260. bool journal_disagrees_with_found_directory_inodes = inode_from_journal && inode_from_journal != inode_number;
  261. if (journal_disagrees_with_found_directory_inodes)
  262. {
  263. std::cout << "Extended directory at " << blocknr << " appears to contains " << inode_to_count.begin()->second <<
  264. ' ' << (linked ? "linked" : "unlinked") << " directory whose parent directory has inode " <<
  265. inode_number << " but according to the journal it should be " << inode_from_journal << ". Using the latter.\n";
  266. // We trust our journal based algorithm more because the content of
  267. // inodes can hardly be trusted: they can be reused and not refer
  268. // to this dir entry at all. Especially in the case of !feature_incompat_filetype
  269. // where even regular files' inodes can have been reused (by directories)
  270. // this will happen frequently, but independent of the frequency at which
  271. // it occurs, the journal is simply more reliable.
  272. inode_number = inode_from_journal;
  273. // However...
  274. if (linked)
  275. std::cout << "WARNING: We really only expect that to happen for unlinked directory entries. Have a look at block " << blocknr << '\n';
  276. if (inode_to_count.begin()->second > 1)
  277. std::cout << "WARNING: It's suspiciously weird that there are more than one such \"directories\". Have a look at block " << blocknr << '\n';
  278. }
  279. else
  280. std::cout << "Extended directory at " << blocknr << " belongs to inode " << inode_number <<
  281. " (from " << inode_to_count.begin()->second << ' ' << (linked ? "linked" : "unlinked") << " directories).\n";
  282. }
  283. }
  284. if (!inode_number) // Not found yet?
  285. {
  286. #ifdef CPPGRAPH
  287. // Let cppgraph know that we call filename_heuristics_action from here.
  288. iterate_over_directory__with__filename_heuristics_action();
  289. #endif
  290. // Do some heuristics on the filenames.
  291. std::set<std::string> filenames;
  292. ++no_filtering;
  293. iterate_over_directory(block_buf, blocknr, filename_heuristics_action, NULL, &filenames);
  294. --no_filtering;
  295. if (filenames.empty())
  296. {
  297. if (inode_from_journal)
  298. {
  299. std::cout << "Extended directory at " << blocknr << " belongs to inode " << inode_from_journal << " (empty; from journal)).\n";
  300. inode_number = inode_from_journal;
  301. }
  302. else
  303. std::cout << "Could not find an inode for empty extended directory at " << blocknr << '\n';
  304. }
  305. else
  306. {
  307. std::string dir = parent_directory(blocknr, filenames);
  308. if (dir.empty())
  309. {
  310. if (inode_from_journal)
  311. {
  312. std::cout << "Extended directory at " << blocknr << " belongs to inode " << inode_from_journal << " (from journal).\n";
  313. inode_number = inode_from_journal;
  314. }
  315. else
  316. std::cout << "Could not find an inode for extended directory at " << blocknr << ", disregarding it's contents.\n";
  317. }
  318. else
  319. {
  320. all_directories_type::iterator directory_iter = all_directories.find(dir);
  321. if (directory_iter == all_directories.end())
  322. {
  323. std::cout << "Extended directory at " << blocknr << " belongs to directory " << dir << " which isn't in all_directories yet.\n";
  324. return true; // Needs to be processed again later.
  325. }
  326. else
  327. {
  328. inode_number = directory_iter->second.inode_number();
  329. std::cout << "Extended directory at " << blocknr << " belongs to inode " << inode_number << '\n';
  330. if (inode_from_journal && inode_from_journal != inode_number)
  331. std::cout << "WARNING: according to the journal it should have been inode " << inode_from_journal << "!?\n";
  332. }
  333. }
  334. }
  335. }
  336. return false; // Done
  337. }
  338. void init_directories(void)
  339. {
  340. static bool initialized = false;
  341. if (initialized)
  342. return;
  343. initialized = true;
  344. DoutEntering(dc::notice, "init_directories()");
  345. std::string device_name_basename = device_name.substr(device_name.find_last_of('/') + 1);
  346. std::string cache_stage2 = device_name_basename + ".ext3grep.stage2";
  347. struct stat sb;
  348. bool have_cache = !(stat(cache_stage2.c_str(), &sb) == -1);
  349. if (have_cache)
  350. {
  351. if (does_not_end_on_END(cache_stage2))
  352. have_cache = false;
  353. }
  354. else if (errno != ENOENT)
  355. {
  356. int error = errno;
  357. std::cout << std::flush;
  358. std::cerr << progname << ": failed to open " << cache_stage2 << ": " << strerror(error) << std::endl;
  359. exit(EXIT_FAILURE);
  360. }
  361. if (!have_cache)
  362. {
  363. init_dir_inode_to_block_cache();
  364. unsigned char* block_buf = new unsigned char [block_size_];
  365. inode_to_extended_blocks_map_type inode_to_extended_blocks_map;
  366. // Run over all extended directory blocks.
  367. for (std::vector<int>::iterator iter = extended_blocks.begin(); iter != extended_blocks.end(); ++iter)
  368. {
  369. int blocknr = *iter;
  370. uint32_t inode_number;
  371. uint32_t inode_from_journal;
  372. bool needs_reprocessing = find_inode_number_of_extended_directory_block(blocknr, block_buf, inode_number, inode_from_journal);
  373. if (needs_reprocessing)
  374. {
  375. // FIXME: should be processed again after adding extended directory blocks to all_directories!
  376. std::cout << "FIXME: Extended directory at " << blocknr << " belongs to non-existent directory!\n";
  377. // Fall back to journal.
  378. if (inode_from_journal)
  379. {
  380. std::cout << "Extended directory at " << blocknr << " belongs to inode " << inode_from_journal << " (fall back to journal).\n";
  381. inode_number = inode_from_journal;
  382. }
  383. }
  384. if (inode_number)
  385. {
  386. // Add the found inode number of this extended block to inode_to_extended_blocks_map.
  387. inode_to_extended_blocks_map_type::iterator iter2 = inode_to_extended_blocks_map.find(inode_number);
  388. if (iter2 != inode_to_extended_blocks_map.end())
  389. iter2->second.push_back(blocknr);
  390. else
  391. {
  392. blocknr_vector_type bv;
  393. bv.blocknr = 0;
  394. bv.push_back(blocknr);
  395. inode_to_extended_blocks_map.insert(inode_to_extended_blocks_map_type::value_type(inode_number, bv));
  396. }
  397. }
  398. }
  399. // Get root inode.
  400. InodePointer root_inode(get_inode(EXT3_ROOT_INO));
  401. Parent parent(root_inode, EXT3_ROOT_INO);
  402. // Get the block that refers to inode EXT3_ROOT_INO.
  403. int root_blocknr = dir_inode_to_block(EXT3_ROOT_INO);
  404. ASSERT(root_blocknr != -1); // This should be impossible; inode EXT3_ROOT_INO is never wiped(?).
  405. // Initialize root_extended_blocks to be the extended directory blocks of the root.
  406. blocknr_vector_type root_extended_blocks;
  407. int root_extended_blocks_size = 0;
  408. inode_to_extended_blocks_map_type::iterator root_extended_blocks_iter = inode_to_extended_blocks_map.find(EXT3_ROOT_INO);
  409. if (root_extended_blocks_iter != inode_to_extended_blocks_map.end())
  410. {
  411. root_extended_blocks = root_extended_blocks_iter->second;
  412. root_extended_blocks_size = root_extended_blocks.size();
  413. ASSERT(root_extended_blocks_size > 0);
  414. }
  415. #ifdef CPPGRAPH
  416. // Let cppgraph know that we call init_directories_action from here.
  417. iterate_over_directory__with__init_directories_action();
  418. #endif
  419. // Run over all directory blocks and add all start blocks to all_directories, updating inode_to_directory.
  420. int last_extended_block_index = root_extended_blocks_size;
  421. for(int blocknr = root_blocknr;; blocknr = root_extended_blocks[--last_extended_block_index])
  422. {
  423. // Get the contents of this block of the root directory.
  424. get_block(blocknr, block_buf);
  425. // Iterate over all directory blocks.
  426. int depth_store = commandline_depth;
  427. commandline_depth = 10000;
  428. iterate_over_directory(block_buf, root_blocknr, init_directories_action, &parent, NULL);
  429. commandline_depth = depth_store;
  430. if (last_extended_block_index == 0)
  431. break;
  432. }
  433. // Next, add all extended directory blocks.
  434. for (all_directories_type::iterator dir_iter = all_directories.begin(); dir_iter != all_directories.end(); ++dir_iter)
  435. {
  436. #ifdef DEBUG
  437. ASSERT(!dir_iter->second.extended_blocks_added());
  438. #endif
  439. uint32_t inode_number = dir_iter->second.inode_number();
  440. inode_to_extended_blocks_map_type::iterator iter = inode_to_extended_blocks_map.find(inode_number);
  441. if (iter != inode_to_extended_blocks_map.end())
  442. {
  443. blocknr_vector_type bv = iter->second;
  444. int const size = bv.size();
  445. if (size > 0)
  446. {
  447. std::cout << "Adding extended directory block(s) for directory \"" << dir_iter->first << "\"." << std::endl;
  448. unsigned char* block_buf = new unsigned char [block_size_];
  449. for (int j = 0; j < size; ++j)
  450. {
  451. int blocknr = bv[j];
  452. get_block(blocknr, block_buf);
  453. // Add extended directory as DirectoryBlock to the corresponding Directory.
  454. dir_iter->second.blocks().push_back(DirectoryBlock());
  455. std::list<DirectoryBlock>::iterator directory_block_iter = dir_iter->second.blocks().end();
  456. --directory_block_iter;
  457. directory_block_iter->read_block(blocknr, directory_block_iter);
  458. // Set up a Parent object that will return the correct dirname.
  459. ext3_dir_entry_2 fake_dir_entry;
  460. fake_dir_entry.inode = inode_number;
  461. fake_dir_entry.rec_len = 0; // Not used
  462. fake_dir_entry.file_type = 0; // Not used
  463. fake_dir_entry.name_len = dir_iter->first.size();
  464. strncpy(fake_dir_entry.name, dir_iter->first.c_str(), fake_dir_entry.name_len);
  465. InodePointer fake_reference(0);
  466. Parent dummy_parent(fake_reference, 0);
  467. InodePointer inoderef(get_inode(inode_number));
  468. Parent parent(&dummy_parent, &fake_dir_entry, inoderef, inode_number);
  469. ASSERT(parent.dirname(false) == dir_iter->first);
  470. // Iterate over all directory blocks that we can reach.
  471. int depth_store = commandline_depth;
  472. commandline_depth = 10000;
  473. iterate_over_directory(block_buf, blocknr, init_directories_action, &parent, NULL);
  474. commandline_depth = depth_store;
  475. }
  476. delete [] block_buf;
  477. }
  478. }
  479. #ifdef DEBUG
  480. dir_iter->second.set_extended_blocks_added();
  481. #endif
  482. }
  483. #ifdef DEBUG
  484. // The block inside the above loop adds new elements to all_directories. If those are
  485. // added AFTER dir_iter then there is no problem because std::map iterators aren't
  486. // invalidated by insertion and they will be taken into account later in the
  487. // same loop. If dir_iter points to a Directory with a path a/b/c then inode_number
  488. // is the inode number of that 'c' directory. Extended blocks of that directory
  489. // only add "." dir entries for recursively found directories, ie a/b/c/d and
  490. // are therefore inserted after the current element and processed automatically
  491. // in the same loop. Therefore, the following should hold:
  492. for (all_directories_type::iterator dir_iter = all_directories.begin(); dir_iter != all_directories.end(); ++dir_iter)
  493. ASSERT(dir_iter->second.extended_blocks_added());
  494. #endif
  495. all_directories_type::iterator lost_plus_found_directory_iter = all_directories.find("lost+found");
  496. ASSERT(lost_plus_found_directory_iter != all_directories.end());
  497. // Add all remaining extended directory blocks to lost+found.
  498. // Also free memory of inode_to_extended_blocks_map.
  499. for (inode_to_extended_blocks_map_type::iterator iter = inode_to_extended_blocks_map.begin(); iter != inode_to_extended_blocks_map.end(); ++iter)
  500. {
  501. uint32_t inode_number = iter->first;
  502. blocknr_vector_type bv = iter->second;
  503. inode_to_directory_type::iterator directory_iter = inode_to_directory.find(inode_number);
  504. if (directory_iter == inode_to_directory.end()) // Not added already?
  505. {
  506. if (bv.size() == 1)
  507. std::cout << "WARNING: Can't link block";
  508. else
  509. std::cout << "WARNING: Can't link blocks";
  510. for (size_t j = 0; j < bv.size(); ++j)
  511. std::cout << ' ' << bv[j];
  512. std::cout << " to inode " << inode_number << " because that inode cannot be found in the inode_to_directory map. Linking it to lost+found instead!\n";
  513. // FIXME: namespace polution. These should be put in lost+found/inode_number or something.
  514. for (size_t j = 0; j < bv.size(); ++j)
  515. {
  516. int blocknr = bv[j];
  517. // Add extended directory as DirectoryBlock to lost+found.
  518. lost_plus_found_directory_iter->second.blocks().push_back(DirectoryBlock());
  519. std::list<DirectoryBlock>::iterator directory_block_iter = lost_plus_found_directory_iter->second.blocks().end();
  520. --directory_block_iter;
  521. directory_block_iter->read_block(blocknr, directory_block_iter);
  522. }
  523. }
  524. // Free memory.
  525. bv.erase();
  526. }
  527. delete [] block_buf;
  528. std::cout << '\n';
  529. std::cout << "Writing analysis so far to '" << cache_stage2 << "'. Delete that file if you want to do this stage again.\n";
  530. std::ofstream cache;
  531. cache.open(cache_stage2.c_str());
  532. cache << "# Stage 2 data for " << device_name << ".\n";
  533. cache << "# Inodes path and directory blocks.\n";
  534. cache << "# INODE PATH BLOCK [BLOCK ...]\n";
  535. for (inode_to_directory_type::iterator iter = inode_to_directory.begin(); iter != inode_to_directory.end(); ++iter)
  536. {
  537. cache << iter->first << " '" << iter->second->first << "'";
  538. Directory& directory(iter->second->second);
  539. if (directory.inode_number() != iter->first)
  540. {
  541. std::cerr << "ERROR: inode_to_directory entry with inode number " << iter->first <<
  542. " points to a Directory with inode number " << directory.inode_number() << " (path \"" << iter->second->first << "\")." << std::endl;
  543. }
  544. ASSERT(directory.inode_number() == iter->first);
  545. for (std::list<DirectoryBlock>::iterator iter2 = directory.blocks().begin(); iter2 != directory.blocks().end(); ++iter2)
  546. cache << ' ' << iter2->block();
  547. cache << '\n';
  548. }
  549. cache << "# END\n";
  550. cache.close();
  551. }
  552. else
  553. {
  554. std::cout << "Loading " << cache_stage2 << "..." << std::flush;
  555. std::ifstream cache;
  556. cache.open(cache_stage2.c_str());
  557. if (!cache.is_open())
  558. {
  559. int error = errno;
  560. std::cout << " error" << std::endl;
  561. std::cerr << progname << ": failed to open " << cache_stage2 << ": " << strerror(error) << std::endl;
  562. exit(EXIT_FAILURE);
  563. }
  564. int inode;
  565. int blocknr;
  566. char c;
  567. // Skip initial comments.
  568. for(;;)
  569. {
  570. cache.get(c);
  571. if (c == '#')
  572. cache.ignore(std::numeric_limits<int>::max(), '\n');
  573. else
  574. {
  575. cache.putback(c);
  576. break;
  577. }
  578. }
  579. ASSERT(!dir_inode_to_block_cache);
  580. dir_inode_to_block_cache = new blocknr_vector_type [inode_count_ + 1];
  581. std::memset(dir_inode_to_block_cache, 0, sizeof(blocknr_vector_type) * (inode_count_ + 1));
  582. std::stringstream buf;
  583. int count = 0;
  584. while (cache >> inode)
  585. {
  586. cache.get(c);
  587. ASSERT(c == ' ');
  588. cache.get(c);
  589. ASSERT(c == '\'');
  590. buf.clear();
  591. buf.str("");
  592. cache.get(*buf.rdbuf(), '\n');
  593. if (inode == EXT3_ROOT_INO) // If the function extracts no elements, it calls setstate(failbit).
  594. cache.clear();
  595. cache.get(c); // Extraction stops on end-of-file or on an element that compares equal to delim (which is not extracted).
  596. ASSERT(c == '\n');
  597. std::string::size_type pos = buf.str().find_last_of('\'');
  598. ASSERT(pos != std::string::npos);
  599. std::pair<all_directories_type::iterator, bool> res = all_directories.insert(all_directories_type::value_type(buf.str().substr(0, pos), Directory(inode)));
  600. ASSERT(res.second);
  601. std::pair<inode_to_directory_type::iterator, bool> res2 = inode_to_directory.insert(inode_to_directory_type::value_type(inode, res.first));
  602. ASSERT(res2.second);
  603. buf.seekg(pos + 1);
  604. std::vector<uint32_t> block_numbers;
  605. while(buf >> blocknr)
  606. {
  607. block_numbers.push_back(blocknr);
  608. c = buf.get();
  609. if (c != ' ')
  610. {
  611. ASSERT(buf.eof());
  612. break;
  613. }
  614. }
  615. dir_inode_to_block_cache[inode] = block_numbers;
  616. std::list<DirectoryBlock>& blocks(res.first->second.blocks());
  617. blocks.resize(block_numbers.size());
  618. std::list<DirectoryBlock>::iterator directory_block_iter = blocks.begin();
  619. for (std::vector<uint32_t>::iterator block_number_iter = block_numbers.begin();
  620. block_number_iter != block_numbers.end(); ++block_number_iter, ++directory_block_iter)
  621. directory_block_iter->read_block(*block_number_iter, directory_block_iter);
  622. if (++count % 100 == 0)
  623. std::cout << '.' << std::flush;
  624. }
  625. cache.close();
  626. std::cout << " done\n";
  627. }
  628. }