aboutsummaryrefslogtreecommitdiff
path: root/util/env_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'util/env_win.cc')
-rw-r--r--util/env_win.cc1031
1 files changed, 1031 insertions, 0 deletions
diff --git a/util/env_win.cc b/util/env_win.cc
new file mode 100644
index 0000000000..ef2ecae830
--- /dev/null
+++ b/util/env_win.cc
@@ -0,0 +1,1031 @@
+// 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)