1275072Semaste//===-- FileCache.cpp -------------------------------------------*- C++ -*-===//
2275072Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6275072Semaste//
7275072Semaste//===----------------------------------------------------------------------===//
8275072Semaste
9275072Semaste#include "lldb/Host/FileCache.h"
10275072Semaste
11275072Semaste#include "lldb/Host/File.h"
12344779Sdim#include "lldb/Host/FileSystem.h"
13275072Semaste
14275072Semasteusing namespace lldb;
15275072Semasteusing namespace lldb_private;
16275072Semaste
17275072SemasteFileCache *FileCache::m_instance = nullptr;
18275072Semaste
19314564SdimFileCache &FileCache::GetInstance() {
20314564Sdim  if (m_instance == nullptr)
21314564Sdim    m_instance = new FileCache();
22275072Semaste
23314564Sdim  return *m_instance;
24275072Semaste}
25275072Semaste
26360784Sdimlldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec,
27360784Sdim                                    File::OpenOptions flags, uint32_t mode,
28360784Sdim                                    Status &error) {
29344779Sdim  if (!file_spec) {
30314564Sdim    error.SetErrorString("empty path");
31314564Sdim    return UINT64_MAX;
32314564Sdim  }
33360784Sdim  auto file = FileSystem::Instance().Open(file_spec, flags, mode);
34360784Sdim  if (!file) {
35360784Sdim    error = file.takeError();
36314564Sdim    return UINT64_MAX;
37360784Sdim  }
38360784Sdim  lldb::user_id_t fd = file.get()->GetDescriptor();
39360784Sdim  m_cache[fd] = std::move(file.get());
40314564Sdim  return fd;
41275072Semaste}
42275072Semaste
43321369Sdimbool FileCache::CloseFile(lldb::user_id_t fd, Status &error) {
44314564Sdim  if (fd == UINT64_MAX) {
45314564Sdim    error.SetErrorString("invalid file descriptor");
46314564Sdim    return false;
47314564Sdim  }
48314564Sdim  FDToFileMap::iterator pos = m_cache.find(fd);
49314564Sdim  if (pos == m_cache.end()) {
50314564Sdim    error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
51314564Sdim    return false;
52314564Sdim  }
53360784Sdim  FileUP &file_up = pos->second;
54360784Sdim  if (!file_up) {
55314564Sdim    error.SetErrorString("invalid host backing file");
56314564Sdim    return false;
57314564Sdim  }
58360784Sdim  error = file_up->Close();
59314564Sdim  m_cache.erase(pos);
60314564Sdim  return error.Success();
61275072Semaste}
62275072Semaste
63314564Sdimuint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
64321369Sdim                              const void *src, uint64_t src_len,
65321369Sdim                              Status &error) {
66314564Sdim  if (fd == UINT64_MAX) {
67314564Sdim    error.SetErrorString("invalid file descriptor");
68314564Sdim    return UINT64_MAX;
69314564Sdim  }
70314564Sdim  FDToFileMap::iterator pos = m_cache.find(fd);
71314564Sdim  if (pos == m_cache.end()) {
72314564Sdim    error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
73314564Sdim    return false;
74314564Sdim  }
75360784Sdim  FileUP &file_up = pos->second;
76360784Sdim  if (!file_up) {
77314564Sdim    error.SetErrorString("invalid host backing file");
78314564Sdim    return UINT64_MAX;
79314564Sdim  }
80360784Sdim  if (static_cast<uint64_t>(file_up->SeekFromStart(offset, &error)) != offset ||
81314564Sdim      error.Fail())
82314564Sdim    return UINT64_MAX;
83314564Sdim  size_t bytes_written = src_len;
84360784Sdim  error = file_up->Write(src, bytes_written);
85314564Sdim  if (error.Fail())
86314564Sdim    return UINT64_MAX;
87314564Sdim  return bytes_written;
88275072Semaste}
89275072Semaste
90314564Sdimuint64_t FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
91321369Sdim                             uint64_t dst_len, Status &error) {
92314564Sdim  if (fd == UINT64_MAX) {
93314564Sdim    error.SetErrorString("invalid file descriptor");
94314564Sdim    return UINT64_MAX;
95314564Sdim  }
96314564Sdim  FDToFileMap::iterator pos = m_cache.find(fd);
97314564Sdim  if (pos == m_cache.end()) {
98314564Sdim    error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
99314564Sdim    return false;
100314564Sdim  }
101360784Sdim  FileUP &file_up = pos->second;
102360784Sdim  if (!file_up) {
103314564Sdim    error.SetErrorString("invalid host backing file");
104314564Sdim    return UINT64_MAX;
105314564Sdim  }
106360784Sdim  if (static_cast<uint64_t>(file_up->SeekFromStart(offset, &error)) != offset ||
107314564Sdim      error.Fail())
108314564Sdim    return UINT64_MAX;
109314564Sdim  size_t bytes_read = dst_len;
110360784Sdim  error = file_up->Read(dst, bytes_read);
111314564Sdim  if (error.Fail())
112314564Sdim    return UINT64_MAX;
113314564Sdim  return bytes_read;
114275072Semaste}
115