1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2003-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
6 // See http://www.boost.org/libs/iostreams for documentation.
8 // Define BOOST_IOSTREAMS_SOURCE so that <boost/iostreams/detail/config.hpp>
9 // knows that we are building the library (possibly exporting code), rather
10 // than using it (possibly importing code).
11 #define BOOST_IOSTREAMS_SOURCE
15 #include <cstdio> // SEEK_SET, etc.
16 #include <boost/config.hpp> // BOOST_JOIN
17 #include <boost/iostreams/detail/error.hpp>
18 #include <boost/iostreams/detail/config/dyn_link.hpp>
19 #include <boost/iostreams/detail/config/rtl.hpp> // BOOST_IOSTREAMS_FD_XXX
20 #include <boost/iostreams/detail/config/windows_posix.hpp>
21 #include <boost/iostreams/detail/system_failure.hpp>
22 #include <boost/iostreams/detail/ios.hpp> // openmodes, failure.
23 #include <boost/iostreams/device/file_descriptor.hpp>
24 #include <boost/integer_traits.hpp>
25 #include <boost/throw_exception.hpp>
28 #include <boost/iostreams/detail/config/disable_warnings.hpp>
30 // OS-specific headers for low-level i/o.
32 #include <fcntl.h> // file opening flags.
33 #include <sys/stat.h> // file access permissions.
34 #ifdef BOOST_IOSTREAMS_WINDOWS
35 # include <io.h> // low-level file i/o.
36 # define WINDOWS_LEAN_AND_MEAN
38 # ifndef INVALID_SET_FILE_POINTER
39 # define INVALID_SET_FILE_POINTER ((DWORD)-1)
42 # include <sys/types.h> // mode_t.
43 # include <unistd.h> // low-level file i/o.
46 namespace boost
{ namespace iostreams
{
48 //------------------Definition of file_descriptor_impl------------------------//
52 // Contains the platform dependant implementation
53 struct file_descriptor_impl
{
54 // Note: These need to match file_desciptor_flags
62 file_descriptor_impl();
63 ~file_descriptor_impl();
64 void open(file_handle fd
, flags
);
65 #ifdef BOOST_IOSTREAMS_WINDOWS
66 void open(int fd
, flags
);
68 void open(const detail::path
&, BOOST_IOS::openmode
);
71 void close_impl(bool close_flag
, bool throw_
);
72 std::streamsize
read(char* s
, std::streamsize n
);
73 std::streamsize
write(const char* s
, std::streamsize n
);
74 std::streampos
seek(stream_offset off
, BOOST_IOS::seekdir way
);
75 static file_handle
invalid_handle();
80 //------------------Implementation of file_descriptor_impl--------------------//
82 file_descriptor_impl::file_descriptor_impl()
83 : handle_(invalid_handle()), flags_(0)
86 file_descriptor_impl::~file_descriptor_impl()
88 close_impl(flags_
& close_on_exit
, false);
91 void file_descriptor_impl::open(file_handle fd
, flags f
)
93 // Using 'close' to close the existing handle so that it will throw an
94 // exception if it fails.
96 // Only closing after assigning the new handle, so that the class will
97 // take ownership of the handle regardless of whether close throws.
99 file_descriptor_impl tmp
;
100 tmp
.handle_
= handle_
;
101 tmp
.flags_
= flags_
& close_on_exit
? close_on_close
: never_close
;
109 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
111 void file_descriptor_impl::open(int fd
, flags f
)
112 { open(reinterpret_cast<file_handle
>(_get_osfhandle(fd
)), f
); }
114 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
116 void file_descriptor_impl::open(const detail::path
& p
, BOOST_IOS::openmode mode
)
118 close_impl(flags_
& close_on_exit
, true);
120 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
121 DWORD dwDesiredAccess
;
122 DWORD dwCreationDisposition
;
123 if ( (mode
& (BOOST_IOS::in
| BOOST_IOS::out
))
125 (BOOST_IOS::in
| BOOST_IOS::out
) )
127 if (mode
& BOOST_IOS::app
)
128 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
129 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
130 dwCreationDisposition
=
131 (mode
& BOOST_IOS::trunc
) ?
134 } else if (mode
& BOOST_IOS::in
) {
135 if (mode
& (BOOST_IOS::app
| BOOST_IOS::trunc
))
136 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
137 dwDesiredAccess
= GENERIC_READ
;
138 dwCreationDisposition
= OPEN_EXISTING
;
139 } else if (mode
& BOOST_IOS::out
) {
140 if ( (mode
& (BOOST_IOS::app
| BOOST_IOS::trunc
))
142 (BOOST_IOS::app
| BOOST_IOS::trunc
) )
143 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
144 if (mode
& BOOST_IOS::app
) {
145 dwCreationDisposition
= OPEN_ALWAYS
;
148 FILE_WRITE_ATTRIBUTES
|
150 STANDARD_RIGHTS_WRITE
|
153 dwDesiredAccess
= GENERIC_WRITE
;
154 dwCreationDisposition
= CREATE_ALWAYS
;
157 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
160 HANDLE handle
= p
.is_wide() ?
161 ::CreateFileW( p
.c_wstr(),
163 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
164 NULL
, // lpSecurityAttributes
165 dwCreationDisposition
,
166 FILE_ATTRIBUTE_NORMAL
,
167 NULL
) : // hTemplateFile
168 ::CreateFileA( p
.c_str(),
170 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
171 NULL
, // lpSecurityAttributes
172 dwCreationDisposition
,
173 FILE_ATTRIBUTE_NORMAL
,
174 NULL
); // hTemplateFile
175 if (handle
!= INVALID_HANDLE_VALUE
) {
177 flags_
= close_always
;
180 throw_system_failure("failed opening file");
182 #else // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------//
184 // Calculate oflag argument to open.
187 if ( (mode
& (BOOST_IOS::in
| BOOST_IOS::out
))
189 (BOOST_IOS::in
| BOOST_IOS::out
) )
191 if( mode
& BOOST_IOS::app
)
192 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
194 if( mode
& BOOST_IOS::trunc
) {
198 } else if (mode
& BOOST_IOS::in
) {
199 if( mode
& (BOOST_IOS::app
| BOOST_IOS::trunc
) )
200 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
202 } else if (mode
& BOOST_IOS::out
) {
203 if( (mode
& (BOOST_IOS::app
| BOOST_IOS::trunc
))
205 (BOOST_IOS::app
| BOOST_IOS::trunc
) )
206 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
208 if (mode
& BOOST_IOS::app
)
215 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
217 #ifdef _LARGEFILE64_SOURCE
218 oflag
|= O_LARGEFILE
;
221 // Calculate pmode argument to open.
223 mode_t pmode
= S_IRUSR
| S_IWUSR
|
229 int fd
= BOOST_IOSTREAMS_FD_OPEN(p
.c_str(), oflag
, pmode
);
231 boost::throw_exception(system_failure("failed opening file"));
234 flags_
= close_always
;
236 #endif // #ifndef BOOST_IOSTREAMS_WINDOWS //----------------------------------//
239 bool file_descriptor_impl::is_open() const
240 { return handle_
!= invalid_handle(); }
242 void file_descriptor_impl::close()
244 close_impl((flags_
& close_on_close
) != 0, true);
247 void file_descriptor_impl::close_impl(bool close_flag
, bool throw_
) {
248 if (handle_
!= invalid_handle()) {
251 #ifdef BOOST_IOSTREAMS_WINDOWS
252 ::CloseHandle(handle_
) == 1;
254 BOOST_IOSTREAMS_FD_CLOSE(handle_
) != -1;
256 if (!success
&& throw_
)
257 throw_system_failure("failed closing file");
259 handle_
= invalid_handle();
264 std::streamsize
file_descriptor_impl::read(char* s
, std::streamsize n
)
266 #ifdef BOOST_IOSTREAMS_WINDOWS
268 if (!::ReadFile(handle_
, s
, n
, &result
, NULL
))
270 // report EOF if the write-side of a pipe has been closed
271 if (GetLastError() == ERROR_BROKEN_PIPE
)
276 throw_system_failure("failed reading");
278 return result
== 0 ? -1 : static_cast<std::streamsize
>(result
);
279 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
281 std::streamsize result
= BOOST_IOSTREAMS_FD_READ(handle_
, s
, n
);
283 throw_system_failure("failed reading");
284 return result
== 0 ? -1 : result
;
285 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
288 std::streamsize
file_descriptor_impl::write(const char* s
, std::streamsize n
)
290 #ifdef BOOST_IOSTREAMS_WINDOWS
292 if (!::WriteFile(handle_
, s
, n
, &ignore
, NULL
))
293 throw_system_failure("failed writing");
295 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
296 int amt
= BOOST_IOSTREAMS_FD_WRITE(handle_
, s
, n
);
297 if (amt
< n
) // Handles blocking fd's only.
298 throw_system_failure("failed writing");
300 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
303 std::streampos
file_descriptor_impl::seek
304 (stream_offset off
, BOOST_IOS::seekdir way
)
306 #ifdef BOOST_IOSTREAMS_WINDOWS
307 LONG lDistanceToMove
= static_cast<LONG
>(off
& 0xffffffff);
308 LONG lDistanceToMoveHigh
= static_cast<LONG
>(off
>> 32);
310 ::SetFilePointer( handle_
,
312 &lDistanceToMoveHigh
,
313 way
== BOOST_IOS::beg
?
315 way
== BOOST_IOS::cur
?
318 if ( dwResultLow
== INVALID_SET_FILE_POINTER
&&
319 ::GetLastError() != NO_ERROR
)
321 boost::throw_exception(system_failure("failed seeking"));
323 return offset_to_position(
324 (stream_offset(lDistanceToMoveHigh
) << 32) + dwResultLow
327 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
328 if ( off
> integer_traits
<BOOST_IOSTREAMS_FD_OFFSET
>::const_max
||
329 off
< integer_traits
<BOOST_IOSTREAMS_FD_OFFSET
>::const_min
)
331 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad offset"));
333 stream_offset result
=
334 BOOST_IOSTREAMS_FD_SEEK(
336 static_cast<BOOST_IOSTREAMS_FD_OFFSET
>(off
),
337 ( way
== BOOST_IOS::beg
?
339 way
== BOOST_IOS::cur
?
344 boost::throw_exception(system_failure("failed seeking"));
345 return offset_to_position(result
);
346 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
349 // Returns the value stored in a file_handle variable when no file is open
350 file_handle
file_descriptor_impl::invalid_handle()
352 #ifdef BOOST_IOSTREAMS_WINDOWS
353 return INVALID_HANDLE_VALUE
;
359 } // End namespace detail.
361 //------------------Implementation of file_descriptor-------------------------//
363 file_descriptor::file_descriptor() : pimpl_(new impl_type
) { }
365 file_descriptor::file_descriptor(handle_type fd
, file_descriptor_flags f
)
366 : pimpl_(new impl_type
)
369 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
370 file_descriptor::file_descriptor(handle_type fd
, bool close_on_exit
)
371 : pimpl_(new impl_type
)
372 { open(fd
, close_on_exit
); }
375 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
377 file_descriptor::file_descriptor(int fd
, file_descriptor_flags f
)
378 : pimpl_(new impl_type
)
381 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
382 file_descriptor::file_descriptor(int fd
, bool close_on_exit
)
383 : pimpl_(new impl_type
)
384 { open(fd
, close_on_exit
); }
387 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
389 file_descriptor::file_descriptor( const std::string
& path
,
390 BOOST_IOS::openmode mode
)
391 : pimpl_(new impl_type
)
392 { open(path
, mode
); }
394 file_descriptor::file_descriptor( const char* path
,
395 BOOST_IOS::openmode mode
)
396 : pimpl_(new impl_type
)
397 { open(path
, mode
); }
399 file_descriptor::file_descriptor(const file_descriptor
& other
)
400 : pimpl_(other
.pimpl_
)
403 void file_descriptor::open(handle_type fd
, file_descriptor_flags f
)
404 { pimpl_
->open(fd
, static_cast<detail::file_descriptor_impl::flags
>(f
)); }
406 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
407 void file_descriptor::open(handle_type fd
, bool close_on_exit
)
408 { pimpl_
->open(fd
, close_on_exit
?
409 detail::file_descriptor_impl::close_always
:
410 detail::file_descriptor_impl::close_on_close
); }
413 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
415 void file_descriptor::open(int fd
, file_descriptor_flags f
)
416 { pimpl_
->open(fd
, static_cast<detail::file_descriptor_impl::flags
>(f
)); }
418 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
419 void file_descriptor::open(int fd
, bool close_on_exit
)
420 { pimpl_
->open(fd
, close_on_exit
?
421 detail::file_descriptor_impl::close_always
:
422 detail::file_descriptor_impl::close_on_close
); }
425 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
427 void file_descriptor::open(const std::string
& path
, BOOST_IOS::openmode mode
)
428 { open(detail::path(path
), mode
); }
430 void file_descriptor::open(const char* path
, BOOST_IOS::openmode mode
)
431 { open(detail::path(path
), mode
); }
433 bool file_descriptor::is_open() const { return pimpl_
->is_open(); }
435 void file_descriptor::close() { pimpl_
->close(); }
437 std::streamsize
file_descriptor::read(char_type
* s
, std::streamsize n
)
438 { return pimpl_
->read(s
, n
); }
440 std::streamsize
file_descriptor::write(const char_type
* s
, std::streamsize n
)
441 { return pimpl_
->write(s
, n
); }
443 std::streampos
file_descriptor::seek(stream_offset off
, BOOST_IOS::seekdir way
)
444 { return pimpl_
->seek(off
, way
); }
446 detail::file_handle
file_descriptor::handle() const { return pimpl_
->handle_
; }
448 void file_descriptor::init() { pimpl_
.reset(new impl_type
); }
450 void file_descriptor::open(
451 const detail::path
& path
,
452 BOOST_IOS::openmode mode
,
453 BOOST_IOS::openmode base
)
456 pimpl_
->open(path
, mode
);
459 //------------------Implementation of file_descriptor_source------------------//
461 file_descriptor_source::file_descriptor_source(
462 handle_type fd
, file_descriptor_flags f
)
465 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
466 file_descriptor_source::file_descriptor_source(
467 handle_type fd
, bool close_on_exit
)
468 { open(fd
, close_on_exit
); }
471 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
473 file_descriptor_source::file_descriptor_source(int fd
, file_descriptor_flags f
)
476 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
477 file_descriptor_source::file_descriptor_source(int fd
, bool close_on_exit
)
478 { open(fd
, close_on_exit
); }
481 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
483 file_descriptor_source::file_descriptor_source(
484 const std::string
& path
, BOOST_IOS::openmode mode
)
485 { open(path
, mode
); }
487 file_descriptor_source::file_descriptor_source(
488 const char* path
, BOOST_IOS::openmode mode
)
489 { open(path
, mode
); }
491 file_descriptor_source::file_descriptor_source(
492 const file_descriptor_source
& other
)
493 : file_descriptor(static_cast<const file_descriptor
&>(other
))
496 void file_descriptor_source::open(handle_type fd
, file_descriptor_flags f
)
497 { file_descriptor::open(fd
, f
); }
499 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
500 void file_descriptor_source::open(handle_type fd
, bool close_on_exit
)
501 { file_descriptor::open(fd
, close_on_exit
); }
504 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
506 void file_descriptor_source::open(int fd
, file_descriptor_flags f
)
507 { file_descriptor::open(fd
, f
); }
509 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
510 void file_descriptor_source::open(int fd
, bool close_on_exit
)
511 { file_descriptor::open(fd
, close_on_exit
); }
514 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
516 void file_descriptor_source::open(
517 const std::string
& path
, BOOST_IOS::openmode mode
)
518 { open(detail::path(path
), mode
); }
520 void file_descriptor_source::open(
521 const char* path
, BOOST_IOS::openmode mode
)
522 { open(detail::path(path
), mode
); }
524 void file_descriptor_source::open(
525 const detail::path
& path
, BOOST_IOS::openmode mode
)
527 if (mode
& (BOOST_IOS::out
| BOOST_IOS::app
| BOOST_IOS::trunc
))
528 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode"));
529 file_descriptor::open(path
, mode
, BOOST_IOS::in
);
532 //------------------Implementation of file_descriptor_sink--------------------//
534 file_descriptor_sink::file_descriptor_sink(
535 handle_type fd
, file_descriptor_flags f
)
538 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
539 file_descriptor_sink::file_descriptor_sink(
540 handle_type fd
, bool close_on_exit
)
541 { open(fd
, close_on_exit
); }
544 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
546 file_descriptor_sink::file_descriptor_sink(int fd
, file_descriptor_flags f
)
549 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
550 file_descriptor_sink::file_descriptor_sink(int fd
, bool close_on_exit
)
551 { open(fd
, close_on_exit
); }
554 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
556 file_descriptor_sink::file_descriptor_sink(
557 const std::string
& path
, BOOST_IOS::openmode mode
)
558 { open(path
, mode
); }
560 file_descriptor_sink::file_descriptor_sink(
561 const char* path
, BOOST_IOS::openmode mode
)
562 { open(path
, mode
); }
564 file_descriptor_sink::file_descriptor_sink(const file_descriptor_sink
& other
)
565 : file_descriptor(static_cast<const file_descriptor
&>(other
))
568 void file_descriptor_sink::open(handle_type fd
, file_descriptor_flags f
)
569 { file_descriptor::open(fd
, f
); }
571 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
572 void file_descriptor_sink::open(handle_type fd
, bool close_on_exit
)
573 { file_descriptor::open(fd
, close_on_exit
); }
576 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
578 void file_descriptor_sink::open(int fd
, file_descriptor_flags f
)
579 { file_descriptor::open(fd
, f
); }
581 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
582 void file_descriptor_sink::open(int fd
, bool close_on_exit
)
583 { file_descriptor::open(fd
, close_on_exit
); }
586 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
588 void file_descriptor_sink::open(
589 const std::string
& path
, BOOST_IOS::openmode mode
)
590 { open(detail::path(path
), mode
); }
592 void file_descriptor_sink::open(
593 const char* path
, BOOST_IOS::openmode mode
)
594 { open(detail::path(path
), mode
); }
596 void file_descriptor_sink::open(
597 const detail::path
& path
, BOOST_IOS::openmode mode
)
599 if (mode
& BOOST_IOS::in
)
600 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode"));
601 file_descriptor::open(path
, mode
, BOOST_IOS::out
);
604 #include <boost/iostreams/detail/config/enable_warnings.hpp>
606 } } // End namespaces iostreams, boost.