mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Add RandomAccessFile
This commit is contained in:
@@ -140,6 +140,7 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_RandomAccessFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h" />
|
||||
@@ -437,6 +438,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_RandomAccessFile.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -623,6 +623,9 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SharedObjectArray.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\files\beast_RandomAccessFile.h">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||
@@ -967,6 +970,9 @@
|
||||
<ClCompile Include="..\..\modules\beast_crypto\math\beast_UnsignedInteger.cpp">
|
||||
<Filter>beast_crypto\math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\files\beast_RandomAccessFile.cpp">
|
||||
<Filter>beast_core\files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\..\TODO.txt" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <unsigned char> (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 <char> data;
|
||||
};
|
||||
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
Result result = file.open (File::createTempFile ("tests"), RandomAccessFile::readWrite);
|
||||
|
||||
expect (result.wasOk (), "Should be ok");
|
||||
}
|
||||
|
||||
private:
|
||||
RandomAccessFile file;
|
||||
};
|
||||
|
||||
static RandomAccessFileTests randomAccessFileTests;
|
||||
242
Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h
Normal file
242
Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h
Normal file
@@ -0,0 +1,242 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <RandomAccessFile>
|
||||
{
|
||||
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 <char> 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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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<jstring> t (javaString (file.getFullPathName()));
|
||||
android.activity.callVoidMethod (BeastAppActivity.scanFile, t.get());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
class BEAST_API MemoryOutputStream
|
||||
: public OutputStream
|
||||
, LeakChecked <MemoryOutputStream>
|
||||
, Uncopyable
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
||||
@@ -40,7 +40,7 @@ class File;
|
||||
|
||||
@see InputStream, MemoryOutputStream, FileOutputStream
|
||||
*/
|
||||
class BEAST_API OutputStream
|
||||
class BEAST_API OutputStream : public Uncopyable
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
|
||||
Reference in New Issue
Block a user