Support: Move c_str from SmallVector back to SmallString and add a free standing
[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 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 windows_error(::GetLastError());
62
63     // Make utf16 null terminated.
64     utf16.push_back(0);
65     utf16.pop_back();
66
67     return 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 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 windows_error(::GetLastError());
92
93     // Make utf8 null terminated.
94     utf8.push_back(0);
95     utf8.pop_back();
96
97     return 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 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 success;
114   }
115
116   // Forwarder for ScopedHandle.
117   BOOL WINAPI CryptReleaseContext(HCRYPTPROV Provider) {
118     return ::CryptReleaseContext(Provider, 0);
119   }
120
121   typedef ScopedHandle<HCRYPTPROV, uintptr_t(-1),
122                        BOOL (WINAPI*)(HCRYPTPROV), CryptReleaseContext>
123     ScopedCryptContext;
124   bool is_separator(const wchar_t value) {
125     switch (value) {
126     case L'\\':
127     case L'/':
128       return true;
129     default:
130       return false;
131     }
132   }
133 }
134
135 namespace llvm {
136 namespace sys  {
137 namespace fs {
138
139 error_code current_path(SmallVectorImpl<char> &result) {
140   SmallVector<wchar_t, 128> cur_path;
141   cur_path.reserve(128);
142 retry_cur_dir:
143   DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
144
145   // A zero return value indicates a failure other than insufficient space.
146   if (len == 0)
147     return windows_error(::GetLastError());
148
149   // If there's insufficient space, the len returned is larger than the len
150   // given.
151   if (len > cur_path.capacity()) {
152     cur_path.reserve(len);
153     goto retry_cur_dir;
154   }
155
156   cur_path.set_size(len);
157   // cur_path now holds the current directory in utf-16. Convert to utf-8.
158
159   // Find out how much space we need. Sadly, this function doesn't return the
160   // size needed unless you tell it the result size is 0, which means you
161   // _always_ have to call it twice.
162   len = ::WideCharToMultiByte(CP_UTF8, 0,
163                               cur_path.data(), cur_path.size(),
164                               result.data(), 0,
165                               NULL, NULL);
166
167   if (len == 0)
168     return make_error_code(windows_error(::GetLastError()));
169
170   result.reserve(len);
171   result.set_size(len);
172   // Now do the actual conversion.
173   len = ::WideCharToMultiByte(CP_UTF8, 0,
174                               cur_path.data(), cur_path.size(),
175                               result.data(), result.size(),
176                               NULL, NULL);
177   if (len == 0)
178     return windows_error(::GetLastError());
179
180   return success;
181 }
182
183 error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
184   // Get arguments.
185   SmallString<128> from_storage;
186   SmallString<128> to_storage;
187   StringRef f = from.toStringRef(from_storage);
188   StringRef t = to.toStringRef(to_storage);
189
190   // Convert to utf-16.
191   SmallVector<wchar_t, 128> wide_from;
192   SmallVector<wchar_t, 128> wide_to;
193   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
194   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
195
196   // Copy the file.
197   BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(),
198                          copt != copy_option::overwrite_if_exists);
199
200   if (res == 0)
201     return windows_error(::GetLastError());
202
203   return success;
204 }
205
206 error_code create_directory(const Twine &path, bool &existed) {
207   SmallString<128> path_storage;
208   SmallVector<wchar_t, 128> path_utf16;
209
210   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
211                                   path_utf16))
212     return ec;
213
214   if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
215     error_code ec = windows_error(::GetLastError());
216     if (ec == windows_error::already_exists)
217       existed = true;
218     else
219       return ec;
220   } else
221     existed = false;
222
223   return success;
224 }
225
226 error_code create_hard_link(const Twine &to, const Twine &from) {
227   // Get arguments.
228   SmallString<128> from_storage;
229   SmallString<128> to_storage;
230   StringRef f = from.toStringRef(from_storage);
231   StringRef t = to.toStringRef(to_storage);
232
233   // Convert to utf-16.
234   SmallVector<wchar_t, 128> wide_from;
235   SmallVector<wchar_t, 128> wide_to;
236   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
237   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
238
239   if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
240     return windows_error(::GetLastError());
241
242   return success;
243 }
244
245 error_code create_symlink(const Twine &to, const Twine &from) {
246   // Only do it if the function is available at runtime.
247   if (!create_symbolic_link_api)
248     return make_error_code(errc::function_not_supported);
249
250   // Get arguments.
251   SmallString<128> from_storage;
252   SmallString<128> to_storage;
253   StringRef f = from.toStringRef(from_storage);
254   StringRef t = to.toStringRef(to_storage);
255
256   // Convert to utf-16.
257   SmallVector<wchar_t, 128> wide_from;
258   SmallVector<wchar_t, 128> wide_to;
259   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
260   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
261
262   if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
263     return windows_error(::GetLastError());
264
265   return success;
266 }
267
268 error_code remove(const Twine &path, bool &existed) {
269   SmallString<128> path_storage;
270   SmallVector<wchar_t, 128> path_utf16;
271
272   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
273                                   path_utf16))
274     return ec;
275
276   if (!::DeleteFileW(path_utf16.begin())) {
277     error_code ec = windows_error(::GetLastError());
278     if (ec != windows_error::file_not_found)
279       return ec;
280     existed = false;
281   } else
282     existed = true;
283
284   return success;
285 }
286
287 error_code rename(const Twine &from, const Twine &to) {
288   // Get arguments.
289   SmallString<128> from_storage;
290   SmallString<128> to_storage;
291   StringRef f = from.toStringRef(from_storage);
292   StringRef t = to.toStringRef(to_storage);
293
294   // Convert to utf-16.
295   SmallVector<wchar_t, 128> wide_from;
296   SmallVector<wchar_t, 128> wide_to;
297   if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
298   if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
299
300   if (!::MoveFileW(wide_from.begin(), wide_to.begin()))
301     return windows_error(::GetLastError());
302
303   return success;
304 }
305
306 error_code resize_file(const Twine &path, uint64_t size) {
307   SmallString<128> path_storage;
308   SmallVector<wchar_t, 128> path_utf16;
309
310   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
311                                   path_utf16))
312     return ec;
313
314   int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE);
315   if (fd == -1)
316     return error_code(errno, generic_category());
317 #ifdef HAVE__CHSIZE_S
318   errno_t error = ::_chsize_s(fd, size);
319 #else
320   errno_t error = ::_chsize(fd, size);
321 #endif
322   ::close(fd);
323   return error_code(error, generic_category());
324 }
325
326 error_code exists(const Twine &path, bool &result) {
327   SmallString<128> path_storage;
328   SmallVector<wchar_t, 128> path_utf16;
329
330   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
331                                   path_utf16))
332     return ec;
333
334   DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
335
336   if (attributes == INVALID_FILE_ATTRIBUTES) {
337     // See if the file didn't actually exist.
338     error_code ec = make_error_code(windows_error(::GetLastError()));
339     if (ec != windows_error::file_not_found &&
340         ec != windows_error::path_not_found)
341       return ec;
342     result = false;
343   } else
344     result = true;
345   return success;
346 }
347
348 error_code equivalent(const Twine &A, const Twine &B, bool &result) {
349   // Get arguments.
350   SmallString<128> a_storage;
351   SmallString<128> b_storage;
352   StringRef a = A.toStringRef(a_storage);
353   StringRef b = B.toStringRef(b_storage);
354
355   // Convert to utf-16.
356   SmallVector<wchar_t, 128> wide_a;
357   SmallVector<wchar_t, 128> wide_b;
358   if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec;
359   if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec;
360
361   AutoHandle HandleB(
362     ::CreateFileW(wide_b.begin(),
363                   0,
364                   FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
365                   0,
366                   OPEN_EXISTING,
367                   FILE_FLAG_BACKUP_SEMANTICS,
368                   0));
369
370   AutoHandle HandleA(
371     ::CreateFileW(wide_a.begin(),
372                   0,
373                   FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
374                   0,
375                   OPEN_EXISTING,
376                   FILE_FLAG_BACKUP_SEMANTICS,
377                   0));
378
379   // If both handles are invalid, it's an error.
380   if (HandleA == INVALID_HANDLE_VALUE &&
381       HandleB == INVALID_HANDLE_VALUE)
382     return windows_error(::GetLastError());
383
384   // If only one is invalid, it's false.
385   if (HandleA == INVALID_HANDLE_VALUE &&
386       HandleB == INVALID_HANDLE_VALUE) {
387     result = false;
388     return success;
389   }
390
391   // Get file information.
392   BY_HANDLE_FILE_INFORMATION InfoA, InfoB;
393   if (!::GetFileInformationByHandle(HandleA, &InfoA))
394     return windows_error(::GetLastError());
395   if (!::GetFileInformationByHandle(HandleB, &InfoB))
396     return windows_error(::GetLastError());
397
398   // See if it's all the same.
399   result =
400     InfoA.dwVolumeSerialNumber           == InfoB.dwVolumeSerialNumber &&
401     InfoA.nFileIndexHigh                 == InfoB.nFileIndexHigh &&
402     InfoA.nFileIndexLow                  == InfoB.nFileIndexLow &&
403     InfoA.nFileSizeHigh                  == InfoB.nFileSizeHigh &&
404     InfoA.nFileSizeLow                   == InfoB.nFileSizeLow &&
405     InfoA.ftLastWriteTime.dwLowDateTime  ==
406       InfoB.ftLastWriteTime.dwLowDateTime &&
407     InfoA.ftLastWriteTime.dwHighDateTime ==
408       InfoB.ftLastWriteTime.dwHighDateTime;
409
410   return success;
411 }
412
413 error_code file_size(const Twine &path, uint64_t &result) {
414   SmallString<128> path_storage;
415   SmallVector<wchar_t, 128> path_utf16;
416
417   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
418                                   path_utf16))
419     return ec;
420
421   WIN32_FILE_ATTRIBUTE_DATA FileData;
422   if (!::GetFileAttributesExW(path_utf16.begin(),
423                               ::GetFileExInfoStandard,
424                               &FileData))
425     return windows_error(::GetLastError());
426
427   result =
428     (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8))
429     + FileData.nFileSizeLow;
430
431   return success;
432 }
433
434 error_code status(const Twine &path, file_status &result) {
435   SmallString<128> path_storage;
436   SmallVector<wchar_t, 128> path_utf16;
437
438   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
439                                   path_utf16))
440     return ec;
441
442   DWORD attr = ::GetFileAttributesW(path_utf16.begin());
443   if (attr == INVALID_FILE_ATTRIBUTES)
444     goto handle_status_error;
445
446   // Handle reparse points.
447   if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
448     AutoHandle h(
449       ::CreateFileW(path_utf16.begin(),
450                     0, // Attributes only.
451                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
452                     NULL,
453                     OPEN_EXISTING,
454                     FILE_FLAG_BACKUP_SEMANTICS,
455                     0));
456     if (h == INVALID_HANDLE_VALUE)
457       goto handle_status_error;
458   }
459
460   if (attr & FILE_ATTRIBUTE_DIRECTORY)
461     result = file_status(file_type::directory_file);
462   else
463     result = file_status(file_type::regular_file);
464
465   return success;
466
467 handle_status_error:
468   error_code ec = windows_error(::GetLastError());
469   if (ec == windows_error::file_not_found ||
470       ec == windows_error::path_not_found)
471     result = file_status(file_type::file_not_found);
472   else if (ec == windows_error::sharing_violation)
473     result = file_status(file_type::type_unknown);
474   else {
475     result = file_status(file_type::status_error);
476     return ec;
477   }
478
479   return success;
480 }
481
482 error_code unique_file(const Twine &model, int &result_fd,
483                              SmallVectorImpl<char> &result_path) {
484   // Use result_path as temp storage.
485   result_path.set_size(0);
486   StringRef m = model.toStringRef(result_path);
487
488   SmallVector<wchar_t, 128> model_utf16;
489   if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
490
491   // Make model absolute by prepending a temp directory if it's not already.
492   bool absolute = path::is_absolute(m);
493
494   if (!absolute) {
495     SmallVector<wchar_t, 64> temp_dir;
496     if (error_code ec = TempDir(temp_dir)) return ec;
497     // Handle c: by removing it.
498     if (model_utf16.size() > 2 && model_utf16[1] == L':') {
499       model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
500     }
501     model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
502   }
503
504   // Replace '%' with random chars. From here on, DO NOT modify model. It may be
505   // needed if the randomly chosen path already exists.
506   SmallVector<wchar_t, 128> random_path_utf16;
507
508   // Get a Crypto Provider for CryptGenRandom.
509   HCRYPTPROV HCPC;
510   if (!::CryptAcquireContextW(&HCPC,
511                               NULL,
512                               NULL,
513                               PROV_RSA_FULL,
514                               0))
515     return windows_error(::GetLastError());
516   ScopedCryptContext CryptoProvider(HCPC);
517
518 retry_random_path:
519   random_path_utf16.set_size(0);
520   for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
521                                                 e = model_utf16.end();
522                                                 i != e; ++i) {
523     if (*i == L'%') {
524       BYTE val = 0;
525       if (!::CryptGenRandom(CryptoProvider, 1, &val))
526           return windows_error(::GetLastError());
527       random_path_utf16.push_back("0123456789abcdef"[val & 15]);
528     }
529     else
530       random_path_utf16.push_back(*i);
531   }
532   // Make random_path_utf16 null terminated.
533   random_path_utf16.push_back(0);
534   random_path_utf16.pop_back();
535
536   // Try to create + open the path.
537 retry_create_file:
538   HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
539                                         GENERIC_READ | GENERIC_WRITE,
540                                         FILE_SHARE_READ,
541                                         NULL,
542                                         // Return ERROR_FILE_EXISTS if the file
543                                         // already exists.
544                                         CREATE_NEW,
545                                         FILE_ATTRIBUTE_TEMPORARY,
546                                         NULL);
547   if (TempFileHandle == INVALID_HANDLE_VALUE) {
548     // If the file existed, try again, otherwise, error.
549     error_code ec = windows_error(::GetLastError());
550     if (ec == windows_error::file_exists)
551       goto retry_random_path;
552     // Check for non-existing parent directories.
553     if (ec == windows_error::path_not_found) {
554       // Create the directories using result_path as temp storage.
555       if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
556                                       random_path_utf16.size(), result_path))
557         return ec;
558       StringRef p(result_path.begin(), result_path.size());
559       SmallString<64> dir_to_create;
560       for (path::const_iterator i = path::begin(p),
561                                 e = --path::end(p); i != e; ++i) {
562         path::append(dir_to_create, *i);
563         bool Exists;
564         if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
565         if (!Exists) {
566           // If c: doesn't exist, bail.
567           if (i->endswith(":"))
568             return ec;
569
570           SmallVector<wchar_t, 64> dir_to_create_utf16;
571           if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
572             return ec;
573
574           // Create the directory.
575           if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
576             return windows_error(::GetLastError());
577         }
578       }
579       goto retry_create_file;
580     }
581     return ec;
582   }
583
584   // Set result_path to the utf-8 representation of the path.
585   if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
586                                   random_path_utf16.size(), result_path)) {
587     ::CloseHandle(TempFileHandle);
588     ::DeleteFileW(random_path_utf16.begin());
589     return ec;
590   }
591
592   // Convert the Windows API file handle into a C-runtime handle.
593   int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
594   if (fd == -1) {
595     ::CloseHandle(TempFileHandle);
596     ::DeleteFileW(random_path_utf16.begin());
597     // MSDN doesn't say anything about _open_osfhandle setting errno or
598     // GetLastError(), so just return invalid_handle.
599     return windows_error::invalid_handle;
600   }
601
602   result_fd = fd;
603   return success;
604 }
605
606 error_code directory_iterator_construct(directory_iterator& it,
607                                         const StringRef &path) {
608   SmallVector<wchar_t, 128> path_utf16;
609
610   if (error_code ec = UTF8ToUTF16(path,
611                                   path_utf16))
612     return ec;
613
614   // Convert path to the format that Windows is happy with.
615   if (path_utf16.size() > 0 &&
616       !is_separator(path_utf16[path.size() - 1]) &&
617       path_utf16[path.size() - 1] != L':') {
618     path_utf16.push_back(L'\\');
619     path_utf16.push_back(L'*');
620   } else {
621     path_utf16.push_back(L'*');
622   }
623
624   //  Get the first directory entry.
625   WIN32_FIND_DATAW FirstFind;
626   ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
627   if (!FindHandle)
628     return windows_error(::GetLastError());
629
630   // Construct the current directory entry.
631   SmallString<128> directory_entry_path_utf8;
632   if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
633                                   ::wcslen(FirstFind.cFileName),
634                                   directory_entry_path_utf8))
635     return ec;
636
637   it.IterationHandle = intptr_t(FindHandle.take());
638   it.CurrentEntry = directory_entry(path);
639   it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
640
641   return success;
642 }
643
644 error_code directory_iterator_destruct(directory_iterator& it) {
645   if (it.IterationHandle != 0)
646     // Closes the handle if it's valid.
647     ScopedFindHandle close(HANDLE(it.IterationHandle));
648   it.IterationHandle = 0;
649   it.CurrentEntry = directory_entry();
650   return success;
651 }
652
653 error_code directory_iterator_increment(directory_iterator& it) {
654   WIN32_FIND_DATAW FindData;
655   if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
656     error_code ec = windows_error(::GetLastError());
657     // Check for end.
658     if (ec == windows_error::no_more_files)
659       return directory_iterator_destruct(it);
660     return ec;
661   }
662
663   SmallString<128> directory_entry_path_utf8;
664   if (error_code ec = UTF16ToUTF8(FindData.cFileName,
665                                   ::wcslen(FindData.cFileName),
666                                   directory_entry_path_utf8))
667     return ec;
668
669   it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
670   return success;
671 }
672
673 } // end namespace fs
674 } // end namespace sys
675 } // end namespace llvm