blob: 8302e599a23d236ec0ceed96a5b6ecb3bdd5d975 [file] [log] [blame]
Sasha Smundak06a12e52016-07-15 17:35:51 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef BAZEL_SRC_TOOLS_SINGLEJAR_MAPPED_FILE_H_
16#define BAZEL_SRC_TOOLS_SINGLEJAR_MAPPED_FILE_H_ 1
17
18#include <fcntl.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <unistd.h>
22
23#include "src/tools/singlejar/diag.h"
24
25/*
26 * A mapped read-only file with auto closing.
27 *
28 * MappedFile::Open maps a file with specified name to memory as read-only.
29 * It is assumed that the address space is large enough for that.
30 * MappedFile::Close deletes the mapping. The destructor calls it, too.
31 * A predictable set of methods provide conversion between file offsets and
32 * mapped addresses, returns map size, etc.
33 *
34 * The implementation is 64-bit Linux or OSX specific.
35 */
36#if !((defined(__linux) || defined(__APPLE__)) && __SIZEOF_POINTER__ == 8)
37#error This code for 64 bit Unix.
38#endif
39
40class MappedFile {
41 public:
42 MappedFile() : mapped_start_(nullptr), mapped_end_(nullptr), fd_(-1) {}
43
44 ~MappedFile() { Close(); }
45
46 bool Open(const char *filename) {
47 if (is_open()) {
48 diag_errx(1, "%s:%d: This instance is already open", __FILE__, __LINE__);
49 }
50 if ((fd_ = open(filename, O_RDONLY)) < 0) {
51 diag_warn("%s:%d: open %s:", __FILE__, __LINE__, filename);
52 return false;
53 }
54 // Map the file, even if it is empty (in which case allocate 1 byte to it).
55 struct stat st;
56 if (fstat(fd_, &st) ||
57 (mapped_start_ = static_cast<char *>(
58 mmap(nullptr, st.st_size ? st.st_size : 1, PROT_READ, MAP_PRIVATE,
59 fd_, 0))) == MAP_FAILED) {
60 diag_warn("%s:%d: mmap %s:", __FILE__, __LINE__, filename);
61 close(fd_);
62 fd_ = -1;
63 return false;
64 }
65 mapped_end_ = mapped_start_ + st.st_size;
66 return true;
67 }
68
69 void Close() {
70 if (is_open()) {
71 munmap(mapped_start_, mapped_end_ - mapped_start_);
72 mapped_start_ = mapped_end_ = nullptr;
73 close(fd_);
74 fd_ = -1;
75 }
76 }
77
78 bool mapped(const void *addr) const {
79 return mapped_start_ <= addr && addr < mapped_end_;
80 }
81
82 const char *start() const { return mapped_start_; }
83 const char *end() const { return mapped_end_; }
84 const char *address(off_t offset) const { return mapped_start_ + offset; }
85 off_t offset(const char *address) const { return address - mapped_start_; }
86 int fd() const { return fd_; }
87 size_t size() const { return mapped_end_ - mapped_start_; }
88 bool is_open() { return fd_ >= 0; }
89
90 private:
91 char *mapped_start_;
92 char *mapped_end_;
93 int fd_;
94};
95
96#endif // BAZEL_SRC_TOOLS_SINGLEJAR_MAPPED_FILE_H_