Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/iostreams/src/mapped_file.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 13.1 KB
Line 
1// (C) Copyright Craig Henderson 2002 'boost/memmap.hpp' from sandbox
2// (C) Copyright Jonathan Turkanis 2004.
3// (C) Copyright Jonathan Graehl 2004.
4
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
7
8// See http://www.boost.org/libs/iostreams for documentation.
9
10// Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>
11// knows that we are building the library (possibly exporting code), rather
12// than using it (possibly importing code).
13#define BOOST_IOSTREAMS_SOURCE
14
15#include <cassert>
16#include <boost/iostreams/detail/config/dyn_link.hpp>
17#include <boost/iostreams/detail/config/windows_posix.hpp>
18#include <boost/iostreams/detail/ios.hpp>  // failure.
19#include <boost/iostreams/detail/system_failure.hpp>
20#include <boost/iostreams/device/mapped_file.hpp>
21
22#ifdef BOOST_IOSTREAMS_WINDOWS
23# define WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers
24# include <windows.h>
25#else
26# include <errno.h>
27# include <fcntl.h>
28# include <sys/mman.h>      // mmap, munmap.
29# include <sys/stat.h>
30# include <sys/types.h>     // struct stat.
31# include <unistd.h>        // sysconf.
32#endif
33
34#include <boost/iostreams/detail/config/disable_warnings.hpp>
35
36namespace boost { namespace iostreams {
37
38namespace detail {
39
40struct mapped_file_impl {
41    mapped_file_impl() { clear(false); }
42    ~mapped_file_impl() { try { close(); } catch (std::exception&) { } }
43    void clear(bool error)
44    {
45        data_ = 0;
46        size_ = 0;
47        mode_ = BOOST_IOS::openmode();
48        error_ = error;
49    #ifdef BOOST_IOSTREAMS_WINDOWS
50        handle_ = INVALID_HANDLE_VALUE;
51        mapped_handle_ = NULL;
52    #else
53        handle_ = 0;
54    #endif
55    }
56    void close()
57    {
58        bool error = false;
59    #ifdef BOOST_IOSTREAMS_WINDOWS
60        if (handle_ == INVALID_HANDLE_VALUE)
61            return;
62        error = !::UnmapViewOfFile(data_) || error;
63        error = !::CloseHandle(mapped_handle_) || error;
64        error = !::CloseHandle(handle_) || error;
65        handle_ = INVALID_HANDLE_VALUE;
66        mapped_handle_ = NULL;
67    #else
68        if (!handle_)
69            return;
70        error = ::munmap(reinterpret_cast<char*>(data_), size_) != 0 || error;
71        error = ::close(handle_) != 0 || error;
72        handle_ = 0;
73    #endif
74        data_ = 0;
75        size_ = 0;
76        mode_ = BOOST_IOS::openmode();
77        if (error)
78            throw_system_failure("error closing mapped file");
79    }
80    char*                data_;
81    std::size_t          size_;
82    BOOST_IOS::openmode  mode_;
83    bool                 error_;
84#ifdef BOOST_IOSTREAMS_WINDOWS
85    HANDLE               handle_;
86    HANDLE               mapped_handle_;
87#else
88    int                  handle_;
89#endif
90};
91
92} // End namespace detail.
93
94//------------------Definition of mapped_file_source--------------------------//
95
96mapped_file_source::mapped_file_source(mapped_file_params p) { open(p); }
97
98mapped_file_source::mapped_file_source( const std::string& path,
99                                        mapped_file_source::size_type length,
100                                        boost::intmax_t offset )
101{ open(path, length, offset); }
102
103void mapped_file_source::open(mapped_file_params p)
104{
105    p.mode &= ~BOOST_IOS::out;
106    open_impl(p);
107}
108
109void mapped_file_source::open( const std::string& path,
110                               mapped_file_source::size_type length,
111                               boost::intmax_t offset )
112{
113    mapped_file_params p(path);
114    p.mode = BOOST_IOS::in;
115    p.length = length;
116    p.offset = offset;
117    open_impl(p);
118}
119
120mapped_file_source::size_type mapped_file_source::size() const
121{ return pimpl_->size_; }
122
123bool mapped_file_source::is_open() const
124{ return !!pimpl_ && pimpl_->handle_ != 0; }
125
126void mapped_file_source::close() { pimpl_->close(); }
127
128mapped_file_source::operator mapped_file_source::safe_bool() const
129{
130    return !!pimpl_ && pimpl_->error_ == false ?
131        &safe_bool_helper::x : 0;
132}
133
134bool mapped_file_source::operator!() const
135{ return !!pimpl_ || pimpl_->error_; }
136
137BOOST_IOS::openmode mapped_file_source::mode() const { return pimpl_->mode_; }
138
139const char* mapped_file_source::data() const { return pimpl_->data_; }
140
141const char* mapped_file_source::begin() const { return data(); }
142
143const char* mapped_file_source::end() const { return data() + size(); }
144
145#ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
146
147namespace detail {
148
149void cleanup_and_throw(detail::mapped_file_impl& impl, const char* msg)
150{
151    if (impl.mapped_handle_ != INVALID_HANDLE_VALUE)
152        ::CloseHandle(impl.mapped_handle_);
153    if (impl.handle_ != NULL)
154        ::CloseHandle(impl.handle_);
155    impl.clear(true);
156    throw_system_failure(msg);
157}
158
159} // End namespace detail.
160
161void mapped_file_source::open_impl(mapped_file_params p)
162{
163    using namespace std;
164
165    if (is_open())
166        throw BOOST_IOSTREAMS_FAILURE("file already open");
167    if (!pimpl_)
168        pimpl_.reset(new impl_type);
169    else
170        pimpl_->clear(false);
171    bool readonly = (p.mode & BOOST_IOS::out) == 0;
172    pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out);
173
174    //--------------Open underlying file--------------------------------------//
175
176    pimpl_->handle_ =
177        ::CreateFileA( p.path.c_str(),
178                       readonly ? GENERIC_READ : GENERIC_ALL,
179                       FILE_SHARE_READ,
180                       NULL,
181                       (p.new_file_size != 0 && !readonly) ? 
182                           CREATE_ALWAYS : 
183                           OPEN_EXISTING,
184                       readonly ?
185                           FILE_ATTRIBUTE_READONLY :
186                           FILE_ATTRIBUTE_TEMPORARY,
187                       NULL );
188
189    if (pimpl_->handle_ == INVALID_HANDLE_VALUE)
190        detail::cleanup_and_throw(*pimpl_, "failed opening file");
191
192    //--------------Set file size---------------------------------------------//
193
194    if (p.new_file_size != 0 && !readonly) {
195        LONG sizehigh = (p.new_file_size >> (sizeof(LONG) * 8));
196        LONG sizelow = (p.new_file_size & 0xffffffff);
197        ::SetFilePointer(pimpl_->handle_, sizelow, &sizehigh, FILE_BEGIN);
198        if (::GetLastError() != NO_ERROR || !::SetEndOfFile(pimpl_->handle_))
199            detail::cleanup_and_throw(*pimpl_, "failed setting file size");
200    }
201
202    //--------------Create mapping--------------------------------------------//
203
204    try_again: // Target of goto in following section.
205
206    pimpl_->mapped_handle_ =
207        ::CreateFileMappingA( pimpl_->handle_, NULL,
208                              readonly ? PAGE_READONLY : PAGE_READWRITE,
209                              0, 0, NULL );
210    if (pimpl_->mapped_handle_ == NULL) {
211        detail::cleanup_and_throw(*pimpl_, "couldn't create mapping");
212    }
213
214    //--------------Access data-----------------------------------------------//
215
216    void* data =
217        ::MapViewOfFileEx( pimpl_->mapped_handle_,
218                           readonly ? FILE_MAP_READ : FILE_MAP_WRITE,
219                           (DWORD) (p.offset >> 32),
220                           (DWORD) (p.offset & 0xffffffff),
221                           p.length != max_length ? p.length : 0, (LPVOID) p.hint );
222    if (!data) {
223        if (p.hint != 0) {
224            p.hint = 0;
225            goto try_again;
226        }
227        detail::cleanup_and_throw(*pimpl_, "failed mapping view");
228    }
229
230    //--------------Determing file size---------------------------------------//
231
232    // Dynamically locate GetFileSizeEx (thanks to Pavel Vozenilik).
233    typedef BOOL (WINAPI *func)(HANDLE, PLARGE_INTEGER);
234    HMODULE hmod = ::GetModuleHandleA("kernel32.dll");
235    func get_size =
236        reinterpret_cast<func>(::GetProcAddress(hmod, "GetFileSizeEx"));
237
238    if (get_size) {
239        LARGE_INTEGER info;
240        if (get_size(pimpl_->handle_, &info)) {
241            boost::intmax_t size =
242                ( (static_cast<boost::intmax_t>(info.HighPart) << 32) |
243                  info.LowPart );
244            pimpl_->size_ =
245                static_cast<std::size_t>(
246                    p.length != max_length ?
247                        std::min<boost::intmax_t>(p.length, size) :
248                        size
249                );
250        } else {
251            detail::cleanup_and_throw(*pimpl_, "failed getting file size");
252            return;
253        }
254    } else {
255        DWORD hi;
256        DWORD low;
257        if ( (low = ::GetFileSize(pimpl_->handle_, &hi))
258                 !=
259             INVALID_FILE_SIZE )
260        {
261            boost::intmax_t size =
262                (static_cast<boost::intmax_t>(hi) << 32) | low;
263            pimpl_->size_ =
264                static_cast<std::size_t>(
265                    p.length != max_length ?
266                        std::min<boost::intmax_t>(p.length, size) :
267                        size
268                );
269        } else {
270            detail::cleanup_and_throw(*pimpl_, "failed getting file size");
271            return;
272        }
273    }
274
275    pimpl_->data_ = reinterpret_cast<char*>(data);
276}
277
278int mapped_file_source::alignment()
279{
280    SYSTEM_INFO info;
281    ::GetSystemInfo(&info);
282    return static_cast<int>(info.dwAllocationGranularity);
283}
284
285#else // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------//
286
287namespace detail {
288
289void cleanup_and_throw(detail::mapped_file_impl& impl, const char* msg)
290{
291    if (impl.handle_ != 0)
292        ::close(impl.handle_);
293    impl.clear(true);
294    throw_system_failure(msg);
295}
296
297} // End namespace detail.
298
299
300void mapped_file_source::open_impl(mapped_file_params p)
301{
302    using namespace std;
303
304    if (is_open())
305        throw BOOST_IOSTREAMS_FAILURE("file already open");
306    if (!pimpl_)
307        pimpl_.reset(new impl_type);
308    else
309        pimpl_->clear(false);
310    bool readonly = (p.mode & BOOST_IOS::out) == 0;
311    pimpl_->mode_ = readonly ? BOOST_IOS::in : (BOOST_IOS::in | BOOST_IOS::out);
312
313    //--------------Open underlying file--------------------------------------//
314
315    int flags = (readonly ? O_RDONLY : O_RDWR);
316    if (p.new_file_size != 0 && !readonly)
317        flags |= (O_CREAT | O_TRUNC);
318    errno = 0;
319    pimpl_->handle_ = ::open(p.path.c_str(), flags, S_IRWXU);
320    if (errno != 0)
321        detail::cleanup_and_throw(*pimpl_, "failed opening file");
322
323    //--------------Set file size---------------------------------------------//
324
325    if (p.new_file_size != 0 && !readonly)
326        if (ftruncate(pimpl_->handle_, p.new_file_size) == -1)
327            detail::cleanup_and_throw(*pimpl_, "failed setting file size");
328
329    //--------------Determine file size---------------------------------------//
330
331    bool success = true;
332    struct stat info;
333    if (p.length != max_length)
334        pimpl_->size_ = p.length;
335    else {
336        success = ::fstat(pimpl_->handle_, &info) != -1;
337        pimpl_->size_ = info.st_size;
338    }
339    if (!success)
340        detail::cleanup_and_throw(*pimpl_, "failed getting file size");
341
342    //--------------Create mapping--------------------------------------------//
343
344    try_again: // Target of goto in following section.
345
346    char* hint = const_cast<char*>(p.hint);
347    void* data = ::mmap( hint, pimpl_->size_,
348                         readonly ? PROT_READ : (PROT_READ | PROT_WRITE),
349                         readonly ? MAP_PRIVATE : MAP_SHARED,
350                         pimpl_->handle_, p.offset );
351    if (data == MAP_FAILED) {
352        if (hint != 0) {
353            hint = 0;
354            goto try_again;
355        }
356        detail::cleanup_and_throw(*pimpl_, "failed mapping file");
357    }
358    pimpl_->data_ = reinterpret_cast<char*>(data);
359
360    return;
361}
362
363int mapped_file_source::alignment()
364{ return static_cast<int>(sysconf(_SC_PAGESIZE)); }
365
366#endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
367
368//------------------Implementation of mapped_file-----------------------------//
369
370mapped_file::mapped_file(mapped_file_params p) { delegate_.open_impl(p); }
371
372mapped_file::mapped_file( const std::string& path, BOOST_IOS::openmode mode,
373                          size_type length, stream_offset offset )
374{ open(path, mode, length, offset); }
375
376void mapped_file::open(mapped_file_params p)
377{ delegate_.open_impl(p); }
378
379void mapped_file::open( const std::string& path, BOOST_IOS::openmode mode,
380                        size_type length, stream_offset offset )
381{
382    mapped_file_params p(path);
383    p.mode = mode;
384    p.length = length;
385    p.offset = offset;
386    open(p);
387}
388
389//------------------Implementation of mapped_file_sink------------------------//
390
391mapped_file_sink::mapped_file_sink(mapped_file_params p) { open(p); }
392
393mapped_file_sink::mapped_file_sink( const std::string& path,
394                                    size_type length, stream_offset offset )
395{ open(path, length, offset); }
396
397void mapped_file_sink::open(mapped_file_params p)
398{
399    p.mode |= BOOST_IOS::out;
400    p.mode &= ~BOOST_IOS::in;
401    mapped_file::open(p);
402}
403
404void mapped_file_sink::open( const std::string& path, size_type length,
405                             stream_offset offset )
406{
407    mapped_file_params p(path);
408    p.mode = BOOST_IOS::out;
409    p.length = length;
410    p.offset = offset;
411    open(p);
412}
413
414//----------------------------------------------------------------------------//
415
416} } // End namespaces iostreams, boost.
417
418#include <boost/iostreams/detail/config/enable_warnings.hpp>
Note: See TracBrowser for help on using the repository browser.