| //===- BuiltinCAS.cpp -------------------------------------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "BuiltinCAS.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/CAS/BuiltinObjectHasher.h" | |
| #include "llvm/CAS/UnifiedOnDiskCache.h" | |
| using namespace llvm; | |
| using namespace llvm::cas; | |
| using namespace llvm::cas::builtin; | |
| static StringRef getCASIDPrefix() { return "llvmcas://"; } | |
| void BuiltinCASContext::anchor() {} | |
| Expected<HashType> BuiltinCASContext::parseID(StringRef Reference) { | |
| if (!Reference.consume_front(getCASIDPrefix())) | |
| return createStringError(std::make_error_code(std::errc::invalid_argument), | |
| "invalid cas-id '" + Reference + "'"); | |
| // FIXME: Allow shortened references? | |
| if (Reference.size() != 2 * sizeof(HashType)) | |
| return createStringError(std::make_error_code(std::errc::invalid_argument), | |
| "wrong size for cas-id hash '" + Reference + "'"); | |
| std::string Binary; | |
| if (!tryGetFromHex(Reference, Binary)) | |
| return createStringError(std::make_error_code(std::errc::invalid_argument), | |
| "invalid hash in cas-id '" + Reference + "'"); | |
| assert(Binary.size() == sizeof(HashType)); | |
| HashType Digest; | |
| llvm::copy(Binary, Digest.data()); | |
| return Digest; | |
| } | |
| Expected<CASID> BuiltinCAS::parseID(StringRef Reference) { | |
| Expected<HashType> Digest = BuiltinCASContext::parseID(Reference); | |
| if (!Digest) | |
| return Digest.takeError(); | |
| return CASID::create(&getContext(), toStringRef(*Digest)); | |
| } | |
| void BuiltinCASContext::printID(ArrayRef<uint8_t> Digest, raw_ostream &OS) { | |
| SmallString<64> Hash; | |
| toHex(Digest, /*LowerCase=*/true, Hash); | |
| OS << getCASIDPrefix() << Hash; | |
| } | |
| void BuiltinCASContext::printIDImpl(raw_ostream &OS, const CASID &ID) const { | |
| BuiltinCASContext::printID(ID.getHash(), OS); | |
| } | |
| const BuiltinCASContext &BuiltinCASContext::getDefaultContext() { | |
| static BuiltinCASContext DefaultContext; | |
| return DefaultContext; | |
| } | |
| Expected<ObjectRef> BuiltinCAS::store(ArrayRef<ObjectRef> Refs, | |
| ArrayRef<char> Data) { | |
| return storeImpl(BuiltinObjectHasher<HasherT>::hashObject(*this, Refs, Data), | |
| Refs, Data); | |
| } | |
| Error BuiltinCAS::validateObject(const CASID &ID) { | |
| auto Ref = getReference(ID); | |
| if (!Ref) | |
| return createUnknownObjectError(ID); | |
| auto Handle = load(*Ref); | |
| if (!Handle) | |
| return Handle.takeError(); | |
| auto Proxy = ObjectProxy::load(*this, *Ref, *Handle); | |
| SmallVector<ObjectRef> Refs; | |
| if (auto E = Proxy.forEachReference([&](ObjectRef Ref) -> Error { | |
| Refs.push_back(Ref); | |
| return Error::success(); | |
| })) | |
| return E; | |
| ArrayRef<char> Data(Proxy.getData().data(), Proxy.getData().size()); | |
| auto Hash = BuiltinObjectHasher<HasherT>::hashObject(*this, Refs, Data); | |
| if (!ID.getHash().equals(Hash)) | |
| return createCorruptObjectError(ID); | |
| return Error::success(); | |
| } | |
| Expected<std::unique_ptr<ondisk::UnifiedOnDiskCache>> | |
| cas::builtin::createBuiltinUnifiedOnDiskCache(StringRef Path) { | |
| #if LLVM_ENABLE_ONDISK_CAS | |
| return ondisk::UnifiedOnDiskCache::open(Path, /*SizeLimit=*/std::nullopt, | |
| BuiltinCASContext::getHashName(), | |
| sizeof(HashType)); | |
| #else | |
| return createStringError(inconvertibleErrorCode(), "OnDiskCache is disabled"); | |
| #endif | |
| } | |
| void cas::builtin::hashingFunc(ArrayRef<ArrayRef<uint8_t>> Refs, | |
| ArrayRef<char> Data, | |
| SmallVectorImpl<uint8_t> &Result) { | |
| auto Hash = | |
| BuiltinObjectHasher<llvm::cas::builtin::HasherT>::hashObject(Refs, Data); | |
| Result.assign(Hash.begin(), Hash.end()); | |
| } |