1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright 2022 Equinix, Inc. 3 4 #include "fru_reader.hpp" 5 6 #include <cstring> 7 8 ssize_t FRUReader::read(off_t start, size_t len, uint8_t* outbuf) 9 { 10 size_t done = 0; 11 size_t remaining = len; 12 size_t cursor = start; 13 while (done < len) 14 { 15 if (eof.has_value() && cursor >= eof.value()) 16 { 17 break; 18 } 19 20 const uint8_t* blkData = nullptr; 21 size_t available = 0; 22 size_t blk = cursor / cacheBlockSize; 23 size_t blkOffset = cursor % cacheBlockSize; 24 auto findBlk = cache.find(blk); 25 if (findBlk == cache.end()) 26 { 27 // miss, populate cache 28 uint8_t* newData = cache[blk].data(); 29 int64_t ret = 30 readFunc(blk * cacheBlockSize, cacheBlockSize, newData); 31 32 // if we've reached the end of the eeprom, record its size 33 if (ret >= 0 && static_cast<size_t>(ret) < cacheBlockSize) 34 { 35 eof = (blk * cacheBlockSize) + ret; 36 } 37 38 if (ret <= 0) 39 { 40 // don't leave empty blocks in the cache 41 cache.erase(blk); 42 return done != 0U ? done : ret; 43 } 44 45 blkData = newData; 46 available = ret; 47 } 48 else 49 { 50 // hit, use cached data 51 blkData = findBlk->second.data(); 52 53 // if the hit is to the block containing the (previously 54 // discovered on the miss that populated it) end of the eeprom, 55 // don't copy spurious bytes past the end 56 if (eof.has_value() && (eof.value() / cacheBlockSize == blk)) 57 { 58 available = eof.value() % cacheBlockSize; 59 } 60 else 61 { 62 available = cacheBlockSize; 63 } 64 } 65 66 size_t toCopy = (blkOffset >= available) 67 ? 0 68 : std::min(available - blkOffset, remaining); 69 70 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 71 memcpy(outbuf + done, blkData + blkOffset, toCopy); 72 cursor += toCopy; 73 done += toCopy; 74 remaining -= toCopy; 75 } 76 77 return done; 78 } 79