How to split the subdirectories names? - c

This code is fetching the subdirectories names that are present in a given directory. What I am trying to do is to split the subdirectories names using using a delimiter " " but when I print the token it should print the first subdirectory only but instead the code prints all the subdirectories names. I don't know what is wrong that the strtok is not working.
Given result is like
/home/bilal/Videos/folder1/rasta
/home/bilal/Videos/folder1/fd
/home/bilal/Videos/folder1/fd/fds
/home/bilal/Videos/folder1/fd/sub
Expected result
/home/bilal/Videos/folder1/rasta
char path[PATH_MAX] = "";
char path1[PATH_MAX];
void listdir(void) {
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(path))) {
perror("opendir-path not found");
return;
}
while ((entry = readdir(dir))) {
char *name = entry->d_name;
if (entry->d_type == DT_DIR) /* if "." or ".." skip */
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
snprintf(path1, 100, "%s/%s ", path, name);
char *token = strtok(path1, " ");
printf("%s\n", token);
if (entry->d_type == DT_DIR) {
char *p;
strcat(path, "/");
strcat(path, name);
listdir(); /* recursive call */
if ((p = strrchr(path, '/'))) {
if (p != path)
*p = 0;
}
}
}
closedir(dir);
}
int main(int argc, char **argv) {
if (argc > 1)
strcpy(path, argv[1]);
else
strcpy(path, "/home/bilal/Videos/folder1");
listdir();
}

There are several issues in the posted code:
There is no need to use 2 separate path arrays, you could use path and remember its original length to strip the trailing part after each iteration.
You append a space after the pathname in snprintf(path1, 100, "%s/%s ", path, name); and strtok() immediately cuts the pathname on this space: it seems redundant and even counterproductive if a component of the pathname contains a space as strtok will stop there instead.
It is unclear what your goal is: each entry is printed as the function enumerates the directory entries and recurses on subdirectories.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
char path[PATH_MAX];
void listdir(void) {
DIR *dir;
struct dirent *entry;
size_t len = strlen(path);
if (len >= sizeof(path) - 1) {
// array too small to construct pathnames
return;
}
if (!(dir = opendir(path)) != NULL) {
perror("opendir-path not found");
return;
}
while ((entry = readdir(dir)) != NULL) {
char *name = entry->d_name;
if (entry->d_type == DT_DIR) { /* if "." or ".." skip */
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
}
snprintf(path + len, sizeof(path) - len, "/%s", name);
printf("%s\n", path);
if (entry->d_type == DT_DIR) {
listdir(); /* recursive call */
}
path[len] = '\0';
}
closedir(dir);
}
int main(int argc, char **argv) {
if (argc > 1)
strcpy(path, argv[1]);
else
strcpy(path, "/home/bilal/Videos/folder1");
listdir();
return 0;
}

Related

How to find a file in a directory and its subdirectories in C on Linux?

I want to write a program that given a filename searches in the current directory and its subdirectories for that file. The names of the subdirectories containing that file should be printed.
But my code prints just the subdirectories.
#include <dirent.h>
#include <stdio.h>
#include <string.h>
void listDir(char *path, char *name)
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir(path)) != NULL) {
while (( ent = readdir(dir)) != NULL) {
if (ent->d_type == DT_REG && name == ent->d_name) {
printf("%s\n", ent->d_name);
}
if (ent->d_type == DT_DIR && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) {
printf("%s\n", ent->d_name);
listDir("/home/dir1/ent->d_name", name);
}
}
closedir(dir);
}
}
void main()
{
listDir("/home/dir1", "file1");
}
You either need to keep track of the full path, or descend into each directory. (if you are looking at foo/bar/baz, then opendir("baz") will fail if you are in the top level directory). Something like:
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
void
listDir(char* path, const char *name)
{
DIR* dir;
struct dirent *ent;
char *end = strrchr(path, '\0');
if( (dir = opendir(path)) == NULL ){
perror(path);
return;
} else while( (ent = readdir(dir)) != NULL ){
if( ent->d_type == DT_DIR && strcmp(ent->d_name, ".")
&& strcmp(ent->d_name, "..") )
{
snprintf(end, PATH_MAX - (end - path), "/%s",
ent->d_name);
listDir(path, name);
*end = '\0';
} else if( !strcmp(ent->d_name, name) ){
printf("%s\n", path);
}
}
closedir(dir);
}
int
main(int argc, char **argv)
{
char path[PATH_MAX];
char *defaults[] = {NULL, NULL, ".", NULL};
if( argc < 2 ){
printf("usage: %s name [path...]", argv[0]);
return EXIT_SUCCESS;
}
const char *name = argv[1];
if( argc < 3 ){
argv = defaults;
}
for( argv += 2; *argv; argv += 1 ){
/* getcwd(fullpath, PATH_MAX); */
snprintf(path, PATH_MAX, "%s", *argv);
listDir(path, name);
}
return 0;
}
There are multiple problems in your code:
the comparison name == ent->d_name does not work for string pointers, you should use !strcmp(name, ent->d_name).
listDir("/home/dir1/ent->d_name", name); does not magically concatenate strings. You should use snprintf or asprintf (on linux and BSD systems) to construct the subdirectory name.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void listDir(const char *path, const char *name) {
DIR *dir;
struct dirent *ent;
if ((dir = opendir(path)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (ent->d_type == DT_REG && !strcmp(name, ent->d_name)) {
printf("%s\n", path);
}
if (ent->d_type == DT_DIR && strcmp(ent->d_name, ".")
&& strcmp(ent->d_name, "..")) {
char *subdir;
size_t len = strlen(path);
const char *sep = "/";
if (len && path[len - 1] == '/')
sep++;
if (asprintf(&subdir, "%s%s%s", path, sep, ent->d_name) > 0) {
listDir(subdir, name);
free(subdir);
}
}
}
closedir(dir);
}
}
int main(int argc, char *argv[]) {
if (argc == 3) {
listDir(argv[1], argv[2]);
} else {
fprintf(stderr, "usage: %s FILE DIR\n", argv[0]);
}
return 0;
}

