MSVC
[novacoin.git] / src / leveldb / util / env_win.cc
1 // This file contains source that originates from:
2 // http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h
3 // http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc
4 // Those files dont' have any explict license headers but the 
5 // project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License'
6 // as the license.
7 #if defined(LEVELDB_PLATFORM_WINDOWS)
8 #include <map>
9
10
11 #include "leveldb/env.h"
12
13 #include "port/port.h"
14 #include "leveldb/slice.h"
15 #include "util/logging.h"
16
17 #include <shlwapi.h>
18 #include <process.h>
19 #include <cstring>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <io.h>
23 #include <algorithm>
24
25 #ifdef max
26 #undef max
27 #endif
28
29 #ifndef va_copy
30 #define va_copy(d,s) ((d) = (s))
31 #endif
32
33 #if defined DeleteFile
34 #undef DeleteFile
35 #endif
36
37 //Declarations
38 namespace leveldb
39 {
40
41 namespace Win32
42 {
43
44 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
45   TypeName(const TypeName&);               \
46   void operator=(const TypeName&)
47
48 std::string GetCurrentDir();
49 std::wstring GetCurrentDirW();
50
51 static const std::string CurrentDir = GetCurrentDir();
52 static const std::wstring CurrentDirW = GetCurrentDirW();
53
54 std::string& ModifyPath(std::string& path);
55 std::wstring& ModifyPath(std::wstring& path);
56
57 std::string GetLastErrSz();
58 std::wstring GetLastErrSzW();
59
60 size_t GetPageSize();
61
62 typedef void (*ScheduleProc)(void*) ;
63
64 struct WorkItemWrapper
65 {
66     WorkItemWrapper(ScheduleProc proc_,void* content_);
67     ScheduleProc proc;
68     void* pContent;
69 };
70
71 DWORD WINAPI WorkItemWrapperProc(LPVOID pContent);
72
73 class Win32SequentialFile : public SequentialFile
74 {
75 public:
76     friend class Win32Env;
77     virtual ~Win32SequentialFile();
78     virtual Status Read(size_t n, Slice* result, char* scratch);
79     virtual Status Skip(uint64_t n);
80     BOOL isEnable();
81 private:
82     BOOL _Init();
83     void _CleanUp();
84     Win32SequentialFile(const std::string& fname);
85     std::string _filename;
86     ::HANDLE _hFile;
87     DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile);
88 };
89
90 class Win32RandomAccessFile : public RandomAccessFile
91 {
92 public:
93     friend class Win32Env;
94     virtual ~Win32RandomAccessFile();
95     virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const;
96     BOOL isEnable();
97 private:
98     BOOL _Init(LPCWSTR path);
99     void _CleanUp();
100     Win32RandomAccessFile(const std::string& fname);
101     HANDLE _hFile;
102     const std::string _filename;
103     DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile);
104 };
105
106 class Win32MapFile : public WritableFile
107 {
108 public:
109     Win32MapFile(const std::string& fname);
110
111     ~Win32MapFile();
112     virtual Status Append(const Slice& data);
113     virtual Status Close();
114     virtual Status Flush();
115     virtual Status Sync();
116     BOOL isEnable();
117 private:
118     std::string _filename;
119     HANDLE _hFile;
120     size_t _page_size;
121     size_t _map_size;       // How much extra memory to map at a time
122     char* _base;            // The mapped region
123     HANDLE _base_handle;        
124     char* _limit;           // Limit of the mapped region
125     char* _dst;             // Where to write next  (in range [base_,limit_])
126     char* _last_sync;       // Where have we synced up to
127     uint64_t _file_offset;  // Offset of base_ in file
128     //LARGE_INTEGER file_offset_;
129     // Have we done an munmap of unsynced data?
130     bool _pending_sync;
131
132     // Roundup x to a multiple of y
133     static size_t _Roundup(size_t x, size_t y);
134     size_t _TruncateToPageBoundary(size_t s);
135     bool _UnmapCurrentRegion();
136     bool _MapNewRegion();
137     DISALLOW_COPY_AND_ASSIGN(Win32MapFile);
138     BOOL _Init(LPCWSTR Path);
139 };
140
141 class Win32FileLock : public FileLock
142 {
143 public:
144     friend class Win32Env;
145     virtual ~Win32FileLock();
146     BOOL isEnable();
147 private:
148     BOOL _Init(LPCWSTR path);
149     void _CleanUp();
150     Win32FileLock(const std::string& fname);
151     HANDLE _hFile;
152     std::string _filename;
153     DISALLOW_COPY_AND_ASSIGN(Win32FileLock);
154 };
155
156 class Win32Logger : public Logger
157 {
158 public: 
159     friend class Win32Env;
160     virtual ~Win32Logger();
161     virtual void Logv(const char* format, va_list ap);
162 private:
163     explicit Win32Logger(WritableFile* pFile);
164     WritableFile* _pFileProxy;
165     DISALLOW_COPY_AND_ASSIGN(Win32Logger);
166 };
167
168 class Win32Env : public Env
169 {
170 public:
171     Win32Env();
172     virtual ~Win32Env();
173     virtual Status NewSequentialFile(const std::string& fname,
174         SequentialFile** result);
175
176     virtual Status NewRandomAccessFile(const std::string& fname,
177         RandomAccessFile** result);
178     virtual Status NewWritableFile(const std::string& fname,
179         WritableFile** result);
180
181     virtual bool FileExists(const std::string& fname);
182
183     virtual Status GetChildren(const std::string& dir,
184         std::vector<std::string>* result);
185
186     virtual Status DeleteFile(const std::string& fname);
187
188     virtual Status CreateDir(const std::string& dirname);
189
190     virtual Status DeleteDir(const std::string& dirname);
191
192     virtual Status GetFileSize(const std::string& fname, uint64_t* file_size);
193
194     virtual Status RenameFile(const std::string& src,
195         const std::string& target);
196
197     virtual Status LockFile(const std::string& fname, FileLock** lock);
198
199     virtual Status UnlockFile(FileLock* lock);
200
201     virtual void Schedule(
202         void (*function)(void* arg),
203         void* arg);
204
205     virtual void StartThread(void (*function)(void* arg), void* arg);
206
207     virtual Status GetTestDirectory(std::string* path);
208
209     //virtual void Logv(WritableFile* log, const char* format, va_list ap);
210
211     virtual Status NewLogger(const std::string& fname, Logger** result);
212
213     virtual uint64_t NowMicros();
214
215     virtual void SleepForMicroseconds(int micros);
216 };
217
218 void ToWidePath(const std::string& value, std::wstring& target) {
219         wchar_t buffer[MAX_PATH];
220         MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH);
221         target = buffer;
222 }
223
224 void ToNarrowPath(const std::wstring& value, std::string& target) {
225         char buffer[MAX_PATH];
226         WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
227         target = buffer;
228 }
229
230 std::string GetCurrentDir()
231 {
232     CHAR path[MAX_PATH];
233     ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH);
234     *strrchr(path,'\\') = 0;
235     return std::string(path);
236 }
237
238 std::wstring GetCurrentDirW()
239 {
240     WCHAR path[MAX_PATH];
241     ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH);
242     *wcsrchr(path,L'\\') = 0;
243     return std::wstring(path);
244 }
245
246 std::string& ModifyPath(std::string& path)
247 {
248     if(path[0] == '/' || path[0] == '\\'){
249         path = CurrentDir + path;
250     }
251     std::replace(path.begin(),path.end(),'/','\\');
252
253     return path;
254 }
255
256 std::wstring& ModifyPath(std::wstring& path)
257 {
258     if(path[0] == L'/' || path[0] == L'\\'){
259         path = CurrentDirW + path;
260     }
261     std::replace(path.begin(),path.end(),L'/',L'\\');
262     return path;
263 }
264
265 std::string GetLastErrSz()
266 {
267     LPWSTR lpMsgBuf;
268     FormatMessageW( 
269         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
270         FORMAT_MESSAGE_FROM_SYSTEM | 
271         FORMAT_MESSAGE_IGNORE_INSERTS,
272         NULL,
273         GetLastError(),
274         0, // Default language
275         (LPWSTR) &lpMsgBuf,
276         0,
277         NULL 
278         );
279     std::string Err;
280         ToNarrowPath(lpMsgBuf, Err); 
281     LocalFree( lpMsgBuf );
282     return Err;
283 }
284
285 std::wstring GetLastErrSzW()
286 {
287     LPVOID lpMsgBuf;
288     FormatMessageW( 
289         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
290         FORMAT_MESSAGE_FROM_SYSTEM | 
291         FORMAT_MESSAGE_IGNORE_INSERTS,
292         NULL,
293         GetLastError(),
294         0, // Default language
295         (LPWSTR) &lpMsgBuf,
296         0,
297         NULL 
298         );
299     std::wstring Err = (LPCWSTR)lpMsgBuf;
300     LocalFree(lpMsgBuf);
301     return Err;
302 }
303
304 WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) :
305     proc(proc_),pContent(content_)
306 {
307
308 }
309
310 DWORD WINAPI WorkItemWrapperProc(LPVOID pContent)
311 {
312     WorkItemWrapper* item = static_cast<WorkItemWrapper*>(pContent);
313     ScheduleProc TempProc = item->proc;
314     void* arg = item->pContent;
315     delete item;
316     TempProc(arg);
317     return 0;
318 }
319
320 size_t GetPageSize()
321 {
322     SYSTEM_INFO si;
323     GetSystemInfo(&si);
324     return std::max(si.dwPageSize,si.dwAllocationGranularity);
325 }
326
327 const size_t g_PageSize = GetPageSize();
328
329
330 Win32SequentialFile::Win32SequentialFile( const std::string& fname ) :
331     _filename(fname),_hFile(NULL)
332 {
333     _Init();
334 }
335
336 Win32SequentialFile::~Win32SequentialFile()
337 {
338     _CleanUp();
339 }
340
341 Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch )
342 {
343     Status sRet;
344     DWORD hasRead = 0;
345     if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){
346         *result = Slice(scratch,hasRead);
347     } else {
348         sRet = Status::IOError(_filename, Win32::GetLastErrSz() );
349     }
350     return sRet;
351 }
352
353 Status Win32SequentialFile::Skip( uint64_t n )
354 {
355     Status sRet;
356     LARGE_INTEGER Move,NowPointer;
357     Move.QuadPart = n;
358     if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){
359         sRet = Status::IOError(_filename,Win32::GetLastErrSz());
360     }
361     return sRet;
362 }
363
364 BOOL Win32SequentialFile::isEnable()
365 {
366     return _hFile ? TRUE : FALSE;
367 }
368
369 BOOL Win32SequentialFile::_Init()
370 {
371         std::wstring path;
372         ToWidePath(_filename, path);
373         _hFile = CreateFileW(path.c_str(),
374                          GENERIC_READ,
375                          FILE_SHARE_READ,
376                          NULL,
377                          OPEN_EXISTING,
378                          FILE_ATTRIBUTE_NORMAL,
379                          NULL);
380     return _hFile ? TRUE : FALSE;
381 }
382
383 void Win32SequentialFile::_CleanUp()
384 {
385     if(_hFile){
386         CloseHandle(_hFile);
387         _hFile = NULL;
388     }
389 }
390
391 Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) :
392     _filename(fname),_hFile(NULL)
393 {
394         std::wstring path;
395         ToWidePath(fname, path);
396     _Init( path.c_str() );
397 }
398
399 Win32RandomAccessFile::~Win32RandomAccessFile()
400 {
401     _CleanUp();
402 }
403
404 Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const
405 {
406     Status sRet;
407     OVERLAPPED ol = {0};
408     ZeroMemory(&ol,sizeof(ol));
409     ol.Offset = (DWORD)offset;
410     ol.OffsetHigh = (DWORD)(offset >> 32);
411     DWORD hasRead = 0;
412     if(!ReadFile(_hFile,scratch,n,&hasRead,&ol))
413         sRet = Status::IOError(_filename,Win32::GetLastErrSz());
414     else
415         *result = Slice(scratch,hasRead);
416     return sRet;
417 }
418
419 BOOL Win32RandomAccessFile::_Init( LPCWSTR path )
420 {
421     BOOL bRet = FALSE;
422     if(!_hFile)
423         _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
424         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL);
425     if(!_hFile || _hFile == INVALID_HANDLE_VALUE )
426         _hFile = NULL;
427     else
428         bRet = TRUE;
429     return bRet;
430 }
431
432 BOOL Win32RandomAccessFile::isEnable()
433 {
434     return _hFile ? TRUE : FALSE;
435 }
436
437 void Win32RandomAccessFile::_CleanUp()
438 {
439     if(_hFile){
440         ::CloseHandle(_hFile);
441         _hFile = NULL;
442     }
443 }
444
445 size_t Win32MapFile::_Roundup( size_t x, size_t y )
446 {
447     return ((x + y - 1) / y) * y;
448 }
449
450 size_t Win32MapFile::_TruncateToPageBoundary( size_t s )
451 {
452     s -= (s & (_page_size - 1));
453     assert((s % _page_size) == 0);
454     return s;
455 }
456
457 bool Win32MapFile::_UnmapCurrentRegion()
458 {
459     bool result = true;
460     if (_base != NULL) {
461         if (_last_sync < _limit) {
462             // Defer syncing this data until next Sync() call, if any
463             _pending_sync = true;
464         }
465         if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle))
466             result = false;
467         _file_offset += _limit - _base;
468         _base = NULL;
469         _base_handle = NULL;
470         _limit = NULL;
471         _last_sync = NULL;
472         _dst = NULL;
473         // Increase the amount we map the next time, but capped at 1MB
474         if (_map_size < (1<<20)) {
475             _map_size *= 2;
476         }
477     }
478     return result;
479 }
480
481 bool Win32MapFile::_MapNewRegion()
482 {
483     assert(_base == NULL);
484     //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32);
485     //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF);
486     DWORD off_hi = (DWORD)(_file_offset >> 32);
487     DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF);
488     LARGE_INTEGER newSize;
489     newSize.QuadPart = _file_offset + _map_size;
490     SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN);
491     SetEndOfFile(_hFile);
492
493     _base_handle = CreateFileMappingA(
494         _hFile,
495         NULL,
496         PAGE_READWRITE,
497         0,
498         0,
499         0);
500     if (_base_handle != NULL) {
501         _base = (char*) MapViewOfFile(_base_handle,
502             FILE_MAP_ALL_ACCESS,
503             off_hi,
504             off_lo,
505             _map_size);
506         if (_base != NULL) {
507             _limit = _base + _map_size;
508             _dst = _base;
509             _last_sync = _base;
510             return true;
511         }
512     }
513     return false;
514 }
515
516 Win32MapFile::Win32MapFile( const std::string& fname) :
517     _filename(fname),
518     _hFile(NULL),
519     _page_size(Win32::g_PageSize),
520     _map_size(_Roundup(65536, Win32::g_PageSize)),
521     _base(NULL),
522     _base_handle(NULL),
523     _limit(NULL),
524     _dst(NULL),
525     _last_sync(NULL),
526     _file_offset(0),
527     _pending_sync(false)
528 {
529         std::wstring path;
530         ToWidePath(fname, path);
531     _Init(path.c_str());
532     assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0);
533 }
534
535 Status Win32MapFile::Append( const Slice& data )
536 {
537     const char* src = data.data();
538     size_t left = data.size();
539     Status s;
540     while (left > 0) {
541         assert(_base <= _dst);
542         assert(_dst <= _limit);
543         size_t avail = _limit - _dst;
544         if (avail == 0) {
545             if (!_UnmapCurrentRegion() ||
546                 !_MapNewRegion()) {
547                     return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz());
548             }
549         }
550         size_t n = (left <= avail) ? left : avail;
551         memcpy(_dst, src, n);
552         _dst += n;
553         src += n;
554         left -= n;
555     }
556     return s;
557 }
558
559 Status Win32MapFile::Close()
560 {
561     Status s;
562     size_t unused = _limit - _dst;
563     if (!_UnmapCurrentRegion()) {
564         s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz());
565     } else if (unused > 0) {
566         // Trim the extra space at the end of the file
567         LARGE_INTEGER newSize;
568         newSize.QuadPart = _file_offset - unused;
569         if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) {
570             s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz());
571         } else 
572             SetEndOfFile(_hFile);
573     }
574     if (!CloseHandle(_hFile)) {
575         if (s.ok()) {
576             s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz());
577         }
578     }
579     _hFile = INVALID_HANDLE_VALUE;
580     _base = NULL;
581     _base_handle = NULL;
582     _limit = NULL;
583
584     return s;
585 }
586
587 Status Win32MapFile::Sync()
588 {
589     Status s;
590     if (_pending_sync) {
591         // Some unmapped data was not synced
592         _pending_sync = false;
593         if (!FlushFileBuffers(_hFile)) {
594             s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz());
595         }
596     }
597     if (_dst > _last_sync) {
598         // Find the beginnings of the pages that contain the first and last
599         // bytes to be synced.
600         size_t p1 = _TruncateToPageBoundary(_last_sync - _base);
601         size_t p2 = _TruncateToPageBoundary(_dst - _base - 1);
602         _last_sync = _dst;
603         if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) {
604             s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz());
605         }
606     }
607     return s;
608 }
609
610 Status Win32MapFile::Flush()
611 {
612     return Status::OK();
613 }
614
615 Win32MapFile::~Win32MapFile()
616 {
617     if (_hFile != INVALID_HANDLE_VALUE) { 
618         Win32MapFile::Close();
619     }
620 }
621
622 BOOL Win32MapFile::_Init( LPCWSTR Path )
623 {
624     DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS;
625     _hFile = CreateFileW(Path,
626                          GENERIC_READ | GENERIC_WRITE,
627                          FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
628                          NULL,
629                          Flag,
630                          FILE_ATTRIBUTE_NORMAL,
631                          NULL);
632     if(!_hFile || _hFile == INVALID_HANDLE_VALUE)
633         return FALSE;
634     else
635         return TRUE;
636 }
637
638 BOOL Win32MapFile::isEnable()
639 {
640     return _hFile ? TRUE : FALSE;
641 }
642
643 Win32FileLock::Win32FileLock( const std::string& fname ) :
644     _hFile(NULL),_filename(fname)
645 {
646         std::wstring path;
647         ToWidePath(fname, path);
648         _Init(path.c_str());
649 }
650
651 Win32FileLock::~Win32FileLock()
652 {
653     _CleanUp();
654 }
655
656 BOOL Win32FileLock::_Init( LPCWSTR path )
657 {
658     BOOL bRet = FALSE;
659     if(!_hFile)
660         _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
661     if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){
662         _hFile = NULL;
663     }
664     else
665         bRet = TRUE;
666     return bRet;
667 }
668
669 void Win32FileLock::_CleanUp()
670 {
671     ::CloseHandle(_hFile);
672     _hFile = NULL;
673 }
674
675 BOOL Win32FileLock::isEnable()
676 {
677     return _hFile ? TRUE : FALSE;
678 }
679
680 Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile)
681 {
682     assert(_pFileProxy);
683 }
684
685 Win32Logger::~Win32Logger()
686 {
687     if(_pFileProxy)
688         delete _pFileProxy;
689 }
690
691 void Win32Logger::Logv( const char* format, va_list ap )
692 {
693     uint64_t thread_id = ::GetCurrentThreadId();
694
695     // We try twice: the first time with a fixed-size stack allocated buffer,
696     // and the second time with a much larger dynamically allocated buffer.
697     char buffer[500];
698     for (int iter = 0; iter < 2; iter++) {
699         char* base;
700         int bufsize;
701         if (iter == 0) {
702             bufsize = sizeof(buffer);
703             base = buffer;
704         } else {
705             bufsize = 30000;
706             base = new char[bufsize];
707         }
708         char* p = base;
709         char* limit = base + bufsize;
710
711         SYSTEMTIME st;
712         GetLocalTime(&st);
713         p += snprintf(p, limit - p,
714             "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
715             int(st.wYear),
716             int(st.wMonth),
717             int(st.wDay),
718             int(st.wHour),
719             int(st.wMinute),
720             int(st.wMinute),
721             int(st.wMilliseconds),
722             static_cast<long long unsigned int>(thread_id));
723
724         // Print the message
725         if (p < limit) {
726             va_list backup_ap;
727             va_copy(backup_ap, ap);
728             p += vsnprintf(p, limit - p, format, backup_ap);
729             va_end(backup_ap);
730         }
731
732         // Truncate to available space if necessary
733         if (p >= limit) {
734             if (iter == 0) {
735                 continue;       // Try again with larger buffer
736             } else {
737                 p = limit - 1;
738             }
739         }
740
741         // Add newline if necessary
742         if (p == base || p[-1] != '\n') {
743             *p++ = '\n';
744         }
745
746         assert(p <= limit);
747         DWORD hasWritten = 0;
748         if(_pFileProxy){
749             _pFileProxy->Append(Slice(base, p - base));
750             _pFileProxy->Flush();
751         }
752         if (base != buffer) {
753             delete[] base;
754         }
755         break;
756     }
757 }
758
759 bool Win32Env::FileExists(const std::string& fname)
760 {
761         std::string path = fname;
762     std::wstring wpath;
763         ToWidePath(ModifyPath(path), wpath);
764     return ::PathFileExistsW(wpath.c_str()) ? true : false;
765 }
766
767 Status Win32Env::GetChildren(const std::string& dir, std::vector<std::string>* result)
768 {
769     Status sRet;
770     ::WIN32_FIND_DATAW wfd;
771     std::string path = dir;
772     ModifyPath(path);
773     path += "\\*.*";
774         std::wstring wpath;
775         ToWidePath(path, wpath);
776
777         ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd);
778     if(hFind && hFind != INVALID_HANDLE_VALUE){
779         BOOL hasNext = TRUE;
780         std::string child;
781         while(hasNext){
782             ToNarrowPath(wfd.cFileName, child); 
783             if(child != ".." && child != ".")  {
784                 result->push_back(child);
785             }
786             hasNext = ::FindNextFileW(hFind,&wfd);
787         }
788         ::FindClose(hFind);
789     }
790     else
791         sRet = Status::IOError(dir,"Could not get children.");
792     return sRet;
793 }
794
795 void Win32Env::SleepForMicroseconds( int micros )
796 {
797     ::Sleep((micros + 999) /1000);
798 }
799
800
801 Status Win32Env::DeleteFile( const std::string& fname )
802 {
803     Status sRet;
804     std::string path = fname;
805     std::wstring wpath;
806         ToWidePath(ModifyPath(path), wpath);
807
808     if(!::DeleteFileW(wpath.c_str())) {
809         sRet = Status::IOError(path, "Could not delete file.");
810     }
811     return sRet;
812 }
813
814 Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size )
815 {
816     Status sRet;
817     std::string path = fname;
818     std::wstring wpath;
819         ToWidePath(ModifyPath(path), wpath);
820
821     HANDLE file = ::CreateFileW(wpath.c_str(),
822         GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
823     LARGE_INTEGER li;
824     if(::GetFileSizeEx(file,&li)){
825         *file_size = (uint64_t)li.QuadPart;
826     }else
827         sRet = Status::IOError(path,"Could not get the file size.");
828     CloseHandle(file);
829     return sRet;
830 }
831
832 Status Win32Env::RenameFile( const std::string& src, const std::string& target )
833 {
834     Status sRet;
835     std::string src_path = src;
836     std::wstring wsrc_path;
837         ToWidePath(ModifyPath(src_path), wsrc_path);
838         std::string target_path = target;
839     std::wstring wtarget_path;
840         ToWidePath(ModifyPath(target_path), wtarget_path);
841
842     if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){
843         DWORD err = GetLastError();
844         if(err == 0x000000b7){
845             if(!::DeleteFileW(wtarget_path.c_str() ) )
846                 sRet = Status::IOError(src, "Could not rename file.");
847                         else if(!::MoveFileW(wsrc_path.c_str(),
848                                  wtarget_path.c_str() ) )
849                 sRet = Status::IOError(src, "Could not rename file.");    
850         }
851     }
852     return sRet;
853 }
854
855 Status Win32Env::LockFile( const std::string& fname, FileLock** lock )
856 {
857     Status sRet;
858     std::string path = fname;
859     ModifyPath(path);
860     Win32FileLock* _lock = new Win32FileLock(path);
861     if(!_lock->isEnable()){
862         delete _lock;
863         *lock = NULL;
864         sRet = Status::IOError(path, "Could not lock file.");
865     }
866     else
867         *lock = _lock;
868     return sRet;
869 }
870
871 Status Win32Env::UnlockFile( FileLock* lock )
872 {
873     Status sRet;
874     delete lock;
875     return sRet;
876 }
877
878 void Win32Env::Schedule( void (*function)(void* arg), void* arg )
879 {
880     QueueUserWorkItem(Win32::WorkItemWrapperProc,
881                       new Win32::WorkItemWrapper(function,arg),
882                       WT_EXECUTEDEFAULT);
883 }
884
885 void Win32Env::StartThread( void (*function)(void* arg), void* arg )
886 {
887     ::_beginthread(function,0,arg);
888 }
889
890 Status Win32Env::GetTestDirectory( std::string* path )
891 {
892     Status sRet;
893     WCHAR TempPath[MAX_PATH];
894     ::GetTempPathW(MAX_PATH,TempPath);
895         ToNarrowPath(TempPath, *path);
896     path->append("leveldb\\test\\");
897     ModifyPath(*path);
898     return sRet;
899 }
900
901 uint64_t Win32Env::NowMicros()
902 {
903 #ifndef USE_VISTA_API
904 #define GetTickCount64 GetTickCount
905 #endif
906     return (uint64_t)(GetTickCount64()*1000);
907 }
908
909 static Status CreateDirInner( const std::string& dirname )
910 {
911     Status sRet;
912 #ifdef _MSC_VER
913     DWORD attr = ::GetFileAttributesA(dirname.c_str());
914 #else
915     DWORD attr = ::GetFileAttributes(dirname.c_str());
916 #endif
917
918     if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist:
919       std::size_t slash = dirname.find_last_of("\\");
920       if (slash != std::string::npos){
921         sRet = CreateDirInner(dirname.substr(0, slash));
922         if (!sRet.ok()) return sRet;
923       }
924 #ifdef _MSC_VER
925       BOOL result = ::CreateDirectoryA(dirname.c_str(), NULL);
926 #else
927       BOOL result = ::CreateDirectory(dirname.c_str(), NULL);
928 #endif
929       if (result == FALSE) {
930         sRet = Status::IOError(dirname, "Could not create directory.");
931         return sRet;
932       }
933     }
934     return sRet;
935 }
936
937 Status Win32Env::CreateDir( const std::string& dirname )
938 {
939     std::string path = dirname;
940     if(path[path.length() - 1] != '\\'){
941         path += '\\';
942     }
943     ModifyPath(path);
944
945     return CreateDirInner(path);
946 }
947
948 Status Win32Env::DeleteDir( const std::string& dirname )
949 {
950     Status sRet;
951     std::wstring path;
952         ToWidePath(dirname, path);
953     ModifyPath(path);
954     if(!::RemoveDirectoryW( path.c_str() ) ){
955         sRet = Status::IOError(dirname, "Could not delete directory.");
956     }
957     return sRet;
958 }
959
960 Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result )
961 {
962     Status sRet;
963     std::string path = fname;
964     ModifyPath(path);
965     Win32SequentialFile* pFile = new Win32SequentialFile(path);
966     if(pFile->isEnable()){
967         *result = pFile;
968     }else {
969         delete pFile;
970         sRet = Status::IOError(path, Win32::GetLastErrSz());
971     }
972     return sRet;
973 }
974
975 Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result )
976 {
977     Status sRet;
978     std::string path = fname;
979     Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path));
980     if(!pFile->isEnable()){
981         delete pFile;
982         *result = NULL;
983         sRet = Status::IOError(path, Win32::GetLastErrSz());
984     }else
985         *result = pFile;
986     return sRet;
987 }
988
989 Status Win32Env::NewLogger( const std::string& fname, Logger** result )
990 {
991     Status sRet;
992     std::string path = fname;
993     Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path));
994     if(!pMapFile->isEnable()){
995         delete pMapFile;
996         *result = NULL;
997         sRet = Status::IOError(path,"could not create a logger.");
998     }else
999         *result = new Win32Logger(pMapFile);
1000     return sRet;
1001 }
1002
1003 Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result )
1004 {
1005     Status sRet;
1006     std::string path = fname;
1007     Win32MapFile* pFile = new Win32MapFile(ModifyPath(path));
1008     if(!pFile->isEnable()){
1009         *result = NULL;
1010         sRet = Status::IOError(fname,Win32::GetLastErrSz());
1011     }else
1012         *result = pFile;
1013     return sRet;
1014 }
1015
1016 Win32Env::Win32Env()
1017 {
1018
1019 }
1020
1021 Win32Env::~Win32Env()
1022 {
1023
1024 }
1025
1026
1027 }  // Win32 namespace
1028
1029 static port::OnceType once = LEVELDB_ONCE_INIT;
1030 static Env* default_env;
1031 static void InitDefaultEnv() { default_env = new Win32::Win32Env(); }
1032
1033 Env* Env::Default() {
1034   port::InitOnce(&once, InitDefaultEnv);
1035   return default_env;
1036 }
1037
1038 }  // namespace leveldb
1039
1040 #endif // defined(LEVELDB_PLATFORM_WINDOWS)