source: box/trunk/lib/backupstore/BackupCommands.cpp @ 3049

Revision 3049, 29.7 KB checked in by chris, 5 months ago (diff)

Add remote host and port to post-login login message, requested by Pete Jalajas.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupCommands.cpp
5//              Purpose: Implement commands for the Backup store protocol
6//              Created: 2003/08/20
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <set>
13#include <sstream>
14
15#include "autogen_BackupProtocol.h"
16#include "autogen_RaidFileException.h"
17#include "BackupConstants.h"
18#include "BackupStoreContext.h"
19#include "BackupStoreConstants.h"
20#include "BackupStoreDirectory.h"
21#include "BackupStoreException.h"
22#include "BackupStoreFile.h"
23#include "BackupStoreInfo.h"
24#include "BufferedStream.h"
25#include "CollectInBufferStream.h"
26#include "FileStream.h"
27#include "InvisibleTempFileStream.h"
28#include "RaidFileController.h"
29#include "StreamableMemBlock.h"
30
31#include "MemLeakFindOn.h"
32
33#define PROTOCOL_ERROR(code) \
34        std::auto_ptr<BackupProtocolMessage>(new BackupProtocolError( \
35                BackupProtocolError::ErrorType, \
36                BackupProtocolError::code));
37
38#define CHECK_PHASE(phase) \
39        if(rContext.GetPhase() != BackupStoreContext::phase) \
40        { \
41                return PROTOCOL_ERROR(Err_NotInRightProtocolPhase); \
42        }
43
44#define CHECK_WRITEABLE_SESSION \
45        if(rContext.SessionIsReadOnly()) \
46        { \
47                return PROTOCOL_ERROR(Err_SessionReadOnly); \
48        }
49
50// --------------------------------------------------------------------------
51//
52// Function
53//              Name:    BackupProtocolVersion::DoCommand(Protocol &, BackupStoreContext &)
54//              Purpose: Return the current version, or an error if the requested version isn't allowed
55//              Created: 2003/08/20
56//
57// --------------------------------------------------------------------------
58std::auto_ptr<BackupProtocolMessage> BackupProtocolVersion::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
59{
60        CHECK_PHASE(Phase_Version)
61
62        // Correct version?
63        if(mVersion != BACKUP_STORE_SERVER_VERSION)
64        {
65                return PROTOCOL_ERROR(Err_WrongVersion);
66        }
67
68        // Mark the next phase
69        rContext.SetPhase(BackupStoreContext::Phase_Login);
70
71        // Return our version
72        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolVersion(BACKUP_STORE_SERVER_VERSION));
73}
74
75// --------------------------------------------------------------------------
76//
77// Function
78//              Name:    BackupProtocolLogin::DoCommand(Protocol &, BackupStoreContext &)
79//              Purpose: Return the current version, or an error if the requested version isn't allowed
80//              Created: 2003/08/20
81//
82// --------------------------------------------------------------------------
83std::auto_ptr<BackupProtocolMessage> BackupProtocolLogin::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
84{
85        CHECK_PHASE(Phase_Login)
86
87        // Check given client ID against the ID in the certificate certificate
88        // and that the client actually has an account on this machine
89        if(mClientID != rContext.GetClientID())
90        {
91                BOX_WARNING("Failed login from client ID " << 
92                        BOX_FORMAT_ACCOUNT(mClientID) << ": "
93                        "wrong certificate for this account");
94                return PROTOCOL_ERROR(Err_BadLogin);
95        }
96
97        if(!rContext.GetClientHasAccount())
98        {
99                BOX_WARNING("Failed login from client ID " << 
100                        BOX_FORMAT_ACCOUNT(mClientID) << ": "
101                        "no such account on this server");
102                return PROTOCOL_ERROR(Err_BadLogin);
103        }
104
105        // If we need to write, check that nothing else has got a write lock
106        if((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
107        {
108                // See if the context will get the lock
109                if(!rContext.AttemptToGetWriteLock())
110                {
111                        BOX_WARNING("Failed to get write lock for Client ID " <<
112                                BOX_FORMAT_ACCOUNT(mClientID));
113                        return PROTOCOL_ERROR(Err_CannotLockStoreForWriting);
114                }
115               
116                // Debug: check we got the lock
117                ASSERT(!rContext.SessionIsReadOnly());
118        }
119       
120        // Load the store info
121        rContext.LoadStoreInfo();
122
123        // Get the last client store marker
124        int64_t clientStoreMarker = rContext.GetClientStoreMarker();
125
126        // Mark the next phase
127        rContext.SetPhase(BackupStoreContext::Phase_Commands);
128       
129        // Log login
130        BOX_NOTICE("Login from Client ID " << 
131                BOX_FORMAT_ACCOUNT(mClientID) << " "
132                "(name=" << rContext.GetAccountName() << "): " <<
133                (((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
134                        ?"Read/Write":"Read-only") << " from " <<
135                rContext.GetConnectionDetails());
136
137        // Get the usage info for reporting to the client
138        int64_t blocksUsed = 0, blocksSoftLimit = 0, blocksHardLimit = 0;
139        rContext.GetStoreDiscUsageInfo(blocksUsed, blocksSoftLimit, blocksHardLimit);
140
141        // Return success
142        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolLoginConfirmed(clientStoreMarker, blocksUsed, blocksSoftLimit, blocksHardLimit));
143}
144
145// --------------------------------------------------------------------------
146//
147// Function
148//              Name:    BackupProtocolFinished::DoCommand(Protocol &, BackupStoreContext &)
149//              Purpose: Marks end of conversation (Protocol framework handles this)
150//              Created: 2003/08/20
151//
152// --------------------------------------------------------------------------
153std::auto_ptr<BackupProtocolMessage> BackupProtocolFinished::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
154{
155        BOX_NOTICE("Session finished for Client ID " << 
156                BOX_FORMAT_ACCOUNT(rContext.GetClientID()) << " "
157                "(name=" << rContext.GetAccountName() << ")");
158
159        // Let the context know about it
160        rContext.ReceivedFinishCommand();
161
162        // can be called in any phase
163        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolFinished);
164}
165
166
167// --------------------------------------------------------------------------
168//
169// Function
170//              Name:    BackupProtocolListDirectory::DoCommand(Protocol &, BackupStoreContext &)
171//              Purpose: Command to list a directory
172//              Created: 2003/09/02
173//
174// --------------------------------------------------------------------------
175std::auto_ptr<BackupProtocolMessage> BackupProtocolListDirectory::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
176{
177        CHECK_PHASE(Phase_Commands)
178
179        // Store the listing to a stream
180        std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
181
182        try
183        {
184                // Ask the context for a directory
185                const BackupStoreDirectory &rdir(
186                        rContext.GetDirectory(mObjectID));
187                rdir.WriteToStream(*stream, mFlagsMustBeSet, 
188                        mFlagsNotToBeSet, mSendAttributes,
189                        false /* never send dependency info to the client */);
190        }
191        catch (RaidFileException &e)
192        {
193                if (e.GetSubType() == RaidFileException::RaidFileDoesntExist)
194                {
195                        return PROTOCOL_ERROR(Err_DoesNotExist);
196                }
197                throw;
198        }
199
200        stream->SetForReading();
201       
202        // Get the protocol to send the stream
203        rProtocol.SendStreamAfterCommand(stream.release());
204
205        return std::auto_ptr<BackupProtocolMessage>(
206                new BackupProtocolSuccess(mObjectID));
207}
208
209// --------------------------------------------------------------------------
210//
211// Function
212//              Name:    BackupProtocolStoreFile::DoCommand(Protocol &, BackupStoreContext &)
213//              Purpose: Command to store a file on the server
214//              Created: 2003/09/02
215//
216// --------------------------------------------------------------------------
217std::auto_ptr<BackupProtocolMessage> BackupProtocolStoreFile::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
218{
219        CHECK_PHASE(Phase_Commands)
220        CHECK_WRITEABLE_SESSION
221
222        std::auto_ptr<BackupProtocolMessage> hookResult =
223                rContext.StartCommandHook(*this);
224        if(hookResult.get())
225        {
226                return hookResult;
227        }
228       
229        // Check that the diff from file actually exists, if it's specified
230        if(mDiffFromFileID != 0)
231        {
232                if(!rContext.ObjectExists(mDiffFromFileID,
233                        BackupStoreContext::ObjectExists_File))
234                {
235                        return PROTOCOL_ERROR(Err_DiffFromFileDoesNotExist);
236                }
237        }
238       
239        // A stream follows, which contains the file
240        std::auto_ptr<IOStream> dirstream(rProtocol.ReceiveStream());
241       
242        // Ask the context to store it
243        int64_t id = 0;
244        try
245        {
246                id = rContext.AddFile(*dirstream, mDirectoryObjectID,
247                        mModificationTime, mAttributesHash, mDiffFromFileID,
248                        mFilename,
249                        true /* mark files with same name as old versions */);
250        }
251        catch(BackupStoreException &e)
252        {
253                if(e.GetSubType() == BackupStoreException::AddedFileDoesNotVerify)
254                {
255                        return PROTOCOL_ERROR(Err_FileDoesNotVerify);
256                }
257                else if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
258                {
259                        return PROTOCOL_ERROR(Err_StorageLimitExceeded);
260                }
261                else
262                {
263                        throw;
264                }
265        }
266       
267        // Tell the caller what the file was
268        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(id));
269}
270
271
272
273
274// --------------------------------------------------------------------------
275//
276// Function
277//              Name:    BackupProtocolGetObject::DoCommand(Protocol &, BackupStoreContext &)
278//              Purpose: Command to get an arbitary object from the server
279//              Created: 2003/09/03
280//
281// --------------------------------------------------------------------------
282std::auto_ptr<BackupProtocolMessage> BackupProtocolGetObject::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
283{
284        CHECK_PHASE(Phase_Commands)
285
286        // Check the object exists
287        if(!rContext.ObjectExists(mObjectID))
288        {
289                return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(NoObject));
290        }
291
292        // Open the object
293        std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
294
295        // Stream it to the peer
296        rProtocol.SendStreamAfterCommand(object.release());
297
298        // Tell the caller what the file was
299        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
300}
301
302// --------------------------------------------------------------------------
303//
304// Function
305//              Name:    BackupProtocolGetFile::DoCommand(Protocol &, BackupStoreContext &)
306//              Purpose: Command to get an file object from the server -- may have to do a bit of
307//                               work to get the object.
308//              Created: 2003/09/03
309//
310// --------------------------------------------------------------------------
311std::auto_ptr<BackupProtocolMessage> BackupProtocolGetFile::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
312{
313        CHECK_PHASE(Phase_Commands)
314
315        // Check the objects exist
316        if(!rContext.ObjectExists(mObjectID)
317                || !rContext.ObjectExists(mInDirectory))
318        {
319                return PROTOCOL_ERROR(Err_DoesNotExist);
320        }
321
322        // Get the directory it's in
323        const BackupStoreDirectory &rdir(rContext.GetDirectory(mInDirectory));
324
325        // Find the object within the directory
326        BackupStoreDirectory::Entry *pfileEntry = rdir.FindEntryByID(mObjectID);
327        if(pfileEntry == 0)
328        {
329                return PROTOCOL_ERROR(Err_DoesNotExistInDirectory);
330        }
331
332        // The result
333        std::auto_ptr<IOStream> stream;
334
335        // Does this depend on anything?
336        if(pfileEntry->GetDependsNewer() != 0)
337        {
338                // File exists, but is a patch from a new version. Generate the older version.
339                std::vector<int64_t> patchChain;
340                int64_t id = mObjectID;
341                BackupStoreDirectory::Entry *en = 0;
342                do
343                {
344                        patchChain.push_back(id);
345                        en = rdir.FindEntryByID(id);
346                        if(en == 0)
347                        {
348                                BOX_ERROR("Object " << 
349                                        BOX_FORMAT_OBJECTID(mObjectID) <<
350                                        " in dir " << 
351                                        BOX_FORMAT_OBJECTID(mInDirectory) <<
352                                        " for account " <<
353                                        BOX_FORMAT_ACCOUNT(rContext.GetClientID()) <<
354                                        " references object " << 
355                                        BOX_FORMAT_OBJECTID(id) <<
356                                        " which does not exist in dir");
357                                return PROTOCOL_ERROR(Err_PatchConsistencyError);
358                        }
359                        id = en->GetDependsNewer();
360                }
361                while(en != 0 && id != 0);
362               
363                // OK! The last entry in the chain is the full file, the others are patches back from it.
364                // Open the last one, which is the current from file
365                std::auto_ptr<IOStream> from(rContext.OpenObject(patchChain[patchChain.size() - 1]));
366               
367                // Then, for each patch in the chain, do a combine
368                for(int p = ((int)patchChain.size()) - 2; p >= 0; --p)
369                {
370                        // ID of patch
371                        int64_t patchID = patchChain[p];
372                       
373                        // Open it a couple of times
374                        std::auto_ptr<IOStream> diff(rContext.OpenObject(patchID));
375                        std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID));
376                       
377                        // Choose a temporary filename for the result of the combination
378                        std::ostringstream fs;
379                        fs << rContext.GetStoreRoot() << ".recombinetemp." << p;
380                        std::string tempFn = 
381                                RaidFileController::DiscSetPathToFileSystemPath(
382                                        rContext.GetStoreDiscSet(), fs.str(),
383                                        p + 16);
384                       
385                        // Open the temporary file
386                        std::auto_ptr<IOStream> combined;
387                        try
388                        {
389                                {
390                                        // Write nastily to allow this to work with gcc 2.x
391                                        std::auto_ptr<IOStream> t(
392                                                new InvisibleTempFileStream(
393                                                        tempFn.c_str(), 
394                                                        O_RDWR | O_CREAT | 
395                                                        O_EXCL | O_BINARY | 
396                                                        O_TRUNC));
397                                        combined = t;
398                                }
399                        }
400                        catch(...)
401                        {
402                                // Make sure it goes
403                                ::unlink(tempFn.c_str());
404                                throw;
405                        }
406                       
407                        // Do the combining
408                        BackupStoreFile::CombineFile(*diff, *diff2, *from, *combined);
409                       
410                        // Move to the beginning of the combined file
411                        combined->Seek(0, IOStream::SeekType_Absolute);
412                       
413                        // Then shuffle round for the next go
414                        if (from.get()) from->Close();
415                        from = combined;
416                }
417               
418                // Now, from contains a nice file to send to the client. Reorder it
419                {
420                        // Write nastily to allow this to work with gcc 2.x
421                        std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(from.get(), true /* take ownership */));
422                        stream = t;
423                }
424               
425                // Release from file to avoid double deletion
426                from.release();
427        }
428        else
429        {
430                // Simple case: file already exists on disc ready to go
431       
432                // Open the object
433                std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
434                BufferedStream buf(*object);
435               
436                // Verify it
437                if(!BackupStoreFile::VerifyEncodedFileFormat(buf))
438                {
439                        return PROTOCOL_ERROR(Err_FileDoesNotVerify);
440                }
441               
442                // Reset stream -- seek to beginning
443                object->Seek(0, IOStream::SeekType_Absolute);
444               
445                // Reorder the stream/file into stream order
446                {
447                        // Write nastily to allow this to work with gcc 2.x
448                        std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(object.get(), true /* take ownership */));
449                        stream = t;
450                }
451
452                // Object will be deleted when the stream is deleted,
453                // so can release the object auto_ptr here to avoid
454                // premature deletion
455                object.release();
456        }
457
458        // Stream the reordered stream to the peer
459        rProtocol.SendStreamAfterCommand(stream.get());
460       
461        // Don't delete the stream here
462        stream.release();
463
464        // Tell the caller what the file was
465        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
466}
467
468
469// --------------------------------------------------------------------------
470//
471// Function
472//              Name:    BackupProtocolCreateDirectory::DoCommand(Protocol &, BackupStoreContext &)
473//              Purpose: Create directory command
474//              Created: 2003/09/04
475//
476// --------------------------------------------------------------------------
477std::auto_ptr<BackupProtocolMessage> BackupProtocolCreateDirectory::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
478{
479        CHECK_PHASE(Phase_Commands)
480        CHECK_WRITEABLE_SESSION
481       
482        // Get the stream containing the attributes
483        std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
484        // Collect the attributes -- do this now so no matter what the outcome,
485        // the data has been absorbed.
486        StreamableMemBlock attr;
487        attr.Set(*attrstream, rProtocol.GetTimeout());
488       
489        // Check to see if the hard limit has been exceeded
490        if(rContext.HardLimitExceeded())
491        {
492                // Won't allow creation if the limit has been exceeded
493                return PROTOCOL_ERROR(Err_StorageLimitExceeded);
494        }
495
496        bool alreadyExists = false;
497        int64_t id = rContext.AddDirectory(mContainingDirectoryID, mDirectoryName, attr, mAttributesModTime, alreadyExists);
498       
499        if(alreadyExists)
500        {
501                return PROTOCOL_ERROR(Err_DirectoryAlreadyExists);
502        }
503
504        // Tell the caller what the file was
505        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(id));
506}
507
508
509
510// --------------------------------------------------------------------------
511//
512// Function
513//              Name:    BackupProtocolChangeDirAttributes::DoCommand(Protocol &, BackupStoreContext &)
514//              Purpose: Change attributes on directory
515//              Created: 2003/09/06
516//
517// --------------------------------------------------------------------------
518std::auto_ptr<BackupProtocolMessage> BackupProtocolChangeDirAttributes::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
519{
520        CHECK_PHASE(Phase_Commands)
521        CHECK_WRITEABLE_SESSION
522
523        // Get the stream containing the attributes
524        std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
525        // Collect the attributes -- do this now so no matter what the outcome,
526        // the data has been absorbed.
527        StreamableMemBlock attr;
528        attr.Set(*attrstream, rProtocol.GetTimeout());
529
530        // Get the context to do it's magic
531        rContext.ChangeDirAttributes(mObjectID, attr, mAttributesModTime);
532
533        // Tell the caller what the file was
534        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
535}
536
537
538// --------------------------------------------------------------------------
539//
540// Function
541//              Name:    BackupProtocolSetReplacementFileAttributes::DoCommand(Protocol &, BackupStoreContext &)
542//              Purpose: Change attributes on directory
543//              Created: 2003/09/06
544//
545// --------------------------------------------------------------------------
546std::auto_ptr<BackupProtocolMessage> BackupProtocolSetReplacementFileAttributes::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
547{
548        CHECK_PHASE(Phase_Commands)
549        CHECK_WRITEABLE_SESSION
550
551        // Get the stream containing the attributes
552        std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
553        // Collect the attributes -- do this now so no matter what the outcome,
554        // the data has been absorbed.
555        StreamableMemBlock attr;
556        attr.Set(*attrstream, rProtocol.GetTimeout());
557
558        // Get the context to do it's magic
559        int64_t objectID = 0;
560        if(!rContext.ChangeFileAttributes(mFilename, mInDirectory, attr, mAttributesHash, objectID))
561        {
562                // Didn't exist
563                return PROTOCOL_ERROR(Err_DoesNotExist);
564        }
565
566        // Tell the caller what the file was
567        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(objectID));
568}
569
570
571
572// --------------------------------------------------------------------------
573//
574// Function
575//              Name:    BackupProtocolDeleteFile::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
576//              Purpose: Delete a file
577//              Created: 2003/10/21
578//
579// --------------------------------------------------------------------------
580std::auto_ptr<BackupProtocolMessage> BackupProtocolDeleteFile::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
581{
582        CHECK_PHASE(Phase_Commands)
583        CHECK_WRITEABLE_SESSION
584
585        // Context handles this
586        int64_t objectID = 0;
587        rContext.DeleteFile(mFilename, mInDirectory, objectID);
588
589        // return the object ID or zero for not found
590        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(objectID));
591}
592
593
594// --------------------------------------------------------------------------
595//
596// Function
597//              Name:    BackupProtocolUndeleteFile::DoCommand(
598//                       BackupProtocolBase &, BackupStoreContext &)
599//              Purpose: Undelete a file
600//              Created: 2008-09-12
601//
602// --------------------------------------------------------------------------
603std::auto_ptr<BackupProtocolMessage> BackupProtocolUndeleteFile::DoCommand(
604        BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
605{
606        CHECK_PHASE(Phase_Commands)
607        CHECK_WRITEABLE_SESSION
608
609        // Context handles this
610        bool result = rContext.UndeleteFile(mObjectID, mInDirectory);
611
612        // return the object ID or zero for not found
613        return std::auto_ptr<BackupProtocolMessage>(
614                new BackupProtocolSuccess(result ? mObjectID : 0));
615}
616
617
618// --------------------------------------------------------------------------
619//
620// Function
621//              Name:    BackupProtocolDeleteDirectory::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
622//              Purpose: Delete a directory
623//              Created: 2003/10/21
624//
625// --------------------------------------------------------------------------
626std::auto_ptr<BackupProtocolMessage> BackupProtocolDeleteDirectory::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
627{
628        CHECK_PHASE(Phase_Commands)
629        CHECK_WRITEABLE_SESSION
630
631        // Check it's not asking for the root directory to be deleted
632        if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
633        {
634                return PROTOCOL_ERROR(Err_CannotDeleteRoot);
635        }
636
637        // Context handles this
638        try
639        {
640                rContext.DeleteDirectory(mObjectID);
641        }
642        catch (BackupStoreException &e)
643        {
644                if(e.GetSubType() == BackupStoreException::MultiplyReferencedObject)
645                {
646                        return PROTOCOL_ERROR(Err_MultiplyReferencedObject);
647                }
648               
649                throw;
650        }
651
652        // return the object ID
653        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
654}
655
656
657// --------------------------------------------------------------------------
658//
659// Function
660//              Name:    BackupProtocolUndeleteDirectory::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
661//              Purpose: Undelete a directory
662//              Created: 23/11/03
663//
664// --------------------------------------------------------------------------
665std::auto_ptr<BackupProtocolMessage> BackupProtocolUndeleteDirectory::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
666{
667        CHECK_PHASE(Phase_Commands)
668        CHECK_WRITEABLE_SESSION
669
670        // Check it's not asking for the root directory to be deleted
671        if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
672        {
673                return PROTOCOL_ERROR(Err_CannotDeleteRoot);
674        }
675
676        // Context handles this
677        rContext.DeleteDirectory(mObjectID, true /* undelete */);
678
679        // return the object ID
680        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
681}
682
683// --------------------------------------------------------------------------
684//
685// Function
686//              Name:    BackupProtocolSetClientStoreMarker::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
687//              Purpose: Command to set the client's store marker
688//              Created: 2003/10/29
689//
690// --------------------------------------------------------------------------
691std::auto_ptr<BackupProtocolMessage> BackupProtocolSetClientStoreMarker::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
692{
693        CHECK_PHASE(Phase_Commands)
694        CHECK_WRITEABLE_SESSION
695
696        // Set the marker
697        rContext.SetClientStoreMarker(mClientStoreMarker);
698
699        // return store marker set
700        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mClientStoreMarker));
701}
702
703
704// --------------------------------------------------------------------------
705//
706// Function
707//              Name:    BackupProtocolMoveObject::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
708//              Purpose: Command to move an object from one directory to another
709//              Created: 2003/11/12
710//
711// --------------------------------------------------------------------------
712std::auto_ptr<BackupProtocolMessage> BackupProtocolMoveObject::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
713{
714        CHECK_PHASE(Phase_Commands)
715        CHECK_WRITEABLE_SESSION
716       
717        // Let context do this, but modify error reporting on exceptions...
718        try
719        {
720                rContext.MoveObject(mObjectID, mMoveFromDirectory, mMoveToDirectory,
721                        mNewFilename, (mFlags & Flags_MoveAllWithSameName) == Flags_MoveAllWithSameName,
722                        (mFlags & Flags_AllowMoveOverDeletedObject) == Flags_AllowMoveOverDeletedObject);
723        }
724        catch(BackupStoreException &e)
725        {
726                if(e.GetSubType() == BackupStoreException::CouldNotFindEntryInDirectory)
727                {
728                        return PROTOCOL_ERROR(Err_DoesNotExist);
729                }
730                else if(e.GetSubType() == BackupStoreException::NameAlreadyExistsInDirectory)
731                {
732                        return PROTOCOL_ERROR(Err_TargetNameExists);
733                }
734                else
735                {
736                        throw;
737                }
738        }
739
740        // Return the object ID
741        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
742}
743
744
745// --------------------------------------------------------------------------
746//
747// Function
748//              Name:    BackupProtocolGetObjectName::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
749//              Purpose: Command to find the name of an object
750//              Created: 12/11/03
751//
752// --------------------------------------------------------------------------
753std::auto_ptr<BackupProtocolMessage> BackupProtocolGetObjectName::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
754{
755        CHECK_PHASE(Phase_Commands)
756       
757        // Create a stream for the list of filenames
758        std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
759
760        // Object and directory IDs
761        int64_t objectID = mObjectID;
762        int64_t dirID = mContainingDirectoryID;
763       
764        // Data to return in the reply
765        int32_t numNameElements = 0;
766        int16_t objectFlags = 0;
767        int64_t modTime = 0;
768        uint64_t attrModHash = 0;
769        bool haveModTimes = false;
770       
771        do
772        {
773                // Check the directory really exists
774                if(!rContext.ObjectExists(dirID, BackupStoreContext::ObjectExists_Directory))
775                {
776                        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolObjectName(BackupProtocolObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
777                }
778
779                // Load up the directory
780                const BackupStoreDirectory &rdir(rContext.GetDirectory(dirID));
781
782                // Find the element in this directory and store it's name
783                if(objectID != ObjectID_DirectoryOnly)
784                {
785                        const BackupStoreDirectory::Entry *en = rdir.FindEntryByID(objectID);
786
787                        // If this can't be found, then there is a problem... tell the caller it can't be found
788                        if(en == 0)
789                        {
790                                // Abort!
791                                return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolObjectName(BackupProtocolObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
792                        }
793                       
794                        // Store flags?
795                        if(objectFlags == 0)
796                        {
797                                objectFlags = en->GetFlags();
798                        }
799                       
800                        // Store modification times?
801                        if(!haveModTimes)
802                        {
803                                modTime = en->GetModificationTime();
804                                attrModHash = en->GetAttributesHash();
805                                haveModTimes = true;
806                        }
807                       
808                        // Store the name in the stream
809                        en->GetName().WriteToStream(*stream);
810                       
811                        // Count of name elements
812                        ++numNameElements;
813                }
814               
815                // Setup for next time round
816                objectID = dirID;
817                dirID = rdir.GetContainerID();
818
819        } while(objectID != 0 && objectID != BACKUPSTORE_ROOT_DIRECTORY_ID);
820
821        // Stream to send?
822        if(numNameElements > 0)
823        {
824                // Get the stream ready to go
825                stream->SetForReading();       
826                // Tell the protocol to send the stream
827                rProtocol.SendStreamAfterCommand(stream.release());
828        }
829
830        // Make reply
831        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolObjectName(numNameElements, modTime, attrModHash, objectFlags));
832}
833
834
835
836// --------------------------------------------------------------------------
837//
838// Function
839//              Name:    BackupProtocolGetBlockIndexByID::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
840//              Purpose: Get the block index from a file, by ID
841//              Created: 19/1/04
842//
843// --------------------------------------------------------------------------
844std::auto_ptr<BackupProtocolMessage> BackupProtocolGetBlockIndexByID::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
845{
846        CHECK_PHASE(Phase_Commands)
847
848        // Open the file
849        std::auto_ptr<IOStream> stream(rContext.OpenObject(mObjectID));
850       
851        // Move the file pointer to the block index
852        BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
853       
854        // Return the stream to the client
855        rProtocol.SendStreamAfterCommand(stream.release());
856
857        // Return the object ID
858        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(mObjectID));
859}
860
861
862// --------------------------------------------------------------------------
863//
864// Function
865//              Name:    BackupProtocolGetBlockIndexByName::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
866//              Purpose: Get the block index from a file, by name within a directory
867//              Created: 19/1/04
868//
869// --------------------------------------------------------------------------
870std::auto_ptr<BackupProtocolMessage> BackupProtocolGetBlockIndexByName::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
871{
872        CHECK_PHASE(Phase_Commands)
873
874        // Get the directory
875        const BackupStoreDirectory &dir(rContext.GetDirectory(mInDirectory));
876       
877        // Find the latest object ID within it which has the same name
878        int64_t objectID = 0;
879        BackupStoreDirectory::Iterator i(dir);
880        BackupStoreDirectory::Entry *en = 0;
881        while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0)
882        {
883                if(en->GetName() == mFilename)
884                {
885                        // Store the ID, if it's a newer ID than the last one
886                        if(en->GetObjectID() > objectID)
887                        {
888                                objectID = en->GetObjectID();
889                        }
890                }
891        }
892       
893        // Found anything?
894        if(objectID == 0)
895        {
896                // No... return a zero object ID
897                return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(0));
898        }
899
900        // Open the file
901        std::auto_ptr<IOStream> stream(rContext.OpenObject(objectID));
902       
903        // Move the file pointer to the block index
904        BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
905       
906        // Return the stream to the client
907        rProtocol.SendStreamAfterCommand(stream.release());
908
909        // Return the object ID
910        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolSuccess(objectID));
911}
912
913
914// --------------------------------------------------------------------------
915//
916// Function
917//              Name:    BackupProtocolGetAccountUsage::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
918//              Purpose: Return the amount of disc space used
919//              Created: 19/4/04
920//
921// --------------------------------------------------------------------------
922std::auto_ptr<BackupProtocolMessage> BackupProtocolGetAccountUsage::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
923{
924        CHECK_PHASE(Phase_Commands)
925
926        // Get store info from context
927        const BackupStoreInfo &rinfo(rContext.GetBackupStoreInfo());
928       
929        // Find block size
930        RaidFileController &rcontroller(RaidFileController::GetController());
931        RaidFileDiscSet &rdiscSet(rcontroller.GetDiscSet(rinfo.GetDiscSetNumber()));
932       
933        // Return info
934        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolAccountUsage(
935                rinfo.GetBlocksUsed(),
936                rinfo.GetBlocksInOldFiles(),
937                rinfo.GetBlocksInDeletedFiles(),
938                rinfo.GetBlocksInDirectories(),
939                rinfo.GetBlocksSoftLimit(),
940                rinfo.GetBlocksHardLimit(),
941                rdiscSet.GetBlockSize()
942        ));
943}
944
945// --------------------------------------------------------------------------
946//
947// Function
948//              Name:    BackupProtocolGetIsAlive::DoCommand(BackupProtocolReplyable &, BackupStoreContext &)
949//              Purpose: Return the amount of disc space used
950//              Created: 19/4/04
951//
952// --------------------------------------------------------------------------
953std::auto_ptr<BackupProtocolMessage> BackupProtocolGetIsAlive::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
954{
955        CHECK_PHASE(Phase_Commands)
956
957        //
958        // NOOP
959        //
960        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolIsAlive());
961}
Note: See TracBrowser for help on using the repository browser.