source: box/trunk/lib/backupstore/BackupStoreFileCmbIdx.cpp @ 2963

Revision 2963, 9.0 KB checked in by chris, 12 months ago (diff)

Move remaining parts of BackupStoreFile? into lib/backupstore, and fix module
dependencies to fail if anything else required by bbstored is still in
lib/backupclient instead of lib/backupstore.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreFileCmbIdx.cpp
5//              Purpose: Combine indicies of a delta file and the file it's a diff from.
6//              Created: 8/7/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <new>
13#include <string.h>
14
15#include "BackupStoreFile.h"
16#include "BackupStoreFileWire.h"
17#include "BackupStoreObjectMagic.h"
18#include "BackupStoreException.h"
19#include "BackupStoreConstants.h"
20#include "BackupStoreFilename.h"
21
22#include "MemLeakFindOn.h"
23
24// Hide from outside world
25namespace
26{
27
28class BSFCombinedIndexStream : public IOStream
29{
30public:
31        BSFCombinedIndexStream(IOStream *pDiff);
32        ~BSFCombinedIndexStream();
33       
34        virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
35        virtual void Write(const void *pBuffer, int NBytes);
36        virtual bool StreamDataLeft();
37        virtual bool StreamClosed();
38        virtual void Initialise(IOStream &rFrom);
39       
40private:
41        IOStream *mpDiff;
42        bool mIsInitialised;
43        bool mHeaderWritten;
44        file_BlockIndexHeader mHeader;
45        int64_t mNumEntriesToGo;
46        int64_t mNumEntriesInFromFile;
47        int64_t *mFromBlockSizes;               // NOTE: Entries in network byte order
48};
49
50};
51
52// --------------------------------------------------------------------------
53//
54// Function
55//              Name:    BackupStoreFile::CombineFileIndices(IOStream &, IOStream &, bool)
56//              Purpose: Given a diff file and the file it's a diff from, return a stream from which
57//                               can be read the index of the combined file, without actually combining them.
58//                               The stream of the diff must have a lifetime greater than or equal to the
59//                               lifetime of the returned stream object. The full "from" file stream
60//                               only needs to exist during the actual function call.
61//                               If you pass in dodgy files which aren't related, then you will either
62//                               get an error or bad results. So don't do that.
63//                               If DiffIsIndexOnly is true, then rDiff is assumed to be a stream positioned
64//                               at the beginning of the block index. Similarly for FromIsIndexOnly.
65//                               WARNING: Reads of the returned streams with buffer sizes less than 64 bytes
66//                               will not return any data.
67//              Created: 8/7/04
68//
69// --------------------------------------------------------------------------
70std::auto_ptr<IOStream> BackupStoreFile::CombineFileIndices(IOStream &rDiff, IOStream &rFrom, bool DiffIsIndexOnly, bool FromIsIndexOnly)
71{
72        // Reposition file pointers?
73        if(!DiffIsIndexOnly)
74        {
75                MoveStreamPositionToBlockIndex(rDiff);
76        }
77        if(!FromIsIndexOnly)
78        {
79                MoveStreamPositionToBlockIndex(rFrom);
80        }
81
82        // Create object
83        std::auto_ptr<IOStream> stream(new BSFCombinedIndexStream(&rDiff));
84
85        // Initialise it
86        ((BSFCombinedIndexStream *)stream.get())->Initialise(rFrom);
87
88        // And return the stream
89        return stream;
90}
91
92
93// --------------------------------------------------------------------------
94//
95// Function
96//              Name:    BSFCombinedIndexStream::BSFCombinedIndexStream()
97//              Purpose: Private class. Constructor.
98//              Created: 8/7/04
99//
100// --------------------------------------------------------------------------
101BSFCombinedIndexStream::BSFCombinedIndexStream(IOStream *pDiff)
102        : mpDiff(pDiff),
103          mIsInitialised(false),
104          mHeaderWritten(false),
105          mNumEntriesToGo(0),
106          mNumEntriesInFromFile(0),
107          mFromBlockSizes(0)
108{
109        ASSERT(mpDiff != 0);
110}
111
112
113// --------------------------------------------------------------------------
114//
115// Function
116//              Name:    BSFCombinedIndexStream::~BSFCombinedIndexStream()
117//              Purpose: Private class. Destructor.
118//              Created: 8/7/04
119//
120// --------------------------------------------------------------------------
121BSFCombinedIndexStream::~BSFCombinedIndexStream()
122{
123        if(mFromBlockSizes != 0)
124        {
125                ::free(mFromBlockSizes);
126                mFromBlockSizes = 0;
127        }
128}
129
130
131// --------------------------------------------------------------------------
132//
133// Function
134//              Name:    BSFCombinedIndexStream::Initialise(IOStream &)
135//              Purpose: Private class. Initalise from the streams (diff passed in constructor).
136//                               Both streams must have file pointer positioned at the block index.
137//              Created: 8/7/04
138//
139// --------------------------------------------------------------------------
140void BSFCombinedIndexStream::Initialise(IOStream &rFrom)
141{
142        // Paranoia is good.
143        if(mIsInitialised)
144        {
145                THROW_EXCEPTION(BackupStoreException, Internal)
146        }
147       
148        // Look at the diff file: Read in the header
149        if(!mpDiff->ReadFullBuffer(&mHeader, sizeof(mHeader), 0))
150        {
151                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
152        }
153        if(ntohl(mHeader.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
154        {
155                THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
156        }
157       
158        // Read relevant data.
159        mNumEntriesToGo = box_ntoh64(mHeader.mNumBlocks);
160       
161        // Adjust a bit to reflect the fact it's no longer a diff
162        mHeader.mOtherFileID = box_hton64(0);
163       
164        // Now look at the from file: Read header
165        file_BlockIndexHeader fromHdr;
166        if(!rFrom.ReadFullBuffer(&fromHdr, sizeof(fromHdr), 0))
167        {
168                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
169        }
170        if(ntohl(fromHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
171        {
172                THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
173        }
174       
175        // Then... allocate memory for the list of sizes
176        mNumEntriesInFromFile = box_ntoh64(fromHdr.mNumBlocks);
177        mFromBlockSizes = (int64_t*)::malloc(mNumEntriesInFromFile * sizeof(int64_t));
178        if(mFromBlockSizes == 0)
179        {
180                throw std::bad_alloc();
181        }
182       
183        // And read them all in!
184        for(int64_t b = 0; b < mNumEntriesInFromFile; ++b)
185        {
186                file_BlockIndexEntry e;
187                if(!rFrom.ReadFullBuffer(&e, sizeof(e), 0))
188                {
189                        THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
190                }
191               
192                // Check that the from file isn't a delta in itself
193                if(box_ntoh64(e.mEncodedSize) <= 0)
194                {
195                        THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
196                }
197
198                // Store size (in network byte order)
199                mFromBlockSizes[b] = e.mEncodedSize;
200        }
201       
202        // Flag as initialised
203        mIsInitialised = true;
204}
205
206
207// --------------------------------------------------------------------------
208//
209// Function
210//              Name:    BSFCombinedIndexStream::Read(void *, int, int)
211//              Purpose: Private class. As interface.
212//              Created: 8/7/04
213//
214// --------------------------------------------------------------------------
215int BSFCombinedIndexStream::Read(void *pBuffer, int NBytes, int Timeout)
216{
217        // Paranoia is good.
218        if(!mIsInitialised || mFromBlockSizes == 0 || mpDiff == 0)
219        {
220                THROW_EXCEPTION(BackupStoreException, Internal)
221        }
222       
223        int written = 0;
224       
225        // Header output yet?
226        if(!mHeaderWritten)
227        {
228                // Enough space?
229                if(NBytes < (int)sizeof(mHeader)) return 0;
230               
231                // Copy in
232                ::memcpy(pBuffer, &mHeader, sizeof(mHeader));
233                NBytes -= sizeof(mHeader);
234                written += sizeof(mHeader);
235       
236                // Flag it's done
237                mHeaderWritten = true;
238        }
239
240        // How many entries can be written?
241        int entriesToWrite = NBytes / sizeof(file_BlockIndexEntry);
242        if(entriesToWrite > mNumEntriesToGo)
243        {
244                entriesToWrite = mNumEntriesToGo;
245        }
246       
247        // Setup ready to go
248        file_BlockIndexEntry *poutput = (file_BlockIndexEntry*)(((uint8_t*)pBuffer) + written);
249
250        // Write entries
251        for(int b = 0; b < entriesToWrite; ++b)
252        {
253                if(!mpDiff->ReadFullBuffer(&(poutput[b]), sizeof(file_BlockIndexEntry), 0))
254                {
255                        THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
256                }
257               
258                // Does this need adjusting?
259                int s = box_ntoh64(poutput[b].mEncodedSize);
260                if(s <= 0)
261                {
262                        // A reference to a block in the from file
263                        int block = 0 - s;
264                        ASSERT(block >= 0);
265                        if(block >= mNumEntriesInFromFile)
266                        {
267                                // That's not good, the block doesn't exist
268                                THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
269                        }
270                       
271                        // Adjust the entry in the buffer
272                        poutput[b].mEncodedSize = mFromBlockSizes[block];       // stored in network byte order, no translation necessary
273                }
274        }
275       
276        // Update written count
277        written += entriesToWrite * sizeof(file_BlockIndexEntry);
278        mNumEntriesToGo -= entriesToWrite;
279       
280        return written;
281}
282
283
284// --------------------------------------------------------------------------
285//
286// Function
287//              Name:    BSFCombinedIndexStream::Write(const void *, int)
288//              Purpose: Private class. As interface.
289//              Created: 8/7/04
290//
291// --------------------------------------------------------------------------
292void BSFCombinedIndexStream::Write(const void *pBuffer, int NBytes)
293{
294        THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
295}
296
297
298// --------------------------------------------------------------------------
299//
300// Function
301//              Name:    BSFCombinedIndexStream::StreamDataLeft()
302//              Purpose: Private class. As interface
303//              Created: 8/7/04
304//
305// --------------------------------------------------------------------------
306bool BSFCombinedIndexStream::StreamDataLeft()
307{
308        return (!mHeaderWritten) || (mNumEntriesToGo > 0);
309}
310
311
312// --------------------------------------------------------------------------
313//
314// Function
315//              Name:    BSFCombinedIndexStream::StreamClosed()
316//              Purpose: Private class. As interface.
317//              Created: 8/7/04
318//
319// --------------------------------------------------------------------------
320bool BSFCombinedIndexStream::StreamClosed()
321{
322        return true;    // doesn't do writing
323}
324
Note: See TracBrowser for help on using the repository browser.