1

I'm writing a little utility to scan through a directory tree recursively and record the tree structure with file names and sizes. (as fast as possible)

Perhaps I've coded myself into a corner. I can get a directory's contents with readdir(3) and treat regular files and directories separately.

I'm not seeing how to obtain the regular file's file size except by openat(), fstat(), close() calls.

Is there a way to get the file size more directly as I'm processing the directory entries? Perhaps from the inode number?

I was expecting this would exist: statat(int parentDirFD, const char * filename) since I only have the filename, not the file path.

I don't appear to have O_PATH support in my kernel.

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

DIR* p_dir = ...;

int dir_fd = dirfd(p_dir);


size_t get_file_size(const char * filename_only, int dir_fd, DIR* pdir )
{
  //// this just strikes me as overly expensive:
  int fd = openat(dir_fd, filename_only, O_RDONLY );
  struct stat sb;
  fstat( fd, &sb );
  size_t file_size = sb.st_size;
  close(fd);
  //////

  return file_size;
}
NoahR
  • 1,417
  • 3
  • 18
  • 33
  • 3
    The function that you expect to be called `statat` is actually called `fstatat`. It takes an extra flag argument to determine whether or not it has `lstat`-like behavior in case of a symlink. [POSIX spec](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html) [Linux man page](http://man7.org/linux/man-pages/man2/fstatat.2.html) –  Aug 04 '17 at 22:22
  • Oh my gosh. There it is! I guess I just overlooked it when looking at my goto web man page [fstat](https://linux.die.net/man/2/fstat). – NoahR Aug 04 '17 at 22:34

1 Answers1

0

Once Wumpus Q. Wumbley gave the answer in the comments, this turned out to be quite easy. fstatat()

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

DIR* p_dir = ...;

int dir_fd = dirfd(p_dir);


size_t get_file_size(const char * filename_only, int dir_fd )
{
  struct stat sb;
  int fstatat_flags = 0; //| AT_SYMLINK_NOFOLLOW
  int stat_res = fstatat( dir_fd, filename_only, &sb, fstatat_flags );
  size_t file_size = sb.st_size;

  return file_size;
}
NoahR
  • 1,417
  • 3
  • 18
  • 33
  • Out of curiosity, did you find any performance difference on your system between `fstatat` (and `openat` + `fdopendir` I suppose) and passing the full pathnames? I did a bit of tinkering myself a few years back hoping to shave off some cycles and recall being somewhat underwhelmed with the results. – doynax Aug 05 '17 at 07:34