Thread: Determine file type (Linux)

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    111

    Determine file type (Linux)

    Ok, sorry for asking such a basic question (again), but I haven't been able to find any intelligent info on exactly how to determine the following: Is a file a directory or not?

    I think I need to use stat, but this returns absolutely nothing in the examples I've tried. I've been using dirent.h, DIR and readdir() to read the folder(s), but the only "safe" information I can get from the files are the filenames (d_name). The d_name value seems totally useless.

  2. #2
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    From man stat:


    Code:
           The following POSIX macros are defined to check the file type using the
           st_mode field:
    
               S_ISREG(m)  is it a regular file?
    
               S_ISDIR(m)  directory?
    
               S_ISCHR(m)  character device?
    
               S_ISBLK(m)  block device?
    
               S_ISFIFO(m) FIFO (named pipe)?

  3. #3
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by cnewbie1 View Post
    Ok, sorry for asking such a basic question (again), but I haven't been able to find any intelligent info on exactly how to determine the following: Is a file a directory or not?

    I think I need to use stat, but this returns absolutely nothing in the examples I've tried. I've been using dirent.h, DIR and readdir() to read the folder(s), but the only "safe" information I can get from the files are the filenames (d_name). The d_name value seems totally useless.
    The stat::st_mode member should have the S_IFDIR bit set if it's a directory. I can't be more specific without seeing the code, though...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    For example:
    Code:
    $ ./isdir . .. isdir*
    .                    -- is a directory
    ..                   -- is a directory
    isdir                -- is not a directory
    isdir.c              -- is not a directory
    $ cat isdir.c
    #include <sys/stat.h>
    #include <unistd.h>
    
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        int a;
        for(a = 1; a < argc; a ++) {
            struct stat buf;
            stat(argv[a], &buf);
            if(S_ISDIR(buf.st_mode)) {
                printf("%-20s -- is a directory\n", argv[a]);
            }
            else {
                printf("%-20s -- is not a directory\n", argv[a]);
            }
        }
        return 0;
    }
    $
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Registered User
    Join Date
    Nov 2009
    Posts
    111
    Thanks, and again apologies for getting back to being more basic than I really should need to be. I'll have a look at the help, hints and advice tomorrow

  6. #6
    Registered User
    Join Date
    Nov 2009
    Posts
    111
    Ok...
    This code (from your example) works fine. If I give it a filename it reports it as not a directory, and a directory is reported as a directory:
    Code:
    int main() {
    	int a;
    	char *filename = "directory/file.txt";
    	//char *filename = "directory/subdirectory";
    
    	struct stat buf;
            stat(filename, &buf);
            if (S_ISDIR(buf.st_mode)) {
                printf("%-20s -- is a directory\n", filename);
            } else {
    	    printf("%-20s -- is not a directory\n", filename);
    	}
    
    	return 0;
    }
    However - when I try to combine this with the directory listing code I've been playing with, it doesn't work. This code lists the contents of a directory:
    Code:
    DIR *dp;
    struct dirent *ep;
    dp = opendir("./directory");
    	        
    if (dp != NULL) {
    	while (ep = readdir(dp)) {
    		if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) {
          			continue;
    		}
    		//printf("%s,", ep->d_name);
    
    		struct stat buf;
    	        stat(ep->d_name, &buf);
    		if (S_ISDIR(buf.st_mode)) {
    	            printf("%-20s -- is a directory\n", ep->d_name);
    	        }
    	        else {
    	            printf("%-20s -- is not a directory\n", ep->d_name);
    	        }
    	}
    	(void)closedir(dp);
    } else {
    	perror("Couldn't open the directory\n");
    }
    All entries are reported as "-- is not a directory". At first I thought it was related to some buffering and where I created the struct, and that the first entry (a file) would be "stuck" and not change. However, I'm not sure.

    The contents of the directory:
    anotherfile.exe
    anothersubfolder
    file
    file.txt
    subdirectory
    yetanotherfile.bat

    The above code lists this:
    Code:
    subdirectory         -- is not a directory
    anothersubfolder     -- is not a directory
    file.txt             -- is not a directory
    .file                -- is not a directory
    anotherfile.exe      -- is not a directory
    file                 -- is not a directory
    yetanotherfile.bat   -- is not a directory
    If I place a break at the end of the while-loop, the only entry listed is
    Code:
    subdirectory         -- is not a directory
    If I remove the break, the first new entry is
    Code:
    subdirectory         -- is a directory
    anothersubfolder     -- is a directory
    file.txt             -- is a directory
    .file                -- is a directory
    anotherfile.exe      -- is a directory
    file                 -- is a directory
    yetanotherfile.bat   -- is a directory
    But only for one run. The next run again reports all entries as not directories.

    .

  7. #7
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    If you read doc of readdir, struct dirent: d_type can be used to determine file type.
    RTM!!!

  8. #8
    Registered User
    Join Date
    Nov 2009
    Posts
    111
    Every place I've seen it discussed, the point is made that d_type cannot be used safely. Only d_name and d_init(?) can be used safely. This is supported by the fact that when I've used it, the values have been completely useless and not saying anything about wether or not the file is a directory.

    So, RTM yourself. And I'll put some really mature exclamation marks at the end as well: !!!

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Innnnnnnnnnnnnteresting. The code you've given works here (on Ubuntu), with "is a directory" appearing as needed in the middle of all the "is not a directory" lines. The way you have it set up, technically your buf variable gets destroyed and re-created every time through the loop, so caching of any sort shouldn't be a problem at all. I guess you can check to see if for some reason the call to stat fails.

    OOH OOH update: If I change my program to walk through a different directory than the one it is in (like you are), then it fails as you say. I get a lot of "No such file or directory" if I use perror; so you probably need to let stat in on the directory somehow.
    Last edited by tabstop; 12-29-2010 at 10:06 AM.

  10. #10
    Registered User
    Join Date
    Nov 2009
    Posts
    111
    But how does that explain that THIS code works, even though the directory it is given is not the one I'm in the running the program?
    Code:
    int main(int argc, char *argv[]) {
    	int a;
    	//char *filename = "directory/file.txt";         // Alt.#1
    	char *filename = "directory/subdirectory";  // Alt.#2
    
    	struct stat buf;
            stat(filename, &buf);
            if (S_ISDIR(buf.st_mode)) {
                printf("%-20s -- is a directory\n", filename);
            } else {
    	    printf("%-20s -- is not a directory\n", filename);
    	}
    	return 0;
    }
    Alt#1 returns "not a directory" and Alt#2 returns "is a directory".

    I don't see any options to pass anything else or more data to stat() either, since it won't accept more arguments.
    Last edited by cnewbie1; 12-29-2010 at 12:01 PM.

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    Check your return from stat!
    Code:
                if (stat(ep->d_name, &buf) == -1) {
                    fprintf(stderr, "%s: ", ep->d_name);
                    perror("stat");
                }
                else if (S_ISDIR(buf.st_mode)) {
    readdir is giving you the name of the file within "./directory", so you are only getting "file.txt", not "./directory/file.txt". You need to prepend the file name with whatever you pass to opendir.

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,125
    > dp = opendir("./directory");
    When you do things like this, the ep->name is just the name of the file (say foo.txt), NOT "./directory/foo.txt".

    The problem is, you're calling stat() for a file in the opened directory, as if it were in the CURRENT directory.

    Y'know, stat() returns a sucess/fail status - try paying attention to it.

    ^^^ Meh - what he said!
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    Registered User
    Join Date
    Nov 2009
    Posts
    111
    Ah, of course - that's logical. Thanks :-)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. LDAP Query
    By Travoiz in forum C++ Programming
    Replies: 0
    Last Post: 08-13-2009, 02:58 PM
  2. Replies: 0
    Last Post: 03-20-2008, 07:59 AM
  3. failure to import external C libraries in C++ project
    By nocturna_gr in forum C++ Programming
    Replies: 3
    Last Post: 12-02-2007, 03:49 PM
  4. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  5. header file bringing errors?
    By bluehead in forum Windows Programming
    Replies: 4
    Last Post: 08-19-2003, 12:51 PM