print all files and subdirectories in a give path - c

So, im writing a program to recursively print the directories/sub-directories and files in a given path. im able to go in the first sub-directory and print all the files in it. my problem right now is i need find a way to step back one directory level and continue from where i left off reading. Until the condition occurs at the original directory level.
#include "Everything.h"
#include "Strsafe.h"
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
LARGE_INTEGER fileSize;
DWORD dwError;
void showdir(TCHAR *szDir);
int _tmain(int argc, LPCTSTR argv[])
{
TCHAR szDir[MAX_PATH];
size_t lengthOfArg;
// verify number of parameters
if (argc != 2)
{
ReportError(_T("Error: Incorrect number of arguments"), 1, FALSE);
}
// get the length of the entered directory
StringCchLength(argv[1], MAX_PATH, &lengthOfArg);
// verify that the directory path is not too long
if (lengthOfArg > MAX_PATH - 2)
{
ReportError(_T("Error: Directory too long"), 2, FALSE);
}
// attach an asterisk (wildcard search char) to end of directory path
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, _T("*"));
showdir(szDir);
}
void showdir(TCHAR *szDir)
{
// begin the search; find the first file in the directory
hFind = FindFirstFile(szDir, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
ReportError(_T("Error in searching"), 3, TRUE);
}
//hFind = FindFirstFile(szDir, &ffd);
while (FindNextFile(hFind, &ffd) != 0)
{
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
fileSize.LowPart = ffd.nFileSizeLow;
fileSize.HighPart = ffd.nFileSizeHigh;
_tprintf(_T("%s %ld\n"), ffd.cFileName, fileSize.QuadPart);
}
// did we find a directory?
// ffd.dwFileAttributes says this is a directory (FILE_ATTRIBUTE_DIRECTORY)
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& (_tcscmp(ffd.cFileName, _T(".")) != 0 && (_tcscmp(ffd.cFileName, _T("..")) != 0)))
{
TCHAR fullpath[MAX_PATH];
StringCchCopy(fullpath, strlen(szDir) - 0, szDir);
StringCchCat(fullpath, MAX_PATH, ffd.cFileName);
StringCchCat(fullpath, MAX_PATH, "\\");
_tprintf(_T("<DIR> %s \n"), fullpath);
StringCchCat(fullpath, MAX_PATH, _T("*"));
showdir(fullpath);
}
// continue the search; try to find more files
}
// figure out if we encountered an error other than "no more files"
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
ReportError(_T("Error in searching"), 4, TRUE);
}
FindClose(hFind);
}

Your global variables
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
LARGE_INTEGER fileSize;
DWORD dwError;
should all be local variables of showdir().
Then each recursion level has its own search handle, and when a nested showdir()
returns, the calling showdir() can simply continue enumerating its directory.
Note also that your code ignores the first file in each directory (the result
of FindFirstFile()). You could it rewrite as (error checking omitted for brevity):
hFind = FindFirstFile(szDir, &ffd);
do {
// ... handle ffd ...
} while (FindNextFile(hFind, &ffd))

Related

PE FILE reading in c

