source: box/trunk/lib/backupstore/BackupStoreCheck.cpp @ 3036

Revision 3036, 22.0 KB checked in by chris, 7 months ago (diff)

Remove debugging code.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreCheck.cpp
5//              Purpose: Check a store for consistency
6//              Created: 21/4/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <stdio.h>
13#include <string.h>
14
15#ifdef HAVE_UNISTD_H
16#       include <unistd.h>
17#endif
18
19#include "BackupStoreCheck.h"
20#include "StoreStructure.h"
21#include "RaidFileRead.h"
22#include "RaidFileWrite.h"
23#include "autogen_BackupStoreException.h"
24#include "BackupStoreObjectMagic.h"
25#include "BackupStoreFile.h"
26#include "BackupStoreDirectory.h"
27#include "BackupStoreConstants.h"
28
29#include "MemLeakFindOn.h"
30
31
32// --------------------------------------------------------------------------
33//
34// Function
35//              Name:    BackupStoreCheck::BackupStoreCheck(const std::string &, int, int32_t, bool, bool)
36//              Purpose: Constructor
37//              Created: 21/4/04
38//
39// --------------------------------------------------------------------------
40BackupStoreCheck::BackupStoreCheck(const std::string &rStoreRoot, int DiscSetNumber, int32_t AccountID, bool FixErrors, bool Quiet)
41        : mStoreRoot(rStoreRoot),
42          mDiscSetNumber(DiscSetNumber),
43          mAccountID(AccountID),
44          mFixErrors(FixErrors),
45          mQuiet(Quiet),
46          mNumberErrorsFound(0),
47          mLastIDInInfo(0),
48          mpInfoLastBlock(0),
49          mInfoLastBlockEntries(0),
50          mLostDirNameSerial(0),
51          mLostAndFoundDirectoryID(0),
52          mBlocksUsed(0),
53          mBlocksInCurrentFiles(0),
54          mBlocksInOldFiles(0),
55          mBlocksInDeletedFiles(0),
56          mBlocksInDirectories(0),
57          mNumFiles(0),
58          mNumOldFiles(0),
59          mNumDeletedFiles(0),
60          mNumDirectories(0)
61{
62}
63
64
65// --------------------------------------------------------------------------
66//
67// Function
68//              Name:    BackupStoreCheck::~BackupStoreCheck()
69//              Purpose: Destructor
70//              Created: 21/4/04
71//
72// --------------------------------------------------------------------------
73BackupStoreCheck::~BackupStoreCheck()
74{
75        // Clean up
76        FreeInfo();
77}
78
79
80// --------------------------------------------------------------------------
81//
82// Function
83//              Name:    BackupStoreCheck::Check()
84//              Purpose: Perform the check on the given account
85//              Created: 21/4/04
86//
87// --------------------------------------------------------------------------
88void BackupStoreCheck::Check()
89{
90        // Lock the account
91        {
92                std::string writeLockFilename;
93                StoreStructure::MakeWriteLockFilename(mStoreRoot, mDiscSetNumber, writeLockFilename);
94
95                bool gotLock = false;
96                int triesLeft = 8;
97                do
98                {
99                        gotLock = mAccountLock.TryAndGetLock(writeLockFilename.c_str(), 0600 /* restrictive file permissions */);
100                       
101                        if(!gotLock)
102                        {
103                                --triesLeft;
104                                ::sleep(1);
105                        }
106                } while(!gotLock && triesLeft > 0);
107       
108                if(!gotLock)
109                {
110                        // Couldn't lock the account -- just stop now
111                        if(!mQuiet)
112                        {
113                                BOX_ERROR("Failed to lock the account -- did not check.\nTry again later after the client has disconnected.\nAlternatively, forcibly kill the server.");
114                        }
115                        THROW_EXCEPTION(BackupStoreException, CouldNotLockStoreAccount)
116                }
117        }
118
119        if(!mQuiet && mFixErrors)
120        {
121                BOX_NOTICE("Will fix errors encountered during checking.");
122        }
123
124        // Phase 1, check objects
125        if(!mQuiet)
126        {
127                BOX_INFO("Checking store account ID " <<
128                        BOX_FORMAT_ACCOUNT(mAccountID) << "...");
129                BOX_INFO("Phase 1, check objects...");
130        }
131        CheckObjects();
132       
133        // Phase 2, check directories
134        if(!mQuiet)
135        {
136                BOX_INFO("Phase 2, check directories...");
137        }
138        CheckDirectories();
139       
140        // Phase 3, check root
141        if(!mQuiet)
142        {
143                BOX_INFO("Phase 3, check root...");
144        }
145        CheckRoot();
146
147        // Phase 4, check unattached objects
148        if(!mQuiet)
149        {
150                BOX_INFO("Phase 4, fix unattached objects...");
151        }
152        CheckUnattachedObjects();
153
154        // Phase 5, fix bad info
155        if(!mQuiet)
156        {
157                BOX_INFO("Phase 5, fix unrecovered inconsistencies...");
158        }
159        FixDirsWithWrongContainerID();
160        FixDirsWithLostDirs();
161       
162        // Phase 6, regenerate store info
163        if(!mQuiet)
164        {
165                BOX_INFO("Phase 6, regenerate store info...");
166        }
167        WriteNewStoreInfo();
168       
169//      DUMP_OBJECT_INFO
170       
171        if(mNumberErrorsFound > 0)
172        {
173                BOX_WARNING("Finished checking store account ID " <<
174                        BOX_FORMAT_ACCOUNT(mAccountID) << ": " <<
175                        mNumberErrorsFound << " errors found");
176                if(!mFixErrors)
177                {
178                        BOX_WARNING("No changes to the store account "
179                                "have been made.");
180                }
181                if(!mFixErrors && mNumberErrorsFound > 0)
182                {
183                        BOX_WARNING("Run again with fix option to "
184                                "fix these errors");
185                }
186                if(mFixErrors && mNumberErrorsFound > 0)
187                {
188                        BOX_WARNING("You should now use bbackupquery "
189                                "on the client machine to examine the store.");
190                        if(mLostAndFoundDirectoryID != 0)
191                        {
192                                BOX_WARNING("A lost+found directory was "
193                                        "created in the account root.\n"
194                                        "This contains files and directories "
195                                        "which could not be matched to "
196                                        "existing directories.\n"\
197                                        "bbackupd will delete this directory "
198                                        "in a few days time.");
199                        }
200                }
201        }
202        else
203        {
204                BOX_NOTICE("Finished checking store account ID " <<
205                        BOX_FORMAT_ACCOUNT(mAccountID) << ": "
206                        "no errors found");
207        }
208}
209
210
211// --------------------------------------------------------------------------
212//
213// Function
214//              Name:    static TwoDigitHexToInt(const char *, int &)
215//              Purpose: Convert a two digit hex string to an int, returning whether it's valid or not
216//              Created: 21/4/04
217//
218// --------------------------------------------------------------------------
219static inline bool TwoDigitHexToInt(const char *String, int &rNumberOut)
220{
221        int n = 0;
222        // Char 0
223        if(String[0] >= '0' && String[0] <= '9')
224        {
225                n = (String[0] - '0') << 4;
226        }
227        else if(String[0] >= 'a' && String[0] <= 'f')
228        {
229                n = ((String[0] - 'a') + 0xa) << 4;
230        }
231        else
232        {
233                return false;
234        }
235        // Char 1
236        if(String[1] >= '0' && String[1] <= '9')
237        {
238                n |= String[1] - '0';
239        }
240        else if(String[1] >= 'a' && String[1] <= 'f')
241        {
242                n |= (String[1] - 'a') + 0xa;
243        }
244        else
245        {
246                return false;
247        }
248
249        // Return a valid number
250        rNumberOut = n;
251        return true;
252}
253
254
255// --------------------------------------------------------------------------
256//
257// Function
258//              Name:    BackupStoreCheck::CheckObjects()
259//              Purpose: Read in the contents of the directory, recurse to other levels,
260//                               checking objects for sanity and readability
261//              Created: 21/4/04
262//
263// --------------------------------------------------------------------------
264void BackupStoreCheck::CheckObjects()
265{
266        // Maximum start ID of directories -- worked out by looking at disc contents, not trusting anything
267        int64_t maxDir = 0;
268
269        // Find the maximum directory starting ID
270        {
271                // Make sure the starting root dir doesn't end with '/'.
272                std::string start(mStoreRoot);
273                if(start.size() > 0 && start[start.size() - 1] == '/')
274                {
275                        start.resize(start.size() - 1);
276                }
277       
278                maxDir = CheckObjectsScanDir(0, 1, mStoreRoot);
279                BOX_TRACE("Max dir starting ID is " <<
280                        BOX_FORMAT_OBJECTID(maxDir));
281        }
282       
283        // Then go through and scan all the objects within those directories
284        for(int64_t d = 0; d <= maxDir; d += (1<<STORE_ID_SEGMENT_LENGTH))
285        {
286                CheckObjectsDir(d);
287        }
288}
289
290// --------------------------------------------------------------------------
291//
292// Function
293//              Name:    BackupStoreCheck::CheckObjectsScanDir(int64_t, int, int, const std::string &)
294//              Purpose: Read in the contents of the directory, recurse to other levels,
295//                               return the maximum starting ID of any directory found.
296//              Created: 21/4/04
297//
298// --------------------------------------------------------------------------
299int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const std::string &rDirName)
300{
301        //TRACE2("Scan directory for max dir starting ID %s, StartID %lld\n", rDirName.c_str(), StartID);
302
303        int64_t maxID = StartID;
304
305        // Read in all the directories, and recurse downwards
306        {
307                std::vector<std::string> dirs;
308                RaidFileRead::ReadDirectoryContents(mDiscSetNumber, rDirName,
309                        RaidFileRead::DirReadType_DirsOnly, dirs);
310
311                for(std::vector<std::string>::const_iterator i(dirs.begin()); i != dirs.end(); ++i)
312                {
313                        // Check to see if it's the right name
314                        int n = 0;
315                        if((*i).size() == 2 && TwoDigitHexToInt((*i).c_str(), n)
316                                && n < (1<<STORE_ID_SEGMENT_LENGTH))
317                        {
318                                // Next level down
319                                int64_t mi = CheckObjectsScanDir(StartID | (n << (Level * STORE_ID_SEGMENT_LENGTH)), Level + 1,
320                                        rDirName + DIRECTORY_SEPARATOR + *i);
321                                // Found a greater starting ID?
322                                if(mi > maxID)
323                                {
324                                        maxID = mi;
325                                }
326                        }
327                        else
328                        {
329                                BOX_WARNING("Spurious or invalid directory " <<
330                                        rDirName << DIRECTORY_SEPARATOR << 
331                                        (*i) << " found, " <<
332                                        (mFixErrors?"deleting":"delete manually"));
333                                ++mNumberErrorsFound;
334                        }
335                }
336        }
337
338        return maxID;
339}
340
341
342// --------------------------------------------------------------------------
343//
344// Function
345//              Name:    BackupStoreCheck::CheckObjectsDir(int64_t)
346//              Purpose: Check all the files within this directory which has
347//                       the given starting ID.
348//              Created: 22/4/04
349//
350// --------------------------------------------------------------------------
351void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
352{
353        // Make directory name -- first generate the filename of an entry in it
354        std::string dirName;
355        StoreStructure::MakeObjectFilename(StartID, mStoreRoot, mDiscSetNumber, dirName, false /* don't make sure the dir exists */);
356        // Check expectations
357        ASSERT(dirName.size() > 4 && 
358                dirName[dirName.size() - 4] == DIRECTORY_SEPARATOR_ASCHAR);
359        // Remove the filename from it
360        dirName.resize(dirName.size() - 4); // four chars for "/o00"
361       
362        // Check directory exists
363        if(!RaidFileRead::DirectoryExists(mDiscSetNumber, dirName))
364        {
365                BOX_WARNING("RaidFile dir " << dirName << " does not exist");
366                return;
367        }
368
369        // Read directory contents
370        std::vector<std::string> files;
371        RaidFileRead::ReadDirectoryContents(mDiscSetNumber, dirName,
372                RaidFileRead::DirReadType_FilesOnly, files);
373       
374        // Array of things present
375        bool idsPresent[(1<<STORE_ID_SEGMENT_LENGTH)];
376        for(int l = 0; l < (1<<STORE_ID_SEGMENT_LENGTH); ++l)
377        {
378                idsPresent[l] = false;
379        }
380       
381        // Parse each entry, building up a list of object IDs which are present in the dir.
382        // This is done so that whatever order is retured from the directory, objects are scanned
383        // in order.
384        // Filename must begin with a 'o' and be three characters long, otherwise it gets deleted.
385        for(std::vector<std::string>::const_iterator i(files.begin()); i != files.end(); ++i)
386        {
387                bool fileOK = true;
388                int n = 0;
389                if((*i).size() == 3 && (*i)[0] == 'o' && TwoDigitHexToInt((*i).c_str() + 1, n)
390                        && n < (1<<STORE_ID_SEGMENT_LENGTH))
391                {
392                        // Filename is valid, mark as existing
393                        idsPresent[n] = true;
394                }
395                // No other files should be present in subdirectories
396                else if(StartID != 0)
397                {
398                        fileOK = false;
399                }
400                // info and refcount databases are OK in the root directory
401                else if(*i == "info" || *i == "refcount.db")
402                {
403                        fileOK = true;
404                }
405                else
406                {
407                        fileOK = false;
408                }
409               
410                if(!fileOK)
411                {
412                        // Unexpected or bad file, delete it
413                        BOX_WARNING("Spurious file " << dirName << 
414                                DIRECTORY_SEPARATOR << (*i) << " found" <<
415                                (mFixErrors?", deleting":""));
416                        ++mNumberErrorsFound;
417                        if(mFixErrors)
418                        {
419                                RaidFileWrite del(mDiscSetNumber, dirName + DIRECTORY_SEPARATOR + *i);
420                                del.Delete();
421                        }
422                }
423        }
424       
425        // Check all the objects found in this directory
426        for(int i = 0; i < (1<<STORE_ID_SEGMENT_LENGTH); ++i)
427        {
428                if(idsPresent[i])
429                {
430                        // Check the object is OK, and add entry
431                        char leaf[8];
432                        ::sprintf(leaf, DIRECTORY_SEPARATOR "o%02x", i);
433                        if(!CheckAndAddObject(StartID | i, dirName + leaf))
434                        {
435                                // File was bad, delete it
436                                BOX_WARNING("Corrupted file " << dirName <<
437                                        leaf << " found" <<
438                                        (mFixErrors?", deleting":""));
439                                ++mNumberErrorsFound;
440                                if(mFixErrors)
441                                {
442                                        RaidFileWrite del(mDiscSetNumber, dirName + leaf);
443                                        del.Delete();
444                                }
445                        }
446                }
447        }
448}
449
450
451// --------------------------------------------------------------------------
452//
453// Function
454//              Name:    BackupStoreCheck::CheckAndAddObject(int64_t,
455//                       const std::string &)
456//              Purpose: Check a specific object and add it to the list
457//                       if it's OK. If there are any errors with the
458//                       reading, return false and it'll be deleted.
459//              Created: 21/4/04
460//
461// --------------------------------------------------------------------------
462bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
463        const std::string &rFilename)
464{
465        // Info on object...
466        bool isFile = true;
467        int64_t containerID = -1;
468        int64_t size = -1;
469
470        try
471        {
472                // Open file
473                std::auto_ptr<RaidFileRead> file(
474                        RaidFileRead::Open(mDiscSetNumber, rFilename));
475                size = file->GetDiscUsageInBlocks();
476               
477                // Read in first four bytes -- don't have to worry about
478                // retrying if not all bytes read as is RaidFile
479                uint32_t signature;
480                if(file->Read(&signature, sizeof(signature)) != sizeof(signature))
481                {
482                        // Too short, can't read signature from it
483                        return false;
484                }
485                // Seek back to beginning
486                file->Seek(0, IOStream::SeekType_Absolute);
487               
488                // Then... check depending on the type
489                switch(ntohl(signature))
490                {
491                case OBJECTMAGIC_FILE_MAGIC_VALUE_V1:
492#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
493                case OBJECTMAGIC_FILE_MAGIC_VALUE_V0:
494#endif
495                        // File... check
496                        containerID = CheckFile(ObjectID, *file);
497                        break;
498
499                case OBJECTMAGIC_DIR_MAGIC_VALUE:
500                        isFile = false;
501                        containerID = CheckDirInitial(ObjectID, *file);
502                        break;
503
504                default:
505                        // Unknown signature. Bad file. Very bad file.
506                        return false;
507                        break;
508                }
509               
510                // Add to usage counts
511                mBlocksUsed += size;
512                if(!isFile)
513                {
514                        mBlocksInDirectories += size;
515                }
516        }
517        catch(...)
518        {
519                // Error caught, not a good file then, let it be deleted
520                return false;
521        }
522       
523        // Got a container ID? (ie check was successful)
524        if(containerID == -1)
525        {
526                return false;
527        }
528
529        // Debugging for Sune Molgaard's issue with non-existent files being
530        // detected as unattached and crashing later in CheckUnattachedObjects()
531        if (ObjectID == 0x90c1a)
532        {
533                BOX_INFO("Adding ID " << BOX_FORMAT_OBJECTID(ObjectID) <<
534                        " contained by " << BOX_FORMAT_OBJECTID(containerID) <<
535                        " with size " << size << " and isFile " << isFile);
536        }
537
538        // Add to list of IDs known about
539        AddID(ObjectID, containerID, size, isFile);
540
541        // Report success
542        return true;
543}
544
545
546// --------------------------------------------------------------------------
547//
548// Function
549//              Name:    BackupStoreCheck::CheckFile(int64_t, IOStream &)
550//              Purpose: Do check on file, return original container ID
551//                       if OK, or -1 on error
552//              Created: 22/4/04
553//
554// --------------------------------------------------------------------------
555int64_t BackupStoreCheck::CheckFile(int64_t ObjectID, IOStream &rStream)
556{
557        // Check that it's not the root directory ID. Having a file as
558        // the root directory would be bad.
559        if(ObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
560        {
561                // Get that dodgy thing deleted!
562                BOX_ERROR("Have file as root directory. This is bad.");
563                return -1;
564        }
565
566        // Check the format of the file, and obtain the container ID
567        int64_t originalContainerID = -1;
568        if(!BackupStoreFile::VerifyEncodedFileFormat(rStream,
569                0 /* don't want diffing from ID */,
570                &originalContainerID))
571        {
572                // Didn't verify
573                return -1;
574        }
575
576        return originalContainerID;
577}
578
579
580// --------------------------------------------------------------------------
581//
582// Function
583//              Name:    BackupStoreCheck::CheckDirInitial(int64_t, IOStream &)
584//              Purpose: Do initial check on directory, return container ID
585//                       if OK, or -1 on error
586//              Created: 22/4/04
587//
588// --------------------------------------------------------------------------
589int64_t BackupStoreCheck::CheckDirInitial(int64_t ObjectID, IOStream &rStream)
590{
591        // Simply attempt to read in the directory
592        BackupStoreDirectory dir;
593        dir.ReadFromStream(rStream, IOStream::TimeOutInfinite);
594
595        // Check object ID
596        if(dir.GetObjectID() != ObjectID)
597        {
598                // Wrong object ID
599                return -1;
600        }
601       
602        // Return container ID
603        return dir.GetContainerID();
604}
605
606
607// --------------------------------------------------------------------------
608//
609// Function
610//              Name:    BackupStoreCheck::CheckDirectories()
611//              Purpose: Check the directories
612//              Created: 22/4/04
613//
614// --------------------------------------------------------------------------
615void BackupStoreCheck::CheckDirectories()
616{
617        // Phase 1 did this:
618        //    Checked that all the directories are readable
619        //    Built a list of all directories and files which exist on the store
620        //
621        // This phase will check all the files in the directories, make
622        // a note of all directories which are missing, and do initial fixing.
623
624        // The root directory is not contained inside another directory, so
625        // it has no directory entry to scan, but we have to count it
626        // somewhere, so we'll count it here.
627        mNumDirectories++;
628
629        // Scan all objects.
630        for(Info_t::const_iterator i(mInfo.begin()); i != mInfo.end(); ++i)
631        {
632                IDBlock *pblock = i->second;
633                int32_t bentries = (pblock == mpInfoLastBlock)?mInfoLastBlockEntries:BACKUPSTORECHECK_BLOCK_SIZE;
634               
635                for(int e = 0; e < bentries; ++e)
636                {
637                        uint8_t flags = GetFlags(pblock, e);
638                        if(flags & Flags_IsDir)
639                        {
640                                // Found a directory. Read it in.
641                                std::string filename;
642                                StoreStructure::MakeObjectFilename(pblock->mID[e], mStoreRoot, mDiscSetNumber, filename, false /* no dir creation */);
643                                BackupStoreDirectory dir;
644                                {
645                                        std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename));
646                                        dir.ReadFromStream(*file, IOStream::TimeOutInfinite);
647                                }
648                               
649                                // Flag for modifications
650                                bool isModified = false;
651                               
652                                // Check for validity
653                                if(dir.CheckAndFix())
654                                {
655                                        // Wasn't quite right, and has been modified
656                                        BOX_WARNING("Directory ID " <<
657                                                BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
658                                                " has bad structure");
659                                        ++mNumberErrorsFound;
660                                        isModified = true;
661                                }
662                               
663                                // Go through, and check that everything in that directory exists and is valid
664                                std::vector<int64_t> toDelete;
665                               
666                                BackupStoreDirectory::Iterator i(dir);
667                                BackupStoreDirectory::Entry *en = 0;
668                                while((en = i.Next()) != 0)
669                                {
670                                        // Lookup the item
671                                        int32_t iIndex;
672                                        IDBlock *piBlock = LookupID(en->GetObjectID(), iIndex);
673                                        bool badEntry = false;
674                                        if(piBlock != 0)
675                                        {
676                                                badEntry = !CheckDirectoryEntry(
677                                                        *en, pblock->mID[e],
678                                                        iIndex, isModified);
679                                        }
680                                        else
681                                        {
682                                                // Item can't be found. Is it a directory?
683                                                if(en->IsDir())
684                                                {
685                                                        // Store the directory for later attention
686                                                        mDirsWhichContainLostDirs[en->GetObjectID()] = pblock->mID[e];
687                                                }
688                                                else
689                                                {
690                                                        // Just remove the entry
691                                                        badEntry = true;
692                                                        BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " references object " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " which does not exist.");
693                                                }
694                                        }
695                                       
696                                        // Is this entry worth keeping?
697                                        if(badEntry)
698                                        {
699                                                toDelete.push_back(en->GetObjectID());
700                                        }
701                                        else if (en->IsFile())
702                                        {
703                                                // Add to sizes?
704                                                if(en->IsOld())
705                                                {
706                                                        mBlocksInOldFiles += en->GetSizeInBlocks();
707                                                }
708                                                if(en->IsDeleted())
709                                                {
710                                                        mBlocksInDeletedFiles += en->GetSizeInBlocks();
711                                                }
712                                                if(!en->IsOld() &&
713                                                        !en->IsDeleted())
714                                                {
715                                                        mBlocksInCurrentFiles += en->GetSizeInBlocks();
716                                                }
717                                        }
718                                }
719                               
720                                if(toDelete.size() > 0)
721                                {
722                                        // Delete entries from directory
723                                        for(std::vector<int64_t>::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d)
724                                        {
725                                                dir.DeleteEntry(*d);
726                                        }
727                                       
728                                        // Mark as modified
729                                        isModified = true;
730                                       
731                                        // Check the directory again, now that entries have been removed
732                                        dir.CheckAndFix();
733                                       
734                                        // Errors found
735                                        ++mNumberErrorsFound;
736                                }
737                               
738                                if(isModified && mFixErrors)
739                                {       
740                                        BOX_WARNING("Fixing directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]));
741
742                                        // Save back to disc
743                                        RaidFileWrite fixed(mDiscSetNumber, filename);
744                                        fixed.Open(true /* allow overwriting */);
745                                        dir.WriteToStream(fixed);
746                                        // Commit it
747                                        fixed.Commit(true /* convert to raid representation now */);
748                                }
749                        }
750                }
751        }
752
753}
754
755bool BackupStoreCheck::CheckDirectoryEntry(BackupStoreDirectory::Entry& rEntry,
756        int64_t DirectoryID, int32_t IndexInDirBlock, bool& rIsModified)
757{
758        IDBlock *piBlock = LookupID(rEntry.GetObjectID(), IndexInDirBlock);
759        ASSERT(piBlock != 0);
760
761        uint8_t iflags = GetFlags(piBlock, IndexInDirBlock);
762        bool badEntry = false;
763       
764        // Is the type the same?
765        if(((iflags & Flags_IsDir) == Flags_IsDir) != rEntry.IsDir())
766        {
767                // Entry is of wrong type
768                BOX_WARNING("Directory ID " <<
769                        BOX_FORMAT_OBJECTID(DirectoryID) <<
770                        " references object " <<
771                        BOX_FORMAT_OBJECTID(rEntry.GetObjectID()) <<
772                        " which has a different type than expected.");
773                badEntry = true;
774        }
775        // Check that the entry is not already contained.
776        else if(iflags & Flags_IsContained)
777        {
778                BOX_WARNING("Directory ID " <<
779                        BOX_FORMAT_OBJECTID(DirectoryID) <<
780                        " references object " <<
781                        BOX_FORMAT_OBJECTID(rEntry.GetObjectID()) <<
782                        " which is already contained.");
783                badEntry = true;
784        }
785        else
786        {
787                // Not already contained -- mark as contained
788                SetFlags(piBlock, IndexInDirBlock, iflags | Flags_IsContained);
789               
790                // Check that the container ID of the object is correct
791                if(piBlock->mContainer[IndexInDirBlock] != DirectoryID)
792                {
793                        // Needs fixing...
794                        if(iflags & Flags_IsDir)
795                        {
796                                // Add to will fix later list
797                                BOX_WARNING("Directory ID " <<
798                                        BOX_FORMAT_OBJECTID(rEntry.GetObjectID())
799                                        << " has wrong container ID.");
800                                mDirsWithWrongContainerID.push_back(rEntry.GetObjectID());
801                        }
802                        else
803                        {
804                                // This is OK for files, they might move
805                                BOX_WARNING("File ID " <<
806                                        BOX_FORMAT_OBJECTID(rEntry.GetObjectID())
807                                        << " has different container ID, "
808                                        "probably moved");
809                        }
810                       
811                        // Fix entry for now
812                        piBlock->mContainer[IndexInDirBlock] = DirectoryID;
813                }
814        }
815       
816        // Check the object size, if it's OK and a file
817        if(!badEntry && !rEntry.IsDir())
818        {
819                if(rEntry.GetSizeInBlocks() != piBlock->mObjectSizeInBlocks[IndexInDirBlock])
820                {
821                        // Wrong size, correct it.
822                        rEntry.SetSizeInBlocks(piBlock->mObjectSizeInBlocks[IndexInDirBlock]);
823
824                        // Mark as changed
825                        rIsModified = true;
826
827                        // Tell user
828                        BOX_WARNING("Directory ID " <<
829                                BOX_FORMAT_OBJECTID(DirectoryID) <<
830                                " has wrong size for object " <<
831                                BOX_FORMAT_OBJECTID(rEntry.GetObjectID()));
832                }
833        }
834
835        if (!badEntry)
836        {
837                if(rEntry.IsDir())
838                {
839                        mNumDirectories++;
840                }
841                else
842                {
843                        mNumFiles++;
844
845                        if(rEntry.IsDeleted())
846                        {
847                                mNumDeletedFiles++;
848                        }
849
850                        if(rEntry.IsOld())
851                        {
852                                mNumOldFiles++;
853                        }
854                }
855        }
856
857        return !badEntry;
858}
859
Note: See TracBrowser for help on using the repository browser.