From 75eb41f5ad044792fd4bdafef5c25d211349648f Mon Sep 17 00:00:00 2001
From: patrick96 <p.ziegler96@gmail.com>
Date: Wed, 25 Nov 2020 01:35:38 +0100
Subject: [PATCH] config: Better error messages when opening files

If a config file is a directory, ifstream would just read it as an empty
file without any errors.

Failing early here is a good idea.
---
 include/components/config_parser.hpp |  2 --
 include/utils/file.hpp               |  1 +
 src/components/config_parser.cpp     | 13 +++++++++++++
 src/utils/file.cpp                   | 17 +++++++++++++++++
 4 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/include/components/config_parser.hpp b/include/components/config_parser.hpp
index 0f5dc096..68f343a8 100644
--- a/include/components/config_parser.hpp
+++ b/include/components/config_parser.hpp
@@ -6,8 +6,6 @@
 #include "components/config.hpp"
 #include "components/logger.hpp"
 #include "errors.hpp"
-#include "utils/file.hpp"
-#include "utils/string.hpp"
 
 POLYBAR_NS
 
diff --git a/include/utils/file.hpp b/include/utils/file.hpp
index 3949e2b8..ba165959 100644
--- a/include/utils/file.hpp
+++ b/include/utils/file.hpp
@@ -102,6 +102,7 @@ class fd_stream : public StreamType {
 
 namespace file_util {
   bool exists(const string& filename);
+  bool is_file(const string& filename);
   string pick(const vector<string>& filenames);
   string contents(const string& filename);
   void write_contents(const string& filename, const string& contents);
diff --git a/src/components/config_parser.cpp b/src/components/config_parser.cpp
index b422584e..dca093ea 100644
--- a/src/components/config_parser.cpp
+++ b/src/components/config_parser.cpp
@@ -1,8 +1,13 @@
 #include "components/config_parser.hpp"
 
 #include <algorithm>
+#include <cerrno>
+#include <cstring>
 #include <fstream>
 
+#include "utils/file.hpp"
+#include "utils/string.hpp"
+
 POLYBAR_NS
 
 config_parser::config_parser(const logger& logger, string&& file, string&& bar)
@@ -89,6 +94,14 @@ void config_parser::parse_file(const string& file, file_list path) {
     throw application_error("include-file: Dependency cycle detected:\n" + path_str);
   }
 
+  if (!file_util::exists(file)) {
+    throw application_error("Failed to open config file " + file + ": " + strerror(errno));
+  }
+
+  if (!file_util::is_file(file)) {
+    throw application_error("Config file " + file + " is not a file");
+  }
+
   m_log.trace("config_parser: Parsing %s", file);
 
   int file_index;
diff --git a/src/utils/file.cpp b/src/utils/file.cpp
index 0a4c6955..756d057d 100644
--- a/src/utils/file.cpp
+++ b/src/utils/file.cpp
@@ -170,12 +170,29 @@ int fd_streambuf::underflow() {
 namespace file_util {
   /**
    * Checks if the given file exist
+   *
+   * May also return false if the file status  cannot be read
+   *
+   * Sets errno when returning false
    */
   bool exists(const string& filename) {
     struct stat buffer {};
     return stat(filename.c_str(), &buffer) == 0;
   }
 
+  /**
+   * Checks if the given path exists and is a file
+   */
+  bool is_file(const string& filename) {
+    struct stat buffer {};
+
+    if (stat(filename.c_str(), &buffer) != 0) {
+      return false;
+    }
+
+    return S_ISREG(buffer.st_mode);
+  }
+
   /**
    * Picks the first existing file out of given entries
    */