1c00cf4a0SZachary Turner //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===// 2c00cf4a0SZachary Turner // 3c00cf4a0SZachary Turner // The LLVM Compiler Infrastructure 4c00cf4a0SZachary Turner // 5c00cf4a0SZachary Turner // This file is distributed under the University of Illinois Open Source 6c00cf4a0SZachary Turner // License. See LICENSE.TXT for details. 7c00cf4a0SZachary Turner // 8c00cf4a0SZachary Turner //===----------------------------------------------------------------------===// 9c00cf4a0SZachary Turner 10c00cf4a0SZachary Turner #include "lldb/Host/windows/windows.h" 11c00cf4a0SZachary Turner 12c00cf4a0SZachary Turner #include <shellapi.h> 13633594c2SAdrian McCarthy #include <sys/stat.h> 14633594c2SAdrian McCarthy #include <sys/types.h> 15c00cf4a0SZachary Turner 16c00cf4a0SZachary Turner #include "lldb/Host/FileSystem.h" 172b38f33bSOleksiy Vyalov #include "lldb/Host/windows/AutoHandle.h" 18cc815568SOleksiy Vyalov #include "llvm/Support/FileSystem.h" 19c00cf4a0SZachary Turner 20c00cf4a0SZachary Turner using namespace lldb_private; 21c00cf4a0SZachary Turner 22*4eff2d31SZachary Turner const char * 23*4eff2d31SZachary Turner FileSystem::DEV_NULL = "nul"; 24*4eff2d31SZachary Turner 25c00cf4a0SZachary Turner FileSpec::PathSyntax 26c00cf4a0SZachary Turner FileSystem::GetNativePathSyntax() 27c00cf4a0SZachary Turner { 28c00cf4a0SZachary Turner return FileSpec::ePathSyntaxWindows; 29c00cf4a0SZachary Turner } 30c00cf4a0SZachary Turner 31c00cf4a0SZachary Turner Error 32d3173f34SChaoren Lin FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) 33c00cf4a0SZachary Turner { 34c00cf4a0SZachary Turner // On Win32, the mode parameter is ignored, as Windows files and directories support a 35c00cf4a0SZachary Turner // different permission model than POSIX. 36c00cf4a0SZachary Turner Error error; 37d3173f34SChaoren Lin const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true); 38cc815568SOleksiy Vyalov if (err_code) 39cc815568SOleksiy Vyalov { 40cc815568SOleksiy Vyalov error.SetErrorString(err_code.message().c_str()); 41cc815568SOleksiy Vyalov } 42cc815568SOleksiy Vyalov 43c00cf4a0SZachary Turner return error; 44c00cf4a0SZachary Turner } 45c00cf4a0SZachary Turner 46c00cf4a0SZachary Turner Error 47d3173f34SChaoren Lin FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) 48c00cf4a0SZachary Turner { 49c00cf4a0SZachary Turner Error error; 50c00cf4a0SZachary Turner if (!recurse) 51c00cf4a0SZachary Turner { 52d3173f34SChaoren Lin BOOL result = ::RemoveDirectory(file_spec.GetCString()); 53c00cf4a0SZachary Turner if (!result) 54c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 55c00cf4a0SZachary Turner } 56c00cf4a0SZachary Turner else 57c00cf4a0SZachary Turner { 58c00cf4a0SZachary Turner // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to 59c00cf4a0SZachary Turner // indicate the end of the list. 60d3173f34SChaoren Lin std::string path_buffer{file_spec.GetPath()}; 61c00cf4a0SZachary Turner path_buffer.push_back(0); 62c00cf4a0SZachary Turner 63c00cf4a0SZachary Turner SHFILEOPSTRUCT shfos = {0}; 64c00cf4a0SZachary Turner shfos.wFunc = FO_DELETE; 65c00cf4a0SZachary Turner shfos.pFrom = path_buffer.c_str(); 66c00cf4a0SZachary Turner shfos.fFlags = FOF_NO_UI; 67c00cf4a0SZachary Turner 68c00cf4a0SZachary Turner int result = ::SHFileOperation(&shfos); 69c00cf4a0SZachary Turner // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values. 70c00cf4a0SZachary Turner if (result != 0) 71c00cf4a0SZachary Turner error.SetErrorStringWithFormat("SHFileOperation failed"); 72c00cf4a0SZachary Turner } 73c00cf4a0SZachary Turner return error; 74c00cf4a0SZachary Turner } 75c00cf4a0SZachary Turner 76c00cf4a0SZachary Turner Error 77d3173f34SChaoren Lin FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) 78c00cf4a0SZachary Turner { 79c00cf4a0SZachary Turner Error error; 80633594c2SAdrian McCarthy // Beware that Windows's permission model is different from Unix's, and it's 81633594c2SAdrian McCarthy // not clear if this API is supposed to check ACLs. To match the caller's 82633594c2SAdrian McCarthy // expectations as closely as possible, we'll use Microsoft's _stat, which 83633594c2SAdrian McCarthy // attempts to emulate POSIX stat. This should be good enough for basic 84633594c2SAdrian McCarthy // checks like FileSpec::Readable. 85633594c2SAdrian McCarthy struct _stat file_stats; 86633594c2SAdrian McCarthy if (::_stat(file_spec.GetCString(), &file_stats) == 0) 87633594c2SAdrian McCarthy { 88633594c2SAdrian McCarthy // The owner permission bits in "st_mode" currently match the definitions 89633594c2SAdrian McCarthy // for the owner file mode bits. 90633594c2SAdrian McCarthy file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC); 91633594c2SAdrian McCarthy } 92633594c2SAdrian McCarthy else 93633594c2SAdrian McCarthy { 94633594c2SAdrian McCarthy error.SetErrorToErrno(); 95633594c2SAdrian McCarthy } 96633594c2SAdrian McCarthy 97c00cf4a0SZachary Turner return error; 98c00cf4a0SZachary Turner } 99c00cf4a0SZachary Turner 100c00cf4a0SZachary Turner Error 101d3173f34SChaoren Lin FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) 102c00cf4a0SZachary Turner { 103c00cf4a0SZachary Turner Error error; 104c00cf4a0SZachary Turner error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); 105c00cf4a0SZachary Turner return error; 106c00cf4a0SZachary Turner } 107c00cf4a0SZachary Turner 108c00cf4a0SZachary Turner lldb::user_id_t 109c00cf4a0SZachary Turner FileSystem::GetFileSize(const FileSpec &file_spec) 110c00cf4a0SZachary Turner { 111c00cf4a0SZachary Turner return file_spec.GetByteSize(); 112c00cf4a0SZachary Turner } 113c00cf4a0SZachary Turner 114c00cf4a0SZachary Turner bool 115c00cf4a0SZachary Turner FileSystem::GetFileExists(const FileSpec &file_spec) 116c00cf4a0SZachary Turner { 117c00cf4a0SZachary Turner return file_spec.Exists(); 118c00cf4a0SZachary Turner } 119c00cf4a0SZachary Turner 120c00cf4a0SZachary Turner Error 121d3173f34SChaoren Lin FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) 122a9ea0711SOleksiy Vyalov { 123a9ea0711SOleksiy Vyalov Error error; 124d3173f34SChaoren Lin if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr)) 125a9ea0711SOleksiy Vyalov error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 126a9ea0711SOleksiy Vyalov return error; 127a9ea0711SOleksiy Vyalov } 128a9ea0711SOleksiy Vyalov 1292b38f33bSOleksiy Vyalov int 1302b38f33bSOleksiy Vyalov FileSystem::GetHardlinkCount(const FileSpec &file_spec) 1312b38f33bSOleksiy Vyalov { 1322b38f33bSOleksiy Vyalov HANDLE file_handle = ::CreateFile(file_spec.GetCString(), 1332b38f33bSOleksiy Vyalov FILE_READ_ATTRIBUTES, 1342b38f33bSOleksiy Vyalov FILE_SHARE_READ, 1352b38f33bSOleksiy Vyalov nullptr, 1362b38f33bSOleksiy Vyalov OPEN_EXISTING, 1372b38f33bSOleksiy Vyalov FILE_ATTRIBUTE_NORMAL, 1382b38f33bSOleksiy Vyalov nullptr); 1392b38f33bSOleksiy Vyalov 1402b38f33bSOleksiy Vyalov if (file_handle == INVALID_HANDLE_VALUE) 1412b38f33bSOleksiy Vyalov return -1; 1422b38f33bSOleksiy Vyalov 1432b38f33bSOleksiy Vyalov AutoHandle auto_file_handle(file_handle); 1442b38f33bSOleksiy Vyalov BY_HANDLE_FILE_INFORMATION file_info; 1452b38f33bSOleksiy Vyalov if (::GetFileInformationByHandle(file_handle, &file_info)) 1462b38f33bSOleksiy Vyalov return file_info.nNumberOfLinks; 1472b38f33bSOleksiy Vyalov 1482b38f33bSOleksiy Vyalov return -1; 1492b38f33bSOleksiy Vyalov } 1502b38f33bSOleksiy Vyalov 151a9ea0711SOleksiy Vyalov Error 152d3173f34SChaoren Lin FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) 153c00cf4a0SZachary Turner { 154c00cf4a0SZachary Turner Error error; 155d3173f34SChaoren Lin DWORD attrib = ::GetFileAttributes(dst.GetCString()); 156c00cf4a0SZachary Turner if (attrib == INVALID_FILE_ATTRIBUTES) 157c00cf4a0SZachary Turner { 158c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 159c00cf4a0SZachary Turner return error; 160c00cf4a0SZachary Turner } 161c00cf4a0SZachary Turner bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); 162c00cf4a0SZachary Turner DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 163d3173f34SChaoren Lin BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag); 164c00cf4a0SZachary Turner if (!result) 165c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 166c00cf4a0SZachary Turner return error; 167c00cf4a0SZachary Turner } 168c00cf4a0SZachary Turner 169c00cf4a0SZachary Turner Error 170d3173f34SChaoren Lin FileSystem::Unlink(const FileSpec &file_spec) 171c00cf4a0SZachary Turner { 172c00cf4a0SZachary Turner Error error; 173d3173f34SChaoren Lin BOOL result = ::DeleteFile(file_spec.GetCString()); 174c00cf4a0SZachary Turner if (!result) 175c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 176c00cf4a0SZachary Turner return error; 177c00cf4a0SZachary Turner } 178c00cf4a0SZachary Turner 179c00cf4a0SZachary Turner Error 180d3173f34SChaoren Lin FileSystem::Readlink(const FileSpec &src, FileSpec &dst) 181c00cf4a0SZachary Turner { 182c00cf4a0SZachary Turner Error error; 183d3173f34SChaoren Lin HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ, 184d3173f34SChaoren Lin FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 185c00cf4a0SZachary Turner FILE_FLAG_OPEN_REPARSE_POINT, NULL); 186c00cf4a0SZachary Turner if (h == INVALID_HANDLE_VALUE) 187c00cf4a0SZachary Turner { 188c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 189c00cf4a0SZachary Turner return error; 190c00cf4a0SZachary Turner } 191c00cf4a0SZachary Turner 192d3173f34SChaoren Lin char buf[PATH_MAX]; 193c00cf4a0SZachary Turner // Subtract 1 from the path length since this function does not add a null terminator. 194d3173f34SChaoren Lin DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1, 195d3173f34SChaoren Lin FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 196c00cf4a0SZachary Turner if (result == 0) 197c00cf4a0SZachary Turner error.SetError(::GetLastError(), lldb::eErrorTypeWin32); 198d3173f34SChaoren Lin else 199d3173f34SChaoren Lin dst.SetFile(buf, false); 200c00cf4a0SZachary Turner 201c00cf4a0SZachary Turner ::CloseHandle(h); 202c00cf4a0SZachary Turner return error; 203c00cf4a0SZachary Turner } 204736888c8SGreg Clayton 2059077e9f8SSean Callanan Error 2069077e9f8SSean Callanan FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) 2079077e9f8SSean Callanan { 2089077e9f8SSean Callanan return Error("ResolveSymbolicLink() isn't implemented on Windows"); 2099077e9f8SSean Callanan } 2109077e9f8SSean Callanan 211736888c8SGreg Clayton bool 212736888c8SGreg Clayton FileSystem::IsLocal(const FileSpec &spec) 213736888c8SGreg Clayton { 214736888c8SGreg Clayton if (spec) 215736888c8SGreg Clayton { 216736888c8SGreg Clayton // TODO: return true if the file is on a locally mounted file system 217736888c8SGreg Clayton return true; 218736888c8SGreg Clayton } 219736888c8SGreg Clayton 220736888c8SGreg Clayton return false; 221736888c8SGreg Clayton } 222