Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 776ea9b4 authored by Tao Bao's avatar Tao Bao Committed by android-build-merger
Browse files

Merge "applypatch: Use unique_fd to avoid leaking FDs." am: 2e5cf3c0

am: d2cd8b4d

Change-Id: I57228be65dfc37f853c3902ad8c5f65c0e3f1018
parents 29dc892c d2cd8b4d
Loading
Loading
Loading
Loading
+270 −282
Original line number Diff line number Diff line
@@ -194,17 +194,16 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
// Save the contents of the given FileContents object under the given
// filename.  Return 0 on success.
int SaveFileContents(const char* filename, const FileContents* file) {
    int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
    if (fd < 0) {
  unique_fd fd(ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
  if (fd == -1) {
    printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
    return -1;
  }

  ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
  if (bytes_written != static_cast<ssize_t>(file->data.size())) {
        printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n",
               filename, bytes_written, file->data.size(), strerror(errno));
        ota_close(fd);
    printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written,
           file->data.size(), strerror(errno));
    return -1;
  }
  if (ota_fsync(fd) != 0) {
@@ -232,24 +231,22 @@ int SaveFileContents(const char* filename, const FileContents* file) {
// "EMMC:<partition_device>[:...]". The target name
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
  std::vector<std::string> pieces = android::base::Split(std::string(target), ":");

int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) {
  std::vector<std::string> pieces = android::base::Split(target, ":");
  if (pieces.size() < 2 || pieces[0] != "EMMC") {
    printf("WriteToPartition called with bad target (%s)\n", target);
    printf("WriteToPartition called with bad target (%s)\n", target.c_str());
    return -1;
  }

  const char* partition = pieces[1].c_str();

  size_t start = 0;
  bool success = false;
  int fd = ota_open(partition, O_RDWR | O_SYNC);
  if (fd < 0) {
  unique_fd fd(ota_open(partition, O_RDWR));
  if (fd == -1) {
    printf("failed to open %s: %s\n", partition, strerror(errno));
    return -1;
  }

  size_t start = 0;
  bool success = false;
  for (size_t attempt = 0; attempt < 2; ++attempt) {
    if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
      printf("failed seek on %s: %s\n", partition, strerror(errno));
@@ -268,23 +265,23 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
    }

    if (ota_fsync(fd) != 0) {
      printf("failed to sync to %s (%s)\n", partition, strerror(errno));
      printf("failed to sync to %s: %s\n", partition, strerror(errno));
      return -1;
    }
    if (ota_close(fd) != 0) {
      printf("failed to close %s (%s)\n", partition, strerror(errno));
      printf("failed to close %s: %s\n", partition, strerror(errno));
      return -1;
    }

    fd = ota_open(partition, O_RDONLY);
    if (fd < 0) {
      printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
    fd.reset(ota_open(partition, O_RDONLY));
    if (fd == -1) {
      printf("failed to reopen %s for verify: %s\n", partition, strerror(errno));
      return -1;
    }

    // Drop caches so our subsequent verification read won't just be reading the cache.
    sync();
    int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY);
    unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
    if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
      printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
    } else {
@@ -293,7 +290,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
    ota_close(dc);
    sleep(1);

    // verify
    // Verify.
    if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
      printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno));
      return -1;
@@ -318,8 +315,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
          return -1;
        }
        if (static_cast<size_t>(read_count) < to_read) {
          printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read,
                 strerror(errno));
          printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read);
        }
        so_far += read_count;
      }
