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