]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp
Upgrade to OpenSSH 6.7p1, retaining libwrap support (which has been removed
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Utility / ModuleCache.cpp
1 //===--------------------- ModuleCache.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 "ModuleCache.h"
11
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/ModuleSpec.h"
14 #include "lldb/Host/File.h"
15 #include "lldb/Host/FileSystem.h"
16 #include "lldb/Host/LockFile.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/FileUtilities.h"
19
20 #include <assert.h>
21
22 #include <cstdio>
23
24 using namespace lldb;
25 using namespace lldb_private;
26
27 namespace {
28
29 const char* kModulesSubdir = ".cache";
30 const char* kLockFileName = ".lock";
31 const char* kTempFileName = ".temp";
32
33 FileSpec
34 JoinPath (const FileSpec &path1, const char* path2)
35 {
36     FileSpec result_spec (path1);
37     result_spec.AppendPathComponent (path2);
38     return result_spec;
39 }
40
41 Error
42 MakeDirectory (const FileSpec &dir_path)
43 {
44     if (dir_path.Exists ())
45     {
46         if (!dir_path.IsDirectory ())
47             return Error ("Invalid existing path");
48
49         return Error ();
50     }
51
52     return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault);
53 }
54
55 FileSpec
56 GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid)
57 {
58     const auto modules_dir_spec = JoinPath (root_dir_spec, kModulesSubdir);
59     return JoinPath (modules_dir_spec, uuid.GetAsString ().c_str ());
60 }
61
62 Error
63 CreateHostSysRootModuleLink (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec, const FileSpec &local_module_spec)
64 {
65     const auto sysroot_module_path_spec = JoinPath (
66         JoinPath (root_dir_spec, hostname), platform_module_spec.GetPath ().c_str ());
67     if (sysroot_module_path_spec.Exists())
68         return Error ();
69
70     const auto error = MakeDirectory (FileSpec (sysroot_module_path_spec.GetDirectory ().AsCString (), false));
71     if (error.Fail ())
72         return error;
73
74     return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec);
75 }
76
77 }  // namespace
78
79 Error
80 ModuleCache::Put (const FileSpec &root_dir_spec,
81                   const char *hostname,
82                   const ModuleSpec &module_spec,
83                   const FileSpec &tmp_file)
84 {
85     const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
86     const auto module_file_path = JoinPath (module_spec_dir, module_spec.GetFileSpec ().GetFilename ().AsCString ());
87
88     const auto tmp_file_path = tmp_file.GetPath ();
89     const auto err_code = llvm::sys::fs::rename (tmp_file_path.c_str (), module_file_path.GetPath ().c_str ());
90     if (err_code)
91         return Error ("Failed to rename file %s to %s: %s",
92                       tmp_file_path.c_str (), module_file_path.GetPath ().c_str (), err_code.message ().c_str ());
93
94     const auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, module_spec.GetFileSpec(), module_file_path);
95     if (error.Fail ())
96         return Error ("Failed to create link to %s: %s", module_file_path.GetPath ().c_str (), error.AsCString ());
97     return Error ();
98 }
99
100 Error
101 ModuleCache::Get (const FileSpec &root_dir_spec,
102                   const char *hostname,
103                   const ModuleSpec &module_spec,
104                   ModuleSP &cached_module_sp,
105                   bool *did_create_ptr)
106 {
107     const auto find_it = m_loaded_modules.find (module_spec.GetUUID ().GetAsString());
108     if (find_it != m_loaded_modules.end ())
109     {
110         cached_module_sp = (*find_it).second.lock ();
111         if (cached_module_sp)
112             return Error ();
113         m_loaded_modules.erase (find_it);
114     }
115
116     const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
117     const auto module_file_path = JoinPath (module_spec_dir, module_spec.GetFileSpec ().GetFilename ().AsCString ());
118
119     if (!module_file_path.Exists ())
120         return Error ("Module %s not found", module_file_path.GetPath ().c_str ());
121     if (module_file_path.GetByteSize () != module_spec.GetObjectSize ())
122         return Error ("Module %s has invalid file size", module_file_path.GetPath ().c_str ());
123
124     // We may have already cached module but downloaded from an another host - in this case let's create a link to it.
125     const auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname, module_spec.GetFileSpec(), module_file_path);
126     if (error.Fail ())
127         return Error ("Failed to create link to %s: %s", module_file_path.GetPath().c_str(), error.AsCString());
128
129     auto cached_module_spec (module_spec);
130     cached_module_spec.GetUUID ().Clear ();  // Clear UUID since it may contain md5 content hash instead of real UUID.
131     cached_module_spec.GetFileSpec () = module_file_path;
132     cached_module_spec.GetPlatformFileSpec () = module_spec.GetFileSpec ();
133     cached_module_sp.reset (new Module (cached_module_spec));
134     if (did_create_ptr)
135         *did_create_ptr = true;
136
137     m_loaded_modules.insert (std::make_pair (module_spec.GetUUID ().GetAsString (), cached_module_sp));
138
139     return Error ();
140 }
141
142 Error
143 ModuleCache::GetAndPut (const FileSpec &root_dir_spec,
144                         const char *hostname,
145                         const ModuleSpec &module_spec,
146                         const Downloader &downloader,
147                         lldb::ModuleSP &cached_module_sp,
148                         bool *did_create_ptr)
149 {
150     const auto module_spec_dir = GetModuleDirectory (root_dir_spec, module_spec.GetUUID ());
151     auto error = MakeDirectory (module_spec_dir);
152     if (error.Fail ())
153         return error;
154
155     // Open lock file.
156     const auto lock_file_spec = JoinPath (module_spec_dir, kLockFileName);
157     File lock_file (lock_file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionCloseOnExec);
158     if (!lock_file)
159     {
160         error.SetErrorToErrno ();
161         return Error("Failed to open lock file %s: %s", lock_file_spec.GetPath ().c_str (), error.AsCString ());
162     }
163     LockFile lock (lock_file.GetDescriptor ());
164     error = lock.WriteLock (0, 1);
165     if (error.Fail ())
166         return Error("Failed to lock file %s:%s", lock_file_spec.GetPath ().c_str (), error.AsCString ());
167
168     // Check local cache for a module.
169     error = Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr);
170     if (error.Success ())
171         return error;
172
173     const auto tmp_download_file_spec = JoinPath (module_spec_dir, kTempFileName);
174     error = downloader (module_spec, tmp_download_file_spec);
175     llvm::FileRemover tmp_file_remover (tmp_download_file_spec.GetPath ().c_str ());
176     if (error.Fail ())
177         return Error("Failed to download module: %s", error.AsCString ());
178
179     // Put downloaded file into local module cache.
180     error = Put (root_dir_spec, hostname, module_spec, tmp_download_file_spec);
181     if (error.Fail ())
182         return Error ("Failed to put module into cache: %s", error.AsCString ());
183
184     tmp_file_remover.releaseFile ();
185     return Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr);
186 }