uncrypt: Replace a few C-strings with std::string.

Also use android::base::{Dirname,Realpath,StartsWith}.

Test: Run uncrypt on device (`uncrypt package block.map`).
Change-Id: Ifacd01d6b35d85ea4afcb93a0dbc0235bb765a75
This commit is contained in:
Tao Bao 2018-12-05 09:23:40 -08:00
parent 62040c53e0
commit d1670a064d

View file

@ -89,7 +89,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <linux/fs.h>
#include <stdarg.h>
#include <stdio.h>
@ -103,6 +102,7 @@
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <android-base/file.h>
@ -163,38 +163,36 @@ static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
}
}
static std::string find_block_device(const char* path, bool* encryptable, bool* encrypted,
bool* f2fs_fs) {
// Look for a volume whose mount point is the prefix of path and
// return its block device. Set encrypted if it's currently
// encrypted.
// Looks for a volume whose mount point is the prefix of path and returns its block device or an
// empty string. Sets encryption flags accordingly.
static std::string FindBlockDevice(const std::string& path, bool* encryptable, bool* encrypted,
bool* f2fs_fs) {
// Ensure f2fs_fs is set to false first.
*f2fs_fs = false;
// ensure f2fs_fs is set to false first.
*f2fs_fs = false;
for (const auto& entry : fstab) {
if (entry.mount_point.empty()) {
continue;
}
auto len = entry.mount_point.size();
if (android::base::StartsWith(path, entry.mount_point) &&
(path[len] == '/' || path[len] == 0)) {
*encrypted = false;
*encryptable = false;
if (entry.is_encryptable() || entry.fs_mgr_flags.file_encryption) {
*encryptable = true;
if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
*encrypted = true;
}
}
if (entry.fs_type == "f2fs") {
*f2fs_fs = true;
}
return entry.blk_device;
}
for (const auto& entry : fstab) {
if (entry.mount_point.empty()) {
continue;
}
auto len = entry.mount_point.size();
if (android::base::StartsWith(path, entry.mount_point) &&
(path[len] == '/' || path[len] == 0)) {
*encrypted = false;
*encryptable = false;
if (entry.is_encryptable() || entry.fs_mgr_flags.file_encryption) {
*encryptable = true;
if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
*encrypted = true;
}
}
if (entry.fs_type == "f2fs") {
*f2fs_fs = true;
}
return entry.blk_device;
}
}
return "";
return "";
}
static bool write_status_to_socket(int status, int socket) {
@ -207,103 +205,102 @@ static bool write_status_to_socket(int status, int socket) {
return android::base::WriteFully(socket, &status_out, sizeof(int));
}
// Parse uncrypt_file to find the update package name.
static bool find_uncrypt_package(const std::string& uncrypt_path_file, std::string* package_name) {
CHECK(package_name != nullptr);
std::string uncrypt_path;
if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
return false;
}
// Parses the given path file to find the update package name.
static bool FindUncryptPackage(const std::string& uncrypt_path_file, std::string* package_name) {
CHECK(package_name != nullptr);
std::string uncrypt_path;
if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
return false;
}
// Remove the trailing '\n' if present.
*package_name = android::base::Trim(uncrypt_path);
return true;
// Remove the trailing '\n' if present.
*package_name = android::base::Trim(uncrypt_path);
return true;
}
static int retry_fibmap(const int fd, const char* name, int* block, const int head_block) {
CHECK(block != nullptr);
for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
if (fsync(fd) == -1) {
PLOG(ERROR) << "failed to fsync \"" << name << "\"";
return kUncryptFileSyncError;
}
if (ioctl(fd, FIBMAP, block) != 0) {
PLOG(ERROR) << "failed to find block " << head_block;
return kUncryptIoctlError;
}
if (*block != 0) {
return kUncryptNoError;
}
sleep(1);
static int RetryFibmap(int fd, const std::string& name, int* block, const int head_block) {
CHECK(block != nullptr);
for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
if (fsync(fd) == -1) {
PLOG(ERROR) << "failed to fsync \"" << name << "\"";
return kUncryptFileSyncError;
}
LOG(ERROR) << "fibmap of " << head_block << "always returns 0";
return kUncryptIoctlError;
if (ioctl(fd, FIBMAP, block) != 0) {
PLOG(ERROR) << "failed to find block " << head_block;
return kUncryptIoctlError;
}
if (*block != 0) {
return kUncryptNoError;
}
sleep(1);
}
LOG(ERROR) << "fibmap of " << head_block << " always returns 0";
return kUncryptIoctlError;
}
static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
bool encrypted, bool f2fs_fs, int socket) {
std::string err;
if (!android::base::RemoveFileIfExists(map_file, &err)) {
LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
return kUncryptFileRemoveError;
}
std::string tmp_map_file = std::string(map_file) + ".tmp";
android::base::unique_fd mapfd(open(tmp_map_file.c_str(),
O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
if (mapfd == -1) {
PLOG(ERROR) << "failed to open " << tmp_map_file;
return kUncryptFileOpenError;
}
// Make sure we can write to the socket.
if (!write_status_to_socket(0, socket)) {
LOG(ERROR) << "failed to write to socket " << socket;
return kUncryptSocketWriteError;
}
struct stat sb;
if (stat(path, &sb) != 0) {
LOG(ERROR) << "failed to stat " << path;
return kUncryptFileStatError;
}
LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
std::vector<int> ranges;
std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n",
blk_dev, static_cast<int64_t>(sb.st_size),
static_cast<int64_t>(sb.st_blksize));
if (!android::base::WriteStringToFd(s, mapfd)) {
PLOG(ERROR) << "failed to write " << tmp_map_file;
return kUncryptWriteError;
}
std::vector<std::vector<unsigned char>> buffers;
if (encrypted) {
buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
}
int head_block = 0;
int head = 0, tail = 0;
android::base::unique_fd fd(open(path, O_RDWR));
if (fd == -1) {
PLOG(ERROR) << "failed to open " << path << " for reading";
return kUncryptFileOpenError;
}
android::base::unique_fd wfd;
if (encrypted) {
wfd.reset(open(blk_dev, O_WRONLY));
if (wfd == -1) {
PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
return kUncryptBlockOpenError;
}
static int ProductBlockMap(const std::string& path, const std::string& map_file,
const std::string& blk_dev, bool encrypted, bool f2fs_fs, int socket) {
std::string err;
if (!android::base::RemoveFileIfExists(map_file, &err)) {
LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
return kUncryptFileRemoveError;
}
std::string tmp_map_file = map_file + ".tmp";
android::base::unique_fd mapfd(open(tmp_map_file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
if (mapfd == -1) {
PLOG(ERROR) << "failed to open " << tmp_map_file;
return kUncryptFileOpenError;
}
// Make sure we can write to the socket.
if (!write_status_to_socket(0, socket)) {
LOG(ERROR) << "failed to write to socket " << socket;
return kUncryptSocketWriteError;
}
struct stat sb;
if (stat(path.c_str(), &sb) != 0) {
PLOG(ERROR) << "failed to stat " << path;
return kUncryptFileStatError;
}
LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
int blocks = ((sb.st_size - 1) / sb.st_blksize) + 1;
LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
std::vector<int> ranges;
std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n", blk_dev.c_str(),
static_cast<int64_t>(sb.st_size),
static_cast<int64_t>(sb.st_blksize));
if (!android::base::WriteStringToFd(s, mapfd)) {
PLOG(ERROR) << "failed to write " << tmp_map_file;
return kUncryptWriteError;
}
std::vector<std::vector<unsigned char>> buffers;
if (encrypted) {
buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
}
int head_block = 0;
int head = 0, tail = 0;
android::base::unique_fd fd(open(path.c_str(), O_RDWR));
if (fd == -1) {
PLOG(ERROR) << "failed to open " << path << " for reading";
return kUncryptFileOpenError;
}
android::base::unique_fd wfd;
if (encrypted) {
wfd.reset(open(blk_dev.c_str(), O_WRONLY));
if (wfd == -1) {
PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
return kUncryptBlockOpenError;
}
}
// F2FS-specific ioctl
// It requires the below kernel commit merged in v4.16-rc1.
@ -351,7 +348,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
if (block == 0) {
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
int error = retry_fibmap(fd, path, &block, head_block);
int error = RetryFibmap(fd, path, &block, head_block);
if (error != kUncryptNoError) {
return error;
}
@ -396,7 +393,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
if (block == 0) {
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
int error = retry_fibmap(fd, path, &block, head_block);
int error = RetryFibmap(fd, path, &block, head_block);
if (error != kUncryptNoError) {
return error;
}
@ -446,13 +443,12 @@ static int produce_block_map(const char* path, const char* map_file, const char*
}
}
if (rename(tmp_map_file.c_str(), map_file) == -1) {
PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
return kUncryptFileRenameError;
if (rename(tmp_map_file.c_str(), map_file.c_str()) == -1) {
PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
return kUncryptFileRenameError;
}
// Sync dir to make rename() result written to disk.
std::string file_name = map_file;
std::string dir_name = dirname(&file_name[0]);
std::string dir_name = android::base::Dirname(map_file);
android::base::unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
if (dfd == -1) {
PLOG(ERROR) << "failed to open dir " << dir_name;
@ -469,45 +465,42 @@ static int produce_block_map(const char* path, const char* map_file, const char*
return 0;
}
static int uncrypt(const char* input_path, const char* map_file, const int socket) {
LOG(INFO) << "update package is \"" << input_path << "\"";
static int Uncrypt(const std::string& input_path, const std::string& map_file, int socket) {
LOG(INFO) << "update package is \"" << input_path << "\"";
// Turn the name of the file we're supposed to convert into an absolute path, so we can find
// what filesystem it's on.
char path[PATH_MAX+1];
if (realpath(input_path, path) == nullptr) {
PLOG(ERROR) << "failed to convert \"" << input_path << "\" to absolute path";
return kUncryptRealpathFindError;
}
// Turn the name of the file we're supposed to convert into an absolute path, so we can find what
// filesystem it's on.
std::string path;
if (!android::base::Realpath(input_path, &path)) {
PLOG(ERROR) << "Failed to convert \"" << input_path << "\" to absolute path";
return kUncryptRealpathFindError;
}
bool encryptable;
bool encrypted;
bool f2fs_fs;
const std::string blk_dev = find_block_device(path, &encryptable, &encrypted, &f2fs_fs);
if (blk_dev.empty()) {
LOG(ERROR) << "failed to find block device for " << path;
return kUncryptBlockDeviceFindError;
}
bool encryptable;
bool encrypted;
bool f2fs_fs;
const std::string blk_dev = FindBlockDevice(path, &encryptable, &encrypted, &f2fs_fs);
if (blk_dev.empty()) {
LOG(ERROR) << "Failed to find block device for " << path;
return kUncryptBlockDeviceFindError;
}
// If the filesystem it's on isn't encrypted, we only produce the
// block map, we don't rewrite the file contents (it would be
// pointless to do so).
LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
// If the filesystem it's on isn't encrypted, we only produce the block map, we don't rewrite the
// file contents (it would be pointless to do so).
LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
// Recovery supports installing packages from 3 paths: /cache,
// /data, and /sdcard. (On a particular device, other locations
// may work, but those are three we actually expect.)
//
// On /data we want to convert the file to a block map so that we
// can read the package without mounting the partition. On /cache
// and /sdcard we leave the file alone.
if (strncmp(path, "/data/", 6) == 0) {
LOG(INFO) << "writing block map " << map_file;
return produce_block_map(path, map_file, blk_dev.c_str(), encrypted, f2fs_fs, socket);
}
// Recovery supports installing packages from 3 paths: /cache, /data, and /sdcard. (On a
// particular device, other locations may work, but those are three we actually expect.)
//
// On /data we want to convert the file to a block map so that we can read the package without
// mounting the partition. On /cache and /sdcard we leave the file alone.
if (android::base::StartsWith(path, "/data/")) {
LOG(INFO) << "writing block map " << map_file;
return ProductBlockMap(path, map_file, blk_dev, encrypted, f2fs_fs, socket);
}
return 0;
return 0;
}
static void log_uncrypt_error_code(UncryptErrorCode error_code) {
@ -523,18 +516,18 @@ static bool uncrypt_wrapper(const char* input_path, const char* map_file, const
std::string package;
if (input_path == nullptr) {
if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
write_status_to_socket(-1, socket);
// Overwrite the error message.
log_uncrypt_error_code(kUncryptPackageMissingError);
return false;
}
input_path = package.c_str();
if (!FindUncryptPackage(UNCRYPT_PATH_FILE, &package)) {
write_status_to_socket(-1, socket);
// Overwrite the error message.
log_uncrypt_error_code(kUncryptPackageMissingError);
return false;
}
input_path = package.c_str();
}
CHECK(map_file != nullptr);
auto start = std::chrono::system_clock::now();
int status = uncrypt(input_path, map_file, socket);
int status = Uncrypt(input_path, map_file, socket);
std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
int count = static_cast<int>(duration.count());