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