lbrycrd/util/env_win.cc

1032 lines
25 KiB
C++
Raw Normal View History

// This file contains source that originates from:
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc
// Those files dont' have any explict license headers but the
// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License'
// as the license.
#if defined(LEVELDB_PLATFORM_WINDOWS)
#include <map>
#include "leveldb/env.h"
#include "port/port.h"
#include "leveldb/slice.h"
#include "util/logging.h"
#include <shlwapi.h>
#include <process.h>
#include <cstring>
#include <stdio.h>
#include <errno.h>
#include <io.h>
#include <algorithm>
#ifdef max
#undef max
#endif
#ifndef va_copy
#define va_copy(d,s) ((d) = (s))
#endif
#if defined DeleteFile
#undef DeleteFile
#endif
//Declarations
namespace leveldb
{
namespace Win32
{
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
std::string GetCurrentDir();
std::wstring GetCurrentDirW();
static const std::string CurrentDir = GetCurrentDir();
static const std::wstring CurrentDirW = GetCurrentDirW();
std::string& ModifyPath(std::string& path);
std::wstring& ModifyPath(std::wstring& path);
std::string GetLastErrSz();
std::wstring GetLastErrSzW();
size_t GetPageSize();
typedef void (*ScheduleProc)(void*) ;
struct WorkItemWrapper
{
WorkItemWrapper(ScheduleProc proc_,void* content_);
ScheduleProc proc;
void* pContent;
};
DWORD WINAPI WorkItemWrapperProc(LPVOID pContent);
class Win32SequentialFile : public SequentialFile
{
public:
friend class Win32Env;
virtual ~Win32SequentialFile();
virtual Status Read(size_t n, Slice* result, char* scratch);
virtual Status Skip(uint64_t n);
BOOL isEnable();
private:
BOOL _Init();
void _CleanUp();
Win32SequentialFile(const std::string& fname);
std::string _filename;
::HANDLE _hFile;
DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile);
};
class Win32RandomAccessFile : public RandomAccessFile
{
public:
friend class Win32Env;
virtual ~Win32RandomAccessFile();
virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const;
BOOL isEnable();
private:
BOOL _Init(LPCWSTR path);
void _CleanUp();
Win32RandomAccessFile(const std::string& fname);
HANDLE _hFile;
const std::string _filename;
DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile);
};
class Win32MapFile : public WritableFile
{
public:
Win32MapFile(const std::string& fname);
~Win32MapFile();
virtual Status Append(const Slice& data);
virtual Status Close();
virtual Status Flush();
virtual Status Sync();
BOOL isEnable();
private:
std::string _filename;
HANDLE _hFile;
size_t _page_size;
size_t _map_size; // How much extra memory to map at a time
char* _base; // The mapped region
HANDLE _base_handle;
char* _limit; // Limit of the mapped region
char* _dst; // Where to write next (in range [base_,limit_])
char* _last_sync; // Where have we synced up to
uint64_t _file_offset; // Offset of base_ in file
//LARGE_INTEGER file_offset_;
// Have we done an munmap of unsynced data?
bool _pending_sync;
// Roundup x to a multiple of y
static size_t _Roundup(size_t x, size_t y);
size_t _TruncateToPageBoundary(size_t s);
bool _UnmapCurrentRegion();
bool _MapNewRegion();
DISALLOW_COPY_AND_ASSIGN(Win32MapFile);
BOOL _Init(LPCWSTR Path);
};
class Win32FileLock : public FileLock
{
public:
friend class Win32Env;
virtual ~Win32FileLock();
BOOL isEnable();
private:
BOOL _Init(LPCWSTR path);
void _CleanUp();
Win32FileLock(const std::string& fname);
HANDLE _hFile;
std::string _filename;
DISALLOW_COPY_AND_ASSIGN(Win32FileLock);
};
class Win32Logger : public Logger
{
public:
friend class Win32Env;
virtual ~Win32Logger();
virtual void Logv(const char* format, va_list ap);
private:
explicit Win32Logger(WritableFile* pFile);
WritableFile* _pFileProxy;
DISALLOW_COPY_AND_ASSIGN(Win32Logger);
};
class Win32Env : public Env
{
public:
Win32Env();
virtual ~Win32Env();
virtual Status NewSequentialFile(const std::string& fname,
SequentialFile** result);
virtual Status NewRandomAccessFile(const std::string& fname,
RandomAccessFile** result);
virtual Status NewWritableFile(const std::string& fname,
WritableFile** result);
virtual bool FileExists(const std::string& fname);
virtual Status GetChildren(const std::string& dir,
std::vector<std::string>* result);
virtual Status DeleteFile(const std::string& fname);
virtual Status CreateDir(const std::string& dirname);
virtual Status DeleteDir(const std::string& dirname);
virtual Status GetFileSize(const std::string& fname, uint64_t* file_size);
virtual Status RenameFile(const std::string& src,
const std::string& target);
virtual Status LockFile(const std::string& fname, FileLock** lock);
virtual Status UnlockFile(FileLock* lock);
virtual void Schedule(
void (*function)(void* arg),
void* arg);
virtual void StartThread(void (*function)(void* arg), void* arg);
virtual Status GetTestDirectory(std::string* path);
//virtual void Logv(WritableFile* log, const char* format, va_list ap);
virtual Status NewLogger(const std::string& fname, Logger** result);
virtual uint64_t NowMicros();
virtual void SleepForMicroseconds(int micros);
};
void ToWidePath(const std::string& value, std::wstring& target) {
wchar_t buffer[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH);
target = buffer;
}
void ToNarrowPath(const std::wstring& value, std::string& target) {
char buffer[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
target = buffer;
}
std::string GetCurrentDir()
{
CHAR path[MAX_PATH];
::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH);
*strrchr(path,'\\') = 0;
return std::string(path);
}
std::wstring GetCurrentDirW()
{
WCHAR path[MAX_PATH];
::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH);
*wcsrchr(path,L'\\') = 0;
return std::wstring(path);
}
std::string& ModifyPath(std::string& path)
{
if(path[0] == '/' || path[0] == '\\'){
path = CurrentDir + path;
}
std::replace(path.begin(),path.end(),'/','\\');
return path;
}
std::wstring& ModifyPath(std::wstring& path)
{
if(path[0] == L'/' || path[0] == L'\\'){
path = CurrentDirW + path;
}
std::replace(path.begin(),path.end(),L'/',L'\\');
return path;
}
std::string GetLastErrSz()
{
LPWSTR lpMsgBuf;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPWSTR) &lpMsgBuf,
0,
NULL
);
std::string Err;
ToNarrowPath(lpMsgBuf, Err);
LocalFree( lpMsgBuf );
return Err;
}
std::wstring GetLastErrSzW()
{
LPVOID lpMsgBuf;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPWSTR) &lpMsgBuf,
0,
NULL
);
std::wstring Err = (LPCWSTR)lpMsgBuf;
LocalFree(lpMsgBuf);
return Err;
}
WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) :
proc(proc_),pContent(content_)
{
}
DWORD WINAPI WorkItemWrapperProc(LPVOID pContent)
{
WorkItemWrapper* item = static_cast<WorkItemWrapper*>(pContent);
ScheduleProc TempProc = item->proc;
void* arg = item->pContent;
delete item;
TempProc(arg);
return 0;
}
size_t GetPageSize()
{
SYSTEM_INFO si;
GetSystemInfo(&si);
return std::max(si.dwPageSize,si.dwAllocationGranularity);
}
const size_t g_PageSize = GetPageSize();
Win32SequentialFile::Win32SequentialFile( const std::string& fname ) :
_filename(fname),_hFile(NULL)
{
_Init();
}
Win32SequentialFile::~Win32SequentialFile()
{
_CleanUp();
}
Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch )
{
Status sRet;
DWORD hasRead = 0;
if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){
*result = Slice(scratch,hasRead);
} else {
sRet = Status::IOError(_filename, Win32::GetLastErrSz() );
}
return sRet;
}
Status Win32SequentialFile::Skip( uint64_t n )
{
Status sRet;
LARGE_INTEGER Move,NowPointer;
Move.QuadPart = n;
if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){
sRet = Status::IOError(_filename,Win32::GetLastErrSz());
}
return sRet;
}
BOOL Win32SequentialFile::isEnable()
{
return _hFile ? TRUE : FALSE;
}
BOOL Win32SequentialFile::_Init()
{
std::wstring path;
ToWidePath(_filename, path);
_hFile = CreateFileW(path.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
return _hFile ? TRUE : FALSE;
}
void Win32SequentialFile::_CleanUp()
{
if(_hFile){
CloseHandle(_hFile);
_hFile = NULL;
}
}
Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) :
_filename(fname),_hFile(NULL)
{
std::wstring path;
ToWidePath(fname, path);
_Init( path.c_str() );
}
Win32RandomAccessFile::~Win32RandomAccessFile()
{
_CleanUp();
}
Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const
{
Status sRet;
OVERLAPPED ol = {0};
ZeroMemory(&ol,sizeof(ol));
ol.Offset = (DWORD)offset;
ol.OffsetHigh = (DWORD)(offset >> 32);
DWORD hasRead = 0;
if(!ReadFile(_hFile,scratch,n,&hasRead,&ol))
sRet = Status::IOError(_filename,Win32::GetLastErrSz());
else
*result = Slice(scratch,hasRead);
return sRet;
}
BOOL Win32RandomAccessFile::_Init( LPCWSTR path )
{
BOOL bRet = FALSE;
if(!_hFile)
_hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL);
if(!_hFile || _hFile == INVALID_HANDLE_VALUE )
_hFile = NULL;
else
bRet = TRUE;
return bRet;
}
BOOL Win32RandomAccessFile::isEnable()
{
return _hFile ? TRUE : FALSE;
}
void Win32RandomAccessFile::_CleanUp()
{
if(_hFile){
::CloseHandle(_hFile);
_hFile = NULL;
}
}
size_t Win32MapFile::_Roundup( size_t x, size_t y )
{
return ((x + y - 1) / y) * y;
}
size_t Win32MapFile::_TruncateToPageBoundary( size_t s )
{
s -= (s & (_page_size - 1));
assert((s % _page_size) == 0);
return s;
}
bool Win32MapFile::_UnmapCurrentRegion()
{
bool result = true;
if (_base != NULL) {
if (_last_sync < _limit) {
// Defer syncing this data until next Sync() call, if any
_pending_sync = true;
}
if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle))
result = false;
_file_offset += _limit - _base;
_base = NULL;
_base_handle = NULL;
_limit = NULL;
_last_sync = NULL;
_dst = NULL;
// Increase the amount we map the next time, but capped at 1MB
if (_map_size < (1<<20)) {
_map_size *= 2;
}
}
return result;
}
bool Win32MapFile::_MapNewRegion()
{
assert(_base == NULL);
//LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32);
//LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF);
DWORD off_hi = (DWORD)(_file_offset >> 32);
DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF);
LARGE_INTEGER newSize;
newSize.QuadPart = _file_offset + _map_size;
SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN);
SetEndOfFile(_hFile);
_base_handle = CreateFileMappingA(
_hFile,
NULL,
PAGE_READWRITE,
0,
0,
0);
if (_base_handle != NULL) {
_base = (char*) MapViewOfFile(_base_handle,
FILE_MAP_ALL_ACCESS,
off_hi,
off_lo,
_map_size);
if (_base != NULL) {
_limit = _base + _map_size;
_dst = _base;
_last_sync = _base;
return true;
}
}
return false;
}
Win32MapFile::Win32MapFile( const std::string& fname) :
_filename(fname),
_hFile(NULL),
_page_size(Win32::g_PageSize),
_map_size(_Roundup(65536, Win32::g_PageSize)),
_base(NULL),
_base_handle(NULL),
_limit(NULL),
_dst(NULL),
_last_sync(NULL),
_file_offset(0),
_pending_sync(false)
{
std::wstring path;
ToWidePath(fname, path);
_Init(path.c_str());
assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0);
}
Status Win32MapFile::Append( const Slice& data )
{
const char* src = data.data();
size_t left = data.size();
Status s;
while (left > 0) {
assert(_base <= _dst);
assert(_dst <= _limit);
size_t avail = _limit - _dst;
if (avail == 0) {
if (!_UnmapCurrentRegion() ||
!_MapNewRegion()) {
return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz());
}
}
size_t n = (left <= avail) ? left : avail;
memcpy(_dst, src, n);
_dst += n;
src += n;
left -= n;
}
return s;
}
Status Win32MapFile::Close()
{
Status s;
size_t unused = _limit - _dst;
if (!_UnmapCurrentRegion()) {
s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz());
} else if (unused > 0) {
// Trim the extra space at the end of the file
LARGE_INTEGER newSize;
newSize.QuadPart = _file_offset - unused;
if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) {
s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz());
} else
SetEndOfFile(_hFile);
}
if (!CloseHandle(_hFile)) {
if (s.ok()) {
s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz());
}
}
_hFile = INVALID_HANDLE_VALUE;
_base = NULL;
_base_handle = NULL;
_limit = NULL;
return s;
}
Status Win32MapFile::Sync()
{
Status s;
if (_pending_sync) {
// Some unmapped data was not synced
_pending_sync = false;
if (!FlushFileBuffers(_hFile)) {
s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz());
}
}
if (_dst > _last_sync) {
// Find the beginnings of the pages that contain the first and last
// bytes to be synced.
size_t p1 = _TruncateToPageBoundary(_last_sync - _base);
size_t p2 = _TruncateToPageBoundary(_dst - _base - 1);
_last_sync = _dst;
if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) {
s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz());
}
}
return s;
}
Status Win32MapFile::Flush()
{
return Status::OK();
}
Win32MapFile::~Win32MapFile()
{
if (_hFile != INVALID_HANDLE_VALUE) {
Win32MapFile::Close();
}
}
BOOL Win32MapFile::_Init( LPCWSTR Path )
{
DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS;
_hFile = CreateFileW(Path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
NULL,
Flag,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(!_hFile || _hFile == INVALID_HANDLE_VALUE)
return FALSE;
else
return TRUE;
}
BOOL Win32MapFile::isEnable()
{
return _hFile ? TRUE : FALSE;
}
Win32FileLock::Win32FileLock( const std::string& fname ) :
_hFile(NULL),_filename(fname)
{
std::wstring path;
ToWidePath(fname, path);
_Init(path.c_str());
}
Win32FileLock::~Win32FileLock()
{
_CleanUp();
}
BOOL Win32FileLock::_Init( LPCWSTR path )
{
BOOL bRet = FALSE;
if(!_hFile)
_hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){
_hFile = NULL;
}
else
bRet = TRUE;
return bRet;
}
void Win32FileLock::_CleanUp()
{
::CloseHandle(_hFile);
_hFile = NULL;
}
BOOL Win32FileLock::isEnable()
{
return _hFile ? TRUE : FALSE;
}
Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile)
{
assert(_pFileProxy);
}
Win32Logger::~Win32Logger()
{
if(_pFileProxy)
delete _pFileProxy;
}
void Win32Logger::Logv( const char* format, va_list ap )
{
uint64_t thread_id = ::GetCurrentThreadId();
// We try twice: the first time with a fixed-size stack allocated buffer,
// and the second time with a much larger dynamically allocated buffer.
char buffer[500];
for (int iter = 0; iter < 2; iter++) {
char* base;
int bufsize;
if (iter == 0) {
bufsize = sizeof(buffer);
base = buffer;
} else {
bufsize = 30000;
base = new char[bufsize];
}
char* p = base;
char* limit = base + bufsize;
SYSTEMTIME st;
GetLocalTime(&st);
p += snprintf(p, limit - p,
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
int(st.wYear),
int(st.wMonth),
int(st.wDay),
int(st.wHour),
int(st.wMinute),
int(st.wMinute),
int(st.wMilliseconds),
static_cast<long long unsigned int>(thread_id));
// Print the message
if (p < limit) {
va_list backup_ap;
va_copy(backup_ap, ap);
p += vsnprintf(p, limit - p, format, backup_ap);
va_end(backup_ap);
}
// Truncate to available space if necessary
if (p >= limit) {
if (iter == 0) {
continue; // Try again with larger buffer
} else {
p = limit - 1;
}
}
// Add newline if necessary
if (p == base || p[-1] != '\n') {
*p++ = '\n';
}
assert(p <= limit);
DWORD hasWritten = 0;
if(_pFileProxy){
_pFileProxy->Append(Slice(base, p - base));
_pFileProxy->Flush();
}
if (base != buffer) {
delete[] base;
}
break;
}
}
bool Win32Env::FileExists(const std::string& fname)
{
std::string path = fname;
std::wstring wpath;
ToWidePath(ModifyPath(path), wpath);
return ::PathFileExistsW(wpath.c_str()) ? true : false;
}
Status Win32Env::GetChildren(const std::string& dir, std::vector<std::string>* result)
{
Status sRet;
::WIN32_FIND_DATAW wfd;
std::string path = dir;
ModifyPath(path);
path += "\\*.*";
std::wstring wpath;
ToWidePath(path, wpath);
::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd);
if(hFind && hFind != INVALID_HANDLE_VALUE){
BOOL hasNext = TRUE;
std::string child;
while(hasNext){
ToNarrowPath(wfd.cFileName, child);
if(child != ".." && child != ".") {
result->push_back(child);
}
hasNext = ::FindNextFileW(hFind,&wfd);
}
::FindClose(hFind);
}
else
sRet = Status::IOError(dir,"Could not get children.");
return sRet;
}
void Win32Env::SleepForMicroseconds( int micros )
{
::Sleep((micros + 999) /1000);
}
Status Win32Env::DeleteFile( const std::string& fname )
{
Status sRet;
std::string path = fname;
std::wstring wpath;
ToWidePath(ModifyPath(path), wpath);
if(!::DeleteFileW(wpath.c_str())) {
sRet = Status::IOError(path, "Could not delete file.");
}
return sRet;
}
Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size )
{
Status sRet;
std::string path = fname;
std::wstring wpath;
ToWidePath(ModifyPath(path), wpath);
HANDLE file = ::CreateFileW(wpath.c_str(),
GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
LARGE_INTEGER li;
if(::GetFileSizeEx(file,&li)){
*file_size = (uint64_t)li.QuadPart;
}else
sRet = Status::IOError(path,"Could not get the file size.");
CloseHandle(file);
return sRet;
}
Status Win32Env::RenameFile( const std::string& src, const std::string& target )
{
Status sRet;
std::string src_path = src;
std::wstring wsrc_path;
ToWidePath(ModifyPath(src_path), wsrc_path);
std::string target_path = target;
std::wstring wtarget_path;
ToWidePath(ModifyPath(target_path), wtarget_path);
if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){
DWORD err = GetLastError();
if(err == 0x000000b7){
if(!::DeleteFileW(wtarget_path.c_str() ) )
sRet = Status::IOError(src, "Could not rename file.");
else if(!::MoveFileW(wsrc_path.c_str(),
wtarget_path.c_str() ) )
sRet = Status::IOError(src, "Could not rename file.");
}
}
return sRet;
}
Status Win32Env::LockFile( const std::string& fname, FileLock** lock )
{
Status sRet;
std::string path = fname;
ModifyPath(path);
Win32FileLock* _lock = new Win32FileLock(path);
if(!_lock->isEnable()){
delete _lock;
*lock = NULL;
sRet = Status::IOError(path, "Could not lock file.");
}
else
*lock = _lock;
return sRet;
}
Status Win32Env::UnlockFile( FileLock* lock )
{
Status sRet;
delete lock;
return sRet;
}
void Win32Env::Schedule( void (*function)(void* arg), void* arg )
{
QueueUserWorkItem(Win32::WorkItemWrapperProc,
new Win32::WorkItemWrapper(function,arg),
WT_EXECUTEDEFAULT);
}
void Win32Env::StartThread( void (*function)(void* arg), void* arg )
{
::_beginthread(function,0,arg);
}
Status Win32Env::GetTestDirectory( std::string* path )
{
Status sRet;
WCHAR TempPath[MAX_PATH];
::GetTempPathW(MAX_PATH,TempPath);
ToNarrowPath(TempPath, *path);
path->append("leveldb\\test\\");
ModifyPath(*path);
return sRet;
}
uint64_t Win32Env::NowMicros()
{
#ifndef USE_VISTA_API
#define GetTickCount64 GetTickCount
#endif
return (uint64_t)(GetTickCount64()*1000);
}
static Status CreateDirInner( const std::string& dirname )
{
Status sRet;
DWORD attr = ::GetFileAttributes(dirname.c_str());
if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist:
std::size_t slash = dirname.find_last_of("\\");
if (slash != std::string::npos){
sRet = CreateDirInner(dirname.substr(0, slash));
if (!sRet.ok()) return sRet;
}
BOOL result = ::CreateDirectory(dirname.c_str(), NULL);
if (result == FALSE) {
sRet = Status::IOError(dirname, "Could not create directory.");
return sRet;
}
}
return sRet;
}
Status Win32Env::CreateDir( const std::string& dirname )
{
std::string path = dirname;
if(path[path.length() - 1] != '\\'){
path += '\\';
}
ModifyPath(path);
return CreateDirInner(path);
}
Status Win32Env::DeleteDir( const std::string& dirname )
{
Status sRet;
std::wstring path;
ToWidePath(dirname, path);
ModifyPath(path);
if(!::RemoveDirectoryW( path.c_str() ) ){
sRet = Status::IOError(dirname, "Could not delete directory.");
}
return sRet;
}
Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result )
{
Status sRet;
std::string path = fname;
ModifyPath(path);
Win32SequentialFile* pFile = new Win32SequentialFile(path);
if(pFile->isEnable()){
*result = pFile;
}else {
delete pFile;
sRet = Status::IOError(path, Win32::GetLastErrSz());
}
return sRet;
}
Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result )
{
Status sRet;
std::string path = fname;
Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path));
if(!pFile->isEnable()){
delete pFile;
*result = NULL;
sRet = Status::IOError(path, Win32::GetLastErrSz());
}else
*result = pFile;
return sRet;
}
Status Win32Env::NewLogger( const std::string& fname, Logger** result )
{
Status sRet;
std::string path = fname;
Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path));
if(!pMapFile->isEnable()){
delete pMapFile;
*result = NULL;
sRet = Status::IOError(path,"could not create a logger.");
}else
*result = new Win32Logger(pMapFile);
return sRet;
}
Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result )
{
Status sRet;
std::string path = fname;
Win32MapFile* pFile = new Win32MapFile(ModifyPath(path));
if(!pFile->isEnable()){
*result = NULL;
sRet = Status::IOError(fname,Win32::GetLastErrSz());
}else
*result = pFile;
return sRet;
}
Win32Env::Win32Env()
{
}
Win32Env::~Win32Env()
{
}
} // Win32 namespace
static port::OnceType once = LEVELDB_ONCE_INIT;
static Env* default_env;
static void InitDefaultEnv() { default_env = new Win32::Win32Env(); }
Env* Env::Default() {
port::InitOnce(&once, InitDefaultEnv);
return default_env;
}
} // namespace leveldb
#endif // defined(LEVELDB_PLATFORM_WINDOWS)