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