I am writing a function next_node
that finds next file in the directory. node takes a directory and a filename as input.
I want it to return NULL
if there is no other file after bname
or if it is "."
or ".."
. It is giving me segmentation fault (core dumped)
ONLY when it runs inside the if
statement of strcmp
.
Can you explain the problem or give a solution please?
Code:
#include <stdio.h>
#include <dirent.h> // DIR opendir() closedir() struct dirent readdir()
#include <string.h> // strcmp()
char *next_node(char *dname, char *bname) {
if (!strcmp(dname, bname)) {
// dname same as bname
return NULL;
}
DIR *dirp = opendir(dname);
struct dirent *direntp;
while (((direntp = readdir(dirp)) != NULL) && (strcmp(direntp->d_name, bname))) {
}
if ((direntp = readdir(dirp)) != NULL) {
// if d_name is "." or ".." return NULL
if ((strcmp(direntp->d_name, ".")) || (strcmp(direntp->d_name, ".."))) {
return NULL;
}
// it can reach here with no problem
closedir(dirp);
return direntp->d_name;
} else {
closedir(dirp);
return NULL;
}
}
int main() {
char *dname = ".";
char *bname = "test.c";
char *result = next_node(dname, bname);
printf("%s\n", result);
return 0;
}
You have five mistakes.
1:
DIR *dirp = opendir(dname);
You don't check if this opendir
succeeds.
2:
struct dirent *direntp;
while (((direntp = readdir(dirp)) != NULL) && (strcmp(direntp->d_name, bname))) {
}
if ((direntp = readdir(dirp)) != NULL) {
Here, you call readdir
even if the previous loop terminated because readdir
returned NULL
. You want:
if ((direntp != NULL) && ((direntp = readdir(dirp)) != NULL)) {
3:
if ((strcmp(direntp->d_name, ".")) || (strcmp(direntp->d_name, ".."))){
Converting an integer to a boolean is equivalent to asking if it's not zero. The strcmp
function returns zero on a match. So asking if it's not zero is asking if it's not match. But everything is either not a match for "." or not a match for ".."! You want:
if ((!strcmp(direntp->d_name, ".")) || (!strcmp(direntp->d_name, ".."))){
4:
// it can reach here with no problem
closedir(dirp);
return direntp->d_name;
You just returned a pointer into a directory that you closed, rendering the pointer invalid. You need to decide what the lifespan of the returned pointer is supposed to be and perhaps allocate some memory to return.
Maybe:
char *ret = strdup (dirent->d_name);
closedir(dirp);
return ret;
Note that the caller needs to free
the returned string when it's done with it.
5:
char *result = next_node(dname, bname);
printf("%s\n", result);
This will fail if the result
is NULL
. Try:
char *result = next_node(dname, bname);
printf("%s\n", (result == NULL) ? "NULL" : result);