+ metawriter->add(file_info);
+}
+
+void scanfile(const string& path, bool include)
+{
+ int fd = -1;
+ long flags;
+ struct stat stat_buf;
+ list<string> refs;
+
+ string true_path;
+ if (relative_paths)
+ true_path = path;
+ else
+ true_path = "/" + path;
+
+ // Set to true if we should scan through the contents of this directory,
+ // but not actually back files up
+ bool scan_only = false;
+
+ // Check this file against the include/exclude list to see if it should be
+ // considered
+ for (list<string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ if (path == *i) {
+ include = true;
+ }
+ }
+
+ for (list<string>::iterator i = excludes.begin();
+ i != excludes.end(); ++i) {
+ if (path == *i) {
+ include = false;
+ }
+ }
+
+ if (excluded_names.size() > 0) {
+ std::string name = path;
+ std::string::size_type last_slash = name.rfind('/');
+ if (last_slash != std::string::npos) {
+ name.replace(0, last_slash + 1, "");
+ }
+
+ for (list<string>::iterator i = excluded_names.begin();
+ i != excluded_names.end(); ++i) {
+ if (name == *i) {
+ include = false;
+ }
+ }
+ }
+
+ for (list<string>::iterator i = searches.begin();
+ i != searches.end(); ++i) {
+ if (path == *i) {
+ scan_only = true;
+ }
+ }
+
+ if (!include && !scan_only)
+ return;
+
+ if (lstat(true_path.c_str(), &stat_buf) < 0) {
+ fprintf(stderr, "lstat(%s): %m\n", path.c_str());
+ return;
+ }
+
+ if ((stat_buf.st_mode & S_IFMT) == S_IFREG) {
+ /* 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. We
+ * supply flags to open to to guard against various conditions before
+ * we can perform an lstat to check that the file is still a regular
+ * file:
+ * - 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). However, O_NOATIME may result in EPERM, so if the
+ * initial open fails, try again without O_NOATIME. */
+ fd = open(true_path.c_str(), O_RDONLY|O_NOATIME|O_NOFOLLOW|O_NONBLOCK);
+ if (fd < 0) {
+ fd = open(true_path.c_str(), O_RDONLY|O_NOFOLLOW|O_NONBLOCK);
+ }
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open file %s: %m\n", path.c_str());
+ return;
+ }
+
+ /* 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);
+
+ /* Perform the stat call again, and check that we still have a regular
+ * file. */
+ if (fstat(fd, &stat_buf) < 0) {
+ fprintf(stderr, "fstat: %m\n");
+ close(fd);
+ return;
+ }
+
+ if ((stat_buf.st_mode & S_IFMT) != S_IFREG) {
+ fprintf(stderr, "file is no longer a regular file!\n");
+ close(fd);
+ return;
+ }
+ }
+
+ dump_inode(path, true_path, stat_buf, fd);