Skip to content

Instantly share code, notes, and snippets.

@doomed-phobos
Created February 21, 2022 19:07
Show Gist options
  • Save doomed-phobos/5cdcbc7b8e287a9ef96197372efd9589 to your computer and use it in GitHub Desktop.
Save doomed-phobos/5cdcbc7b8e287a9ef96197372efd9589 to your computer and use it in GitHub Desktop.
Search recursive following a pattern extension.
/* ================
* Glob and Copy
* ================
* «» Add this in manifest file for disable maximum path length limitation:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
<application>
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>
*/
#include <iostream>
#include <string_view>
#include <windows.h>
#include <vector>
#include <functional>
#include <Shlwapi.h>
size_t nFilesCopied = 0;
std::wstring get_real_path(const std::wstring_view& path);
void copy_file(const std::wstring& src_dir, const std::wstring& dst_dir, const std::wstring& filename);
template<typename Fn,
typename = typename std::enable_if_t<std::is_convertible_v<
Fn, std::function<void(const std::wstring& /*src_dir*/, const std::wstring& /*filename*/)>>>>
void search_recursive(const std::wstring& dir, const std::wstring& pattern, Fn&& fn) {
HANDLE hSearch;
WIN32_FIND_DATAW ffd;
SetCurrentDirectoryW(dir.c_str());
hSearch = FindFirstFileW(L"*", &ffd);
if(hSearch != INVALID_HANDLE_VALUE) {
do {
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
continue;
} else if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if(wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0)
search_recursive(dir + L'\\' + ffd.cFileName, pattern, fn);
} else {
if(PathMatchSpecW(ffd.cFileName, pattern.c_str()) == TRUE)
fn(dir, ffd.cFileName);
}
} while(FindNextFileW(hSearch, &ffd) != 0);
}
FindClose(hSearch);
}
int wmain(int argc, wchar_t* argv[]) {
if(argc != 4) {
wprintf(L"[!] Usage: GlobAndCopy <pattern> <src_dir> <dst_dir>\n");
return -1;
}
const std::wstring_view pattern = argv[1];
const std::wstring_view src_dir = argv[2];
const std::wstring_view dst_dir = argv[3];
if(src_dir.size() > MAX_PATH - pattern.size() ||
dst_dir.size() > MAX_PATH - pattern.size()) {
wprintf(L"[!] <src_dir> or <dst_dir> is too large\n", src_dir, dst_dir);
return -1;
}
wprintf(L"[*] Finding %s in %s\n", pattern.data(), src_dir.data());
auto real_src_dir = get_real_path(src_dir);
auto real_dst_dir = get_real_path(dst_dir);
wprintf(L"[*] Source Dir: %s\n"
L"[*] Destination Dir: %s\n", real_src_dir.c_str(), real_dst_dir.c_str());
search_recursive(
real_src_dir,
std::wstring(pattern),
[&](const std::wstring& src_dir, const std::wstring& filename) {copy_file(src_dir, real_dst_dir, filename);});
wprintf(L"[*] %lld files copied!", nFilesCopied);
return 0;
}
// Convert . or .. to real path.
// If exists \, delete it
std::wstring get_real_path(const std::wstring_view& path) {
wchar_t real_path[MAX_PATH];
GetFullPathNameW(path.data(), MAX_PATH, real_path, NULL);
size_t size = wcslen(real_path);
if(size > MAX_PATH)
return std::wstring();
if(real_path[size-1] == L'\\')
real_path[size-1] = 0;
return real_path;
}
void copy_file(const std::wstring& src_dir, const std::wstring& dst_dir, const std::wstring& filename) {
std::wstring src_file = src_dir + L'\\' + filename;
SetCurrentDirectoryW(dst_dir.c_str());
if(CopyFileW(
src_file.c_str(),
filename.c_str(),
TRUE) == FALSE) {
wprintf(L"[!] File %s generates error code %ld\n", src_file.c_str(), GetLastError());
return;
}
wprintf(L"[*] Copied %s\n", src_file.c_str());
++nFilesCopied;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment