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