1//===- BuiltinCAS.cpp -------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "BuiltinCAS.h"
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/CAS/BuiltinObjectHasher.h"
12#include "llvm/CAS/UnifiedOnDiskCache.h"
13
14using namespace llvm;
15using namespace llvm::cas;
16using namespace llvm::cas::builtin;
17
18static StringRef getCASIDPrefix() { return "llvmcas://"; }
19void BuiltinCASContext::anchor() {}
20
21Expected<HashType> BuiltinCASContext::parseID(StringRef Reference) {
22 if (!Reference.consume_front(Prefix: getCASIDPrefix()))
23 return createStringError(EC: std::make_error_code(e: std::errc::invalid_argument),
24 S: "invalid cas-id '" + Reference + "'");
25
26 // FIXME: Allow shortened references?
27 if (Reference.size() != 2 * sizeof(HashType))
28 return createStringError(EC: std::make_error_code(e: std::errc::invalid_argument),
29 S: "wrong size for cas-id hash '" + Reference + "'");
30
31 std::string Binary;
32 if (!tryGetFromHex(Input: Reference, Output&: Binary))
33 return createStringError(EC: std::make_error_code(e: std::errc::invalid_argument),
34 S: "invalid hash in cas-id '" + Reference + "'");
35
36 assert(Binary.size() == sizeof(HashType));
37 HashType Digest;
38 llvm::copy(Range&: Binary, Out: Digest.data());
39 return Digest;
40}
41
42Expected<CASID> BuiltinCAS::parseID(StringRef Reference) {
43 Expected<HashType> Digest = BuiltinCASContext::parseID(Reference);
44 if (!Digest)
45 return Digest.takeError();
46
47 return CASID::create(Context: &getContext(), Hash: toStringRef(Input: *Digest));
48}
49
50void BuiltinCASContext::printID(ArrayRef<uint8_t> Digest, raw_ostream &OS) {
51 SmallString<64> Hash;
52 toHex(Input: Digest, /*LowerCase=*/true, Output&: Hash);
53 OS << getCASIDPrefix() << Hash;
54}
55
56void BuiltinCASContext::printIDImpl(raw_ostream &OS, const CASID &ID) const {
57 BuiltinCASContext::printID(Digest: ID.getHash(), OS);
58}
59
60const BuiltinCASContext &BuiltinCASContext::getDefaultContext() {
61 static BuiltinCASContext DefaultContext;
62 return DefaultContext;
63}
64
65Expected<ObjectRef> BuiltinCAS::store(ArrayRef<ObjectRef> Refs,
66 ArrayRef<char> Data) {
67 return storeImpl(ComputedHash: BuiltinObjectHasher<HasherT>::hashObject(CAS: *this, Refs, Data),
68 Refs, Data);
69}
70
71Error BuiltinCAS::validateObject(const CASID &ID) {
72 auto Ref = getReference(ID);
73 if (!Ref)
74 return createUnknownObjectError(ID);
75
76 auto Handle = load(Ref: *Ref);
77 if (!Handle)
78 return Handle.takeError();
79
80 auto Proxy = ObjectProxy::load(CAS&: *this, Ref: *Ref, Node: *Handle);
81 SmallVector<ObjectRef> Refs;
82 if (auto E = Proxy.forEachReference(Callback: [&](ObjectRef Ref) -> Error {
83 Refs.push_back(Elt: Ref);
84 return Error::success();
85 }))
86 return E;
87
88 ArrayRef<char> Data(Proxy.getData().data(), Proxy.getData().size());
89 auto Hash = BuiltinObjectHasher<HasherT>::hashObject(CAS: *this, Refs, Data);
90 if (!ID.getHash().equals(RHS: Hash))
91 return createCorruptObjectError(ID);
92
93 return Error::success();
94}
95
96Expected<std::unique_ptr<ondisk::UnifiedOnDiskCache>>
97cas::builtin::createBuiltinUnifiedOnDiskCache(StringRef Path) {
98#if LLVM_ENABLE_ONDISK_CAS
99 return ondisk::UnifiedOnDiskCache::open(Path, /*SizeLimit=*/std::nullopt,
100 HashName: BuiltinCASContext::getHashName(),
101 HashByteSize: sizeof(HashType));
102#else
103 return createStringError(inconvertibleErrorCode(), "OnDiskCache is disabled");
104#endif
105}
106
107void cas::builtin::hashingFunc(ArrayRef<ArrayRef<uint8_t>> Refs,
108 ArrayRef<char> Data,
109 SmallVectorImpl<uint8_t> &Result) {
110 auto Hash =
111 BuiltinObjectHasher<llvm::cas::builtin::HasherT>::hashObject(Refs, Data);
112 Result.assign(in_start: Hash.begin(), in_end: Hash.end());
113}
114