I need to check if file is PE file or not. I need to check first two byte is MZ or not and I did this.
This is my task: When verifying the PE format, not only according to the MZ expression, but also using the conditions that the IMAGE_NT_HEADERS structure is read and the Signature field is verified by reading the IMAGE_FILE_HEADER field and the Machine field is equal to the Th value IMAGE_FILE_MACHINE_I386 or IMAGE_FILE_MACHINE_AMD64.
I cannot figure how can do the rest of them. I hope you can help me.
int checkPE(char *file){
int fd=open(file,READ_FLAGS,0777);
char buffer[TWOBYTE+1] = {'\0'};
size_t bytes_read;
char ch;
if(fd==-1){ //if file cannot be opened give a error message.
perror("The file cannot be opened.\n");
return -1;
}
bytes_read = read(fd,buffer,TWOBYTE);
if(bytes_read==-1){
perror("Error while reading file\n");
return -1;
}
if(strcmp(buffer,MZ)!=0){
return -1;
}
int closeFlag = close(fd);
if(closeFlag==-1){
perror("The file cannot be closed.\n");
return -1;
}
}
There is nothing more than just parsing some structures. You have already the algorithm. I assume that you just need the implementation. Consider the following example utility.
PS: For further details, just comment it below.
#include <stdio.h>
#include <windows.h>
BOOL CheckValidity(BYTE* baseAddress);
int main(int argc, char* argv[]) {
if (argc != 2)
{
printf("You didn't specified a PE file.\n");
printf("Usage: CheckPEImage.exe <Full path of PE File>\n");
return -1;
}
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return -1;
HANDLE hMemoryMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMemoryMap)
return -2;
PBYTE baseAddress = (PBYTE)MapViewOfFile(hMemoryMap, FILE_MAP_READ, 0, 0, 0);
if (!baseAddress)
return -3;
printf("PE Image is %s.\n", CheckValidity(baseAddress) ? "valid" : "invalid");
getchar();
return 0;
}
BOOL CheckValidity(BYTE* baseAddress)
{
PIMAGE_DOS_HEADER lpDosHeader;
PIMAGE_FILE_HEADER lpFileHeader;
PIMAGE_NT_HEADERS lpNtHeaders;
PIMAGE_OPTIONAL_HEADER lpOptionalHeader;
lpDosHeader = (PIMAGE_DOS_HEADER)baseAddress;
lpNtHeaders = (PIMAGE_NT_HEADERS)(baseAddress + lpDosHeader->e_lfanew);
if (lpDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return FALSE;
if (lpNtHeaders->Signature != IMAGE_NT_SIGNATURE)
return FALSE;
if (lpNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 && lpNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
return FALSE;
return TRUE;
}

How can I list all files in a directory on Windows without using dirent.h in C?

I can't find any way to list all files without using dirent.h. Does anyone have an idea or suggestions?
I can't work with dirent.h because my compiler doesn't work with it, so this is why I am searching for another option
I run and write the program on Windows 10.
You want to use FindFirstFile, FindNextFile, and FindClose. Microsoft provides an example on MSDN:
Listing the Files in a Directory
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")
void DisplayErrorBox(LPTSTR lpszFunction);
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
// If the directory is not specified as a command-line argument,
// print usage.
if(argc != 2)
{
_tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
return (-1);
}
// Check that the input path plus 3 is not longer than MAX_PATH.
// Three characters are for the "\*" plus NULL appended below.
StringCchLength(argv[1], MAX_PATH, &length_of_arg);
if (length_of_arg > (MAX_PATH - 3))
{
_tprintf(TEXT("\nDirectory path is too long.\n"));
return (-1);
}
_tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);
// Prepare string for use with FindFile functions. First, copy the
// string to a buffer, then append '\*' to the directory name.
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
// Find the first file in the directory.
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
DisplayErrorBox(TEXT("FindFirstFile"));
return dwError;
}
// List all the files in the directory with some info about them.
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
void DisplayErrorBox(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and clean up
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}

How to get the list of all drives in C

