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