index.html: add new file
[vss2svn.git] / ssphys / SSPhys / GetCommand.cpp
blob1e171fe092f5cb2571bedb52e2708b23629025b6
1 // GetCommand.cpp: implementation of the GetCommand class.
2 //
3 //////////////////////////////////////////////////////////////////////
5 #include "stdafx.h"
6 #include "GetCommand.h"
7 #include <SSPhysLib\SSFiles.h>
8 #include <SSPhysLib\SSItemInfoObject.h>
9 #include <SSPhysLib\SSVersionObject.h>
10 #include <SSPhysLib\FileName.h>
11 #include <SSPhysLib\SSProjectObject.h>
12 #include <io.h>
13 #include <fcntl.h>
14 #include <fstream>
15 #include <strstream>
17 #include "windows.h"
18 //////////////////////////////////////////////////////////////////////
19 // Construction/Destruction
20 //////////////////////////////////////////////////////////////////////
21 bool fexists (const char* file)
23 FILE* pFile = fopen (file, "r");
24 if (pFile)
26 fclose (pFile);
27 return true;
29 return false;
32 //---------------------------------------------------------------------------
33 CGetCommand::CGetCommand ()
34 : CCommand ("get"),
35 m_Version (-1),
36 m_bForceOverwrite (false),
37 m_bBulkGet (false)
41 COptionInfoList CGetCommand::GetOptionsInfo () const
43 COptionInfoList options = CCommand::GetOptionsInfo();
44 options.push_back (COptionInfo ('v', 'v', "version", "version to get", COptionInfo::requiredArgument));
45 options.push_back (COptionInfo ('f', 'f', "force-overwrite", "overwrite target file", COptionInfo::noArgument));
46 options.push_back (COptionInfo ('b', 'b', "bulk", "bulk operation: get all intermediate files with the same name as the source name", COptionInfo::noArgument));
47 return options;
50 bool CGetCommand::SetOption (const COption& option)
52 switch (option.id)
54 case 'v':
55 m_Version = atoi ((const char*) option.value);
56 break;
57 case 'f':
58 m_bForceOverwrite = true;
59 break;
60 case 'b':
61 m_bBulkGet = true;
62 break;
63 default:
64 return false;
66 return true;
69 bool CGetCommand::SetArguments (CArguments& args)
71 if (args.empty ())
72 throw SSException ("no argument");
74 m_PhysFile = args.front ();
75 args.pop ();
77 if (args.empty ())
78 throw SSException ("missing argument");
80 m_DestFile = args.front ();
81 args.pop ();
83 return true;
88 class CActionVisitor : public ISSActionVisitor
90 public:
91 virtual ~CActionVisitor () {}
93 virtual bool Apply (const SSLabeledAction& rAction) { return Apply ((const SSAction&) rAction); }
94 // virtual bool Apply (const SSSingleFileAction& rAction) { return Apply ((const SSAction&) rAction); }
95 virtual bool Apply (const SSCreatedProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
96 virtual bool Apply (const SSCreatedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
97 virtual bool Apply (const SSAddedProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
98 virtual bool Apply (const SSAddedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
99 virtual bool Apply (const SSDeletedProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
100 virtual bool Apply (const SSDeletedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
101 virtual bool Apply (const SSRecoveredProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
102 virtual bool Apply (const SSRecoveredFileAction& rAction) { return Apply ((const SSAction&) rAction); }
103 virtual bool Apply (const SSRollbackAction& rAction) { return Apply ((const SSAction&) rAction); }
105 virtual bool Apply (const SSDestroyedProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
106 virtual bool Apply (const SSDestroyedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
107 virtual bool Apply (const SSRenamedProjectAction& rAction) { return Apply ((const SSAction&) rAction); }
108 virtual bool Apply (const SSRenamedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
109 virtual bool Apply (const SSCheckedInAction& rAction) { return Apply ((const SSAction&) rAction); }
110 virtual bool Apply (const SSSharedAction& rAction) { return Apply ((const SSAction&) rAction); }
112 protected:
113 virtual bool Apply (const SSAction& rAction)
115 return true;
120 std::string CreateTempFile ( const char* pzPrefix = NULL, const char* pzPath = NULL)
122 return tempnam( pzPath, pzPrefix );
123 // while( true )
125 // std::string cPath = tempnam( pzPath, pzPrefix );
126 // if (Open (cPath, O_RDWR | O_CREAT | O_EXCL ) < 0)
127 // {
128 // if ( errno == EEXIST )
129 // {
130 // continue;
131 // }
132 // else
133 // {
134 //// throw errno_exception( "Failed to create file" );
135 // }
136 // }
137 // else
138 // {
139 // Close ();
140 // break;
141 // }
145 class CAutoFile
147 public:
148 CAutoFile (std::string name, bool bDelete = true)
149 : m_FileName (name),
150 m_bDeleteFile (bDelete)
154 CAutoFile (CAutoFile const & r)
155 : m_bDeleteFile (r.m_bDeleteFile),
156 m_FileName (r.Detatch ())
160 CAutoFile& operator= (CAutoFile const & r)
162 if (this != &r)
164 if (m_FileName != r.GetPath())
166 if (m_bDeleteFile)
167 Unlink ();
168 m_bDeleteFile = r.m_bDeleteFile;
170 else if (r.m_bDeleteFile)
171 m_bDeleteFile = r.m_bDeleteFile;
172 m_FileName = r.Detatch();
174 return (*this);
177 ~CAutoFile()
179 if (m_bDeleteFile)
180 Unlink ();
183 std::string GetPath () const { return m_FileName; }
185 std::string Detatch() const;
186 int Unlink();
188 protected:
190 std::string m_FileName;
191 mutable bool m_bDeleteFile;
194 std::string CAutoFile::Detatch() const
196 m_bDeleteFile = false;
197 return m_FileName;
200 int CAutoFile::Unlink()
202 if ( m_bDeleteFile )
204 m_bDeleteFile = false;
205 return( unlink( m_FileName.c_str () ) );
207 else
209 return( 0 );
215 class CReverseDelta
217 public:
218 CReverseDelta (const char* buffer, size_t length)
219 : m_pBuffer (buffer), m_length (length)
223 bool operator () (std::istream& input, std::ostream& output) const
225 for (long i = 0; i < m_length; )
227 const FD* pfd = (const FD*) (m_pBuffer+i);
228 i += sizeof(FD);
229 // printf ("fd: %d, start %d, len %d\n", pfd->command, pfd->start, pfd->end);
231 switch (pfd->command)
233 case 2:
234 // assert finito
235 break;
236 case 1:
238 char b[256];
239 long size = pfd->end;
240 input.seekg(pfd->start);
241 if (input.fail ())
242 throw SSException ("reverse delta: invalid seek beyond file size");
244 while (size > 0)
246 long s = __min (size, sizeof (b));
247 input.read (b, s);
248 output.write (b, s);
249 size -= s;
252 break;
253 case 0:
254 output.write (m_pBuffer+i, pfd->end);
255 i += pfd->end;
256 break;
257 default:
258 std::strstream msg;
259 msg << "unknown reverse delta command " << pfd->command;
260 throw SSException (msg.str());
261 break;
265 return true;
267 protected:
268 const char* m_pBuffer;
269 size_t m_length;
273 class CHistoryHandler : public CActionVisitor
275 public:
276 CHistoryHandler (std::string src)
277 : m_File (src, false)
281 std::string GetPath ()
283 return m_File.GetPath();
286 virtual bool SaveAs (std::string name, bool overwrite = false) = 0;
288 protected:
289 CAutoFile m_File;
293 class CReverseHistoryHandler : public CHistoryHandler
295 public:
296 CReverseHistoryHandler (std::string src)
297 : CHistoryHandler (src)
301 virtual bool Apply (const SSCheckedInAction& rAction)
303 SSRecordPtr pRecord = rAction.GetFileDelta();
304 CAutoFile targetFile (CreateTempFile());
306 std::ifstream input (m_File.GetPath().c_str(), std::ios::in|std::ios::binary);
307 if (!input.is_open())
308 return false;
309 std::ofstream output (targetFile.GetPath().c_str(), std::ios::out|std::ios::binary);
310 if (!output.is_open())
311 return false;
313 CReverseDelta revDelta ((const char*)pRecord->GetBuffer(), pRecord->GetLen());
314 bool ret = revDelta (input, output);
316 input.close();
317 output.close ();
319 if (ret)
321 m_File = targetFile;
323 return ret;
326 virtual bool SaveAs (std::string name, bool overwrite = false)
328 return ::CopyFile (GetPath ().c_str(), name.c_str(), !overwrite) != 0;
331 virtual bool Apply (const SSAction& rAction)
333 throw SSException ("unsuported action in CReverseHistoryHandler");
338 class CProjectHistoryHandler : public CHistoryHandler
340 public:
341 CProjectHistoryHandler (std::string src)
342 : CHistoryHandler (src)
344 SSProjectFile projectFile (GetPath ());
345 BuildList (projectFile);
348 virtual bool SaveAs (std::string name, bool overwrite = false)
350 return false;
353 virtual bool Apply (const SSLabeledAction& rAction) { /* nothing to do */ return true; }
354 //// virtual bool Apply (const SSSingleFileAction& rAction) { return Apply ((const SSAction&) rAction); }
355 virtual bool Apply (const SSCreatedProjectAction& rAction) { /* nothing to do */ return true; }
356 virtual bool Apply (const SSCreatedFileAction& rAction) { /* nothing to do */ return true; }
357 virtual bool Apply (const SSAddedProjectAction& rAction);
358 virtual bool Apply (const SSAddedFileAction& rAction);
359 virtual bool Apply (const SSDeletedProjectAction& rAction);
360 virtual bool Apply (const SSDeletedFileAction& rAction);
361 virtual bool Apply (const SSRecoveredProjectAction& rAction);
362 virtual bool Apply (const SSRecoveredFileAction& rAction);
364 virtual bool Apply (const SSDestroyedProjectAction& rAction);
365 virtual bool Apply (const SSDestroyedFileAction& rAction);
366 virtual bool Apply (const SSRenamedProjectAction& rAction);
367 virtual bool Apply (const SSRenamedFileAction& rAction);
368 // virtual bool Apply (const SSCheckedInAction& rAction) { return Apply ((const SSAction&) rAction); }
369 // TODO:
370 // virtual bool Apply (const SSSharedFileAction& rAction) { return Apply ((const SSAction&) rAction); }
372 protected:
373 virtual bool Apply (const SSAction& rAction)
375 throw SSException ("unsuported action in CProjectHistoryHandler");
378 typedef std::vector<SSProjectObject>::iterator iterator;
379 std::vector<SSProjectObject> m_Items;
381 void BuildList (SSProjectFile& rFile);
382 iterator FindItem (std::string physFile);
383 iterator InsertItem (SSProjectObject object);
388 void CProjectHistoryHandler::BuildList (SSProjectFile& rFile)
390 // iterate all records and add them to the collection
391 SSRecordPtr recordPtr = rFile.GetFirstRecord ();
392 while (recordPtr)
394 if (recordPtr->GetType() == eProjectEntry)
396 SSProjectObject projectObject (recordPtr);
397 m_Items.push_back (projectObject);
400 recordPtr = rFile.GetNextRecord (recordPtr);
404 CProjectHistoryHandler::iterator CProjectHistoryHandler::FindItem (std::string physFile)
406 iterator itor;
407 iterator end = m_Items.end();
408 iterator found = end;
410 for (itor = m_Items.begin(); itor != end; ++itor)
412 SSProjectObject& po = *itor;
413 // std::cout << itemPtr->GetPhysical () << std::endl;
414 if (physFile == po.GetPhysFile())
416 if (found != end)
417 throw SSException ("duplicate entry");
419 found = itor;
423 return found;
426 CProjectHistoryHandler::iterator CProjectHistoryHandler::InsertItem (SSProjectObject object)
428 m_Items.push_back (object);
429 iterator last = m_Items.end();
430 return --last;
433 bool CProjectHistoryHandler::Apply (const SSAddedFileAction& rAction)
435 iterator itor = FindItem (rAction.GetPhysical());
436 if (itor != m_Items.end())
437 m_Items.erase(itor);
438 else
439 throw SSException ("item not found");
441 return true;
444 bool CProjectHistoryHandler::Apply (const SSAddedProjectAction& rAction)
446 iterator itor = FindItem (rAction.GetPhysical());
447 if (itor != m_Items.end())
448 m_Items.erase(itor);
449 else
450 throw SSException ("item not found");
452 return true;
455 bool CProjectHistoryHandler::Apply (const SSDeletedFileAction& rAction)
457 iterator itor = FindItem (rAction.GetPhysical());
458 if (itor != m_Items.end ())
460 SSProjectObject& po = *itor;
461 po.Recover ();
463 else
464 throw SSException ("item not found");
466 return true;
468 bool CProjectHistoryHandler::Apply (const SSDeletedProjectAction& rAction)
470 iterator itor = FindItem (rAction.GetPhysical());
471 if (itor != m_Items.end ())
473 SSProjectObject& po = *itor;
474 po.Recover ();
476 else
477 throw SSException ("item not found");
479 return true;
481 bool CProjectHistoryHandler::Apply (const SSRecoveredFileAction& rAction)
483 iterator itor = FindItem (rAction.GetPhysical());
484 if (itor != m_Items.end ())
486 SSProjectObject& po = *itor;
487 po.Delete ();
489 else
490 throw SSException ("item not found");
492 return true;
494 bool CProjectHistoryHandler::Apply (const SSRecoveredProjectAction& rAction)
496 iterator itor = FindItem (rAction.GetPhysical());
497 if (itor != m_Items.end ())
499 SSProjectObject& po = *itor;
500 po.Delete ();
502 else
503 throw SSException ("item not found");
505 return true;
508 bool CProjectHistoryHandler::Apply (const SSDestroyedProjectAction& rAction)
510 if (FindItem (rAction.GetPhysical ()) != m_Items.end ())
511 throw SSException ("adding already existing item");
513 PROJECT_ENTRY pe;
514 // pe.flags = ??;
515 pe.name = rAction.GetSSName ();
516 strncpy (pe.phys, rAction.GetPhysical().c_str(), 8);
517 pe.phys[8] = '\0';
518 pe.pinnedToVersion = 0;
519 // pe.type = ??
520 SSProjectObject pr (pe);
521 InsertItem (pr);
523 return true;
526 bool CProjectHistoryHandler::Apply (const SSDestroyedFileAction& rAction)
528 // durch map wahrscheinlich besser zu lösen
529 if (FindItem (rAction.GetPhysical()) != m_Items.end ())
530 throw SSException ("adding already existing item");
532 PROJECT_ENTRY pe;
533 // pe.flags = ??;
534 pe.name = rAction.GetSSName ();
535 strncpy (pe.phys, rAction.GetPhysical().c_str(), 8);
536 pe.phys[8] = '\0';
537 pe.pinnedToVersion = 0;
538 // pe.type = ??
539 SSProjectObject pr (pe);
540 InsertItem (pr);
542 return true;
545 bool CProjectHistoryHandler::Apply (const SSRenamedProjectAction& rAction)
547 iterator itor = FindItem (rAction.GetPhysical());
548 if (itor == m_Items.end ())
549 throw SSException ("item not found");
551 SSProjectObject& po = *itor;
552 po.Rename (rAction.GetNewSSName (), rAction.GetSSName());
553 return true;
556 bool CProjectHistoryHandler::Apply (const SSRenamedFileAction& rAction)
558 iterator itor = FindItem (rAction.GetPhysical());
559 if (itor == m_Items.end ())
560 throw SSException ("item not found");
562 SSProjectObject& po = *itor;
563 po.Rename (rAction.GetNewSSName (), rAction.GetSSName());
564 return true;
572 void CGetCommand::Execute ()
574 if (m_DestFile.empty ())
575 throw SSException ("please specify a destination file for the get operation");
577 if (fexists (m_DestFile.c_str ()) && !m_bForceOverwrite)
578 throw SSException ("destination file exists. Please use overwrite flag");
580 SSHistoryFile file(m_PhysFile);
581 std::auto_ptr<SSItemInfoObject> pItem (file.GetItemInfo());
582 if (!pItem.get ())
583 throw SSException ("no information object found");
585 std::auto_ptr<CHistoryHandler> pVisitor;
586 std::string lastDataFileName = pItem->GetDataFileName ();
588 if (pItem->GetType() == SSITEM_FILE)
589 pVisitor = std::auto_ptr<CHistoryHandler> (new CReverseHistoryHandler (lastDataFileName));
590 else
591 pVisitor = std::auto_ptr<CHistoryHandler> (new CProjectHistoryHandler (lastDataFileName));
594 SSVersionObject version (pItem->GetHistoryLast ());
595 while (version && version.GetVersionNumber() > m_Version)
597 if (version.GetAction())
599 version.GetAction ()->Accept (*pVisitor.get());
600 if (m_bBulkGet)
602 char buffer[66];
603 CFileName fname (m_PhysFile.c_str ());
604 fname.SetExt (itoa (version.GetVersionNumber (), buffer, 10));
606 if (!pVisitor->SaveAs (fname.GetFileName ().c_str(), false))
607 throw SSException ("failed to create target file" + fname.GetFileName ());
611 version = version.GetPreviousObject ();
614 if (!pVisitor->SaveAs (m_DestFile.c_str(), m_bForceOverwrite))
615 throw SSException ("failed to create target file");