|
26 марта 2020
Резервное копирование файлов
скачать 21backupFiles 64 и 32 bit
Схема копирования файлов задается в настроечном файле 21backupFiles.txt.
В настроечном файле указывается ключ --Dir-- с последующим каталогом назначения.
Далее указываются пути к файлам, которые нужно скопировать. Если вместо файла указан
каталог, то копируются все вложенные файлы.
Далее можно указать другие каталоги назначения (--Dir--) и список копируемых файлов.
По умолчанию перед (повторным) копированием делается проверка даты последнего изменения файла.
(при первом копировании конечных файлов ещё нет и проверять нечего)
Если даты разные - файл изменен - то он копируется. То есть копируются изменённые файлы.
Перед именами каталогов или файлов можно указать ключи <+d> и <-d>.
<+d> - проверять даты последнего изменения файла.
<-d> - НЕ проверять даты последнего изменения файла - копировать всегда.
Если для каталога назначения (--Dir--) задан ключ <+d> или <-d>, то ко всем файлам, указанным для
этого каталога, по умолчанию будет применяться эта настройка. Если эти ключи указаны для
конкретного файла, то будет применяться эта частная настройка.
Когда ключи <+d> или <-d> не указаны для каталога назначения (--Dir--), то это означает <+d> (проверять даты).
Когда ключи <+d> или <-d> не указаны для файлов, то это означает, что берётся настройка из каталога назначения.
При копировании сохраняется структура каталогов.
Варианты запуска.
Оконный. В этом случае сообщения об ошибках пишутся в текстовое поле на форме.
Отображается шкала копирования.
Консольный. Запуск с ключом "-w"( можно сделать ярлык и добавить ключ -w ). В этом случае сообщения об ошибках пишутся в текстовый файл
21backUpFilesLOG.txt . Шкала копирования не отображается.
Ограничения:
максимальная длина конечного пути - 255 символов
используется однобайтовая кодовая таблица ( для windows - windows-1251 ).
/* файл 21backupFiles.c */
//cd "C:\Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin"
//x86_64-w64-mingw32-gcc.exe 21backupFiles.c list_intr.c -lshlwapi -o 21backupFiles.exe -mwindows // -mconsole
// 21backupFiles.exe
//cd "C:\Program Files (x86)\mingw-w64\i686-8.1.0-win32-dwarf-rt_v6-rev0\mingw32\bin"
//i686-w64-mingw32-gcc.exe 21backupFiles.c list_intr.c -lshlwapi -o 21backupFiles32bit.exe -mwindows // -mconsole
// 21backupFiles32bit.exe
#include <windows.h> // заголовочный файл, содержащий WINAPI
#include <shlwapi.h>
#include <stdio.h>
#include "list_intr.h"
//#include <commctrl.h>
//#include <string.h>
#define message01 "Ошибка при чтении файла 21backupFiles.txt. Возможно, его нет."
#define message012 "Ошибка получения атрибутов файла. GetFileAttributesExA"
#define message02 "Ошибочные, несуществующие пути. Или файлы, указанные вместо каталога назначения.
Или пропущенные при отсутствии каталога назначения. :"
#define message03 "Нет существующих путей для копирования."
#define message04 "НЕТ ПАМЯТИ"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void startCoping(void);
void startCopingInConsole(void);
void OutPathToEdit(Paths * ps, char * cstr);
void OutPathToFile(Paths * ps, char * cstr, FILE * ff);
void AddTextToEdit(HWND el, char * str);
HWND hWnd_button1, editctl;
HWND hMainWnd; // дескриптор будущего окна
Paths exPath, unexPath;
WORD sx, sy;
/* 64-bit */
long long id_button1 = 10001;
long long IDC_EDIT = 10002;
/* // 32-bit
int id_button1 = 10001;
int IDC_EDIT = 10002;
*/
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
TCHAR szClassName[] = "21backUpFiles"; // строка с именем класса
MSG msg; // создаём экземпляр структуры MSG для обработки сообщений
WNDCLASSEX wc; // создааём экземпляр, для обращения к членам класса WNDCLASSEX
///////here is a case : window or console mode.//////////
if (strstr(lpCmdLine, "-w") != NULL){
startCopingInConsole();
return 0;
}
/////////////////
/////////////////
wc.cbSize = sizeof(wc); // размер структуры (в байтах)
wc.style = CS_HREDRAW | CS_VREDRAW; // стиль класса окна
wc.lpfnWndProc = WndProc; // указатель на пользовательскую функцию
wc.lpszMenuName = NULL; // указатель на имя меню (у нас его нет)
wc.lpszClassName = szClassName; // указатель на имя класса
wc.cbWndExtra = 0; // число освобождаемых байтов в конце структуры
wc.cbClsExtra = 0; // число освобождаемых байтов при создании экземпляра приложения
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // декриптор пиктограммы
wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // дескриптор маленькой пиктограммы (в трэе)
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // дескриптор курсора
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // дескриптор кисти для закраски фона окна
wc.hInstance = hInst; // указатель на строку, содержащую имя меню, применяемого для класса
if(!RegisterClassEx(&wc)){
// в случае отсутствия регистрации класса:
MessageBox(NULL, "window's class is not registered!", "Err_Err", MB_OK);
return 1;
}
// Функция, создающая окно:
hMainWnd = CreateWindow(
szClassName, // имя класса
"21_back_Up_Files", // имя окна (то что сверху)
WS_OVERLAPPEDWINDOW, // | WS_VSCROLL, // режимы отображения окна
CW_USEDEFAULT, // позиция окна по оси х
CW_USEDEFAULT, // позиция окна по оси у (раз дефолт в х, то писать не нужно)
500, // ширина окна
400, // высота окна (раз дефолт в ширине, то писать не нужно)
NULL, // дескриптор родительского окна
NULL, // дескриптор меню
hInst, // дескриптор экземпляра приложения
NULL); // ничего не передааём из WndProc
if(!hMainWnd){
// в случае некорректного создания окна (неверные параметры и тп):
MessageBox(NULL, "Window is not created!", "Err_Err2", MB_OK);
return 0;
}
//////////////button1 - to start coping. //////////////////////////////////
//Создаем кнопку2
hWnd_button1 = CreateWindow(TEXT("button"), TEXT("start coping"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 30, 130, 30, hMainWnd, (HMENU)id_button1, hInst, NULL);
////////////// EDIT 1/////////////////////////////////////////
editctl = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
10, 70, 100, 100, hMainWnd, (HMENU)IDC_EDIT, hInst, 0);
ShowWindow(hMainWnd, nCmdShow); // отображаем окно
UpdateWindow(hMainWnd); // обновляем окно
while(GetMessage(&msg, NULL, 0, 0)){ // извлекаем сообщения из очереди, посылаемые фу-циями, ОС
TranslateMessage(&msg); // интерпретируем сообщения
DispatchMessage(&msg); // передааём сообщения обратно ОС
}
return msg.wParam; // возвращаем код выхода из приложения
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
switch(uMsg){
case WM_COMMAND:
if (LOWORD(wParam) == id_button1){ // start coping
startCoping();
}
break;
case WM_SIZE: // Sent to a window after its size has changed
sx = LOWORD(lParam); //ширина клиентской области
sy = HIWORD(lParam); //высота
SetWindowPos(editctl, (HWND)NULL, 10, 70, sx- 20, sy - 80, 0);
break;
case WM_DESTROY:
PostQuitMessage(0); // отправляем WinMain() сообщение WM_QUIT
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
// window's mode
void startCoping(void){
char * err;
int readRes;
SetWindowText(editctl, "### Begin\xD\xA");
initPaths(&exPath, &unexPath);
readRes = ReadPaths(&exPath, &unexPath);
if ( readRes == 1 ){
AddTextToEdit(editctl, message01);
return;
} else if ( readRes == 2 ){
AddTextToEdit(editctl, message012);
return;
} else if ( readRes == 3 ){
AddTextToEdit(editctl, message04);
return;
}
if ( unexPath.nump > 0 )
OutPathToEdit(&unexPath, message02);
if ( exPath.nump == 0 ){
AddTextToEdit(editctl, message03);
return;
}
err = NULL;
copy(&exPath, err, 0);
if (err != NULL){
AddTextToEdit(editctl, err);
AddTextToEdit(editctl, "\xD\xA");
free(err);
}
//очистка памяти, занятой связными списками
freePaths(&exPath, &unexPath);
AddTextToEdit(editctl, "### End.");
}
void AddTextToEdit(HWND el, char * str){
int nLen = GetWindowTextLength(el);
SendMessage (el, EM_SETSEL, nLen, nLen);
SendMessage (el, EM_REPLACESEL, 0, (LPARAM)str);
}
// console's mode
void startCopingInConsole(void){
char * err;
FILE * ff;
int readRes;
ff = fopen("21backUpFilesLOG.txt", "w");
if ( ff == NULL )
MessageBox(NULL, "Error of opening of 21backUpFilesLOG.txt file.", "Err", MB_OK);
initPaths(&exPath, &unexPath);
readRes = ReadPaths(&exPath, &unexPath);
if ( readRes == 1 ){
fputs(message01, ff);
if ( ff != NULL )
fclose(ff);
return;
} else if ( readRes == 2 ){
fputs(message012, ff);
if ( ff != NULL )
fclose(ff);
return;
} else if ( readRes == 3 ){
fputs(message04, ff);
if ( ff != NULL )
fclose(ff);
return;
}
if ( unexPath.nump > 0 && ff != NULL )
OutPathToFile(&unexPath, message02, ff);
if ( exPath.nump == 0 ){
fputs(message03, ff);
if ( ff != NULL )
fclose(ff);
return;
}
err = NULL;
copy(&exPath, err, 1);
if (err != NULL){
fputs("\n", ff);
fputs(err, ff);
free(err);
}
if ( ff != NULL )
fclose(ff);
//очистка памяти, занятой связными списками
freePaths(&exPath, &unexPath);
}
void OutPathToEdit(Paths * ps, char * cstr){
unsigned int slen, clen, i = 0;
Node * nextEx;
char * str;
slen = ps->lengthAllPaths1 + ps->nump * 2; // + \xD\xA
clen = strlen(cstr);
str = (char *) malloc( clen + slen + 3 ); // + \xD\xA + \0
if (str == NULL){
AddTextToEdit(editctl, "Нет свободной памяти.");
return;
}
sprintf(str, "%s\xD\xA", cstr);
i = clen + 2;
nextEx = ps->begin;
while ( nextEx != NULL ){
sprintf(str + i, "%s\xD\xA", nextEx->item.path1);
i += nextEx->item.num1 + 2; // + \xD\xA
nextEx = nextEx->next;
}
AddTextToEdit(editctl, str);
AddTextToEdit(editctl, "\xD\xA");
free(str);
}
void OutPathToFile(Paths * ps, char * cstr, FILE * ff){
Node * nextEx;
fputs(cstr, ff);
fputs("\n", ff);
nextEx = ps->begin;
while ( nextEx != NULL ){
fputs(nextEx->item.path1, ff);
fputs("\n", ff);
nextEx = nextEx->next;
}
}
/* list_intr.h -- интерфейс списка */
#ifndef _LIST_INTR_
#define _LIST_INTR_
////////////////////////////////////////
typedef struct item {
char * path1;
unsigned int num1;
FILETIME t1;
unsigned short int checkDate; //проверять дату последнего изменения
char * path2;
unsigned int num2;
FILETIME t2;
short int getCopied;
} Item;
////////////////////////////////////////
typedef struct node {
Item item;
struct node * next;
} Node;
typedef struct paths{
Node * begin;
unsigned int lengthAllPaths1; // длина всех путей файлов
unsigned int lengthAllPaths2;
unsigned int lengthAllPaths1fact;// фактическая длина путей файлов с учетом отбора по дате изменения
unsigned int lengthAllPaths2fact;
unsigned int nump;
short int numGetCopied;
} Paths;
//инициализирует переменные
void initPaths(Paths * exPath, Paths * unexPath);
//чтение данных из настроечного файла
//вход: exPath - указатель на список, куда будут добавлены существующие пути
// unexPath - указатель на список, куда будут добавлены не существующие пути
//выход: заполнены оба списка или один из них; возвращает 0 в случае успешного выполнения
int ReadPaths(Paths * exPath, Paths * unexPath);
// копирует файлы
int copy(Paths * exPath, char * err, unsigned short console);
//очищает занятую память
int freePaths(Paths * exPath, Paths * unexPath);
#endif
/* файл list_intr.c - реализация интерфейса*/
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "list_intr.h"
#define f1 "\\*.*"
#define DirArg "--Dir--"
#define checkOn "<+d>"
#define checkOff "<-d>"
#define haventMem "\nНЕТ ПАМЯТИ\n"
static void findFAdd(char * path, HANDLE handleNext, WIN32_FIND_DATAA * dataF, Paths * exPath,
Node ** nextExInFind, char * currDir, int lenCurrDir, unsigned short int checkDate);
void initPaths(Paths * exPath, Paths * unexPath){
exPath->begin = NULL;
exPath->lengthAllPaths1 = 0;
exPath->lengthAllPaths2 = 0;
exPath->lengthAllPaths1fact = 0;
exPath->lengthAllPaths2fact = 0;
exPath->nump = 0;
exPath->numGetCopied = 0;
unexPath->begin = NULL;
unexPath->lengthAllPaths1 = 0;
unexPath->lengthAllPaths2 = 0;
unexPath->lengthAllPaths1fact = 0;
unexPath->lengthAllPaths2fact = 0;
unexPath->nump = 0;
}
int ReadPaths(Paths * exPath, Paths * unexPath){
int rez, retval, rezGetAttr, len, mem = 0, isDir;
int cc = 0, i, lenFlag, lenCurrDir;
char path[MAX_PATH+1]; // MAX_PATH = 260
char * n;
char * pFrom, * pFromN, * pathN, * beginFlag, * currDir;
unsigned short int checkDateDefault, checkDateFact;
WIN32_FILE_ATTRIBUTE_DATA fileAttr;
WIN32_FIND_DATAA dataF;
HANDLE handleNext;
Node * tempNode;
Node * nextEx = NULL;
Node * nextUnEx = NULL;
FILE * in = fopen("21backupFiles.txt", "r");
if (in == NULL)
return 1;
currDir = NULL;
while ( fgets(path, MAX_PATH+1, in) != NULL ){ //остаются символы перевода строки
n = strchr(path, '\n');
if (n != NULL)
*n = '\0';
len = strlen(path);
if (len == 0)
continue;
//printf("MAINE=== path = %s\n", path);
beginFlag = strstr(path, DirArg);
if (beginFlag != NULL){
lenFlag = strlen(DirArg);
//printf("begug 1, path = %s\n", path);
//обновляю каталог или устанавливаю первый раз
//разбираю строку. получаю каталог. проверяю его на существование
//устанавливаю новый текущий Каталог назначения
if ( currDir != NULL ){
free(currDir);
currDir = NULL;
}
i = beginFlag - path + lenFlag;
// поиск второго флага для каталога назначения
if ( (beginFlag = strstr(path + i, checkOff)) != NULL){
checkDateDefault = 0;
lenFlag = strlen(checkOff);
i = beginFlag - path + lenFlag;
}else if ( (beginFlag = strstr(path + i, checkOn)) != NULL) {
checkDateDefault = 1;
lenFlag = strlen(checkOn);
i = beginFlag - path + lenFlag;
}else
checkDateDefault = 1;
// ///
for ( ; i < len; i++ ){
if( path[i] == ' ' || path[i] == '\011')
continue;
//printf("path = %s\ncheckDateDefault = %u\n", path + i, checkDateDefault);
retval = PathFileExists(path + i);
if (retval != 0 ){ // существует
rezGetAttr = GetFileAttributesExA(path + i, GetFileExInfoStandard, &fileAttr);
if ( rezGetAttr == 0 ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 2;
}
if ( (fileAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) // это файл(ошибочно)
isDir = 1;
else
isDir = 0;
}
if (retval != 0 && isDir){ // файл существует и это деректория
//printf("path = %s\n", path + i);
//проверка на завершающий слэш
if ( *(path + len - 1) == '\\'){
len = strlen(path + i);
currDir = malloc( len + 1); // + \0
if ( currDir == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy( currDir, path + i );
}else{
len = strlen(path + i) + 1; // + '\\'
currDir = malloc( len + 1); // + \0
if ( currDir == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy( currDir, path + i );
*(currDir + len - 1) = '\\';
*(currDir + len) = '\0';
}
lenCurrDir = len;
}else{
//записываю в список несуществующих путей.
len = strlen(path + i);
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
tempNode->next = NULL;
tempNode->item.path1 = NULL;
tempNode->item.path2 = NULL;
mem = len + 1;
tempNode -> item.path1 = (char*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy (tempNode -> item.path1, path + i);
tempNode -> item.num1 = len; // без /0
unexPath->lengthAllPaths1 += len;
if ( unexPath->begin == NULL ){ // добавляем первый элемент
unexPath->begin = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
} else { // добавляем последующие элементы
nextUnEx->next = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
}
}
break;
}
continue;
}
if ( currDir == NULL ){
// записать пропущенную строку с неуказанным каталогом назначения
len = strlen(path);
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
tempNode->next = NULL;
tempNode->item.path1 = NULL;
tempNode->item.path2 = NULL;
mem = len + 1;
tempNode -> item.path1 = (char*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy (tempNode -> item.path1, path);
tempNode -> item.num1 = len; // без /0
unexPath->lengthAllPaths1 += len;
if ( unexPath->begin == NULL ){ // добавляем первый элемент
unexPath->begin = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
} else { // добавляем последующие элементы
nextUnEx->next = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
}
continue;
}
// поиск второго флага для файла или каталога
if ( (beginFlag = strstr(path, checkOff)) != NULL){
checkDateFact = 0;
lenFlag = strlen(checkOff);
i = beginFlag - path + lenFlag;
while ( path[i] == ' ' || path[i] == '\011' )
i++;
}else if ( (beginFlag = strstr(path, checkOn)) != NULL) {
checkDateFact = 1;
lenFlag = strlen(checkOn);
i = beginFlag - path + lenFlag;
while ( path[i] == ' ' || path[i] == '\011' )
i++;
}else{
checkDateFact = checkDateDefault;
i = 0;
}
retval = PathFileExists(path + i);
//printf("path01 ==%s\n", path + i);
if (retval != 0 ){ // файл существует
// проверка, это файл или директория
rezGetAttr = GetFileAttributesExA(path + i, GetFileExInfoStandard, &fileAttr);
if ( rezGetAttr == 0 ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 2;
}
len = strlen(path + i);
if ( (fileAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ // это файл
//printf("path02 = %s\n", path + i);
//printf("test. it is File BEGIN\n");
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
tempNode->next = NULL;
tempNode->item.t1 = fileAttr.ftLastWriteTime; // структура копируется
tempNode->item.t2.dwLowDateTime = 0;
tempNode->item.t2.dwHighDateTime = 0;
tempNode->item.getCopied = 0;
tempNode->item.checkDate = checkDateFact;
mem = len + 1;
tempNode -> item.path1 = (char*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy (tempNode -> item.path1, path + i);
tempNode -> item.num1 = len; // без /0
tempNode -> item.path2 = (char*) malloc ( lenCurrDir +1 );
if ( tempNode -> item.path2 == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy (tempNode -> item.path2, currDir);
tempNode -> item.num2 = lenCurrDir; // без /0
exPath->lengthAllPaths1 += len;
exPath->lengthAllPaths1fact += len;
//printf("FF1 dubug\n");
if ( exPath->begin == NULL ){ // добавляем первый элемент
//printf("FF2 dubug\n");
exPath->begin = tempNode;
nextEx = tempNode;
exPath->nump++;
//printf("FF4 dubug\n");
} else { // добавляем последующие элементы
//printf("FF3 dubug\n");
nextEx->next = tempNode;
nextEx = tempNode;
exPath->nump++;
}
//printf("test. it is File END\n");
} else { // это директория. нужно получить вложенные файлы
if ( *(path + i + len -1) == '\\'){
*(path + i + len -1) = '\0';
len--;
}
pathN = (char*) malloc( strlen(f1) + len + 1);
if ( pathN == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
sprintf(pathN, "%s%s", path + i, f1);
handleNext = FindFirstFileA( (LPCTSTR)pathN, &dataF); // => dataF.cFileName = "."
if ( handleNext != INVALID_HANDLE_VALUE ){
findFAdd( path + i, handleNext, &dataF, exPath, &nextEx, currDir, lenCurrDir, checkDateFact);
FindClose(handleNext);
}
//else //можно обработать ошибку
free(pathN); // можно заменить pathN с выделением памяти на pathN[MAX_PATH]
}
} else { // не существует
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
tempNode->next = NULL;
tempNode->item.path1 = NULL;
tempNode->item.path2 = NULL;
mem = len + 1;
tempNode -> item.path1 = (char*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
fclose(in); // ПРОВЕРИТЬ НА ОШИБКУ
return 3;
}
strcpy (tempNode -> item.path1, path + i);
tempNode -> item.num1 = len; // без /0
unexPath->lengthAllPaths1 += len;
if ( unexPath->begin == NULL ){ // добавляем первый элемент
unexPath->begin = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
} else { // добавляем последующие элементы
nextUnEx->next = tempNode;
nextUnEx = tempNode;
unexPath->nump++;
}
}
}
fclose(in); // добавить проверку на успешное закрытие
if ( currDir != NULL ){
free(currDir);
}
//if ( handleNext != INVALID_HANDLE_VALUE )
// FindClose(handleNext);
/*
// тест. вывод прочитанных путей //
//
nextEx = exPath->begin;
while ( nextEx != NULL ){
printf("path1 = %s; num1 = %u\n", nextEx->item.path1, nextEx->item.num1);
nextEx = nextEx->next;
}
printf("nump = %u\n", exPath->nump);
printf("lengthAllPaths1 = %u\n", exPath->lengthAllPaths1);
// тест. вывод несуществующих путей
nextEx = unexPath->begin;
while ( nextEx != NULL ){
printf("path1 = %s; num1 = %u\n", nextEx->item.path1, nextEx->item.num1);
nextEx = nextEx->next;
}
printf("nump = %u\n", unexPath->nump);
printf("lengthAllPaths1 = %u\n", unexPath->lengthAllPaths1);
//
*/
return 0;
} // end ReadPaths()
// поиск вложенных файлов и добавление к основному списку существующих путей
static void findFAdd(char * path, HANDLE handleNext, WIN32_FIND_DATAA * dataF, Paths * exPath,
Node ** nextExInFind, char * currDir, int lenCurrDir, unsigned short int checkDate){
Node * tempNode;
int len, mem = 0;
char CurPath[MAX_PATH+1];
while ( FindNextFileA(handleNext, dataF) != 0 ){
if ( (dataF -> dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
sprintf(CurPath, "%s\\%s", path, dataF -> cFileName );
tempNode = malloc(sizeof(Node));
if ( tempNode == NULL ){
return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
}
tempNode->next = NULL;
tempNode->item.t1 = dataF -> ftLastWriteTime; // структура копируется
tempNode->item.t2.dwLowDateTime = 0;
tempNode->item.t2.dwHighDateTime = 0;
tempNode->item.getCopied = 0;
tempNode->item.checkDate = checkDate;
len = strlen(CurPath);
mem = len + 1;
tempNode -> item.path1 = (char*) malloc ( mem ); // выделение памяти под путь
if ( tempNode -> item.path1 == NULL ){
return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
}
strcpy (tempNode -> item.path1, CurPath); // копирование можно заменить выделением памяти
tempNode -> item.num1 = len; // без /0
tempNode -> item.path2 = (char*) malloc ( lenCurrDir +1 );
if ( tempNode -> item.path2 == NULL ){
return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
}
strcpy (tempNode -> item.path2, currDir);
tempNode -> item.num2 = lenCurrDir; // без /0
exPath->lengthAllPaths1 += len;
exPath->lengthAllPaths1fact += len;
if ( exPath->begin == NULL ){ // добавляем первый элемент
exPath->begin = tempNode;
*nextExInFind = tempNode;
exPath->nump++;
} else { // добавляем последующие элементы
(*nextExInFind)->next = tempNode;
*nextExInFind = tempNode;
exPath->nump++;
}
} else {
if ( (dataF -> cFileName)[0] == '.' && (dataF -> cFileName)[1] == '.' ) // ".."
continue;
char newDirF[MAX_PATH+1];
snprintf(newDirF, sizeof newDirF, "%s\\%s", path, dataF -> cFileName);
char pathN[MAX_PATH+1];
snprintf(pathN, sizeof pathN, "%s\\%s%s", path, dataF -> cFileName, f1);
HANDLE handleNext2 = FindFirstFileA( (LPCTSTR)(pathN), dataF); // => dataF.cFileName = "."
findFAdd(newDirF, handleNext2, dataF, exPath, nextExInFind, currDir, lenCurrDir, checkDate);
FindClose(handleNext2);
}
}
}
static int sortPaths(const void * p1, const void * p2){
const char ** s1 = (const char**) p1;
const char ** s2 = (const char**) p2;
return strcmp( *(s1), *(s2));
}
int copy(Paths * exPath, char * err, unsigned short console){
unsigned int lenDir, lenPath2, i, y, retval, found;
Node * currN;
char * tempPath2, * pFrom, * pFromN, * pTo, * pToN;
//char * tempPartPath;
int rez, rezGetAttr;
LPSHFILEOPSTRUCTA lpFileOp;
WIN32_FILE_ATTRIBUTE_DATA fileAttr;
/* struct mustNeedCreate {
char * item;
struct mustNeedCreate * next;
};
struct mustNeedCreate * pmustNeedCreate = NULL, * pmustNeedCreateNext, * pmustNeedFind;
unsigned int num_mustNeedCreate = 0; // количество узлов в списке промежуточных путей
char ** array_mustNeedCreate;
*/
//--- make destination paths
//--- create list of paths which need creat.
currN = exPath->begin;
//if (currN == NULL) // проверяю в вызывающей процедуре
// return 0;
tempPath2 = malloc( sizeof(char) * 300);
if ( tempPath2 == NULL ){
err = haventMem;
return 0;
}
//tempPartPath = malloc( sizeof(char) * 300); // копируем начальный полный путь. режем по '\'
//strcpy(tempPath2, onlyEndDir);
//lenDir = strlen(onlyEndDir);
/* //test
currN = exPath->begin;
while (currN != NULL){
printf("path1 = %s\nnum1 = %d\n--------------\n", currN->item.path1, currN->item.num1);
currN = currN-> next;
}
//test
*/
// в цикле я получаю пути назначения
while (currN != NULL){
strcpy(tempPath2, currN->item.path2);
lenDir = currN->item.num2;
free(currN->item.path2);
for (i = 0; i < currN->item.num1; i++)
if ( (currN->item.path1)[i] == ':'){
//printf("break\n");
break;
}else{
//printf("%c\n", (currN->item.path1)[i]);
*(tempPath2+lenDir+i) = (currN->item.path1)[i]; //C:\Users\usr1\AppData\Roaming\Mozilla\ert.txt
}
strcpy(tempPath2+lenDir+i, currN->item.path1 + i + 1);
//printf("tempPath2 = %s\n", tempPath2);
//printf("lenDir = %d, i = %d\n", lenDir, i);
lenPath2 = strlen(tempPath2);
currN->item.path2 = malloc( sizeof(char) * lenPath2 + 1 );
if ( currN->item.path2 == NULL ){
err = haventMem;
return 0;
}
strcpy(currN->item.path2, tempPath2);
currN->item.num2 = lenPath2;
exPath->lengthAllPaths2 += lenPath2;
retval = PathFileExists(currN->item.path2);
if (retval != 0 ){ // a target file alredy exists (It is not a dir). Get his LastWriteTime attribute.
if ( currN->item.checkDate ){
rezGetAttr = GetFileAttributesExA(currN->item.path2, GetFileExInfoStandard, &fileAttr);
if ( rezGetAttr != 0 ){
//printf("test111\n", exPath->nump);
currN->item.t2 = fileAttr.ftLastWriteTime; // структура копируется
//принимаем конечное решение о копировании.
//Сравниваем ftLastWriteTime(FILETIME) исходного пути и пути назначения
//если они равны, значит файл не менялся(исключение: программная корректировка времени)
if ( currN->item.t1.dwLowDateTime != currN->item.t2.dwLowDateTime
|| currN->item.t1.dwHighDateTime != currN->item.t2.dwHighDateTime)
currN->item.getCopied = 1;
}
}else
currN->item.getCopied = 1;
} else
currN->item.getCopied = 1;
if ( currN->item.getCopied ){
exPath->numGetCopied++;
exPath->lengthAllPaths2fact += lenPath2;
}else{
exPath->lengthAllPaths1fact -= currN->item.num1;
}
//test
//printf("path1 = %s; num1 = %u; t1l = %u; t1h = %u\n", currN->item.path1, currN->item.num1,
// currN->item.t1.dwLowDateTime, currN->item.t1.dwHighDateTime);
//printf("path1 = %s; num1 = %u; t2l = %u; t2h = %u\n", currN->item.path2, currN->item.num2,
// currN->item.t2.dwLowDateTime, currN->item.t2.dwHighDateTime);
//printf("getCopied = %d\n-----------\n", currN->item.getCopied);
/* функция SHFileOperationA() сама будет создавать нужные пути (в отличие от copyFile()).
//поэтому этот кусок больше не нужен
// членю пути назначения, получаю промежуточные каталоги от большего к меньшему:
H:\BackUps_from_Disc1\C\Users\usr1\AppData\Roaming\Mozilla\Firefox\
H:\BackUps_from_Disc1\C\Users\usr1\AppData\Roaming\Mozilla\
H:\BackUps_from_Disc1\C\Users\usr1\AppData\Roaming\
и так далее
// каждый несуществующий путь добавляю в отдельный список. Перед добавлением проверяю,
// что этого пути там ещё нет. перед основной функцией копирования НУЖНО ВСЕ ЭТИ ПУТИ СОЗДАТЬ
//printf("debug01 numbTotal = %d\n", exPath->nump);
for (y = currN->item.num2 - 1; y >= 0; y--){
strcpy(tempPartPath, currN->item.path2);
if ( tempPartPath[y] == '\\' ){
tempPartPath[y+1] = '\0'; // '\' остаётся в пути
retval = PathFileExists(tempPartPath);
// ( чтобы каждый раз не обращаться к диску, можно сделать список-КЭШ и смотреть в нём.)
if (retval != 0 ){
//printf("extsting path\n");
break; // путь существует, значит родительские пути тоже.
}else{ // текущий путь не существует. нужно проверить, если ли он в списке и если нет, то добавить.
if ( pmustNeedCreate == NULL ){ // первый элемент в списке
//printf("first create. %s\n", tempPartPath);
pmustNeedCreate = malloc(sizeof(struct mustNeedCreate));
num_mustNeedCreate++;
pmustNeedCreate->next = NULL;
pmustNeedCreate->item = malloc(sizeof(char) * (strlen(tempPartPath) + 1 ) );
// ( можно упростить вычисление текущей длины tempPartPath ? )
strcpy(pmustNeedCreate->item, tempPartPath);
pmustNeedCreateNext = pmustNeedCreate;
}else{ //последующие элементы в списке
pmustNeedFind = pmustNeedCreate;
found = 0;
while ( pmustNeedFind != NULL ){
//printf("second create. %s\n", tempPartPath);
if ( strcmp(pmustNeedFind->item, tempPartPath) == 0){
found = 1;
//printf("found. %s\n", tempPartPath);
break;
}
pmustNeedFind = pmustNeedFind->next;
}
if (found == 0){ // если путь не найден, то добавляем
//printf("not found. %s\n", tempPartPath);
pmustNeedCreateNext->next = malloc(sizeof(struct mustNeedCreate));
num_mustNeedCreate++;
pmustNeedCreateNext = pmustNeedCreateNext->next;
pmustNeedCreateNext->next = NULL;
pmustNeedCreateNext->item = malloc(sizeof(char) * (strlen(tempPartPath) + 1 ) );
// ( можно упростить вычисление текущей длины tempPartPath ? )
strcpy(pmustNeedCreateNext->item, tempPartPath);
}
}
}
}
}
*/
///////////////////////////////////////////
currN = currN-> next;
}
free(tempPath2);
//free(tempPartPath);
/*
// тест. вывод промежуточных путей, которые нужно создать
pmustNeedCreateNext = pmustNeedCreate;
while ( pmustNeedCreateNext != NULL ){
printf("path = %s\n", pmustNeedCreateNext->item);
pmustNeedCreateNext = pmustNeedCreateNext->next;
}
*/
/* функция SHFileOperationA() сама будет создавать нужные пути (в отличие от copyFile()).
поэтому этот кусок больше не нужен
//промежуточные пути нужно отсортировать в порядке возрастания(этого достаточно)
//чтобы сначала создать каталог
// H:\BackUps\C\ , а затем уже
// H:\BackUps\C\Users\ .
// для упрощения сортировки превращаем связный список в массив. При
// этом освобождается только память узлов, но не массивов, которые хранят
// полезные данные.(В списке содержатся промежуточные пути. Указатели на них
// будут переброшены в массив.)
if ( num_mustNeedCreate > 0 )
array_mustNeedCreate = (char**) malloc( sizeof(char * ) * num_mustNeedCreate );
i = 0;
// очистить память pmustNeedCreate и одновременно заполнить массив
while ( pmustNeedCreate != NULL ){
pmustNeedCreateNext = pmustNeedCreate->next;
//free(pmustNeedCreate->item);
*(array_mustNeedCreate + i) = pmustNeedCreate->item;
i++;
free(pmustNeedCreate);
pmustNeedCreate = pmustNeedCreateNext;
}
// тест. вывод промежуточных путей, которые нужно создать
//for(i = 0; i < num_mustNeedCreate; i++)
// printf("%s\n", *(array_mustNeedCreate + i) );
//сортировка
if ( num_mustNeedCreate > 1 )
qsort(array_mustNeedCreate, num_mustNeedCreate, sizeof(char * ), sortPaths);
// тест. вывод промежуточных путей, которые нужно создать
//for(i = 0; i < num_mustNeedCreate; i++)
// printf("%s\n", *(array_mustNeedCreate + i) );
// создание промежуточных путей из pmustNeedCreate
for(i = 0; i < num_mustNeedCreate; i++)
CreateDirectoryA(*(array_mustNeedCreate + i), NULL); // проверить возвращаемое значение
// владелец создаваемых каталогов == пользователю, запустившему приложение
// очистить память array_mustNeedCreate
for(i = 0; i < num_mustNeedCreate; i++)
free( *(array_mustNeedCreate + i) );
if ( num_mustNeedCreate > 0 )
free( array_mustNeedCreate );
*/
// COPING ------ COPING ------ COPING ------ COPING ------ COPING
// CopyFile() даёт ошибку ERROR_SHARING_VIOLATION. Буду использовать SHFileOperationA()
// эта функция может сама создавать каталоги.
// SHFileOperationA() также предусматривает флаг FOF_MULTIDESTFILES и можно указывать
// множественные соответствия откуда и куда копировать
if ( exPath->numGetCopied == 0 ){ //все файлы могли быть скопированы ранее и не изменились за это время
return 0;
}
//printf("numGetCopied == %d\n", exPath->numGetCopied);
pFrom = malloc( sizeof(char) * ( exPath->lengthAllPaths1fact + exPath->numGetCopied + 1) );
if ( pFrom == NULL ){
err = haventMem;
return 0;
}
pFromN = pFrom;
pTo = malloc( sizeof(char) * ( exPath->lengthAllPaths2fact + exPath->numGetCopied + 1) );
if ( pTo == NULL ){
err = haventMem;
return 0;
}
pToN = pTo;
currN = exPath->begin;
while (currN != NULL){
if ( currN->item.getCopied == 1 ){
strcpy (pFromN, currN->item.path1);
//test
//printf("p1==%s p2==%s num1==%u num2==%d\n", currN->item.path1, currN->item.path2, currN->item.num1, currN->item.num2);
pFromN = pFromN + currN->item.num1 + 1;
strcpy (pToN, currN->item.path2);
//printf("pTo = %s\n--------------\n", pToN);
pToN = pToN + currN->item.num2 + 1;
}
currN = currN-> next;
}
*pFromN = '\0'; // or pFromN[0] // => '\0\0'
*pToN = '\0';
//printf("lengthAllPaths1 = %d\nlengthAllPaths2 = %d\nnump = %d\n--------------\n",
//exPath->lengthAllPaths1, exPath->lengthAllPaths2, exPath->nump);
/*FILE * ff = fopen("test.txt", "w");
fwrite(pFrom, sizeof(char), exPath->lengthAllPaths1fact + exPath->numGetCopied + 1, ff);
fwrite(pTo, sizeof(char), exPath->lengthAllPaths2fact + exPath->numGetCopied + 1, ff);
fclose(ff);
*/
lpFileOp = malloc(sizeof(SHFILEOPSTRUCTA));
if ( lpFileOp == NULL ){
err = haventMem;
return 0;
}
lpFileOp -> hwnd = 0;
lpFileOp -> wFunc = FO_COPY;
lpFileOp -> pFrom = pFrom;
lpFileOp -> pTo = pTo;
if (!console)
lpFileOp -> fFlags = FOF_MULTIDESTFILES | FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION; // | FOF_SIMPLEPROGRESS;
else
lpFileOp -> fFlags = FOF_MULTIDESTFILES | FOF_NO_UI;
/*
FOF_NO_UI==1556
FOF_MULTIDESTFILES==1
FOF_NOCONFIRMMKDIR==512
FOF_NOCONFIRMATION==16
*/
// при FOF_MULTIDESTFILES нужно задавать полные конечные пути для каждого файла.
// можно указывать конечное имя файла, отличное от начального имени.
//lpFileOp -> fAnyOperationsAborted
lpFileOp -> hNameMappings = NULL;
lpFileOp -> lpszProgressTitle = NULL;
rez = SHFileOperationA( lpFileOp );
if (rez != 0 ){
sprintf(pFrom, "Ошибка при копировании файлов. error = %d (%x)", rez, rez);
lenPath2 = strlen(pFrom);
err = (char*) malloc( lenPath2 + 1 );
if (err != NULL) // fix me
strcpy(err, pFrom);
else
err = haventMem;
//MessageBox(NULL, pFrom, "_CopyFiles_", MB_OK);
}
/*currN = exPath->begin;
while (currN != NULL){
//printf("path1 = %s\npath2 = %s\n--------------\n", currN->item.path1, currN->item.path2);
//CopyFile( currN->item.path1, currN->item.path1, FALSE);
//прохожу весь список соответствий путей и формирую строки pFrom и pTo для структуры SHFILEOPSTRUCTA structure
//printf("error %d\n--------\n", GetLastError());
//err no 32 (0x20) - The process cannot access the file because it is being used by another process.
currN = currN-> next;
}*/
free(pFrom);
free(pTo);
free(lpFileOp);
return 0;
}
int freePaths(Paths * exPath, Paths * unexPath){ // соединить циклы. они одинаковые
Node * currN = NULL;
Node * nextN;
currN = exPath->begin;
while (currN != NULL){
nextN = currN-> next;
if (currN->item.path1 != NULL)
free(currN->item.path1);
if (currN->item.path2 != NULL)
free(currN->item.path2);
free(currN);
currN = nextN;
}
exPath->nump = 0;
/////////////////////////////////
currN = unexPath->begin;
while (currN != NULL){
nextN = currN-> next;
if (currN->item.path1 != NULL)
free(currN->item.path1);
if (currN->item.path2 != NULL)
free(currN->item.path2);
free(currN);
currN = nextN;
}
unexPath->nump = 0;
}
> 50
|
|
Комментарии