Page 1 of 1

stat() no working properly on another dir than the CWD

Posted: Thu Aug 22, 2013 3:40 pm
by Reylak
Hello all, I'm working on a simple function that must list the content of any given folder on the card. It seems to be working nice when I list the current directory (".") but whenever I want to explore another folder the function 'stat()' (which seems to be usable according to several examples I came across) gives weird results.

I haven't checked for the time of last access, etc. but as for st_mode and st_size I'm sure there is a problem.
st_mode cannot be exploited to determine whether it's a directory or not with the usual macro S_ISDIR (it always returns 0); however I managed to find the method "elem->d_type == DT_DIR", where elem is the dirent struct, which is working properly.
st_size doesn't give the actual size; in the root (accessed using "/") the size of every item (directories and files) is 34049932, and on some others it comes to 0.

As said above, when I stat in the current working directory, S_ISDIR works fine and the given size is correct.

Here is my code if it can help:

Code: Select all

    struct dirent *elem;
    struct stat st;
    
    const char *dirName = luaL_checkstring(L, 1);        // luaL_checkstring() just gives the name of the folder to be listed
    
    DIR *dir = opendir(dirName);
    
    while ((elem = readdir(dir))) {
        lua_pushstring(L, elem->d_name);
        lua_pushboolean(L, elem->d_type == DT_DIR);
        stat(elem->d_name, &st);
        lua_pushnumber(L, st.st_size);
    }
The "lua_XXX" functions are from the Lua's C API; just think of them as simple output (e.g lua_pushstring() would be as printing elem->d_name). The code is of course missing many parts only related to Lua that I removed so it is clearer.

I gladly thank you for any help about this as it is a major bug in my project.

Re: stat() no working properly on another dir than the CWD

Posted: Thu Sep 05, 2013 11:11 pm
by WinterMute
If you want to use stat on files not in the current working directory you'll need to concatenate dirName & elem->d_name for the stat call. The function should be returning -1 assuming a file of the same name doesn't exist in the current directory.

S_ISDIR used to work, I'll have a look when I get time & see what's happened.

Re: stat() no working properly on another dir than the CWD

Posted: Fri Sep 06, 2013 3:48 pm
by mtheall
Well, here is something similar. Make sure you are checking for errors!

Code: Select all

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>

int myReaddir(const char *Path) {
  static char   path[PATH_MAX];
  struct dirent *dent;
  struct stat   st;
  DIR           *dp;
  char          *p, *end = path + PATH_MAX - 1;
  size_t        len = strlen(Path);

  if(Path[0] != '/') {
    /* a relative directory */
    if(getcwd(path, sizeof(path)) == NULL) {
      return 1;
    }
  }
  else if(len < PATH_MAX-1) {
    /* an absolute directory */
    strcpy(path, Path);
  }
  else {
    return 1;
  }

  /* this is where we append each entry's name to the path */
  p = path + len;

  /* make sure there's a trailing slash */
  if(p[-1] != '/') {
    if(p < end-1) {
      *p++ = '/';
      *p = 0;
    }
  }

  /* open the directory */
  dp = opendir(Path);
  if(dp == NULL) {
    return 1;
  }

  /* loop through each directory entry */
  while((dent = readdir(dp)) != NULL) {
    /* let's make sure the path + name fit */
    if(p + strlen(dent->d_name) < end) {
      /* append the name to the path */
      strcpy(p, dent->d_name);

      /* stat the path */
      if(stat(path, &st) != 0) {
        /* an error, do what you want */
      }
      else {
        /* everything successful for this entry */
        printf("%s\n", dent->d_name);
        printf("  Directory: %s\n", dent->d_type == DT_DIR ? "true" : "false");
        printf("  Size:      %zu\n", st.st_size);
      }
    }
    else {
      /* this name was too long, do what you want */
    }
  }

  closedir(dp);

  return 0;
}

int main(int argc, char *argv[]) {
  const char *path = argv[1];

  if(path != NULL)
    return myReaddir(path);
  else
    return 1;
}
Probably the reason S_ISDIR wasn't working and everything has the same size is because stat() is failing and st is not modified.

Re: stat() no working properly on another dir than the CWD

Posted: Fri Sep 06, 2013 4:50 pm
by Reylak
Whew I couldn't have guessed there were so many things to check and do before listing a folder ^^ Thank you for the code, I will test it and incorporate it as soon as possible.

According to what you said it seems logical that S_ISDIR is working and was failing because stat() couldn't operate properly.