How to make the strtok working when reading the pathnames?

In this code, I am trying to split the pathnames with the help of strtok(). I am watching the \n sign to differentiate different pathnames. Although when I print the path variable, it gives all the pathnames.
But when I split them and print the token[1] variable, it gives me the segmentation fault. I used token[0], but it gave me all the pathnames as it was printed with the path variable but without \n sign concatenated with pathnames.
int watch(char *dirname) {
DIR *dir;
struct dirent *entity;
char path[500] = { 0 };
char *token[2];
dir = opendir(dirname);
if (dir != NULL) {
while (entity = readdir(dir)) {
snprintf(path, sizeof(path), "%s%s", dirname, entity->d_name);
strcat(path, "\n");
token[0] = strtok(path, "\n");
token[1] = strtok(NULL, "\n");
printf("%s\n", token[1]);
}
closedir(dir);
} else {
perror("Couldn't open the directory");
}
}
The given code does not make sense and it is unclear what the real purpose is.
As it stands token[1] will always be NULL. As the string to tokenize is something like "dirfilename\n" and then split on \n. The second call to strtok always returns NULL.
So the question remains, what is the purpose of this code?
When concatenating the dirname and filename, you do not insert a / between them. Use "%s/%s" to make it a pathname.
It is unclear why there should be any ; in the pathname. This might be a confusion with the PATH variable.
Here is a simple program to enumerate files from the directories in the PATH variable:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
int list_path(const char *p, int len) {
char path[1024];
DIR *dir;
struct dirent *entity;
int count = 0;
if (len + 2 > (int)sizeof(path))
return -1;
snprintf(path, sizeof(path), "%.*s", len, p);
dir = opendir(path);
if (dir != NULL) {
while ((entity = readdir(dir)) != NULL) {
if (!strcmp(entity->d_name, ".") || !strcmp(entity->d_name, ".."))
continue;
count++;
snprintf(path + len, sizeof(path) - len, "/%s", entity->d_name);
printf("%s\n", path);
}
closedir(dir);
}
return count;
}
int main() {
char *path = getenv("PATH");
const char *pathsep = ":"; // use `;` for Windows
int len;
if (path) {
while (*path) {
len = strcspn(path, pathsep);
list_path(path, len);
path += len + (path[len] != '\0');
}
}
return 0;
}

How to list all files of a directory recursively in c

This is a c program that list all files of a directory recursively , so it can list all files in c: drive for example .
The above program works fine but i've been trying for 5 days and i can't get it to work without using a function (only main , not main and the other function (listFilesRecursively) )
#include <stdio.h>
#include <string.h>
#include <dirent.h>
void listFilesRecursively(char *path);
int main()
{
// Directory path to list files
char path[100];
// Input path from user
strcpy(path , "c://");
listFilesRecursively(path);
return 0;
}
/**
* Lists all files and sub-directories recursively
* considering path as base path.
*/
void listFilesRecursively(char *basePath)
{
char path[1000];
struct dirent *dp;
DIR *dir = opendir(basePath);
// Unable to open directory stream
if (!dir)
return;
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
{
printf("%s\n", dp->d_name);
// Construct new path from our base path
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp->d_name);
listFilesRecursively(path);
}
}
closedir(dir);
}
Thanks :)
I can't for the life of me think why anybody would want to enumerate directories by calling main() recursively. But, since I can't resist a pointless challenge, here's a version that does. Do I get the prize for "most fruitless waste of ten minutes?" ;)
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
const char *path;
if (argc != 2) path = "/etc"; /* Set starting directory, if not passed */
else
path = argv[1];
DIR *dir = opendir (path);
if (dir)
{
struct dirent *dp;
while ((dp = readdir(dir)) != NULL)
{
if (dp->d_name[0] != '.')
{
char *fullpath = malloc (strlen (path) + strlen (dp->d_name) + 2);
strcpy (fullpath, path);
strcat (fullpath, "/");
strcat (fullpath, dp->d_name);
if (dp->d_type == DT_DIR)
{
char **new_argv = malloc (2 * sizeof (char *));
new_argv[0] = argv[0];
new_argv[1] = fullpath;
main (2, new_argv);
free (new_argv);
}
else
printf ("%s\n", fullpath);
free (fullpath);
}
}
closedir(dir);
}
else
fprintf (stderr, "Can't open dir %s: %s", path, strerror (errno));
return 0;
}

