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 #include "llvm/Support/FileSystem.h" 19 20 using namespace lldb_private; 21 22 const char * 23 FileSystem::DEV_NULL = "nul"; 24 25 FileSpec::PathSyntax 26 FileSystem::GetNativePathSyntax() 27 { 28 return FileSpec::ePathSyntaxWindows; 29 } 30 31 Error 32 FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) 33 { 34 // On Win32, the mode parameter is ignored, as Windows files and directories support a 35 // different permission model than POSIX. 36 Error error; 37 const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true); 38 if (err_code) 39 { 40 error.SetErrorString(err_code.message().c_str()); 41 } 42 43 return error; 44 } 45 46 Error 47 FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) 48 { 49 Error error; 50 if (!recurse) 51 { 52 BOOL result = ::RemoveDirectory(file_spec.GetCString()); 53 if (!result) 54 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 55 } 56 else 57 { 58 // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to 59 // indicate the end of the list. 60 std::string path_buffer{file_spec.GetPath()}; 61 path_buffer.push_back(0); 62 63 SHFILEOPSTRUCT shfos = {0}; 64 shfos.wFunc = FO_DELETE; 65 shfos.pFrom = path_buffer.c_str(); 66 shfos.fFlags = FOF_NO_UI; 67 68 int result = ::SHFileOperation(&shfos); 69 // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values. 70 if (result != 0) 71 error.SetErrorStringWithFormat("SHFileOperation failed"); 72 } 73 return error; 74 } 75 76 Error 77 FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) 78 { 79 Error error; 80 // Beware that Windows's permission model is different from Unix's, and it's 81 // not clear if this API is supposed to check ACLs. To match the caller's 82 // expectations as closely as possible, we'll use Microsoft's _stat, which 83 // attempts to emulate POSIX stat. This should be good enough for basic 84 // checks like FileSpec::Readable. 85 struct _stat file_stats; 86 if (::_stat(file_spec.GetCString(), &file_stats) == 0) 87 { 88 // The owner permission bits in "st_mode" currently match the definitions 89 // for the owner file mode bits. 90 file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC); 91 } 92 else 93 { 94 error.SetErrorToErrno(); 95 } 96 97 return error; 98 } 99 100 Error 101 FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) 102 { 103 Error error; 104 error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); 105 return error; 106 } 107 108 lldb::user_id_t 109 FileSystem::GetFileSize(const FileSpec &file_spec) 110 { 111 return file_spec.GetByteSize(); 112 } 113 114 bool 115 FileSystem::GetFileExists(const FileSpec &file_spec) 116 { 117 return file_spec.Exists(); 118 } 119 120 Error 121 FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) 122 { 123 Error error; 124 if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr)) 125 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 126 return error; 127 } 128 129 int 130 FileSystem::GetHardlinkCount(const FileSpec &file_spec) 131 { 132 HANDLE file_handle = ::CreateFile(file_spec.GetCString(), 133 FILE_READ_ATTRIBUTES, 134 FILE_SHARE_READ, 135 nullptr, 136 OPEN_EXISTING, 137 FILE_ATTRIBUTE_NORMAL, 138 nullptr); 139 140 if (file_handle == INVALID_HANDLE_VALUE) 141 return -1; 142 143 AutoHandle auto_file_handle(file_handle); 144 BY_HANDLE_FILE_INFORMATION file_info; 145 if (::GetFileInformationByHandle(file_handle, &file_info)) 146 return file_info.nNumberOfLinks; 147 148 return -1; 149 } 150 151 Error 152 FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) 153 { 154 Error error; 155 DWORD attrib = ::GetFileAttributes(dst.GetCString()); 156 if (attrib == INVALID_FILE_ATTRIBUTES) 157 { 158 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 159 return error; 160 } 161 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 162 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 163 BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag); 164 if (!result) 165 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 166 return error; 167 } 168 169 Error 170 FileSystem::Unlink(const FileSpec &file_spec) 171 { 172 Error error; 173 BOOL result = ::DeleteFile(file_spec.GetCString()); 174 if (!result) 175 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 176 return error; 177 } 178 179 Error 180 FileSystem::Readlink(const FileSpec &src, FileSpec &dst) 181 { 182 Error error; 183 HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ, 184 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 185 FILE_FLAG_OPEN_REPARSE_POINT, NULL); 186 if (h == INVALID_HANDLE_VALUE) 187 { 188 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 189 return error; 190 } 191 192 char buf[PATH_MAX]; 193 // Subtract 1 from the path length since this function does not add a null terminator. 194 DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1, 195 FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 196 if (result == 0) 197 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 198 else 199 dst.SetFile(buf, false); 200 201 ::CloseHandle(h); 202 return error; 203 } 204 205 Error 206 FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) 207 { 208 return Error("ResolveSymbolicLink() isn't implemented on Windows"); 209 } 210 211 bool 212 FileSystem::IsLocal(const FileSpec &spec) 213 { 214 if (spec) 215 { 216 // TODO: return true if the file is on a locally mounted file system 217 return true; 218 } 219 220 return false; 221 } 222