~louis/ubuntu/trusty/clamav/lp799623_fix_logrotate

« back to all changes in this revision

Viewing changes to libclamav/c++/llvm/lib/Support/MemoryBuffer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2010-03-12 11:30:04 UTC
  • mfrom: (0.41.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100312113004-b0fop4bkycszdd0z
Tags: 0.96~rc1+dfsg-0ubuntu1
* New upstream RC - FFE (LP: #537636):
  - Add OfficialDatabaseOnly option to clamav-base.postinst.in
  - Add LocalSocketGroup option to clamav-base.postinst.in
  - Add LocalSocketMode option to clamav-base.postinst.in
  - Add CrossFilesystems option to clamav-base.postinst.in
  - Add ClamukoScannerCount option to clamav-base.postinst.in
  - Add BytecodeSecurity opiton to clamav-base.postinst.in
  - Add DetectionStatsHostID option to clamav-freshclam.postinst.in
  - Add Bytecode option to clamav-freshclam.postinst.in
  - Add MilterSocketGroup option to clamav-milter.postinst.in
  - Add MilterSocketMode option to clamav-milter.postinst.in
  - Add ReportHostname option to clamav-milter.postinst.in
  - Bump libclamav SO version to 6.1.0 in libclamav6.install
  - Drop clamdmon from clamav.examples (no longer shipped by upstream)
  - Drop libclamav.a from libclamav-dev.install (not built by upstream)
  - Update SO version for lintian override for libclamav6
  - Add new Bytecode Testing Tool, usr/bin/clambc, to clamav.install
  - Add build-depends on python and python-setuptools for new test suite
  - Update debian/copyright for the embedded copy of llvm (using the system
    llvm is not currently feasible)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
 
2
//
 
3
//                     The LLVM Compiler Infrastructure
 
4
//
 
5
// This file is distributed under the University of Illinois Open Source
 
6
// License. See LICENSE.TXT for details.
 
7
//
 
8
//===----------------------------------------------------------------------===//
 
9
//
 
10
//  This file implements the MemoryBuffer interface.
 
11
//
 
12
//===----------------------------------------------------------------------===//
 
13
 
 
14
#include "llvm/Support/MemoryBuffer.h"
 
15
#include "llvm/ADT/OwningPtr.h"
 
16
#include "llvm/ADT/SmallString.h"
 
17
#include "llvm/System/Path.h"
 
18
#include "llvm/System/Process.h"
 
19
#include "llvm/System/Program.h"
 
20
#include <cassert>
 
21
#include <cstdio>
 
22
#include <cstring>
 
23
#include <cerrno>
 
24
#include <sys/types.h>
 
25
#include <sys/stat.h>
 
26
#if !defined(_MSC_VER) && !defined(__MINGW32__)
 
27
#include <unistd.h>
 
28
#include <sys/uio.h>
 
29
#else
 
30
#include <io.h>
 
31
#endif
 
32
#include <fcntl.h>
 
33
using namespace llvm;
 
34
 
 
35
//===----------------------------------------------------------------------===//
 
36
// MemoryBuffer implementation itself.
 
37
//===----------------------------------------------------------------------===//
 
38
 
 
39
MemoryBuffer::~MemoryBuffer() {
 
40
  if (MustDeleteBuffer)
 
41
    free((void*)BufferStart);
 
42
}
 
43
 
 
44
/// initCopyOf - Initialize this source buffer with a copy of the specified
 
45
/// memory range.  We make the copy so that we can null terminate it
 
46
/// successfully.
 
47
void MemoryBuffer::initCopyOf(const char *BufStart, const char *BufEnd) {
 
48
  size_t Size = BufEnd-BufStart;
 
49
  BufferStart = (char *)malloc(Size+1);
 
50
  BufferEnd = BufferStart+Size;
 
51
  memcpy(const_cast<char*>(BufferStart), BufStart, Size);
 
52
  *const_cast<char*>(BufferEnd) = 0;   // Null terminate buffer.
 
53
  MustDeleteBuffer = true;
 
54
}
 
55
 
 
56
/// init - Initialize this MemoryBuffer as a reference to externally allocated
 
57
/// memory, memory that we know is already null terminated.
 
58
void MemoryBuffer::init(const char *BufStart, const char *BufEnd) {
 
59
  assert(BufEnd[0] == 0 && "Buffer is not null terminated!");
 
60
  BufferStart = BufStart;
 
61
  BufferEnd = BufEnd;
 
62
  MustDeleteBuffer = false;
 
63
}
 
64
 
 
65
//===----------------------------------------------------------------------===//
 
66
// MemoryBufferMem implementation.
 
67
//===----------------------------------------------------------------------===//
 
68
 
 
69
namespace {
 
70
class MemoryBufferMem : public MemoryBuffer {
 
71
  std::string FileID;
 
72
public:
 
73
  MemoryBufferMem(const char *Start, const char *End, StringRef FID,
 
74
                  bool Copy = false)
 
75
  : FileID(FID) {
 
76
    if (!Copy)
 
77
      init(Start, End);
 
78
    else
 
79
      initCopyOf(Start, End);
 
80
  }
 
81
  
 
82
  virtual const char *getBufferIdentifier() const {
 
83
    return FileID.c_str();
 
84
  }
 
85
};
 
86
}
 
87
 
 
88
/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
 
89
/// that EndPtr[0] must be a null byte and be accessible!
 
90
MemoryBuffer *MemoryBuffer::getMemBuffer(const char *StartPtr, 
 
91
                                         const char *EndPtr,
 
92
                                         const char *BufferName) {
 
93
  return new MemoryBufferMem(StartPtr, EndPtr, BufferName);
 
94
}
 
95
 
 
96
/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
 
97
/// copying the contents and taking ownership of it.  This has no requirements
 
98
/// on EndPtr[0].
 
99
MemoryBuffer *MemoryBuffer::getMemBufferCopy(const char *StartPtr, 
 
100
                                             const char *EndPtr,
 
101
                                             const char *BufferName) {
 
102
  return new MemoryBufferMem(StartPtr, EndPtr, BufferName, true);
 
103
}
 
104
 
 
105
/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
 
106
/// that is completely initialized to zeros.  Note that the caller should
 
107
/// initialize the memory allocated by this method.  The memory is owned by
 
108
/// the MemoryBuffer object.
 
109
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
 
110
                                                  StringRef BufferName) {
 
111
  char *Buf = (char *)malloc(Size+1);
 
112
  if (!Buf) return 0;
 
113
  Buf[Size] = 0;
 
114
  MemoryBufferMem *SB = new MemoryBufferMem(Buf, Buf+Size, BufferName);
 
115
  // The memory for this buffer is owned by the MemoryBuffer.
 
116
  SB->MustDeleteBuffer = true;
 
117
  return SB;
 
118
}
 
119
 
 
120
/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
 
121
/// is completely initialized to zeros.  Note that the caller should
 
122
/// initialize the memory allocated by this method.  The memory is owned by
 
123
/// the MemoryBuffer object.
 
124
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size,
 
125
                                            const char *BufferName) {
 
126
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
 
127
  if (!SB) return 0;
 
128
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size+1);
 
