Skip to content

Commit

Permalink
Encapsulate file mapping in preparation for providing a Windows imple…
Browse files Browse the repository at this point in the history
…mentation.

Progress on #276.

--
MOS_MIGRATED_REVID=114740700
  • Loading branch information
lberki authored and damienmg committed Feb 16, 2016
1 parent 0e5be36 commit 2573376
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 83 deletions.
6 changes: 5 additions & 1 deletion third_party/ijar/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ filegroup(

cc_library(
name = "zip",
srcs = ["zip.cc"],
srcs = [
"mapped_file_unix.cc",
"zip.cc",
],
hdrs = [
"common.h",
"mapped_file.h",
"zip.h",
],
# TODO(bazel-team): we should replace the -lz flag, it is non-hermetic.
Expand Down
82 changes: 82 additions & 0 deletions third_party/ijar/mapped_file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef INCLUDED_THIRD_PARTY_IJAR_MAPPED_FILE_H
#define INCLUDED_THIRD_PARTY_IJAR_MAPPED_FILE_H

#include "third_party/ijar/common.h"

namespace devtools_ijar {

class MappedInputFileImpl;
class MappedOutputFileImpl;

// A memory mapped input file.
class MappedInputFile {
private:
MappedInputFileImpl *impl_;

protected:
const char* errmsg_;
bool opened_;
u1* buffer_;
size_t length_;

public:
MappedInputFile(const char* name);
virtual ~MappedInputFile();

// If opening the file succeeded or not.
bool Opened() const { return opened_; }

// Description of the last error that happened.
const char* Error() const { return errmsg_; }

// The mapped contents of the file.
u1* Buffer() const { return buffer_ ; }

// The length of the file.
size_t Length() const { return length_; }

// Unmap a given number of bytes from the beginning of the file.
void Discard(size_t bytes);
int Close();
};

class MappedOutputFile {
private:
MappedOutputFileImpl *impl_;

protected:
const char* errmsg_;
bool opened_;
u1* buffer_;

public:
MappedOutputFile(const char* name, u8 estimated_size);
virtual ~MappedOutputFile();

// If opening the file succeeded or not.
bool Opened() const { return opened_; }

// Description of the last error that happened.
const char* Error() const { return errmsg_; }

// The mapped contents of the file.
u1* Buffer() const { return buffer_; }
int Close(int size);
};

} // namespace devtools_ijar
#endif
147 changes: 147 additions & 0 deletions third_party/ijar/mapped_file_unix.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

#include <algorithm>

#include "third_party/ijar/mapped_file.h"

#define MAX_ERROR 2048

namespace devtools_ijar {

static char errmsg[MAX_ERROR];

struct MappedInputFileImpl {
size_t discarded_;
int fd_;
};

MappedInputFile::MappedInputFile(const char* name) {
impl_ = NULL;
opened_ = false;

int fd = open(name, O_RDONLY);
if (fd < 0) {
snprintf(errmsg, MAX_ERROR, "open(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

off_t length = lseek(fd, 0, SEEK_END);
if (length < 0) {
snprintf(errmsg, MAX_ERROR, "lseek(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

void* buffer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (buffer == MAP_FAILED) {
snprintf(errmsg, MAX_ERROR, "mmap(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

impl_ = new MappedInputFileImpl();
impl_->fd_ = fd;
impl_->discarded_ = 0;
buffer_ = reinterpret_cast<u1*>(buffer);
length_ = length;
opened_ = true;
}

MappedInputFile::~MappedInputFile() {
delete impl_;
}

void MappedInputFile::Discard(size_t bytes) {
munmap(buffer_ + impl_->discarded_, bytes);
impl_->discarded_ += bytes;
}

int MappedInputFile::Close() {
if (close(impl_->fd_) < 0) {
snprintf(errmsg, MAX_ERROR, "close(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}

return 0;
}

struct MappedOutputFileImpl {
int fd_;
};

MappedOutputFile::MappedOutputFile(const char* name, u8 estimated_size) {
impl_ = NULL;
opened_ = false;
int fd = open(name, O_CREAT|O_RDWR|O_TRUNC, 0644);
if (fd < 0) {
snprintf(errmsg, MAX_ERROR, "open(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

// Create mmap-able sparse file
if (ftruncate(fd, estimated_size) < 0) {
snprintf(errmsg, MAX_ERROR, "ftruncate(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

// Ensure that any buffer overflow in JarStripper will result in
// SIGSEGV or SIGBUS by over-allocating beyond the end of the file.
size_t mmap_length = std::min(estimated_size + sysconf(_SC_PAGESIZE),
(u8) std::numeric_limits<size_t>::max());
void* mapped = mmap(NULL, mmap_length, PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED) {
snprintf(errmsg, MAX_ERROR, "mmap(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}

impl_ = new MappedOutputFileImpl();
impl_->fd_ = fd;
buffer_ = reinterpret_cast<u1*>(mapped);
opened_ = true;
}


MappedOutputFile::~MappedOutputFile() {
delete impl_;
}

int MappedOutputFile::Close(int size) {
if (ftruncate(impl_->fd_, size) < 0) {
snprintf(errmsg, MAX_ERROR, "ftruncate(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}

if (close(impl_->fd_) < 0) {
snprintf(errmsg, MAX_ERROR, "close(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}

return 0;
}

} // namespace devtools_ijar

0 comments on commit 2573376

Please sign in to comment.