source: box/trunk/lib/backupstore/BackupStoreFileRevDiff.cpp @ 2945

Revision 2945, 7.0 KB checked in by chris, 13 months ago (diff)

Major refactoring to make lib/backupclient depend on lib/backupstore rather
than the other way around. This is needed to allow clients to have all the
code that they'd need to implement local backups (using the Local protocol)
in subsequent commits.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreFileRevDiff.cpp
5//              Purpose: Reverse a patch, to build a new patch from new to old files
6//              Created: 12/7/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <new>
13#include <stdlib.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
25// --------------------------------------------------------------------------
26//
27// Function
28//              Name:    BackupStoreFile::ReverseDiffFile(IOStream &, IOStream &, IOStream &, IOStream &, int64_t)
29//              Purpose: Reverse a patch, to build a new patch from new to old files. Takes
30//                               two independent copies to the From file, for efficiency.
31//              Created: 12/7/04
32//
33// --------------------------------------------------------------------------
34void BackupStoreFile::ReverseDiffFile(IOStream &rDiff, IOStream &rFrom, IOStream &rFrom2, IOStream &rOut, int64_t ObjectIDOfFrom, bool *pIsCompletelyDifferent)
35{
36        // Read and copy the header from the from file to the out file -- beginnings of the patch
37        file_StreamFormat hdr;
38        if(!rFrom.ReadFullBuffer(&hdr, sizeof(hdr), 0))
39        {
40                THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
41        }
42        if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
43        {
44                THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
45        }
46        // Copy
47        rOut.Write(&hdr, sizeof(hdr));
48        // Copy over filename and attributes
49        // BLOCK
50        {
51                BackupStoreFilename filename;
52                filename.ReadFromStream(rFrom, IOStream::TimeOutInfinite);
53                filename.WriteToStream(rOut);
54                StreamableMemBlock attr;
55                attr.ReadFromStream(rFrom, IOStream::TimeOutInfinite);
56                attr.WriteToStream(rOut);
57        }
58       
59        // Build an index of common blocks.
60        // For each block in the from file, we want to know it's index in the
61        // diff file. Allocate memory for this information.
62        int64_t fromNumBlocks = box_ntoh64(hdr.mNumBlocks);
63        int64_t *pfromIndexInfo = (int64_t*)::malloc(fromNumBlocks * sizeof(int64_t));
64        if(pfromIndexInfo == 0)
65        {
66                throw std::bad_alloc();
67        }
68
69        // Buffer data
70        void *buffer = 0;
71        int bufferSize = 0;     
72       
73        // flag
74        bool isCompletelyDifferent = true;
75       
76        try
77        {
78                // Initialise the index to be all 0, ie not filled in yet
79                for(int64_t i = 0; i < fromNumBlocks; ++i)
80                {
81                        pfromIndexInfo[i] = 0;
82                }
83       
84                // Within the from file, skip to the index
85                MoveStreamPositionToBlockIndex(rDiff);
86
87                // Read in header of index
88                file_BlockIndexHeader diffIdxHdr;
89                if(!rDiff.ReadFullBuffer(&diffIdxHdr, sizeof(diffIdxHdr), 0))
90                {
91                        THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
92                }
93                if(ntohl(diffIdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
94                {
95                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
96                }
97
98                // And then read in each entry
99                int64_t diffNumBlocks = box_ntoh64(diffIdxHdr.mNumBlocks);
100                for(int64_t b = 0; b < diffNumBlocks; ++b)
101                {
102                        file_BlockIndexEntry e;
103                        if(!rDiff.ReadFullBuffer(&e, sizeof(e), 0))
104                        {
105                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
106                        }
107
108                        // Where's the block?
109                        int64_t blockEn = box_ntoh64(e.mEncodedSize);
110                        if(blockEn > 0)
111                        {
112                                // Block is in the delta file, is ignored for now -- not relevant to rebuilding the from file
113                        }
114                        else
115                        {
116                                // Block is in the original file, store which block it is in this file
117                                int64_t fromIndex = 0 - blockEn;
118                                if(fromIndex < 0 || fromIndex >= fromNumBlocks)
119                                {
120                                        THROW_EXCEPTION(BackupStoreException, IncompatibleFromAndDiffFiles)
121                                }
122                               
123                                // Store information about where it is in the new file
124                                // NOTE: This is slight different to how it'll be stored in the final index.
125                                pfromIndexInfo[fromIndex] = -1 - b;
126                        }
127                }
128               
129                // Open the index for the second copy of the from file
130                MoveStreamPositionToBlockIndex(rFrom2);
131
132                // Read in header of index
133                file_BlockIndexHeader fromIdxHdr;
134                if(!rFrom2.ReadFullBuffer(&fromIdxHdr, sizeof(fromIdxHdr), 0))
135                {
136                        THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
137                }
138                if(ntohl(fromIdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
139                        || box_ntoh64(fromIdxHdr.mOtherFileID) != 0)
140                {
141                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
142                }
143
144                // So, we can now start building the data in the file
145                int64_t filePosition = rFrom.GetPosition();
146                for(int64_t b = 0; b < fromNumBlocks; ++b)
147                {
148                        // Read entry from from index
149                        file_BlockIndexEntry e;
150                        if(!rFrom2.ReadFullBuffer(&e, sizeof(e), 0))
151                        {
152                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
153                        }
154
155                        // Get size
156                        int64_t blockSize = box_hton64(e.mEncodedSize);
157                        if(blockSize < 0)
158                        {
159                                THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
160                        }
161               
162                        // Copy this block?
163                        if(pfromIndexInfo[b] == 0)
164                        {
165                                // Copy it, first move to file location
166                                rFrom.Seek(filePosition, IOStream::SeekType_Absolute);
167                               
168                                // Make sure there's memory available to copy this
169                                if(bufferSize < blockSize || buffer == 0)
170                                {
171                                        // Free old block
172                                        if(buffer != 0)
173                                        {
174                                                ::free(buffer);
175                                                buffer = 0;
176                                                bufferSize = 0;
177                                        }
178                                        // Allocate new block
179                                        buffer = ::malloc(blockSize);
180                                        if(buffer == 0)
181                                        {
182                                                throw std::bad_alloc();
183                                        }
184                                        bufferSize = blockSize;
185                                }
186                                ASSERT(bufferSize >= blockSize);
187                               
188                                // Copy the block
189                                if(!rFrom.ReadFullBuffer(buffer, blockSize, 0))
190                                {
191                                        THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
192                                }
193                                rOut.Write(buffer, blockSize);
194
195                                // Store the size
196                                pfromIndexInfo[b] = blockSize;
197                        }
198                        else
199                        {
200                                // Block isn't needed, so it's not completely different
201                                isCompletelyDifferent = false;
202                        }
203                        filePosition += blockSize;
204                }
205               
206                // Then write the index, modified header first
207                fromIdxHdr.mOtherFileID = isCompletelyDifferent?0:(box_hton64(ObjectIDOfFrom));
208                rOut.Write(&fromIdxHdr, sizeof(fromIdxHdr));
209
210                // Move to start of index entries
211                rFrom.Seek(filePosition + sizeof(file_BlockIndexHeader), IOStream::SeekType_Absolute);
212               
213                // Then copy modified entries
214                for(int64_t b = 0; b < fromNumBlocks; ++b)
215                {
216                        // Read entry from from index
217                        file_BlockIndexEntry e;
218                        if(!rFrom.ReadFullBuffer(&e, sizeof(e), 0))
219                        {
220                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
221                        }
222                       
223                        // Modify...
224                        int64_t s = pfromIndexInfo[b];
225                        // Adjust to reflect real block index (remember 0 has a different meaning here)
226                        if(s < 0) ++s;
227                        // Insert
228                        e.mEncodedSize = box_hton64(s);
229                        // Write
230                        rOut.Write(&e, sizeof(e));
231                }
232        }
233        catch(...)
234        {
235                ::free(pfromIndexInfo);
236                if(buffer != 0)
237                {
238                        ::free(buffer);
239                }
240                throw;
241        }
242
243        // Free memory used (oh for finally {} blocks)
244        ::free(pfromIndexInfo);
245        if(buffer != 0)
246        {
247                ::free(buffer);
248        }
249       
250        // return completely different flag
251        if(pIsCompletelyDifferent != 0)
252        {
253                *pIsCompletelyDifferent = isCompletelyDifferent;
254        }
255}
256
257
258
Note: See TracBrowser for help on using the repository browser.