a84783f96acbd19d1804cd4588b30c5073bfca91
[oota-llvm.git] / lib / Support / Windows / PathV2.inc
1 //===- llvm/Support/Win32/PathV2.cpp - Windows Path Impl --------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Windows specific implementation of the PathV2 API.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic Windows code that
16 //===          is guaranteed to work on *all* Windows variants.
17 //===----------------------------------------------------------------------===//
18
19 #include "Windows.h"
20 #include <WinCrypt.h>
21 #include <fcntl.h>
22 #include <io.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 // MinGW doesn't define this.
27 #ifndef _ERRNO_T_DEFINED
28 #define _ERRNO_T_DEFINED
29 typedef int errno_t;
30 #endif
31
32 using namespace llvm;
33
34 namespace {
35   typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
36     /*__in*/ LPCWSTR lpSymlinkFileName,
37     /*__in*/ LPCWSTR lpTargetFileName,
38     /*__in*/ DWORD dwFlags);
39
40   PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
41     ::GetProcAddress(::GetModuleHandleA("kernel32.dll"),
42                      "CreateSymbolicLinkW"));
43
44   error_code UTF8ToUTF16(const StringRef &utf8,
45                                SmallVectorImpl<wchar_t> &utf16) {
46     int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
47                                     utf8.begin(), utf8.size(),
48                                     utf16.begin(), 0);
49
50     if (len == 0)
51       return make_error_code(windows_error(::GetLastError()));
52
53     utf16.reserve(len + 1);
54     utf16.set_size(len);
55
56     len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
57                                     utf8.begin(), utf8.size(),
58                                     utf16.begin(), utf16.size());
59
60     if (len == 0)
61       return make_error_code(windows_error(::GetLastError()));
62
63     // Make utf16 null terminated.
64     utf16.push_back(0);
65     utf16.pop_back();
66
67     return make_error_code(errc::success);
68   }
69
70   error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
71                                SmallVectorImpl<char> &utf8) {
72     // Get length.
73     int len = ::WideCharToMultiByte(CP_UTF8, 0,
74                                     utf16, utf16_len,
75                                     utf8.begin(), 0,
76                                     NULL, NULL);
77
78     if (len == 0)
79       return make_error_code(windows_error(::GetLastError()));
80
81     utf8.reserve(len);
82     utf8.set_size(len);
83
84     // Now do the actual conversion.
85     len = ::WideCharToMultiByte(CP_UTF8, 0,
86                                 utf16, utf16_len,
87                                 utf8.data(), utf8.size(),
88                                 NULL, NULL);
89
90     if (len == 0)
91       return make_error_code(windows_error(::GetLastError()));
92
93     // Make utf8 null terminated.
94     utf8.push_back(0);
95     utf8.pop_back();
96
97     return make_error_code(errc::success);
98   }
99
100   error_code TempDir(SmallVectorImpl<wchar_t> &result) {
101   retry_temp_dir:
102     DWORD len = ::GetTempPathW(result.capacity(), result.begin());
103
104     if (len == 0)
105       return make_error_code(windows_error(::GetLastError()));
106
107     if (len > result.capacity()) {
108       result.reserve(len);
109       goto retry_temp_dir;
110     }
111
112     result.set_size(len);
113     return make_error_code(errc::success);
114   }
115
116   struct AutoCryptoProvider {
117     HCRYPTPROV CryptoProvider;
118
119     ~AutoCryptoProvider() {
120       ::CryptReleaseContext(CryptoProvider, 0);
121     }
122
123     operator HCRYPTPROV() const {return CryptoProvider;}
124   };
125 }
126
127 namespace llvm {
128 namespace sys  {
129 namespace path {
130
131 error_code current_path(SmallVectorImpl<char> &result) {
132   SmallVector<wchar_t, 128> cur_path;
133   cur_path.reserve(128);
134 retry_cur_dir:
135   DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
136
137   // A zero return value indicates a failure other than insufficient space.
138   if (len == 0)
139     return make_error_code(windows_error(::GetLastError()));
140
141   // If there's insufficient space, the len returned is larger than the len
142   // given.
143   if (len > cur_path.capacity()) {
144     cur_path.reserve(len);
145     goto retry_cur_dir;
146   }
147
148   cur_path.set_size(len);
149   // cur_path now holds the current directory in utf-16. Convert to utf-8.
150
151   // Find out how much space we need. Sadly, this function doesn't return the
152   // size needed unless you tell it the result size is 0, which means you
153   // _always_ have to call it twice.
154   len = ::WideCharToMultiByte(CP_UTF8, 0,
155                               cur_path.data(), cur_path.size(),
156                               result.data(), 0,
157                               NULL, NULL);
158
159   if (len == 0)
160     return make_error_code(windows_error(::GetLastError()));
161
162   result.reserve(len);
163   result.set_size(len);
164   // Now do the actual conversion.
165   len = ::WideCharToMultiByte(CP_UTF8, 0,
166                               cur_path.data(), cur_path.size(),
167                               result.data(), result.size(),
168                               NULL, NULL);
169   if (len == 0)
170     return make_error_code(windows_error(::GetLastError()));
171
172   return make_error_code(errc::success);
173 }
174
175 } // end namespace path
176
177 namespace fs {
178
179 error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
180   // Get arguments.
181   SmallString<128> from_storage;
182   SmallString<128> to_storage;
183   StringRef f = from.toStringRef(from_storage);
184   StringRef t = to.toStringRef(to_storage);
185
186   // Convert to utf-16.
187   SmallVector<wchar_t, 128> wide_from;
188   SmallVector<wchar_t, 128> wide_to;
189   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
190   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
191
192   // Copy the file.
193   BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(),
194                          copt != copy_option::overwrite_if_exists);
195
196   if (res == 0)
197     return make_error_code(windows_error(::GetLastError()));
198
199   return make_error_code(errc::success);
200 }
201
202 error_code create_directory(const Twine &path, bool &existed) {
203   SmallString<128> path_storage;
204   SmallVector<wchar_t, 128> path_utf16;
205
206   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
207                                   path_utf16))
208     return ec;
209
210   if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
211     error_code ec = make_error_code(windows_error(::GetLastError()));
212     if (ec == make_error_code(windows_error::already_exists))
213       existed = true;
214     else
215       return ec;
216   } else
217     existed = false;
218
219   return make_error_code(errc::success);
220 }
221
222 error_code create_hard_link(const Twine &to, const Twine &from) {
223   // Get arguments.
224   SmallString<128> from_storage;
225   SmallString<128> to_storage;
226   StringRef f = from.toStringRef(from_storage);
227   StringRef t = to.toStringRef(to_storage);
228
229   // Convert to utf-16.
230   SmallVector<wchar_t, 128> wide_from;
231   SmallVector<wchar_t, 128> wide_to;
232   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
233   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
234
235   if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
236     return make_error_code(windows_error(::GetLastError()));
237
238   return make_error_code(errc::success);
239 }
240
241 error_code create_symlink(const Twine &to, const Twine &from) {
242   // Only do it if the function is available at runtime.
243   if (!create_symbolic_link_api)
244     return make_error_code(errc::function_not_supported);
245
246   // Get arguments.
247   SmallString<128> from_storage;
248   SmallString<128> to_storage;
249   StringRef f = from.toStringRef(from_storage);
250   StringRef t = to.toStringRef(to_storage);
251
252   // Convert to utf-16.
253   SmallVector<wchar_t, 128> wide_from;
254   SmallVector<wchar_t, 128> wide_to;
255   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
256   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
257
258   if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
259     return make_error_code(windows_error(::GetLastError()));
260
261   return make_error_code(errc::success);
262 }
263
264 error_code remove(const Twine &path, bool &existed) {
265   SmallString<128> path_storage;
266   SmallVector<wchar_t, 128> path_utf16;
267
268   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
269                                   path_utf16))
270     return ec;
271
272   if (!::DeleteFileW(path_utf16.begin())) {
273     error_code ec = make_error_code(windows_error(::GetLastError()));
274     if (ec != make_error_code(windows_error::file_not_found))
275       return ec;
276     existed = false;
277   } else
278     existed = true;
279
280   return make_error_code(errc::success);
281 }
282
283 error_code rename(const Twine &from, const Twine &to) {
284   // Get arguments.
285   SmallString<128> from_storage;
286   SmallString<128> to_storage;
287   StringRef f = from.toStringRef(from_storage);
288   StringRef t = to.toStringRef(to_storage);
289
290   // Convert to utf-16.
291   SmallVector<wchar_t, 128> wide_from;
292   SmallVector<wchar_t, 128> wide_to;
293   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
294   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
295
296   if (!::MoveFileW(wide_from.begin(), wide_to.begin()))
297     return make_error_code(windows_error(::GetLastError()));
298
299   return make_error_code(errc::success);
300 }
301
302 error_code resize_file(const Twine &path, uint64_t size) {
303   SmallString<128> path_storage;
304   SmallVector<wchar_t, 128> path_utf16;
305
306   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
307                                   path_utf16))
308     return ec;
309
310   int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE);
311   if (fd == -1)
312     return error_code(errno, generic_category());
313 #ifdef HAVE__CHSIZE_S
314   errno_t error = ::_chsize_s(fd, size);
315 #else
316   errno_t error = ::_chsize(fd, size);
317 #endif
318   ::close(fd);
319   return error_code(error, generic_category());
320 }
321
322 error_code exists(const Twine &path, bool &result) {
323   SmallString<128> path_storage;
324   SmallVector<wchar_t, 128> path_utf16;
325
326   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
327                                   path_utf16))
328     return ec;
329
330   DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
331
332   if (attributes == INVALID_FILE_ATTRIBUTES) {
333     // See if the file didn't actually exist.
334     error_code ec = make_error_code(windows_error(::GetLastError()));
335     if (ec != error_code(windows_error::file_not_found) &&
336         ec != error_code(windows_error::path_not_found))
337       return ec;
338     result = false;
339   } else
340     result = true;
341   return make_error_code(errc::success);
342 }
343
344 error_code equivalent(const Twine &A, const Twine &B, bool &result) {
345   // Get arguments.
346   SmallString<128> a_storage;
347   SmallString<128> b_storage;
348   StringRef a = A.toStringRef(a_storage);
349   StringRef b = B.toStringRef(b_storage);
350
351   // Convert to utf-16.
352   SmallVector<wchar_t, 128> wide_a;
353   SmallVector<wchar_t, 128> wide_b;
354   if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec;
355   if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec;
356
357   AutoHandle HandleB(
358     ::CreateFileW(wide_b.begin(),
359                   0,
360                   FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
361                   0,
362                   OPEN_EXISTING,
363                   FILE_FLAG_BACKUP_SEMANTICS,
364                   0));
365
366   AutoHandle HandleA(
367     ::CreateFileW(wide_a.begin(),
368                   0,
369                   FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
370                   0,
371                   OPEN_EXISTING,
372                   FILE_FLAG_BACKUP_SEMANTICS,
373                   0));
374
375   // If both handles are invalid, it's an error.
376   if (HandleA == INVALID_HANDLE_VALUE &&
377       HandleB == INVALID_HANDLE_VALUE)
378     return make_error_code(windows_error(::GetLastError()));
379
380   // If only one is invalid, it's false.
381   if (HandleA == INVALID_HANDLE_VALUE &&
382       HandleB == INVALID_HANDLE_VALUE) {
383     result = false;
384     return make_error_code(errc::success);
385   }
386
387   // Get file information.
388   BY_HANDLE_FILE_INFORMATION InfoA, InfoB;
389   if (!::GetFileInformationByHandle(HandleA, &InfoA))
390     return make_error_code(windows_error(::GetLastError()));
391   if (!::GetFileInformationByHandle(HandleB, &InfoB))
392     return make_error_code(windows_error(::GetLastError()));
393
394   // See if it's all the same.
395   result =
396     InfoA.dwVolumeSerialNumber           == InfoB.dwVolumeSerialNumber &&
397     InfoA.nFileIndexHigh                 == InfoB.nFileIndexHigh &&
398     InfoA.nFileIndexLow                  == InfoB.nFileIndexLow &&
399     InfoA.nFileSizeHigh                  == InfoB.nFileSizeHigh &&
400     InfoA.nFileSizeLow                   == InfoB.nFileSizeLow &&
401     InfoA.ftLastWriteTime.dwLowDateTime  ==
402       InfoB.ftLastWriteTime.dwLowDateTime &&
403     InfoA.ftLastWriteTime.dwHighDateTime ==
404       InfoB.ftLastWriteTime.dwHighDateTime;
405
406   return make_error_code(errc::success);
407 }
408
409 error_code file_size(const Twine &path, uint64_t &result) {
410   SmallString<128> path_storage;
411   SmallVector<wchar_t, 128> path_utf16;
412
413   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
414                                   path_utf16))
415     return ec;
416
417   WIN32_FILE_ATTRIBUTE_DATA FileData;
418   if (!::GetFileAttributesExW(path_utf16.begin(),
419                               ::GetFileExInfoStandard,
420                               &FileData))
421     return make_error_code(windows_error(::GetLastError()));
422
423   result =
424     (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8))
425     + FileData.nFileSizeLow;
426
427   return make_error_code(errc::success);
428 }
429
430 error_code unique_file(const Twine &model, int &result_fd,
431                              SmallVectorImpl<char> &result_path) {
432   // Use result_path as temp storage.
433   result_path.set_size(0);
434   StringRef m = model.toStringRef(result_path);
435
436   SmallVector<wchar_t, 128> model_utf16;
437   if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
438
439   // Make model absolute by prepending a temp directory if it's not already.
440   bool absolute;
441   if (error_code ec = path::is_absolute(m, absolute)) return ec;
442
443   if (!absolute) {
444     SmallVector<wchar_t, 64> temp_dir;
445     if (error_code ec = TempDir(temp_dir)) return ec;
446     // Handle c: by removing it.
447     if (model_utf16.size() > 2 && model_utf16[1] == L':') {
448       model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
449     }
450     model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
451   }
452
453   // Replace '%' with random chars. From here on, DO NOT modify model. It may be
454   // needed if the randomly chosen path already exists.
455   SmallVector<wchar_t, 128> random_path_utf16;
456
457   // Get a Crypto Provider for CryptGenRandom.
458   AutoCryptoProvider CryptoProvider;
459   BOOL success = ::CryptAcquireContextW(&CryptoProvider.CryptoProvider,
460                                         NULL,
461                                         NULL,
462                                         PROV_RSA_FULL,
463                                         0);
464   if (!success)
465     return make_error_code(windows_error(::GetLastError()));
466
467 retry_random_path:
468   random_path_utf16.set_size(0);
469   for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
470                                                 e = model_utf16.end();
471                                                 i != e; ++i) {
472     if (*i == L'%') {
473       BYTE val = 0;
474       if (!::CryptGenRandom(CryptoProvider, 1, &val))
475           return make_error_code(windows_error(::GetLastError()));
476       random_path_utf16.push_back("0123456789abcdef"[val & 15]);
477     }
478     else
479       random_path_utf16.push_back(*i);
480   }
481   // Make random_path_utf16 null terminated.
482   random_path_utf16.push_back(0);
483   random_path_utf16.pop_back();
484
485   // Try to create + open the path.
486 retry_create_file:
487   HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
488                                         GENERIC_READ | GENERIC_WRITE,
489                                         FILE_SHARE_READ,
490                                         NULL,
491                                         // Return ERROR_FILE_EXISTS if the file
492                                         // already exists.
493                                         CREATE_NEW,
494                                         FILE_ATTRIBUTE_TEMPORARY,
495                                         NULL);
496   if (TempFileHandle == INVALID_HANDLE_VALUE) {
497     // If the file existed, try again, otherwise, error.
498     error_code ec = make_error_code(windows_error(::GetLastError()));
499     if (ec == error_code(windows_error::file_exists))
500       goto retry_random_path;
501     // Check for non-existing parent directories.
502     if (ec == error_code(windows_error::path_not_found)) {
503       // Create the directories using result_path as temp storage.
504       if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
505                                       random_path_utf16.size(), result_path))
506         return ec;
507       StringRef p(result_path.begin(), result_path.size());
508       SmallString<64> dir_to_create;
509       for (path::const_iterator i = path::begin(p),
510                                 e = --path::end(p); i != e; ++i) {
511         if (error_code ec = path::append(dir_to_create, *i)) return ec;
512         bool Exists;
513         if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
514         if (!Exists) {
515           // If c: doesn't exist, bail.
516           if (i->endswith(":"))
517             return ec;
518
519           SmallVector<wchar_t, 64> dir_to_create_utf16;
520           if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
521             return ec;
522
523           // Create the directory.
524           if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
525             return make_error_code(windows_error(::GetLastError()));
526         }
527       }
528       goto retry_create_file;
529     }
530     return ec;
531   }
532
533   // Set result_path to the utf-8 representation of the path.
534   if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
535                                   random_path_utf16.size(), result_path)) {
536     ::CloseHandle(TempFileHandle);
537     ::DeleteFileW(random_path_utf16.begin());
538     return ec;
539   }
540
541   // Convert the Windows API file handle into a C-runtime handle.
542   int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
543   if (fd == -1) {
544     ::CloseHandle(TempFileHandle);
545     ::DeleteFileW(random_path_utf16.begin());
546     // MSDN doesn't say anything about _open_osfhandle setting errno or
547     // GetLastError(), so just return invalid_handle.
548     return make_error_code(windows_error::invalid_handle);
549   }
550
551   result_fd = fd;
552   return make_error_code(errc::success);
553 }
554 } // end namespace fs
555 } // end namespace sys
556 } // end namespace llvm