Is there any method using which i can list down all the available drives and their folder content. ie i want to access all the drives and then the folders in each drive and then the sub-folders of each folder and so on till the last possible level in each drive.
C language .. Windows platform .. i have tried using alphabetic array with system() but am unable to get the names of files and folders .
This is not "standard C" (ie: ANSI, C89, C99, etc), but it makes minimal use of operating-system specific calls (ie: just "windows.h", not MS .NET or MFC technologies). This is the minimalist approach to what you are attempting to do. Once you have a list of all drive letters, you need to query each drive recursively for its directory listings.
This is a mix of C and C++, but you'll likely be using a free version of Visual Studio to build this anyways.
Code Listing - Get drive letters
#include <windows.h>
#include <stdio.h>
int main()
{
char buf[255];
// get the drive letters as a set of strings
int sz = GetLogicalDriveStrings(sizeof(buf), buf);
if( sz > 0)
{
// buf now contains a list of all the drive letters. Each drive letter is
// terminated with '\0' and the last one is terminated by two consecutive '\0' bytes.
char* p1 = buf;
char* p2;
while( *p1 != '\0' && (p2 = strchr(p1,'\0')) != NULL )
{
printf("%s\n", p1);
p1 = p2+1;
}
}
else
{
// Oops! something went wrong so display the error message
DWORD dwError = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, buf, sizeof(buf), 0);
printf("%s\n", buf);
}
}
Code Listing - Directory listing
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")
void DisplayErrorBox(LPTSTR lpszFunction);
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
// If the directory is not specified as a command-line argument,
// print usage.
if(argc != 2)
{
_tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
return (-1);
}
// Check that the input path plus 3 is not longer than MAX_PATH.
// Three characters are for the "\*" plus NULL appended below.
StringCchLength(argv[1], MAX_PATH, &length_of_arg);
if (length_of_arg > (MAX_PATH - 3))
{
_tprintf(TEXT("\nDirectory path is too long.\n"));
return (-1);
}
_tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);
// Prepare string for use with FindFile functions. First, copy the
// string to a buffer, then append '\*' to the directory name.
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
// Find the first file in the directory.
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
DisplayErrorBox(TEXT("FindFirstFile"));
return dwError;
}
// List all the files in the directory with some info about them.
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
void DisplayErrorBox(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and clean up
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
References
List Windows Logical Drive Letters, Accessed 2014-08-01, <http://www.daniweb.com/software-development/c/code/237803/list-windows-logical-drive-letters>
Listing the Files in a Directory, Accessed 2014-08-01, <http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200%28v=vs.85%29.aspx>
Standard C has no way to directly address the drive, or, for that matter, even know what a drive is.
Generally, each C compiler vendor will include a library which handles those things for the specific platform the compiler is written for. But these are all specific to the vendor.
Boost has cross-platform library for C++, including one for dealing with the file system.

Enumerate files in directory with wildcard in C

I use code like this to enumerate all shader files in subdirectory shaders:
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
shader_counter = 1;
pclog("searching shader files \n");
hFind = FindFirstFile("shaders\\*.fx", &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
pclog("no shader files found \n");
}
else
{
pclog("shader files found \n");
while(hFind!=INVALID_HANDLE_VALUE)
{
pclog("Filename=%s\n",FindFileData.cFileName);
hFind = FindNextFile(hFind, &FindFileData);
shader_counter++;
}
pclog("Exit loop\n");
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
But it only outputs 3 files out of many and crashes. What am I doing wrong ?
Edit , this is correct code to enumerate subdirectory using wildcard , maybe someone will find it usefull:
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
BOOL found = TRUE;
hFind = FindFirstFile("shaders\\*.fx", &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{ // directory/wildcard not found
}
else
{
while(found)
{
//printf("Filename=%s\n",FindFileData.cFileName);
found = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
According to the Microsoft documentation, the return value to FindNextFile is not the same as for FindFirstFile. FindNextFile returns a boolean value:
...
BOOL found = TRUE;
printf("shader files found \n");
while (found)
{
printf("Filename=%s\n",FindFileData.cFileName);
found = FindNextFile(hFind, &FindFileData);
shader_counter++;
}
printf("Exit loop\n");
FindClose(hFind);
...
(It has to be an independent value, otherwise you would pass an invalid handle to FindClose.)

the file extension in StringCbCatN() to get all the files name withextension

Code that I am running now:
int main(int argc, char *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError;
LPSTR DirSpec;
size_t length_of_arg;
int i,j;
char cd[256],schar[500];
FILE *fp;
DirSpec = (LPSTR) malloc (BUFSIZE);
// Check for command-line parameter; otherwise, print usage.
if(argc != 2)
{
printf("Usage: Test <dir>\n");
return 2;
}
// Check that the input is not larger than allowed.
//scanf("%s",argv[1]);
StringCbLength(argv[1], BUFSIZE, &length_of_arg);
if (length_of_arg > (BUFSIZE - 2))
{
printf("Input directory is too large.\n");
return 3;
}
printf ("Target directory is %s.\n", argv[1]);
StringCbCopyN (DirSpec, BUFSIZE, argv[1], length_of_arg+1);
StringCbCatN (DirSpec, BUFSIZE, "\\namefile.b11", 18);
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("Invalid file handle. Error is %u.\n", GetLastError());
return (-1);
}
else
{
printf ("First file name is %s.\n", FindFileData.cFileName);
fp=fopen(DirSpec,"rb");
for(i=0;i< 8;i++)
{
schar[i]= fgetc(fp);//get each character from file
}
if ( i > 7 )
{
cd[i]=schar[6]*65336+schar[5]*256+schar[4];
printf("%d",cd[i]);
}
// List all the other files in the directory.
while (FindNextFile(hFind, &FindFileData) != 0)
{
printf ("Next file name is %s.\n", FindFileData.cFileName);
}
dwError = GetLastError();
FindClose(hFind);
if (dwError != ERROR_NO_MORE_FILES)
{
printf ("FindNextFile error. Error is %u.\n", dwError);
return (-1);
}
}
free(DirSpec);
getchar();
return (0);
}
This is working fine. If I concatinate the file name directly by using StringCbCatN().
But for every file I need to change the file name.which I don't want. Is it possible to print the file with file extension?

Resources