@ -23,19 +23,6 @@ namespace ROCKSDB_NAMESPACE {
# ifndef ROCKSDB_LITE
class EncryptedSequentialFile : public SequentialFile {
private :
std : : unique_ptr < SequentialFile > file_ ;
std : : unique_ptr < BlockAccessCipherStream > stream_ ;
uint64_t offset_ ;
size_t prefixLength_ ;
public :
// Default ctor. Given underlying sequential file is supposed to be at
// offset == prefixLength.
EncryptedSequentialFile ( SequentialFile * f , BlockAccessCipherStream * s , size_t prefixLength )
: file_ ( f ) , stream_ ( s ) , offset_ ( prefixLength ) , prefixLength_ ( prefixLength ) {
}
// Read up to "n" bytes from the file. "scratch[0..n-1]" may be
// written by this routine. Sets "*result" to the data that was
@ -45,7 +32,7 @@ class EncryptedSequentialFile : public SequentialFile {
// If an error was encountered, returns a non-OK status.
//
// REQUIRES: External synchronization
Status Read ( size_t n , Slice * result , char * scratch ) override {
Status EncryptedSequentialFile : : Read ( size_t n , Slice * result , char * scratch ) {
assert ( scratch ) ;
Status status = file_ - > Read ( n , result , scratch ) ;
if ( ! status . ok ( ) ) {
@ -67,7 +54,7 @@ class EncryptedSequentialFile : public SequentialFile {
// file, and Skip will return OK.
//
// REQUIRES: External synchronization
Status Skip ( uint64_t n ) override {
Status EncryptedSequentialFile : : Skip ( uint64_t n ) {
auto status = file_ - > Skip ( n ) ;
if ( ! status . ok ( ) ) {
return status ;
@ -78,25 +65,27 @@ class EncryptedSequentialFile : public SequentialFile {
// Indicates the upper layers if the current SequentialFile implementation
// uses direct IO.
bool use_direct_io ( ) const override { return file_ - > use_direct_io ( ) ; }
bool EncryptedSequentialFile : : use_direct_io ( ) const {
return file_ - > use_direct_io ( ) ;
}
// Use the returned alignment value to allocate
// aligned buffer for Direct I/O
size_t GetRequiredBufferAlignment ( ) const override {
size_t EncryptedSequentialFile : : GetRequiredBufferAlignment ( ) const {
return file_ - > GetRequiredBufferAlignment ( ) ;
}
// Remove any kind of caching of data from the offset to offset+length
// of this file. If the length is 0, then it refers to the end of file.
// If the system is not caching the file contents, then this is a noop.
Status InvalidateCache ( size_t offset , size_t length ) override {
Status EncryptedSequentialFile : : InvalidateCache ( size_t offset , size_t length ) {
return file_ - > InvalidateCache ( offset + prefixLength_ , length ) ;
}
// Positioned Read for direct I/O
// If Direct I/O enabled, offset, n, and scratch should be properly aligned
Status PositionedRead ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) override {
Status EncryptedSequentialFile : : PositionedRead ( uint64_t offset , size_t n ,
Slice * result , char * scratch ) {
assert ( scratch ) ;
offset + = prefixLength_ ; // Skip prefix
auto status = file_ - > PositionedRead ( offset , n , result , scratch ) ;
@ -110,18 +99,6 @@ class EncryptedSequentialFile : public SequentialFile {
}
return status ;
}
} ;
// A file abstraction for randomly reading the contents of a file.
class EncryptedRandomAccessFile : public RandomAccessFile {
private :
std : : unique_ptr < RandomAccessFile > file_ ;
std : : unique_ptr < BlockAccessCipherStream > stream_ ;
size_t prefixLength_ ;
public :
EncryptedRandomAccessFile ( RandomAccessFile * f , BlockAccessCipherStream * s , size_t prefixLength )
: file_ ( f ) , stream_ ( s ) , prefixLength_ ( prefixLength ) { }
// Read up to "n" bytes from the file starting at "offset".
// "scratch[0..n-1]" may be written by this routine. Sets "*result"
@ -133,8 +110,8 @@ class EncryptedRandomAccessFile : public RandomAccessFile {
//
// Safe for concurrent use by multiple threads.
// If Direct I/O enabled, offset, n, and scratch should be aligned properly.
Status Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const override {
Status EncryptedRandomAccessFile : : Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const {
assert ( scratch ) ;
offset + = prefixLength_ ;
auto status = file_ - > Read ( offset , n , result , scratch ) ;
@ -149,7 +126,7 @@ class EncryptedRandomAccessFile : public RandomAccessFile {
}
// Readahead the file starting from offset by n bytes for caching.
Status Prefetch ( uint64_t offset , size_t n ) override {
Status EncryptedRandomAccessFile : : Prefetch ( uint64_t offset , size_t n ) {
// return Status::OK();
return file_ - > Prefetch ( offset + prefixLength_ , n ) ;
}
@ -169,45 +146,38 @@ class EncryptedRandomAccessFile : public RandomAccessFile {
// a single varint.
//
// Note: these IDs are only valid for the duration of the process.
size_t GetUniqueId ( char * id , size_t max_size ) const override {
size_t EncryptedRandomAccessFile : : GetUniqueId ( char * id , size_t max_size ) const {
return file_ - > GetUniqueId ( id , max_size ) ;
} ;
void Hint ( AccessPattern pattern ) override { file_ - > Hint ( pattern ) ; }
void EncryptedRandomAccessFile : : Hint ( AccessPattern pattern ) {
file_ - > Hint ( pattern ) ;
}
// Indicates the upper layers if the current RandomAccessFile implementation
// uses direct IO.
bool use_direct_io ( ) const override { return file_ - > use_direct_io ( ) ; }
bool EncryptedRandomAccessFile : : use_direct_io ( ) const {
return file_ - > use_direct_io ( ) ;
}
// Use the returned alignment value to allocate
// aligned buffer for Direct I/O
size_t GetRequiredBufferAlignment ( ) const override {
size_t EncryptedRandomAccessFile : : GetRequiredBufferAlignment ( ) const {
return file_ - > GetRequiredBufferAlignment ( ) ;
}
// Remove any kind of caching of data from the offset to offset+length
// of this file. If the length is 0, then it refers to the end of file.
// If the system is not caching the file contents, then this is a noop.
Status InvalidateCache ( size_t offset , size_t length ) override {
Status EncryptedRandomAccessFile : : InvalidateCache ( size_t offset ,
size_t length ) {
return file_ - > InvalidateCache ( offset + prefixLength_ , length ) ;
}
} ;
// A file abstraction for sequential writing. The implementation
// must provide buffering since callers may append small fragments
// at a time to the file.
class EncryptedWritableFile : public WritableFileWrapper {
private :
std : : unique_ptr < WritableFile > file_ ;
std : : unique_ptr < BlockAccessCipherStream > stream_ ;
size_t prefixLength_ ;
public :
// Default ctor. Prefix is assumed to be written already.
EncryptedWritableFile ( WritableFile * f , BlockAccessCipherStream * s , size_t prefixLength )
: WritableFileWrapper ( f ) , file_ ( f ) , stream_ ( s ) , prefixLength_ ( prefixLength ) { }
Status Append ( const Slice & data ) override {
Status EncryptedWritableFile : : Append ( const Slice & data ) {
AlignedBuffer buf ;
Status status ;
Slice dataToAppend ( data ) ;
@ -236,7 +206,8 @@ class EncryptedWritableFile : public WritableFileWrapper {
return status ;
}
Status PositionedAppend ( const Slice & data , uint64_t offset ) override {
Status EncryptedWritableFile : : PositionedAppend ( const Slice & data ,
uint64_t offset ) {
AlignedBuffer buf ;
Status status ;
Slice dataToAppend ( data ) ;
@ -265,18 +236,20 @@ class EncryptedWritableFile : public WritableFileWrapper {
// Indicates the upper layers if the current WritableFile implementation
// uses direct IO.
bool use_direct_io ( ) const override { return file_ - > use_direct_io ( ) ; }
bool EncryptedWritableFile : : use_direct_io ( ) const {
return file_ - > use_direct_io ( ) ;
}
// Use the returned alignment value to allocate
// aligned buffer for Direct I/O
size_t GetRequiredBufferAlignment ( ) const override {
size_t EncryptedWritableFile : : GetRequiredBufferAlignment ( ) const {
return file_ - > GetRequiredBufferAlignment ( ) ;
}
/*
* Get the size of valid data in the file .
*/
uint64_t GetFileSize ( ) override {
uint64_t EncryptedWritableFile : : GetFileSize ( ) {
return file_ - > GetFileSize ( ) - prefixLength_ ;
}
@ -284,7 +257,7 @@ class EncryptedWritableFile : public WritableFileWrapper {
// before closing. It is not always possible to keep track of the file
// size due to whole pages writes. The behavior is undefined if called
// with other writes to follow.
Status Truncate ( uint64_t size ) override {
Status EncryptedWritableFile : : Truncate ( uint64_t size ) {
return file_ - > Truncate ( size + prefixLength_ ) ;
}
@ -292,7 +265,7 @@ class EncryptedWritableFile : public WritableFileWrapper {
// of this file. If the length is 0, then it refers to the end of file.
// If the system is not caching the file contents, then this is a noop.
// This call has no effect on dirty pages in the cache.
Status InvalidateCache ( size_t offset , size_t length ) override {
Status EncryptedWritableFile : : InvalidateCache ( size_t offset , size_t length ) {
return file_ - > InvalidateCache ( offset + prefixLength_ , length ) ;
}
@ -302,7 +275,7 @@ class EncryptedWritableFile : public WritableFileWrapper {
// This asks the OS to initiate flushing the cached data to disk,
// without waiting for completion.
// Default implementation does nothing.
Status RangeSync ( uint64_t offset , uint64_t nbytes ) override {
Status EncryptedWritableFile : : RangeSync ( uint64_t offset , uint64_t nbytes ) {
return file_ - > RangeSync ( offset + prefixLength_ , nbytes ) ;
}
@ -311,40 +284,32 @@ class EncryptedWritableFile : public WritableFileWrapper {
// of space on devices where it can result in less file
// fragmentation and/or less waste from over-zealous filesystem
// pre-allocation.
void PrepareWrite ( size_t offset , size_t len ) override {
void EncryptedWritableFile : : PrepareWrite ( size_t offset , size_t len ) {
file_ - > PrepareWrite ( offset + prefixLength_ , len ) ;
}
// Pre-allocates space for a file.
Status Allocate ( uint64_t offset , uint64_t len ) override {
Status EncryptedWritableFile : : Allocate ( uint64_t offset , uint64_t len ) {
return file_ - > Allocate ( offset + prefixLength_ , len ) ;
}
} ;
// A file abstraction for random reading and writing.
class EncryptedRandomRWFile : public RandomRWFile {
private :
std : : unique_ptr < RandomRWFile > file_ ;
std : : unique_ptr < BlockAccessCipherStream > stream_ ;
size_t prefixLength_ ;
public :
EncryptedRandomRWFile ( RandomRWFile * f , BlockAccessCipherStream * s , size_t prefixLength )
: file_ ( f ) , stream_ ( s ) , prefixLength_ ( prefixLength ) { }
// Indicates if the class makes use of direct I/O
// If false you must pass aligned buffer to Write()
bool use_direct_io ( ) const override { return file_ - > use_direct_io ( ) ; }
bool EncryptedRandomRWFile : : use_direct_io ( ) const {
return file_ - > use_direct_io ( ) ;
}
// Use the returned alignment value to allocate
// aligned buffer for Direct I/O
size_t GetRequiredBufferAlignment ( ) const override {
size_t EncryptedRandomRWFile : : GetRequiredBufferAlignment ( ) const {
return file_ - > GetRequiredBufferAlignment ( ) ;
}
// Write bytes in `data` at offset `offset`, Returns Status::OK() on success.
// Pass aligned buffer when use_direct_io() returns true.
Status Write ( uint64_t offset , const Slice & data ) override {
Status EncryptedRandomRWFile : : Write ( uint64_t offset , const Slice & data ) {
AlignedBuffer buf ;
Status status ;
Slice dataToWrite ( data ) ;
@ -371,8 +336,8 @@ class EncryptedRandomRWFile : public RandomRWFile {
// Read up to `n` bytes starting from offset `offset` and store them in
// result, provided `scratch` size should be at least `n`.
// Returns Status::OK() on success.
Status Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const override {
Status EncryptedRandomRWFile : : Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const {
assert ( scratch ) ;
offset + = prefixLength_ ;
auto status = file_ - > Read ( offset , n , result , scratch ) ;
@ -386,16 +351,16 @@ class EncryptedRandomRWFile : public RandomRWFile {
return status ;
}
Status Flush ( ) override { return file_ - > Flush ( ) ; }
Status EncryptedRandomRWFile : : Flush ( ) { return file_ - > Flush ( ) ; }
Status Sync ( ) override { return file_ - > Sync ( ) ; }
Status EncryptedRandomRWFile : : Sync ( ) { return file_ - > Sync ( ) ; }
Status Fsync ( ) override { return file_ - > Fsync ( ) ; }
Status EncryptedRandomRWFile : : Fsync ( ) { return file_ - > Fsync ( ) ; }
Status Close ( ) override { return file_ - > Close ( ) ; }
} ;
Status EncryptedRandomRWFile : : Close ( ) { return file_ - > Close ( ) ; }
// EncryptedEnv implements an Env wrapper that adds encryption to files stored on disk.
// EncryptedEnv implements an Env wrapper that adds encryption to files stored
// on disk.
class EncryptedEnv : public EnvWrapper {
public :
EncryptedEnv ( Env * base_env , EncryptionProvider * provider )
@ -404,7 +369,7 @@ class EncryptedEnv : public EnvWrapper {
}
// NewSequentialFile opens a file for sequential reading.
Status NewSequentialFile ( const std : : string & fname ,
virtual Status NewSequentialFile ( const std : : string & fname ,
std : : unique_ptr < SequentialFile > * result ,
const EnvOptions & options ) override {
result - > reset ( ) ;
@ -425,7 +390,8 @@ class EncryptedEnv : public EnvWrapper {
// Read prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
status = underlying - > Read ( prefixLength , & prefixSlice , prefixBuf . BufferStart ( ) ) ;
status =
underlying - > Read ( prefixLength , & prefixSlice , prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
@ -433,16 +399,18 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < SequentialFile > ( new EncryptedSequentialFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < SequentialFile > ( new EncryptedSequentialFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
// NewRandomAccessFile opens a file for random read access.
Status NewRandomAccessFile ( const std : : string & fname ,
virtual Status NewRandomAccessFile ( const std : : string & fname ,
std : : unique_ptr < RandomAccessFile > * result ,
const EnvOptions & options ) override {
result - > reset ( ) ;
@ -463,7 +431,8 @@ class EncryptedEnv : public EnvWrapper {
// Read prefix
prefixBuf . Alignment ( underlying - > GetRequiredBufferAlignment ( ) ) ;
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
status = underlying - > Read ( 0 , prefixLength , & prefixSlice , prefixBuf . BufferStart ( ) ) ;
status = underlying - > Read ( 0 , prefixLength , & prefixSlice ,
prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
@ -471,16 +440,18 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < RandomAccessFile > ( new EncryptedRandomAccessFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < RandomAccessFile > ( new EncryptedRandomAccessFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
// NewWritableFile opens a file for sequential writing.
Status NewWritableFile ( const std : : string & fname ,
virtual Status NewWritableFile ( const std : : string & fname ,
std : : unique_ptr < WritableFile > * result ,
const EnvOptions & options ) override {
result - > reset ( ) ;
@ -512,11 +483,13 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
@ -527,7 +500,7 @@ class EncryptedEnv : public EnvWrapper {
// returns non-OK.
//
// The returned file will only be accessed by one thread at a time.
Status ReopenWritableFile ( const std : : string & fname ,
virtual Status ReopenWritableFile ( const std : : string & fname ,
std : : unique_ptr < WritableFile > * result ,
const EnvOptions & options ) override {
result - > reset ( ) ;
@ -559,16 +532,18 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
// Reuse an existing file by renaming it and opening it as writable.
Status ReuseWritableFile ( const std : : string & fname ,
virtual Status ReuseWritableFile ( const std : : string & fname ,
const std : : string & old_fname ,
std : : unique_ptr < WritableFile > * result ,
const EnvOptions & options ) override {
@ -578,7 +553,8 @@ class EncryptedEnv : public EnvWrapper {
}
// Open file using underlying Env implementation
std : : unique_ptr < WritableFile > underlying ;
Status status = EnvWrapper : : ReuseWritableFile ( fname , old_fname , & underlying , options ) ;
Status status =
EnvWrapper : : ReuseWritableFile ( fname , old_fname , & underlying , options ) ;
if ( ! status . ok ( ) ) {
return status ;
}
@ -601,11 +577,13 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < WritableFile > ( new EncryptedWritableFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
@ -614,7 +592,7 @@ class EncryptedEnv : public EnvWrapper {
// *result and returns OK. On failure returns non-OK.
//
// The returned file will only be accessed by one thread at a time.
Status NewRandomRWFile ( const std : : string & fname ,
virtual Status NewRandomRWFile ( const std : : string & fname ,
std : : unique_ptr < RandomRWFile > * result ,
const EnvOptions & options ) override {
result - > reset ( ) ;
@ -639,14 +617,16 @@ class EncryptedEnv : public EnvWrapper {
prefixBuf . AllocateNewBuffer ( prefixLength ) ;
if ( ! isNewFile ) {
// File already exists, read prefix
status = underlying - > Read ( 0 , prefixLength , & prefixSlice , prefixBuf . BufferStart ( ) ) ;
status = underlying - > Read ( 0 , prefixLength , & prefixSlice ,
prefixBuf . BufferStart ( ) ) ;
if ( ! status . ok ( ) ) {
return status ;
}
prefixBuf . Size ( prefixLength ) ;
} else {
// File is new, initialize & write prefix
provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) , prefixLength ) ;
provider_ - > CreateNewPrefix ( fname , prefixBuf . BufferStart ( ) ,
prefixLength ) ;
prefixBuf . Size ( prefixLength ) ;
prefixSlice = Slice ( prefixBuf . BufferStart ( ) , prefixBuf . CurrentSize ( ) ) ;
// Write prefix
@ -658,25 +638,31 @@ class EncryptedEnv : public EnvWrapper {
}
// Create cipher stream
std : : unique_ptr < BlockAccessCipherStream > stream ;
status = provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
status =
provider_ - > CreateCipherStream ( fname , options , prefixSlice , & stream ) ;
if ( ! status . ok ( ) ) {
return status ;
}
( * result ) = std : : unique_ptr < RandomRWFile > ( new EncryptedRandomRWFile ( underlying . release ( ) , stream . release ( ) , prefixLength ) ) ;
( * result ) = std : : unique_ptr < RandomRWFile > ( new EncryptedRandomRWFile (
std : : move ( underlying ) , std : : move ( stream ) , prefixLength ) ) ;
return Status : : OK ( ) ;
}
// Store in *result the attributes of the children of the specified directory.
// In case the implementation lists the directory prior to iterating the files
// and files are concurrently deleted, the deleted files will be omitted from
// Store in *result the attributes of the children of the specified
// directory.
// In case the implementation lists the directory prior to iterating the
// files
// and files are concurrently deleted, the deleted files will be omitted
// from
// result.
// The name attributes are relative to "dir".
// Original contents of *results are dropped.
// Returns OK if "dir" exists and "*result" contains its children.
// NotFound if "dir" does not exist, the calling process does not have
// NotFound if "dir" does not exist, the calling process does not
// have
// permission to access "dir", or if "dir" is invalid.
// IOError if an IO Error was encountered
Status GetChildrenFileAttributes (
virtual Status GetChildrenFileAttributes (
const std : : string & dir , std : : vector < FileAttributes > * result ) override {
auto status = EnvWrapper : : GetChildrenFileAttributes ( dir , result ) ;
if ( ! status . ok ( ) ) {
@ -684,14 +670,19 @@ class EncryptedEnv : public EnvWrapper {
}
size_t prefixLength = provider_ - > GetPrefixLength ( ) ;
for ( auto it = std : : begin ( * result ) ; it ! = std : : end ( * result ) ; + + it ) {
assert ( it - > size_bytes > = prefixLength ) ;
// assert(it->size_bytes >= prefixLength);
// breaks env_basic_test when called on directory containing
// directories
// which makes subtraction of prefixLength worrisome since
// FileAttributes does not identify directories
it - > size_bytes - = prefixLength ;
}
return Status : : OK ( ) ;
}
// Store the size of fname in *file_size.
Status GetFileSize ( const std : : string & fname , uint64_t * file_size ) override {
virtual Status GetFileSize ( const std : : string & fname ,
uint64_t * file_size ) override {
auto status = EnvWrapper : : GetFileSize ( fname , file_size ) ;
if ( ! status . ok ( ) ) {
return status ;