how to store the names of paths in a list or an array of strings in C?

I have the following code to find files recursively in a folder. The arguments I am prompt to enter are path where files are located, and 2 the "wildcard" of the files I am trying to list:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#define MAX_STRING_SIZE 255
void listFilesRecursively(char *path, char *suffix);
int main()
{
// Directory path to list files
char path[100];
char suffix[100];
// Suffix Band Sentinel-2 of Type B02_10m.tif
// Input path from user
printf("Enter path to list files: ");
scanf("%s", path);
printf("Enter the wildcard: ");
scanf("%s", suffix);
listFilesRecursively(path, suffix);
return 0;
}
int string_ends_with(const char * str, const char * suffix)
{
int str_len = strlen(str);
int suffix_len = strlen(suffix);
return
(str_len >= suffix_len) &&
(0 == strcmp(str + (str_len-suffix_len), suffix));
}
/**
* Lists all files and sub-directories recursively
* considering path as base path.
*/
void listFilesRecursively(char *basePath, char *suffix)
{
char path[1000];
struct dirent *dp;
DIR *dir = opendir(basePath);
// Unable to open directory stream
if (!dir)
return;
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
{
//printf("%s\n", dp->d_name);
// Construct new path from our base path
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp->d_name);
if (string_ends_with(path, suffix))
printf("%s\n", path);
listFilesRecursively(path, suffix);
}
}
//int num = sizeof(arr) / sizeof(arr[0]);
//printf("%d", num);
//for(int i = 0; i <= num; i++){
// printf(arr[i]);
closedir(dir);
}
It works fine because it prints the files that end with a certain ending (line 66:67), however, How could I store those values in a list to return in my program? I tried different things but none of them seemed to work.
Thank you very much!

C get contents of file recursivley

I am trying to print out the contents of every file given a directory recursively. I have some logical error in my code and I can't figure out where it's going wrong.
Go through directory/subdirectories and get filename:
char filename[500], filepath[500];
void listdir(char *dir)
{
DIR *dp;
struct dirent *name;
struct stat statbuf;
if((dp = opendir(dir)) == NULL)
{
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((name = readdir(dp)) != NULL)
{
if(lstat(name->d_name, &statbuf) == 0)
{
if(statbuf.st_mode & S_IFDIR)
{
/* Found a directory, but ignore . and .. */
if(strcmp(".", name->d_name) == 0 || strcmp("..", name->d_name) == 0)
continue;
// Directory name
int len = strlen(filepath);
strcat(filepath, name->d_name);
strcat(filepath, "/");
/* Recurse at a new indent level */
listdir(name->d_name);
filepath[len] = '\0';
}
else
{
// Filename
strcpy(filename, filepath);
strcat(filename, name->d_name);
// Prevent double printing
if(file[strlen(filename) - 1] != '~')
readFile(filename);
}
}
}
chdir("..");
closedir(dp);
}
Open/Read file contents:
void readFile(char *filepath)
{
char ch;
FILE *file;
file = fopen(filepath, "r");
if(file)
{
while((ch = fgetc(file)) != EOF)
printf("%c", ch);
fclose(file);
}
}
Main:
int main(int argc, int *argv[])
{
listdir(argv[1]);
return 0;
}
So if I run the program like this ./fileread ~/Desktop and I have this on the Desktop:
Songs.txt, test/test.txt, test/random.txt
It will print out the contents of Songs.txt, but won't print out anything inside the test folder. If I take out "Prevent double printing" line, then it will print out the contents of Songs.txt twice and still not print out anything inside the test folder.
What am I doing wrong? Any help would be appreciated!
UPDATED
I added local strings:
void getdir(char *dir)
{
char *direct;
char filepath[250];
...
direct = malloc(strlen(dir) + strlen(name->d_name) + 2);
strcpy(direct, dir);
strcat(direct, "/");
strcat(direct, name->d_name);
getdir(direct);
free(direct);
}
else
{
// Concatenate file name
strcpy(filepath, dir);
strcat(filepath, "/");
strcat(filepath, name->d_name);
if(filepath[strlen(filepath) - 1] != '~')
readFile(filepath);
}
This seems to work great. If there's anything I shouldn't do, please let me know. Thanks for the help everyone!

Resources