129
  return SB;
 
130
}
 
131
 
 
132
 
 
133
/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
 
134
/// if the Filename is "-".  If an error occurs, this returns null and fills
 
135
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
 
136
/// returns an empty buffer.
 
137
MemoryBuffer *MemoryBuffer::getFileOrSTDIN(StringRef Filename,
 
138
                                           std::string *ErrStr,
 
139
                                           int64_t FileSize) {
 
140
  if (Filename == "-")
 
141
    return getSTDIN();
 
142
  return getFile(Filename, ErrStr, FileSize);
 
143
}
 
144
 
 
145
//===----------------------------------------------------------------------===//
 
146
// MemoryBuffer::getFile implementation.
 
147
//===----------------------------------------------------------------------===//
 
148
 
 
149
namespace {
 
150
/// MemoryBufferMMapFile - This represents a file that was mapped in with the
 
151
/// sys::Path::MapInFilePages method.  When destroyed, it calls the
 
152
/// sys::Path::UnMapFilePages method.
 
153
class MemoryBufferMMapFile : public MemoryBuffer {
 
154
  std::string Filename;
 
155
public:
 
156
  MemoryBufferMMapFile(StringRef filename, const char *Pages, uint64_t Size)
 
157
    : Filename(filename) {
 
158
    init(Pages, Pages+Size);
 
159
  }
 
160
  
 
161
  virtual const char *getBufferIdentifier() const {
 
162
    return Filename.c_str();
 
163
  }
 
164
    
 
165
  ~MemoryBufferMMapFile() {
 
166
    sys::Path::UnMapFilePages(getBufferStart(), getBufferSize());
 
167
  }
 
168
};
 
169
}
 
