From 74510a95be6c8d3911b538c848efd3d6b6ba6d72 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 17 Jul 2013 07:02:33 -0700 Subject: [PATCH] Add RandomAccessFile --- .../Builds/VisualStudio2012/beast.vcxproj | 7 + .../VisualStudio2012/beast.vcxproj.filters | 6 + .../beast/modules/beast_core/beast_core.cpp | 1 + .../beast/modules/beast_core/beast_core.h | 1 + .../files/beast_RandomAccessFile.cpp | 214 ++++++++++++++++ .../beast_core/files/beast_RandomAccessFile.h | 242 ++++++++++++++++++ .../beast_core/memory/beast_Uncopyable.h | 5 +- .../native/beast_posix_SharedCode.h | 170 ++++++++++++ .../beast_core/native/beast_win32_Files.cpp | 155 +++++++++++ .../streams/beast_MemoryOutputStream.h | 1 - .../beast_core/streams/beast_OutputStream.h | 2 +- 11 files changed, 801 insertions(+), 3 deletions(-) create mode 100644 Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.cpp create mode 100644 Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index 8309bb27d2..6cc039c10c 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -140,6 +140,7 @@ + @@ -437,6 +438,12 @@ true true + + true + true + true + true + true true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 7b777f5085..c70a09c151 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -623,6 +623,9 @@ beast_core\containers + + beast_core\files + @@ -967,6 +970,9 @@ beast_crypto\math + + beast_core\files + diff --git a/Subtrees/beast/modules/beast_core/beast_core.cpp b/Subtrees/beast/modules/beast_core/beast_core.cpp index 82966a182e..cb3662d5d8 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.cpp +++ b/Subtrees/beast/modules/beast_core/beast_core.cpp @@ -155,6 +155,7 @@ namespace beast #include "files/beast_FileInputStream.cpp" #include "files/beast_FileOutputStream.cpp" #include "files/beast_FileSearchPath.cpp" +#include "files/beast_RandomAccessFile.cpp" #include "files/beast_TemporaryFile.cpp" #include "json/beast_JSON.cpp" diff --git a/Subtrees/beast/modules/beast_core/beast_core.h b/Subtrees/beast/modules/beast_core/beast_core.h index a0d9a3042f..8abaf273ea 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.h +++ b/Subtrees/beast/modules/beast_core/beast_core.h @@ -252,6 +252,7 @@ namespace beast #include "files/beast_FileOutputStream.h" #include "files/beast_FileSearchPath.h" #include "files/beast_MemoryMappedFile.h" +#include "files/beast_RandomAccessFile.h" #include "files/beast_TemporaryFile.h" #include "json/beast_JSON.h" #include "logging/beast_FileLogger.h" diff --git a/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.cpp b/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.cpp new file mode 100644 index 0000000000..e9588a7382 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.cpp @@ -0,0 +1,214 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +RandomAccessFile::RandomAccessFile (int bufferSizeToUse) noexcept + : fileHandle (nullptr) + , currentPosition (0) + , bufferSize (bufferSizeToUse) + , bytesInBuffer (0) + , writeBuffer (bmax (bufferSizeToUse, 16)) // enforce minimum size of 16 +{ +} + +RandomAccessFile::~RandomAccessFile () +{ + close (); +} + +Result RandomAccessFile::open (File const& path, Mode mode) +{ + close (); + + return nativeOpen (path, mode); +} + +void RandomAccessFile::close () +{ + if (isOpen ()) + { + flushBuffer (); + nativeFlush (); + nativeClose (); + } +} + +Result RandomAccessFile::setPosition (FileOffset newPosition) +{ + Result result (Result::ok ()); + + if (newPosition != currentPosition) + { + flushBuffer (); + + result = nativeSetPosition (newPosition); + } + + return result; +} + +Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount) +{ + return nativeRead (buffer, numBytes, pActualAmount); +} + +Result RandomAccessFile::write (const void* data, ByteCount numBytes, ByteCount* pActualAmount) +{ + bassert (data != nullptr && ((ssize_t) numBytes) >= 0); + + Result result (Result::ok ()); + + ByteCount amountWritten = 0; + + if (bytesInBuffer + numBytes < bufferSize) + { + memcpy (writeBuffer + bytesInBuffer, data, numBytes); + bytesInBuffer += numBytes; + currentPosition += numBytes; + } + else + { + result = flushBuffer (); + + if (result.wasOk ()) + { + if (numBytes < bufferSize) + { + bassert (bytesInBuffer == 0); + + memcpy (writeBuffer + bytesInBuffer, data, numBytes); + bytesInBuffer += numBytes; + currentPosition += numBytes; + } + else + { + ByteCount bytesWritten; + + result = nativeWrite (data, numBytes, &bytesWritten); + + if (result.wasOk ()) + currentPosition += bytesWritten; + } + } + } + + if (pActualAmount != nullptr) + *pActualAmount = amountWritten; + + return result; +} + +Result RandomAccessFile::truncate () +{ + Result result = flush (); + + if (result.wasOk ()) + result = nativeTruncate (); + + return result; +} + +Result RandomAccessFile::flush () +{ + Result result = flushBuffer (); + + if (result.wasOk ()) + result = nativeFlush (); + + return result; +} + +Result RandomAccessFile::flushBuffer () +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + if (bytesInBuffer > 0) + { + result = nativeWrite (writeBuffer, bytesInBuffer); + bytesInBuffer = 0; + } + + return result; +} + +//------------------------------------------------------------------------------ + +class RandomAccessFileTests : public UnitTest +{ +public: + RandomAccessFileTests () : UnitTest ("RandomAccessFile") + { + } + + struct Payload + { + Payload (int maxBytes) + : bufferSize (maxBytes) + , data (maxBytes) + { + } + + // Create a pseudo-random payload + void generate (int64 seedValue) noexcept + { + Random r (seedValue); + + bytes = 1 + r.nextInt (bufferSize); + + bassert (bytes >= 1 && bytes <= bufferSize); + + for (int i = 0; i < bytes; ++i) + data [i] = static_cast (r.nextInt ()); + } + + bool operator== (Payload const& other) const noexcept + { + if (bytes == other.bytes) + { + return memcmp (data.getData (), other.data.getData (), bytes) == 0; + } + else + { + return false; + } + } + + int const bufferSize; + int bytes; + HeapBlock data; + }; + + + void runTest () + { + Result result = file.open (File::createTempFile ("tests"), RandomAccessFile::readWrite); + + expect (result.wasOk (), "Should be ok"); + } + +private: + RandomAccessFile file; +}; + +static RandomAccessFileTests randomAccessFileTests; diff --git a/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h b/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h new file mode 100644 index 0000000000..b97e17dcb1 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_RANDOMACCESSFILE_H_INCLUDED +#define BEAST_RANDOMACCESSFILE_H_INCLUDED + +#include "../misc/beast_Result.h" + +/** Provides random access reading and writing to an operating system file. + + This class wraps the underlying native operating system routines for + opening and closing a file for reading and/or writing, seeking within + the file, and performing read and write operations. There are also methods + provided for obtaining an input or output stream which will work with + the file. + + Writes are batched using an internal buffer. The buffer is flushed when + it fills, the current position is manually changed, or the file + is closed. It is also possible to explicitly flush the buffer. + + @note All files are opened in binary mode. No text newline conversions + are performed. + + @see FileInputStream, FileOutputStream +*/ +class BEAST_API RandomAccessFile : Uncopyable, LeakChecked +{ +public: + /** The type of an FileOffset. + + This can be useful when writing templates. + */ + typedef int64 FileOffset; + + /** The type of a byte count. + + This can be useful when writing templates. + */ + typedef size_t ByteCount; + + /** The access mode. + + @see open + */ + enum Mode + { + readOnly, + readWrite + }; + + //============================================================================== + /** Creates an unopened file object. + + @see open, isOpen + */ + explicit RandomAccessFile (int bufferSizeToUse = 16384) noexcept; + + /** Destroy the file object. + + If the operating system file is open it will be closed. + */ + ~RandomAccessFile (); + + /** Determine if a file is open. + + @return `true` if the operating system file is open. + */ + bool isOpen () const noexcept { return fileHandle != nullptr; } + + /** Opens a file object. + + The file is opened with the specified permissions. The initial + position is set to the beginning of the file. + + @note If a file is already open, it will be closed first. + + @param path The path to the file + @param mode The access permissions + @return An indication of the success of the operation. + + @see Mode + */ + Result open (File const& path, Mode mode); + + /** Closes the file object. + + Any data that needs to be flushed will be written before the file is closed. + + @note If no file is opened, this call does nothing. + */ + void close (); + + /** Retrieve the @ref File associated with this object. + + @return The associated @ref File. + */ + File const& getFile () const noexcept { return file; } + + /** Get the current position. + + The next read or write will take place from here. + + @return The current position, as an absolute byte FileOffset from the begining. + */ + FileOffset getPosition () const noexcept { return currentPosition; } + + /** Set the current position. + + The next read or write will take place at this location. + + @param newPosition The byte FileOffset from the beginning of the file to move to. + + @return `true` if the operation was successful. + */ + Result setPosition (FileOffset newPosition); + + /** Read data at the current position. + + The caller is responsible for making sure that the memory pointed to + by `buffer` is at least as large as `bytesToRead`. + + @note The file must have been opened with read permission. + + @param buffer The memory to store the incoming data + @param numBytes The number of bytes to read. + @param pActualAmount Pointer to store the actual amount read, or `nullptr`. + + @return `true` if all the bytes were read. + */ + Result read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0); + + /** Write data at the current position. + + The current position is advanced past the data written. If data is + written past the end of the file, the file size is increased on disk. + + The caller is responsible for making sure that the memory pointed to + by `buffer` is at least as large as `bytesToWrite`. + + @note The file must have been opened with write permission. + + @param data A pointer to the data buffer to write to the file. + @param numBytes The number of bytes to write. + @param pActualAmount Pointer to store the actual amount written, or `nullptr`. + + @return `true` if all the data was written. + */ + Result write (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0); + + /** Truncate the file at the current position. + */ + Result truncate (); + + /** Flush the output buffers. + + This calls the operating system to make sure all data has been written. + */ + Result flush(); + + //============================================================================== +private: + Result flushBuffer (); + + // Some of these these methods are implemented natively on + // the corresponding platform. + // + // See beast_posix_SharedCode.h and beast_win32_Files.cpp + Result nativeOpen (File const& path, Mode mode); + void nativeClose (); + Result nativeSetPosition (FileOffset newPosition); + Result nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0); + Result nativeWrite (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0); + Result nativeTruncate (); + Result nativeFlush (); + +private: + File file; + void* fileHandle; + FileOffset currentPosition; + ByteCount const bufferSize; + ByteCount bytesInBuffer; + HeapBlock writeBuffer; +}; + +class BEAST_API RandomAccessFileInputStream : public InputStream +{ +public: + explicit RandomAccessFileInputStream (RandomAccessFile& file) : m_file (file) { } + + int64 getTotalLength() { return m_file.getFile ().getSize (); } + bool isExhausted() { return getPosition () == getTotalLength (); } + int read (void* destBuffer, int maxBytesToRead) + { + size_t actualBytes = 0; + m_file.read (destBuffer, maxBytesToRead, &actualBytes); + return actualBytes; + } + + int64 getPosition() { return m_file.getPosition (); } + bool setPosition (int64 newPosition) { return m_file.setPosition (newPosition); } + void skipNextBytes (int64 numBytesToSkip) { m_file.setPosition (getPosition () + numBytesToSkip); } + +private: + RandomAccessFile& m_file; +}; + +class BEAST_API RandomAccessFileOutputStream : public OutputStream +{ +public: + explicit RandomAccessFileOutputStream (RandomAccessFile& file) : m_file (file) { } + + void flush() { m_file.flush (); } + int64 getPosition() { return m_file.getPosition (); } + bool setPosition (int64 newPosition) { return m_file.setPosition (newPosition); } + bool write (const void* dataToWrite, size_t numberOfBytes) { return m_file.write (dataToWrite, numberOfBytes); } + +private: + RandomAccessFile& m_file; +}; + +#endif + diff --git a/Subtrees/beast/modules/beast_core/memory/beast_Uncopyable.h b/Subtrees/beast/modules/beast_core/memory/beast_Uncopyable.h index e1f1a614b1..349dde0a10 100644 --- a/Subtrees/beast/modules/beast_core/memory/beast_Uncopyable.h +++ b/Subtrees/beast/modules/beast_core/memory/beast_Uncopyable.h @@ -45,13 +45,16 @@ @code - class MyClass : Uncopyable + class MyClass : public Uncopyable { public: //... }; @endcode + + @note The derivation should be public or else child classes which + also derive from Uncopyable may not compile. */ class Uncopyable { diff --git a/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h b/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h index 936be35f40..7de9d0ebbd 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h +++ b/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h @@ -504,6 +504,176 @@ Result FileOutputStream::truncate() return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition)); } +//============================================================================== +RandomAccessFile::RandomAccessFile (int bufferSizeToUse) noexcept + : fileHandle (nullptr) + , currentPosition (0) + , writeBuffer (bufferSizeToUse) +{ +} + +RandomAccessFile::~RandomAccessFile () +{ + close (); +} + +Result RandomAccessFile::open (File const& path, Mode mode) +{ + close (); + + Result result (Result::ok ()); + + if (path.exists()) + { + int oflag; + switch (mode) + { + case readOnly: + oflag = O_RDONLY; + break; + + default: + case readWRite: + oflag = O_RDWR; + break; + }; + + const int f = ::open (path.getFullPathName().toUTF8(), oflag, 00644); + + if (f != -1) + { + currentPosition = lseek (f, 0, SEEK_SET); + + if (currentPosition >= 0) + { + file = path; + fileHandle = fdToVoidPointer (f); + } + else + { + result = getResultForErrno(); + ::close (f); + } + } + else + { + result = getResultForErrno(); + } + } + else if (mode == readWrite) + { + const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644); + + if (f != -1) + { + file = path; + fileHandle = fdToVoidPointer (f); + } + else + { + result = getResultForErrno(); + } + } + else + { + // file doesn't exist and we're opening read-only + Result::fail (String (strerror (ENOENT))); + } + + return result; +} + +void RandomAccessFile::close () +{ + if (fileHandle != nullptr) + { + file = File::nonexistent (); + ::close (getFD (fileHandle)); + fileHandle = nullptr; + } +} + +Result RandomAccessFile::setPosition (Offset newPosition) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + off_t const actual = lseek (getFD (fileHandle), newPosition, SEEK_SET); + + if (actual != newPosition) + result = getResultForErrno(); + + return result; +} + +Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount ) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + ssize_t amount = ::read (getFD (fileHandle), buffer, numBytes); + + if (amount < 0) + { + result = getResultForErrno(); + amount = 0; + } + + if (pActualAmount != nullptr) + *pActualAmount = amount; + + return (size_t) result; +} + +Result RandomAccessFile::write (void const* data, ByteCount numBytes, size_t* pActualAmount) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + ssize_t const actual = ::write (getFD (fileHandle), data, numBytes); + + if (actual == -1) + { + status = getResultForErrno(); + actual = 0; + } + + if (pActualAmount != nullptr) + *pActualAmount = actual; + + return result; +} + +Result RandomAccessFile::truncate () +{ + flush(); + + return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition)); +} + +void RandomAccessFile::flush () +{ + bassert (isOpen ()); + + if (fileHandle != nullptr) + { + if (fsync (getFD (fileHandle)) == -1) + status = getResultForErrno(); + + #if BEAST_ANDROID + // This stuff tells the OS to asynchronously update the metadata + // that the OS has cached aboud the file - this metadata is used + // when the device is acting as a USB drive, and unless it's explicitly + // refreshed, it'll get out of step with the real file. + const LocalRef t (javaString (file.getFullPathName())); + android.activity.callVoidMethod (BeastAppActivity.scanFile, t.get()); + #endif + } +} + //============================================================================== String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue) { diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp index 444bc51c3e..cb5933a69b 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp @@ -307,6 +307,161 @@ Result FileOutputStream::truncate() : WindowsFileHelpers::getResultForLastError(); } +//============================================================================== + +Result RandomAccessFile::nativeOpen (File const& path, Mode mode) +{ + bassert (! isOpen ()); + + Result result (Result::ok ()); + + DWORD dwDesiredAccess; + switch (mode) + { + case readOnly: + dwDesiredAccess = GENERIC_READ; + break; + + default: + case readWrite: + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + break; + }; + + DWORD dwCreationDisposition; + switch (mode) + { + case readOnly: + dwCreationDisposition = OPEN_EXISTING; + break; + + default: + case readWrite: + dwCreationDisposition = OPEN_ALWAYS; + break; + }; + + HANDLE h = CreateFile (path.getFullPathName().toWideCharPointer(), + dwDesiredAccess, + FILE_SHARE_READ, + 0, + dwCreationDisposition, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (h != INVALID_HANDLE_VALUE) + { + file = path; + fileHandle = h; + + result = setPosition (0); + + if (result.failed ()) + nativeClose (); + } + else + { + result = WindowsFileHelpers::getResultForLastError(); + } + + return result; +} + +void RandomAccessFile::nativeClose () +{ + bassert (isOpen ()); + + CloseHandle ((HANDLE) fileHandle); + + file = File::nonexistent (); + fileHandle = nullptr; + currentPosition = 0; +} + +Result RandomAccessFile::nativeSetPosition (FileOffset newPosition) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + LARGE_INTEGER li; + li.QuadPart = newPosition; + li.LowPart = SetFilePointer ((HANDLE) fileHandle, + (LONG) li.LowPart, + &li.HighPart, + FILE_BEGIN); + + if (li.LowPart != INVALID_SET_FILE_POINTER) + { + currentPosition = li.QuadPart; + } + else + { + result = WindowsFileHelpers::getResultForLastError(); + } + + return result; +} + +Result RandomAccessFile::nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount ) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + DWORD actualNum = 0; + + if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0)) + result = WindowsFileHelpers::getResultForLastError(); + + if (pActualAmount != nullptr) + *pActualAmount = actualNum; + + return result; +} + +Result RandomAccessFile::nativeWrite (void const* data, ByteCount numBytes, size_t* pActualAmount) +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + DWORD actualNum = 0; + + if (! WriteFile ((HANDLE) fileHandle, data, (DWORD) numBytes, &actualNum, 0)) + result = WindowsFileHelpers::getResultForLastError(); + + if (pActualAmount != nullptr) + *pActualAmount = actualNum; + + return result; +} + +Result RandomAccessFile::nativeTruncate () +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + if (! SetEndOfFile ((HANDLE) fileHandle)) + result = WindowsFileHelpers::getResultForLastError(); + + return result; +} + +Result RandomAccessFile::nativeFlush () +{ + bassert (isOpen ()); + + Result result (Result::ok ()); + + if (! FlushFileBuffers ((HANDLE) fileHandle)) + result = WindowsFileHelpers::getResultForLastError(); + + return result; +} + + //============================================================================== void MemoryMappedFile::openInternal (const File& file, AccessMode mode) { diff --git a/Subtrees/beast/modules/beast_core/streams/beast_MemoryOutputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_MemoryOutputStream.h index c93f1ba0f2..f2e8f7ad8c 100644 --- a/Subtrees/beast/modules/beast_core/streams/beast_MemoryOutputStream.h +++ b/Subtrees/beast/modules/beast_core/streams/beast_MemoryOutputStream.h @@ -38,7 +38,6 @@ class BEAST_API MemoryOutputStream : public OutputStream , LeakChecked - , Uncopyable { public: //============================================================================== diff --git a/Subtrees/beast/modules/beast_core/streams/beast_OutputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_OutputStream.h index 33b744a7d6..0528f0fcac 100644 --- a/Subtrees/beast/modules/beast_core/streams/beast_OutputStream.h +++ b/Subtrees/beast/modules/beast_core/streams/beast_OutputStream.h @@ -40,7 +40,7 @@ class File; @see InputStream, MemoryOutputStream, FileOutputStream */ -class BEAST_API OutputStream +class BEAST_API OutputStream : public Uncopyable { protected: //==============================================================================