summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/files.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-26 15:30:07 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-26 15:30:07 +0000
commita844f8e10213c19b6e48d6ff98e97bc9f026a42a (patch)
tree9cada2344ca78a2c2de555dc8b7fa943ee7382fe /crawl-ref/source/files.cc
parent1f1939b11a6ed95f769644c21e53589a1e7abeb9 (diff)
downloadcrawl-ref-a844f8e10213c19b6e48d6ff98e97bc9f026a42a.tar.gz
crawl-ref-a844f8e10213c19b6e48d6ff98e97bc9f026a42a.zip
Better support for settings files that include other files:
- Files can be included as "include foo" in .crawlrc instead of using the Lua call: : crawl.read_options('foo'). include foo and the Lua crawl.read_options('foo') are not equivalent - Lua only runs after the start of a new game, which is too late for some option settings. - Crawl searches for included files in this sequence: - Absolute paths: use the path directly (but not if DATA_DIR_PATH is set, since we don't want Crawl to read arbitrary files on multiuser systems). - Search relative to the including file. - Search relative to any -rcdir(s) provided. - Search in the data file search path. - The data file search path now includes settings/ for when we move rc stuff to settings/ .gitignore: ignore saves and morgue dirs correctly. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5256 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/files.cc')
-rw-r--r--crawl-ref/source/files.cc108
1 files changed, 99 insertions, 9 deletions
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index fe2a654037..02ddf79278 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -281,6 +281,44 @@ std::string get_base_filename(const std::string &filename)
return (filename);
}
+bool is_absolute_path(const std::string &path)
+{
+ return (!path.empty()
+ && (path[0] == FILE_SEPARATOR
+#if defined(WIN32CONSOLE) || defined(WIN32TILES)
+ || path.find(':') != std::string::npos
+#endif
+ ));
+}
+
+// Concatenates two paths, separating them with FILE_SEPARATOR if necessary.
+// Assumes that the second path is not absolute.
+//
+// If the first path is empty, returns the second unchanged. The second path
+// may be absolute in this case.
+std::string catpath(const std::string &first, const std::string &second)
+{
+ if (first.empty())
+ return (second);
+
+ std::string directory = first;
+ if (directory[directory.length() - 1] != FILE_SEPARATOR)
+ directory += FILE_SEPARATOR;
+ directory += second;
+
+ return (directory);
+}
+
+// Given a relative path and a reference file name, returns the relative path
+// suffixed to the directory containing the reference file name. Assumes that
+// the second path is not absolute.
+std::string get_path_relative_to(const std::string &referencefile,
+ const std::string &relativepath)
+{
+ return catpath(get_parent_directory(referencefile),
+ relativepath);
+}
+
std::string change_file_extension(const std::string &filename,
const std::string &ext)
{
@@ -312,7 +350,7 @@ void check_newer(const std::string &target,
action();
}
-static bool file_exists(const std::string &name)
+bool file_exists(const std::string &name)
{
#ifdef HAVE_STAT
struct stat st;
@@ -328,12 +366,16 @@ static bool file_exists(const std::string &name)
}
// Low-tech existence check.
-static bool dir_exists(const std::string &dir)
+bool dir_exists(const std::string &dir)
{
#ifdef _MSC_VER
DWORD lAttr = GetFileAttributes(dir.c_str());
return (lAttr != INVALID_FILE_ATTRIBUTES
&& (lAttr & FILE_ATTRIBUTE_DIRECTORY));
+#elif defined(HAVE_STAT)
+ struct stat st;
+ const int err = ::stat(dir.c_str(), &st);
+ return (!err && S_ISDIR(st.st_mode));
#else
DIR *d = opendir(dir.c_str());
const bool exists = !!d;
@@ -385,36 +427,84 @@ static bool create_dirs(const std::string &dir)
return (true);
}
+// Checks whether the given path is safe to read from. A path is safe if:
+// 1. If Unix: It contains no shell metacharacters.
+// 2. If DATA_DIR_PATH is set: the path is not an absolute path.
+// 3. If DATA_DIR_PATH is set: the path contains no ".." sequence.
+void assert_read_safe_path(const std::string &path) throw (std::string)
+{
+ // Check for rank tomfoolery first:
+ if (path.empty())
+ throw "Empty file name.";
+
+#ifdef UNIX
+ if (!shell_safe(path.c_str()))
+ throw make_stringf("\"%s\" contains bad characters.",
+ path.c_str());
+#endif
+
+#ifdef DATA_DIR_PATH
+ if (is_absolute_path(path))
+ throw make_stringf("\"%s\" is an absolute path.", path.c_str());
+
+ if (path.find("..") != std::string::npos)
+ throw make_stringf("\"%s\" contains \"..\" sequences.",
+ path.c_str());
+#endif
+
+ // Path is okay.
+}
+
+bool is_read_safe_path(const std::string &path)
+{
+ try
+ {
+ assert_read_safe_path(path);
+ }
+ catch (const std::string &err)
+ {
+ return (false);
+ }
+ return (true);
+}
+
+std::string canonicalise_file_separator(const std::string &path)
+{
+#if FILE_SEPARATOR != '/'
+ return (replace_all_of(path, "/", std::string(1, FILE_SEPARATOR)));
+#else
+ // No action needed here.
+ return (path);
+#endif
+}
+
std::string datafile_path(std::string basename,
bool croak_on_fail,
bool test_base_path)
{
-#if FILE_SEPARATOR != '/'
- basename = replace_all_of(basename, "/", std::string(1, FILE_SEPARATOR));
-#endif
+ basename = canonicalise_file_separator(basename);
if (test_base_path && file_exists(basename))
return (basename);
- std::string cdir = !SysEnv.crawl_dir.empty()? SysEnv.crawl_dir : "";
-
const std::string rawbases[] = {
#ifdef DATA_DIR_PATH
DATA_DIR_PATH,
#else
- cdir,
+ !SysEnv.crawl_dir.empty()? SysEnv.crawl_dir : "",
#endif
};
const std::string prefixes[] = {
std::string("dat") + FILE_SEPARATOR,
std::string("docs") + FILE_SEPARATOR,
+ std::string("settings") + FILE_SEPARATOR,
#ifndef DATA_DIR_PATH
std::string("..") + FILE_SEPARATOR + "docs" + FILE_SEPARATOR,
std::string("..") + FILE_SEPARATOR + "dat" + FILE_SEPARATOR,
+ std::string("..") + FILE_SEPARATOR + "settings" + FILE_SEPARATOR,
std::string("..") + FILE_SEPARATOR,
#endif
- std::string(".") + FILE_SEPARATOR,
"",
};