I'm trying to display the contents of the directory, I am adding the directory name to the array of strings and printing it, but instead of printing the array the program prints "tmp".
void do_ls(char * dir){
struct dirent * entry;
DIR * dp = opendir(dir);
if(dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
errno = 0;
while((entry = readdir(dp)) != NULL){
if(entry == NULL && errno != 0){
perror("readdir failed");
exit(errno);
}
else{
if(entry->d_name[0] == '.')
continue;
while(i < totalNumOfFiles){
for(int j=0; j<lenOfLongestFile; j++){
fileNames[i][j] = entry->d_name[j];
}
i++;
}
}
}
i = 0;
while(i < totalNumOfFiles){
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
This is the function in question, the variables totalNumOfFiles and lenOfLongestFile are global variables and they work correctly I have tested them.
Let's see what we have here... My comments... well, in the comments ;)
void do_ls(char * dir) {
struct dirent *entry;
DIR *dp = opendir(dir);
if (dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
// I don't know what function below does
// I assume it sets totalNumOfFiles and lenOfLongestFile;
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
// You don't have to set errno to zero
errno = 0;
while ((entry = readdir(dp)) != NULL) {
// Statement above guarantees that the loop won't be run
// when entry == NULL, so what for is the if statement below?
// It's a dead code. get rid of it.
if (entry == NULL && errno != 0) {
perror("readdir failed");
exit(errno);
} else {
if(entry->d_name[0] == '.')
continue;
// Ok, so here we are with a SINGLE file entry, and with this
// SINGLE file entry you fill the WHOLE table with it.
// This is clearly wrong.
while (i < totalNumOfFiles) {
// Also, you should use a strcpy function to copy string.
// It will copy necessary number of bytes and trailing 0.
for(int j=0; j<lenOfLongestFile; j++){
fileNames[i][j] = entry->d_name[j];
}
i++;
}
}
// So here all rows in the table are filled with the last read
// file name
}
i = 0;
while(i < totalNumOfFiles){
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
Here is corrected code:
void do_ls(char *dir) {
struct dirent *entry;
DIR *dp = opendir(dir);
if (dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
while ((entry = readdir(dp)) != NULL) {
if (entry->d_name[0] == '.')
continue;
strcpy(fileNames[i], entry->d_name);
i++;
}
i = 0;
while (i < totalNumOfFiles) {
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
Related
So im writing a program to open a directory, get all the files inside, and then read the contents of each file. currently i successfully got all the file names in a string array. the print files[] loop shows all the file names, but the loop to check frequency does not read the files correctly. how do i successfully read an array of file names and then scan each of their contents?
//Open Directory
DIR *dr = opendir(path);
struct dirent *de;
if(dr == NULL){
printf("Could not open directory");
return 0 ;
}
const char* files[100];
int buffer=0;
//Read Directory Files
while((de = readdir(dr)) != NULL){
files[buffer] = de->d_name;
buffer++;
}
for(int x = 0; x <= buffer; x++){
printf("%s" , files[x]);
}
closedir(dr);
//Check Frequency
for(int i = 0; i <= buffer; i++){
int ch;
FILE *fp;
fp = fopen(files[i], "r");
if(fp == NULL)
continue;
ch = fgetc(fp);
while(ch != EOF){
ch = tolower(ch);
if(ch>=97 && ch<= 122){
alphabetfreq[ch-97]++;
}
ch = fgetc(fp);
}
fclose(fp);
There are multiple things wrong with the program. But the main reason why it is not reading the files is that you are just passing the file names to fopen(), so it is looking for them in current directory and returning null values. Also you are not handling the null results carefully. And the condition in the loop should x < buffer and not x <= buffer.
#include<stdio.h>
#include<dirent.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
int main()
{
int alphabetfreq[100], i;
for(i = 0; i < 100; i++){
alphabetfreq[i] = 0;
}
char path[] = "/home/path_to_directory/";
DIR *dr = opendir(path);
struct dirent *de;
if(dr == NULL){
printf("Could not open directory");
return 0 ;
}
const char* files[100];
int buffer=0;
//Read Directory Files
while((de = readdir(dr)) != NULL){
files[buffer] = de->d_name;
buffer++;
}
for(int x = 0; x < buffer; x++){
printf("%s" , files[x]);
}
closedir(dr);
printf("\n");
//Check Frequency
for(int i = 0; i < buffer; i++){
int ch;
FILE *fp;
char * file = malloc(strlen(path) + strlen(files[i]) + 1);
strcpy(file, path);
strcat(file, files[i]);
fp = fopen(file, "r");
if(fp == NULL)
{
printf("no file %s\n", file);
continue;
}
ch = fgetc(fp);
while(ch != EOF){
ch = tolower(ch);
if(ch>=97 && ch<= 122){
alphabetfreq[ch-97]++;
}
ch = fgetc(fp);
}
fclose(fp);
}
for(i = 0; i < 26; i++)
{
printf("%c %d\n", i+97, alphabetfreq[i]);
}
}
This is working for me.
I'm trying to store file names in an array. The array is in a struct, and I want to store the names of files found in a directory in the array. However, the process that I'm using to store the names seems to be corrupting 2 or 3 of the names during the process. I think the problem is with the strdup keyword. Whenever I run my program either it reads in the program executable (which is in the directory above the directory I'm reading the files from), or weird symbols stored in the first few array locations. The following is part of my program where I'm trying to capture and store the file names, and a picture of the output results:
typedef struct{
char *filename;
}filename;
typedef struct Configs{
char file_data_path[50];
char event_log_path[50];
filename *fn_data;
}Configs;
typedef struct TestConfigs{
bool done;
int selection;
int attempts_counter;
Configs tConfig;
}TestConfigs;
void read_files(struct TestConfigs *setup);
int main(void) {
printf("Hello Test\n");
TestConfigs setup;
read_files(&setup);
system("pause");
return EXIT_SUCCESS;
}
void read_files(struct TestConfigs *setup)
{
setup->done = false;
setup->attempts_counter = 3;
char cwd[1024];
DIR *dir = NULL;
struct dirent *pent = NULL;
struct stat info;
int total_num_of_files = 0;
strcpy(setup->tConfig.file_data_path, "data/");
chdir(setup->tConfig.frame_data_path);
if((getcwd(cwd, sizeof(cwd))) != NULL)
{
printf("Current Directory: %s\n", cwd);
}
dir = opendir(cwd);
if(dir != NULL)
{
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
total_num_of_files++;
}
}
}
}
printf("# of files found: %d\n", total_num_of_files);
rewinddir(dir);
// SETUP ARRAY HERE!
setup->tConfig.fn_data = malloc(total_num_of_files);
total_num_of_files= 0;
printf("During Storage Process:\n");
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
setup->tConfig.fn_data[total_num_of_files].filename = (char*)malloc(sizeof(pent->d_name));
setup->tConfig.fn_data[total_num_of_files].filename = strdup(pent->d_name); // <- Possible source of the storage problem
printf("Filename stored in fn_data[%d] = %s\n", total_num_of_files, setup->Config.fn_data[total_num_of_files].filename);
total_num_of_files++;
}
}
}
}
printf("\n");
printf("After Storage Process:\n");
for(int i = 0; i < total_num_of_files; i++)
{
printf("Filename stored in fn_data[%d] = %s\n", i, setup->tConfig.fn_data[i].filename);
}
}
closedir(dir);
}
Output results here
What can I do to resolve the corrupt storage of the filenames in the first few array locations? How come only the first few locations aren't properly storing the filenames, but the other locations are Ok? Is the issue with strdup, and if so, what's a good alternative for capturing and storing the file names in the array? Thanks in advance!
setup->tConfig.fn_data = malloc(total_num_of_files);
One byte per file?
Need, e.g., setup->tConfig.fn_data = malloc(total_num_of_files * sizeof(filename));
This:
setup->tConfig.fn_data[total_num_of_files].filename = (char*)malloc(sizeof(pent->d_name));
setup->tConfig.fn_data[total_num_of_files].filename = strdup(pent->d_name); // <- Possible source of the storage problem
makes no sense; the strdup() will overwrite the pointer returned by malloc() and that memory will be forever lost ("leaked") which is bad.
You don't have to allocate memory for strdup(), it does that for you. It's basically:
char * strdup(const char *s)
{
const size_t sz = strlen(s) + 1;
char * const p = malloc(sz);
if (p != NULL)
memcpy(p, s, sz);
return p;
}
Platform: Windows XP Service Pack 3
Compiler: Code::Blocks version 12.11
I am currently writing a program that will recursively delete a given directory using the POSIX directory functions. But I am having a problem with readdir() and its counterpart the dirent structure. I read in readdir's documentation that multiple calls to the function will overwrite the data held in the structure returned by the function. So I thought readdir() must allcoate memmory for the struct itself and then simply reassign the pointer address to the structure that captures it's return value. I tested this theory and I was correct readdir() allocated memmory for it's member d_name. The problem I am having is that readdir returns a NULL pointer when the directory stream is empty, so I use a while loop with the condition (dirent_ptr != NULL) to iterate the entire directory. But because readdir() will handle the memmory allocation of the structure I simply declare a dirent structure and let readdir() do its job. Unfourtatnly for some reason dirent structures are initialized to NULL(or it might be my complier) so my loop never starts because it's conditional statement is not initialy true. So I guess my question is what am I doing wrong here?
Here are important variable declarations and the included librarys. Please note that all of these variables are declared globaly.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
int recursive_delete(const char *path);
int file_delete(const char *path, int file_size);
struct dirent *direntp;
struct stat *statp;
struct switches
{
int verbose;
int no_prompt;
int continue_if_error;
int files_only;
}; struct switches switches;
Rather than resolving relative paths I simply cd to the path given as an argument and then I use the . and .. wildcards to move threw the directorys so that relative paths(d_names) are valid. Also the switches structure simply contains command line switches and should be ignored and I am aware of errors in the following code but unfourtantly I cannot fix them because I cannot get past the above mentioned problem.
int recursive_delete(const char *path)
{
DIR *dirp;
int return_value = 0;
int recursive_return_value = 0;
if((chdir(path)) == -1)
{
perror("ERROR(3)");
return 1;
}
printf("CDED to \"%s\"\n", path);
dirp = opendir(".");
if(dirp == NULL)
{
perror("ERROR(4)");
return 1;
}
printf("OPENED \"%s\"\n", path);
while(direntp != NULL)
{
direntp = readdir(dirp);
if( (direntp == NULL) && (errno != 0) )
{
perror("ERROR(5)");
return 1;
}
printf("READ \"%s\" FROM \"%s\"\n", direntp->d_name, path);
if( (strcmp(direntp->d_name, ".")!=0) && (strcmp(direntp->d_name, "..")!=0) )
{
if((stat(direntp->d_name, statp)) == -1)
{
perror("ERROR(6)");
return 1;
}
printf("STATED \"%s\"\n", direntp->d_name);
if(S_ISREG(statp->st_mode))
{
printf("DELETING \"...\\%s\\%s\"\n", path, direntp->d_name);
return_value += file_delete(direntp->d_name, statp->st_size);
if( (!switches.continue_if_error) && (return_value != 0) )
{
break;
}
}
else if(S_ISDIR(statp->st_mode))
{
printf("\n\n\nCALLING RECURSIVE DELETE with \"%s\"\n", direntp->d_name);
recursive_return_value = recursive_delete(direntp->d_name);
return_value += recursive_return_value;
if( (!switches.continue_if_error) && (recursive_return_value != 0) )
{
break;
}
if( (!switches.files_only) && (recursive_return_value == 0) )
{
if((chdir("..")) == -1)
{
perror("ERROR(6)");
return 1;
}
printf("CDED BACK TO \"%s\" FROM \"%s\"\n", path, direntp->d_name);
if((rmdir(direntp->d_name)) == -1)
{
perror("ERROR(7)");
return 1;
}
if(switches.verbose)
{
printf("DELETED DIRECTORY \"...\\%s\\\"\n\n\n", direntp->d_name);
}
}
}
}
}
return return_value;
}
Your code structure should look something like thhis (with most error checks omitted for clarity):
int recursive_delete(const char *path)
{
DIR* dirp = NULL;
int return_value = 0;
char* initial_cur_dir = malloc(1000);
getcwd(initial_cur_dir, 1000);
chdir(path);
dirp = opendir(".");
while (dirp != NULL)
{
struct dirent* direntp;
struct stat stat;
direntp = readdir(dirp);
if (direntp == NULL)
break;
stat(direntp->d_name, &stat);
if (S_ISDIR(statp->st_mode))
{
if (strcmp(direntp->d_name, ".") && strcmp(direntp->d_name, ".."))
{
return_value += recursive_delete(direntp->d_name);
}
}
else if (S_ISREG(statp->st_mode))
{
unlink(direntp->d_name);
}
}
if (initial_cur_dir != NULL)
{
chdir(initial_cur_dir);
rmdir(path);
}
ErrorLabel: // you should goto here when an error is detected
if (dirp != NULL)
{
closedir(dirp);
}
if (initial_cur_dir != NULL)
{
chdir(initial_cur_dir);
free(initial_cur_dir);
}
return return_value;
}
From the code attached, it's not clear where direntp is being initialized (before the while loop). Possibly try something like:
direntp = readdir(dirp);
while(direntp != NULL)
{
// all your work here
direntp = readdir(dirp);
}
This pattern ensures that direntp is initialized and updated for your while loop. However, on second glance of your code I'm not exactly sure what the while loop is supposed to be doing in the first place. How is direntp or dirp changing in your loop?
It's possible that you can just get away with an if test (instead of the while) and just let the recursive call handle the "looping" effect...
I have a code that scans all the files in a directory for targeted words, and prints them out into a new file. The problem right now is after the while loop reads a file and stores a variable into the string (ex. customer), if the next file being read does not have the targeted word, it still displays the result stored in the string from the previous file. My goal is to make it display "N/A" if the current file does not have the target word.
I have tried a few ways to clear the string at the end or beginning of the while loop, but none of them work most of them just gives me a coredump error. Running out of ideas, any help would be much appreciated!
Code (shortened for easier reading):
int main(int argc, char** argv)
{
char directory[100];
char buff[100];
char delims[] = " :=";
char* result = NULL;
char* customer;
char* device;
char* buffer;
int i = 0;
DIR* FD;
struct dirent* in_file;
int c = 0;
printf("Enter directory:");
scanf("%s",directory);
FILE* ft = fopen("workorderlist.csv", "w"); /* Open file to write to*/
if (ft == NULL)
{
puts("Cannot open target file");
exit(1);
}
fprintf (ft, "Work Order,Customer,Device,Test_Prog,Software,DUT_board_id,Corl box\n");
/* Open Directory */
if (NULL == (FD = opendir(directory)))
{
puts("Cannot open directory");
return 1;
}
while ((in_file = readdir(FD)))
{
if (!strcmp (in_file->d_name, "."))
{
continue;
}
if (!strcmp (in_file->d_name, ".."))
{
continue;
}
/* Open files to read from */
buffer = (char*)malloc(100);
sprintf(buffer, "%s/%s", directory, in_file->d_name);
size_t len = strlen(buffer);
if (len >= 4 && memcmp(buffer + len - 4, ".wor", 4) == 0) /* checks if file ends with .wor */
{
FILE* fs = fopen(buffer, "r"); /* open file to read */
if (fs == NULL)
{
puts("Cannot open source file");
return 1;
}
/* Scanning each file for targeted words: */
while (fgets(buff, 100, fs) != NULL)
{
result = strtok( buff, delims );
while (result != NULL)
{
if ((strcmp(result, "Customer") == 0))
{
result = strtok(NULL,delims);
customer = (char*)malloc((strlen(result)+1)*sizeof(char));
strcpy(customer, result);
for (i = 0; i < strlen(customer) + 1; i++)
{
if (customer[i] == '\n')
{
break;
}
}
customer[i] = ' ';
}
if (strcmp(result, "device") == 0)
{
result = strtok(NULL, delims);
device = (char*)malloc((strlen(result) + 1) * sizeof(char));
strcpy(device, result);
for (i = 0; i < strlen(device) + 1; i++)
{
if(device[i] == '\n')
{
break;
}
}
device[i] = ' ';
}
result = strtok(NULL,delims);
}
}
if (customer == '\0')
{
customer = "N/A";
}
if (device == '\0')
{
device = "N/A";
}
fprintf(ft, "%s,%s,%s,%s,%s,%s,%s\n",
in_file->d_name, customer, device, testprog,
software, dutboardid, corlbox);
printf(in_file->d_name);
printf("\n");
fclose (fs) ;
c++;
}
}
printf("Total Workorders Found: %d (Info saved to workorderlist.csv)\n", c);
fclose(ft);
return 0;
}
First at all, customer/device are strings. You should not be doing == for it comparison. You can, for example, compare the first char of the string: device[0] == '\0';
You should do string initialization before the loop starts.
You can achieve this by using strcpy with a known value or any other string manipulation function. The value that you use to initialize the string before the loop is the one you gonna test with strcmp or similar later.
Is like with ints or any other C data type, but you need manipulation functions instead.
By the way, haven't you posted your read file loop in a question here too?
Hope this helps.
Here is a program I made this program has segmentation fault I checked it in gdb in the second last of code free(somepath); .I do not have any reason for why is this segmentation fault coming?
Some one please suggest some thing.
#include<dirent.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<stdio.h>
char *directs[20], *files[20];
int i = 0;
int j = 0;
int count = 0;
void printdir(char *);
int count_dirs(char *);
int count_files(char *);
void new_printdir(int ,int ,char *);
int main()
{
char startdir[20];
printf("Scanning user directories\n");
scanf("%s", startdir);
printdir(startdir);
}
void printdir(char *dir)
{
DIR *dp = opendir(dir);
int nDirs, nFiles, nD, nF;
nDirs = 0;
nFiles = 0;
nD = 0;
nF = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
nDirs = count_dirs(dir);
nFiles = count_files(dir);
new_printdir(nDirs,nFiles,dir);
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char * filepath = malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) == 0) {
if (S_ISDIR(statBuf.st_mode)) {
printdir(filepath);
}
else {
}
}
}
free(filepath);
} //2nd while
closedir(dp);
}
else {
fprintf(stderr, "Error, cannot open directory %s\n", dir);
}
} //printdir
int count_dirs(char *dir)
{
DIR *dp = opendir(dir);
int nD;
nD = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char *filepath = malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) != 0) {
fprintf(stderr, "File Not found? %s\n",filepath);
}
if (S_ISDIR(statBuf.st_mode)) {
nD++;
} else {
continue;
}
free(filepath);
}
}
closedir(dp);
} else {
fprintf(stderr, "Error, cannot open directory %s\n", dir);
}
return nD;
}
int count_files(char *dir)
{
DIR *dp = opendir(dir);
int nF;
nF = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char *filepath =
malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) != 0) {
fprintf(stderr, "File Not found? %s\n", filepath);
}
if (S_ISDIR(statBuf.st_mode)) {
continue;
} else {
nF++;
}
free(filepath);
}
}
closedir(dp);
} else {
fprintf(stderr, "Error, cannot open file %s\n", dir);
}
return nF;
}
void new_printdir(int nDirs,int nFiles,char *dir)
{
struct dirent **namelist;
DIR *dop;
int i, j,t,re,nD,nF;
char userd[20],*somepath;
i = scandir(dir, &namelist, 0, alphasort);
t=0;
if (i < 0)
perror ("Scandir failed to open directory I hope you understand \n");
else {
for (j = 0; j < i; j++) {
if(strcmp(".",namelist[j]->d_name)==0||strcmp("..",namelist[j]->d_name)==0)
continue;
somepath = malloc(strlen(dir)+strlen(namelist[j]->d_name)+2);
sprintf(somepath,"%s/%s",dir,namelist[j]->d_name);
dop=opendir(somepath);
if(dop)
{
nD++;
if ((nDirs-nD)<3)
{printf("%s ",namelist[j]->d_name);}
}
else {
nF++;
if ((nFiles-nF)<3)
printf("%s ",namelist[j]->d_name);
}
closedir(dop);
free(namelist[j]);
}
}
free(namelist);
free(somepath);
}
Why is this segmentation fault happening this is not clear to me.
What can I do to get rid of it?
In your code, you are not guaranteed to allocate memory and assign it to somepath (you also fail to free somepath except for the last iteration of the loop). You should put your free(somepath) statement at the end of the for-loop, and you should initialize somepath to NULL both at the very beginning of the function and at the start of each for loop to avoid similar careless errors.
You're not initializing the somepath variable - it has an undefined value unless the malloc() executes (i.e. for empty folders). You should initialize it to NULL at the place of definition.
You do not initialize somepath to 0 (NULL), but you could under some circumstances release the value. This means you release a random value - which is not a good idea.