@@ -343,8 +339,8 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
    return -1;
  }

  if (ota_close(fd) != 0) {
    printf("error closing %s (%s)\n", partition, strerror(errno));
  if (ota_close(fd) == -1) {
    printf("error closing %s: %s\n", partition, strerror(errno));
    return -1;
  }
  sync();
@@ -595,7 +591,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
  }

  std::string target_str(target_filename);

  std::vector<std::string> pieces = android::base::Split(target_str, ":");
  if (pieces.size() != 2 || pieces[0] != "EMMC") {
    printf("invalid target name \"%s\"", target_filename);
@@ -641,15 +636,6 @@ static int GenerateTarget(FileContents* source_file,
                          const uint8_t target_sha1[SHA_DIGEST_LENGTH],
                          size_t target_size,
                          const Value* bonus_data) {
    int retry = 1;
    SHA_CTX ctx;
    std::string memory_sink_str;
    FileContents* source_to_use;
    int made_copy = 0;

    bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
    const std::string tmp_target_filename = std::string(target_filename) + ".patch";

  // assume that target_filename (eg "/system/app/Foo.apk") is located
  // on the same filesystem as its top-level directory ("/system").
  // We need something that exists for calling statfs().
@@ -659,18 +645,21 @@ static int GenerateTarget(FileContents* source_file,
    target_fs.resize(slash_pos);
  }

  FileContents* source_to_use;
  const Value* patch;
    if (source_patch_value != NULL) {
  if (source_patch_value != nullptr) {
    source_to_use = source_file;
    patch = source_patch_value;
  } else {
    source_to_use = copy_file;
    patch = copy_patch_value;
  }

  if (patch->type != VAL_BLOB) {
    printf("patch is not a blob\n");
    return 1;
  }

  const char* header = &patch->data[0];
  size_t header_bytes_read = patch->data.size();
  bool use_bsdiff = false;
@@ -683,9 +672,15 @@ static int GenerateTarget(FileContents* source_file,
    return 1;
  }

  bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
  const std::string tmp_target_filename = std::string(target_filename) + ".patch";

  int retry = 1;
  bool made_copy = false;
  SHA_CTX ctx;
  std::string memory_sink_str;  // Don't need to reserve space.
  do {
        // Is there enough room in the target filesystem to hold the patched
        // file?
    // Is there enough room in the target filesystem to hold the patched file?

    if (target_is_partition) {
      // If the target is a partition, we're actually going to
@@ -704,18 +699,17 @@ static int GenerateTarget(FileContents* source_file,
        printf("failed to back up source file\n");
        return 1;
      }
            made_copy = 1;
      made_copy = true;
      retry = 0;
    } else {
            int enough_space = 0;
      bool enough_space = false;
      if (retry > 0) {
        size_t free_space = FreeSpaceForFile(target_fs.c_str());
                enough_space =
                    (free_space > (256 << 10)) &&          // 256k (two-block) minimum
        enough_space = (free_space > (256 << 10)) &&          // 256k (two-block) minimum
                       (free_space > (target_size * 3 / 2));  // 50% margin of error
        if (!enough_space) {
                    printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n",
                           target_size, free_space, retry, enough_space);
          printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size,
                 free_space, retry, enough_space);
        }
      }

@@ -723,7 +717,7 @@ static int GenerateTarget(FileContents* source_file,
        retry = 0;
      }

            if (!enough_space && source_patch_value != NULL) {
      if (!enough_space && source_patch_value != nullptr) {
        // Using the original source, but not enough free space.  First
        // copy the source file to cache, then delete it from the original
        // location.
@@ -745,7 +739,7 @@ static int GenerateTarget(FileContents* source_file,
          printf("failed to back up source file\n");
          return 1;
        }
                made_copy = 1;
        made_copy = true;
        unlink(source_filename);

        size_t free_space = FreeSpaceForFile(target_fs.c_str());
@@ -753,48 +747,43 @@ static int GenerateTarget(FileContents* source_file,
      }
    }


        SinkFn sink = NULL;
        void* token = NULL;
        int output_fd = -1;
    SinkFn sink = nullptr;
    void* token = nullptr;
    unique_fd output_fd;
    if (target_is_partition) {
      // We store the decoded output in memory.
      sink = MemorySink;
      token = &memory_sink_str;
    } else {
      // We write the decoded output to "<tgt-file>.patch".
            output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
                                 S_IRUSR | S_IWUSR);
            if (output_fd < 0) {
                printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
                       strerror(errno));
      output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
                               S_IRUSR | S_IWUSR));
      if (output_fd == -1) {
        printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno));
        return 1;
      }
      sink = FileSink;
      token = &output_fd;
    }


    SHA1_Init(&ctx);

    int result;
    if (use_bsdiff) {
            result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(),
                                      patch, 0, sink, token, &ctx);
      result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0,
                                sink, token, &ctx);
    } else {
            result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(),
                                     patch, sink, token, &ctx, bonus_data);
      result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink,
                               token, &ctx, bonus_data);
    }

    if (!target_is_partition) {
      if (ota_fsync(output_fd) != 0) {
                printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(),
                       strerror(errno));
        printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
        result = 1;
      }
      if (ota_close(output_fd) != 0) {
                printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(),
                       strerror(errno));
        printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
        result = 1;
      }
    }
@@ -802,7 +791,7 @@ static int GenerateTarget(FileContents* source_file,
    if (result != 0) {
      if (retry == 0) {
        printf("applying patch failed\n");
                return result != 0;
        return 1;
      } else {
        printf("applying patch failed; retrying\n");
      }
@@ -832,13 +821,13 @@ static int GenerateTarget(FileContents* source_file,
      return 1;
    }
  } else {
        // Give the .patch file the same owner, group, and mode of the
        // original source file.
    // Give the .patch file the same owner, group, and mode of the original source file.
    if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
      printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
      return 1;
    }
        if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
    if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid,
              source_to_use->st.st_gid) != 0) {
      printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
      return 1;
    }
@@ -850,8 +839,7 @@ static int GenerateTarget(FileContents* source_file,
    }
  }

    // If this run of applypatch created the copy, and we're here, we
    // can delete it.
  // If this run of applypatch created the copy, and we're here, we can delete it.
  if (made_copy) {
    unlink(CACHE_TEMP_SOURCE);
  }
+10 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <sys/stat.h>

#include <android-base/unique_fd.h>

#define OTAIO_CACHE_FNAME "/cache/saved.file"

void ota_set_fault_files();
@@ -50,4 +52,12 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte);

int ota_fsync(int fd);

struct OtaCloser {
  static void Close(int fd) {
    ota_close(fd);
  }
};

using unique_fd = android::base::unique_fd_impl<OtaCloser>;

#endif