From b821ea320164735dd6cc7ad9edaeaa1f558b676d Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Mon, 11 Dec 2006 21:46:33 -0800 Subject: [PATCH] More work on descending directory structure. Improvements: - Directory listings are processed in sorted order. - Open regular files, but be very paranoid in doing so (try to avoid danger from race conditions). --- scandir.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scandir.cc b/scandir.cc index 7e02f27..64aec8a 100644 --- a/scandir.cc +++ b/scandir.cc @@ -9,14 +9,30 @@ #include #include +#include #include +#include using std::string; +using std::vector; void scandir(const string& path); +void dumpfile(int fd) +{ + struct stat stat_buf; + fstat(fd, &stat_buf); + + if ((stat_buf.st_mode & S_IFMT) != S_IFREG) { + printf("file is no longer a regular file!\n"); + return; + } +} + void scanfile(const string& path) { + int fd; + long flags; struct stat stat_buf; lstat(path.c_str(), &stat_buf); @@ -36,6 +52,27 @@ void scanfile(const string& path) break; case S_IFREG: printf(" regular file\n"); + /* Be paranoid when opening the file. We have no guarantee that the + * file was not replaced between the stat() call above and the open() + * call below, so we might not even be opening a regular file. That + * the file descriptor refers to a regular file is checked in + * dumpfile(). But we also supply flags to open to to guard against + * various conditions before we can perform that verification: + * - O_NOFOLLOW: in the event the file was replaced by a symlink + * - O_NONBLOCK: prevents open() from blocking if the file was + * replaced by a fifo + * We also add in O_NOATIME, since this may reduce disk writes (for + * inode updates). */ + fd = open(path.c_str(), O_RDONLY|O_NOATIME|O_NOFOLLOW|O_NONBLOCK); + + /* Drop the use of the O_NONBLOCK flag; we only wanted that for file + * open. */ + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + + dumpfile(fd); + close(fd); + break; case S_IFDIR: printf(" directory\n"); @@ -56,10 +93,19 @@ void scandir(const string& path) } struct dirent *ent; + vector contents; while ((ent = readdir(dir)) != NULL) { string filename(ent->d_name); if (filename == "." || filename == "..") continue; + contents.push_back(filename); + } + + sort(contents.begin(), contents.end()); + + for (vector::iterator i = contents.begin(); + i != contents.end(); ++i) { + const string& filename = *i; printf(" d_name = '%s'\n", filename.c_str()); scanfile(path + "/" + filename); } -- 2.20.1