Synopsis: |
| common.h |
| FileInfo.h |
| main.cpp |
| MirrorDir.cpp |
| MirrorDir.h |
| OsFileSearch.cpp |
| OsFileSearch.h |
| OsUtils.cpp |
| OsUtils.h |
| Statistics.h |
| ||
#pragma once
//-----------------------------------------------------
template <class T, class Fn>
inline void for_all(const T& flist, Fn f)
{
std::for_each(flist.begin(), flist.end(), f);
}
const int VERBOSE_QUIET = 0;
const int VERBOSE_NORMAL = 1;
const int VERBOSE_SOME = 2;
const int VERBOSE_VERY = 3;
extern int gVerbose; // 0 is quiet, 1 just the summary, 2 is some messages, 3 is very verbose
extern bool gDoCommands; // false to show commands but not execute them; true to execute commands
| ||
| ||
#pragma once
#include <string>
#include <vector>
#include <iostream>
struct FileInfo
{
FileInfo(const std::string& n, long sz)
: name(n), size(sz)
{
}
FileInfo(const FileInfo& other)
: name(other.name), size(other.size)
{
}
bool operator == (const FileInfo& other) const
{
return name == other.name;
}
const FileInfo& operator = (const FileInfo& other)
{
name = other.name;
size = other.size;
return *this;
}
std::string name;
long size;
} ;
typedef std::vector<FileInfo> FileInfoList;
//-----------------------------------------------------
inline bool IsFileLessThan(const FileInfo& left, const FileInfo& right)
{
return left.name < right.name;
}
//-----------------------------------------------------
inline void WriteLine(const FileInfo& f)
{
if (gVerbose >= VERBOSE_SOME)
std::cout << f.name << "\n";
}
| ||
| ||
#include <iostream>
#include <string>
using std::cout;
using std::string;
#include "Statistics.h"
#include "OsUtils.h"
#include "MirrorDir.h"
Statistics gStats;
int gVerbose = VERBOSE_NORMAL; // 0 is quiet, 1 just the summary, 2 is some messages, 3 is very verbose
bool gDoCommands = true; // false to show commands but not execute them; true to execute commands
//-----------------------------------------------------
class App
{
public:
void Run()
{
if (!OsUtils::DirExists(rightroot))
OsUtils::mkdir(rightroot);
MirrorDir(leftroot, rightroot);
}
//-----------------------------------------------------
void usage()
{
cout << "usage: mirror leftdir rightdir [options]\n";
cout << " options:\n";
cout << " -? help\n";
cout << " -h help\n";
cout << " -v verbose\n";
cout << " -vv very verbose\n";
cout << " -q quiet\n";
cout << " -s show only, do not execute\n";
exit(1);
}
//-----------------------------------------------------
void usage(const string& msg)
{
cout << "mirror: " << msg << "\n\n";
usage();
}
void Init()
{
gStats.Init();
SetDefaults();
}
void SetDefaults()
{
gVerbose = VERBOSE_NORMAL;
gDoCommands = true; // false to show commands but not execute them; true to execute commands
}
void ParseCommandLine(int argc, char** argv)
{
for(int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (arg == "-?" || arg == "-h")
usage();
else if (arg == "-v")
gVerbose = VERBOSE_SOME;
else if (arg == "-vv")
gVerbose = VERBOSE_VERY;
else if (arg == "-q")
gVerbose = VERBOSE_QUIET;
else if (arg == "-s")
gDoCommands = false;
else if (arg[0] == '-')
usage("unknown switch");
else if (leftroot.empty())
leftroot = arg;
else if (rightroot.empty())
rightroot = arg;
else
usage("unknown argument");
}
if (leftroot.empty() || rightroot.empty())
usage("must specify both directories");
if (leftroot == rightroot)
{
cout << "Left and right roots must be different\n";
exit(1);
}
if (!OsUtils::DirExists(leftroot) || !OsUtils::IsADir(leftroot))
{
cout << "left root does not exist or is not a valid directory\n";
exit(1);
}
if (OsUtils::DirExists(rightroot) && !OsUtils::IsADir(rightroot))
{
cout << "right root is not a valid directory\n";
exit(1);
}
}
string leftroot;
string rightroot;
} ;
//-----------------------------------------------------
int main(int argc, char** argv)
{
App app;
app.Init();
app.ParseCommandLine(argc, argv);
app.Run();
gStats.Dump(cout);
return 0;
}
| ||
| ||
#include <string>
#include <algorithm>
#include <iostream>
using std::string;
using std::sort;
using std::cout;
#include "Common.h"
#include "MirrorDir.h"
#include "FileInfo.h"
#include "OsUtils.h"
#include "OsFileSearch.h"
//-----------------------------------------------------
struct ChangeHandler
{
virtual void operator() (const string& ldir, const string& rdir, const FileInfo& f) const = 0;
} ;
//-----------------------------------------------------
struct ChangeHandler2
{
virtual void operator() (const string& ldir, const FileInfo& l, const string& rdir, const FileInfo& r) const = 0;
} ;
//prototypes:
void ScanDirectory(const string& dir, FileInfoList& flist, FileInfoList& dlist);
void compare(const string& leftdir, const FileInfoList& left,
const string& rightdir, const FileInfoList& right,
const ChangeHandler& insfile, const ChangeHandler& delfile, const ChangeHandler2& eqfile);
//-----------------------------------------------------
struct InsertedDir : public ChangeHandler
{
void operator() (const string& /*ld*/, const string& rd, const FileInfo& f) const
{
//remove directory in the right directory
string dir = rd + "\\" + f.name;
if (gVerbose >= VERBOSE_SOME)
cout << "dir : rmdir-> " << dir << "\n";
if (gDoCommands)
OsUtils::rmtree(dir);
}
} ;
//-----------------------------------------------------
struct DeletedDir : public ChangeHandler
{
void operator() (const string& /*ld*/, const string& rd, const FileInfo& f) const
{
string dir = rd + "\\" + f.name;
if (gVerbose >= VERBOSE_SOME)
cout << "dir : mkdir-> " << dir << "\n";
if (gDoCommands)
OsUtils::mkdir(dir);
}
} ;
//-----------------------------------------------------
struct EqualDir : public ChangeHandler2
{
void operator() (const string& ld, const FileInfo& l, const string& /*rd*/, const FileInfo& /*r*/) const
{
// do nothing if the directories are equal
if (gVerbose >= VERBOSE_VERY)
cout << "dir : eq-> " << ld << "\\" << l.name << "\n";
}
} ;
//-----------------------------------------------------
struct InsertedFile : public ChangeHandler
{
void operator() (const string& /*ld*/, const string& rd, const FileInfo& f) const
{
//delete old files in the right directory root (make a backup???)
string rpath = rd + "\\" + f.name;
if (gVerbose >= VERBOSE_SOME)
cout << "file: old-> 'del " << rpath << "'\n";
if (gDoCommands)
OsUtils::delfile(rpath);
}
} ;
//-----------------------------------------------------
struct DeletedFile : public ChangeHandler
{
void operator() (const string& ld, const string& rd, const FileInfo& f) const
{
// copy new from the left to the right directory root
string lpath = ld + "\\" + f.name;
string rpath = rd + "\\" + f.name;
if (gVerbose >= VERBOSE_SOME)
cout << "file: new-> 'copy " << lpath << " " << rpath << "'\n";
if (gDoCommands)
OsUtils::copyfile(lpath, rpath);
}
} ;
//-----------------------------------------------------
struct EqualFile : public ChangeHandler2
{
void operator() (const string& ld, const FileInfo& l, const string& rd, const FileInfo& r) const
{
string lpath = ld + "\\" + l.name;
string rpath = rd + "\\" + l.name;
if (l.size == r.size)
{
if (gVerbose >= VERBOSE_VERY)
cout << "file: eq -> no action " << lpath << "\n";
}
else
{
if (gVerbose >= VERBOSE_SOME)
cout << "file: chg-> 'copy " << lpath << " " << rpath << "'\n";
if (gDoCommands)
OsUtils::copyfile(lpath, rpath);
}
}
} ;
//-----------------------------------------------------
void MirrorDir(const string& leftdir, const string& rightdir)
{
FileInfoList leftflist;
FileInfoList leftdlist;
FileInfoList rightflist;
FileInfoList rightdlist;
ScanDirectory(leftdir, leftflist, leftdlist);
ScanDirectory(rightdir, rightflist, rightdlist);
sort(leftflist.begin(), leftflist.end(), IsFileLessThan);
sort(rightflist.begin(), rightflist.end(), IsFileLessThan);
sort(leftdlist.begin(), leftdlist.end(), IsFileLessThan);
sort(rightdlist.begin(), rightdlist.end(), IsFileLessThan);
if (gVerbose >= VERBOSE_VERY)
{
cout << "------------------\n";
for_all(leftdlist, WriteLine);
cout << "files---\n";
for_all(leftflist, WriteLine);
cout << "------------------\n";
for_all(rightdlist, WriteLine);
cout << "files---\n";
for_all(rightflist, WriteLine);
cout << "------------------\n";
}
compare(leftdir, leftdlist, rightdir, rightdlist, InsertedDir(), DeletedDir(), EqualDir());
compare(leftdir, leftflist, rightdir, rightflist, InsertedFile(), DeletedFile(), EqualFile());
for(FileInfoList::iterator it = leftdlist.begin(); it != leftdlist.end(); ++it)
MirrorDir(leftdir + "\\" + (*it).name, rightdir + "\\" + (*it).name);
}
//-----------------------------------------------------
void ScanDirectory(const string& dir, FileInfoList& flist, FileInfoList& dlist)
{
OsFileSearch osfs(dir);
for (osfs.First(); osfs.IsMore(); osfs.Next())
{
if (osfs.IsDots())
;
else if (osfs.IsDir())
dlist.push_back(FileInfo(osfs.GetRelativePath(), 0));
else
flist.push_back(FileInfo(osfs.GetRelativePath(), osfs.GetSize()));
}
}
//-----------------------------------------------------
//-- assume files are sorted
void compare(const string& leftdir, const FileInfoList& left,
const string& rightdir, const FileInfoList& right,
const ChangeHandler& insfile, const ChangeHandler& delfile, const ChangeHandler2& eqfile)
{
FileInfoList::const_iterator ileft = left.begin();
FileInfoList::const_iterator iright = right.begin();
while (ileft != left.end() || iright != right.end())
{
if (ileft == left.end())
{
insfile(leftdir, rightdir, *iright);
++iright;
}
else if (iright == right.end())
{
delfile(leftdir, rightdir, *ileft);
++ileft;
}
else if (*ileft == *iright)
{
eqfile(leftdir, *ileft, rightdir, *iright);
++ileft;
++iright;
}
//else if (IsPathLessThan((*ileft).name, (*iright).name))
else if (IsFileLessThan(*ileft, *iright))
{
delfile(leftdir, rightdir, *ileft);
++ileft;
}
else
{
insfile(leftdir, rightdir, *iright);
++iright;
}
}
}
| ||
| ||
#pragma once #include <string> void MirrorDir(const std::string& leftdir, const std::string& rightdir); | ||
| ||
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
using std::string;
#include "OsFileSearch.h"
class OsFileSearch::Private
{
public:
Private(const string& dir)
: mRc(FALSE), hfile(INVALID_HANDLE_VALUE), mDir(dir)
{
}
BOOL mRc;
WIN32_FIND_DATA fdata;
HANDLE hfile;
const string& mDir;
} ;
OsFileSearch::OsFileSearch(const string& dir)
: impl(* new OsFileSearch::Private(dir) )
{
}
OsFileSearch::~OsFileSearch()
{
Close();
delete &impl;
}
void OsFileSearch::First()
{
string fspec = impl.mDir + "\\*.*";
impl.hfile = FindFirstFile(fspec.c_str(), &impl.fdata);
impl.mRc = IsValid() ? TRUE : FALSE;
}
bool OsFileSearch::IsMore()
{
return impl.mRc == TRUE;
}
void OsFileSearch::Next()
{
impl.mRc = FindNextFile(impl.hfile, &impl.fdata);
}
bool OsFileSearch::IsDir()
{
return (impl.fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
bool OsFileSearch::IsReadOnly()
{
return (impl.fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
}
bool OsFileSearch::IsDots()
{
return strcmp(impl.fdata.cFileName, ".") == 0 || strcmp(impl.fdata.cFileName, "..") == 0;
}
string OsFileSearch::GetFullPath()
{
return string(impl.mDir + "\\" + strlwr(impl.fdata.cFileName));
}
string OsFileSearch::GetRelativePath()
{
return string(strlwr(impl.fdata.cFileName));
}
long OsFileSearch::GetSize()
{
return impl.fdata.nFileSizeLow;
}
void OsFileSearch::Close()
{
if (!IsValid()) return;
FindClose(impl.hfile);
impl.hfile = INVALID_HANDLE_VALUE;
}
bool OsFileSearch::IsValid()
{
return impl.hfile != INVALID_HANDLE_VALUE;
}
| ||
| ||
#pragma once
#include <string>
using std::string;
class OsFileSearch
{
public:
explicit OsFileSearch(const string& dir);
~OsFileSearch();
void First();
bool IsMore();
void Next();
bool IsDir();
bool IsReadOnly();
bool IsDots();
string GetFullPath();
string GetRelativePath();
long GetSize();
void Close();
private:
bool IsValid();
private:
class Private;
Private& impl;
} ;
| ||
| ||
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
using std::cout;
#include "OsUtils.h"
#include "Statistics.h"
#include "OsFileSearch.h"
//-----------------------------------------------------
bool OsUtils::DirExists(const string& d)
{
DWORD fattr = GetFileAttributes(d.c_str());
if (fattr == 0xFFFFFFFF)
{
return false;
}
return true;
}
//-----------------------------------------------------
bool OsUtils::IsADir(const string& d)
{
DWORD fattr = GetFileAttributes(d.c_str());
if ((fattr & FILE_ATTRIBUTE_DIRECTORY) != 0) //is a directory
{
return true;
}
return false;
}
void OsUtils::copyfile(const string& lpath, const string& rpath)
{
BOOL wrc = ::CopyFile(lpath.c_str(), rpath.c_str(), FALSE);
if (wrc)
{
gStats.NumFilesCopied++;
return;
}
gStats.NumFailedFiles++;
CheckError("copy file failed");
}
void OsUtils::delfile(const string& path)
{
BOOL wrc = ::DeleteFile(path.c_str());
if (wrc)
{
gStats.NumFilesDeleted++;
return;
}
DWORD gle = GetLastError();
if (gle == ERROR_ACCESS_DENIED)
{
ClearReadOnly(path);
BOOL wrc = ::DeleteFile(path.c_str());
if (wrc)
{
gStats.NumFilesDeleted++;
return;
}
}
gStats.NumFailedFiles++;
CheckError("delete file failed");
}
void OsUtils::rmdir(const string& dir)
{
BOOL wrc = ::RemoveDirectory(dir.c_str());
if (wrc)
{
gStats.NumDirsDeleted++;
return;
}
gStats.NumFailedDirs++;
CheckError("remove directory failed");
}
void OsUtils::mkdir(const string& dir)
{
BOOL wrc = ::CreateDirectory(dir.c_str(), 0);
if (wrc)
{
gStats.NumDirsCreated++;
return;
}
gStats.NumFailedDirs++;
CheckError("create directory failed");
}
void OsUtils::rmtree(const string& dir)
{
OsFileSearch osfs(dir);
for (osfs.First(); osfs.IsMore(); osfs.Next())
{
if (osfs.IsDots())
;
else if (osfs.IsDir())
rmtree(osfs.GetFullPath());
else
delfile(osfs.GetFullPath());
}
osfs.Close();
OsUtils::rmdir(dir);
}
void OsUtils::ClearReadOnly(const string& path)
{
DWORD attrs = ::GetFileAttributes(path.c_str());
attrs = attrs & ~FILE_ATTRIBUTE_READONLY;
::SetFileAttributes(path.c_str(), attrs);
}
void OsUtils::CheckError(const string& prefix)
{
DWORD gle = GetLastError();
if (gle == ERROR_SHARING_VIOLATION)
cout << prefix << ": (" << gle << ") SHARING_VIOLATION\n";
else if (gle == ERROR_ACCESS_DENIED)
cout << prefix << ": (" << gle << ") ACCESS_DENIED\n";
else if (gle != 0)
cout << prefix << ": " << gle << "\n";
}
| ||
| ||
#pragma once
#include <string>
using std::string;
struct OsUtils
{
public:
static void copyfile(const string& lpath, const string& rpath);
static void delfile(const string& path);
static void rmdir(const string& dir);
static void mkdir(const string& dir);
static void rmtree(const string& dir);
static bool IsADir(const string& d);
static bool DirExists(const string& d);
private:
static void ClearReadOnly(const string& path);
static void CheckError(const string& prefix);
} ;
| ||
| ||
#pragma once
#include <ostream>
using std::ostream;
#include "Common.h"
struct Statistics
{
int NumDirsDeleted;
int NumDirsCreated;
int NumFilesDeleted;
int NumFilesCopied;
int NumFailedFiles;
int NumFailedDirs;
Statistics()
{
Init();
}
void Init()
{
NumDirsDeleted = 0;
NumDirsCreated = 0;
NumFilesDeleted = 0;
NumFilesCopied = 0;
NumFailedFiles = 0;
NumFailedDirs = 0;
}
void Dump(ostream& os)
{
if (gVerbose < VERBOSE_NORMAL) return;
os << "Num directories deleted: " << NumDirsDeleted << "\n";
os << "Num directories created: " << NumDirsCreated << "\n";
os << "Num failed directories : " << NumFailedDirs << "\n";
os << "Num files deleted : " << NumFilesDeleted << "\n";
os << "Num files copied : " << NumFilesCopied << "\n";
os << "Num failed files : " << NumFailedFiles << "\n";
}
} ;
extern Statistics gStats;
|
| Contact me about content on this page using john_web-at-arrizza-dot-com |
| For Web Master or site problems contact: webadmin-at-arrizza-dot-com |
| Copyright John Arrizza (c) 2001-2010 |