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