+7(960) 250-82-68 spam@mirossa.ru


 mirossa        1С           C         PHP       JAVA       MCU  


Статьи
 
 

26 марта 2020

Резервное копирование файлов

win.exe CMD.exe скачать 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 ).

title.exe

title.exe

title.exe

/* файл 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

Комментарии




information