fix test2_3, prune template files from build (they were redundant), more mmap destruc...
[dyninst.git] / common / src / MappedFile.C
1 #include "common/h/MappedFile.h"
2 #include "common/h/pathName.h"
3
4 hash_map<std::string, MappedFile *> MappedFile::mapped_files;
5
6 MappedFile *MappedFile::createMappedFile(std::string fullpath_)
7 {
8    if (mapped_files.find(fullpath_) != mapped_files.end()) {
9       //fprintf(stderr, "%s[%d]:  mapped file exists for %s\n", FILE__, __LINE__, fullpath_.c_str());
10       MappedFile  *ret = mapped_files[fullpath_];
11       ret->refCount++;
12       return ret;
13    }
14
15
16    bool ok = false;
17    MappedFile *mf = new MappedFile(fullpath_, ok);
18    if (!mf || !ok) {
19       if (mf)
20          delete mf;
21       return NULL;
22    }
23    
24    mapped_files[fullpath_] = mf;
25    
26 //   fprintf(stderr, "%s[%d]:  MMAPFILE %s: mapped_files.size() =  %d\n", FILE__, __LINE__, fullpath_.c_str(), mapped_files.size());
27    return mf;
28 }
29
30 MappedFile::MappedFile(std::string fullpath_, bool &ok) :
31    fullpath(std::string(fullpath_)),
32    did_mmap(false),
33    did_open(false),
34    refCount(1)
35 {
36   ok = check_path(fullpath);
37   if (!ok) return;
38   ok = open_file();
39   if (!ok) return;
40   ok = map_file();
41
42   //  I think on unixes we can close the fd after mapping the file, 
43   //  but is this really somehow better?
44 }
45
46 MappedFile *MappedFile::createMappedFile(void *loc)
47 {
48    bool ok = false;
49    MappedFile *mf = new MappedFile(loc, ok);
50    if (!mf || !ok) {
51       if (mf)
52          delete mf;
53       return NULL;
54   }
55
56   return mf;
57 }
58
59 MappedFile::MappedFile(void *loc, bool &ok) :
60    fullpath("in_memory_file"),
61    did_mmap(false),
62    did_open(false),
63    refCount(1)
64 {
65   ok = open_file(loc);
66   if (!ok) return;
67   ok = map_file();
68 }
69
70 void MappedFile::closeMappedFile(MappedFile *mf)
71 {
72    //fprintf(stderr, "%s[%d]:  welcome to closeMappedFile(%s) refCount = %d\n", FILE__, __LINE__, mf->pathname().c_str(), mf->refCount);
73    mf->refCount--;
74    if (mf->refCount <= 0) {
75       hash_map<std::string, MappedFile *>::iterator iter;
76       iter = mapped_files.find(mf->pathname());
77       if (iter != mapped_files.end()) {
78          mapped_files.erase(iter);
79       }
80       //fprintf(stderr, "%s[%d]:  DELETING mapped file\n", FILE__, __LINE__);
81       //  dtor handles unmap and close
82       delete mf;
83    }
84 }
85
86 bool MappedFile::clean_up()
87 {
88    if (did_mmap) {
89       if (!unmap_file()) goto err;
90    }
91    if (did_open) {
92       if (!close_file()) goto err;
93    }
94    return true;
95
96 err:
97    fprintf(stderr, "%s[%d]:  error unmapping file %s\n", 
98          FILE__, __LINE__, fullpath.c_str() );
99    return false;
100 }
101
102 MappedFile::~MappedFile()
103 {
104   //  warning, destructor should not allowed to throw exceptions
105    if (did_mmap)  {
106       //fprintf(stderr, "%s[%d]: unmapping %s\n", FILE__, __LINE__, fullpath.c_str());
107       unmap_file();
108    }
109    if (did_open) 
110       close_file();
111 }
112
113 bool MappedFile::check_path(std::string &filename)
114 {
115    struct stat statbuf;
116    if (0 != stat(filename.c_str(), &statbuf)) {
117       char ebuf[1024];
118 #if defined(os_windows)
119       LPVOID lpMsgBuf;
120       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
121             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
122             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
123             &lpMsgBuf,    0,    NULL );
124
125       sprintf(ebuf, "stat: %s", (char *) lpMsgBuf);
126       LocalFree(lpMsgBuf);
127 #else
128       sprintf(ebuf, "stat: %s", strerror(errno));
129 #endif
130       goto err;
131    }
132
133    file_size = statbuf.st_size;
134
135    return true;
136
137 err:
138    fprintf(stderr, "%s[%d]: bad path: %s\n", FILE__, __LINE__, filename.c_str());
139    return false;
140 }
141
142 #if defined(os_windows)
143 bool MappedFile::open_file(void *loc)
144 {
145    hFile = LocalHandle( loc );  //For a mem image
146    if (!hFile) {
147       LPVOID lpMsgBuf;
148       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
149             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
150             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
151             &lpMsgBuf,    0,    NULL );
152
153       char ebuf[1024];
154       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
155       LocalFree(lpMsgBuf);
156       goto err;
157    }
158    did_open = true;
159
160    return true;
161 err:
162    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
163    return false;
164 }
165 #else
166 bool MappedFile::open_file(void * /*loc*/)
167 {
168    did_open = false;
169    fd = -1;
170    return true;
171 }
172 #endif
173
174 bool MappedFile::open_file()
175 {
176 #if defined(os_windows)
177    hFile = CreateFile(fullpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
178          NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
179    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
180       LPVOID lpMsgBuf;
181       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
182             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
183             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
184             &lpMsgBuf,    0,    NULL );
185
186       char ebuf[1024];
187       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
188       LocalFree(lpMsgBuf);
189       goto err;
190    }
191 #else
192    fd = open(fullpath.c_str(), O_RDONLY);
193    if (-1 == fd) {
194       char ebuf[1024];
195       sprintf(ebuf, "open(%s) failed: %s", fullpath.c_str(), strerror(errno));
196       goto err;
197    }
198 #endif
199
200    did_open = true;
201    return true;
202 err:
203    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
204    return false;
205 }
206
207 bool MappedFile::map_file()
208 {
209    char ebuf[1024];
210 #if defined(os_windows)
211
212    // map the file to our address space
213    // first, create a file mapping object
214    
215    hMap = CreateFileMapping( hFile,
216          NULL,           // security attrs
217          PAGE_READONLY,  // protection flags
218          0,              // max size - high DWORD
219          0,              // max size - low DWORD
220          NULL );         // mapping name - not used
221
222    if (!hMap) {
223       LPVOID lpMsgBuf;
224       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
225             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
226             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
227             &lpMsgBuf,    0,    NULL );
228
229       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
230       LocalFree(lpMsgBuf);
231       goto err;
232    }
233
234    // next, map the file to our address space
235
236    map_addr = MapViewOfFileEx( hMap,             // mapping object
237          FILE_MAP_READ,  // desired access
238          0,              // loc to map - hi DWORD
239          0,              // loc to map - lo DWORD
240          0,              // #bytes to map - 0=all
241          NULL );         // suggested map addr
242
243    if (!map_addr) {
244       LPVOID lpMsgBuf;
245       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
246             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
247             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
248             &lpMsgBuf,    0,    NULL );
249
250       sprintf(ebuf, "MapViewOfFileEx failed: %s", (char *) lpMsgBuf);
251       LocalFree(lpMsgBuf);
252       goto err;
253    }
254
255 #else
256
257    map_addr = mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0);
258    if (MAP_FAILED == map_addr) {
259       sprintf(ebuf, "mmap(0, %d, PROT_READ, MAP_SHARED, %d, 0): %s", 
260             file_size, fd, strerror(errno));
261       goto err;
262    }
263
264 #endif
265
266    did_mmap = true;
267    return true;
268 err:
269    return false;
270 }
271
272 bool MappedFile::unmap_file()
273 {
274 #if defined(os_windows)
275
276    UnmapViewOfFile(map_addr);
277    CloseHandle(hMap);
278
279 #else
280
281    if ( 0 != munmap(map_addr, file_size))  {
282       fprintf(stderr, "%s[%d]: failed to unmap file\n", FILE__, __LINE__);
283       return false;
284    }
285    
286    map_addr = NULL;
287 #endif
288    return true;
289 }
290
291 bool MappedFile::close_file()
292 {
293 #if defined (os_windows)
294
295    CloseHandle(hFile);
296
297 #else
298
299    if (-1 == close(fd)) {
300       fprintf(stderr, "%s[%d]: failed to close file\n", FILE__, __LINE__);
301       return false;
302    }
303
304 #endif
305    return true;
306 }
307
308 std::string &MappedFile::pathname() {
309         return fullpath;
310 }
311
312 std::string MappedFile::filename() {
313         return extract_pathname_tail(fullpath);
314 }