source: box/trunk/lib/backupclient/BackupClientRestore.cpp @ 3082

Revision 3082, 21.9 KB checked in by chris, 4 months ago (diff)

Force all options to be present to BackupClientRestore?(), to fix
misinterpretation of char * arguments as bools. Use macros to
simplify test code. Test that locations not present when bbackupd
started will be detected and backed up if subsequently created.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupClientRestore.cpp
5//              Purpose:
6//              Created: 23/11/03
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#ifdef HAVE_UNISTD_H
13        #include <unistd.h>
14#endif
15
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <string>
19#include <set>
20#include <limits.h>
21#include <stdio.h>
22#include <errno.h>
23
24#include "BackupClientRestore.h"
25#include "autogen_BackupProtocol.h"
26#include "CommonException.h"
27#include "BackupClientFileAttributes.h"
28#include "IOStream.h"
29#include "BackupStoreDirectory.h"
30#include "BackupStoreFile.h"
31#include "CollectInBufferStream.h"
32#include "FileStream.h"
33#include "Utils.h"
34
35#include "MemLeakFindOn.h"
36
37#define MAX_BYTES_WRITTEN_BETWEEN_RESTORE_INFO_SAVES (128*1024)
38
39class RestoreResumeInfo
40{
41public:
42        // constructor
43        RestoreResumeInfo()
44                : mNextLevelID(0),
45                  mpNextLevel(0)
46        {
47        }
48       
49        // destructor
50        ~RestoreResumeInfo()
51        {
52                delete mpNextLevel;
53                mpNextLevel = 0;
54        }
55       
56        // Get a next level object
57        RestoreResumeInfo &AddLevel(int64_t ID, const std::string &rLocalName)
58        {
59                ASSERT(mpNextLevel == 0 && mNextLevelID == 0);
60                mpNextLevel = new RestoreResumeInfo;
61                mNextLevelID = ID;
62                mNextLevelLocalName = rLocalName;
63                return *mpNextLevel;
64        }
65       
66        // Remove the next level info
67        void RemoveLevel()
68        {
69                ASSERT(mpNextLevel != 0 && mNextLevelID != 0);
70                delete mpNextLevel;
71                mpNextLevel = 0;
72                mNextLevelID = 0;
73                mNextLevelLocalName.erase();
74        }
75       
76        void Save(const std::string &rFilename) const
77        {
78                // TODO: use proper buffered streams when they're done
79                // Build info in memory buffer
80                CollectInBufferStream write;
81               
82                // Save this level
83                SaveLevel(write);
84       
85                // Store in file
86                write.SetForReading();
87                FileStream file(rFilename.c_str(), O_WRONLY | O_CREAT);
88                write.CopyStreamTo(file, IOStream::TimeOutInfinite, 8*1024 /* large buffer */);
89        }
90
91        void SaveLevel(IOStream &rWrite) const
92        {
93                // Write the restored objects
94                int64_t numObjects = mRestoredObjects.size();
95                rWrite.Write(&numObjects, sizeof(numObjects));
96                for(std::set<int64_t>::const_iterator i(mRestoredObjects.begin()); i != mRestoredObjects.end(); ++i)
97                {
98                        int64_t id = *i;
99                        rWrite.Write(&id, sizeof(id));
100                }
101               
102                // Next level?
103                if(mpNextLevel != 0)
104                {
105                        // ID
106                        rWrite.Write(&mNextLevelID, sizeof(mNextLevelID));
107                        // Name string
108                        int32_t nsize = mNextLevelLocalName.size();
109                        rWrite.Write(&nsize, sizeof(nsize));
110                        rWrite.Write(mNextLevelLocalName.c_str(), nsize);
111                        // And then the level itself
112                        mpNextLevel->SaveLevel(rWrite);
113                }
114                else
115                {
116                        // Just write a zero
117                        int64_t zero = 0;
118                        rWrite.Write(&zero, sizeof(zero));
119                }
120        }
121
122        // Not written to be efficient -- shouldn't be called very often.
123        bool Load(const std::string &rFilename)
124        {
125                // Delete and reset if necessary
126                if(mpNextLevel != 0)
127                {
128                        RemoveLevel();
129                }
130               
131                // Open file
132                FileStream file(rFilename.c_str());
133               
134                // Load this level
135                return LoadLevel(file);
136        }
137       
138        #define CHECKED_READ(x, s) if(!rRead.ReadFullBuffer(x, s, 0)) {return false;}
139        bool LoadLevel(IOStream &rRead)
140        {
141                // Load the restored objects list
142                mRestoredObjects.clear();
143                int64_t numObjects = 0;
144                CHECKED_READ(&numObjects, sizeof(numObjects));
145                for(int64_t o = 0; o < numObjects; ++o)
146                {
147                        int64_t id;
148                        CHECKED_READ(&id, sizeof(id));
149                        mRestoredObjects.insert(id);
150                }
151
152                // ID of next level?
153                int64_t nextID = 0;
154                CHECKED_READ(&nextID, sizeof(nextID));
155                if(nextID != 0)
156                {
157                        // Load the next level!
158                        std::string name;
159                        int32_t nsize = 0;
160                        CHECKED_READ(&nsize, sizeof(nsize));
161                        char n[PATH_MAX];
162                        if(nsize > PATH_MAX) return false;
163                        CHECKED_READ(n, nsize);
164                        name.assign(n, nsize);
165                       
166                        // Create a new level
167                        mpNextLevel = new RestoreResumeInfo;
168                        mNextLevelID = nextID;
169                        mNextLevelLocalName = name;
170                       
171                        // And ask it to read itself in
172                        if(!mpNextLevel->LoadLevel(rRead))
173                        {
174                                return false;
175                        }
176                }
177
178                return true;
179        }
180
181        // List of objects at this level which have been done already
182        std::set<int64_t> mRestoredObjects;
183        // Next level ID
184        int64_t mNextLevelID;
185        // Pointer to next level
186        RestoreResumeInfo *mpNextLevel;
187        // Local filename of next level
188        std::string mNextLevelLocalName;
189};
190
191// parameters structure
192typedef struct
193{
194        bool PrintDots;
195        bool RestoreDeleted;
196        bool ContinueAfterErrors;
197        bool ContinuedAfterError;
198        std::string mRestoreResumeInfoFilename;
199        RestoreResumeInfo mResumeInfo;
200} RestoreParams;
201
202
203
204// --------------------------------------------------------------------------
205//
206// Function
207//              Name:    BackupClientRestoreDir(BackupProtocolClient &,
208//                       int64_t, const char *, bool)
209//              Purpose: Restore a directory
210//              Created: 23/11/03
211//
212// --------------------------------------------------------------------------
213static int BackupClientRestoreDir(BackupProtocolClient &rConnection,
214        int64_t DirectoryID, const std::string &rRemoteDirectoryName,
215        const std::string &rLocalDirectoryName,
216        RestoreParams &Params, RestoreResumeInfo &rLevel)
217{
218        // If we're resuming... check that we haven't got a next level to
219        // look at
220        if(rLevel.mpNextLevel != 0)
221        {
222                // Recurse immediately
223                std::string localDirname(rLocalDirectoryName + 
224                        DIRECTORY_SEPARATOR_ASCHAR + 
225                        rLevel.mNextLevelLocalName);
226                BackupClientRestoreDir(rConnection, rLevel.mNextLevelID,
227                        rRemoteDirectoryName + '/' + 
228                        rLevel.mNextLevelLocalName, localDirname,
229                        Params, *rLevel.mpNextLevel);
230               
231                // Add it to the list of done itmes
232                rLevel.mRestoredObjects.insert(rLevel.mNextLevelID);
233
234                // Remove the level for the recursed directory
235                rLevel.RemoveLevel();           
236        }
237       
238        // Create the local directory, if not already done.
239        // Path and owner set later, just use restrictive owner mode.
240
241        int exists;
242
243        try
244        {
245                exists = ObjectExists(rLocalDirectoryName.c_str());
246        }
247        catch (BoxException &e)
248        {
249                BOX_ERROR("Failed to check existence for " <<
250                        rLocalDirectoryName << ": " << e.what());
251                return Restore_UnknownError;
252        }
253        catch(std::exception &e)
254        {
255                BOX_ERROR("Failed to check existence for " <<
256                        rLocalDirectoryName << ": " << e.what());
257                return Restore_UnknownError;
258        }
259        catch(...)
260        {
261                BOX_ERROR("Failed to check existence for " <<
262                        rLocalDirectoryName << ": unknown error");
263                return Restore_UnknownError;
264        }
265
266        switch(exists)
267        {
268                case ObjectExists_Dir:
269                        // Do nothing
270                        break;
271                case ObjectExists_File:
272                        {
273                                // File exists with this name, which is fun.
274                                // Get rid of it.
275                                BOX_WARNING("File present with name '" <<
276                                        rLocalDirectoryName << "', removing "
277                                        "out of the way of restored directory. "
278                                        "Use specific restore with ID to "
279                                        "restore this object.");
280                                if(::unlink(rLocalDirectoryName.c_str()) != 0)
281                                {
282                                        BOX_LOG_SYS_ERROR("Failed to delete "
283                                                "file '" << 
284                                                rLocalDirectoryName << "'");
285                                        return Restore_UnknownError;
286                                }
287                                BOX_TRACE("In restore, directory name " 
288                                        "collision with file '" <<
289                                        rLocalDirectoryName << "'");
290                        }
291                        break;
292                case ObjectExists_NoObject:
293                        // we'll create it in a second, after checking
294                        // whether the parent directory exists
295                        break;
296                default:
297                        ASSERT(false);
298                        break;
299        }
300
301        std::string parentDirectoryName(rLocalDirectoryName);
302        if(parentDirectoryName[parentDirectoryName.size() - 1] == 
303                DIRECTORY_SEPARATOR_ASCHAR)
304        {
305                parentDirectoryName.resize(parentDirectoryName.size() - 1);
306        }
307
308        size_t lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR);
309
310        if(lastSlash == std::string::npos)
311        {
312                // might be a forward slash separator,
313                // especially in the unit tests!
314                lastSlash = parentDirectoryName.rfind('/');
315        }
316
317        if(lastSlash != std::string::npos)
318        {
319                // the target directory is a deep path, remove the last
320                // directory name and check that the resulting parent
321                // exists, otherwise the restore should fail.
322                parentDirectoryName.resize(lastSlash);
323
324                #ifdef WIN32
325                        // if the path is a drive letter, then we need to
326                        // add a a backslash to query the root directory.
327                        if (lastSlash == 2 && parentDirectoryName[1] == ':')
328                        {
329                                parentDirectoryName += '\\';
330                        }
331                        else if (lastSlash == 0)
332                        {
333                                parentDirectoryName += '\\';
334                        }
335                #endif
336
337                int parentExists;
338
339                try
340                {
341                        parentExists = ObjectExists(parentDirectoryName.c_str());
342                }
343                catch (BoxException &e)
344                {
345                        BOX_ERROR("Failed to check existence for " <<
346                                parentDirectoryName << ": " << e.what());
347                        return Restore_UnknownError;
348                }
349                catch(std::exception &e)
350                {
351                        BOX_ERROR("Failed to check existence for " <<
352                                parentDirectoryName << ": " << e.what());
353                        return Restore_UnknownError;
354                }
355                catch(...)
356                {
357                        BOX_ERROR("Failed to check existence for " <<
358                                parentDirectoryName << ": unknown error");
359                        return Restore_UnknownError;
360                }
361
362                switch(parentExists)
363                {
364                        case ObjectExists_Dir:
365                                // this is fine, do nothing
366                                break;
367
368                        case ObjectExists_File:
369                                BOX_ERROR("Failed to restore: '" <<
370                                        parentDirectoryName << "' "
371                                        "is a file, but should be a "
372                                        "directory.");
373                                return Restore_TargetPathNotFound;
374
375                        case ObjectExists_NoObject:
376                                BOX_ERROR("Failed to restore: parent '" <<
377                                        parentDirectoryName << "' of target "
378                                        "directory does not exist.");
379                                return Restore_TargetPathNotFound;
380
381                        default:
382                                BOX_ERROR("Failed to restore: unknown "
383                                        "result from ObjectExists('" <<
384                                        parentDirectoryName << "')");
385                                return Restore_UnknownError;
386                }
387        }
388
389        if((exists == ObjectExists_NoObject ||
390                exists == ObjectExists_File) && 
391                ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
392        {
393                BOX_LOG_SYS_ERROR("Failed to create directory '" <<
394                        rLocalDirectoryName << "'");
395
396                if (Params.ContinueAfterErrors)
397                {
398                        Params.ContinuedAfterError = true;
399                }
400                else
401                {
402                        return Restore_UnknownError;
403                }
404        }
405
406        // Save the restore info, in case it's needed later
407        try
408        {
409                Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
410        }
411        catch(std::exception &e)
412        {
413                BOX_ERROR("Failed to save resume info file '" <<
414                        Params.mRestoreResumeInfoFilename << "': " <<
415                        e.what());
416
417                if (Params.ContinueAfterErrors)
418                {
419                        Params.ContinuedAfterError = true;
420                }
421                else
422                {
423                        return Restore_UnknownError;
424                }
425        }
426        catch(...)
427        {
428                BOX_ERROR("Failed to save resume info file '" <<
429                        Params.mRestoreResumeInfoFilename <<
430                        "': unknown error");
431
432                if (Params.ContinueAfterErrors)
433                {
434                        Params.ContinuedAfterError = true;
435                }
436                else
437                {
438                        return Restore_UnknownError;
439                }
440        }
441
442        // Fetch the directory listing from the server -- getting a
443        // list of files which is appropriate to the restore type
444        rConnection.QueryListDirectory(
445                DirectoryID,
446                Params.RestoreDeleted?(BackupProtocolListDirectory::Flags_Deleted):(BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING),
447                BackupProtocolListDirectory::Flags_OldVersion | (Params.RestoreDeleted?(0):(BackupProtocolListDirectory::Flags_Deleted)),
448                true /* want attributes */);
449
450        // Retrieve the directory from the stream following
451        BackupStoreDirectory dir;
452        std::auto_ptr<IOStream> dirstream(rConnection.ReceiveStream());
453        dir.ReadFromStream(*dirstream, rConnection.GetTimeout());
454
455        // Apply attributes to the directory
456        const StreamableMemBlock &dirAttrBlock(dir.GetAttributes());
457        BackupClientFileAttributes dirAttr(dirAttrBlock);
458
459        try
460        {
461                dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), true);
462        }
463        catch(std::exception &e)
464        {
465                BOX_ERROR("Failed to restore attributes for '" <<
466                        rLocalDirectoryName << "': " << e.what());
467
468                if (Params.ContinueAfterErrors)
469                {
470                        Params.ContinuedAfterError = true;
471                }
472                else
473                {
474                        return Restore_UnknownError;
475                }
476        }
477        catch(...)
478        {
479                BOX_ERROR("Failed to restore attributes for '" <<
480                        rLocalDirectoryName << "': unknown error");
481
482                if (Params.ContinueAfterErrors)
483                {
484                        Params.ContinuedAfterError = true;
485                }
486                else
487                {
488                        return Restore_UnknownError;
489                }
490        }
491
492        int64_t bytesWrittenSinceLastRestoreInfoSave = 0;
493       
494        // Process files
495        {
496                BackupStoreDirectory::Iterator i(dir);
497                BackupStoreDirectory::Entry *en = 0;
498                while((en = i.Next(BackupStoreDirectory::Entry::Flags_File))
499                        != 0)
500                {
501                        // Check ID hasn't already been done
502                        if(rLevel.mRestoredObjects.find(en->GetObjectID())
503                                == rLevel.mRestoredObjects.end())
504                        {
505                                // Local name
506                                BackupStoreFilenameClear nm(en->GetName());
507                                std::string localFilename(rLocalDirectoryName +
508                                        DIRECTORY_SEPARATOR_ASCHAR +
509                                        nm.GetClearFilename());
510                               
511                                // Unlink anything which already exists:
512                                // For resuming restores, we can't overwrite
513                                // files already there.
514                                if(ObjectExists(localFilename)
515                                        != ObjectExists_NoObject &&
516                                        ::unlink(localFilename.c_str()) != 0)
517                                {
518                                        BOX_LOG_SYS_ERROR("Failed to delete "
519                                                "file '" << localFilename << 
520                                                "'");
521
522                                        if (Params.ContinueAfterErrors)
523                                        {
524                                                Params.ContinuedAfterError = true;
525                                        }
526                                        else
527                                        {
528                                                return Restore_UnknownError;
529                                        }
530                                }
531                               
532                                BOX_TRACE("Restoring file: " <<
533                                        rRemoteDirectoryName + '/' + 
534                                        nm.GetClearFilename() << " (" <<
535                                        en->GetSizeInBlocks() << " blocks)");
536
537                                // Request it from the store
538                                rConnection.QueryGetFile(DirectoryID,
539                                        en->GetObjectID());
540               
541                                // Stream containing encoded file
542                                std::auto_ptr<IOStream> objectStream(
543                                        rConnection.ReceiveStream());
544               
545                                // Decode the file -- need to do different
546                                // things depending on whether the directory
547                                // entry has additional attributes
548                                try
549                                {
550                                        if(en->HasAttributes())
551                                        {
552                                                // Use these attributes
553                                                const StreamableMemBlock &storeAttr(en->GetAttributes());
554                                                BackupClientFileAttributes attr(storeAttr);
555                                                BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout(), &attr);
556                                        }
557                                        else
558                                        {
559                                                // Use attributes stored in file
560                                                BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout());
561                                        }
562                                }
563                                catch(std::exception &e)
564                                {
565                                        BOX_ERROR("Failed to restore file '" <<
566                                                localFilename << "': " <<
567                                                e.what());
568
569                                        if (Params.ContinueAfterErrors)
570                                        {
571                                                Params.ContinuedAfterError = true;
572                                                // ensure that protocol remains usable
573                                                objectStream->Flush();
574                                        }
575                                        else
576                                        {
577                                                return Restore_UnknownError;
578                                        }
579                                }
580                                catch(...)
581                                {
582                                        BOX_ERROR("Failed to restore file '" <<
583                                                localFilename <<
584                                                "': unknown error");
585
586                                        if (Params.ContinueAfterErrors)
587                                        {
588                                                Params.ContinuedAfterError = true;
589                                        }
590                                        else
591                                        {
592                                                return Restore_UnknownError;
593                                        }
594                                }
595                               
596                                // Progress display?
597                                if(Params.PrintDots)
598                                {
599                                        printf(".");
600                                        fflush(stdout);
601                                }
602
603                                // Add it to the list of done itmes
604                                rLevel.mRestoredObjects.insert(en->GetObjectID());
605                               
606                                // Save restore info?
607                                int64_t fileSize;
608                                bool exists = false;
609
610                                try
611                                {
612                                        exists = FileExists(
613                                                localFilename.c_str(),
614                                                &fileSize, 
615                                                true /* treat links as not
616                                                        existing */);
617                                }
618                                catch(std::exception &e)
619                                {
620                                        BOX_ERROR("Failed to determine "
621                                                "whether file exists: '" <<
622                                                localFilename << "': " <<
623                                                e.what());
624
625                                        if (Params.ContinueAfterErrors)
626                                        {
627                                                Params.ContinuedAfterError = true;
628                                        }
629                                        else
630                                        {
631                                                return Restore_UnknownError;
632                                        }
633                                }
634                                catch(...)
635                                {
636                                        BOX_ERROR("Failed to determine "
637                                                "whether file exists: '" <<
638                                                localFilename << "': "
639                                                "unknown error");
640
641                                        if (Params.ContinueAfterErrors)
642                                        {
643                                                Params.ContinuedAfterError = true;
644                                        }
645                                        else
646                                        {
647                                                return Restore_UnknownError;
648                                        }
649                                }
650
651                                if(exists)
652                                {
653                                        // File exists...
654                                        bytesWrittenSinceLastRestoreInfoSave
655                                                += fileSize;
656                                       
657                                        if(bytesWrittenSinceLastRestoreInfoSave > MAX_BYTES_WRITTEN_BETWEEN_RESTORE_INFO_SAVES)
658                                        {
659                                                // Save the restore info, in
660                                                // case it's needed later
661                                                try
662                                                {
663                                                        Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
664                                                }
665                                                catch(std::exception &e)
666                                                {
667                                                        BOX_ERROR("Failed to save resume info file '" <<
668                                                                Params.mRestoreResumeInfoFilename <<
669                                                                "': " << e.what());
670                                                        return Restore_UnknownError;
671                                                }
672                                                catch(...)
673                                                {
674                                                        BOX_ERROR("Failed to save resume info file '" <<
675                                                                Params.mRestoreResumeInfoFilename <<
676                                                                "': unknown error");
677                                                        return Restore_UnknownError;
678                                                }
679
680                                                bytesWrittenSinceLastRestoreInfoSave = 0;
681                                        }
682                                }
683                        }
684                }
685        }
686
687        // Make sure the restore info has been saved   
688        if(bytesWrittenSinceLastRestoreInfoSave != 0)
689        {
690                // Save the restore info, in case it's needed later
691                try
692                {
693                        Params.mResumeInfo.Save(
694                                Params.mRestoreResumeInfoFilename);
695                }
696                catch(std::exception &e)
697                {
698                        BOX_ERROR("Failed to save resume info file '" <<
699                                Params.mRestoreResumeInfoFilename << "': " <<
700                                e.what());
701                        if (Params.ContinueAfterErrors)
702                        {
703                                Params.ContinuedAfterError = true;
704                        }
705                        else
706                        {
707                                return Restore_UnknownError;
708                        }
709                }
710                catch(...)
711                {
712                        BOX_ERROR("Failed to save resume info file '" <<
713                                Params.mRestoreResumeInfoFilename <<
714                                "': unknown error");
715                        if (Params.ContinueAfterErrors)
716                        {
717                                Params.ContinuedAfterError = true;
718                        }
719                        else
720                        {
721                                return Restore_UnknownError;
722                        }
723                }
724               
725                bytesWrittenSinceLastRestoreInfoSave = 0;
726        }
727
728       
729        // Recurse to directories
730        {
731                BackupStoreDirectory::Iterator i(dir);
732                BackupStoreDirectory::Entry *en = 0;
733                while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir))
734                        != 0)
735                {
736                        // Check ID hasn't already been done
737                        if(rLevel.mRestoredObjects.find(en->GetObjectID())
738                                == rLevel.mRestoredObjects.end())
739                        {
740                                // Local name
741                                BackupStoreFilenameClear nm(en->GetName());
742                                std::string localDirname(rLocalDirectoryName
743                                        + DIRECTORY_SEPARATOR_ASCHAR
744                                        + nm.GetClearFilename());
745                               
746                                // Add the level for the next entry
747                                RestoreResumeInfo &rnextLevel(
748                                        rLevel.AddLevel(en->GetObjectID(),
749                                                nm.GetClearFilename()));
750                               
751                                // Recurse
752
753                                BOX_TRACE("Entering directory: " <<
754                                        rRemoteDirectoryName + '/' + 
755                                        nm.GetClearFilename());
756
757                                int result = BackupClientRestoreDir(
758                                        rConnection, en->GetObjectID(), 
759                                        rRemoteDirectoryName + '/' + 
760                                        nm.GetClearFilename(), localDirname,
761                                        Params, rnextLevel);
762
763                                if (result != Restore_Complete)
764                                {
765                                        return result;
766                                }
767                               
768                                // Remove the level for the above call
769                                rLevel.RemoveLevel();
770                               
771                                // Add it to the list of done itmes
772                                rLevel.mRestoredObjects.insert(en->GetObjectID());
773                        }
774                }
775        }
776
777        // now remove the user writable flag, if we added it earlier
778        try
779        {
780                dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), false);
781        }
782        catch(std::exception &e)
783        {
784                BOX_ERROR("Failed to restore attributes for '" <<
785                        rLocalDirectoryName << "': " << e.what());
786                if (Params.ContinueAfterErrors)
787                {
788                        Params.ContinuedAfterError = true;
789                }
790                else
791                {
792                        return Restore_UnknownError;
793                }
794        }
795        catch(...)
796        {
797                BOX_ERROR("Failed to restore attributes for '" <<
798                        rLocalDirectoryName << "': unknown error");
799                if (Params.ContinueAfterErrors)
800                {
801                        Params.ContinuedAfterError = true;
802                }
803                else
804                {
805                        return Restore_UnknownError;
806                }
807        }
808
809        return Restore_Complete;
810}
811
812
813// --------------------------------------------------------------------------
814//
815// Function
816//              Name:    BackupClientRestore(BackupProtocolClient &, int64_t,
817//                       const char *, bool, bool, bool, bool, bool)
818//              Purpose: Restore a directory on the server to a local
819//                       directory on the disc. The local directory must not
820//                       already exist.
821//
822//                       If a restore is aborted for any reason, then it may
823//                       be resumed if Resume == true. If Resume == false
824//                       and resumption is possible, then
825//                       Restore_ResumePossible is returned.
826//
827//                       Set RestoreDeleted to restore a deleted directory.
828//                       This may not give the directory structure when it
829//                       was deleted, because files may have been deleted
830//                       within it before it was deleted.
831//
832//                       Returns Restore_TargetExists if the target
833//                       directory exists, but there is no restore possible.
834//                       (Won't attempt to overwrite things.)
835//
836//                       Returns Restore_Complete on success. (Exceptions
837//                       on error, unless ContinueAfterError is true and
838//                       the error is recoverable, in which case it returns
839//                       Restore_CompleteWithErrors)
840//              Created: 23/11/03
841//
842// --------------------------------------------------------------------------
843int BackupClientRestore(BackupProtocolClient &rConnection,
844        int64_t DirectoryID, const std::string& RemoteDirectoryName,
845        const std::string& LocalDirectoryName, bool PrintDots, bool RestoreDeleted,
846        bool UndeleteAfterRestoreDeleted, bool Resume,
847        bool ContinueAfterErrors)
848{
849        // Parameter block
850        RestoreParams params;
851        params.PrintDots = PrintDots;
852        params.RestoreDeleted = RestoreDeleted;
853        params.ContinueAfterErrors = ContinueAfterErrors;
854        params.ContinuedAfterError = false;
855        params.mRestoreResumeInfoFilename = LocalDirectoryName;
856        params.mRestoreResumeInfoFilename += ".boxbackupresume";
857
858        // Target exists?
859        int targetExistance = ObjectExists(LocalDirectoryName);
860
861        // Does any resumption information exist?
862        bool doingResume = false;
863        if(FileExists(params.mRestoreResumeInfoFilename.c_str()) &&
864                targetExistance == ObjectExists_Dir)
865        {
866                if(!Resume)
867                {
868                        // Caller didn't specify that resume should be done,
869                        // so refuse to do it but say why.
870                        return Restore_ResumePossible;
871                }
872               
873                // Attempt to load the resume info file
874                if(!params.mResumeInfo.Load(params.mRestoreResumeInfoFilename))
875                {
876                        // failed -- bad file, so things have gone a bit wrong
877                        return Restore_TargetExists;
878                }
879               
880                // Flag as doing resume so next check isn't actually performed
881                doingResume = true;
882        }
883
884        // Does the directory already exist?
885        if(targetExistance != ObjectExists_NoObject && !doingResume)
886        {
887                // Don't do anything in this case!
888                return Restore_TargetExists;
889        }
890       
891        // Restore the directory
892        int result = BackupClientRestoreDir(rConnection, DirectoryID, 
893                RemoteDirectoryName, LocalDirectoryName, params,
894                params.mResumeInfo);
895        if (result != Restore_Complete)
896        {
897                return result;
898        }
899
900        // Undelete the directory on the server?
901        if(RestoreDeleted && UndeleteAfterRestoreDeleted)
902        {
903                // Send the command
904                rConnection.QueryUndeleteDirectory(DirectoryID);
905        }
906
907        // Finish progress display?
908        if(PrintDots)
909        {
910                printf("\n");
911                fflush(stdout);
912        }
913       
914        // Delete the resume information file
915        ::unlink(params.mRestoreResumeInfoFilename.c_str());
916
917        return params.ContinuedAfterError ? Restore_CompleteWithErrors
918                : Restore_Complete;
919}
920
Note: See TracBrowser for help on using the repository browser.