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 don't have any explicit license headers but the
5 // project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License'
7 #if defined(LEVELDB_PLATFORM_WINDOWS)
11 #include "leveldb/env.h"
13 #include "port/port.h"
14 #include "leveldb/slice.h"
15 #include "util/logging.h"
30 #define va_copy(d,s) ((d) = (s))
33 #if defined DeleteFile
44 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
45 TypeName(const TypeName&); \
46 void operator=(const TypeName&)
48 std::string
GetCurrentDir();
49 std::wstring
GetCurrentDirW();
51 static const std::string CurrentDir
= GetCurrentDir();
52 static const std::wstring CurrentDirW
= GetCurrentDirW();
54 std::string
& ModifyPath(std::string
& path
);
55 std::wstring
& ModifyPath(std::wstring
& path
);
57 std::string
GetLastErrSz();
58 std::wstring
GetLastErrSzW();
62 typedef void (*ScheduleProc
)(void*) ;
64 struct WorkItemWrapper
66 WorkItemWrapper(ScheduleProc proc_
,void* content_
);
71 DWORD WINAPI
WorkItemWrapperProc(LPVOID pContent
);
73 class Win32SequentialFile
: public SequentialFile
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
);
84 Win32SequentialFile(const std::string
& fname
);
85 std::string _filename
;
87 DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile
);
90 class Win32RandomAccessFile
: public RandomAccessFile
93 friend class Win32Env
;
94 virtual ~Win32RandomAccessFile();
95 virtual Status
Read(uint64_t offset
, size_t n
, Slice
* result
,char* scratch
) const;
98 BOOL
_Init(LPCWSTR path
);
100 Win32RandomAccessFile(const std::string
& fname
);
102 const std::string _filename
;
103 DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile
);
106 class Win32WritableFile
: public WritableFile
109 Win32WritableFile(const std::string
& fname
, bool append
);
110 ~Win32WritableFile();
112 virtual Status
Append(const Slice
& data
);
113 virtual Status
Close();
114 virtual Status
Flush();
115 virtual Status
Sync();
118 std::string filename_
;
122 class Win32FileLock
: public FileLock
125 friend class Win32Env
;
126 virtual ~Win32FileLock();
129 BOOL
_Init(LPCWSTR path
);
131 Win32FileLock(const std::string
& fname
);
133 std::string _filename
;
134 DISALLOW_COPY_AND_ASSIGN(Win32FileLock
);
137 class Win32Logger
: public Logger
140 friend class Win32Env
;
141 virtual ~Win32Logger();
142 virtual void Logv(const char* format
, va_list ap
);
144 explicit Win32Logger(WritableFile
* pFile
);
145 WritableFile
* _pFileProxy
;
146 DISALLOW_COPY_AND_ASSIGN(Win32Logger
);
149 class Win32Env
: public Env
154 virtual Status
NewSequentialFile(const std::string
& fname
,
155 SequentialFile
** result
);
157 virtual Status
NewRandomAccessFile(const std::string
& fname
,
158 RandomAccessFile
** result
);
159 virtual Status
NewWritableFile(const std::string
& fname
,
160 WritableFile
** result
);
161 virtual Status
NewAppendableFile(const std::string
& fname
,
162 WritableFile
** result
);
164 virtual bool FileExists(const std::string
& fname
);
166 virtual Status
GetChildren(const std::string
& dir
,
167 std::vector
<std::string
>* result
);
169 virtual Status
DeleteFile(const std::string
& fname
);
171 virtual Status
CreateDir(const std::string
& dirname
);
173 virtual Status
DeleteDir(const std::string
& dirname
);
175 virtual Status
GetFileSize(const std::string
& fname
, uint64_t* file_size
);
177 virtual Status
RenameFile(const std::string
& src
,
178 const std::string
& target
);
180 virtual Status
LockFile(const std::string
& fname
, FileLock
** lock
);
182 virtual Status
UnlockFile(FileLock
* lock
);
184 virtual void Schedule(
185 void (*function
)(void* arg
),
188 virtual void StartThread(void (*function
)(void* arg
), void* arg
);
190 virtual Status
GetTestDirectory(std::string
* path
);
192 //virtual void Logv(WritableFile* log, const char* format, va_list ap);
194 virtual Status
NewLogger(const std::string
& fname
, Logger
** result
);
196 virtual uint64_t NowMicros();
198 virtual void SleepForMicroseconds(int micros
);
201 void ToWidePath(const std::string
& value
, std::wstring
& target
) {
202 wchar_t buffer
[MAX_PATH
];
203 MultiByteToWideChar(CP_ACP
, 0, value
.c_str(), -1, buffer
, MAX_PATH
);
207 void ToNarrowPath(const std::wstring
& value
, std::string
& target
) {
208 char buffer
[MAX_PATH
];
209 WideCharToMultiByte(CP_ACP
, 0, value
.c_str(), -1, buffer
, MAX_PATH
, NULL
, NULL
);
213 std::string
GetCurrentDir()
216 ::GetModuleFileNameA(::GetModuleHandleA(NULL
),path
,MAX_PATH
);
217 *strrchr(path
,'\\') = 0;
218 return std::string(path
);
221 std::wstring
GetCurrentDirW()
223 WCHAR path
[MAX_PATH
];
224 ::GetModuleFileNameW(::GetModuleHandleW(NULL
),path
,MAX_PATH
);
225 *wcsrchr(path
,L
'\\') = 0;
226 return std::wstring(path
);
229 std::string
& ModifyPath(std::string
& path
)
231 if(path
[0] == '/' || path
[0] == '\\'){
232 path
= CurrentDir
+ path
;
234 std::replace(path
.begin(),path
.end(),'/','\\');
239 std::wstring
& ModifyPath(std::wstring
& path
)
241 if(path
[0] == L
'/' || path
[0] == L
'\\'){
242 path
= CurrentDirW
+ path
;
244 std::replace(path
.begin(),path
.end(),L
'/',L
'\\');
248 std::string
GetLastErrSz()
252 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
253 FORMAT_MESSAGE_FROM_SYSTEM
|
254 FORMAT_MESSAGE_IGNORE_INSERTS
,
257 0, // Default language
263 ToNarrowPath(lpMsgBuf
, Err
);
264 LocalFree( lpMsgBuf
);
268 std::wstring
GetLastErrSzW()
272 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
273 FORMAT_MESSAGE_FROM_SYSTEM
|
274 FORMAT_MESSAGE_IGNORE_INSERTS
,
277 0, // Default language
282 std::wstring Err
= (LPCWSTR
)lpMsgBuf
;
287 WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_
,void* content_
) :
288 proc(proc_
),pContent(content_
)
293 DWORD WINAPI
WorkItemWrapperProc(LPVOID pContent
)
295 WorkItemWrapper
* item
= static_cast<WorkItemWrapper
*>(pContent
);
296 ScheduleProc TempProc
= item
->proc
;
297 void* arg
= item
->pContent
;
307 return std::max(si
.dwPageSize
,si
.dwAllocationGranularity
);
310 const size_t g_PageSize
= GetPageSize();
313 Win32SequentialFile::Win32SequentialFile( const std::string
& fname
) :
314 _filename(fname
),_hFile(NULL
)
319 Win32SequentialFile::~Win32SequentialFile()
324 Status
Win32SequentialFile::Read( size_t n
, Slice
* result
, char* scratch
)
328 if(_hFile
&& ReadFile(_hFile
,scratch
,n
,&hasRead
,NULL
) ){
329 *result
= Slice(scratch
,hasRead
);
331 sRet
= Status::IOError(_filename
, Win32::GetLastErrSz() );
336 Status
Win32SequentialFile::Skip( uint64_t n
)
339 LARGE_INTEGER Move
,NowPointer
;
341 if(!SetFilePointerEx(_hFile
,Move
,&NowPointer
,FILE_CURRENT
)){
342 sRet
= Status::IOError(_filename
,Win32::GetLastErrSz());
347 BOOL
Win32SequentialFile::isEnable()
349 return _hFile
? TRUE
: FALSE
;
352 BOOL
Win32SequentialFile::_Init()
355 ToWidePath(_filename
, path
);
356 _hFile
= CreateFileW(path
.c_str(),
358 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
361 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_SEQUENTIAL_SCAN
,
363 if (_hFile
== INVALID_HANDLE_VALUE
)
365 return _hFile
? TRUE
: FALSE
;
368 void Win32SequentialFile::_CleanUp()
376 Win32RandomAccessFile::Win32RandomAccessFile( const std::string
& fname
) :
377 _filename(fname
),_hFile(NULL
)
380 ToWidePath(fname
, path
);
381 _Init( path
.c_str() );
384 Win32RandomAccessFile::~Win32RandomAccessFile()
389 Status
Win32RandomAccessFile::Read(uint64_t offset
,size_t n
,Slice
* result
,char* scratch
) const
393 ZeroMemory(&ol
,sizeof(ol
));
394 ol
.Offset
= (DWORD
)offset
;
395 ol
.OffsetHigh
= (DWORD
)(offset
>> 32);
397 if(!ReadFile(_hFile
,scratch
,n
,&hasRead
,&ol
))
398 sRet
= Status::IOError(_filename
,Win32::GetLastErrSz());
400 *result
= Slice(scratch
,hasRead
);
404 BOOL
Win32RandomAccessFile::_Init( LPCWSTR path
)
408 _hFile
= ::CreateFileW(path
,GENERIC_READ
,FILE_SHARE_READ
|FILE_SHARE_WRITE
,NULL
,OPEN_EXISTING
,
409 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_RANDOM_ACCESS
,NULL
);
410 if(!_hFile
|| _hFile
== INVALID_HANDLE_VALUE
)
417 BOOL
Win32RandomAccessFile::isEnable()
419 return _hFile
? TRUE
: FALSE
;
422 void Win32RandomAccessFile::_CleanUp()
425 ::CloseHandle(_hFile
);
430 Win32WritableFile::Win32WritableFile(const std::string
& fname
, bool append
)
434 ToWidePath(fname
, path
);
435 // NewAppendableFile: append to an existing file, or create a new one
436 // if none exists - this is OPEN_ALWAYS behavior, with
437 // FILE_APPEND_DATA to avoid having to manually position the file
438 // pointer at the end of the file.
439 // NewWritableFile: create a new file, delete if it exists - this is
440 // CREATE_ALWAYS behavior. This file is used for writing only so
441 // use GENERIC_WRITE.
442 _hFile
= CreateFileW(path
.c_str(),
443 append
? FILE_APPEND_DATA
: GENERIC_WRITE
,
444 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
446 append
? OPEN_ALWAYS
: CREATE_ALWAYS
,
447 FILE_ATTRIBUTE_NORMAL
,
449 // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use
452 Win32WritableFile::~Win32WritableFile()
454 if (_hFile
!= INVALID_HANDLE_VALUE
)
458 Status
Win32WritableFile::Append(const Slice
& data
)
461 if (!WriteFile(_hFile
, data
.data(), data
.size(), &r
, NULL
) || r
!= data
.size()) {
462 return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_
, Win32::GetLastErrSz());
467 Status
Win32WritableFile::Close()
469 if (!CloseHandle(_hFile
)) {
470 return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_
, Win32::GetLastErrSz());
472 _hFile
= INVALID_HANDLE_VALUE
;
476 Status
Win32WritableFile::Flush()
478 // Nothing to do here, there are no application-side buffers
482 Status
Win32WritableFile::Sync()
484 if (!FlushFileBuffers(_hFile
)) {
485 return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_
, Win32::GetLastErrSz());
490 BOOL
Win32WritableFile::isEnable()
492 return _hFile
!= INVALID_HANDLE_VALUE
;
495 Win32FileLock::Win32FileLock( const std::string
& fname
) :
496 _hFile(NULL
),_filename(fname
)
499 ToWidePath(fname
, path
);
503 Win32FileLock::~Win32FileLock()
508 BOOL
Win32FileLock::_Init( LPCWSTR path
)
512 _hFile
= ::CreateFileW(path
,0,0,NULL
,CREATE_ALWAYS
,FILE_ATTRIBUTE_NORMAL
,NULL
);
513 if(!_hFile
|| _hFile
== INVALID_HANDLE_VALUE
){
521 void Win32FileLock::_CleanUp()
523 ::CloseHandle(_hFile
);
527 BOOL
Win32FileLock::isEnable()
529 return _hFile
? TRUE
: FALSE
;
532 Win32Logger::Win32Logger(WritableFile
* pFile
) : _pFileProxy(pFile
)
537 Win32Logger::~Win32Logger()
543 void Win32Logger::Logv( const char* format
, va_list ap
)
545 uint64_t thread_id
= ::GetCurrentThreadId();
547 // We try twice: the first time with a fixed-size stack allocated buffer,
548 // and the second time with a much larger dynamically allocated buffer.
550 for (int iter
= 0; iter
< 2; iter
++) {
554 bufsize
= sizeof(buffer
);
558 base
= new char[bufsize
];
561 char* limit
= base
+ bufsize
;
565 p
+= snprintf(p
, limit
- p
,
566 "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
573 int(st
.wMilliseconds
),
574 static_cast<long long unsigned int>(thread_id
));
579 va_copy(backup_ap
, ap
);
580 p
+= vsnprintf(p
, limit
- p
, format
, backup_ap
);
584 // Truncate to available space if necessary
587 continue; // Try again with larger buffer
593 // Add newline if necessary
594 if (p
== base
|| p
[-1] != '\n') {
599 DWORD hasWritten
= 0;
601 _pFileProxy
->Append(Slice(base
, p
- base
));
602 _pFileProxy
->Flush();
604 if (base
!= buffer
) {
611 bool Win32Env::FileExists(const std::string
& fname
)
613 std::string path
= fname
;
615 ToWidePath(ModifyPath(path
), wpath
);
616 return ::PathFileExistsW(wpath
.c_str()) ? true : false;
619 Status
Win32Env::GetChildren(const std::string
& dir
, std::vector
<std::string
>* result
)
622 ::WIN32_FIND_DATAW wfd
;
623 std::string path
= dir
;
627 ToWidePath(path
, wpath
);
629 ::HANDLE hFind
= ::FindFirstFileW(wpath
.c_str() ,&wfd
);
630 if(hFind
&& hFind
!= INVALID_HANDLE_VALUE
){
634 ToNarrowPath(wfd
.cFileName
, child
);
635 if(child
!= ".." && child
!= ".") {
636 result
->push_back(child
);
638 hasNext
= ::FindNextFileW(hFind
,&wfd
);
643 sRet
= Status::IOError(dir
,"Could not get children.");
647 void Win32Env::SleepForMicroseconds( int micros
)
649 ::Sleep((micros
+ 999) /1000);
653 Status
Win32Env::DeleteFile( const std::string
& fname
)
656 std::string path
= fname
;
658 ToWidePath(ModifyPath(path
), wpath
);
660 if(!::DeleteFileW(wpath
.c_str())) {
661 sRet
= Status::IOError(path
, "Could not delete file.");
666 Status
Win32Env::GetFileSize( const std::string
& fname
, uint64_t* file_size
)
669 std::string path
= fname
;
671 ToWidePath(ModifyPath(path
), wpath
);
673 HANDLE file
= ::CreateFileW(wpath
.c_str(),
674 GENERIC_READ
,FILE_SHARE_READ
|FILE_SHARE_WRITE
,NULL
,OPEN_EXISTING
,FILE_ATTRIBUTE_NORMAL
,NULL
);
676 if(::GetFileSizeEx(file
,&li
)){
677 *file_size
= (uint64_t)li
.QuadPart
;
679 sRet
= Status::IOError(path
,"Could not get the file size.");
684 Status
Win32Env::RenameFile( const std::string
& src
, const std::string
& target
)
687 std::string src_path
= src
;
688 std::wstring wsrc_path
;
689 ToWidePath(ModifyPath(src_path
), wsrc_path
);
690 std::string target_path
= target
;
691 std::wstring wtarget_path
;
692 ToWidePath(ModifyPath(target_path
), wtarget_path
);
694 if(!MoveFileW(wsrc_path
.c_str(), wtarget_path
.c_str() ) ){
695 DWORD err
= GetLastError();
696 if(err
== 0x000000b7){
697 if(!::DeleteFileW(wtarget_path
.c_str() ) )
698 sRet
= Status::IOError(src
, "Could not rename file.");
699 else if(!::MoveFileW(wsrc_path
.c_str(),
700 wtarget_path
.c_str() ) )
701 sRet
= Status::IOError(src
, "Could not rename file.");
707 Status
Win32Env::LockFile( const std::string
& fname
, FileLock
** lock
)
710 std::string path
= fname
;
712 Win32FileLock
* _lock
= new Win32FileLock(path
);
713 if(!_lock
->isEnable()){
716 sRet
= Status::IOError(path
, "Could not lock file.");
723 Status
Win32Env::UnlockFile( FileLock
* lock
)
730 void Win32Env::Schedule( void (*function
)(void* arg
), void* arg
)
732 QueueUserWorkItem(Win32::WorkItemWrapperProc
,
733 new Win32::WorkItemWrapper(function
,arg
),
737 void Win32Env::StartThread( void (*function
)(void* arg
), void* arg
)
739 ::_beginthread(function
,0,arg
);
742 Status
Win32Env::GetTestDirectory( std::string
* path
)
745 WCHAR TempPath
[MAX_PATH
];
746 ::GetTempPathW(MAX_PATH
,TempPath
);
747 ToNarrowPath(TempPath
, *path
);
748 path
->append("leveldb\\test\\");
753 uint64_t Win32Env::NowMicros()
755 #ifndef USE_VISTA_API
756 #define GetTickCount64 GetTickCount
758 return (uint64_t)(GetTickCount64()*1000);
761 static Status
CreateDirInner( const std::string
& dirname
)
764 DWORD attr
= ::GetFileAttributes(dirname
.c_str());
765 if (attr
== INVALID_FILE_ATTRIBUTES
) { // doesn't exist:
766 std::size_t slash
= dirname
.find_last_of("\\");
767 if (slash
!= std::string::npos
){
768 sRet
= CreateDirInner(dirname
.substr(0, slash
));
769 if (!sRet
.ok()) return sRet
;
771 BOOL result
= ::CreateDirectory(dirname
.c_str(), NULL
);
772 if (result
== FALSE
) {
773 sRet
= Status::IOError(dirname
, "Could not create directory.");
780 Status
Win32Env::CreateDir( const std::string
& dirname
)
782 std::string path
= dirname
;
783 if(path
[path
.length() - 1] != '\\'){
788 return CreateDirInner(path
);
791 Status
Win32Env::DeleteDir( const std::string
& dirname
)
795 ToWidePath(dirname
, path
);
797 if(!::RemoveDirectoryW( path
.c_str() ) ){
798 sRet
= Status::IOError(dirname
, "Could not delete directory.");
803 Status
Win32Env::NewSequentialFile( const std::string
& fname
, SequentialFile
** result
)
806 std::string path
= fname
;
808 Win32SequentialFile
* pFile
= new Win32SequentialFile(path
);
809 if(pFile
->isEnable()){
813 sRet
= Status::IOError(path
, Win32::GetLastErrSz());
818 Status
Win32Env::NewRandomAccessFile( const std::string
& fname
, RandomAccessFile
** result
)
821 std::string path
= fname
;
822 Win32RandomAccessFile
* pFile
= new Win32RandomAccessFile(ModifyPath(path
));
823 if(!pFile
->isEnable()){
826 sRet
= Status::IOError(path
, Win32::GetLastErrSz());
832 Status
Win32Env::NewLogger( const std::string
& fname
, Logger
** result
)
835 std::string path
= fname
;
836 // Logs are opened with write semantics, not with append semantics
837 // (see PosixEnv::NewLogger)
838 Win32WritableFile
* pMapFile
= new Win32WritableFile(ModifyPath(path
), false);
839 if(!pMapFile
->isEnable()){
842 sRet
= Status::IOError(path
,"could not create a logger.");
844 *result
= new Win32Logger(pMapFile
);
848 Status
Win32Env::NewWritableFile( const std::string
& fname
, WritableFile
** result
)
851 std::string path
= fname
;
852 Win32WritableFile
* pFile
= new Win32WritableFile(ModifyPath(path
), false);
853 if(!pFile
->isEnable()){
855 sRet
= Status::IOError(fname
,Win32::GetLastErrSz());
861 Status
Win32Env::NewAppendableFile( const std::string
& fname
, WritableFile
** result
)
864 std::string path
= fname
;
865 Win32WritableFile
* pFile
= new Win32WritableFile(ModifyPath(path
), true);
866 if(!pFile
->isEnable()){
868 sRet
= Status::IOError(fname
,Win32::GetLastErrSz());
879 Win32Env::~Win32Env()
887 static port::OnceType once
= LEVELDB_ONCE_INIT
;
888 static Env
* default_env
;
889 static void InitDefaultEnv() { default_env
= new Win32::Win32Env(); }
891 Env
* Env::Default() {
892 port::InitOnce(&once
, InitDefaultEnv
);
896 } // namespace leveldb
898 #endif // defined(LEVELDB_PLATFORM_WINDOWS)