Fix PR1581, patch by Timo Savola
[oota-llvm.git] / lib / System / Win32 / MappedFile.inc
1 //===- Win32/MappedFile.cpp - Win32 MappedFile Implementation ---*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Jeff Cohen and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides the Win32 implementation of the MappedFile concept.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only Win32 code.
16 //===----------------------------------------------------------------------===//
17
18 #include "Win32.h"
19 #include "llvm/System/Process.h"
20
21 namespace llvm {
22 using namespace sys;
23
24 struct sys::MappedFileInfo {
25   HANDLE hFile;
26   HANDLE hMapping;
27   size_t size;
28 };
29
30 bool MappedFile::initialize(std::string* ErrMsg) {
31   assert(!info_);
32   info_ = new MappedFileInfo;
33   info_->hFile = INVALID_HANDLE_VALUE;
34   info_->hMapping = NULL;
35
36   DWORD mode = options_ & WRITE_ACCESS ? GENERIC_WRITE : GENERIC_READ;
37   DWORD disposition = options_ & WRITE_ACCESS ? OPEN_ALWAYS : OPEN_EXISTING;
38   DWORD share = options_ & WRITE_ACCESS ? FILE_SHARE_WRITE : FILE_SHARE_READ;
39   share = options_ & SHARED_MAPPING ? share : 0;
40   info_->hFile = CreateFile(path_.c_str(), mode, share, NULL, disposition,
41                             FILE_ATTRIBUTE_NORMAL, NULL);
42   if (info_->hFile == INVALID_HANDLE_VALUE) {
43     delete info_;
44     info_ = NULL;
45     return MakeErrMsg(ErrMsg,
46       std::string("Can't open file: ") + path_.toString());
47   }
48
49   LARGE_INTEGER size;
50   if (!GetFileSizeEx(info_->hFile, &size) ||
51       (info_->size = size_t(size.QuadPart), info_->size != size.QuadPart)) {
52     CloseHandle(info_->hFile);
53     delete info_;
54     info_ = NULL;
55     return MakeErrMsg(ErrMsg, 
56       std::string("Can't get size of file: ") + path_.toString());
57   }
58
59   return false;
60 }
61
62 void MappedFile::terminate() {
63   unmap();
64   if (info_->hFile != INVALID_HANDLE_VALUE)
65     CloseHandle(info_->hFile);
66   delete info_;
67   info_ = NULL;
68 }
69
70 void MappedFile::unmap() {
71   assert(info_ && "MappedFile not initialized");
72   if (isMapped()) {
73     UnmapViewOfFile(base_);
74     base_ = NULL;
75   }
76   if (info_->hMapping != INVALID_HANDLE_VALUE) {
77     CloseHandle(info_->hMapping);
78     info_->hMapping = NULL;
79   }
80 }
81
82 void* MappedFile::map(std::string* ErrMsg) {
83   if (!isMapped()) {
84     DWORD prot = PAGE_READONLY;
85     if (options_ & EXEC_ACCESS)
86       prot = SEC_IMAGE;
87     else if (options_ & WRITE_ACCESS)
88       prot = PAGE_READWRITE;
89     info_->hMapping = CreateFileMapping(info_->hFile, NULL, prot, 0, 0, NULL);
90     if (info_->hMapping == NULL) {
91       MakeErrMsg(ErrMsg, std::string("Can't map file: ") + path_.toString());
92       return 0;
93     }
94
95     prot = (options_ & WRITE_ACCESS) ? FILE_MAP_WRITE : FILE_MAP_READ;
96     base_ = MapViewOfFileEx(info_->hMapping, prot, 0, 0, 0, NULL);
97     if (base_ == NULL) {
98       CloseHandle(info_->hMapping);
99       info_->hMapping = NULL;
100       MakeErrMsg(ErrMsg, std::string("Can't map file: ") + path_.toString());
101       return 0;
102     }
103   }
104   return base_;
105 }
106
107 size_t MappedFile::size() const {
108   assert(info_ && "MappedFile not initialized");
109   return info_->size;
110 }
111
112 bool MappedFile::size(size_t new_size, std::string* ErrMsg) {
113   assert(info_ && "MappedFile not initialized");
114
115   // Take the mapping out of memory.
116   unmap();
117
118   // Adjust the new_size to a page boundary.
119   size_t pagesizem1 = Process::GetPageSize() - 1;
120   new_size = (new_size + pagesizem1) & ~pagesizem1;
121
122   // If the file needs to be extended, do so.
123   if (new_size > info_->size) {
124     LARGE_INTEGER eof;
125     eof.QuadPart = new_size;
126     if (!SetFilePointerEx(info_->hFile, eof, NULL, FILE_BEGIN))
127       return MakeErrMsg(ErrMsg, 
128         std::string("Can't set end of file: ") + path_.toString());
129     if (!SetEndOfFile(info_->hFile))
130       return MakeErrMsg(ErrMsg, 
131         std::string("Can't set end of file: ") + path_.toString());
132     info_->size = new_size;
133   }
134
135   // Remap the file.
136   return map(ErrMsg);
137 }
138
139 }
140