acl/lib_acl_cpp/samples/dircmp/main.cpp
2014-11-19 00:25:21 +08:00

271 lines
5.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "lib_acl.h"
#ifdef WIN32
#include <io.h>
#include <direct.h>
#define access _access
#define chdir _chdir
#define getcwd _getcwd
#endif // WIN32
#include "acl_cpp/lib_acl.hpp"
#ifdef WIN32
#define SEP '\\'
#else
#define SEP '/'
#endif
// 去年路径前的 "./" 或 ".\",因为在 WIN32 下
#define SKIP(ptr) do \
{ \
if (*ptr == '.' && *(ptr + 1) == '/') \
ptr += 2; \
else if (*ptr == '.' && *(ptr + 1) == '\\') \
ptr += 2; \
} while (0)
static bool cmp_file(acl::scan_dir& scan, const char* name,
const acl::string& to_path, int* ndiff)
{
const char* rpath = scan.curr_path();
if (rpath == NULL)
{
logger_error("get current path error: %s, file: %s",
acl::last_serror(), name);
return false;
}
SKIP(rpath);
SKIP(name);
// printf(">>rpath: %s\r\n", rpath);
// printf(">>name: %s\r\n", name);
acl::string from_filepath;
if (*rpath == 0)
from_filepath << name;
else
from_filepath << rpath << SEP << name;
// 只读方式打开源文件,如果打开失败,则直接返回 false
acl::ifstream from_fp;
if (from_fp.open_read(from_filepath.c_str()) == false)
{
logger_error("open source file: %s error: %s",
from_filepath.c_str(), acl::last_serror());
return false;
}
acl::string to_pathbuf;
acl::string to_filepath;
to_pathbuf << to_path << SEP << rpath;
to_filepath << to_path << SEP << rpath << SEP << name;
//printf("from_filepath: %s, to_filepath: %s\r\n",
// from_fp.file_path(), to_filepath.c_str());
// 尝试打开目标文件如果目标文件不存在则将计数器加1
acl::ifstream to_fp;
if (to_fp.open_read(to_filepath.c_str()) == false)
{
(*ndiff)++;
logger("file diff, from: %s, to: %s", from_filepath.c_str(),
to_filepath.c_str());
return true;
}
// 先比较目标文件与源文件大小是否相同
acl_int64 length;
if ((length = to_fp.fsize()) != from_fp.fsize())
{
(*ndiff)++;
logger("file diff, from: %s, to: %s", from_filepath.c_str(),
to_filepath.c_str());
return true;
}
// 再比较目标文件与源文件内容是否相同
char from_buf[4096], to_buf[4096];
int from_len, to_len;
acl_int64 read_len = 0;
while (true)
{
from_len = from_fp.read(from_buf, sizeof(from_buf), false);
if (from_len == -1)
{
if (read_len == length)
return true;
#ifdef WIN32
logger_error("read from file(%s) error(%s),"
"file size: %I64d read len: %I64d",
from_fp.file_path(), acl::last_serror(),
length, read_len);
#else
logger_error("read from file(%s) error(%s),"
"file size: %lld, read len: %lld",
from_fp.file_path(), acl::last_serror(),
length, read_len);
#endif
return false;
}
read_len += from_len;
to_len = to_fp.read(to_buf, from_len, true);
if (to_len == -1)
{
(*ndiff)++;
logger("file diff, from: %s, to: %s",
from_filepath.c_str(), to_filepath.c_str());
return true;
}
if (memcmp(from_buf, to_buf, to_len) != 0)
{
(*ndiff)++;
logger("file diff, from: %s, to: %s",
from_filepath.c_str(), to_filepath.c_str());
return true;
}
}
}
static bool check_dir(acl::scan_dir& scan, const char* to, int* ndiff)
{
const char* rpath = scan.curr_path();
if (rpath == false)
{
logger_error("get from's path error: %s, to: %s",
acl::last_serror(), to);
return false;
}
SKIP(rpath);
acl::string to_path;
to_path << to << SEP << rpath;
// printf(">>to_path: %s, to: %s\r\n", to_path.c_str(), to);
if (access(to_path.c_str(), 0) == 0)
return true;
(*ndiff)++;
logger("dir diff: %s, error: %s", to_path.c_str(), acl::last_serror());
return true;
}
static void do_cmp(const acl::string& from, const acl::string& to)
{
acl::scan_dir scan;
if (scan.open(from.c_str()) == false)
{
logger_error("open path: %s error: %s",
from.c_str(), acl::last_serror());
return;
}
const char* name;
bool is_file;
int nfiles = 0, ndirs = 0, nfiles_diff = 0, ndirs_diff = 0;
while ((name = scan.next(false, &is_file)) != NULL)
{
SKIP(name);
if (is_file)
{
if (cmp_file(scan, name, to, &nfiles_diff) == false)
{
printf(">>cmp failed, name: %s\r\n", name);
break;
}
nfiles++;
}
else if (check_dir(scan, to, &ndirs_diff) == false)
{
printf(">>check_dir failed, name: %s\r\n", name);
break;
}
else
ndirs++;
if ((nfiles + ndirs) % 100 == 0)
{
printf("current file count: diff %d / scaned %d, "
"dir count: diff %d / scaned %d\r",
nfiles_diff, nfiles, ndirs_diff, ndirs);
fflush(stdout);
}
}
printf("total file count: diff %d / scaned %d, dir count: "
"diff %d / scaned %d\r\n", nfiles_diff, nfiles,
ndirs_diff, ndirs);
}
static void usage(const char* procname)
{
logger_error("usage: %s -h [help] -f from_path -t to_path", procname);
}
int main(int argc, char* argv[])
{
int ch;
acl::string path_from, path_to;
acl::log::stdout_open(true);
while ((ch = getopt(argc, argv, "hf:t:")) > 0)
{
switch (ch)
{
case 'h':
usage(argv[0]);
return 0;
case 'f':
path_from = optarg;
break;
case 't':
path_to = optarg;
break;
default:
break;
}
}
if (path_from.empty() || path_to.empty())
{
usage(argv[0]);
return 1;
}
if (path_from == path_to)
{
logger_error("path_from(%s) == path_to(%s)", path_from.c_str(),
path_to.c_str());
usage(argv[0]);
return 1;
}
if (chdir(path_from.c_str()) == -1)
{
logger_error("chdir to %s error: %s",
path_from.c_str(), acl::last_serror());
return 1;
}
char path[256];
if (getcwd(path, sizeof(path)) == NULL)
{
logger_error("getcwd error: %s", path);
return 1;
}
logger_error("current path: %s", path);
do_cmp(".", path_to);
logger("enter any key to exit");
getchar();
return (0);
}