diff options
| -rw-r--r-- | compiler/image_writer.cc | 36 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file.cc | 19 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file.h | 4 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file_test.cc | 28 | ||||
| -rw-r--r-- | runtime/gc/space/image_space.cc | 63 |
5 files changed, 94 insertions, 56 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 871435b85f..b1b971f6ba 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -266,17 +266,9 @@ bool ImageWriter::Write(int image_fd, << PrettyDuration(NanoTime() - compress_start_time); } - // Write header first, as uncompressed. - image_header->data_size_ = data_size; - if (!image_file->WriteFully(image_info.image_->Begin(), sizeof(ImageHeader))) { - PLOG(ERROR) << "Failed to write image file header " << image_filename; - image_file->Erase(); - return false; - } - // Write out the image + fields + methods. const bool is_compressed = compressed_data != nullptr; - if (!image_file->WriteFully(image_data_to_write, data_size)) { + if (!image_file->PwriteFully(image_data_to_write, data_size, sizeof(ImageHeader))) { PLOG(ERROR) << "Failed to write image file data " << image_filename; image_file->Erase(); return false; @@ -291,13 +283,33 @@ bool ImageWriter::Write(int image_fd, if (!is_compressed) { CHECK_EQ(bitmap_position_in_file, bitmap_section.Offset()); } - if (!image_file->Write(reinterpret_cast<char*>(image_info.image_bitmap_->Begin()), - bitmap_section.Size(), - bitmap_position_in_file)) { + if (!image_file->PwriteFully(reinterpret_cast<char*>(image_info.image_bitmap_->Begin()), + bitmap_section.Size(), + bitmap_position_in_file)) { PLOG(ERROR) << "Failed to write image file " << image_filename; image_file->Erase(); return false; } + + int err = image_file->Flush(); + if (err < 0) { + PLOG(ERROR) << "Failed to flush image file " << image_filename << " with result " << err; + image_file->Erase(); + return false; + } + + // Write header last in case the compiler gets killed in the middle of image writing. + // We do not want to have a corrupted image with a valid header. + // The header is uncompressed since it contains whether the image is compressed or not. + image_header->data_size_ = data_size; + if (!image_file->PwriteFully(reinterpret_cast<char*>(image_info.image_->Begin()), + sizeof(ImageHeader), + 0)) { + PLOG(ERROR) << "Failed to write image file header " << image_filename; + image_file->Erase(); + return false; + } + CHECK_EQ(bitmap_position_in_file + bitmap_section.Size(), static_cast<size_t>(image_file->GetLength())); if (image_file->FlushCloseOrErase() != 0) { diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index 4672948f31..e4097dd3de 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -234,21 +234,34 @@ bool FdFile::PreadFully(void* buffer, size_t byte_count, size_t offset) { return ReadFullyGeneric<pread>(fd_, buffer, byte_count, offset); } -bool FdFile::WriteFully(const void* buffer, size_t byte_count) { +template <bool kUseOffset> +bool FdFile::WriteFullyGeneric(const void* buffer, size_t byte_count, size_t offset) { DCHECK(!read_only_mode_); - const char* ptr = static_cast<const char*>(buffer); moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file."); + DCHECK(kUseOffset || offset == 0u); + const char* ptr = static_cast<const char*>(buffer); while (byte_count > 0) { - ssize_t bytes_written = TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); + ssize_t bytes_written = kUseOffset + ? TEMP_FAILURE_RETRY(pwrite(fd_, ptr, byte_count, offset)) + : TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); if (bytes_written == -1) { return false; } byte_count -= bytes_written; // Reduce the number of remaining bytes. ptr += bytes_written; // Move the buffer forward. + offset += static_cast<size_t>(bytes_written); } return true; } +bool FdFile::PwriteFully(const void* buffer, size_t byte_count, size_t offset) { + return WriteFullyGeneric<true>(buffer, byte_count, offset); +} + +bool FdFile::WriteFully(const void* buffer, size_t byte_count) { + return WriteFullyGeneric<false>(buffer, byte_count, 0u); +} + bool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) { DCHECK(!read_only_mode_); off_t off = static_cast<off_t>(offset); diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h index 8040afe9b7..16cd44f4ef 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/runtime/base/unix_file/fd_file.h @@ -79,6 +79,7 @@ class FdFile : public RandomAccessFile { bool ReadFully(void* buffer, size_t byte_count) WARN_UNUSED; bool PreadFully(void* buffer, size_t byte_count, size_t offset) WARN_UNUSED; bool WriteFully(const void* buffer, size_t byte_count) WARN_UNUSED; + bool PwriteFully(const void* buffer, size_t byte_count, size_t offset) WARN_UNUSED; // Copy data from another file. bool Copy(FdFile* input_file, int64_t offset, int64_t size); @@ -119,6 +120,9 @@ class FdFile : public RandomAccessFile { GuardState guard_state_; private: + template <bool kUseOffset> + bool WriteFullyGeneric(const void* buffer, size_t byte_count, size_t offset); + int fd_; std::string file_path_; bool auto_close_; diff --git a/runtime/base/unix_file/fd_file_test.cc b/runtime/base/unix_file/fd_file_test.cc index ecf607c892..9bc87e5bb9 100644 --- a/runtime/base/unix_file/fd_file_test.cc +++ b/runtime/base/unix_file/fd_file_test.cc @@ -110,6 +110,34 @@ TEST_F(FdFileTest, ReadFullyWithOffset) { ASSERT_EQ(file.Close(), 0); } +TEST_F(FdFileTest, ReadWriteFullyWithOffset) { + // New scratch file, zero-length. + art::ScratchFile tmp; + FdFile file; + ASSERT_TRUE(file.Open(tmp.GetFilename(), O_RDWR)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + + const char* test_string = "This is a test string"; + size_t length = strlen(test_string) + 1; + const size_t offset = 12; + std::unique_ptr<char[]> offset_read_string(new char[length]); + std::unique_ptr<char[]> read_string(new char[length]); + + // Write scratch data to file that we can read back into. + EXPECT_TRUE(file.PwriteFully(test_string, length, offset)); + ASSERT_EQ(file.Flush(), 0); + + // Test reading both the offsets. + EXPECT_TRUE(file.PreadFully(&offset_read_string[0], length, offset)); + EXPECT_STREQ(test_string, &offset_read_string[0]); + + EXPECT_TRUE(file.PreadFully(&read_string[0], length, 0u)); + EXPECT_NE(memcmp(&read_string[0], test_string, length), 0); + + ASSERT_EQ(file.Close(), 0); +} + TEST_F(FdFileTest, Copy) { art::ScratchFile src_tmp; FdFile src; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index a4e558728e..9ecd391e4d 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1535,50 +1535,31 @@ void ImageSpace::CreateMultiImageLocations(const std::string& input_image_file_n // images[0] is f/c/d/e.art // ---------------------------------------------- // images[1] is g/h/i/j.art -> /a/b/h/i/j.art - - // Derive pattern. - std::vector<std::string> left; - Split(input_image_file_name, '/', &left); - std::vector<std::string> right; - Split(images[0], '/', &right); - - size_t common = 1; - while (common < left.size() && common < right.size()) { - if (left[left.size() - common - 1] != right[right.size() - common - 1]) { - break; - } - common++; - } - - std::vector<std::string> prefix_vector(left.begin(), left.end() - common); - std::string common_prefix = Join(prefix_vector, '/'); - if (!common_prefix.empty() && common_prefix[0] != '/' && input_image_file_name[0] == '/') { - common_prefix = "/" + common_prefix; - } + const std::string& first_image = images[0]; + // Length of common suffix. + size_t common = 0; + while (common < input_image_file_name.size() && + common < first_image.size() && + *(input_image_file_name.end() - common - 1) == *(first_image.end() - common - 1)) { + ++common; + } + // We want to replace the prefix of the input image with the prefix of the boot class path. + // This handles the case where the image file contains @ separators. + // Example image_file_name is oats/system@framework@boot.art + // images[0] is .../arm/boot.art + // means that the image name prefix will be oats/system@framework@ + // so that the other images are openable. + const size_t old_prefix_length = first_image.size() - common; + const std::string new_prefix = input_image_file_name.substr( + 0, + input_image_file_name.size() - common); // Apply pattern to images[1] .. images[n]. for (size_t i = 1; i < images.size(); ++i) { - std::string image = images[i]; - - size_t rslash = std::string::npos; - for (size_t j = 0; j < common; ++j) { - if (rslash != std::string::npos) { - rslash--; - } - - rslash = image.rfind('/', rslash); - if (rslash == std::string::npos) { - rslash = 0; - } - if (rslash == 0) { - break; - } - } - std::string image_part = image.substr(rslash); - - std::string new_image = common_prefix + (StartsWith(image_part, "/") ? "" : "/") + - image_part; - image_file_names->push_back(new_image); + const std::string& image = images[i]; + CHECK_GT(image.length(), old_prefix_length); + std::string suffix = image.substr(old_prefix_length); + image_file_names->push_back(new_prefix + suffix); } } |