@@ -387,8 +387,9 @@ class WindowsEnv : public Env {
387387 *result = nullptr ;
388388 DWORD desired_access = GENERIC_READ;
389389 DWORD share_mode = FILE_SHARE_READ;
390- ScopedHandle handle = ::CreateFileA (
391- filename.c_str (), desired_access, share_mode,
390+ auto wFilename = toUtf16 (filename);
391+ ScopedHandle handle = ::CreateFileW (
392+ wFilename.c_str (), desired_access, share_mode,
392393 /* lpSecurityAttributes=*/ nullptr , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
393394 /* hTemplateFile=*/ nullptr );
394395 if (!handle.is_valid ()) {
@@ -404,8 +405,9 @@ class WindowsEnv : public Env {
404405 *result = nullptr ;
405406 DWORD desired_access = GENERIC_READ;
406407 DWORD share_mode = FILE_SHARE_READ;
408+ auto wFilename = toUtf16 (filename);
407409 ScopedHandle handle =
408- ::CreateFileA (filename .c_str(), desired_access, share_mode,
410+ ::CreateFileW (wFilename .c_str(), desired_access, share_mode,
409411 /* lpSecurityAttributes=*/ nullptr, OPEN_EXISTING,
410412 FILE_ATTRIBUTE_READONLY,
411413 /* hTemplateFile=*/ nullptr);
@@ -425,7 +427,7 @@ class WindowsEnv : public Env {
425427 }
426428
427429 ScopedHandle mapping =
428- ::CreateFileMappingA (handle.get(),
430+ ::CreateFileMappingW (handle.get(),
429431 /* security attributes=*/ nullptr, PAGE_READONLY,
430432 /* dwMaximumSizeHigh=*/ 0,
431433 /* dwMaximumSizeLow=*/ 0,
@@ -450,8 +452,9 @@ class WindowsEnv : public Env {
450452 WritableFile** result) override {
451453 DWORD desired_access = GENERIC_WRITE;
452454 DWORD share_mode = 0 ; // Exclusive access.
453- ScopedHandle handle = ::CreateFileA (
454- filename.c_str (), desired_access, share_mode,
455+ auto wFilename = toUtf16 (filename);
456+ ScopedHandle handle = ::CreateFileW (
457+ wFilename.c_str (), desired_access, share_mode,
455458 /* lpSecurityAttributes=*/ nullptr , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
456459 /* hTemplateFile=*/ nullptr );
457460 if (!handle.is_valid ()) {
@@ -467,8 +470,9 @@ class WindowsEnv : public Env {
467470 WritableFile** result) override {
468471 DWORD desired_access = FILE_APPEND_DATA;
469472 DWORD share_mode = 0 ; // Exclusive access.
470- ScopedHandle handle = ::CreateFileA (
471- filename.c_str (), desired_access, share_mode,
473+ auto wFilename = toUtf16 (filename);
474+ ScopedHandle handle = ::CreateFileW (
475+ wFilename.c_str (), desired_access, share_mode,
472476 /* lpSecurityAttributes=*/ nullptr , OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
473477 /* hTemplateFile=*/ nullptr );
474478 if (!handle.is_valid ()) {
@@ -481,14 +485,16 @@ class WindowsEnv : public Env {
481485 }
482486
483487 bool FileExists (const std::string& filename) override {
484- return GetFileAttributesA (filename.c_str ()) != INVALID_FILE_ATTRIBUTES;
488+ auto wFilename = toUtf16 (filename);
489+ return GetFileAttributesW (wFilename.c_str ()) != INVALID_FILE_ATTRIBUTES;
485490 }
486491
487492 Status GetChildren (const std::string& directory_path,
488493 std::vector<std::string>* result) override {
489494 const std::string find_pattern = directory_path + " \\ *" ;
490- WIN32_FIND_DATAA find_data;
491- HANDLE dir_handle = ::FindFirstFileA (find_pattern.c_str (), &find_data);
495+ WIN32_FIND_DATAW find_data;
496+ auto wFind_pattern = toUtf16 (find_pattern);
497+ HANDLE dir_handle = ::FindFirstFileW (wFind_pattern.c_str (), &find_data);
492498 if (dir_handle == INVALID_HANDLE_VALUE) {
493499 DWORD last_error = ::GetLastError ();
494500 if (last_error == ERROR_FILE_NOT_FOUND) {
@@ -500,11 +506,12 @@ class WindowsEnv : public Env {
500506 char base_name[_MAX_FNAME];
501507 char ext[_MAX_EXT];
502508
503- if (!_splitpath_s (find_data.cFileName , nullptr , 0 , nullptr , 0 , base_name,
504- ARRAYSIZE (base_name), ext, ARRAYSIZE (ext))) {
509+ auto find_data_filename = toUtf8 (find_data.cFileName );
510+ if (!_splitpath_s (find_data_filename.c_str (), nullptr , 0 , nullptr , 0 ,
511+ base_name, ARRAYSIZE (base_name), ext, ARRAYSIZE (ext))) {
505512 result->emplace_back (std::string (base_name) + ext);
506513 }
507- } while (::FindNextFileA (dir_handle, &find_data));
514+ } while (::FindNextFileW (dir_handle, &find_data));
508515 DWORD last_error = ::GetLastError ();
509516 ::FindClose (dir_handle);
510517 if (last_error != ERROR_NO_MORE_FILES) {
@@ -514,29 +521,33 @@ class WindowsEnv : public Env {
514521 }
515522
516523 Status DeleteFile (const std::string& filename) override {
517- if (!::DeleteFileA (filename.c_str ())) {
524+ auto wFilename = toUtf16 (filename);
525+ if (!::DeleteFileW (wFilename.c_str ())) {
518526 return WindowsError (filename, ::GetLastError ());
519527 }
520528 return Status::OK ();
521529 }
522530
523531 Status CreateDir (const std::string& dirname) override {
524- if (!::CreateDirectoryA (dirname.c_str (), nullptr )) {
532+ auto wDirname = toUtf16 (dirname);
533+ if (!::CreateDirectoryW (wDirname.c_str (), nullptr )) {
525534 return WindowsError (dirname, ::GetLastError ());
526535 }
527536 return Status::OK ();
528537 }
529538
530539 Status DeleteDir (const std::string& dirname) override {
531- if (!::RemoveDirectoryA (dirname.c_str ())) {
540+ auto wDirname = toUtf16 (dirname);
541+ if (!::RemoveDirectoryW (wDirname.c_str ())) {
532542 return WindowsError (dirname, ::GetLastError ());
533543 }
534544 return Status::OK ();
535545 }
536546
537547 Status GetFileSize (const std::string& filename, uint64_t * size) override {
538548 WIN32_FILE_ATTRIBUTE_DATA file_attributes;
539- if (!::GetFileAttributesExA (filename.c_str (), GetFileExInfoStandard,
549+ auto wFilename = toUtf16 (filename);
550+ if (!::GetFileAttributesExW (wFilename.c_str (), GetFileExInfoStandard,
540551 &file_attributes)) {
541552 return WindowsError (filename, ::GetLastError ());
542553 }
@@ -550,7 +561,9 @@ class WindowsEnv : public Env {
550561 Status RenameFile (const std::string& from, const std::string& to) override {
551562 // Try a simple move first. It will only succeed when |to| doesn't already
552563 // exist.
553- if (::MoveFileA (from.c_str (), to.c_str ())) {
564+ auto wFrom = toUtf16 (from);
565+ auto wTo = toUtf16 (to);
566+ if (::MoveFileW (wFrom.c_str (), wTo.c_str ())) {
554567 return Status::OK ();
555568 }
556569 DWORD move_error = ::GetLastError ();
@@ -559,7 +572,7 @@ class WindowsEnv : public Env {
559572 // succeed when |to| does exist. When writing to a network share, we may not
560573 // be able to change the ACLs. Ignore ACL errors then
561574 // (REPLACEFILE_IGNORE_MERGE_ERRORS).
562- if (::ReplaceFileA (to .c_str (), from .c_str (), /* lpBackupFileName=*/ nullptr ,
575+ if (::ReplaceFileW (wTo .c_str (), wFrom .c_str (), /* lpBackupFileName=*/ nullptr ,
563576 REPLACEFILE_IGNORE_MERGE_ERRORS,
564577 /* lpExclude=*/ nullptr , /* lpReserved=*/ nullptr )) {
565578 return Status::OK ();
@@ -579,8 +592,9 @@ class WindowsEnv : public Env {
579592 Status LockFile (const std::string& filename, FileLock** lock) override {
580593 *lock = nullptr ;
581594 Status result;
582- ScopedHandle handle = ::CreateFileA (
583- filename.c_str (), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
595+ auto wFilename = toUtf16 (filename);
596+ ScopedHandle handle = ::CreateFileW (
597+ wFilename.c_str (), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
584598 /* lpSecurityAttributes=*/ nullptr , OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
585599 nullptr );
586600 if (!handle.is_valid ()) {
@@ -620,10 +634,11 @@ class WindowsEnv : public Env {
620634 return Status::OK ();
621635 }
622636
623- char tmp_path [MAX_PATH];
624- if (!GetTempPathA (ARRAYSIZE (tmp_path ), tmp_path )) {
637+ wchar_t wtmp_path [MAX_PATH];
638+ if (!GetTempPathW (ARRAYSIZE (wtmp_path ), wtmp_path )) {
625639 return WindowsError (" GetTempPath" , ::GetLastError ());
626640 }
641+ std::string tmp_path = toUtf8 (std::wstring (wtmp_path));
627642 std::stringstream ss;
628643 ss << tmp_path << " leveldbtest-" << std::this_thread::get_id ();
629644 *result = ss.str ();
@@ -634,7 +649,8 @@ class WindowsEnv : public Env {
634649 }
635650
636651 Status NewLogger (const std::string& filename, Logger** result) override {
637- std::FILE* fp = std::fopen (filename.c_str (), " w" );
652+ auto wFilename = toUtf16 (filename);
653+ std::FILE* fp = _wfopen (wFilename.c_str (), L" w" );
638654 if (fp == nullptr ) {
639655 *result = nullptr ;
640656 return WindowsError (filename, ::GetLastError ());
@@ -690,6 +706,31 @@ class WindowsEnv : public Env {
690706 GUARDED_BY (background_work_mutex_);
691707
692708 Limiter mmap_limiter_; // Thread-safe.
709+
710+ // Converts a Windows wide multi-byte UTF-16 string to a UTF-8 string.
711+ // See http://utf8everywhere.org/#windows
712+ std::string toUtf8 (const std::wstring& wstr) {
713+ if (wstr.empty ()) return std::string ();
714+ int size_needed = WideCharToMultiByte (
715+ CP_UTF8, 0 , &wstr[0 ], (int )wstr.size (), NULL , 0 , NULL , NULL );
716+ std::string strTo (size_needed, 0 );
717+ WideCharToMultiByte (CP_UTF8, 0 , &wstr[0 ], (int )wstr.size (), &strTo[0 ],
718+ size_needed, NULL , NULL );
719+ return strTo;
720+ }
721+
722+ // Converts a UTF-8 string to a Windows UTF-16 multi-byte wide character
723+ // string.
724+ // See http://utf8everywhere.org/#windows
725+ std::wstring toUtf16 (const std::string& str) {
726+ if (str.empty ()) return std::wstring ();
727+ int size_needed =
728+ MultiByteToWideChar (CP_UTF8, 0 , &str[0 ], (int )str.size (), NULL , 0 );
729+ std::wstring strTo (size_needed, 0 );
730+ MultiByteToWideChar (CP_UTF8, 0 , &str[0 ], (int )str.size (), &strTo[0 ],
731+ size_needed);
732+ return strTo;
733+ }
693734};
694735
695736// Return the maximum number of concurrent mmaps.
0 commit comments