| Index: src/platform/memento_softwareupdate/split_write.cc
|
| diff --git a/src/platform/memento_softwareupdate/split_write.cc b/src/platform/memento_softwareupdate/split_write.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e7a03dc4ff887d7e8b6235a6307cff018cc3d160
|
| --- /dev/null
|
| +++ b/src/platform/memento_softwareupdate/split_write.cc
|
| @@ -0,0 +1,137 @@
|
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <sys/stat.h>
|
| +#include <sys/types.h>
|
| +
|
| +#include <endian.h>
|
| +#include <fcntl.h>
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <unistd.h>
|
| +
|
| +#include <algorithm>
|
| +
|
| +namespace {
|
| +
|
| +class ScopedFileDescriptorCloser {
|
| + public:
|
| + ScopedFileDescriptorCloser(int fd) : fd_(fd) {}
|
| + ~ScopedFileDescriptorCloser() {
|
| + close(fd_);
|
| + }
|
| + private:
|
| + const int fd_;
|
| +};
|
| +
|
| +const int kBufSize = 1024 * 1024 * 4; // 4 MiB
|
| +
|
| +// This program takes two files as args. It will open both and write the
|
| +// first part of stdin into the first file, the second part into the second
|
| +// file. The first 8 bytes contain the unsigned big-endian count of bytes
|
| +// that should go to the first file. Following bytes go to the second file.
|
| +
|
| +// Writes all bytes to fd. Exits on error.
|
| +void write_all(int fd, const void *buf, size_t count) {
|
| + const char* c_buf = static_cast<const char*>(buf);
|
| + size_t written = 0;
|
| + while (written < count) {
|
| + ssize_t rc = write(fd, c_buf + written, count - written);
|
| + if (rc < 0) {
|
| + perror("write");
|
| + exit(1);
|
| + }
|
| + written += static_cast<size_t>(rc);
|
| + }
|
| +}
|
| +
|
| +// Returns bytes read, which may be short on EOF. Exits on error.
|
| +size_t read_all(int fd, void* buf, size_t count) {
|
| + char* c_buf = static_cast<char*>(buf);
|
| + size_t bytes_read = 0;
|
| + while (bytes_read < count) {
|
| + ssize_t rc = read(fd, c_buf + bytes_read, count - bytes_read);
|
| + if (rc == 0) {
|
| + break;
|
| + }
|
| + if (rc < 0) {
|
| + perror("read");
|
| + exit(1);
|
| + }
|
| + bytes_read += static_cast<size_t>(rc);
|
| + }
|
| + return bytes_read;
|
| +}
|
| +
|
| +void usage(char* argv0) {
|
| + fprintf(stderr, "Usage: %s first_file second_file\n", argv0);
|
| + exit(1);
|
| +}
|
| +
|
| +// Returns valid fd or exits program.
|
| +int open_file(const char* path) {
|
| + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
| + if (fd < 0) {
|
| + perror("open");
|
| + fprintf(stderr, "failed to open %s\n", path);
|
| + exit(1);
|
| + }
|
| +}
|
| +
|
| +typedef long long int64;
|
| +// Compile assert sizeof(int64) == 8:
|
| +char int64_8_bytes_long[(sizeof(int64) == 8) - 1];
|
| +
|
| +} // namespace {}
|
| +
|
| +int main(int argc, char** argv) {
|
| + if (argc != 3) {
|
| + usage(argv[0]);
|
| + }
|
| + const int fd1 = open_file(argv[1]);
|
| + ScopedFileDescriptorCloser fd1_closer(fd1);
|
| + const int fd2 = open_file(argv[2]);
|
| + ScopedFileDescriptorCloser fd2_closer(fd2);
|
| + const int fd_in = 0; // stdin
|
| + char* const buf = static_cast<char*>(malloc(kBufSize));
|
| + if (buf == NULL) {
|
| + fprintf(stderr, "malloc on buffer failed.\n");
|
| + return 1;
|
| + }
|
| + int64 first_file_size = 0;
|
| + size_t bytes_read =
|
| + read_all(fd_in, &first_file_size, sizeof(first_file_size));
|
| + if (bytes_read < sizeof(first_file_size)) {
|
| + fprintf(stderr, "short read on first file size.\n");
|
| + return 1;
|
| + }
|
| + first_file_size = be64toh(first_file_size);
|
| + int64 first_bytes_written = 0;
|
| + while (first_bytes_written < first_file_size) {
|
| + size_t chunk_size = std::min(first_file_size - first_bytes_written,
|
| + static_cast<int64>(kBufSize));
|
| + chunk_size = read_all(fd_in, buf, chunk_size);
|
| + if (chunk_size == 0) {
|
| + // All data went to first partition, none left for second.
|
| + // This is okay only if the first file size is exactl how much we've
|
| + // written thus far
|
| + if (first_file_size == first_bytes_written) {
|
| + return 0;
|
| + } else {
|
| + fprintf(stderr, "file appears truncated.\n");
|
| + return 1;
|
| + }
|
| + }
|
| + write_all(fd1, buf, chunk_size);
|
| + first_bytes_written += chunk_size;
|
| + }
|
| + // Do the rest on the second file
|
| + for (;;) {
|
| + size_t chunk_size = read_all(fd_in, buf, kBufSize);
|
| + if (chunk_size == 0)
|
| + break;
|
| + write_all(fd2, buf, chunk_size);
|
| + }
|
| + return 0;
|
| +}
|
|
|