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