1*0b57cec5SDimitry Andric //===-- FileCache.cpp -----------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Host/FileCache.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "lldb/Host/File.h"
12*0b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric using namespace lldb;
15*0b57cec5SDimitry Andric using namespace lldb_private;
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric FileCache *FileCache::m_instance = nullptr;
18*0b57cec5SDimitry Andric 
GetInstance()19*0b57cec5SDimitry Andric FileCache &FileCache::GetInstance() {
20*0b57cec5SDimitry Andric   if (m_instance == nullptr)
21*0b57cec5SDimitry Andric     m_instance = new FileCache();
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric   return *m_instance;
24*0b57cec5SDimitry Andric }
25*0b57cec5SDimitry Andric 
OpenFile(const FileSpec & file_spec,File::OpenOptions flags,uint32_t mode,Status & error)26*0b57cec5SDimitry Andric lldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec,
27*0b57cec5SDimitry Andric                                     File::OpenOptions flags, uint32_t mode,
28*0b57cec5SDimitry Andric                                     Status &error) {
29*0b57cec5SDimitry Andric   if (!file_spec) {
30*0b57cec5SDimitry Andric     error.SetErrorString("empty path");
31*0b57cec5SDimitry Andric     return UINT64_MAX;
32*0b57cec5SDimitry Andric   }
33*0b57cec5SDimitry Andric   auto file = FileSystem::Instance().Open(file_spec, flags, mode);
34*0b57cec5SDimitry Andric   if (!file) {
35*0b57cec5SDimitry Andric     error = file.takeError();
36*0b57cec5SDimitry Andric     return UINT64_MAX;
37*0b57cec5SDimitry Andric   }
38*0b57cec5SDimitry Andric   lldb::user_id_t fd = file.get()->GetDescriptor();
39*0b57cec5SDimitry Andric   m_cache[fd] = std::move(file.get());
40*0b57cec5SDimitry Andric   return fd;
41*0b57cec5SDimitry Andric }
42*0b57cec5SDimitry Andric 
CloseFile(lldb::user_id_t fd,Status & error)43*0b57cec5SDimitry Andric bool FileCache::CloseFile(lldb::user_id_t fd, Status &error) {
44*0b57cec5SDimitry Andric   if (fd == UINT64_MAX) {
45*0b57cec5SDimitry Andric     error.SetErrorString("invalid file descriptor");
46*0b57cec5SDimitry Andric     return false;
47*0b57cec5SDimitry Andric   }
48*0b57cec5SDimitry Andric   FDToFileMap::iterator pos = m_cache.find(fd);
49*0b57cec5SDimitry Andric   if (pos == m_cache.end()) {
50*0b57cec5SDimitry Andric     error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
51*0b57cec5SDimitry Andric     return false;
52*0b57cec5SDimitry Andric   }
53*0b57cec5SDimitry Andric   FileUP &file_up = pos->second;
54*0b57cec5SDimitry Andric   if (!file_up) {
55*0b57cec5SDimitry Andric     error.SetErrorString("invalid host backing file");
56*0b57cec5SDimitry Andric     return false;
57*0b57cec5SDimitry Andric   }
58*0b57cec5SDimitry Andric   error = file_up->Close();
59*0b57cec5SDimitry Andric   m_cache.erase(pos);
60*0b57cec5SDimitry Andric   return error.Success();
61*0b57cec5SDimitry Andric }
62*0b57cec5SDimitry Andric 
WriteFile(lldb::user_id_t fd,uint64_t offset,const void * src,uint64_t src_len,Status & error)63*0b57cec5SDimitry Andric uint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
64*0b57cec5SDimitry Andric                               const void *src, uint64_t src_len,
65*0b57cec5SDimitry Andric                               Status &error) {
66*0b57cec5SDimitry Andric   if (fd == UINT64_MAX) {
67*0b57cec5SDimitry Andric     error.SetErrorString("invalid file descriptor");
68*0b57cec5SDimitry Andric     return UINT64_MAX;
69*0b57cec5SDimitry Andric   }
70*0b57cec5SDimitry Andric   FDToFileMap::iterator pos = m_cache.find(fd);
71*0b57cec5SDimitry Andric   if (pos == m_cache.end()) {
72*0b57cec5SDimitry Andric     error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
73*0b57cec5SDimitry Andric     return false;
74*0b57cec5SDimitry Andric   }
75*0b57cec5SDimitry Andric   FileUP &file_up = pos->second;
76*0b57cec5SDimitry Andric   if (!file_up) {
77*0b57cec5SDimitry Andric     error.SetErrorString("invalid host backing file");
78*0b57cec5SDimitry Andric     return UINT64_MAX;
79*0b57cec5SDimitry Andric   }
80*0b57cec5SDimitry Andric   if (static_cast<uint64_t>(file_up->SeekFromStart(offset, &error)) != offset ||
81*0b57cec5SDimitry Andric       error.Fail())
82*0b57cec5SDimitry Andric     return UINT64_MAX;
83*0b57cec5SDimitry Andric   size_t bytes_written = src_len;
84*0b57cec5SDimitry Andric   error = file_up->Write(src, bytes_written);
85*0b57cec5SDimitry Andric   if (error.Fail())
86*0b57cec5SDimitry Andric     return UINT64_MAX;
87*0b57cec5SDimitry Andric   return bytes_written;
88*0b57cec5SDimitry Andric }
89*0b57cec5SDimitry Andric 
ReadFile(lldb::user_id_t fd,uint64_t offset,void * dst,uint64_t dst_len,Status & error)90*0b57cec5SDimitry Andric uint64_t FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
91*0b57cec5SDimitry Andric                              uint64_t dst_len, Status &error) {
92*0b57cec5SDimitry Andric   if (fd == UINT64_MAX) {
93*0b57cec5SDimitry Andric     error.SetErrorString("invalid file descriptor");
94*0b57cec5SDimitry Andric     return UINT64_MAX;
95*0b57cec5SDimitry Andric   }
96*0b57cec5SDimitry Andric   FDToFileMap::iterator pos = m_cache.find(fd);
97*0b57cec5SDimitry Andric   if (pos == m_cache.end()) {
98*0b57cec5SDimitry Andric     error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
99*0b57cec5SDimitry Andric     return false;
100*0b57cec5SDimitry Andric   }
101*0b57cec5SDimitry Andric   FileUP &file_up = pos->second;
102*0b57cec5SDimitry Andric   if (!file_up) {
103*0b57cec5SDimitry Andric     error.SetErrorString("invalid host backing file");
104*0b57cec5SDimitry Andric     return UINT64_MAX;
105*0b57cec5SDimitry Andric   }
106*0b57cec5SDimitry Andric   if (static_cast<uint64_t>(file_up->SeekFromStart(offset, &error)) != offset ||
107*0b57cec5SDimitry Andric       error.Fail())
108*0b57cec5SDimitry Andric     return UINT64_MAX;
109*0b57cec5SDimitry Andric   size_t bytes_read = dst_len;
110*0b57cec5SDimitry Andric   error = file_up->Read(dst, bytes_read);
111*0b57cec5SDimitry Andric   if (error.Fail())
112*0b57cec5SDimitry Andric     return UINT64_MAX;
113   return bytes_read;
114 }
115