LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   writing a recursive 'find' command (https://www.linuxquestions.org/questions/programming-9/writing-a-recursive-find-command-534903/)

nadroj 03-05-2007 08:45 PM

writing a recursive 'find' command
 
im working on a homework assignment. the assignment is to write a simple unix 'myFind' command with synopsis: find <filename>. it searches current directory and every subdirectory and prints the path of each file whos name is <filename>.

after some debugging, i thought it would be easier to basically make it a recursive 'ls' command, as my find isnt working. the 'ls' isnt working either. when i run from my home directory it seems to work fine. however, if i run from / or /usr (maybe more directories too) it does not work.

when i run from / it gets stuck searching in a weird directory (which doesnt exist) like /dev/fd/3/0/dev/fd/3/cpu/bin/dev/3...etc

when i run from /usr it also doesnt work properly. if i run it from /usr, as "./myFind | grep stdio.h" it returns no output. however, there are multiple files in subdirectories of this folder named stdio.h.

i have tried using stat but it isnt helping so i stopped with that. i have emailed my professor asking if we have to check if a file is a link, device, etc, and he said we dont have to, and also that we do not _have_ to use stat to do this assignment. i would like to do it without stat.

heres the code if you have time to check it out.
Code:

#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include<string.h>

void search(char* path)
{
        DIR* dp;

        dp = opendir(path);

        if (dp == NULL)
        {
                printf("cant open: %s\n",path);
                return;
        }

        struct dirent* dirp;
        while( (dirp = readdir(dp)) != NULL )
        {
                if (strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0)
                        continue;

                printf("%s%s\n", path,dirp->d_name);

                char tmpPath[256]="";
                strcat(tmpPath,path);
                strcat(tmpPath,dirp->d_name);
                strcat(tmpPath,"/");

                search(tmpPath);
        }
       
}

int main(int argc, char* argv[])
{
        search("./");
}

thanks for your time.

edit:
from my home directory (with a deep arbitrarily copied hierarchy) it lists the files, including one named:
Quote:

./subtest/subdir/test/cvx/dfgd/sdf/fgh/ghj/acpi/events/alsa/sound/linux-2.4.33.3/arch/m68k/sun3/config.c
the reason im including this is to show that it is looking in complicated and deep subdirectories such as the one above. this (and the /dev/... thing above) leads me to think that there must be a problem with files that are not regular files or directories. however, my professor told me it can be done without checking for this.

graemef 03-05-2007 10:10 PM

When reading the contents of a directory, the directory may consist of files and other directories. So you need to determine if the current directory element you are looking at is a file or a directory. Only if it is a directory will you want to do a recursive call to search.

nadroj 03-05-2007 10:26 PM

is the only way to determine this to use 'stat'?

my code does 'kind of' take care of what your talking about. after the recursive call in the while loop, i call opendir on the directory passed to search. if the opendir call was NULL, then the path passed to the function was referring to a file, and the function returns.

it seems to work the way i have it (only in my home directory). or do you still see a specific problem with doing it this way?

graemef 03-05-2007 10:39 PM

using stat() would be the way that I would check it, using the st_mode element of the stat structure, and the S_IFDIR flag. I would say that it is more efficient to test and then only do the recursive call for directories. To me it is also cleaner. You don't need to worry about the special files . .. and you can also decide to follow or not to follow symbolic links.

nadroj 03-05-2007 11:10 PM

thanks for your help (forgot to say previously).
i was trying earlier with stat and couldnt get it to work, so i tried to do it without stat.

im now trying to do it and im getting the same lack of success.
i will post how i modified the body of the while loop.
Code:

while( (dirp = readdir(dp)) != NULL )
        {
                if (strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0)
                        continue;
 
                printf("%s%s\n", path,dirp->d_name);
 
                struct stat buf;
                stat(dirp->d_name, &buf);
       
                if (buf.st_mode == S_IFDIR)
                {
                        char tmpPath[256]="";
                        strcat(tmpPath,path);
                        strcat(tmpPath,dirp->d_name);
                        strcat(tmpPath,"/");
       
                        search(tmpPath);
                }
        }

from what i have read, you can use either the method you described (which is shown here) or another method, to check if the dirent* is a file. you can also check: if (S_ISDIR(buf.st_mode))
i have tried both just now and it just seems to list everything in the current directory.

i tested with a printf inside the if statement comparing buf.st_mode and it never prints.

edit: i think im getting somewhere.. will post back tomorrow.

graemef 03-06-2007 01:06 AM

First print out buf.st_mode. It might be easier to understand what is going on if you look at the value in hex mode.

Then rather than doing an equivalence comparison == you need to look at the individual bits. S_IFDIR is a flag so you want to do a bitwise comparison, something like:
if (buf.st_mode & S_IFDIR)


All times are GMT -5. The time now is 11:38 AM.