4#include "Stroika/Foundation/StroikaPreComp.h"
10#if qStroika_Foundation_Common_Platform_POSIX
12#elif qStroika_Foundation_Common_Platform_Windows
19#include "Stroika/Foundation/Execution/Activity.h"
20#include "Stroika/Foundation/Execution/Common.h"
21#include "Stroika/Foundation/Execution/Exceptions.h"
22#include "Stroika/Foundation/Execution/Throw.h"
23#if qStroika_Foundation_Common_Platform_Windows
24#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
26#include "Stroika/Foundation/Streams/InternallySynchronizedOutputStream.h"
36using namespace Stroika::Foundation::Debug;
38using namespace Stroika::Foundation::IO;
40using namespace Stroika::Foundation::IO::FileSystem::FileOutputStream;
44using Execution::ThrowSystemErrNo;
46#if qStroika_Foundation_Common_Platform_Windows
54 Rep_ (
const Rep_&) =
delete;
55 Rep_ (
const filesystem::path& fileName, AppendFlag appendFlag, FlushFlag flushFlag)
57 , fFlushFlag{flushFlag}
58 , fFileName_{fileName}
60 auto activity =
LazyEvalActivity ([&] () ->
String {
return "opening {} for write access"_f(fFileName_); });
62#if qStroika_Foundation_Common_Platform_Windows
63 int appendFlag2Or = appendFlag == eStartFromStart ? _O_TRUNC : _O_APPEND;
64 errno_t e = ::_wsopen_s (&fFD_, fileName.generic_wstring ().c_str (), _O_WRONLY | _O_CREAT | _O_BINARY | appendFlag2Or,
65 _SH_DENYNO, _S_IREAD | _S_IWRITE);
73 int appendFlag2Or = appendFlag == eStartFromStart ? O_TRUNC : O_APPEND;
74 const mode_t kCreateMode_ = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
76 fFD_ = ::open (fileName.generic_string ().c_str (), O_WRONLY | O_CREAT | appendFlag2Or, kCreateMode_), fileName);
79 Rep_ (FileDescriptorType fd, AdoptFDPolicy adoptFDPolicy, SeekableFlag seekableFlag, FlushFlag flushFlag)
81 , fFlushFlag{flushFlag}
82 , fAdoptFDPolicy_{adoptFDPolicy}
88 IgnoreExceptionsForCall (Flush ());
89 if (fAdoptFDPolicy_ == AdoptFDPolicy::eCloseOnDestruction and IsOpenWrite ()) {
90#if qStroika_Foundation_Common_Platform_Windows
97 nonvirtual Rep_& operator= (
const Rep_&) =
delete;
104 if (IsOpenWrite ()) {
105 if (fAdoptFDPolicy_ == AdoptFDPolicy::eCloseOnDestruction) {
106#if qStroika_Foundation_Common_Platform_Windows
114 Ensure (not IsOpenWrite ());
120 virtual void Write (span<const byte> elts)
override
122 Require (not elts.empty ());
126 const byte* i = elts.data ();
127 const byte* end = elts.data () + elts.size ();
129#if qStroika_Foundation_Common_Platform_Windows
134 Assert (n <= (end - i));
138 virtual void Flush ()
override
141 if (fFlushFlag == FlushFlag::eToDisk) {
145#if qStroika_Foundation_Common_Platform_POSIX
147#elif qStroika_Foundation_Common_Platform_Windows
157#if qStroika_Foundation_Common_Platform_Linux
159#elif qStroika_Foundation_Common_Platform_Windows
167 Require (fSeekable_);
168 using namespace Streams;
169 static const auto kException_ = range_error{
"seek"};
173 if (offset < 0) [[unlikely]] {
176#if qStroika_Foundation_Common_Platform_Linux
178#elif qStroika_Foundation_Common_Platform_Windows
185#if qStroika_Foundation_Common_Platform_Linux
187#elif qStroika_Foundation_Common_Platform_Windows
194#if qStroika_Foundation_Common_Platform_Linux
196#elif qStroika_Foundation_Common_Platform_Windows
210 AdoptFDPolicy fAdoptFDPolicy_{AdoptFDPolicy::eCloseOnDestruction};
211 bool fSeekable_{
true};
212 optional<filesystem::path> fFileName_;
222auto FileOutputStream::New (
const filesystem::path& fileName, FlushFlag flushFlag) ->
Ptr
224 return Ptr{Memory::MakeSharedPtr<Rep_> (fileName, AppendFlag::eDEFAULT, flushFlag)};
227auto FileOutputStream::New (
const filesystem::path& fileName, AppendFlag appendFlag, FlushFlag flushFlag) ->
Ptr
229 return Ptr{Memory::MakeSharedPtr<Rep_> (fileName, appendFlag, flushFlag)};
232auto FileOutputStream::New (FileDescriptorType fd, AdoptFDPolicy adoptFDPolicy, SeekableFlag seekableFlag, FlushFlag flushFlag) ->
Ptr
234 return Ptr{Memory::MakeSharedPtr<Rep_> (fd, adoptFDPolicy, seekableFlag, flushFlag)};
239 switch (internallySynchronized) {
240 case Execution::eInternallySynchronized:
241 return Streams::InternallySynchronizedOutputStream::New<Rep_> ({}, fileName, AppendFlag::eDEFAULT, flushFlag);
242 case Execution::eNotKnownInternallySynchronized:
243 return New (fileName, AppendFlag::eDEFAULT, flushFlag);
251 AppendFlag appendFlag, FlushFlag flushFlag) ->
Ptr
253 switch (internallySynchronized) {
254 case Execution::eInternallySynchronized:
255 return Streams::InternallySynchronizedOutputStream::New<Rep_> ({}, fileName, appendFlag, flushFlag);
256 case Execution::eNotKnownInternallySynchronized:
257 return New (fileName, appendFlag, flushFlag);
265 SeekableFlag seekableFlag, FlushFlag flushFlag) ->
Ptr
267 switch (internallySynchronized) {
268 case Execution::eInternallySynchronized:
269 return Streams::InternallySynchronizedOutputStream::New<Rep_> ({}, fd, adoptFDPolicy, seekableFlag, flushFlag);
270 case Execution::eNotKnownInternallySynchronized:
271 return New (fd, adoptFDPolicy, seekableFlag, flushFlag);
#define AssertNotImplemented()
#define RequireNotReached()
int64_t SignedSeekOffsetType
String is like std::u32string, except it is much easier to use, often much more space efficient,...
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
static INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode, const path &p1={}, const path &p2={})
static void ThrowPOSIXErrNo(errno_t errNo, const path &p1={}, const path &p2={})
treats errNo as a POSIX errno value, and throws a FileSystem::Exception (subclass of @std::filesystem...
static void ThrowSystemErrNo(int sysErr, const path &p1={}, const path &p2={})
treats errNo as a platform-defined error number, and throws a FileSystem::Exception (subclass of @std...
virtual bool IsSeekable() const =0
Abstract interface for output stream object. Don't call directly (use Ptr usually) - but use directly...
virtual void CloseWrite()=0
virtual void Write(span< const ELEMENT_TYPE > elts)=0
virtual bool IsOpenWrite() const =0
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
void ThrowPOSIXErrNo(errno_t errNo=errno)
treats errNo as a POSIX errno value, and throws a SystemError (subclass of @std::system_error) except...
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)