1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2015 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
162b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
172b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include "update_engine/payload_generator/ext2_filesystem.h"
182b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
192b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <et/com_err.h>
202b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <ext2fs/ext2_io.h>
212b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <ext2fs/ext2fs.h>
222b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
232b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <map>
242b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <set>
252b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
262b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <base/logging.h>
272b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include <base/strings/stringprintf.h>
282b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
301beda780333ce51d7872603b70712772eb2383fbAlex Deymo#include "update_engine/payload_generator/extent_ranges.h"
312b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include "update_engine/payload_generator/extent_utils.h"
322b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo#include "update_engine/update_metadata.pb.h"
332b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
342b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymousing std::set;
352b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymousing std::string;
362b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymousing std::unique_ptr;
372b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymousing std::vector;
382b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
392b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymonamespace chromeos_update_engine {
402b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
412b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymonamespace {
422b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo// Processes all blocks belonging to an inode and adds them to the extent list.
432b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo// This function should match the prototype expected by ext2fs_block_iterate2().
442b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymoint ProcessInodeAllBlocks(ext2_filsys fs,
452b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                          blk_t* blocknr,
462b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                          e2_blkcnt_t blockcnt,
472b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                          blk_t ref_blk,
482b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                          int ref_offset,
492b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                          void* priv) {
502b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  vector<Extent>* extents = static_cast<vector<Extent>*>(priv);
512b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  AppendBlockToExtents(extents, *blocknr);
522b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return 0;
532b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
542b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
552b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo// Processes only indirect, double indirect or triple indirect metadata
562b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo// blocks belonging to an inode. This function should match the prototype of
572b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo// ext2fs_block_iterate2().
582b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymoint AddMetadataBlocks(ext2_filsys fs,
592b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                      blk_t* blocknr,
602b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                      e2_blkcnt_t blockcnt,
612b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                      blk_t ref_blk,
622b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                      int ref_offset,
632b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                      void* priv) {
642b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  set<uint64_t>* blocks = static_cast<set<uint64_t>*>(priv);
652b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // If |blockcnt| is non-negative, |blocknr| points to the physical block
662b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // number.
672b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // If |blockcnt| is negative, it is one of the values: BLOCK_COUNT_IND,
682b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // BLOCK_COUNT_DIND, BLOCK_COUNT_TIND or BLOCK_COUNT_TRANSLATOR and
692b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // |blocknr| points to a block in the first three cases. The last case is
702b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // only used by GNU Hurd, so we shouldn't see those cases here.
712b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (blockcnt == BLOCK_COUNT_IND || blockcnt == BLOCK_COUNT_DIND ||
722b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      blockcnt == BLOCK_COUNT_TIND) {
732b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    blocks->insert(*blocknr);
742b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
752b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return 0;
762b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
772b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
782b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymostruct UpdateFileAndAppendState {
792b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  std::map<ext2_ino_t, FilesystemInterface::File>* inodes = nullptr;
802b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  set<ext2_ino_t>* used_inodes = nullptr;
812b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  vector<FilesystemInterface::File>* files = nullptr;
822b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2_filsys filsys;
832b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo};
842b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
852b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymoint UpdateFileAndAppend(ext2_ino_t dir,
862b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        int entry,
872b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        struct ext2_dir_entry *dirent,
882b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        int offset,
892b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        int blocksize,
902b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        char *buf,
912b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                        void *priv_data) {
922b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  UpdateFileAndAppendState* state =
932b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      static_cast<UpdateFileAndAppendState*>(priv_data);
942b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  uint32_t file_type = dirent->name_len >> 8;
952b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Directories can't have hard links, and they are added from the outer loop.
962b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (file_type == EXT2_FT_DIR)
972b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return 0;
982b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
992b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  auto ino_file = state->inodes->find(dirent->inode);
1002b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (ino_file == state->inodes->end())
1012b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return 0;
1022b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  auto dir_file = state->inodes->find(dir);
1032b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (dir_file == state->inodes->end())
1042b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return 0;
1052b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  string basename(dirent->name, dirent->name_len & 0xff);
1062b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ino_file->second.name = dir_file->second.name;
1072b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (dir_file->second.name != "/")
1082b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    ino_file->second.name += "/";
1092b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ino_file->second.name += basename;
1102b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1112b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Append this file to the output. If the file has a hard link, it will be
1122b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // added twice to the output, but with different names, which is ok. That will
1132b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // help identify all the versions of the same file.
1142b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  state->files->push_back(ino_file->second);
1152b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  state->used_inodes->insert(dirent->inode);
1162b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return 0;
1172b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
1182b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1192b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}  // namespace
1202b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1212b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymounique_ptr<Ext2Filesystem> Ext2Filesystem::CreateFromFile(
1222b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    const string& filename) {
1232b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (filename.empty())
1242b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return nullptr;
1252b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  unique_ptr<Ext2Filesystem> result(new Ext2Filesystem());
1262e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  result->filename_ = filename;
1272b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1282b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  errcode_t err = ext2fs_open(filename.c_str(),
1292b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                              0,  // flags (read only)
1302b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                              0,  // superblock block number
1312b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                              0,  // block_size (autodetect)
1322b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                              unix_io_manager,
1332b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                              &result->filsys_);
1342b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (err) {
1352b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    LOG(ERROR) << "Opening ext2fs " << filename;
1362b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return nullptr;
1372b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
1382b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return result;
1392b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
1402b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1412b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex DeymoExt2Filesystem::~Ext2Filesystem() {
1422b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2fs_free(filsys_);
1432b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
1442b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1452b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymosize_t Ext2Filesystem::GetBlockSize() const {
1462b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return filsys_->blocksize;
1472b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
1482b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1492b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymosize_t Ext2Filesystem::GetBlockCount() const {
1502b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return ext2fs_blocks_count(filsys_->super);
1512b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
1522b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1532b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymobool Ext2Filesystem::GetFiles(vector<File>* files) const {
1542b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_read_inode_bitmap(filsys_));
1552b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1562b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2_inode_scan iscan;
1572b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  TEST_AND_RETURN_FALSE_ERRCODE(
1582b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      ext2fs_open_inode_scan(filsys_, 0 /* buffer_blocks */, &iscan));
1592b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1602b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  std::map<ext2_ino_t, File> inodes;
1612b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1622b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // List of directories. We need to first parse all the files in a directory
1632b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // to later fix the absolute paths.
1642b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  vector<ext2_ino_t> directories;
1652b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1662b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  set<uint64_t> inode_blocks;
1672b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1682b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Iterator
1692b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2_ino_t it_ino;
1702b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2_inode it_inode;
1712b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1722b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  bool ok = true;
1732b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  while (true) {
1742b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    errcode_t error = ext2fs_get_next_inode(iscan, &it_ino, &it_inode);
1752b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (error) {
1762b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      LOG(ERROR) << "Failed to retrieve next inode (" << error << ")";
1772b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      ok = false;
1782b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      break;
1792b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
1802b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (it_ino == 0)
1812b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      break;
1822b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1832b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    // Skip inodes that are not in use.
1842b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (!ext2fs_test_inode_bitmap(filsys_->inode_map, it_ino))
1852b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      continue;
1862b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1872b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    File& file = inodes[it_ino];
1882b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (it_ino == EXT2_RESIZE_INO) {
1892b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      file.name = "<group-descriptors>";
1902b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    } else {
1912b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      file.name = base::StringPrintf("<inode-%u>", it_ino);
1922b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
1932b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
1942b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    memset(&file.file_stat, 0, sizeof(file.file_stat));
1952b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_ino = it_ino;
1962b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_mode = it_inode.i_mode;
1972b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_nlink = it_inode.i_links_count;
1982b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_uid = it_inode.i_uid;
1992b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_gid = it_inode.i_gid;
2002b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_size = it_inode.i_size;
2012b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_blksize = filsys_->blocksize;
2022b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_blocks = it_inode.i_blocks;
2032b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_atime = it_inode.i_atime;
2042b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_mtime = it_inode.i_mtime;
2052b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.file_stat.st_ctime = it_inode.i_ctime;
2062b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2072b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    bool is_dir = (ext2fs_check_directory(filsys_, it_ino) == 0);
2082b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (is_dir)
2092b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      directories.push_back(it_ino);
2102b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2112b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (!ext2fs_inode_has_valid_blocks(&it_inode))
2122b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      continue;
2132b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2142b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    // Process the inode data and metadata blocks.
2152b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    // For normal files, inode blocks are indirect, double indirect
2162b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    // and triple indirect blocks (no data blocks). For directories and
2172b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    // the journal, all blocks are considered metadata blocks.
2182b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    int flags = it_ino < EXT2_GOOD_OLD_FIRST_INO ? 0 : BLOCK_FLAG_DATA_ONLY;
2192b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    error = ext2fs_block_iterate2(filsys_, it_ino, flags,
2202b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                                  nullptr,  // block_buf
2212b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                                  ProcessInodeAllBlocks,
2222b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                                  &file.extents);
2232b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2242b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (error) {
2252b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      LOG(ERROR) << "Failed to enumerate inode " << it_ino
2262b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                << " blocks (" << error << ")";
2272b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      continue;
2282b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
2292b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (it_ino >= EXT2_GOOD_OLD_FIRST_INO) {
2302b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      ext2fs_block_iterate2(filsys_, it_ino, 0, nullptr,
2312b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                            AddMetadataBlocks,
2322b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                            &inode_blocks);
2332b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
2342b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
2352b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  ext2fs_close_inode_scan(iscan);
2362b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (!ok)
2372b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    return false;
2382b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2392b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // The set of inodes already added to the output. There can be less elements
2402b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // here than in files since the later can contain repeated inodes due to
2412b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // hardlink files.
2422b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  set<ext2_ino_t> used_inodes;
2432b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2442b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  UpdateFileAndAppendState priv_data;
2452b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  priv_data.inodes = &inodes;
2462b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  priv_data.used_inodes = &used_inodes;
2472b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  priv_data.files = files;
2482b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  priv_data.filsys = filsys_;
2492b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2502b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  files->clear();
2512b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Iterate over all the files of each directory to update the name and add it.
2522b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  for (ext2_ino_t dir_ino : directories) {
2532b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    char* dir_name = nullptr;
2542b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    errcode_t error = ext2fs_get_pathname(filsys_, dir_ino, 0, &dir_name);
2552b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (error) {
2562b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      // Not being able to read a directory name is not a fatal error, it is
2572b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      // just skiped.
2582b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      LOG(WARNING) << "Reading directory name on inode " << dir_ino
2592b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                   << " (error " << error << ")";
2602b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      inodes[dir_ino].name = base::StringPrintf("<dir-%u>", dir_ino);
2612b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    } else {
2622b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      inodes[dir_ino].name = dir_name;
2632b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      files->push_back(inodes[dir_ino]);
2642b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      used_inodes.insert(dir_ino);
2652b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
266a50870549b0fc16b659250449fffbd3eacc57d8bAlex Deymo    ext2fs_free_mem(&dir_name);
2672b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2682b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    error = ext2fs_dir_iterate2(
2692b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo        filsys_, dir_ino, 0, nullptr /* block_buf */,
2702b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo        UpdateFileAndAppend, &priv_data);
2712b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (error) {
2722b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      LOG(WARNING) << "Failed to enumerate files in directory "
2732b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo                   << inodes[dir_ino].name << " (error " << error << ")";
2742b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
2752b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
2762b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2772b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Add <inode-blocks> file with the blocks that hold inodes.
2782b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  File inode_file;
2792b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  inode_file.name = "<inode-blocks>";
2802b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  for (uint64_t block : inode_blocks) {
2812b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    AppendBlockToExtents(&inode_file.extents, block);
2822b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
2832b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  files->push_back(inode_file);
2842b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
2852b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Add <free-spacce> blocs.
2862b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  errcode_t error = ext2fs_read_block_bitmap(filsys_);
2872b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  if (error) {
2882b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    LOG(ERROR) << "Reading the blocks bitmap (error " << error << ")";
2892b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  } else {
2902b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    File free_space;
2912b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    free_space.name = "<free-space>";
2922b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    blk64_t blk_start = ext2fs_get_block_bitmap_start2(filsys_->block_map);
2932b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    blk64_t blk_end = ext2fs_get_block_bitmap_end2(filsys_->block_map);
2942b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    for (blk64_t block = blk_start; block < blk_end; block++) {
2952b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      if (!ext2fs_test_block_bitmap2(filsys_->block_map, block))
2962b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo        AppendBlockToExtents(&free_space.extents, block);
2972b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    }
2982b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    files->push_back(free_space);
2992b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
3002b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
3012b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // Add all the unreachable files plus the pseudo-files with an inode. Since
3022b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  // these inodes aren't files in the filesystem, ignore the empty ones.
3032b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  for (const auto& ino_file : inodes) {
3042b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (used_inodes.find(ino_file.first) != used_inodes.end())
3052b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      continue;
3062b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    if (ino_file.second.extents.empty())
3072b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo      continue;
3082b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
3092b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    File file = ino_file.second;
3102b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    ExtentRanges ranges;
3112b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    ranges.AddExtents(file.extents);
3122b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    file.extents = ranges.GetExtentsForBlockCount(ranges.blocks());
3132b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
3142b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo    files->push_back(file);
3152b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  }
3162b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
3172b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo  return true;
3182b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}
3192b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo
3203f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenkobool Ext2Filesystem::LoadSettings(brillo::KeyValueStore* store) const {
3212e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  // First search for the settings inode following symlinks if we find some.
3222e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  ext2_ino_t ino_num = 0;
3232e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  errcode_t err = ext2fs_namei_follow(
3242e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo      filsys_, EXT2_ROOT_INO /* root */, EXT2_ROOT_INO /* cwd */,
3252e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo      "/etc/update_engine.conf", &ino_num);
3262e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  if (err != 0)
3272e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo    return false;
3282e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo
3292e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  ext2_inode ino_data;
3302e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  if (ext2fs_read_inode(filsys_, ino_num, &ino_data) != 0)
3312e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo    return false;
3322e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo
3332e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  // Load the list of blocks and then the contents of the inodes.
3342e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  vector<Extent> extents;
3352e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  err = ext2fs_block_iterate2(filsys_, ino_num, BLOCK_FLAG_DATA_ONLY,
3362e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo                              nullptr,  // block_buf
3372e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo                              ProcessInodeAllBlocks,
3382e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo                              &extents);
3392e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  if (err != 0)
3402e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo    return false;
3412e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo
3423f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob blob;
3432e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  uint64_t physical_size = BlocksInExtents(extents) * filsys_->blocksize;
3442e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  // Sparse holes in the settings file are not supported.
3452e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  if (EXT2_I_SIZE(&ino_data) > physical_size)
3462e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo    return false;
3472e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  if (!utils::ReadExtents(filename_, extents, &blob, physical_size,
3482e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo                          filsys_->blocksize))
3492e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo    return false;
3502e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo
3512e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  string text(blob.begin(), blob.begin() + EXT2_I_SIZE(&ino_data));
3522e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo  return store->LoadFromString(text);
3532e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo}
3542e9533be9eb2e022d653400f47a354a7f06bf9dbAlex Deymo
3552b19cfbcdb1aa8c5d1f338d19312fe14b6734bd5Alex Deymo}  // namespace chromeos_update_engine
356