I am trying to encrypt all the files in a particular folder and that folder has sub folders when i try to print all the files it works good but when i try to encrypt all the files it keeps on encrypting the same file again and again
void dirListFiles(wchar_t *startDir) {
HANDLE hFind;
WIN32_FIND_DATA wfd;
wchar_t path[99999];
char *enName;
const char *extension = ".enc";
int wcsChars;
wsprintf(path, L"%s\\*", startDir);
if ((hFind = FindFirstFile(path, &wfd)) == INVALID_HANDLE_VALUE) {
return;
}
do {
if ((wcsncmp(L".", wfd.cFileName, 1) !=0) && (wcsncmp(L"..", wfd.cFileName, 2) != 0) ) {
wsprintf(path, L"%s\\%s", startDir, wfd.cFileName);
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
dirListFiles(path);
} else {
wcsChars = wcslen(path);
char *szTo = new char[wcsChars + 1];
szTo[wcsChars] = '\0';
WideCharToMultiByte(CP_ACP, 0, path, -1, szTo, wcsChars, NULL, NULL);
enName = (char *)malloc(strlen(szTo) + 1 + 4);
strcpy(enName, szTo);
strcat(enName, extension);
// If i add this line it keeps on encrypting the same file
//fencrypt(szTo, enName, (unsigned const char*)"1234567812345678");
printf("%s\n", enName);
delete[] szTo;
free(enName);
}
}
} while(FindNextFile(hFind, &wfd));
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return;
}
}
If i add fencrypt(szTo, enName, (unsigned const char*)"1234567812345678"); then it encrypts the files in the main folder that is G:\WinApp but when it enters G:\WinApp\ipch\winapp-1918e0a3 it keeps on encrypting the same file again and again there is no file in G:\WinApp\ipch\ only a folder winapp-1918e0a3 this is my encryption function please tell where am i wrong
void fencrypt(char* read, char* write, const unsigned char* enc_key) {
RAND_bytes(iv, AES_BLOCK_SIZE);
readFile = fopen(read,"rb");
writeFile = fopen(write,"wb");
fwrite(iv, 1, 8, writeFile);
fwrite("\0\0\0\0\0\0\0\0", 1, 8, writeFile);
AES_set_encrypt_key(enc_key, 256, &key);
init_ctr(&state, iv);
while(1) {
bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile);
AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num);
bytes_written = fwrite(outdata, 1, bytes_read, writeFile);
if (bytes_read < AES_BLOCK_SIZE) {
break;
}
}
fclose(writeFile);
fclose(readFile);
}
I'm far from 100% sure, but I have a feeling that when you create a new file in your directory, the FindNextFile gets confused and finds the same filename again because it's not actually the same file. You may need to either collect a list of all files in a directory and process them one at a time, or keep a list of what you have already done and skip over the ones you have done.
The FindNextFile call will probably see the newly appeared encrypted file and therefore you will keep processing the new files also.
Since you are appending an ".enc" extension to your encrypted files, it would be relatively simple to skip files that already have this extension.
Related
I wrote a simple code to do some operation on every file in every folder (subfolders).
It's perfectly works until the path comes with 'SPACE
' character program crashs and INVALID_HANDLE_VALUE has been called. This is function:
int dirListFiles(char* startDir)
{
HANDLE hFind;
WIN32_FIND_DATAA wfd;
char path[MAX_PATH];
sprintf(path, "%s\\*", startDir);
std::string fileName;
std::string s_path = startDir;
std::string fullPath;
fprintf(stdout, "In Directory \"%s\"\n\n", startDir);
if ((hFind = FindFirstFileA(path, &wfd)) == INVALID_HANDLE_VALUE)
{
printf("FindFirstFIle failed on path = \"%s\"\n", path);
abort();
}
BOOL cont = TRUE;
while (cont == TRUE)
{
if ((strncmp(".", wfd.cFileName, 1) != 0) && (strncmp("..", wfd.cFileName, 2) != 0))
{
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(path, "%s\\%s", startDir, wfd.cFileName);
dirListFiles(path);
}
else
{
fileName = wfd.cFileName;
fullPath = s_path + "\\" + fileName;
std::string fileExt = PathFindExtension(fullPath.c_str());
if (fileExt == ".cpp")
{
... Some operation on file
}
}
}
cont = FindNextFile(hFind, &wfd);
}
FindClose(hFind);
For example, If FindNextFile wants to Open Program Files (x86) which has space between file name cause error and program exit. What Can I do for supporting spaces? What Is Problem?
Space is legal character in directory and file names.
First I propose to modify slightly your code:
if ((hFind = FindFirstFileA(path, &wfd)) == INVALID_HANDLE_VALUE)
{
printf("FindFirstFIle failed on path = \"%s\". Error %d\n", path, GetLastError());
return 0; // I think you shouldn't abort on error, just skip this dir.
}
Now check error codes reported by your program.
For some paths I have got error #5 (access denied). Examples:
c:\Program Files (x86)\Google\CrashReports\*
c:\ProgramData\Microsoft\Windows Defender\Clean Store\*
c:\Windows\System32\config\*
Got two cases with code #123 (Invalid name) for path names unmanageable by FindFirstFileA. To correct this behavior it would be better to use wide version of function FindFirstFileW. See both answers for c++ folder only search. For new Windows applications you should use wide version of API, converting with MultiByteToWideChar and WideCharToMultiByte if needed.
You have also logic error. Code skips all directories and files starting with dot.
I write for myself a small program in C ++, which could perform some operations on files that it finds (in my filter), and that's stumbled on the mechanism of searching for files. At start the program asks the full path, and then by file type recursively looking for them in all subdirectories of the selected directory. The trouble is that after performing an operation (cycle fopen - operation - fclose) can not rename or delete the file. The program simply exits with code 0. It is I sin on the file searching mechanism, as is likely, the function uses image for the time of its implementation and does not delete or rename the file. I tried different options to manage files through WinAPI, std (fstream) and just fopen / fclose. Nothing comes out.
Code snippet:
int main() {
char sPath[MAX_PATH] = "C:\\TmpDir";
char sExt[10] = "doc";
char sEXT[10] = "DOC";
GetFileList(sPath, sExt, sEXT);
printf("Results= %d\n", rez);
system("pause");
return 0;
}
void GetFileList(LPTSTR sPath, LPTSTR sExt, LPTSTR sEXT) {
WIN32_FIND_DATA pFILEDATA;
HANDLE hFile = FindFirstFile(strcat(sPath, "\\*.*"), &pFILEDATA);
sPath[strlen(sPath) - strlen(strstr(sPath, "*.*"))] = '\0';
if (hFile != INVALID_HANDLE_VALUE) {
char * chBuf;
do {
if (strlen(pFILEDATA.cFileName) == 1 && strchr(pFILEDATA.cFileName, '.') != NULL)
if (FindNextFile(hFile, &pFILEDATA) == 0)
break;
if (strlen(pFILEDATA.cFileName) == 2 && strstr(pFILEDATA.cFileName, "..") != NULL)
if (FindNextFile(hFile, &pFILEDATA) == 0)
break;
if (pFILEDATA.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
GetFileList(strcat(sPath, pFILEDATA.cFileName), sExt, sEXT);
sPath[strlen(sPath) - strlen(pFILEDATA.cFileName) - 1] = '\0';
} else {
if ((chBuf = strrchr(pFILEDATA.cFileName, '.'))) {
if (strstr(chBuf + 1, sExt) || strstr(chBuf + 1, sEXT)) {
CharToOem(sPath, sPath);
printf("%s", sPath);
OemToChar(sPath, sPath);
CharToOem(pFILEDATA.cFileName, pFILEDATA.cFileName);
printf("%s\n", pFILEDATA.cFileName);
/* Какая-то операция с файлом.
...
Конец операции с файлом. */
rez++;
}
}
}
} while (FindNextFile(hFile, &pFILEDATA));
}
}
I'm using libzip in a c++ application for Linux that will need to be able to zip/unzip directories containing symbolic links. I want to add the link itself without following it. Reading out the link with readlink() and adding it to the zip archive results in a nonsense standard file when unzipped with unzip.
Solution does not need to be portable, it will only be used under Linux. The linux zip command has a --symlinks flags so the zip standard should support it. System calls are not really an option, the number of files is quite large and this makes the application extremely slow.
Is it possible to add symlinks with libzip, and how?
Thanks,
Sander
Based on documentation: no
According to its webpage, libzip is based on zlib. The zip program used in Linux, etc, is info-zip, which does not use zlib, but is self-contained (and contains features not in zlib).
Yes it's possible.
Below a function i use for zipping a list of files in c-code.
The files to zip are stored in a cJSON struct,no uid/gid set and files/directories relative to a directory "base" (as that is my appliction).
The Function returns 0 on success.
int list_zip_it(char * upload_zip_name,char * base, cJSON * filelist)
{
int result=0;
int error_n = 0;
struct zip *archive = zip_open(upload_zip_name, ZIP_TRUNCATE | ZIP_CREATE, &error_n);
if(!archive)
{
printf(stderr,"could not open or create archive\n");
return -1;
}
mode_t mode=0;
cJSON * item;
cJSON_ArrayForEach(item,filelist)
{
char * path=NULL;
path=item->valuestring;
// stat the item
struct stat sb;
if (stat(path, &sb) == 0 ) mode=sb.st_mode;
zip_uint32_t attr=0;
attr=((mode ) << 16L);
char rel_file[1024];
if (strncmp(path,CI_PROJECT_DIR,strlen(base))==0 )
{
snprintf(rel_file,1024,"%s",path+strlen(base)+1);
printf("archive filename: %s\n",rel_file);
}
else
{
fprintf(stderr,"filename outside base-derectory\n");
continue;
}
if (S_ISDIR(mode))
{
int index = (int)zip_add_dir(archive, rel_file);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else if (S_ISLNK(mode)) // symlink
{
char link[1024];//=calloc(1, 1024);
memset(link, 0, 1024);
ssize_t size_link=readlink(path , link, 1023);
if (size_link > 0)
{
struct zip_source *source = zip_source_buffer(archive , link, ( zip_uint64_t)size_link,0);
if (source)
{
int index = (int)zip_add(archive, rel_file, source);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else
{
printf(stderr,"failed to create source buffer: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
}
else error("failed to read link: %s \n",path );
}
else if (S_ISREG(mode))
{
struct zip_source *source = zip_source_file(archive, path, 0, 0);
if(source == NULL)
{
error("failed to create source buffer: %s \n", zip_strerror(archive) );
result=1;
break;
}
// todo calculate filename relative to project_dir
int index = (int)zip_add(archive, rel_file, source);
if(index < 0 )
{
int zep,sep;
zip_error_get(archive, &zep, &sep);
if (zep== ZIP_ER_EXISTS )
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
else
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
result=1;
break;
}
}
else
{
zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
}
}
zip_close(archive);
return result;
}
I'm using the libssh library in MFC C++, specifically the SFTP wrapper. I have code working when not using threading, but I want to use AfxBeginThread to allow user action to continue.
I have confirmed I'm passing the exact same filenames and target save paths using the thread or not - I've tested this by hardcoding the file to save and the destination to save directly in BeginDownload().
Is there a specific way the SFTP wrapper for the libssh must be used to let the download perform within a thread? I would like to allow users to download multiple files at the same time from the same instance of the ssh objects, and just launch a new thread each time a file needs to be downloaded.
Here is what I'm using for the actual downloading. m_sftp_sesssion is my sftp_session object created upon logging in.
bool CSFtpManager::BeginDownload(CString filename, CString savefilename)
{
sftp_dir dir = sftp_opendir(m_sftp_session, "../../../directory");
sftp_attributes attrs = sftp_readdir(m_sftp_session, dir);
int access_type = O_RDONLY;
sftp_file file;
file = sftp_open(m_sftp_session, "../../../directory/myfile.zip", access_type, 0);
const char* x2 = ssh_get_error(m_ssh_session);
if(file == NULL)
{
int a;
}
int nbytes;
char buffer[1024];
FILE * pFile;
pFile = fopen(CStringA(savefilename), "wb");
nbytes = sftp_read(file, buffer, sizeof(buffer)); //this is crashing inside a thread
while(nbytes > 0)
{
fwrite(buffer, sizeof(char), sizeof(buffer), pFile);
nbytes = sftp_read(file, buffer, sizeof(buffer));
}
fclose(pFile);
sftp_close(file);
return true;
}
Here is my login method where my libssh objects are being set in member variables for later use. Included is a commented line calling my BeginDownload. Calling it outside a thread (i.e. clicking a login button) does work.
bool CSFtpManager::login()
{
int verbosity = SSH_LOG_PROTOCOL;
m_ssh_session = ssh_new();
ssh_options_set(m_ssh_session, SSH_OPTIONS_HOST, "ftp3 host..");
//setting username and password...
ssh_options_set(m_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(m_ssh_session, SSH_OPTIONS_PORT, &m_iPort);
int x = ssh_connect(m_ssh_session);
const char* x2 = ssh_get_error(m_ssh_session);
if(rc != SSH_AUTH_SUCCESS)
{
return false;
}
m_sftp_session;
m_sftp_session = sftp_new(m_ssh_session);
//Calling BeginDownload here does work
//BeginDownload(L"file.txt", L"T:\\file.txt");
... }
Here is what I'm using to call the exact same function via a thread
CWinThread* pThread2 = AfxBeginThread(BeginSFTPDownload, bundle);
And the method being ran via the above:
UINT CMainFrame::BeginSFTPDownload( LPVOID pParam)
{
pSft->BeginDownload(L"test.txt", L"T:\\test.txt");
return 0;
}
I'm trying to read all files in a directory. I have the following code:
void scanDirectory(char* dir)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
char DirSpec[MAX_PATH]; // directory specification
strcpy(DirSpec, dir);
strcat(DirSpec, "\\*");
hFind = FindFirstFile(DirSpec, &FindFileData);
int i = 0;
do {
i++;
printf("%d \n", i);
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
printf(" %s <DIR>\n", FindFileData.cFileName);
}
else
{
printf("File %s\n", FindFileData.cFileName);
}
} while(!FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
The problem is that when I execute the code it results in an infinite loop. Also the output characters are strange, like "File ".
I think you are not using chars and wide chars in a consequent way. You should either use functions with wide char and wchar_t type or vice versa. (But it was a compile error for me so it may depend on some kind of project settings as well.)
And your exit condition in the while loop is also wrong it should test for FindNextFile and not !FindNextFile. The infinite loop may be because of this condition as if it doesn't find any files it will run forever.
Also you should test for the return value of FindFirstFile and not go into the loop if it doesn't find any files.
You are calling !FindNextFile instead of FindNextFile, also you are not checking why
the FindNextFile fails, so you can't be sure if all the files were processed.
Use something like this.
WIN32_FIND_DATA stFindData;
HANDLE hFind = FindFirstFile(cSearchPattern, &stFindData);
if(hFind != INVALID_HANDLE_VALUE)
{
do
{
// Process File
}
while (FindNextFile(hFind, &stFindData) != 0);
DWORD dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
// Not All Files processed, deal with Error
}
FindClose(hFind);
}
Can't you just use .Net like below:
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(Path);
System.IO.FileInfo[] files = dir.GetFiles();
foreach (System.IO.FileInfo file in files)
{
// Do whatever you need with the file info...
string filename = file.Name;
string fullFilename = file.FullName;
}
This is a c# example but you can use for each in C++ the same. Hope this helps.