blob: d79e3c2750a0f1746edc66b7207b4088a834ce44 [file] [log] [blame]
// Copyright 2015 The Chromium 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 <fcntl.h>
#include <unistd.h>
#include <vector>
#include "base/files/file_util.h"
#include "mojo/services/files/interfaces/files.mojom.h"
#include "mojo/tools/embed/data.h"
namespace nacl {
int DataToTempFileDescriptor(const mojo::embed::Data& data) {
base::FilePath path;
CHECK(CreateTemporaryFile(&path)) << "Could not create temp file for data";
int fd = open(path.value().c_str(), O_RDWR);
CHECK_GE(fd, 0) << "Could not open temporary file";
size_t bytes_left_to_write = data.size;
const char* source = data.data;
while (bytes_left_to_write > 0) {
ssize_t bytes = HANDLE_EINTR(write(fd, source, bytes_left_to_write));
CHECK_GE(bytes, 0) << "Error writing data to temp file";
bytes_left_to_write -= bytes;
source += bytes;
}
CHECK(!unlink(path.value().c_str())) << "Could not unlink temporary file";
return fd;
}
int MojoFileToTempFileDescriptor(mojo::files::FilePtr mojo_file) {
base::FilePath path;
CHECK(CreateTemporaryFile(&path)) << "Could not create temp file for data";
int fd = open(path.value().c_str(), O_RDWR);
CHECK_GE(fd, 0) << "Could not open temporary file";
CHECK(!unlink(path.value().c_str())) << "Could not unlink temporary file";
mojo::files::Error error = mojo::files::Error::INTERNAL;
mojo::files::FileInformationPtr file_info;
mojo_file->Stat([&error, &file_info](mojo::files::Error e,
mojo::files::FileInformationPtr f) {
error = e;
file_info = f.Pass();
});
CHECK(mojo_file.WaitForIncomingResponse());
CHECK_EQ(mojo::files::Error::OK, error);
CHECK(!file_info.is_null());
size_t bytes_left_to_write = file_info->size;
int64_t offset = 0;
static const size_t kBufferSize = 0x100000;
while (bytes_left_to_write > 0) {
size_t bytes_to_read = kBufferSize;
if (bytes_left_to_write < kBufferSize)
bytes_to_read = bytes_left_to_write;
mojo::Array<uint8_t> buf;
mojo_file->Read(
bytes_to_read, offset, mojo::files::Whence::FROM_START,
[&error, &buf](mojo::files::Error e, mojo::Array<uint8_t> b) {
error = e;
buf = b.Pass();
});
CHECK(mojo_file.WaitForIncomingResponse());
ssize_t bytes = HANDLE_EINTR(write(fd, buf.data(), bytes_to_read));
CHECK_GE(bytes, 0) << "Error writing data to temp file";
bytes_left_to_write -= bytes;
offset += bytes;
}
// Close the mojo file supplied
mojo_file->Close([&error](mojo::files::Error e) { error = e; });
CHECK(mojo_file.WaitForIncomingResponse());
CHECK_EQ(mojo::files::Error::OK, error);
return fd;
}
void FileDescriptorToMojoFile(int fd, mojo::files::FilePtr mojo_file) {
mojo::files::Error error = mojo::files::Error::INTERNAL;
static const size_t kBufferSize = 0x100000;
scoped_ptr<uint8_t[]> buf(new uint8_t[kBufferSize]);
int64_t offset = 0;
while (true) {
ssize_t bytes = HANDLE_EINTR(read(fd, buf.get(), kBufferSize));
CHECK_GE(bytes, 0);
if (bytes == 0)
break;
std::vector<uint8_t> source_v;
source_v.assign(buf.get(), buf.get() + bytes);
ssize_t num_bytes_written = 0;
mojo_file->Write(
mojo::Array<uint8_t>::From(source_v), offset,
mojo::files::Whence::FROM_START,
[&error, &num_bytes_written](mojo::files::Error e, ssize_t n) {
error = e;
num_bytes_written = n;
});
CHECK(mojo_file.WaitForIncomingResponse());
CHECK_EQ(mojo::files::Error::OK, error);
CHECK_EQ(num_bytes_written, bytes);
offset += bytes;
}
mojo_file->Close([&error](mojo::files::Error e) { error = e; });
CHECK(mojo_file.WaitForIncomingResponse());
CHECK_EQ(mojo::files::Error::OK, error);
}
} // namespace nacl