开发者

POSIX Program to search entire file system for a file

Hey everyone. I need to write a POSIX program to search through an entire file system for a specified file starting at the top directory. I've got some code which isn't done at all, but when I run it, and check to see if a particular file is a directory, it's saying this file which is not at all a directory is a directory and is trying to move into it, causing an error. I'm not sure how I can tell it that this type of file isn't a directory.

Here's my code. I know it's not 开发者_C百科perfect and I could probably do some things differently in the way of getting the directory names and passing them into the function. Either way, I'm pretty sure I have to do this recursively.

The file in question is /dev/dri/card0 and I'm running this from a Debian virtual machine.

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std; 

void SearchDirectory(string file_Name, string directory){
    string new_Directory = directory; 
    DIR *dirp; 
    dirp = opendir(directory.c_str()); 
    struct dirent *dptr; 
    struct stat statStruct; 

    while(dptr = readdir(dirp)){
        stat(dptr->d_name, &statStruct); 
        if( S_ISDIR(statStruct.st_mode) ){

            string check = dptr->d_name; 
            if ( check.compare(".") == 0 || check.compare("..") == 0 ){
                continue; 
            }
            else{
                cout << dptr->d_name << " is is a directory" << endl; 
                new_Directory.append("/");
                new_Directory.append(dptr->d_name);  
                SearchDirectory(file_Name, new_Directory); 
            }
        }
        else if( S_ISREG(statStruct.st_mode)){
            string check = dptr->d_name; 
            if( check.compare(file_Name) == 0){
                cout << "Found " << file_Name << " in " << directory << "/" << endl; 
            }
        }
    }
}

int main(int argc, char *argv[]){

    if(argc < 2 || argc > 2){
        cerr << "This program will find the specified file." << endl; 
        cerr << "Usage: mysearch <filename>" << endl; 
        return 1; 
    }

    string file_Name = argv[1]; 
    SearchDirectory(file_Name, "/"); 

    return 0; 

}


POSIX.2 requires a working "find" command.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>", argv[0]);
    }

    execlp("find", "find", "/", "-name", argv[1], "-print", (char *)NULL);
    exit(EXIT_FAILURE);
}


->d_name returns just the name of the file, not the path to the file. You need to stat (not yet constructed) new_Directory instead of dptr->d_name.

You also have a problem if a directory contains more than one subdirectories. Your construction of new_Directory is incorrect for each subdirectory after the first.

You never closedir your directory handle, so you run out of resources. You should also consider loading the entire directory into an array before recursing to avoid running out of handles.

void SearchDirectory(string directory, string target_File_Name){
    DIR *dirp = opendir(directory.c_str());
    if (!dirp) {
        perror(("opendir " + directory).c_str());
        return;
    }

    struct dirent *dptr;
    while(dptr = readdir(dirp)){
        string file_Name = dptr->d_name;
        string file_Path = directory + "/" + file_Name;

        struct stat statStruct; 
        stat(file_Path.c_str(), &statStruct); 
        if( S_ISDIR(statStruct.st_mode) ){
            if ( file_Name.compare(".") == 0 || file_Name.compare("..") == 0 ){
                continue; 
            }

            SearchDirectory(file_Path, target_File_Name);
        }
        else if( S_ISREG(statStruct.st_mode)){
            if( file_Name.compare(target_File_Name) == 0){
                cout << file_Path << endl;
            }
        }
    }

    closedir(dirp);
}

Update: Added second problem.

Update: Added third problem.

Update: Added code.


Not for the benefit of the OP, who writes "The point is to come up with a way to do it myself," but rather for the benefit of posterity, here is a way to use Boost.Filesystem:

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// sample usage: find_file("/home", ".profile");
void find_file( const fs::path& dirPath, const std::string& fileName) {
  fs::recursive_directory_iterator end;
  for(fs::recursive_directory_iterator it(dirPath); it != end; ++it) {
    if(it->leaf() == fileName)
      std::cout << it->path() << "\n";
    if(fs::is_symlink(it->symlink_status()))
      it.no_push();
  }
}


Use fork, execv and the Unix implemented /usr/bin/find process and redirect its output for your result area?


I'm not sure if it's POSIX or not but the nftw library function is widely available on UNIX (HP-UX, AIX, Linux).


Your problem is "search a tree for a match"

BFS and DFS are the canonical basic algorithms. Give them a start node and go.

You will get into trouble if you follow symlinks; so test for them and don't follow them.

You should be able to map each point in the *FS algorithms to a directory operation.


Since C++ is an option, why not use something like Boost.Filesystem? The Boost.Filesystem two-minute tutorial gives an example of how to implement your search using directory iterators.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