att
[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    return false;
139 }
140
141 #if defined(os_windows)
142 bool MappedFile::open_file(void *loc)
143 {
144    hFile = LocalHandle( loc );  //For a mem image
145    if (!hFile) {
146       LPVOID lpMsgBuf;
147       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
148             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
149             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
150             &lpMsgBuf,    0,    NULL );
151
152       char ebuf[1024];
153       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
154       LocalFree(lpMsgBuf);
155       goto err;
156    }
157    did_open = true;
158
159    return true;
160 err:
161    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
162    return false;
163 }
164 #else
165 bool MappedFile::open_file(void * /*loc*/)
166 {
167    did_open = false;
168    fd = -1;
169    return true;
170 }
171 #endif
172
173 bool MappedFile::open_file()
174 {
175 #if defined(os_windows)
176    hFile = CreateFile(fullpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
177          NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
178    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
179       LPVOID lpMsgBuf;
180       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
181             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
182             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
183             &lpMsgBuf,    0,    NULL );
184
185       char ebuf[1024];
186       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
187       LocalFree(lpMsgBuf);
188       goto err;
189    }
190 #else
191    fd = open(fullpath.c_str(), O_RDONLY);
192    if (-1 == fd) {
193       char ebuf[1024];
194       sprintf(ebuf, "open(%s) failed: %s", fullpath.c_str(), strerror(errno));
195       goto err;
196    }
197 #endif
198
199    did_open = true;
200    return true;
201 err:
202    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
203    return false;
204 }
205
206 bool MappedFile::map_file()
207 {
208    char ebuf[1024];
209 #if defined(os_windows)
210
211    // map the file to our address space
212    // first, create a file mapping object
213    
214    hMap = CreateFileMapping( hFile,
215          NULL,           // security attrs
216          PAGE_READONLY,  // protection flags
217          0,              // max size - high DWORD
218          0,              // max size - low DWORD
219          NULL );         // mapping name - not used
220
221    if (!hMap) {
222       LPVOID lpMsgBuf;
223       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
224             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
225             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
226             &lpMsgBuf,    0,    NULL );
227
228       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
229       LocalFree(lpMsgBuf);
230       goto err;
231    }
232
233    // next, map the file to our address space
234
235    map_addr = MapViewOfFileEx( hMap,             // mapping object
236          FILE_MAP_READ,  // desired access
237          0,              // loc to map - hi DWORD
238          0,              // loc to map - lo DWORD
239          0,              // #bytes to map - 0=all
240          NULL );         // suggested map addr
241
242    if (!map_addr) {
243       LPVOID lpMsgBuf;
244       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
245             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
246             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
247             &lpMsgBuf,    0,    NULL );
248
249       sprintf(ebuf, "MapViewOfFileEx failed: %s", (char *) lpMsgBuf);
250       LocalFree(lpMsgBuf);
251       goto err;
252    }
253
254 #else
255
256    map_addr = mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0);
257    if (MAP_FAILED == map_addr) {
258       sprintf(ebuf, "mmap(0, %d, PROT_READ, MAP_SHARED, %d, 0): %s", 
259             file_size, fd, strerror(errno));
260       goto err;
261    }
262
263 #endif
264
265    did_mmap = true;
266    return true;
267 err:
268    return false;
269 }
270
271 bool MappedFile::unmap_file()
272 {
273 #if defined(os_windows)
274
275    UnmapViewOfFile(map_addr);
276    CloseHandle(hMap);
277
278 #else
279
280    if ( 0 != munmap(map_addr, file_size))  {
281       fprintf(stderr, "%s[%d]: failed to unmap file\n", FILE__, __LINE__);
282       return false;
283    }
284    
285    map_addr = NULL;
286 #endif
287    return true;
288 }
289
290 bool MappedFile::close_file()
291 {
292 #if defined (os_windows)
293
294    CloseHandle(hFile);
295
296 #else
297
298    if (-1 == close(fd)) {
299       fprintf(stderr, "%s[%d]: failed to close file\n", FILE__, __LINE__);
300       return false;
301    }
302
303 #endif
304    return true;
305 }
306
307 std::string &MappedFile::pathname() {
308         return fullpath;
309 }
310
311 std::string MappedFile::filename() {
312         return extract_pathname_tail(fullpath);
313 }