Update copyright to LGPL on all files
[dyninst.git] / common / src / MappedFile.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 #include "common/h/MappedFile.h"
32 #include "common/h/pathName.h"
33
34 dyn_hash_map<std::string, MappedFile *> MappedFile::mapped_files;
35
36 MappedFile *MappedFile::createMappedFile(std::string fullpath_)
37 {
38    //fprintf(stderr, "%s[%d]:  createMappedFile %s\n", FILE__, __LINE__, fullpath_.c_str());
39    if (mapped_files.find(fullpath_) != mapped_files.end()) {
40       //fprintf(stderr, "%s[%d]:  mapped file exists for %s\n", FILE__, __LINE__, fullpath_.c_str());
41       MappedFile  *ret = mapped_files[fullpath_];
42       if (ret->can_share) {
43          ret->refCount++;
44          return ret;
45       }
46    }
47
48
49    bool ok = false;
50    MappedFile *mf = new MappedFile(fullpath_, ok);
51    if (!mf || !ok) {
52       if (mf)
53          delete mf;
54       return NULL;
55    }
56    
57    mapped_files[fullpath_] = mf;
58    
59    //fprintf(stderr, "%s[%d]:  MMAPFILE %s: mapped_files.size() =  %d\n", FILE__, __LINE__, fullpath_.c_str(), mapped_files.size());
60    return mf;
61 }
62
63 MappedFile::MappedFile(std::string fullpath_, bool &ok) :
64    fullpath(fullpath_),
65    did_mmap(false),
66    did_open(false),
67    can_share(true),
68    refCount(1)
69 {
70   ok = check_path(fullpath);
71   if (!ok) return;
72   ok = open_file();
73   if (!ok) return;
74   ok = map_file();
75
76   //  I think on unixes we can close the fd after mapping the file, 
77   //  but is this really somehow better?
78 }
79
80 MappedFile *MappedFile::createMappedFile(void *loc, unsigned long size_)
81 {
82    bool ok = false;
83    MappedFile *mf = new MappedFile(loc, size_, ok);
84    if (!mf || !ok) {
85       if (mf)
86          delete mf;
87       return NULL;
88   }
89
90   return mf;
91 }
92
93 MappedFile::MappedFile(void *loc, unsigned long size_, bool &ok) :
94    fullpath("in_memory_file"),
95    did_mmap(false),
96    did_open(false),
97    can_share(true),
98    refCount(1)
99 {
100   ok = open_file(loc, size_);
101 #if defined(os_windows)  
102   if (!ok) return;
103   ok = map_file();
104 #endif
105 }
106
107 void MappedFile::closeMappedFile(MappedFile *&mf)
108 {
109    if (!mf) 
110    {
111       fprintf(stderr, "%s[%d]:  BAD NEWS:  called closeMappedFile(NULL)\n", FILE__, __LINE__);
112       return;
113    }
114
115   //fprintf(stderr, "%s[%d]:  welcome to closeMappedFile() refCount = %d\n", FILE__, __LINE__, mf->refCount);
116    mf->refCount--;
117
118    if (mf->refCount <= 0) 
119    {
120       dyn_hash_map<std::string, MappedFile *>::iterator iter;
121       iter = mapped_files.find(mf->pathname());
122
123       if (iter != mapped_files.end()) 
124       {
125          mapped_files.erase(iter);
126       }
127
128       //fprintf(stderr, "%s[%d]:  DELETING mapped file\n", FILE__, __LINE__);
129       //  dtor handles unmap and close
130
131       delete mf;
132       mf = NULL;
133    }
134 }
135
136 bool MappedFile::clean_up()
137 {
138    if (did_mmap) {
139       if (!unmap_file()) goto err;
140    }
141    if (did_open) {
142       if (!close_file()) goto err;
143    }
144    return true;
145
146 err:
147    fprintf(stderr, "%s[%d]:  error unmapping file %s\n", 
148          FILE__, __LINE__, fullpath.c_str() );
149    return false;
150 }
151
152 MappedFile::~MappedFile()
153 {
154   //  warning, destructor should not allowed to throw exceptions
155    if (did_mmap)  {
156       //fprintf(stderr, "%s[%d]: unmapping %s\n", FILE__, __LINE__, fullpath.c_str());
157       unmap_file();
158    }
159    if (did_open) 
160       close_file();
161 }
162
163 bool MappedFile::check_path(std::string &filename)
164 {
165    struct stat statbuf;
166    if (0 != stat(filename.c_str(), &statbuf)) {
167       char ebuf[1024];
168 #if defined(os_windows)
169       LPVOID lpMsgBuf;
170       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
171             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
172             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
173             &lpMsgBuf,    0,    NULL );
174
175       sprintf(ebuf, "stat: %s", (char *) lpMsgBuf);
176       LocalFree(lpMsgBuf);
177 #else
178       sprintf(ebuf, "stat: %s", strerror(errno));
179 #endif
180       goto err;
181    }
182
183    file_size = statbuf.st_size;
184
185    return true;
186
187 err:
188    return false;
189 }
190
191 bool MappedFile::open_file(void *loc, unsigned long size_)
192 {
193 #if defined(os_windows)
194    hFile = LocalHandle( loc );  //For a mem image
195    if (!hFile) {
196       LPVOID lpMsgBuf;
197       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
198                     FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
199                     GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
200                     (LPTSTR) &lpMsgBuf, 0, NULL);
201
202       char ebuf[1024];
203       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
204       LocalFree(lpMsgBuf);
205       goto err;
206    }
207    did_open = true;
208
209    return true;
210 err:
211    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
212    return false;
213 #else
214    map_addr = loc;
215    file_size = size_;
216    did_open = false;
217    fd = -1;
218    return true;
219 #endif
220 }
221
222 bool MappedFile::open_file()
223 {
224 #if defined(os_windows)
225    hFile = CreateFile(fullpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
226          NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
227    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
228       LPVOID lpMsgBuf;
229       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
230             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
231             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
232             &lpMsgBuf,    0,    NULL );
233
234       char ebuf[1024];
235       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
236       LocalFree(lpMsgBuf);
237       goto err;
238    }
239 #else
240    fd = open(fullpath.c_str(), O_RDONLY);
241    if (-1 == fd) {
242       char ebuf[1024];
243       sprintf(ebuf, "open(%s) failed: %s", fullpath.c_str(), strerror(errno));
244       goto err;
245    }
246 #endif
247
248    did_open = true;
249    return true;
250 err:
251    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
252    return false;
253 }
254
255 bool MappedFile::map_file()
256 {
257    char ebuf[1024];
258 #if defined(os_windows)
259
260    // map the file to our address space
261    // first, create a file mapping object
262    
263    hMap = CreateFileMapping( hFile,
264          NULL,           // security attrs
265          PAGE_READONLY,  // protection flags
266          0,              // max size - high DWORD
267          0,              // max size - low DWORD
268          NULL );         // mapping name - not used
269
270    if (!hMap) {
271       LPVOID lpMsgBuf;
272       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
273             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
274             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
275             &lpMsgBuf,    0,    NULL );
276
277       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
278       LocalFree(lpMsgBuf);
279       goto err;
280    }
281
282    // next, map the file to our address space
283
284    map_addr = MapViewOfFileEx( hMap,             // mapping object
285          FILE_MAP_READ,  // desired access
286          0,              // loc to map - hi DWORD
287          0,              // loc to map - lo DWORD
288          0,              // #bytes to map - 0=all
289          NULL );         // suggested map addr
290
291    if (!map_addr) {
292       LPVOID lpMsgBuf;
293       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
294             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
295             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
296             &lpMsgBuf,    0,    NULL );
297
298       sprintf(ebuf, "MapViewOfFileEx failed: %s", (char *) lpMsgBuf);
299       LocalFree(lpMsgBuf);
300       goto err;
301    }
302
303 #else
304
305    map_addr = mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0);
306    if (MAP_FAILED == map_addr) {
307       sprintf(ebuf, "mmap(0, %lu, PROT_READ, MAP_SHARED, %d, 0): %s", 
308             file_size, fd, strerror(errno));
309       goto err;
310    }
311
312 #endif
313
314    did_mmap = true;
315    return true;
316 err:
317    return false;
318 }
319
320 bool MappedFile::unmap_file()
321 {
322 #if defined(os_windows)
323
324    UnmapViewOfFile(map_addr);
325    CloseHandle(hMap);
326
327 #else
328
329    if ( 0 != munmap(map_addr, file_size))  {
330       fprintf(stderr, "%s[%d]: failed to unmap file\n", FILE__, __LINE__);
331       return false;
332    }
333    
334    map_addr = NULL;
335 #endif
336    return true;
337 }
338
339 bool MappedFile::close_file()
340 {
341 #if defined (os_windows)
342
343    CloseHandle(hFile);
344
345 #else
346
347    if (-1 == close(fd)) {
348       fprintf(stderr, "%s[%d]: failed to close file\n", FILE__, __LINE__);
349       return false;
350    }
351
352 #endif
353    return true;
354 }
355
356 std::string MappedFile::pathname() 
357 {
358         return fullpath;
359 }
360
361 std::string MappedFile::filename() 
362 {
363         return extract_pathname_tail(fullpath);
364 }
365
366 void MappedFile::setSharing(bool s)
367 {
368    can_share = s;
369 }
370
371 bool MappedFile::canBeShared()
372 {
373    return can_share;
374 }