more serialization stuff, still disabled under the cap_serialization flag. Other...
[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    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(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, unsigned long size_)
47 {
48    bool ok = false;
49    MappedFile *mf = new MappedFile(loc, size_, 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, unsigned long size_, bool &ok) :
60    fullpath("in_memory_file"),
61    did_mmap(false),
62    did_open(false),
63    refCount(1)
64 {
65   ok = open_file(loc, size_);
66 #if defined(os_windows)  
67   if (!ok) return;
68   ok = map_file();
69 #endif
70 }
71
72 void MappedFile::closeMappedFile(MappedFile *&mf)
73 {
74    if (!mf) 
75    {
76       fprintf(stderr, "%s[%d]:  BAD NEWS:  called closeMappedFile(NULL)\n", FILE__, __LINE__);
77       return;
78    }
79
80    //fprintf(stderr, "%s[%d]:  welcome to closeMappedFile(%s) refCount = %d\n", FILE__, __LINE__, mf->pathname().c_str(), mf->refCount);
81
82    mf->refCount--;
83
84    if (mf->refCount <= 0) 
85    {
86       dyn_hash_map<std::string, MappedFile *>::iterator iter;
87       iter = mapped_files.find(mf->pathname());
88
89       if (iter != mapped_files.end()) 
90       {
91          mapped_files.erase(iter);
92       }
93
94       //fprintf(stderr, "%s[%d]:  DELETING mapped file\n", FILE__, __LINE__);
95       //  dtor handles unmap and close
96
97       delete mf;
98       mf = NULL;
99    }
100 }
101
102 bool MappedFile::clean_up()
103 {
104    if (did_mmap) {
105       if (!unmap_file()) goto err;
106    }
107    if (did_open) {
108       if (!close_file()) goto err;
109    }
110    return true;
111
112 err:
113    fprintf(stderr, "%s[%d]:  error unmapping file %s\n", 
114          FILE__, __LINE__, fullpath.c_str() );
115    return false;
116 }
117
118 MappedFile::~MappedFile()
119 {
120   //  warning, destructor should not allowed to throw exceptions
121    if (did_mmap)  {
122       //fprintf(stderr, "%s[%d]: unmapping %s\n", FILE__, __LINE__, fullpath.c_str());
123       unmap_file();
124    }
125    if (did_open) 
126       close_file();
127 }
128
129 bool MappedFile::check_path(std::string &filename)
130 {
131    struct stat statbuf;
132    if (0 != stat(filename.c_str(), &statbuf)) {
133       char ebuf[1024];
134 #if defined(os_windows)
135       LPVOID lpMsgBuf;
136       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
137             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
138             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
139             &lpMsgBuf,    0,    NULL );
140
141       sprintf(ebuf, "stat: %s", (char *) lpMsgBuf);
142       LocalFree(lpMsgBuf);
143 #else
144       sprintf(ebuf, "stat: %s", strerror(errno));
145 #endif
146       goto err;
147    }
148
149    file_size = statbuf.st_size;
150
151    return true;
152
153 err:
154    return false;
155 }
156
157 bool MappedFile::open_file(void *loc, unsigned long size_)
158 {
159 #if defined(os_windows)
160    hFile = LocalHandle( loc );  //For a mem image
161    if (!hFile) {
162       LPVOID lpMsgBuf;
163       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
164                     FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
165                     GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
166                     (LPTSTR) &lpMsgBuf, 0, NULL);
167
168       char ebuf[1024];
169       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
170       LocalFree(lpMsgBuf);
171       goto err;
172    }
173    did_open = true;
174
175    return true;
176 err:
177    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
178    return false;
179 #else
180    map_addr = loc;
181    file_size = size_;
182    did_open = false;
183    fd = -1;
184    return true;
185 #endif
186 }
187
188 bool MappedFile::open_file()
189 {
190 #if defined(os_windows)
191    hFile = CreateFile(fullpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
192          NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
193    if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
194       LPVOID lpMsgBuf;
195       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
196             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
197             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
198             &lpMsgBuf,    0,    NULL );
199
200       char ebuf[1024];
201       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
202       LocalFree(lpMsgBuf);
203       goto err;
204    }
205 #else
206    fd = open(fullpath.c_str(), O_RDONLY);
207    if (-1 == fd) {
208       char ebuf[1024];
209       sprintf(ebuf, "open(%s) failed: %s", fullpath.c_str(), strerror(errno));
210       goto err;
211    }
212 #endif
213
214    did_open = true;
215    return true;
216 err:
217    fprintf(stderr, "%s[%d]: failed to open file\n", FILE__, __LINE__);
218    return false;
219 }
220
221 bool MappedFile::map_file()
222 {
223    char ebuf[1024];
224 #if defined(os_windows)
225
226    // map the file to our address space
227    // first, create a file mapping object
228    
229    hMap = CreateFileMapping( hFile,
230          NULL,           // security attrs
231          PAGE_READONLY,  // protection flags
232          0,              // max size - high DWORD
233          0,              // max size - low DWORD
234          NULL );         // mapping name - not used
235
236    if (!hMap) {
237       LPVOID lpMsgBuf;
238       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
239             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
240             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
241             &lpMsgBuf,    0,    NULL );
242
243       sprintf(ebuf, "CreateFileMapping failed: %s", (char *) lpMsgBuf);
244       LocalFree(lpMsgBuf);
245       goto err;
246    }
247
248    // next, map the file to our address space
249
250    map_addr = MapViewOfFileEx( hMap,             // mapping object
251          FILE_MAP_READ,  // desired access
252          0,              // loc to map - hi DWORD
253          0,              // loc to map - lo DWORD
254          0,              // #bytes to map - 0=all
255          NULL );         // suggested map addr
256
257    if (!map_addr) {
258       LPVOID lpMsgBuf;
259       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
260             |     FORMAT_MESSAGE_IGNORE_INSERTS,    NULL,
261             GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)
262             &lpMsgBuf,    0,    NULL );
263
264       sprintf(ebuf, "MapViewOfFileEx failed: %s", (char *) lpMsgBuf);
265       LocalFree(lpMsgBuf);
266       goto err;
267    }
268
269 #else
270
271    map_addr = mmap(0, file_size, PROT_READ, MAP_SHARED, fd, 0);
272    if (MAP_FAILED == map_addr) {
273       sprintf(ebuf, "mmap(0, %d, PROT_READ, MAP_SHARED, %d, 0): %s", 
274             file_size, fd, strerror(errno));
275       goto err;
276    }
277
278 #endif
279
280    did_mmap = true;
281    return true;
282 err:
283    return false;
284 }
285
286 bool MappedFile::unmap_file()
287 {
288 #if defined(os_windows)
289
290    UnmapViewOfFile(map_addr);
291    CloseHandle(hMap);
292
293 #else
294
295    if ( 0 != munmap(map_addr, file_size))  {
296       fprintf(stderr, "%s[%d]: failed to unmap file\n", FILE__, __LINE__);
297       return false;
298    }
299    
300    map_addr = NULL;
301 #endif
302    return true;
303 }
304
305 bool MappedFile::close_file()
306 {
307 #if defined (os_windows)
308
309    CloseHandle(hFile);
310
311 #else
312
313    if (-1 == close(fd)) {
314       fprintf(stderr, "%s[%d]: failed to close file\n", FILE__, __LINE__);
315       return false;
316    }
317
318 #endif
319    return true;
320 }
321
322 std::string MappedFile::pathname() 
323 {
324         return fullpath;
325 }
326
327 std::string MappedFile::filename() 
328 {
329         return extract_pathname_tail(fullpath);
330 }