1c00cf4a0SZachary Turner //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2c00cf4a0SZachary Turner //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c00cf4a0SZachary Turner //
7c00cf4a0SZachary Turner //===----------------------------------------------------------------------===//
8c00cf4a0SZachary Turner 
9c00cf4a0SZachary Turner #include "lldb/Host/windows/windows.h"
10c00cf4a0SZachary Turner 
11c00cf4a0SZachary Turner #include <shellapi.h>
12633594c2SAdrian McCarthy #include <sys/stat.h>
13633594c2SAdrian McCarthy #include <sys/types.h>
14c00cf4a0SZachary Turner 
15c00cf4a0SZachary Turner #include "lldb/Host/FileSystem.h"
162b38f33bSOleksiy Vyalov #include "lldb/Host/windows/AutoHandle.h"
178d48cd60SZachary Turner #include "lldb/Host/windows/PosixApi.h"
18190fadcdSZachary Turner 
19190fadcdSZachary Turner #include "llvm/Support/ConvertUTF.h"
20cc815568SOleksiy Vyalov #include "llvm/Support/FileSystem.h"
21c00cf4a0SZachary Turner 
22c00cf4a0SZachary Turner using namespace lldb_private;
23c00cf4a0SZachary Turner 
24b9c1b51eSKate Stone const char *FileSystem::DEV_NULL = "nul";
254eff2d31SZachary Turner 
26b9c1b51eSKate Stone const char *FileSystem::PATH_CONVERSION_ERROR =
27b9c1b51eSKate Stone     "Error converting path between UTF-8 and native encoding";
28190fadcdSZachary Turner 
2997206d57SZachary Turner Status FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) {
3097206d57SZachary Turner   Status error;
31190fadcdSZachary Turner   std::wstring wsrc, wdst;
32b9c1b51eSKate Stone   if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) ||
33b9c1b51eSKate Stone       !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
34190fadcdSZachary Turner     error.SetErrorString(PATH_CONVERSION_ERROR);
35190fadcdSZachary Turner   if (error.Fail())
36190fadcdSZachary Turner     return error;
37190fadcdSZachary Turner   DWORD attrib = ::GetFileAttributesW(wdst.c_str());
38b9c1b51eSKate Stone   if (attrib == INVALID_FILE_ATTRIBUTES) {
39c00cf4a0SZachary Turner     error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
40c00cf4a0SZachary Turner     return error;
41c00cf4a0SZachary Turner   }
42c00cf4a0SZachary Turner   bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
43c00cf4a0SZachary Turner   DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
44190fadcdSZachary Turner   BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag);
45c00cf4a0SZachary Turner   if (!result)
46c00cf4a0SZachary Turner     error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
47c00cf4a0SZachary Turner   return error;
48c00cf4a0SZachary Turner }
49c00cf4a0SZachary Turner 
5097206d57SZachary Turner Status FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
5197206d57SZachary Turner   Status error;
52190fadcdSZachary Turner   std::wstring wsrc;
53b9c1b51eSKate Stone   if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) {
54190fadcdSZachary Turner     error.SetErrorString(PATH_CONVERSION_ERROR);
55190fadcdSZachary Turner     return error;
56190fadcdSZachary Turner   }
57190fadcdSZachary Turner 
58b9c1b51eSKate Stone   HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ,
59b9c1b51eSKate Stone                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
60b9c1b51eSKate Stone                            OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
61b9c1b51eSKate Stone   if (h == INVALID_HANDLE_VALUE) {
62c00cf4a0SZachary Turner     error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
63c00cf4a0SZachary Turner     return error;
64c00cf4a0SZachary Turner   }
65c00cf4a0SZachary Turner 
66190fadcdSZachary Turner   std::vector<wchar_t> buf(PATH_MAX + 1);
67b9c1b51eSKate Stone   // Subtract 1 from the path length since this function does not add a null
68b9c1b51eSKate Stone   // terminator.
69b9c1b51eSKate Stone   DWORD result = ::GetFinalPathNameByHandleW(
70b9c1b51eSKate Stone       h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
71190fadcdSZachary Turner   std::string path;
72c00cf4a0SZachary Turner   if (result == 0)
73c00cf4a0SZachary Turner     error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
74190fadcdSZachary Turner   else if (!llvm::convertWideToUTF8(buf.data(), path))
75190fadcdSZachary Turner     error.SetErrorString(PATH_CONVERSION_ERROR);
76d3173f34SChaoren Lin   else
7754bb3161SAleksandr Urakov     dst.SetFile(path, FileSpec::Style::native);
78c00cf4a0SZachary Turner 
79c00cf4a0SZachary Turner   ::CloseHandle(h);
80c00cf4a0SZachary Turner   return error;
81c00cf4a0SZachary Turner }
82736888c8SGreg Clayton 
8397206d57SZachary Turner Status FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
8497206d57SZachary Turner   return Status("ResolveSymbolicLink() isn't implemented on Windows");
859077e9f8SSean Callanan }
869077e9f8SSean Callanan 
87b9c1b51eSKate Stone FILE *FileSystem::Fopen(const char *path, const char *mode) {
88190fadcdSZachary Turner   std::wstring wpath, wmode;
89190fadcdSZachary Turner   if (!llvm::ConvertUTF8toWide(path, wpath))
90190fadcdSZachary Turner     return nullptr;
91190fadcdSZachary Turner   if (!llvm::ConvertUTF8toWide(mode, wmode))
92190fadcdSZachary Turner     return nullptr;
93190fadcdSZachary Turner   FILE *file;
94190fadcdSZachary Turner   if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0)
95190fadcdSZachary Turner     return nullptr;
96190fadcdSZachary Turner   return file;
97190fadcdSZachary Turner }
98d7c2b798SJonas Devlieghere 
99d7c2b798SJonas Devlieghere int FileSystem::Open(const char *path, int flags, int mode) {
100d7c2b798SJonas Devlieghere   std::wstring wpath;
101d7c2b798SJonas Devlieghere   if (!llvm::ConvertUTF8toWide(path, wpath))
102d7c2b798SJonas Devlieghere     return -1;
103d7c2b798SJonas Devlieghere   int result;
104d7c2b798SJonas Devlieghere   ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode);
105d7c2b798SJonas Devlieghere   return result;
106d7c2b798SJonas Devlieghere }
107