1 //===-- FileSystem.cpp ------------------------------------------*- 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 #include "lldb/Host/windows/windows.h" 11 12 #include <shellapi.h> 13 #include <sys/stat.h> 14 #include <sys/types.h> 15 16 #include "lldb/Host/FileSystem.h" 17 #include "lldb/Host/windows/AutoHandle.h" 18 19 #include "llvm/Support/ConvertUTF.h" 20 #include "llvm/Support/FileSystem.h" 21 22 using namespace lldb_private; 23 24 const char *FileSystem::DEV_NULL = "nul"; 25 26 const char *FileSystem::PATH_CONVERSION_ERROR = 27 "Error converting path between UTF-8 and native encoding"; 28 29 FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { 30 return FileSpec::ePathSyntaxWindows; 31 } 32 33 lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { 34 return file_spec.GetByteSize(); 35 } 36 37 bool FileSystem::GetFileExists(const FileSpec &file_spec) { 38 return file_spec.Exists(); 39 } 40 41 Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { 42 Error error; 43 std::wstring wsrc, wdst; 44 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || 45 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) 46 error.SetErrorString(PATH_CONVERSION_ERROR); 47 else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr)) 48 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 49 return error; 50 } 51 52 int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { 53 std::wstring path; 54 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) 55 return -1; 56 57 HANDLE file_handle = 58 ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 59 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 60 61 if (file_handle == INVALID_HANDLE_VALUE) 62 return -1; 63 64 AutoHandle auto_file_handle(file_handle); 65 BY_HANDLE_FILE_INFORMATION file_info; 66 if (::GetFileInformationByHandle(file_handle, &file_info)) 67 return file_info.nNumberOfLinks; 68 69 return -1; 70 } 71 72 Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { 73 Error error; 74 std::wstring wsrc, wdst; 75 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || 76 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) 77 error.SetErrorString(PATH_CONVERSION_ERROR); 78 if (error.Fail()) 79 return error; 80 DWORD attrib = ::GetFileAttributesW(wdst.c_str()); 81 if (attrib == INVALID_FILE_ATTRIBUTES) { 82 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 83 return error; 84 } 85 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 86 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 87 BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag); 88 if (!result) 89 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 90 return error; 91 } 92 93 Error FileSystem::Unlink(const FileSpec &file_spec) { 94 Error error; 95 std::wstring path; 96 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) { 97 error.SetErrorString(PATH_CONVERSION_ERROR); 98 return error; 99 } 100 BOOL result = ::DeleteFileW(path.c_str()); 101 if (!result) 102 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 103 return error; 104 } 105 106 Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { 107 Error error; 108 std::wstring wsrc; 109 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) { 110 error.SetErrorString(PATH_CONVERSION_ERROR); 111 return error; 112 } 113 114 HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, 115 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 116 OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); 117 if (h == INVALID_HANDLE_VALUE) { 118 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 119 return error; 120 } 121 122 std::vector<wchar_t> buf(PATH_MAX + 1); 123 // Subtract 1 from the path length since this function does not add a null 124 // terminator. 125 DWORD result = ::GetFinalPathNameByHandleW( 126 h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 127 std::string path; 128 if (result == 0) 129 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 130 else if (!llvm::convertWideToUTF8(buf.data(), path)) 131 error.SetErrorString(PATH_CONVERSION_ERROR); 132 else 133 dst.SetFile(path, false); 134 135 ::CloseHandle(h); 136 return error; 137 } 138 139 Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { 140 return Error("ResolveSymbolicLink() isn't implemented on Windows"); 141 } 142 143 bool FileSystem::IsLocal(const FileSpec &spec) { 144 if (spec) { 145 // TODO: return true if the file is on a locally mounted file system 146 return true; 147 } 148 149 return false; 150 } 151 152 FILE *FileSystem::Fopen(const char *path, const char *mode) { 153 std::wstring wpath, wmode; 154 if (!llvm::ConvertUTF8toWide(path, wpath)) 155 return nullptr; 156 if (!llvm::ConvertUTF8toWide(mode, wmode)) 157 return nullptr; 158 FILE *file; 159 if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0) 160 return nullptr; 161 return file; 162 } 163 164 int FileSystem::Stat(const char *path, struct stat *stats) { 165 std::wstring wpath; 166 if (!llvm::ConvertUTF8toWide(path, wpath)) { 167 errno = EINVAL; 168 return -EINVAL; 169 } 170 int stat_result; 171 #ifdef _USE_32BIT_TIME_T 172 struct _stat32 file_stats; 173 stat_result = ::_wstat32(wpath.c_str(), &file_stats); 174 #else 175 struct _stat64i32 file_stats; 176 stat_result = ::_wstat64i32(wpath.c_str(), &file_stats); 177 #endif 178 if (stat_result == 0) { 179 static_assert(sizeof(struct stat) == sizeof(file_stats), 180 "stat and _stat32/_stat64i32 must have the same layout"); 181 *stats = *reinterpret_cast<struct stat *>(&file_stats); 182 } 183 return stat_result; 184 } 185