acl/lib_acl_cpp/samples/dircopy/main.cpp
2014-06-22 19:42:08 +08:00

340 lines
6.6 KiB
C++

#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 copy_file(acl::ifstream& in, const acl::string& to_path,
const acl::string& to_filepath, int* ncopied)
{
if (in.fseek(0, SEEK_SET) < 0)
{
logger_error("fseek from file: %s error: %s",
in.file_path(), acl::last_serror());
return false;
}
if (access(to_path.c_str(), 0) != 0)
{
if (acl_make_dirs(to_path.c_str(), 0755) == -1)
{
logger_error("create dirs: %s error: %s",
to_path.c_str(), acl::last_serror());
return false;
}
}
acl_int64 length = in.fsize();
if (length < 0)
{
logger_error("get file(%s)'s size error: %s", in.file_path(),
acl::last_serror());
return false;
}
acl::ofstream out;
if (out.open_trunc(to_filepath.c_str()) == false)
{
logger_error("ope_trunc file: %s error: %s",
to_filepath.c_str(), acl::last_serror());
return false;
}
char buf[4096];
int ret;
acl_int64 nread = 0;
while (true)
{
ret = in.read(buf, sizeof(buf), false);
if (ret == -1)
{
if (nread == length)
break;
logger_error("read from file: %s error: %s, "
"nread: %lld, length: %lld",
in.file_path(), acl::last_serror(),
nread, length);
return false;
}
nread += ret;
if (out.write(buf, ret) == -1)
{
logger_error("write to file: %s error: %s",
to_filepath.c_str(), acl::last_serror());
return false;
}
}
(*ncopied)++;
return true;
}
static bool cmp_copy(acl::scan_dir& scan, const char* name,
const acl::string& to_path, int* ncopied)
{
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;
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());
acl::ifstream to_fp;
if (to_fp.open_read(to_filepath.c_str()) == false)
return copy_file(from_fp, to_pathbuf, to_filepath, ncopied);
acl_int64 length;
if ((length = to_fp.fsize()) != from_fp.fsize())
{
to_fp.close();
return copy_file(from_fp, to_pathbuf, to_filepath, ncopied);
}
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)
{
to_fp.close();
return copy_file(from_fp, to_pathbuf,
to_filepath, ncopied);
}
if (memcmp(from_buf, to_buf, to_len) != 0)
{
to_fp.close();
return copy_file(from_fp, to_pathbuf,
from_filepath, ncopied);
}
}
}
static bool check_dir(acl::scan_dir& scan, const char* to, int* ncopied)
{
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;
else
{
int ret = acl_make_dirs(to_path.c_str(), 0755);
if (ret == 0)
{
(*ncopied)++;
return true;
}
else
{
logger_error("make dirs(%s) error: %s",
to_path.c_str(), acl::last_serror());
return false;
}
}
}
static void do_copy(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_copied = 0, ndirs_copied = 0;
while ((name = scan.next(false, &is_file)) != NULL)
{
SKIP(name);
if (is_file)
{
if (cmp_copy(scan, name, to, &nfiles_copied) == false)
{
printf(">>cm_copy failed, name: %s\r\n", name);
break;
}
nfiles++;
}
else if (check_dir(scan, to, &ndirs_copied) == false)
{
printf(">>check_dir failed, name: %s\r\n", name);
break;
}
else
ndirs++;
if ((nfiles + ndirs) % 100 == 0)
{
printf("current file count: copied %d / scaned %d, "
"dir count: copied %d / scaned %d\r",
nfiles_copied, nfiles, ndirs_copied, ndirs);
fflush(stdout);
}
}
printf("total file count: copyied %d / scaned %d, dir count: "
"copied %d / scaned %d\r\n", nfiles_copied, nfiles,
ndirs_copied, 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_copy(".", path_to);
logger("enter any key to exit");
getchar();
return (0);
}