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