#include <windows.h>
#include <iostream>
#include <stack>
int const BuffSize = 65536;
bool MyCopyFile(std::string src, std::string dest) {
static char Buff[BuffSize];
DWORD ActualReadBytes, ActualWriteBytes;
HANDLE hFileSrc, hFileDest;
hFileSrc = ::CreateFile(src.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFileSrc == INVALID_HANDLE_VALUE) {
std::cerr << "Cannot open(read) :" << src << std::endl;
return false;
}
hFileDest = ::CreateFile(dest.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFileSrc == INVALID_HANDLE_VALUE) {
std::cerr << "Cannot open(write) :" << dest << std::endl;
::CloseHandle(hFileSrc);
return false;
}
int nReadTotalBytes = 0;
int nWriteTotalBytes = 0;
for (;;) {
if (!::ReadFile(hFileSrc, Buff, BuffSize, &ActualReadBytes, 0)) {
std::cerr << "Opend but cannot read: " << src << " : " << nReadTotalBytes << "/" << nWriteTotalBytes << std::endl;
::CloseHandle(hFileSrc);
::CloseHandle(hFileDest);
return false;
}
nReadTotalBytes += ActualReadBytes;
/* out of loop */
if (ActualReadBytes == 0)
break;
if(!::WriteFile(hFileDest, Buff, ActualReadBytes, &ActualWriteBytes, 0)) {
std::cerr << "Opend and read but cannot write: " << dest << " : " << nReadTotalBytes << "/" << nWriteTotalBytes << std::endl;
break; /* out of for (;;) */
}
nWriteTotalBytes += ActualWriteBytes;
}
std::cout << nReadTotalBytes << "/" << nWriteTotalBytes << " ";
::CloseHandle(hFileSrc);
::CloseHandle(hFileDest);
return true;
}
struct PathPair {
std::string src;
std::string dest;
PathPair(std::string src, std::string dest) : src(src), dest(dest) { }
};
std::stack<PathPair> path_stack;
void copy_body(std::string original_dest) {
while (!path_stack.empty()) {
PathPair path_pair = path_stack.top(); path_stack.pop();
std::string now_path = path_pair.src;
std::string now_dest_path = path_pair.dest;
if (now_path.find_last_of(std::string("/")) != now_path.length() - 1) now_path += "/"; /* '/' で終わらない場合に '/' を追加 */
if (now_dest_path.find_last_of(std::string("/")) != now_dest_path.length() - 1) now_dest_path += "/"; /* '/' で終わらない場合に '/' を追加 */
std::string now_path_findfirst = now_path + "*.*";
WIN32_FIND_DATA FindFileData;
HANDLE hFindFirstNext = ::FindFirstFile(now_path_findfirst.c_str(), &FindFileData);
bool bInLoop = (hFindFirstNext != INVALID_HANDLE_VALUE);
while (bInLoop) {
std::string now_path_filename;
std::string now_dest_path_filename;
std::string filename = std::string(FindFileData.cFileName);
if (filename == "." || filename == "..") goto FINDNEXTFILE;
now_path_filename = now_path + filename;
now_dest_path_filename = now_dest_path + filename;
/* prevent recursively-endless-loop */
if (now_path_filename == original_dest)
goto FINDNEXTFILE;
if (::GetFileAttributes(now_path_filename.c_str()) & FILE_ATTRIBUTE_DIRECTORY) { /* when now_path_filename is a directory */
if ((signed int)::GetFileAttributes(now_dest_path_filename.c_str()) == -1) {
if(::CreateDirectory(now_dest_path_filename.c_str(), 0)) {
std::cout << "Create directory: " << now_dest_path_filename << std::endl;
} else {
std::cerr << "Failure to create directory: " << now_dest_path_filename << std::endl;
break;
}
}
path_stack.push(PathPair(now_path_filename, now_dest_path_filename));
} else { /* when now_path_filename is a file */
std::cout << now_path_filename << " -> " << now_dest_path_filename << " ";
if (MyCopyFile(now_path_filename, now_dest_path_filename)) {
std::cout << " : OK" << std::endl;
}
}
FINDNEXTFILE:
bInLoop = ::FindNextFile(hFindFirstNext, &FindFileData);
} /* while(bInLoop) */
if (hFindFirstNext != INVALID_HANDLE_VALUE)
::FindClose(hFindFirstNext);
} /* while(!path_stack.empty()) */
}
int main(int argc, char *argv[]) {
if (argc != 3) {
std::cerr << argv[0] << " : copy files and directory recursively." << std::endl;
std::cerr << "usage: " << argv[0] << " src-path dest-path " << std::endl;
return 0;
}
std::string src = std::string(argv[1]);
std::string dest= std::string(argv[2]);
if (src.find(std::string("./")) != 0)
src = std::string("./") + src;
if (dest.find(std::string("./")) != 0)
dest = std::string("./") + dest;
int attributes = ::GetFileAttributes(dest.c_str());
if (attributes == -1) {
std::cerr << "Directory: " << dest << " is not exists, aborted." << std::endl;
return 0;
}
path_stack.push(PathPair(src, dest));
copy_body(dest);
return 0;
}
/* end */