1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 #if !defined(OS_WIN) && !defined(WIN32) && !defined(_WIN32)
11 #error Windows Specific Code
12 #endif
13 
14 #include "port/win/port_win.h"
15 
16 #include <io.h>
17 #include "port/port_dirent.h"
18 #include "port/sys_time.h"
19 
20 #include <cstdlib>
21 #include <stdio.h>
22 #include <assert.h>
23 #include <string.h>
24 
25 #include <memory>
26 #include <exception>
27 #include <chrono>
28 
29 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
30 // utf8 <-> utf16
31 #include <string>
32 #include <locale>
33 #include <codecvt>
34 #endif
35 
36 #include "logging/logging.h"
37 
38 namespace ROCKSDB_NAMESPACE {
39 
40 extern const bool kDefaultToAdaptiveMutex = false;
41 
42 namespace port {
43 
44 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
utf16_to_utf8(const std::wstring & utf16)45 std::string utf16_to_utf8(const std::wstring& utf16) {
46   std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> convert;
47   return convert.to_bytes(utf16);
48 }
49 
utf8_to_utf16(const std::string & utf8)50 std::wstring utf8_to_utf16(const std::string& utf8) {
51   std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
52   return converter.from_bytes(utf8);
53 }
54 #endif
55 
gettimeofday(struct timeval * tv,struct timezone *)56 void gettimeofday(struct timeval* tv, struct timezone* /* tz */) {
57   using namespace std::chrono;
58 
59   microseconds usNow(
60       duration_cast<microseconds>(system_clock::now().time_since_epoch()));
61 
62   seconds secNow(duration_cast<seconds>(usNow));
63 
64   tv->tv_sec = static_cast<long>(secNow.count());
65   tv->tv_usec = static_cast<long>(usNow.count() -
66       duration_cast<microseconds>(secNow).count());
67 }
68 
~Mutex()69 Mutex::~Mutex() {}
70 
~CondVar()71 CondVar::~CondVar() {}
72 
Wait()73 void CondVar::Wait() {
74   // Caller must ensure that mutex is held prior to calling this method
75   std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
76 #ifndef NDEBUG
77   mu_->locked_ = false;
78 #endif
79   cv_.wait(lk);
80 #ifndef NDEBUG
81   mu_->locked_ = true;
82 #endif
83   // Release ownership of the lock as we don't want it to be unlocked when
84   // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
85   lk.release();
86 }
87 
TimedWait(uint64_t abs_time_us)88 bool CondVar::TimedWait(uint64_t abs_time_us) {
89 
90   using namespace std::chrono;
91 
92   // MSVC++ library implements wait_until in terms of wait_for so
93   // we need to convert absolute wait into relative wait.
94   microseconds usAbsTime(abs_time_us);
95 
96   microseconds usNow(
97     duration_cast<microseconds>(system_clock::now().time_since_epoch()));
98   microseconds relTimeUs =
99     (usAbsTime > usNow) ? (usAbsTime - usNow) : microseconds::zero();
100 
101   // Caller must ensure that mutex is held prior to calling this method
102   std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
103 #ifndef NDEBUG
104   mu_->locked_ = false;
105 #endif
106   std::cv_status cvStatus = cv_.wait_for(lk, relTimeUs);
107 #ifndef NDEBUG
108   mu_->locked_ = true;
109 #endif
110   // Release ownership of the lock as we don't want it to be unlocked when
111   // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
112   lk.release();
113 
114   if (cvStatus == std::cv_status::timeout) {
115     return true;
116   }
117 
118   return false;
119 }
120 
Signal()121 void CondVar::Signal() { cv_.notify_one(); }
122 
SignalAll()123 void CondVar::SignalAll() { cv_.notify_all(); }
124 
PhysicalCoreID()125 int PhysicalCoreID() { return GetCurrentProcessorNumber(); }
126 
InitOnce(OnceType * once,void (* initializer)())127 void InitOnce(OnceType* once, void (*initializer)()) {
128   std::call_once(once->flag_, initializer);
129 }
130 
131 // Private structure, exposed only by pointer
132 struct DIR {
133   HANDLE      handle_;
134   bool        firstread_;
135   RX_WIN32_FIND_DATA data_;
136   dirent entry_;
137 
DIRROCKSDB_NAMESPACE::port::DIR138   DIR() : handle_(INVALID_HANDLE_VALUE),
139     firstread_(true) {}
140 
141   DIR(const DIR&) = delete;
142   DIR& operator=(const DIR&) = delete;
143 
~DIRROCKSDB_NAMESPACE::port::DIR144   ~DIR() {
145     if (INVALID_HANDLE_VALUE != handle_) {
146       ::FindClose(handle_);
147     }
148   }
149 };
150 
opendir(const char * name)151 DIR* opendir(const char* name) {
152   if (!name || *name == 0) {
153     errno = ENOENT;
154     return nullptr;
155   }
156 
157   std::string pattern(name);
158   pattern.append("\\").append("*");
159 
160   std::unique_ptr<DIR> dir(new DIR);
161 
162   dir->handle_ =
163       RX_FindFirstFileEx(RX_FN(pattern).c_str(),
164                          FindExInfoBasic,  // Do not want alternative name
165                          &dir->data_, FindExSearchNameMatch,
166                          NULL,  // lpSearchFilter
167                          0);
168 
169   if (dir->handle_ == INVALID_HANDLE_VALUE) {
170     return nullptr;
171   }
172 
173   RX_FILESTRING x(dir->data_.cFileName, RX_FNLEN(dir->data_.cFileName));
174   strcpy_s(dir->entry_.d_name, sizeof(dir->entry_.d_name), FN_TO_RX(x).c_str());
175 
176   return dir.release();
177 }
178 
readdir(DIR * dirp)179 struct dirent* readdir(DIR* dirp) {
180   if (!dirp || dirp->handle_ == INVALID_HANDLE_VALUE) {
181     errno = EBADF;
182     return nullptr;
183   }
184 
185   if (dirp->firstread_) {
186     dirp->firstread_ = false;
187     return &dirp->entry_;
188   }
189 
190   auto ret = RX_FindNextFile(dirp->handle_, &dirp->data_);
191 
192   if (ret == 0) {
193     return nullptr;
194   }
195 
196   RX_FILESTRING x(dirp->data_.cFileName, RX_FNLEN(dirp->data_.cFileName));
197   strcpy_s(dirp->entry_.d_name, sizeof(dirp->entry_.d_name),
198            FN_TO_RX(x).c_str());
199 
200   return &dirp->entry_;
201 }
202 
closedir(DIR * dirp)203 int closedir(DIR* dirp) {
204   delete dirp;
205   return 0;
206 }
207 
truncate(const char * path,int64_t length)208 int truncate(const char* path, int64_t length) {
209   if (path == nullptr) {
210     errno = EFAULT;
211     return -1;
212   }
213   return ROCKSDB_NAMESPACE::port::Truncate(path, length);
214 }
215 
Truncate(std::string path,int64_t len)216 int Truncate(std::string path, int64_t len) {
217 
218   if (len < 0) {
219     errno = EINVAL;
220     return -1;
221   }
222 
223   HANDLE hFile =
224       RX_CreateFile(RX_FN(path).c_str(), GENERIC_READ | GENERIC_WRITE,
225                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
226                  NULL,           // Security attrs
227                  OPEN_EXISTING,  // Truncate existing file only
228                  FILE_ATTRIBUTE_NORMAL, NULL);
229 
230   if (INVALID_HANDLE_VALUE == hFile) {
231     auto lastError = GetLastError();
232     if (lastError == ERROR_FILE_NOT_FOUND) {
233       errno = ENOENT;
234     } else if (lastError == ERROR_ACCESS_DENIED) {
235       errno = EACCES;
236     } else {
237       errno = EIO;
238     }
239     return -1;
240   }
241 
242   int result = 0;
243   FILE_END_OF_FILE_INFO end_of_file;
244   end_of_file.EndOfFile.QuadPart = len;
245 
246   if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file,
247                                   sizeof(FILE_END_OF_FILE_INFO))) {
248     errno = EIO;
249     result = -1;
250   }
251 
252   CloseHandle(hFile);
253   return result;
254 }
255 
Crash(const std::string & srcfile,int srcline)256 void Crash(const std::string& srcfile, int srcline) {
257   fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline);
258   fflush(stdout);
259   abort();
260 }
261 
GetMaxOpenFiles()262 int GetMaxOpenFiles() { return -1; }
263 
264 // Assume 4KB page size
265 const size_t kPageSize = 4U * 1024U;
266 
SetCpuPriority(ThreadId id,CpuPriority priority)267 void SetCpuPriority(ThreadId id, CpuPriority priority) {
268   // Not supported
269   (void)id;
270   (void)priority;
271 }
272 
273 }  // namespace port
274 }  // namespace ROCKSDB_NAMESPACE
275