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 14 #include "lldb/Host/FileSystem.h" 15 #include "llvm/Support/FileSystem.h" 16 17 using namespace lldb_private; 18 19 FileSpec::PathSyntax 20 FileSystem::GetNativePathSyntax() 21 { 22 return FileSpec::ePathSyntaxWindows; 23 } 24 25 Error 26 FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) 27 { 28 // On Win32, the mode parameter is ignored, as Windows files and directories support a 29 // different permission model than POSIX. 30 Error error; 31 const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true); 32 if (err_code) 33 { 34 error.SetErrorString(err_code.message().c_str()); 35 } 36 37 return error; 38 } 39 40 Error 41 FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) 42 { 43 Error error; 44 if (!recurse) 45 { 46 BOOL result = ::RemoveDirectory(file_spec.GetCString()); 47 if (!result) 48 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 49 } 50 else 51 { 52 // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to 53 // indicate the end of the list. 54 std::string path_buffer{file_spec.GetPath()}; 55 path_buffer.push_back(0); 56 57 SHFILEOPSTRUCT shfos = {0}; 58 shfos.wFunc = FO_DELETE; 59 shfos.pFrom = path_buffer.c_str(); 60 shfos.fFlags = FOF_NO_UI; 61 62 int result = ::SHFileOperation(&shfos); 63 // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values. 64 if (result != 0) 65 error.SetErrorStringWithFormat("SHFileOperation failed"); 66 } 67 return error; 68 } 69 70 Error 71 FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) 72 { 73 Error error; 74 error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); 75 return error; 76 } 77 78 Error 79 FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) 80 { 81 Error error; 82 error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); 83 return error; 84 } 85 86 lldb::user_id_t 87 FileSystem::GetFileSize(const FileSpec &file_spec) 88 { 89 return file_spec.GetByteSize(); 90 } 91 92 bool 93 FileSystem::GetFileExists(const FileSpec &file_spec) 94 { 95 return file_spec.Exists(); 96 } 97 98 Error 99 FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) 100 { 101 Error error; 102 if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr)) 103 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 104 return error; 105 } 106 107 Error 108 FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) 109 { 110 Error error; 111 DWORD attrib = ::GetFileAttributes(dst.GetCString()); 112 if (attrib == INVALID_FILE_ATTRIBUTES) 113 { 114 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 115 return error; 116 } 117 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 118 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 119 BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag); 120 if (!result) 121 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 122 return error; 123 } 124 125 Error 126 FileSystem::Unlink(const FileSpec &file_spec) 127 { 128 Error error; 129 BOOL result = ::DeleteFile(file_spec.GetCString()); 130 if (!result) 131 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 132 return error; 133 } 134 135 Error 136 FileSystem::Readlink(const FileSpec &src, FileSpec &dst) 137 { 138 Error error; 139 HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ, 140 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 141 FILE_FLAG_OPEN_REPARSE_POINT, NULL); 142 if (h == INVALID_HANDLE_VALUE) 143 { 144 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 145 return error; 146 } 147 148 char buf[PATH_MAX]; 149 // Subtract 1 from the path length since this function does not add a null terminator. 150 DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1, 151 FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 152 if (result == 0) 153 error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 154 else 155 dst.SetFile(buf, false); 156 157 ::CloseHandle(h); 158 return error; 159 } 160 161 bool 162 FileSystem::IsLocal(const FileSpec &spec) 163 { 164 if (spec) 165 { 166 // TODO: return true if the file is on a locally mounted file system 167 return true; 168 } 169 170 return false; 171 } 172