Support/FileSystem: Fix MinGW build. It doesn't have _chsize_s.
[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, NULL,
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, NULL,
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, NULL,
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, NULL,
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(), NULL))
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 unique_file(const Twine &model, int &result_fd,
345                              SmallVectorImpl<char> &result_path) {
346   // Use result_path as temp storage.
347   result_path.set_size(0);
348   StringRef m = model.toStringRef(result_path);
349
350   SmallVector<wchar_t, 128> model_utf16;
351   if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
352
353   // Make model absolute by prepending a temp directory if it's not already.
354   bool absolute;
355   if (error_code ec = path::is_absolute(m, absolute)) return ec;
356
357   if (!absolute) {
358     SmallVector<wchar_t, 64> temp_dir;
359     if (error_code ec = TempDir(temp_dir)) return ec;
360     // Handle c: by removing it.
361     if (model_utf16.size() > 2 && model_utf16[1] == L':') {
362       model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
363     }
364     model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
365   }
366
367   // Replace '%' with random chars. From here on, DO NOT modify model. It may be
368   // needed if the randomly chosen path already exists.
369   SmallVector<wchar_t, 128> random_path_utf16;
370
371   // Get a Crypto Provider for CryptGenRandom.
372   AutoCryptoProvider CryptoProvider;
373   BOOL success = ::CryptAcquireContextW(&CryptoProvider.CryptoProvider,
374                                         NULL,
375                                         NULL,
376                                         PROV_RSA_FULL,
377                                         NULL);
378   if (!success)
379     return make_error_code(windows_error(::GetLastError()));
380
381 retry_random_path:
382   random_path_utf16.set_size(0);
383   for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
384                                                 e = model_utf16.end();
385                                                 i != e; ++i) {
386     if (*i == L'%') {
387       BYTE val = 0;
388       if (!::CryptGenRandom(CryptoProvider, 1, &val))
389           return make_error_code(windows_error(::GetLastError()));
390       random_path_utf16.push_back("0123456789abcdef"[val & 15]);
391     }
392     else
393       random_path_utf16.push_back(*i);
394   }
395   // Make random_path_utf16 null terminated.
396   random_path_utf16.push_back(0);
397   random_path_utf16.pop_back();
398
399   // Try to create + open the path.
400 retry_create_file:
401   HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
402                                         GENERIC_READ | GENERIC_WRITE,
403                                         FILE_SHARE_READ,
404                                         NULL,
405                                         // Return ERROR_FILE_EXISTS if the file
406                                         // already exists.
407                                         CREATE_NEW,
408                                         FILE_ATTRIBUTE_TEMPORARY,
409                                         NULL);
410   if (TempFileHandle == INVALID_HANDLE_VALUE) {
411     // If the file existed, try again, otherwise, error.
412     error_code ec = make_error_code(windows_error(::GetLastError()));
413     if (ec == error_code(windows_error::file_exists))
414       goto retry_random_path;
415     // Check for non-existing parent directories.
416     if (ec == error_code(windows_error::path_not_found)) {
417       // Create the directories using result_path as temp storage.
418       if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
419                                       random_path_utf16.size(), result_path))
420         return ec;
421       StringRef p(result_path.begin(), result_path.size());
422       SmallString<64> dir_to_create;
423       for (path::const_iterator i = path::begin(p),
424                                 e = --path::end(p); i != e; ++i) {
425         if (error_code ec = path::append(dir_to_create, *i)) return ec;
426         bool Exists;
427         if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
428         if (!Exists) {
429           // If c: doesn't exist, bail.
430           if (i->endswith(":"))
431             return ec;
432
433           SmallVector<wchar_t, 64> dir_to_create_utf16;
434           if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
435             return ec;
436
437           // Create the directory.
438           if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
439             return make_error_code(windows_error(::GetLastError()));
440         }
441       }
442       goto retry_create_file;
443     }
444     return ec;
445   }
446
447   // Set result_path to the utf-8 representation of the path.
448   if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
449                                   random_path_utf16.size(), result_path)) {
450     ::CloseHandle(TempFileHandle);
451     ::DeleteFileW(random_path_utf16.begin());
452     return ec;
453   }
454
455   // Convert the Windows API file handle into a C-runtime handle.
456   int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
457   if (fd == -1) {
458     ::CloseHandle(TempFileHandle);
459     ::DeleteFileW(random_path_utf16.begin());
460     // MSDN doesn't say anything about _open_osfhandle setting errno or
461     // GetLastError(), so just return invalid_handle.
462     return make_error_code(windows_error::invalid_handle);
463   }
464
465   result_fd = fd;
466   return make_error_code(errc::success);
467 }
468 } // end namespace fs
469 } // end namespace sys
470 } // end namespace llvm