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