170
 
 
171
MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr,
 
172
                                    int64_t FileSize) {
 
173
  int OpenFlags = 0;
 
174
#ifdef O_BINARY
 
175
  OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
 
176
#endif
 
177
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
 
178
  int FD = ::open(PathBuf.c_str(), O_RDONLY|OpenFlags);
 
179
  if (FD == -1) {
 
180
    if (ErrStr) *ErrStr = strerror(errno);
 
181
    return 0;
 
182
  }
 
183
  
 
184
  // If we don't know the file size, use fstat to find out.  fstat on an open
 
185
  // file descriptor is cheaper than stat on a random path.
 
186
  if (FileSize == -1) {
 
187
    struct stat FileInfo;
 
188
    // TODO: This should use fstat64 when available.
 
189
    if (fstat(FD, &FileInfo) == -1) {
 
190
      if (ErrStr) *ErrStr = strerror(errno);
 
191
      ::close(FD);
 
192
      return 0;
 
193
    }
 
194
    FileSize = FileInfo.st_size;
 
195
  }
 
196
  
 
197
  
 
198
  // If the file is large, try to use mmap to read it in.  We don't use mmap
 
199
  // for small files, because this can severely fragment our address space. Also
 
200
  // don't try to map files that are exactly a multiple of the system page size,
 
201
  // as the file would not have the required null terminator.
 
202
  //
 
203
  // FIXME: Can we just mmap an extra page in the latter case?
 
204
  if (FileSize >= 4096*4 &&
 
205
      (FileSize & (sys::Process::GetPageSize()-1)) != 0) {
 
206
    if (const char *Pages = sys::Path::MapInFilePages(FD, FileSize)) {
 
207
      // Close the file descriptor, now that the whole file is in memory.
 
208
      ::close(FD);
 
209
      return new MemoryBufferMMapFile(Filename, Pages, FileSize);
 
210
    }
 
211
  }
 
212
 
 
213
  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(FileSize, Filename);
 
214
  if (!Buf) {
 
215
    // Failed to create a buffer.
 
216
    if (ErrStr) *ErrStr = "could not allocate buffer";
 
217
    ::close(FD);
 
218
    return 0;
 
219
  }
 
220
 
 
221
  OwningPtr<MemoryBuffer> SB(Buf);
 
222
  char *BufPtr = const_cast<char*>(SB->getBufferStart());
 
223
  
 
224
  size_t BytesLeft = FileSize;
 
225
  while (BytesLeft) {
 
226
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
 
227
    if (NumRead > 0) {
 
228
      BytesLeft -= NumRead;
 
229
      BufPtr += NumRead;
 
230
    } else if (NumRead == -1 && errno == EINTR) {
 
231
      // try again
 
232
    } else {
 
233
      // error reading.
 
234
      if (ErrStr) *ErrStr = strerror(errno);
 
235
      close(FD);
 
236
      return 0;
 
237
    }
 
238
  }
 
239
  close(FD);
 
240
  
 
241
  return SB.take();
 
242
}
 
243
 
 
244
//===----------------------------------------------------------------------===//
 
245
// MemoryBuffer::getSTDIN implementation.
 
246
//===----------------------------------------------------------------------===//
 
247
 
 
248
namespace {
 
249
class STDINBufferFile : public MemoryBuffer {
 
250
public:
 
251
  virtual const char *getBufferIdentifier() const {
 
252
    return "<stdin>";
 
253
  }
 
254
};
 
255
}
 
256
 
 
257
MemoryBuffer *MemoryBuffer::getSTDIN() {
 
258
  char Buffer[4096*4];
 
259
 
 
260
  std::vector<char> FileData;
 
261
 
 
262
  // Read in all of the data from stdin, we cannot mmap stdin.
 
263
  //
 
264
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
 
265
  // fallback if it fails.
 
266
  sys::Program::ChangeStdinToBinary();
 
267
  size_t ReadBytes;
 
268
  do {
 
269
    ReadBytes = fread(Buffer, sizeof(char), sizeof(Buffer), stdin);
 
270
    FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes);
 
271
  } while (ReadBytes == sizeof(Buffer));
 
272
 
 
273
  FileData.push_back(0); // &FileData[Size] is invalid. So is &*FileData.end().
 
274
  size_t Size = FileData.size();
 
275
  MemoryBuffer *B = new STDINBufferFile();
 
276
  B->initCopyOf(&FileData[0], &FileData[Size-1]);
 
277
  return B;
 
278
}