// -------------------------------------------------------------------------- // // Function // Name: static LoadIndex(IOStream &, int64_t, BlocksAvailableEntry **, int64_t, bool &) // Purpose: Read in an index, and decrypt, and store in the in memory block format. // rCanDiffFromThis is set to false if the version of the from file is too old. // Created: 12/1/04 // // -------------------------------------------------------------------------- static void LoadIndex(IOStream &rBlockIndex, int64_t ThisID, BlocksAvailableEntry **ppIndex, int64_t &rNumBlocksOut, int Timeout, bool &rCanDiffFromThis) { // Reset rNumBlocksOut = 0; rCanDiffFromThis = false; // Read header file_BlockIndexHeader hdr; if(!rBlockIndex.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, Timeout)) { // Couldn't read header THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream) } #ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE // Check against backwards comptaibility stuff if(hdr.mMagicValue == (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0)) { // Won't diff against old version // Absorb rest of stream char buffer[2048]; while(rBlockIndex.StreamDataLeft()) { rBlockIndex.Read(buffer, sizeof(buffer), 1000 /* 1 sec timeout */); } // Tell caller rCanDiffFromThis = false; return; } #endif // Check magic if(hdr.mMagicValue != (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)) { THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile) } // Check that we're not trying to diff against a file which references blocks from another file if(((int64_t)box_ntoh64(hdr.mOtherFileID)) != 0) { THROW_EXCEPTION(BackupStoreException, CannotDiffAnIncompleteStoreFile) } // Mark as an acceptable diff. rCanDiffFromThis = true; // Get basic information int64_t numBlocks = box_ntoh64(hdr.mNumBlocks); uint64_t entryIVBase = box_ntoh64(hdr.mEntryIVBase); //TODO: Verify that these sizes look reasonable // Allocate space for the index BlocksAvailableEntry *pindex = (BlocksAvailableEntry*)::malloc(sizeof(BlocksAvailableEntry) * numBlocks); if(pindex == 0) { throw std::bad_alloc(); } try { for(int64_t b = 0; b < numBlocks; ++b) { // Read an entry from the stream file_BlockIndexEntry entry; if(!rBlockIndex.ReadFullBuffer(&entry, sizeof(entry), 0 /* not interested in bytes read if this fails */, Timeout)) { // Couldn't read entry THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream) } // Calculate IV for this entry uint64_t iv = entryIVBase; iv += b; // Network byte order iv = box_hton64(iv); sBlowfishDecryptBlockEntry.SetIV(&iv); // Decrypt the encrypted section file_BlockIndexEntryEnc entryEnc; int sectionSize = sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc), entry.mEnEnc, sizeof(entry.mEnEnc)); if(sectionSize != sizeof(entryEnc)) { THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength) } // Check that we're not trying to diff against a file which references blocks from another file if(((int64_t)box_ntoh64(entry.mEncodedSize)) <= 0) { THROW_EXCEPTION(BackupStoreException, CannotDiffAnIncompleteStoreFile) } // Store all the required information pindex[b].mpNextInHashList = 0; // hash list not set up yet pindex[b].mSize = ntohl(entryEnc.mSize); pindex[b].mWeakChecksum = ntohl(entryEnc.mWeakChecksum); ::memcpy(pindex[b].mStrongChecksum, entryEnc.mStrongChecksum, sizeof(pindex[b].mStrongChecksum)); } // Store index pointer for called ASSERT(ppIndex != 0); *ppIndex = pindex; // Store number of blocks for caller rNumBlocksOut = numBlocks; } catch(...) { // clean up and send the exception along its way ::free(pindex); throw; } }