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 Error FileSystem::MakeDirectory(const FileSpec &file_spec, 34 uint32_t file_permissions) { 35 // On Win32, the mode parameter is ignored, as Windows files and directories 36 // support a 37 // different permission model than POSIX. 38 Error error; 39 const auto err_code = 40 llvm::sys::fs::create_directories(file_spec.GetPath(), true); 41 if (err_code) { 42 error.SetErrorString(err_code.message().c_str()); 43 } 44 45 return error; 46 } 47 48 Error FileSystem::GetFilePermissions(const FileSpec &file_spec, 49 uint32_t &file_permissions) { 50 Error error; 51 // Beware that Windows's permission model is different from Unix's, and it's 52 // not clear if this API is supposed to check ACLs. To match the caller's 53 // expectations as closely as possible, we'll use Microsoft's _stat, which 54 // attempts to emulate POSIX stat. This should be good enough for basic 55 // checks like FileSpec::Readable. 56 struct _stat file_stats; 57 if (::_stat(file_spec.GetCString(), &file_stats) == 0) { 58 // The owner permission bits in "st_mode" currently match the definitions 59 // for the owner file mode bits. 60 file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC); 61 } else { 62 error.SetErrorToErrno(); 63 } 64 65 return error; 66 } 67 68 Error FileSystem::SetFilePermissions(const FileSpec &file_spec, 69 uint32_t file_permissions) { 70 Error error; 71 error.SetErrorStringWithFormat("%s is not supported on this host", 72 LLVM_PRETTY_FUNCTION); 73 return error; 74 } 75 76 lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { 77 return file_spec.GetByteSize(); 78 } 79 80 bool FileSystem::GetFileExists(const FileSpec &file_spec) { 81 return file_spec.Exists(); 82 } 83 84 Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { 85 Error error; 86 std::wstring wsrc, wdst; 87 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || 88 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) 89 error.SetErrorString(PATH_CONVERSION_ERROR); 90 else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr)) 91 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 92 return error; 93 } 94 95 int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { 96 std::wstring path; 97 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) 98 return -1; 99 100 HANDLE file_handle = 101 ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 102 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 103 104 if (file_handle == INVALID_HANDLE_VALUE) 105 return -1; 106 107 AutoHandle auto_file_handle(file_handle); 108 BY_HANDLE_FILE_INFORMATION file_info; 109 if (::GetFileInformationByHandle(file_handle, &file_info)) 110 return file_info.nNumberOfLinks; 111 112 return -1; 113 } 114 115 Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { 116 Error error; 117 std::wstring wsrc, wdst; 118 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || 119 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) 120 error.SetErrorString(PATH_CONVERSION_ERROR); 121 if (error.Fail()) 122 return error; 123 DWORD attrib = ::GetFileAttributesW(wdst.c_str()); 124 if (attrib == INVALID_FILE_ATTRIBUTES) { 125 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 126 return error; 127 } 128 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 129 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 130 BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag); 131 if (!result) 132 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 133 return error; 134 } 135 136 Error FileSystem::Unlink(const FileSpec &file_spec) { 137 Error error; 138 std::wstring path; 139 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) { 140 error.SetErrorString(PATH_CONVERSION_ERROR); 141 return error; 142 } 143 BOOL result = ::DeleteFileW(path.c_str()); 144 if (!result) 145 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 146 return error; 147 } 148 149 Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { 150 Error error; 151 std::wstring wsrc; 152 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) { 153 error.SetErrorString(PATH_CONVERSION_ERROR); 154 return error; 155 } 156 157 HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, 158 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 159 OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); 160 if (h == INVALID_HANDLE_VALUE) { 161 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 162 return error; 163 } 164 165 std::vector<wchar_t> buf(PATH_MAX + 1); 166 // Subtract 1 from the path length since this function does not add a null 167 // terminator. 168 DWORD result = ::GetFinalPathNameByHandleW( 169 h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 170 std::string path; 171 if (result == 0) 172 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 173 else if (!llvm::convertWideToUTF8(buf.data(), path)) 174 error.SetErrorString(PATH_CONVERSION_ERROR); 175 else 176 dst.SetFile(path, false); 177 178 ::CloseHandle(h); 179 return error; 180 } 181 182 Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { 183 return Error("ResolveSymbolicLink() isn't implemented on Windows"); 184 } 185 186 bool FileSystem::IsLocal(const FileSpec &spec) { 187 if (spec) { 188 // TODO: return true if the file is on a locally mounted file system 189 return true; 190 } 191 192 return false; 193 } 194 195 FILE *FileSystem::Fopen(const char *path, const char *mode) { 196 std::wstring wpath, wmode; 197 if (!llvm::ConvertUTF8toWide(path, wpath)) 198 return nullptr; 199 if (!llvm::ConvertUTF8toWide(mode, wmode)) 200 return nullptr; 201 FILE *file; 202 if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0) 203 return nullptr; 204 return file; 205 } 206 207 int FileSystem::Stat(const char *path, struct stat *stats) { 208 std::wstring wpath; 209 if (!llvm::ConvertUTF8toWide(path, wpath)) { 210 errno = EINVAL; 211 return -EINVAL; 212 } 213 int stat_result; 214 #ifdef _USE_32BIT_TIME_T 215 struct _stat32 file_stats; 216 stat_result = ::_wstat32(wpath.c_str(), &file_stats); 217 #else 218 struct _stat64i32 file_stats; 219 stat_result = ::_wstat64i32(wpath.c_str(), &file_stats); 220 #endif 221 if (stat_result == 0) { 222 static_assert(sizeof(struct stat) == sizeof(file_stats), 223 "stat and _stat32/_stat64i32 must have the same layout"); 224 *stats = *reinterpret_cast<struct stat *>(&file_stats); 225 } 226 return stat_result; 227 } 228