Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RRawFileUnix.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Jakob Blomer
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "ROOT/RRawFileUnix.hxx"
13 #include "ROOT/RMakeUnique.hxx"
14 
15 #include "TError.h"
16 
17 #include <cerrno>
18 #include <cstring>
19 #include <stdexcept>
20 #include <string>
21 #include <utility>
22 
23 #include <fcntl.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 namespace {
29 constexpr int kDefaultBlockSize = 4096; // If fstat() does not provide a block size hint, use this value instead
30 } // anonymous namespace
31 
32 ROOT::Internal::RRawFileUnix::RRawFileUnix(std::string_view url, ROptions options)
33  : RRawFile(url, options), fFileDes(-1)
34 {
35 }
36 
37 ROOT::Internal::RRawFileUnix::~RRawFileUnix()
38 {
39  if (fFileDes >= 0)
40  close(fFileDes);
41 }
42 
43 std::unique_ptr<ROOT::Internal::RRawFile> ROOT::Internal::RRawFileUnix::Clone() const
44 {
45  return std::make_unique<RRawFileUnix>(fUrl, fOptions);
46 }
47 
48 std::uint64_t ROOT::Internal::RRawFileUnix::GetSizeImpl()
49 {
50  struct stat info;
51  int res = fstat(fFileDes, &info);
52  if (res != 0)
53  throw std::runtime_error("Cannot call fstat on '" + fUrl + "', error: " + std::string(strerror(errno)));
54  return info.st_size;
55 }
56 
57 void *ROOT::Internal::RRawFileUnix::MapImpl(size_t nbytes, std::uint64_t offset, std::uint64_t &mapdOffset)
58 {
59  static std::uint64_t szPageBitmap = sysconf(_SC_PAGESIZE) - 1;
60  mapdOffset = offset & ~szPageBitmap;
61  nbytes += offset & szPageBitmap;
62 
63  void *result = mmap(nullptr, nbytes, PROT_READ, MAP_PRIVATE, fFileDes, mapdOffset);
64  if (result == MAP_FAILED)
65  throw std::runtime_error(std::string("Cannot perform memory mapping: ") + strerror(errno));
66  return result;
67 }
68 
69 void ROOT::Internal::RRawFileUnix::OpenImpl()
70 {
71  fFileDes = open(GetLocation(fUrl).c_str(), O_RDONLY);
72  if (fFileDes < 0) {
73  throw std::runtime_error("Cannot open '" + fUrl + "', error: " + std::string(strerror(errno)));
74  }
75 
76  if (fOptions.fBlockSize >= 0)
77  return;
78 
79  struct stat info;
80  int res = fstat(fFileDes, &info);
81  if (res != 0) {
82  throw std::runtime_error("Cannot call fstat on '" + fUrl + "', error: " + std::string(strerror(errno)));
83  }
84  if (info.st_blksize > 0) {
85  fOptions.fBlockSize = info.st_blksize;
86  } else {
87  fOptions.fBlockSize = kDefaultBlockSize;
88  }
89 }
90 
91 size_t ROOT::Internal::RRawFileUnix::ReadAtImpl(void *buffer, size_t nbytes, std::uint64_t offset)
92 {
93  size_t total_bytes = 0;
94  while (nbytes) {
95  ssize_t res = pread(fFileDes, buffer, nbytes, offset);
96  if (res < 0) {
97  if (errno == EINTR)
98  continue;
99  throw std::runtime_error("Cannot read from '" + fUrl + "', error: " + std::string(strerror(errno)));
100  } else if (res == 0) {
101  return total_bytes;
102  }
103  R__ASSERT(static_cast<size_t>(res) <= nbytes);
104  buffer = reinterpret_cast<unsigned char *>(buffer) + res;
105  nbytes -= res;
106  total_bytes += res;
107  offset += res;
108  }
109  return total_bytes;
110 }
111 
112 void ROOT::Internal::RRawFileUnix::UnmapImpl(void *region, size_t nbytes)
113 {
114  int rv = munmap(region, nbytes);
115  if (rv != 0)
116  throw std::runtime_error(std::string("Cannot remove memory mapping: ") + strerror(errno));
117 }