Index: include/lldb/Host/FileSystem.h =================================================================== --- include/lldb/Host/FileSystem.h +++ include/lldb/Host/FileSystem.h @@ -32,6 +32,7 @@ static lldb::user_id_t GetFileSize(const FileSpec &file_spec); static bool GetFileExists(const FileSpec &file_spec); + static bool CanCreateSymlinks(); static Error Symlink(const char *src, const char *dst); static Error Readlink(const char *path, char *buf, size_t buf_len); static Error Unlink(const char *path); Index: source/Host/posix/FileSystem.cpp =================================================================== --- source/Host/posix/FileSystem.cpp +++ source/Host/posix/FileSystem.cpp @@ -148,6 +148,12 @@ return file_spec.Exists(); } +bool +FileSystem::CanCreateSymlinks() +{ + return true; +} + Error FileSystem::Symlink(const char *src, const char *dst) { Index: source/Host/windows/FileSystem.cpp =================================================================== --- source/Host/windows/FileSystem.cpp +++ source/Host/windows/FileSystem.cpp @@ -11,11 +11,73 @@ #include +#include +#include + +#include "lldb/Core/Log.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/windows/AutoHandle.h" #include "llvm/Support/FileSystem.h" using namespace lldb_private; +namespace +{ + +Error EnableCreateSymLinkPrivilege() +{ + HANDLE hProcessToken; + + // Get a token for this process. + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) + return Error(::GetLastError(), lldb::eErrorTypeWin32); + AutoHandle process_token(hProcessToken); + + // Get the LUID for the SE_CREATE_SYMBOLIC_LINK privilege. + LUID luid = {0}; + if (!::LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid)) + return Error(::GetLastError(), lldb::eErrorTypeWin32); + + DWORD buffer_len; + if (!::GetTokenInformation(hProcessToken, TokenPrivileges, NULL, 0, &buffer_len)) + { + const auto err = ::GetLastError(); + if (err != ERROR_INSUFFICIENT_BUFFER) + return Error(err, lldb::eErrorTypeWin32); + } + + std::vector buffer(buffer_len); + if (!::GetTokenInformation(hProcessToken, TokenPrivileges, &buffer[0], buffer_len, &buffer_len)) + return Error(::GetLastError(), lldb::eErrorTypeWin32); + + // Iterate through all the privileges. + bool found = false; + auto privs_ptr = reinterpret_cast(&buffer[0]); + for (DWORD i = 0; i < privs_ptr->PrivilegeCount; i++) + { + if (!memcmp(&privs_ptr->Privileges[i].Luid, &luid, sizeof(LUID))) + { + found = true; + break; + } + } + if (!found) + return Error("Process token doesn't have SE_CREATE_SYMBOLIC_LINK privilege"); + + TOKEN_PRIVILEGES tkp = {0}; + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + tkp.Privileges[0].Luid = luid; + + // Enable privilege for this process. + if (!::AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, reinterpret_cast(NULL), 0)) + return Error(::GetLastError(), lldb::eErrorTypeWin32); + + return Error(); +} + +} // namespace + FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { @@ -95,9 +157,29 @@ return file_spec.Exists(); } +bool +FileSystem::CanCreateSymlinks() +{ + static std::once_flag g_cancreatesymlinks_init_flag; + static bool g_cancreatesymlinks = false; + + std::call_once(g_cancreatesymlinks_init_flag, []() { + const auto error = EnableCreateSymLinkPrivilege(); + g_cancreatesymlinks = error.Success(); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST)); + if (log) + log->Printf("Cannot create sym links: %s", error.AsCString()); + }); + return g_cancreatesymlinks; +} + Error FileSystem::Symlink(const char *linkname, const char *target) { + if (!CanCreateSymlinks()) + return Error("Process isn't allowed to create symlinks."); + Error error; DWORD attrib = ::GetFileAttributes(target); if (attrib == INVALID_FILE_ATTRIBUTES) Index: source/Utility/ModuleCache.h =================================================================== --- source/Utility/ModuleCache.h +++ source/Utility/ModuleCache.h @@ -70,15 +70,6 @@ lldb::ModuleSP &cached_module_sp, bool *did_create_ptr); - static FileSpec - GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid); - - static FileSpec - GetHostSysRootModulePath (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec); - - static Error - CreateHostSysRootModuleSymLink (const FileSpec &sysroot_module_path_spec, const FileSpec &module_file_path); - std::unordered_map m_loaded_modules; }; Index: source/Utility/ModuleCache.cpp =================================================================== --- source/Utility/ModuleCache.cpp +++ source/Utility/ModuleCache.cpp @@ -53,6 +53,31 @@ eFilePermissionsDirectoryDefault); } +FileSpec +GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid) +{ + const auto modules_dir_spec = JoinPath (root_dir_spec, kModulesSubdir); + return JoinPath (modules_dir_spec, uuid.GetAsString ().c_str ()); +} + +Error +CreateHostSysRootModuleSymLink (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec, const FileSpec &local_module_spec) +{ + if (!FileSystem::CanCreateSymlinks()) + return Error(); + + const auto sysroot_module_path_spec = JoinPath ( + JoinPath (root_dir_spec, hostname), platform_module_spec.GetPath ().c_str ()); + if (sysroot_module_path_spec.Exists()) + return Error (); + + const auto error = MakeDirectory (FileSpec (sysroot_module_path_spec.GetDirectory ().AsCString (), false)); + if (error.Fail ()) + return error; + + return FileSystem::Symlink (sysroot_module_path_spec.GetPath ().c_str (), local_module_spec.GetPath ().c_str ()); +} + } // namespace Error @@ -70,9 +95,10 @@ return Error ("Failed to rename file %s to %s: %s", tmp_file_path.c_str (), module_file_path.GetPath ().c_str (), err_code.message ().c_str ()); - // Create sysroot link to a module. - const auto sysroot_module_path_spec = GetHostSysRootModulePath (root_dir_spec, hostname, module_spec.GetFileSpec ()); - return CreateHostSysRootModuleSymLink (sysroot_module_path_spec, module_file_path); + const auto error = CreateHostSysRootModuleSymLink (root_dir_spec, hostname, module_spec.GetFileSpec (), module_file_path); + if (error.Fail ()) + return Error ("Failed to create symlink to %s: %s", module_file_path.GetPath ().c_str (), error.AsCString ()); + return Error (); } Error @@ -91,7 +117,7 @@ m_loaded_modules.erase (find_it); } - const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ()); + const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ()); const auto module_file_path = JoinPath (module_spec_dir, module_spec.GetFileSpec ().GetFilename ().AsCString ()); if (!module_file_path.Exists ()) @@ -100,9 +126,9 @@ return Error ("Module %s has invalid file size", module_file_path.GetPath ().c_str ()); // We may have already cached module but downloaded from an another host - in this case let's create a symlink to it. - const auto sysroot_module_path_spec = GetHostSysRootModulePath (root_dir_spec, hostname, module_spec.GetFileSpec ()); - if (!sysroot_module_path_spec.Exists ()) - CreateHostSysRootModuleSymLink (sysroot_module_path_spec, module_spec.GetFileSpec ()); + const auto error = CreateHostSysRootModuleSymLink (root_dir_spec, hostname, module_spec.GetFileSpec(), module_file_path); + if (error.Fail ()) + return Error ("Failed to create symlink to %s: %s", module_file_path.GetPath().c_str(), error.AsCString()); auto cached_module_spec (module_spec); cached_module_spec.GetUUID ().Clear (); // Clear UUID since it may contain md5 content hash instead of real UUID. @@ -162,28 +188,3 @@ tmp_file_remover.releaseFile (); return Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr); } - -FileSpec -ModuleCache::GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid) -{ - const auto modules_dir_spec = JoinPath (root_dir_spec, kModulesSubdir); - return JoinPath (modules_dir_spec, uuid.GetAsString ().c_str ()); -} - -FileSpec -ModuleCache::GetHostSysRootModulePath (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec) -{ - const auto sysroot_dir = JoinPath (root_dir_spec, hostname); - return JoinPath (sysroot_dir, platform_module_spec.GetPath ().c_str ()); -} - -Error -ModuleCache::CreateHostSysRootModuleSymLink (const FileSpec &sysroot_module_path_spec, const FileSpec &module_file_path) -{ - const auto error = MakeDirectory (FileSpec (sysroot_module_path_spec.GetDirectory ().AsCString (), false)); - if (error.Fail ()) - return error; - - return FileSystem::Symlink (sysroot_module_path_spec.GetPath ().c_str (), - module_file_path.GetPath ().c_str ()); -}