I am using the code below to save file names to an array. I got the code from here save file names to an array. When I run this code it says that there are 5 files in the directory (i.e. count is 5), however, there are only 3. Could somebody verify if this is correct or am I making a bad mistake?
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <malloc.h>
size_t file_list(const char *path, char ***ls) {
size_t count = 0;
size_t length = 0;
DIR *dp = NULL;
struct dirent *ep = NULL;
dp = opendir(path);
if(NULL == dp) {
fprintf(stderr, "no such directory: '%s'", path);
return 0;
}
*ls = NULL;
ep = readdir(dp);
while(NULL != ep){
count++;
ep = readdir(dp);
}
rewinddir(dp);
*ls = calloc(count, sizeof(char *));
count = 0;
ep = readdir(dp);
while(NULL != ep){
(*ls)[count++] = strdup(ep->d_name);
ep = readdir(dp);
}
closedir(dp);
return count;
}
int main(int argc, char **argv) {
char **files;
size_t count;
int i;
count = file_list("/home/rgerganov", &files);
for (i = 0; i < count; i++) {
printf("%s\n", files[i]);
}
}
I asked myself the same question for a school project a few months ago. When you use the dirent structure and you list them accessing the element d_name, it actually counts the directories PLUS the "." and the "..", so it's normal. If you don't want to take them as directories, just create an iterator variable for the loop and add a condition like:
int i = 0;
while (condition)
{
if (ep->d_name[i] == '.' )
{
++i;
}
//do stuff here
}
Related
I want to read all .txt files in the directory and add those file names to an array. Catching the text files part is okay but I am having a problem storing those file names inside an array. What is the mistake I've done here? This is my code.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <strings.h>
int main()
{
DIR *p;
struct dirent *pp;
p = opendir ("./");
char file_list[10][10];
char shades[10][10];
int i = 0;
if (p != NULL)
{
while ((pp = readdir (p))!=NULL) {
int length = strlen(pp->d_name);
if (strncmp(pp->d_name + length - 4, ".txt", 4) == 0) {
puts (pp->d_name);
strcpy(shades[i], pp->d_name);
}
}
i = i + 1;
(void) closedir (p);
for(int i=0; i<4; i++){
printf("\n %s", &shades[i]);
}
}
return(0);
}
What seems to be a problem here is that 'strings' in C works much different than in C++ or C# or Python.
To make it work you'll need to alloc memory for each string.
If I understood correctly what you want to do, here's an example:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#define FILE_LIST_MAX 10
int main()
{
DIR *p = opendir("./");
struct dirent *pp;
char **file_list = malloc(FILE_LIST_MAX * sizeof(char*));
int i = 0;
if (p == NULL) {
printf("Could not open current directory" );
return 0;
}
while ((pp = readdir(p)) != NULL) {
int length = strlen(pp->d_name);
printf ("%s\n", pp->d_name);
if(length > 4 && memcmp(pp->d_name + length - 4, ".txt", 4) == 0) {
char filename[length];
sprintf(filename, "%s", pp->d_name);
file_list[i] = malloc(length * sizeof(char));
strcpy(file_list[i], filename);
i++;
}
}
(void) closedir(p);
printf("\n.txt filenames within array");
for(int j = 0; j < i; j++) {
printf("\n%s", file_list[j]);
}
for(int j = 0; j < i; j++) {
free(file_list[j]);
}
free(file_list);
return(0);
}
It's not perfect though as you must manually change file_list capacity in FILE_LIST_MAX
Here's an example output from executing this code:
Much better approach would be implementing a dynamic array of chars which will automatically resizes as necessary.
I need to make a program in C that accesses some files and retrieves a set of keywords and stores them in a list, then for each keyword it would loop through a set of emails and count how many times each keyword appeared PER email
#note i'm not allowed to use global variables
my code's kind of a mess as it is, but here it is:
#define _GNU_SOURCE
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include <stdlib.h>
#define MAXKEYWORDLENGTH 64
typedef struct {
char keyword[MAXKEYWORDLENGTH];
int keywordCount;
int stdev;
} keywordData;
typedef struct {
int emailCount;
} emailData;
int fetchKeywordNumber(const char* filename)
{
int keywordNumber;
FILE* keywords = fopen(filename, "r");
fscanf(keywords,"%d", &keywordNumber);
fclose(keywords);
return keywordNumber;
}
keywordData *fetchKeywords(const char* filename)
{
FILE* keywords = fopen(filename, "r");
keywordData *kd;
// accessing first line of the file which has the number of keywords
int keywordNumber;
keywordNumber = fetchKeywordNumber(filename);
// first number in the file is the number of keywords in the file, so i dont need to count them
if(keywords)
if(fscanf(keywords,"%d", &keywordNumber) != 1) { /* error handling*/}
// printf("%d\n", keywordNumber);
kd = malloc(keywordNumber * sizeof(*kd));
if(kd)
for(int i = 0; i < keywordNumber; i++)
{
fscanf(keywords,"%s", kd[i].keyword);
// printf("%s\n", kd[i].keyword);
}
if(keywords) fclose(keywords);
return kd;
}
int countWord(const char* filename, char wordname, int wordIndex)
{
FILE* email = fopen(filename, "r");
int keywordCount = 0;
fseek(email, 0, SEEK_END);
long emailSize = ftell(email);
fseek(email, 0, SEEK_SET); // same as rewind(f);
char *string = malloc(emailSize + 1);
fread(string, emailSize, 1, email);
fclose(email);
string[emailSize] = 0;
char *bodyPos = strstr(string, "Body:");
const char *next = bodyPos;
while ((next = strcasestr(next, wordname)) != NULL)
{
keywordCount++;
next++;
printf("Found a keyword: %s, occurence number: %d\n", kd[i].keyword, kd[i].keywordCount);
}
return keywordCount;
}
keywordData *emailLoop(char wordName, int wordIndex)
{
keywordData* kd;
kd = malloc((wordIndex + 1) * sizeof(keywordData));
struct dirent *de; // Pointer for directory entry
DIR *dr = opendir("/home/student/bitdefender-challenge/check_baliza/data/emails/");
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory" );
return 0;
}
while ((de = readdir(dr)) != NULL)
{
if(!(strcmp(de->d_name, ".")) || !(strcmp(de->d_name, "..")))
continue;
char directory[256];
sprintf(directory, "%s%s", "/home/student/bitdefender-challenge/check_baliza/data/emails/", de->d_name);
kd[wordIndex].keywordCount = countWord(directory, wordName, wordIndex);
}
closedir(dr);
return kd;
}
int main()
{
char* keywordFilename = "/home/student/bitdefender-challenge/check_baliza/data/keywords";
char* emailFilename = "/home/student/bitdefender-challenge/check_baliza/data/emails/40";
// keywordData* result = readEmail(emailFilename, fetchKeywords(keywordFilename));
int keywordCount = fetchKeywordNumber(keywordFilename);
keywordData *result = fetchKeywords(keywordFilename);
for(int i = 0; i < keywordCount; i++)
{
emailLoop(result[i].keyword, i);
}
return 0;
}
i'd like to receive some advice on how to make this count the number of occurences for each word per each email and the standard deviation for each keyword
my output would need to be like this:
<word> <total occurence number found in all emails> <standard deviation>
I am trying to list the files inside a directory to a particular level which is specified by the user.
The main issue which I am facing is that I think is that the sub-directories are not recognised as a directory. Thus I tried appending the string to the upper level of a directory. But it doesn't seem to be working.
Here is the directory structure generated using ls -R (All dir* are directories):
dir1 dir2 dir3 listDirectory listDirectory.c
./dir1:
dir1.1 dir1.2 dir1.3
./dir1/dir1.1:
dir1.1.1
./dir1/dir1.1/dir1.1.1:
./dir1/dir1.2:
./dir1/dir1.3:
./dir2:
dir2.1 dir2.2 dir2.3
./dir2/dir2.1:
./dir2/dir2.2:
./dir2/dir2.3:
./dir3:
Here is the code:
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat s;
regex_t regex;
const char *expression = "^[.]*$";
int reti;
//Directory listing main loop
int listDirectory(int counter,int level,char arr[200]){
printf("Here Counter = %d and Level = %d\n", counter, level);
//Check if the counter is equal to level. If yes exit
if(counter >= level){
return 0;
}
char *currentDirctory = arr;
// printf("%s\n",currentDirctory);
struct dirent *de; // Pointer for directory entry
DIR *dr = opendir(currentDirctory); // opendir() returns a pointer of DIR type.
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return 0;
}
//Read the contents of the directory
while ((de = readdir(dr)) != NULL){
int size = 0;
struct stat statbuf;
char *x = de->d_name; //The name of each file or folder
char c2[100];
strcpy(c2,x);
strcpy(arr,c2);
//Replace the content of arr with that of new directory or file name
reti = regexec(®ex, arr, 0, NULL, 0);
//Check if the file doesn't match . or .. which is the parent and grand-parent directory
if(!reti){
//If it matches check for next file
continue;
}
else if(reti == REG_NOMATCH){
printf("%s\n",arr);
//Check if the file or the path is a direcfory
stat(arr, &statbuf);
if(S_ISDIR(statbuf.st_mode)){
//If it is a directory then increase the counter and size and put the directory in loop for next call
counter += 1;
listDirectory(counter,level, arr);
size += 1;
}
else{
//It is a file check for next file
continue;
}
counter -= size;
}
}
closedir(dr);
}
int main(){
char arr[200] = "./";
reti = regcomp(®ex, expression, 0);
if(reti) {
fprintf(stderr, "Could not compile regex\n");
}
listDirectory(0,2,arr);
return 0;
}
The output is:
Here Counter = 0 and Level = 2
dir3
Here Counter = 1 and Level = 2
listDirectory.c
dir1
Here Counter = 1 and Level = 2
dir1.1
dir1.3
dir1.2
listDirectory
dir2
Here Counter = 1 and Level = 2
dir2.3
dir2.2
dir2.1
but it should be:
Here Counter = 0 and Level = 2
dir3
Here Counter = 1 and Level = 2
listDirectory.c
dir1
Here Counter = 1 and Level = 2
dir1.1
Here Counter = 2 and Level = 2
dir1.1.1
dir1.2
listDirectory
dir2
Here Counter = 1 and Level = 2
dir2.3
dir2.2
dir2.1
Finally it worked.
I made many changes so don't know what line worked.
So here is the resultant code
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat s;
regex_t regex;
const char *expression = "^[.]*$";
int reti;
//Directory listing main loop
int listDirectory(int counter,int level,char arr[200]){
printf("Here Counter = %d and Level = %d and directory is %s\n", counter, level, arr);
char c = '/';
size_t len = strlen(arr);
char *str2 = malloc(len + 1 + 1 );
strcpy(str2, arr);
str2[len] = c;
str2[len + 1] = '\0';
//Check if the counter is equal to level. If yes exit
if(counter >= level){
return 0;
}
char *currentDirctory = str2;
// printf("%s\n",currentDirctory);
struct dirent *de; // Pointer for directory entry
DIR *dr = opendir(currentDirctory); // opendir() returns a pointer of DIR type.
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
// printf("\nCould not open current directory\n");
return 0;
}
char root[100];
strcpy(root,str2);
//Read the contents of the directory
while ((de = readdir(dr)) != NULL){
int size = 0;
struct stat statbuf;
char *x = de->d_name; //The name of each file or folder
char c2[100];
strcpy(c2,x);
strcpy(currentDirctory,c2);
//Replace the content of arr with that of new directory or file name
reti = regexec(®ex, currentDirctory, 0, NULL, 0);
//Check if the file doesn't match . or .. which is the parent and grand-parent directory
if(!reti){
//If it matches check for next file
continue;
}
else if(reti == REG_NOMATCH){
//Check if the file or the path is a direcfory
// printf("\nRoot is %s\n",str2);
stat(arr, &statbuf);
// if(S_ISDIR(statbuf.st_mode)){
//If it is a directory then increase the counter and size and put the directory in loop for next call
// printf("%s %s\n",arr,str2);
counter += 1;
size_t len = strlen(root);
size_t len2 = strlen(currentDirctory);
char *str3 = malloc(len + len2 + 1 );
strcpy(str3, root);
strcat(str3,currentDirctory);
// str3[len] = currentDirctory;
str3[len2 + len + 1] = '\0';
// printf("\nGoing into loop directory is %s root is %s\n",str3,root);
listDirectory(counter,level, str3);
size += 1;
// }
// else{
//It is a file check for next file
// continue;
// }
counter -= size;
}
}
closedir(dr);
}
int main(){
char arr[200] = ".";
reti = regcomp(®ex, expression, 0);
if(reti) {
fprintf(stderr, "Could not compile regex\n");
}
listDirectory(0,3,arr);
return 0;
}
I have created two C-functions to encrypt and decrypt entire folders.
#include "myaes.h"
#define SUFFIX ".crypt" //the file suffix for encrypted files
#define MASTER "6ADAC6D678CF49EEF4BB9C16A61F4"
int aesEncryptDir(const char *d)
//encrypts every file in directory d
{
AES_KEY key;
DIR *dp = opendir(d);
FILE *fp,*fp_c;
struct dirent *entry;
char fullpath[strlen(d) + 300];
char cryppath[strlen(fullpath) + 20];
char buffer[10000];
void *in = malloc(16);
void *out = malloc(16);
int sz;
size_t s_read;
if(AES_set_encrypt_key(MASTER,256,&key) != 0)
return -1;
const AES_KEY *static_key = &key;
if(!dp) //could not dir file pointer, maybe the folder does not exist
return -1;
while(entry = readdir(dp))
{
if(strncmp(entry->d_name,".",1) != 0 && strncmp(entry->d_name,"..",2) != 0)
{
memset(fullpath,0,sizeof(fullpath));
memset(cryppath,0,sizeof(cryppath));
memset(buffer,0,sizeof(buffer));
snprintf(fullpath,sizeof(fullpath),"%s/%s",d,entry->d_name);
snprintf(cryppath,sizeof(fullpath),"%s%s",fullpath,SUFFIX);
if(strstr(fullpath,SUFFIX) != NULL)
continue;
fp = fopen(fullpath,"r+");
fp_c = fopen(cryppath,"w");
fseek(fp,0L,SEEK_END);
sz = ftell(fp);
rewind(fp);
fwrite(&sz,sizeof(int),1,fp_c);
while((s_read = fread(buffer,1,1000,fp)))
{
for(int v = 0; v < s_read; v+= 16)
{
memcpy(in,buffer+v,16);
AES_encrypt(in,out,static_key);
fwrite(out,1,16,fp_c);
}
}
}
fclose(fp);
remove(fullpath);
fclose(fp_c);
}
if(closedir(dp) != 0)
return -1;
free(in);
free(out);
return 0;
}
int aesDecryptDir(const char *d)
//decrypts every file in directory d
{
AES_KEY key;
DIR *dp = opendir(d);
FILE *fp,*fp_c;
struct dirent *entry;
char fullpath[strlen(d) + 300];
char comppath[strlen(d) + 300];
char recoverpath[strlen(fullpath)];
char buffer[10000];
int sz = 0;
void *in = malloc(16);
void *out= malloc(16);
if(AES_set_decrypt_key(MASTER,256,&key) != 0)
return -1;
const AES_KEY *static_key = &key;
if(!dp) //could not dir file pointer, maybe the folder does not exist
return -1;
while(entry = readdir(dp))
{
if(strncmp(entry->d_name,".",1) != 0 && strncmp(entry->d_name,"..",2) != 0)
{
memset(fullpath,0,sizeof(fullpath));
memset(recoverpath,0,sizeof(recoverpath));
snprintf(fullpath,sizeof(fullpath),"%s/%s",d,entry->d_name);
strcpy(comppath,fullpath);
if(strstr(comppath,SUFFIX) == NULL)
continue;
strcpy(recoverpath,fullpath);
recoverpath[strlen(fullpath) - strlen(SUFFIX)] = '\0';
fp = fopen(fullpath,"r+");
fp_c = fopen(recoverpath,"w");
fread(&sz,sizeof(int),1,fp);
while(fread(in,16,1,fp))
{
AES_decrypt(in,out,static_key);
fwrite(out,(sz>=16)?16:sz,1,fp_c);
sz-=16;
}
fclose(fp);
fclose(fp_c);
}
}
if(closedir(dp) != 0)
return -1;
free(in);
free(out);
return 0;
}
myaes.h
#ifndef MYAES_H
#define MYAES_H
#include <dirent.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
int aesEncryptDir(const char *d);
int aesDecryptDir(const char *d);
#endif
If i now run a plain text file through aesEncryptDir and then aesDecryptDir, it comes out unchanged. A diff also indicates no changes. A binary file (.jpg) however gets corrupted in the process.
Why does this happen? Has it got something to do with the encoding of the binary files? Do I have to handle binary files differently for en-/decryption?
I want to be able to get the list of folders and file (if possible with sub folders) and return it (array for example)
So i have this script:
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name); // I dont want to print, I want to add it to a array
}
closedir (dir);
} else {
/* could not open directory */
perror ("");
return EXIT_FAILURE;
}
So i can do:
array = getFolders('.');
now if I loop thru the array i can see all folders and files.
eg:
array[0] = 'file1.txt';
array[1] = 'folder1/';
array[2] = 'folder1/file2.txt';
array[3] = 'folder1/file3.txt';
array[4] = 'folder2/';
array[5] = 'folder3/';
array[6] = 'folder3/filez.txt';
etc...
You can allocate a list of pointers and store each entry by allocating memory for the directory entry:
char **getFolder()
{
char **list = malloc(4096* sizeof *list);
size_t i = 0;
....
while ((ent = readdir (dir)) != NULL) {
list[i]=strdup(ent->d_name);
i++;
if( i >=4096 ) { /* time to realloc */}
}
return list;
}
and from the caller, you can use receive it as:
char **list=getFolder();
If you are going to have too many entries than you can use realloc() to increase the size of the list inside the loop. If strdup is not available, it can be easily implemented by using malloc() and strlen() functions.
I have excluded error checking for simplicity. Ideally, malloc() ans strdup should be checked for errors.
use DIR command in popen, and malloc and realloc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define INC 1024
char **getFolders(const char *path, /* out */ size_t *count){
char buff[1024];
snprintf(buff, sizeof buff, "dir /B /S /ON \"%s\"", path);
FILE *fp = popen(buff, "r");
size_t capacity = INC;
char **entry;
struct stat finfo;
if(NULL==(entry=malloc(capacity*sizeof(*entry)))){
perror("malloc");
exit(EXIT_FAILURE);
}
*count = 0;
while(fgets(buff, sizeof buff, fp)){
size_t len;
for(len = 0; buff[len]; ++len){
if(buff[len] == '\\')
buff[len] = '/';
}
buff[len-1] = '\0';
stat(buff, &finfo);
if(S_ISDIR(finfo.st_mode))
buff[len-1] = '/';
entry[*count] = strdup(buff);
if(++*count == capacity){
capacity += INC;
if(NULL==(entry=realloc(entry, capacity*sizeof(*entry)))){
perror("realloc");
exit(EXIT_FAILURE);
}
}
}
pclose(fp);
return entry;
}
int main(void){
size_t i, count = 0;
char **entry = getFolders("c:/src/", &count);
for(i = 0; i < count; ++i){
printf("%s\n", entry[i]);
free(entry[i]);
}
free(entry);
return 0;
}