I'm writing a code that reads the first line from a file, where this line includes a path to directory. Then the list_dir() function would enter all subfolders..
I checked the list_dir() and it's works great when I'm sending the path manually -
For example: list_dir ("/home/Desktop/example");
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
static void list_dir (const char *dirPath)
{
// Open the directory in dir_name
DIR *d;
d = opendir (dirPath);
/* Check it was opened. */
printf("%s",dirPath);
if (!d) {
printf ("Cannot open directory\n");
exit (1);
}
while (1) {
struct dirent * entry;
const char * d_name;
/* "Readdir" gets subsequent entries from "d". */
entry = readdir (d);
/* if There are no more entries in this directory */
if (!entry) {
break;
}
/* Print the name of the file and directory. */
d_name = entry->d_name;
printf ("%s/%s\n", dirPath, d_name);
if (entry->d_type & DT_DIR) {
/* Check that the directory is not "d" or d's parent. */
if (strcmp (d_name, "..") != 0 && strcmp (d_name, ".") != 0) {
int path_length;
char path[PATH_MAX];
path_length = snprintf (path, PATH_MAX,"%s/%s", dirPath, d_name);
printf ("%s\n", path);
if (path_length >= PATH_MAX) {
fprintf (stderr, "Path length has got too long.\n");
exit (EXIT_FAILURE);
}
/* Recursively call "list_dir" with the new path. */
list_dir(path);
}
}
}
/* After going through all the entries, close the directory. */
if (closedir (d)) {
printf ("Cannot Close directory");
exit (1);
}
}
void main(int argc, char *argv[])
{
//configuration file path
char* dirPath = argv[1];
FILE *f1 = fopen(dirPath, "r");
if (f1 == NULL) {
printf("Cannot open the file for reading");
exit(1);
}
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, f1)) != -1) {
break;
}
list_dir (line);
fclose (f1);
free(line);
}
example for the txt file:
/home/Desktop/example/
bla bla bla
bla bla bla
As you understand, the problem is when I'm sending the path from main() function, list_dir() can't open the path and I get "Cannot open directory" as an error. Help?
As the commenters above said there is a newline at the end of dirPath and that's why you get Cannot open directory, add strtok(dirPath, "\n"); just before opendir to get rid of the trailing newline.
Also note that you are including some headers more than once and that main should return an int.
Related
I wish to read all the text files in a particular folder. The files' names do not have any common pattern in them- else the task would have been easier.
//read a file from the directory
//Perform a common operation
//write output to a common file
//read the next file
It will be good if I could work around with sub-folders as well, but even the basic implementation is sufficient.
I tried looking at the previously asked related questions (here, here, here and here), but none of them give a C and Linux specific answer which I need.
edit : So, this is what I wrote based on the answers received-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char **argv)
{
DIR* FD;
struct dirent* in_file;
FILE *output_file;
FILE *entry_file;
char buffer[BUFSIZ];
/* Opening common file for writing */
output_file = fopen("/home/pnp/snort_rules_folder/rulesoutput.txt", "a+");
if (output_file == NULL)
{
fprintf(stderr, "Error : Failed to open output_file\n");
return 1;
}
/* Scanning the in directory */
if (NULL == (FD = opendir ("/home/pnp/snort_rules_folder/rules")))
{
fprintf(stderr, "Error : Failed to open input directory\n");
fclose(output_file);
return 1;
}
while ((in_file = readdir(FD)))
{
/* On linux/Unix we don't want current and parent directories
* If you're on Windows machine remove this two lines
*/
if (!strcmp (in_file->d_name, "."))
continue;
if (!strcmp (in_file->d_name, ".."))
continue;
/* Open directory entry file for common operation */
/* TODO : change permissions to meet your need! */
entry_file = fopen(in_file->d_name, "r");
if (entry_file == NULL)
{
fprintf(stderr, "Error : Failed to open entry file\n");
fclose(output_file);
return 1;
}
/* Doing some stuff with entry_file : */
while (fgets(buffer, BUFSIZ, entry_file) != NULL)
{
/* Use fprintf or fwrite to write some stuff into common_file*/
}
fprintf(output_file, "reading file %s", in_file->d_name);
/* When you finish with the file, close it */
fclose(entry_file);
}
/* Don't forget to close common file before leaving */
fclose(output_file);
return 0;
}
And the error received-
pnp#pnp-laptop:~/snort_rules_folder$ ./a.out
Error : Failed to open entry file
You can use this sample code and modify it if you need:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
/* This is just a sample code, modify it to meet your need */
int main(int argc, char **argv)
{
DIR* FD;
struct dirent* in_file;
FILE *common_file;
FILE *entry_file;
char buffer[BUFSIZ];
/* Openiing common file for writing */
common_file = fopen(path_to_your_common_file, "w");
if (common_file == NULL)
{
fprintf(stderr, "Error : Failed to open common_file - %s\n", strerror(errno));
return 1;
}
/* Scanning the in directory */
if (NULL == (FD = opendir (in_dir)))
{
fprintf(stderr, "Error : Failed to open input directory - %s\n", strerror(errno));
fclose(common_file);
return 1;
}
while ((in_file = readdir(FD)))
{
/* On linux/Unix we don't want current and parent directories
* On windows machine too, thanks Greg Hewgill
*/
if (!strcmp (in_file->d_name, "."))
continue;
if (!strcmp (in_file->d_name, ".."))
continue;
/* Open directory entry file for common operation */
/* TODO : change permissions to meet your need! */
entry_file = fopen(in_file->d_name, "rw");
if (entry_file == NULL)
{
fprintf(stderr, "Error : Failed to open entry file - %s\n", strerror(errno));
fclose(common_file);
return 1;
}
/* Doing some struf with entry_file : */
/* For example use fgets */
while (fgets(buffer, BUFSIZ, entry_file) != NULL)
{
/* Use fprintf or fwrite to write some stuff into common_file*/
}
/* When you finish with the file, close it */
fclose(entry_file);
}
/* Don't forget to close common file before leaving */
fclose(common_file);
return 0;
}
Hope this hellp.
Regards.
Trying to make a pwd for the c shell. This is what I found on a website and wanted to learn more about it.
I have use debugging printf statements all the way through the program already and it returns the "." instead of the actual dir name all the way through. What am I missing? Why would this be happening?
#include <dirent.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
struct stat stat_buf;
struct dirent *file_info;
ino_t itself_ino; /* holds current folder inode */
ino_t parent_ino; /* holds parent folder inode */
char Current[PATH_MAX]; /* folder name */
char Path[PATH_MAX]; /* holds the full path */
char Slash[PATH_MAX]; /* add / before the folder name */
DIR *dir;
while (1)
{
dir = opendir(".");
if(dir == NULL) {
fprintf(stderr, "cannot get current directory.\n");
exit(-1);
}
/* read the information about the current folder */
file_info = readdir(dir);
lstat(file_info->d_name, &stat_buf);
itself_ino = stat_buf.st_ino;
closedir(dir);
chdir(".."); /* go to parent directory */
dir = opendir(".");
file_info = readdir(dir);
lstat(file_info->d_name, &stat_buf);
parent_ino = stat_buf.st_ino;
if(itself_ino == parent_ino) {
/*closedir(dir);*/
break;
} else {
strcpy(Slash, "/");
strcpy(Current, file_info->d_name);
strcat(Slash, Current); /* add "/" as the first */
strcat(Slash, Path); /* charcter of the directory */
/* check the length of the pathname */
if(strlen(Slash) >= PATH_MAX) {
fprintf(stderr, "Error! Path too long!\n");
exit(0);
}
/* save the full pathname */
strcpy(Path, Slash);
}
closedir(dir);
}
/* print the full path of the current working directory */
printf("%s\n", Path);
return 0;
}
It's just realpath:
if (realpath(".", &Path) == NULL) {
// handle error
}
However maybe you aim at getcwd or get_current_dir_name.
printf("%s\n", get_current_dir_name());
I want to read all files that I can find in the folder where my executable is, except the runnable file that I'm running. I code the following code but, although this list correctly the files that I have in my folder, I cannot open them with fopen because fopen prints that the file doesn't exists. If I do gedit "path of the file obtained from my program in c" then it opens perfectly from the term. Where is the bug?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
int main (int argc, char **argv) {
//Determining the number of files we have.
//We call to a bash command http://stackoverflow.com/questions/646241/c-run-a-system-command-and-get-output
FILE *fp, *fin;
char path[1035], cwd[1024];
int scanned = 0;
/* Open the command for reading. */
//https://askubuntu.com/questions/370697/how-to-count-number-of-files-in-a-directory-but-not-recursively
//This count soft and hard links also (I think)
fp = popen("ls -F |grep -v /", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it. */
//Loop for each file. Be careful! if the exe is inside, it will also be counted!
while (fgets(path, sizeof(path)-1, fp) != NULL) {
printf("Reading file: %s\n", path);
fin=fopen(path,"r");
scanned = 0;
printf("caa");
if (fin != NULL){
printf("AA\n");
fclose(fin);
}
if (!fin)perror("fopen");
printf("Done! \n");
}
/* close */
pclose(fp);
printf("end");
return 0;
}
There are 2 bugs in your code:
when the code updates the "path" variable in your code. It has a newline at the end which needs to be corrected to NUL. This gives an incorrect path.
Something like below can be appended to your code:
while (fgets(path, sizeof(path)-1, fp) != NULL) {
len=strlen(path);
path[len-1]='\0';
Use 'ls -A1', since 'ls -F' adds a '*' in binary name:
fp = popen("ls -A1 |grep -v /", "r");
ok so just in case someone else needs a better approach, I redid the code with the comments I had. Here I let you the new code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
int isDirectory(const char *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0)
return 0;
return S_ISDIR(statbuf.st_mode);
}
int main (int argc, char **argv) {
FILE *fp, *fin;
char path[1035], cwd[1024];
int scanned = 0;
int ints;
DIR *dir;
struct dirent *ent;
//getcwd prints directory where the app ran.
if ((dir = opendir (getcwd(cwd, sizeof(cwd)))) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
/*Skips . and ..*/
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
if (isDirectory(ent->d_name) != 0) continue;
printf ("Reading file: %s\n", ent->d_name);
scanned = 0;
fin=fopen(ent->d_name,"r");
if (fin != NULL){
while ((scanned = fscanf(fin, "%d", ints)) != EOF) {
if(scanned == 1){
printf("%d\n", ints);
}else {
printf("Whoops! Input format is incorrect!\n");
break;
}
} //LOOP: reading file
fclose(fin);
}
if (!fin)perror("fopen");
printf("Done! \n");
}//LOOP: while opendir
closedir (dir);
} else {
/* could not open directory */
perror ("opendir");
return EXIT_FAILURE;
}
return 0;
}
The following code is supposed to work as follows: print the list of the files in a directory, and print the content of each .c file.
it works fine when executed in UNIX for the same directory: ./a.out ./
However, I was not able to make it work for ./a.out ../differentDir execution.
I know that if the absolute path is provided as an argument, I could use argv[1] for that. However, when it is provided in a form of a relative path I am lost.
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dp = opendir(argv[1])) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
Upon opening the file to read, the file pathname needs to also be relative.
// Form prefix for complete relative file name
char filename[MAXPATH];
strcpy(filename, argv[1]);
// append '/' if directory path does not end in '/'
if (TBD_code(filename)) {
strcat(filename, "/");
}
char *end = filename[strlen(filename)];
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
if (findC(dirp->d_name)) {
// append filename to prefix
strcpy(end, dirp->d_name);
fp=fopen(filename, "r");
...
You can use realpath(argv1...) like in this example. realpath will return the absolute path for a relative path.
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv) {
char *path = "../..";
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
char *res = realpath(path, buff);
if (res) {
printf("This source is at %s.\n", buff);
} else {
perror("realpath");
exit(EXIT_FAILURE);
}
return 0;
}
To include the desired behavior in your program, you can use realpathin your code:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
char *res = realpath(argv[1], buff);
if ((dp = opendir(res)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
You could first change to the directory chdir either with relative or absolute path and the get the absolute path via the getcwd
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
#define PATH_SIZE 512
int main(int argc, char **argv) {
char buf[BUFFSIZE];
char path[PATH_SIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length, r;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
strcpy(path, argv[1]);
r = chdir(path);
if( r != 0 )
{
printf("Invalid path '%s'\n",path);
exit(1);
}
getcwd(path,PATH_SIZE);
if ((dp = opendir(path)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
I am trying to simulate linux command ls using linux api from c. Looking at the code it does make sense, but when I run it I get "stat error: No such file or directory". I have checked that opendir is working ok. I think the problem is in stat, which is returning -1 even though I think it should return 0.
What am I missing?
Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
if (stat(direntp->d_name, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
It's because you aren't stating the actual file. It's in a different directory. If you want the real filename, combine argv[1] and direntp->d_name with a '/' between them.
Also, hungarian naming is icky, even the minor bit like 'p' on the end. If you have so many variables you need to keep track of their types in their names you're doing something wrong.
Here is a revised version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
char fullpath[MAXPATHLEN + 1];
size_t dirnamelen;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
fullpath[MAXPATHLEN - 1] = '\0';
dirnamelen = strlen(fullpath);
if (strlen(argv[1]) > dirnamelen) {
fprintf( stderr, "Directory name is too long: %s", argv[1] );
exit(2);
}
fullpath[dirnamelen++] = '/';
fullpath[dirnamelen] = '\0';
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
fullpath[dirnamelen] = '\0';
if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
continue;
} else {
/* strncpy is mild overkill because the if statement has verified that
there's enough space. */
strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
fullpath[MAXPATHLEN] = '\0';
}
if (stat(fullpath, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
Note that I use MAXPATHLEN (from <limits.h>) and carefully check to make sure there aren't any buffer overflows. You should do the same in your code.
Edit: Changed code to use strn family functions for added safety.
Add
#include <unistd.h>
...
chdir(argv[1]);
or call stat with the full pathname like this
...
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", argv[1], direntp->d_name);
if (stat(fullpath, &stat_buf) == -1)
...
Others have suggested building a full path for stat(), or using chdir(). Both those will work (although they are subject to a race condition, if the directory is renamed while you are in the middle of reading it).
An alternative, which is not subject to the race condition, and is therefore arguably more "correct", is to use fstatat(). Just replace your existing stat() call with:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
(The chdir() method can be made race-condition-free too: either by using fchdir(dirfd(dirp)) instead of chdir(), or by changing directory to argv[1] and then opening "." with opendir(). The pathname construction method can't be made race-condition-free).
Why dont you try this? Just give the path to argv[1] like this /home/sabri/Desktop/Test
int main(int argc, char *argv[])
{
struct dirent *direntp;
DIR *dirp;
if (argc != 2)
{
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
if ((dirp = opendir(argv[1])) == NULL)
{
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
printf("%s\n", direntp->d_name);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
If you are using on unix, then you may use the system command.
system("ls -ltr | grep -d");