| 1868 | } |
| 1869 | |
| 1870 | Future<> ReadFooterAsync(arrow::internal::Executor* executor) { |
| 1871 | constexpr int32_t kMagicSize = static_cast<int>(kArrowMagicBytes.size()); |
| 1872 | |
| 1873 | if (footer_offset_ <= kMagicSize * 2 + 4) { |
| 1874 | return Status::Invalid("File is too small: ", footer_offset_); |
| 1875 | } |
| 1876 | |
| 1877 | int file_end_size = static_cast<int>(kMagicSize + sizeof(int32_t)); |
| 1878 | auto self = std::dynamic_pointer_cast<RecordBatchFileReaderImpl>(shared_from_this()); |
| 1879 | auto read_magic = file_->ReadAsync(footer_offset_ - file_end_size, file_end_size); |
| 1880 | if (executor) read_magic = executor->Transfer(std::move(read_magic)); |
| 1881 | return read_magic |
| 1882 | .Then([=](const std::shared_ptr<Buffer>& buffer) |
| 1883 | -> Future<std::shared_ptr<Buffer>> { |
| 1884 | const int64_t expected_footer_size = kMagicSize + sizeof(int32_t); |
| 1885 | if (buffer->size() < expected_footer_size) { |
| 1886 | return Status::Invalid("Unable to read ", expected_footer_size, |
| 1887 | "from end of file"); |
| 1888 | } |
| 1889 | |
| 1890 | const auto magic_start = buffer->data() + sizeof(int32_t); |
| 1891 | if (std::string_view(reinterpret_cast<const char*>(magic_start), kMagicSize) != |
| 1892 | kArrowMagicBytes) { |
| 1893 | return Status::Invalid("Not an Arrow file"); |
| 1894 | } |
| 1895 | |
| 1896 | int32_t footer_length = bit_util::FromLittleEndian( |
| 1897 | *reinterpret_cast<const int32_t*>(buffer->data())); |
| 1898 | |
| 1899 | if (footer_length <= 0 || |
| 1900 | footer_length > self->footer_offset_ - kMagicSize * 2 - 4) { |
| 1901 | return Status::Invalid("File is smaller than indicated metadata size"); |
| 1902 | } |
| 1903 | |
| 1904 | // Now read the footer |
| 1905 | auto read_footer = self->file_->ReadAsync( |
| 1906 | self->footer_offset_ - footer_length - file_end_size, footer_length); |
| 1907 | if (executor) read_footer = executor->Transfer(std::move(read_footer)); |
| 1908 | return read_footer; |
| 1909 | }) |
| 1910 | .Then([=](const std::shared_ptr<Buffer>& buffer) -> Status { |
| 1911 | self->footer_buffer_ = buffer; |
| 1912 | const auto data = self->footer_buffer_->data(); |
| 1913 | const auto size = self->footer_buffer_->size(); |
| 1914 | if (!internal::VerifyFlatbuffers<flatbuf::Footer>(data, size)) { |
| 1915 | return Status::IOError("Verification of flatbuffer-encoded Footer failed."); |
| 1916 | } |
| 1917 | self->footer_ = flatbuf::GetFooter(data); |
| 1918 | |
| 1919 | auto fb_metadata = self->footer_->custom_metadata(); |
| 1920 | if (fb_metadata != nullptr) { |
| 1921 | std::shared_ptr<KeyValueMetadata> md; |
| 1922 | RETURN_NOT_OK(internal::GetKeyValueMetadata(fb_metadata, &md)); |
| 1923 | self->metadata_ = std::move(md); // const-ify |
| 1924 | } |
| 1925 | return Status::OK(); |
| 1926 | }); |
| 1927 | } |
nothing calls this directly
no test coverage detected