diff options
Diffstat (limited to 'updater/blockimg.cpp')
-rw-r--r-- | updater/blockimg.cpp | 267 |
1 files changed, 117 insertions, 150 deletions
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index a80180a9a..f08ca5b0c 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -33,24 +33,24 @@ #include <unistd.h> #include <fec/io.h> -#include <map> #include <memory> #include <string> +#include <unordered_map> #include <vector> #include <android-base/parseint.h> #include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <ziparchive/zip_archive.h> #include "applypatch/applypatch.h" #include "edify/expr.h" #include "error_code.h" -#include "install.h" +#include "updater/install.h" #include "openssl/sha.h" -#include "minzip/Hash.h" #include "ota_io.h" #include "print_sha1.h" -#include "unique_fd.h" -#include "updater.h" +#include "updater/updater.h" #define BLOCKSIZE 4096 @@ -71,7 +71,7 @@ struct RangeSet { static CauseCode failure_type = kNoCause; static bool is_retry = false; -static std::map<std::string, RangeSet> stash_map; +static std::unordered_map<std::string, RangeSet> stash_map; static void parse_range(const std::string& range_text, RangeSet& rs) { @@ -151,6 +151,10 @@ static int read_all(int fd, uint8_t* data, size_t size) { failure_type = kFreadFailure; fprintf(stderr, "read failed: %s\n", strerror(errno)); return -1; + } else if (r == 0) { + failure_type = kFreadFailure; + fprintf(stderr, "read reached unexpected EOF.\n"); + return -1; } so_far += r; } @@ -213,7 +217,7 @@ static void allocate(size_t size, std::vector<uint8_t>& buffer) { } struct RangeSinkState { - RangeSinkState(RangeSet& rs) : tgt(rs) { }; + explicit RangeSinkState(RangeSet& rs) : tgt(rs) { }; int fd; const RangeSet& tgt; @@ -296,8 +300,8 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) { // rss and signals the condition again. struct NewThreadInfo { - ZipArchive* za; - const ZipEntry* entry; + ZipArchiveHandle za; + ZipEntry entry; RangeSinkState* rss; @@ -305,7 +309,7 @@ struct NewThreadInfo { pthread_cond_t cv; }; -static bool receive_new_data(const unsigned char* data, int size, void* cookie) { +static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) { NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie); while (size > 0) { @@ -338,7 +342,7 @@ static bool receive_new_data(const unsigned char* data, int size, void* cookie) static void* unzip_new_data(void* cookie) { NewThreadInfo* nti = (NewThreadInfo*) cookie; - mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti); + ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti); return nullptr; } @@ -398,7 +402,7 @@ struct CommandParameters { std::string stashbase; bool canwrite; int createdstash; - int fd; + android::base::unique_fd fd; bool foundwrites; bool isunresumable; int version; @@ -608,9 +612,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s return -1; } - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY)); - unique_fd fd_holder(fd); - + android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY))); if (fd == -1) { fprintf(stderr, "open \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); return -1; @@ -665,9 +667,9 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str()); - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)); - unique_fd fd_holder(fd); - + android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), + O_WRONLY | O_CREAT | O_TRUNC, + STASH_FILE_MODE))); if (fd == -1) { fprintf(stderr, "failed to create \"%s\": %s\n", fn.c_str(), strerror(errno)); return -1; @@ -690,9 +692,8 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } std::string dname = GetStashFileName(base, "", ""); - int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY)); - unique_fd dfd_holder(dfd); - + android::base::unique_fd dfd(TEMP_FAILURE_RETRY(ota_open(dname.c_str(), + O_RDONLY | O_DIRECTORY))); if (dfd == -1) { failure_type = kFileOpenFailure; fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); @@ -980,8 +981,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& tgthash = params.tokens[params.cpos++]; } - if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, params.stashbase, - &overlap) == -1) { + if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, + params.stashbase, &overlap) == -1) { return -1; } @@ -1215,7 +1216,7 @@ static int PerformCommandDiff(CommandParameters& params) { size_t len; if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) { - fprintf(stderr, "invalid patch offset\n"); + fprintf(stderr, "invalid patch len\n"); return -1; } @@ -1247,10 +1248,8 @@ static int PerformCommandDiff(CommandParameters& params) { if (status == 0) { fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size); - Value patch_value; - patch_value.type = VAL_BLOB; - patch_value.size = len; - patch_value.data = (char*) (params.patch_start + offset); + Value patch_value(VAL_BLOB, + std::string(reinterpret_cast<const char*>(params.patch_start + offset), len)); RangeSinkState rss(tgt); rss.fd = params.fd; @@ -1352,28 +1351,6 @@ struct Command { CommandFunction f; }; -// CompareCommands and CompareCommandNames are for the hash table - -static int CompareCommands(const void* c1, const void* c2) { - return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name); -} - -static int CompareCommandNames(const void* c1, const void* c2) { - return strcmp(((const Command*) c1)->name, (const char*) c2); -} - -// HashString is used to hash command names for the hash table - -static unsigned int HashString(const char *s) { - unsigned int hash = 0; - if (s) { - while (*s) { - hash = hash * 33 + *s++; - } - } - return hash; -} - // args: // - block device (or file) to modify in-place // - transfer list (blob) @@ -1382,8 +1359,7 @@ static unsigned int HashString(const char *s) { static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[], const Command* commands, size_t cmdcount, bool dryrun) { - CommandParameters params; - memset(¶ms, 0, sizeof(params)); + CommandParameters params = {}; params.canwrite = !dryrun; fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update"); @@ -1398,66 +1374,64 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg Value* patch_data_fn = nullptr; if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value, &new_data_fn, &patch_data_fn) < 0) { - return StringValue(strdup("")); + return StringValue(""); } - std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename, - FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> transfer_list_value_holder(transfer_list_value, - FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> new_data_fn_holder(new_data_fn, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue); + std::unique_ptr<Value> blockdev_filename_holder(blockdev_filename); + std::unique_ptr<Value> transfer_list_value_holder(transfer_list_value); + std::unique_ptr<Value> new_data_fn_holder(new_data_fn); + std::unique_ptr<Value> patch_data_fn_holder(patch_data_fn); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (transfer_list_value->type != VAL_BLOB) { ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name); - return StringValue(strdup("")); + return StringValue(""); } if (new_data_fn->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (patch_data_fn->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie); if (ui == nullptr) { - return StringValue(strdup("")); + return StringValue(""); } FILE* cmd_pipe = ui->cmd_pipe; - ZipArchive* za = ui->package_zip; + ZipArchiveHandle za = ui->package_zip; if (cmd_pipe == nullptr || za == nullptr) { - return StringValue(strdup("")); + return StringValue(""); } - const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data); - if (patch_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data); - return StringValue(strdup("")); + ZipString path_data(patch_data_fn->data.c_str()); + ZipEntry patch_entry; + if (FindEntry(za, path_data, &patch_entry) != 0) { + fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str()); + return StringValue(""); } - params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry); - const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data); - if (new_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data); - return StringValue(strdup("")); + params.patch_start = ui->package_zip_addr + patch_entry.offset; + ZipString new_data(new_data_fn->data.c_str()); + ZipEntry new_entry; + if (FindEntry(za, new_data, &new_entry) != 0) { + fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str()); + return StringValue(""); } - params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR)); - unique_fd fd_holder(params.fd); - + params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR))); if (params.fd == -1) { - fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno)); - return StringValue(strdup("")); + fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } if (params.canwrite) { @@ -1473,24 +1447,21 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg int error = pthread_create(¶ms.thread, &attr, unzip_new_data, ¶ms.nti); if (error != 0) { fprintf(stderr, "pthread_create failed: %s\n", strerror(error)); - return StringValue(strdup("")); + return StringValue(""); } } - // Copy all the lines in transfer_list_value into std::string for - // processing. - const std::string transfer_list(transfer_list_value->data, transfer_list_value->size); - std::vector<std::string> lines = android::base::Split(transfer_list, "\n"); + std::vector<std::string> lines = android::base::Split(transfer_list_value->data, "\n"); if (lines.size() < 2) { ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n", lines.size()); - return StringValue(strdup("")); + return StringValue(""); } // First line in transfer list is the version number if (!android::base::ParseInt(lines[0].c_str(), ¶ms.version, 1, 4)) { fprintf(stderr, "unexpected transfer list version [%s]\n", lines[0].c_str()); - return StringValue(strdup("")); + return StringValue(""); } fprintf(stderr, "blockimg version is %d\n", params.version); @@ -1499,11 +1470,11 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg int total_blocks; if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) { ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str()); - return StringValue(strdup("")); + return StringValue(""); } if (total_blocks == 0) { - return StringValue(strdup("t")); + return StringValue("t"); } size_t start = 2; @@ -1511,7 +1482,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg if (lines.size() < 4) { ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", lines.size()); - return StringValue(strdup("")); + return StringValue(""); } // Third line is how many stash entries are needed simultaneously @@ -1522,12 +1493,12 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) { ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n", lines[3].c_str()); - return StringValue(strdup("")); + return StringValue(""); } - int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase); + int res = CreateStash(state, stash_max_blocks, blockdev_filename->data.c_str(), params.stashbase); if (res == -1) { - return StringValue(strdup("")); + return StringValue(""); } params.createdstash = res; @@ -1535,13 +1506,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg start += 2; } - // Build a hash table of the available commands - HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr); - std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree); - + // Build a map of the available commands + std::unordered_map<std::string, const Command*> cmd_map; for (size_t i = 0; i < cmdcount; ++i) { - unsigned int cmdhash = HashString(commands[i].name); - mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true); + if (cmd_map.find(commands[i].name) != cmd_map.end()) { + fprintf(stderr, "Error: command [%s] already exists in the cmd map.\n", + commands[i].name); + return StringValue(strdup("")); + } + cmd_map[commands[i].name] = &commands[i]; } int rc = -1; @@ -1558,16 +1531,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg params.cmdname = params.tokens[params.cpos++].c_str(); params.cmdline = line_str.c_str(); - unsigned int cmdhash = HashString(params.cmdname); - const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash, - const_cast<char*>(params.cmdname), CompareCommandNames, - false)); - - if (cmd == nullptr) { + if (cmd_map.find(params.cmdname) == cmd_map.end()) { fprintf(stderr, "unexpected command [%s]\n", params.cmdname); goto pbiudone; } + const Command* cmd = cmd_map[params.cmdname]; + if (cmd->f != nullptr && cmd->f(params) == -1) { fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str()); goto pbiudone; @@ -1591,7 +1561,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg fprintf(stderr, "stashed %zu blocks\n", params.stashed); fprintf(stderr, "max alloc needed was %zu\n", params.buffer.size()); - const char* partition = strrchr(blockdev_filename->data, '/'); + const char* partition = strrchr(blockdev_filename->data.c_str(), '/'); if (partition != nullptr && *(partition+1) != 0) { fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE); @@ -1613,7 +1583,7 @@ pbiudone: failure_type = kFsyncFailure; fprintf(stderr, "fsync failed: %s\n", strerror(errno)); } - // params.fd will be automatically closed because of the fd_holder above. + // params.fd will be automatically closed because it's a unique_fd. // Only delete the stash if the update cannot be resumed, or it's // a verification run and we created the stash. @@ -1625,7 +1595,7 @@ pbiudone: state->cause_code = failure_type; } - return StringValue(rc == 0 ? strdup("t") : strdup("")); + return StringValue(rc == 0 ? "t" : ""); } // The transfer list is a text file containing commands to @@ -1723,28 +1693,26 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) Value* ranges; if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) { - return StringValue(strdup("")); + return StringValue(""); } - std::unique_ptr<Value, decltype(&FreeValue)> ranges_holder(ranges, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename, - FreeValue); + std::unique_ptr<Value> ranges_holder(ranges); + std::unique_ptr<Value> blockdev_filename_holder(blockdev_filename); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (ranges->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } - int fd = open(blockdev_filename->data, O_RDWR); - unique_fd fd_holder(fd); - if (fd < 0) { - ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + android::base::unique_fd fd(ota_open(blockdev_filename->data.c_str(), O_RDWR)); + if (fd == -1) { + ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } RangeSet rs; @@ -1756,16 +1724,16 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) std::vector<uint8_t> buffer(BLOCKSIZE); for (size_t i = 0; i < rs.count; ++i) { if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) { - ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) { if (read_all(fd, buffer, BLOCKSIZE) == -1) { - ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + ErrorAbort(state, kFreadFailure, "failed to read %s: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } SHA1_Update(&ctx, buffer.data(), BLOCKSIZE); @@ -1774,7 +1742,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) uint8_t digest[SHA_DIGEST_LENGTH]; SHA1_Final(digest, &ctx); - return StringValue(strdup(print_sha1(digest).c_str())); + return StringValue(print_sha1(digest)); } // This function checks if a device has been remounted R/W prior to an incremental @@ -1788,28 +1756,27 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) if (ReadValueArgs(state, argv, 1, &arg_filename) < 0) { return nullptr; } - std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue); + std::unique_ptr<Value> filename(arg_filename); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } - int fd = open(arg_filename->data, O_RDONLY); - unique_fd fd_holder(fd); + android::base::unique_fd fd(ota_open(arg_filename->data.c_str(), O_RDONLY)); if (fd == -1) { - ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data, + ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } RangeSet blk0 {1 /*count*/, 1/*size*/, std::vector<size_t> {0, 1}/*position*/}; std::vector<uint8_t> block0_buffer(BLOCKSIZE); if (ReadBlocks(blk0, block0_buffer, fd) == -1) { - ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data, + ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout @@ -1827,7 +1794,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) uiPrintf(state, "Last remount happened on %s", ctime(&mount_time)); } - return StringValue(strdup("t")); + return StringValue("t"); } @@ -1839,40 +1806,40 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ return NULL; } - std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue); + std::unique_ptr<Value> filename(arg_filename); + std::unique_ptr<Value> ranges(arg_ranges); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (ranges->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } // Output notice to log when recover is attempted - fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data); + fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data.c_str()); // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read - fec::io fh(filename->data, O_RDWR); + fec::io fh(filename->data.c_str(), O_RDWR); if (!fh) { - ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data, + ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } if (!fh.has_ecc() || !fh.has_verity()) { ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors"); - return StringValue(strdup("")); + return StringValue(""); } fec_status status; if (!fh.get_status(status)) { ErrorAbort(state, kLibfecFailure, "failed to read FEC status"); - return StringValue(strdup("")); + return StringValue(""); } RangeSet rs; @@ -1889,8 +1856,8 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) { ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s", - filename->data, j, strerror(errno)); - return StringValue(strdup("")); + filename->data.c_str(), j, strerror(errno)); + return StringValue(""); } // If we want to be able to recover from a situation where rewriting a corrected @@ -1905,8 +1872,8 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ // read and check if the errors field value has increased. } } - fprintf(stderr, "...%s image recovered successfully.\n", filename->data); - return StringValue(strdup("t")); + fprintf(stderr, "...%s image recovered successfully.\n", filename->data.c_str()); + return StringValue("t"); } void RegisterBlockImageFunctions() { |