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
;
124 if ( !(mode
& (BOOST_IOS::in
| BOOST_IOS::out
| BOOST_IOS::app
)) ||
125 ((mode
& BOOST_IOS::trunc
) &&
126 ((mode
& BOOST_IOS::app
) || !(mode
& BOOST_IOS::out
))) ) {
127 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
129 else if ( mode
& BOOST_IOS::in
) {
130 if ( mode
& BOOST_IOS::app
)
132 dwCreationDisposition
= OPEN_ALWAYS
;
136 FILE_WRITE_ATTRIBUTES
|
138 STANDARD_RIGHTS_WRITE
|
141 else if ( mode
& BOOST_IOS::trunc
)
143 dwCreationDisposition
= CREATE_ALWAYS
;
144 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
146 else if ( mode
& BOOST_IOS::out
)
148 dwCreationDisposition
= OPEN_EXISTING
;
149 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
153 dwCreationDisposition
= OPEN_EXISTING
;
154 dwDesiredAccess
= GENERIC_READ
;
158 if ( mode
& BOOST_IOS::app
)
160 dwCreationDisposition
= OPEN_ALWAYS
;
163 FILE_WRITE_ATTRIBUTES
|
165 STANDARD_RIGHTS_WRITE
|
170 dwCreationDisposition
= CREATE_ALWAYS
;
171 dwDesiredAccess
= GENERIC_WRITE
;
176 HANDLE handle
= p
.is_wide() ?
177 ::CreateFileW( p
.c_wstr(),
179 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
180 NULL
, // lpSecurityAttributes
181 dwCreationDisposition
,
182 FILE_ATTRIBUTE_NORMAL
,
183 NULL
) : // hTemplateFile
184 ::CreateFileA( p
.c_str(),
186 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
187 NULL
, // lpSecurityAttributes
188 dwCreationDisposition
,
189 FILE_ATTRIBUTE_NORMAL
,
190 NULL
); // hTemplateFile
191 if (handle
!= INVALID_HANDLE_VALUE
) {
193 flags_
= close_always
;
196 throw_system_failure("failed opening file");
198 #else // #ifdef BOOST_IOSTREAMS_WINDOWS //------------------------------------//
200 // Calculate oflag argument to open.
203 if ( !(mode
& (BOOST_IOS::in
| BOOST_IOS::out
| BOOST_IOS::app
)) ||
204 ((mode
& BOOST_IOS::trunc
) &&
205 ((mode
& BOOST_IOS::app
) || !(mode
& BOOST_IOS::out
))) ) {
206 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad open mode"));
208 else if ( mode
& BOOST_IOS::in
) {
209 if ( mode
& BOOST_IOS::app
)
210 oflag
|= O_CREAT
| O_APPEND
| O_RDWR
;
211 else if ( mode
& BOOST_IOS::trunc
)
212 oflag
|= O_CREAT
| O_TRUNC
| O_RDWR
;
213 else if ( mode
& BOOST_IOS::out
)
219 if ( mode
& BOOST_IOS::app
)
220 oflag
|= O_CREAT
| O_APPEND
| O_WRONLY
;
222 oflag
|= O_CREAT
| O_TRUNC
| O_WRONLY
;
224 #ifdef _LARGEFILE64_SOURCE
225 oflag
|= O_LARGEFILE
;
228 // Calculate pmode argument to open.
230 mode_t pmode
= S_IRUSR
| S_IWUSR
|
236 int fd
= BOOST_IOSTREAMS_FD_OPEN(p
.c_str(), oflag
, pmode
);
238 boost::throw_exception(system_failure("failed opening file"));
240 if ( mode
& BOOST_IOS::ate
) {
241 if (BOOST_IOSTREAMS_FD_SEEK(fd
, 0, SEEK_END
) == -1) {
242 BOOST_IOSTREAMS_FD_CLOSE(fd
);
243 boost::throw_exception(system_failure("failed opening file"));
247 flags_
= close_always
;
249 #endif // #ifndef BOOST_IOSTREAMS_WINDOWS //----------------------------------//
252 bool file_descriptor_impl::is_open() const
253 { return handle_
!= invalid_handle(); }
255 void file_descriptor_impl::close()
257 close_impl((flags_
& close_on_close
) != 0, true);
260 void file_descriptor_impl::close_impl(bool close_flag
, bool throw_
) {
261 if (handle_
!= invalid_handle()) {
264 #ifdef BOOST_IOSTREAMS_WINDOWS
265 ::CloseHandle(handle_
) == 1;
267 BOOST_IOSTREAMS_FD_CLOSE(handle_
) != -1;
269 if (!success
&& throw_
)
270 throw_system_failure("failed closing file");
272 handle_
= invalid_handle();
277 std::streamsize
file_descriptor_impl::read(char* s
, std::streamsize n
)
279 #ifdef BOOST_IOSTREAMS_WINDOWS
281 if (!::ReadFile(handle_
, s
, static_cast<DWORD
>(n
), &result
, NULL
))
283 // report EOF if the write-side of a pipe has been closed
284 if (GetLastError() == ERROR_BROKEN_PIPE
)
289 throw_system_failure("failed reading");
291 return result
== 0 ? -1 : static_cast<std::streamsize
>(result
);
292 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
294 std::streamsize result
= BOOST_IOSTREAMS_FD_READ(handle_
, s
, n
);
296 throw_system_failure("failed reading");
297 return result
== 0 ? -1 : result
;
298 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
301 std::streamsize
file_descriptor_impl::write(const char* s
, std::streamsize n
)
303 #ifdef BOOST_IOSTREAMS_WINDOWS
305 if (!::WriteFile(handle_
, s
, static_cast<DWORD
>(n
), &ignore
, NULL
))
306 throw_system_failure("failed writing");
308 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
309 int amt
= BOOST_IOSTREAMS_FD_WRITE(handle_
, s
, n
);
310 if (amt
< n
) // Handles blocking fd's only.
311 throw_system_failure("failed writing");
313 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
316 std::streampos
file_descriptor_impl::seek
317 (stream_offset off
, BOOST_IOS::seekdir way
)
319 #ifdef BOOST_IOSTREAMS_WINDOWS
320 LONG lDistanceToMove
= static_cast<LONG
>(off
& 0xffffffff);
321 LONG lDistanceToMoveHigh
= static_cast<LONG
>(off
>> 32);
323 ::SetFilePointer( handle_
,
325 &lDistanceToMoveHigh
,
326 way
== BOOST_IOS::beg
?
328 way
== BOOST_IOS::cur
?
331 if ( dwResultLow
== INVALID_SET_FILE_POINTER
&&
332 ::GetLastError() != NO_ERROR
)
334 boost::throw_exception(system_failure("failed seeking"));
336 return offset_to_position(
337 (stream_offset(lDistanceToMoveHigh
) << 32) + dwResultLow
340 #else // #ifdef BOOST_IOSTREAMS_WINDOWS
341 if ( off
> integer_traits
<BOOST_IOSTREAMS_FD_OFFSET
>::const_max
||
342 off
< integer_traits
<BOOST_IOSTREAMS_FD_OFFSET
>::const_min
)
344 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("bad offset"));
346 stream_offset result
=
347 BOOST_IOSTREAMS_FD_SEEK(
349 static_cast<BOOST_IOSTREAMS_FD_OFFSET
>(off
),
350 ( way
== BOOST_IOS::beg
?
352 way
== BOOST_IOS::cur
?
357 boost::throw_exception(system_failure("failed seeking"));
358 return offset_to_position(result
);
359 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS
362 // Returns the value stored in a file_handle variable when no file is open
363 file_handle
file_descriptor_impl::invalid_handle()
365 #ifdef BOOST_IOSTREAMS_WINDOWS
366 return INVALID_HANDLE_VALUE
;
372 } // End namespace detail.
374 //------------------Implementation of file_descriptor-------------------------//
376 file_descriptor::file_descriptor() : pimpl_(new impl_type
) { }
378 file_descriptor::file_descriptor(handle_type fd
, file_descriptor_flags f
)
379 : pimpl_(new impl_type
)
382 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
383 file_descriptor::file_descriptor(handle_type fd
, bool close_on_exit
)
384 : pimpl_(new impl_type
)
385 { open(fd
, close_on_exit
); }
388 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
390 file_descriptor::file_descriptor(int fd
, file_descriptor_flags f
)
391 : pimpl_(new impl_type
)
394 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
395 file_descriptor::file_descriptor(int fd
, bool close_on_exit
)
396 : pimpl_(new impl_type
)
397 { open(fd
, close_on_exit
); }
400 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
402 file_descriptor::file_descriptor( const std::string
& path
,
403 BOOST_IOS::openmode mode
)
404 : pimpl_(new impl_type
)
405 { open(path
, mode
); }
407 file_descriptor::file_descriptor( const char* path
,
408 BOOST_IOS::openmode mode
)
409 : pimpl_(new impl_type
)
410 { open(path
, mode
); }
412 file_descriptor::file_descriptor(const file_descriptor
& other
)
413 : pimpl_(other
.pimpl_
)
416 void file_descriptor::open(handle_type fd
, file_descriptor_flags f
)
417 { pimpl_
->open(fd
, static_cast<detail::file_descriptor_impl::flags
>(f
)); }
419 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
420 void file_descriptor::open(handle_type fd
, bool close_on_exit
)
421 { pimpl_
->open(fd
, close_on_exit
?
422 detail::file_descriptor_impl::close_always
:
423 detail::file_descriptor_impl::close_on_close
); }
426 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
428 void file_descriptor::open(int fd
, file_descriptor_flags f
)
429 { pimpl_
->open(fd
, static_cast<detail::file_descriptor_impl::flags
>(f
)); }
431 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
432 void file_descriptor::open(int fd
, bool close_on_exit
)
433 { pimpl_
->open(fd
, close_on_exit
?
434 detail::file_descriptor_impl::close_always
:
435 detail::file_descriptor_impl::close_on_close
); }
438 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
440 void file_descriptor::open(const std::string
& path
, BOOST_IOS::openmode mode
)
441 { open(detail::path(path
), mode
); }
443 void file_descriptor::open(const char* path
, BOOST_IOS::openmode mode
)
444 { open(detail::path(path
), mode
); }
446 bool file_descriptor::is_open() const { return pimpl_
->is_open(); }
448 void file_descriptor::close() { pimpl_
->close(); }
450 std::streamsize
file_descriptor::read(char_type
* s
, std::streamsize n
)
451 { return pimpl_
->read(s
, n
); }
453 std::streamsize
file_descriptor::write(const char_type
* s
, std::streamsize n
)
454 { return pimpl_
->write(s
, n
); }
456 std::streampos
file_descriptor::seek(stream_offset off
, BOOST_IOS::seekdir way
)
457 { return pimpl_
->seek(off
, way
); }
459 detail::file_handle
file_descriptor::handle() const { return pimpl_
->handle_
; }
461 void file_descriptor::init() { pimpl_
.reset(new impl_type
); }
463 void file_descriptor::open(
464 const detail::path
& path
,
465 BOOST_IOS::openmode mode
,
466 BOOST_IOS::openmode base
)
469 pimpl_
->open(path
, mode
);
472 //------------------Implementation of file_descriptor_source------------------//
474 file_descriptor_source::file_descriptor_source(
475 handle_type fd
, file_descriptor_flags f
)
478 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
479 file_descriptor_source::file_descriptor_source(
480 handle_type fd
, bool close_on_exit
)
481 { open(fd
, close_on_exit
); }
484 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
486 file_descriptor_source::file_descriptor_source(int fd
, file_descriptor_flags f
)
489 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
490 file_descriptor_source::file_descriptor_source(int fd
, bool close_on_exit
)
491 { open(fd
, close_on_exit
); }
494 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
496 file_descriptor_source::file_descriptor_source(
497 const std::string
& path
, BOOST_IOS::openmode mode
)
498 { open(path
, mode
); }
500 file_descriptor_source::file_descriptor_source(
501 const char* path
, BOOST_IOS::openmode mode
)
502 { open(path
, mode
); }
504 file_descriptor_source::file_descriptor_source(
505 const file_descriptor_source
& other
)
506 : file_descriptor(static_cast<const file_descriptor
&>(other
))
509 void file_descriptor_source::open(handle_type fd
, file_descriptor_flags f
)
510 { file_descriptor::open(fd
, f
); }
512 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
513 void file_descriptor_source::open(handle_type fd
, bool close_on_exit
)
514 { file_descriptor::open(fd
, close_on_exit
); }
517 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
519 void file_descriptor_source::open(int fd
, file_descriptor_flags f
)
520 { file_descriptor::open(fd
, f
); }
522 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
523 void file_descriptor_source::open(int fd
, bool close_on_exit
)
524 { file_descriptor::open(fd
, close_on_exit
); }
527 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
529 void file_descriptor_source::open(
530 const std::string
& path
, BOOST_IOS::openmode mode
)
531 { open(detail::path(path
), mode
); }
533 void file_descriptor_source::open(
534 const char* path
, BOOST_IOS::openmode mode
)
535 { open(detail::path(path
), mode
); }
537 void file_descriptor_source::open(
538 const detail::path
& path
, BOOST_IOS::openmode mode
)
540 if (mode
& (BOOST_IOS::out
| BOOST_IOS::trunc
))
541 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode"));
542 file_descriptor::open(path
, mode
, BOOST_IOS::in
);
545 //------------------Implementation of file_descriptor_sink--------------------//
547 file_descriptor_sink::file_descriptor_sink(
548 handle_type fd
, file_descriptor_flags f
)
551 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
552 file_descriptor_sink::file_descriptor_sink(
553 handle_type fd
, bool close_on_exit
)
554 { open(fd
, close_on_exit
); }
557 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
559 file_descriptor_sink::file_descriptor_sink(int fd
, file_descriptor_flags f
)
562 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
563 file_descriptor_sink::file_descriptor_sink(int fd
, bool close_on_exit
)
564 { open(fd
, close_on_exit
); }
567 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
569 file_descriptor_sink::file_descriptor_sink(
570 const std::string
& path
, BOOST_IOS::openmode mode
)
571 { open(path
, mode
); }
573 file_descriptor_sink::file_descriptor_sink(
574 const char* path
, BOOST_IOS::openmode mode
)
575 { open(path
, mode
); }
577 file_descriptor_sink::file_descriptor_sink(const file_descriptor_sink
& other
)
578 : file_descriptor(static_cast<const file_descriptor
&>(other
))
581 void file_descriptor_sink::open(handle_type fd
, file_descriptor_flags f
)
582 { file_descriptor::open(fd
, f
); }
584 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
585 void file_descriptor_sink::open(handle_type fd
, bool close_on_exit
)
586 { file_descriptor::open(fd
, close_on_exit
); }
589 #ifdef BOOST_IOSTREAMS_WINDOWS //---------------------------------------------//
591 void file_descriptor_sink::open(int fd
, file_descriptor_flags f
)
592 { file_descriptor::open(fd
, f
); }
594 #if defined(BOOST_IOSTREAMS_USE_DEPRECATED)
595 void file_descriptor_sink::open(int fd
, bool close_on_exit
)
596 { file_descriptor::open(fd
, close_on_exit
); }
599 #endif // #ifdef BOOST_IOSTREAMS_WINDOWS //-----------------------------------//
601 void file_descriptor_sink::open(
602 const std::string
& path
, BOOST_IOS::openmode mode
)
603 { open(detail::path(path
), mode
); }
605 void file_descriptor_sink::open(
606 const char* path
, BOOST_IOS::openmode mode
)
607 { open(detail::path(path
), mode
); }
609 void file_descriptor_sink::open(
610 const detail::path
& path
, BOOST_IOS::openmode mode
)
612 if (mode
& BOOST_IOS::in
)
613 boost::throw_exception(BOOST_IOSTREAMS_FAILURE("invalid mode"));
614 file_descriptor::open(path
, mode
, BOOST_IOS::out
);
617 #include <boost/iostreams/detail/config/enable_warnings.hpp>
619 } } // End namespaces iostreams, boost.