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");
Related
WHAT I HAVE TO DO
I have to find, starting from a directory, a file located in one of all directories that have as root the directory passed in input.
Something as shell command find.
INPUT/OUTPUT
Having this in input:
./myfind /home/claudio/Scrivania file.txt
I need something as this in output, absolute path and last modify date ecc:
/home/claudio/Scrivania/SistemiOperativi/file.txt Tue Mar 30 19:51:54 2021
MY CODE
It doesn't print anything.
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#if !defined(NAME_MAX)
#define NAME_MAX 256
#endif
void find(const char* passed_dir_name, const char* passed_file_name) {
if (chdir(passed_dir_name) == -1) {
perror("FATAL ERROR CHANGING DIRECTORY");
exit(EXIT_FAILURE);
}
DIR* current_directory;
if ((current_directory = opendir(".")) == NULL) {
perror("FATAL ERROR OPENING CURRENT WORKING DIRECTORY");
exit(EXIT_FAILURE);
}
char* buf;
if ((buf = calloc(NAME_MAX, sizeof(char))) == NULL) {
perror("FATAL ERROR ALLOCATING MEMORY");
exit(EXIT_FAILURE);
}
struct dirent* dir;
while ((dir = readdir(current_directory)) != NULL) {
struct stat statbuf;
stat(dir->d_name, &statbuf);
if (S_ISDIR(statbuf.st_mode)) {
if (strncmp(dir->d_name, ".", 1) != 0 && strncmp(dir->d_name, "..", 2) != 0) {
find(dir->d_name, passed_file_name);
}
} else {
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name) == 0)) {
if (getcwd(buf, NAME_MAX) == NULL) {
perror("FATAL ERROR");
exit(EXIT_FAILURE);
}
fprintf(stdout, "%s/%s %s", buf, dir->d_name, ctime(&statbuf.st_mtime));
}
}
}
if (closedir(current_directory) == -1) {
perror("FATAL ERROR CLOSING CURRENT WORKING DIRECTORY");
exit(EXIT_FAILURE);
}
chdir("..");
free(buf);
}
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr, "ERROR: RUn as ./myfind directory\n");
exit(EXIT_FAILURE);
}
const char* dir = argv[1];
const char* file = argv[2];
struct stat statbuf;
stat(dir, &statbuf);
if(!S_ISDIR(statbuf.st_mode)) {
fprintf(stderr, "FATAL ERROR: %s IS NOT A DIRECTORY\n", dir);
exit(EXIT_FAILURE);
}
find(dir, file);
exit(EXIT_SUCCESS);
}
Your parentheses are wrong in:
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name) == 0))
You need to write:
if (strncmp(dir->d_name, passed_file_name, strlen(passed_file_name)) == 0)
Since strncmp(x, y, 0) will always return 0, the condition is never being met.
But note that there's no point in using strncmp here at all. strncmp is only needed if you don't know that one of your entries is a null terminated string. You have a guarante that d_name is null-terminated, and if passed_file_name is not, then strlen is going to be problematic. You might as well just write strcmp(dir->d_name, passed_file_name).
I'm struggling to get the functionality of the "which command" that appears in LINUX, which I require to do the same in C.
I explain my question. In Linux Terminal, if I enter "which file1.txt", it searches in the entire filesystem and prints the path. The syntax for the same is "which ".
Similarly, I want to do the same functionality using the C program. I should only use C. Could anybody help me with how to complete this? I tried many ways, but unable to complete it.
#define _POSIX_SOURCE
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#undef _POSIX_SOURCE
#include <stdio.h>
void traverse(char *fn, int indent) {
DIR *dir;
struct dirent *entry;
int count;
char path[1025];
struct stat info;
for (count=0; count<indent; count++) printf(" ");
printf("%s\n", fn);
if ((dir = opendir(fn)) == NULL)
perror("opendir() error");
else {
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] != '.') {
strcpy(path, fn);
strcat(path, "/");
strcat(path, entry->d_name);
if (stat(path, &info) != 0)
fprintf(stderr, "stat() error on %s: %s\n", path,
strerror(errno));
else if (S_ISDIR(info.st_mode))
traverse(path, indent+1);
}
}
closedir(dir);
}
}
main() {
puts("Directory structure:");
traverse("/", 0);
}
I am using Raspbian and this is a part of an exercise for my advanced C programming in Linux environments. I have to open a directory and list its content, checking if entries are subdirectories or files.
Here is what I did:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
//declarations
int main(int argc, char ** argv){
if(argc != 2){
fprintf(stderr, "Wrong number of arguments\n");
exit(EXIT_FAILURE);
}
DIR *dir;
dir = opendir(argv[1]);
if(!dir){
fprintf(stderr, "Error: unable to open directory\n");
exit(EXIT_FAILURE);
}
struct dirent * entry;
struct stat filestat;
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
stat(entry->d_name, &filestat);
//printf("S_ISREG(%s) value is:%d\n", entry->d_name, S_ISREG(filestat.st_mode));
//printf("S_ISDIR(%s) value is:%d\n", entry->d_name, S_ISDIR(filestat.st_mode));
if(S_ISDIR(filestat.st_mode) == 0){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
closedir(dir);
printf("END\n");
return EXIT_SUCCESS;
}
Now, it works if I am working with relative paths. If I am working on absolute paths, S_ISREG and S_ISDIR macros always return 0. What am I doing wrong?
It seems by doing stat(entry -> d_name, &filestat) you're giving as directory path just the name of the folder you're looking at, which should work if it belongs to the directory from which the file is being executed but might not work with absolute paths
Also, you are not checking if stat is producing any error, which might also be an issue here - or at least provide some insight to the real problem
you might want to try concatenating your path to entry->d_name and use that when you call stat instead, e.g.
char fullPath[MAX_LEN];
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
sprintf(fullPath, "%s/%s", argv[1], entry->dname);
if(stat(fullPath, &filestat) < 0){
//handle error
}
if(S_ISDIR(filestat.st_mode) == 0){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
where MAX_LEN is some predefined constant
Use
if (fstatat(dirfd(dir), entry->d_name, &filestat, AT_SYMLINK_NOFOLLOW) == -1) {
fprintf(stderr, "Cannot stat %s/%s: %s.\n",
argv[1], entry->d_name, strerror(errno));
/* Optionally, exit(EXIT_FAILURE); */
} else {
/* Directory entry information in filestat */
}
As explained in the man 3 readdir manual page, if entry->d_type == DT_UNKNOWN, you need to do the above fstatat() to obtain the type.
This is because some filesystems do not provide the information in the directory entries, and return d_type == DT_UNKNOWN for all directory entries. All applications are required to handle DT_UNKNOWN correctly.
Note that you need
#define _POSIX_C_SOURCE 200809L
#define _ATFILE_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
at the beginning of your file, to tell the C library to expose the functions (fstatat() and strerror()).
However, opendir()/readdir()/closedir() is the wrong way to check directory contents, because the contents may change during your traversal. You would be better off using [scandir()](https://man7.org/linux/man-pages/man3/scandir.3.html9, glob() (if searching for files matching a pattern), or nftw() (if traversing entire trees) which are all POSIX.1 standard functions provided by POSIXy C libraries (basically all except Windows).
An exercise claiming to show how to list files in a directory and using opendir()/readdir()/closedir() is at best misleading, because it leaves all the complexity – handling changes to the directory contents, like renamed files – to you the writer, without telling you such work is necessary! Yes, two decades ago filesystems were typically so simple that opendir()/readdir()/closedir() worked without issues, but that is not the case anymore. The other functions listed above are supposed to handle such cases gracefully, so you the programmer shouldn't need to do it yourself.
Here is one way to properly implement the directory scan in Linux:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <ftw.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
static int report_entry(const char *path,
const struct stat *info,
int typeflag,
struct FTW *ftwbuf)
{
/* If you need it, entry name is (path + ftwbuf->base). */
switch (typeflag) {
case FTW_D: /* Directory */
printf("%s is a directory\n", path);
/* If this is the path given to nftw(), recurse into it: */
if (ftwbuf->level == 0)
return FTW_CONTINUE;
/* Do not recurse into any other directories. */
return FTW_SKIP_SUBTREE;
case FTW_DNR: /* Directory, but no access to contents */
printf("%s is a directory but there is no read access\n", path);
return FTW_CONTINUE;
case FTW_DP: /* Directory that was already mentioned */
return FTW_CONTINUE;
case FTW_F: /* Regular file */
printf("%s is a file\n", path);
return FTW_CONTINUE;
case FTW_SL: /* Symlink, and FTW_PHYS was set for nftw() */
printf("%s is a symbolic link\n", path);
return FTW_CONTINUE;
case FTW_SLN: /* Symlink to a nonexistent file */
/* This will NOT be reported if FTW_PHYS is set in the nftw() call. */
printf("%s is a symbolic link to a nonexistent file\n", path);
return FTW_CONTINUE;
case FTW_NS: /* stat() failed */
printf("%s is unknown, and cannot be stat()'d\n", path);
return FTW_CONTINUE;
default: /* Should never occur */
printf("%s is of unknown an unexpected type (%d)\n", path, typeflag);
return FTW_STOP;
}
}
/* Number of file descriptors nftw() is allowed to use.
It mostly matters to applications that use many file descriptors,
like service daemons (servers). If nftw() runs out, it slows down,
but does not fail. In Linux, processes usually have at least
a thousand file descriptors available, so 64 is very conservative. */
#ifndef NFTW_FDS
#define NFTW_FDS 64
#endif
int report_directory(const char *path)
{
int result;
if (!path || !*path) {
/* No path specified; invalid parameter */
errno = EINVAL;
return -1;
}
result = nftw(path, report_entry, NFTW_FDS, FTW_ACTIONRETVAL | FTW_PHYS);
if (result == -1) {
/* nftw() error, errno set. */
return -1;
} else
if (result == FTW_STOP) {
/* report_entry() returned FTW_STOP. We assume error was already printed. */
errno = 0;
return -1;
} else
if (result != 0) {
/* Unexpected error */
errno = EIO;
return -1;
}
/* Done successfully. */
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *thisname = (argc >= 1 && argv && argv[0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", thisname);
fprintf(stderr, " %s DIRECTORY-OR-FILE\n", thisname);
fprintf(stderr, "\n");
return (argc == 2) ? EXIT_SUCCESS : EXIT_FAILURE;
}
if (report_directory(argv[1]) != 0) {
if (errno) {
fprintf(stderr, "Error: %s: %s.\n", argv[1], strerror(errno));
}
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Try this:
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
if(entry->d_type == DT_DIR){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
It might not work on your platform though, read the readdir documentation for more information.
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'm stuck on unix system programming and am beginner about it. Assume that there is a directory which is X. There are a file(text1.txt) and another directory which is Y in X. Last, there are two files(text2.noExtension) and text3.noExtension) and another directory which is Z in Y. My goal is that read files and enter directories until there is no directory. Candidly, I really don't have any idea how to go on.
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
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 want to list all directories and sub-directories, try something recursive. E.g.:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void listOfDir(char * dirname, int level)
{
struct dirent *direntp;
DIR *dirp;
char *subdirname;
if ((dirp = opendir(dirname)) == NULL)
{
return;
}
while ((direntp = readdir(dirp)) != NULL)
{
if(strcmp(direntp->d_name, ".")==0 || strcmp(direntp->d_name, "..")==0)
continue; // skip current and parent directories
printf("%*c%s\n", level, '>', direntp->d_name);
if( direntp->d_type == 4)
{
// build child dir name and call listOfDir
subdirname = (char*)malloc(strlen(direntp->d_name) + strlen(dirname) + 2);
strcpy(subdirname, dirname);
strcat(subdirname, "/");
strcat(subdirname, direntp->d_name);
listOfDir(subdirname, level+1);
free(subdirname);
}
}
closedir(dirp);
}
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;
}
listOfDir(argv[1], 1);
return 0;
}
Expression like printf("%*c", level, '>') just make indents for elach level of nesting