The Battle for Wesnoth  1.15.12+dev
filesystem.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Declarations for File-IO.
18  */
19 
20 #pragma once
21 
22 #include <ctime>
23 #include <fstream>
24 #include <iosfwd>
25 #include <memory>
26 #include <string>
27 #include <vector>
28 
29 #include "exceptions.hpp"
30 
31 class config;
32 class game_config_view;
33 struct SDL_RWops;
34 
35 namespace filesystem {
36 
37 using scoped_istream = std::unique_ptr<std::istream>;
38 using scoped_ostream = std::unique_ptr<std::ostream>;
39 
40 typedef std::unique_ptr<SDL_RWops, void(*)(SDL_RWops*)> rwops_ptr;
41 
42 rwops_ptr make_read_RWops(const std::string &path);
43 rwops_ptr make_write_RWops(const std::string &path);
44 
45 /** An exception object used when an IO error occurs */
46 struct io_exception : public game::error {
47  io_exception() : game::error("") {}
48  io_exception(const std::string& msg) : game::error(msg) {}
49 };
50 
51 struct file_tree_checksum;
52 
56 
57 // A list of file and directory blacklist patterns
59 {
60 public:
62  : file_patterns_(), directory_patterns_()
63  {}
64  blacklist_pattern_list(const std::vector<std::string>& file_patterns, const std::vector<std::string>& directory_patterns)
65  : file_patterns_(file_patterns), directory_patterns_(directory_patterns)
66  {}
67 
68  bool match_file(const std::string& name) const;
69 
70  bool match_dir(const std::string& name) const;
71 
72  void add_file_pattern(const std::string& pattern)
73  {
74  file_patterns_.push_back(pattern);
75  }
76 
77  void add_directory_pattern(const std::string& pattern)
78  {
79  directory_patterns_.push_back(pattern);
80  }
81 
82  void remove_blacklisted_files_and_dirs(std::vector<std::string>& files, std::vector<std::string>& directories) const;
83 
84 private:
85  std::vector<std::string> file_patterns_;
86  std::vector<std::string> directory_patterns_;
87 };
88 
90  {
91  /* Blacklist dot-files/dirs, which are hidden files in UNIX platforms */
92  ".+",
93  "#*#",
94  "*~",
95  "*-bak",
96  "*.swp",
97  "*.pbl",
98  "*.ign",
99  "_info.cfg",
100  "*.exe",
101  "*.bat",
102  "*.cmd",
103  "*.com",
104  "*.scr",
105  "*.sh",
106  "*.js",
107  "*.vbs",
108  "*.o",
109  "*.ini",
110  /* Remove junk created by certain file manager ;) */
111  "Thumbs.db",
112  /* Eclipse plugin */
113  "*.wesnoth",
114  "*.project",
115  },
116  {
117  ".+",
118  /* macOS metadata-like cruft (http://floatingsun.net/2007/02/07/whats-with-__macosx-in-zip-files/) */
119  "__MACOSX",
120  }
121 };
122 
123 /**
124  * Populates 'files' with all the files and
125  * 'dirs' with all the directories in dir.
126  * If files or dirs are nullptr they will not be used.
127  *
128  * mode: determines whether the entire path or just the filename is retrieved.
129  * filter: determines if we skip images and sounds directories
130  * reorder: triggers the special handling of _main.cfg and _final.cfg
131  * checksum: can be used to store checksum info
132  */
133 void get_files_in_dir(const std::string &dir,
134  std::vector<std::string>* files,
135  std::vector<std::string>* dirs=nullptr,
139  file_tree_checksum* checksum = nullptr);
140 
141 std::string get_dir(const std::string &dir);
142 
143 // The location of various important files:
144 std::string get_prefs_file();
145 std::string get_credentials_file();
146 std::string get_default_prefs_file();
147 std::string get_save_index_file();
148 std::string get_saves_dir();
149 std::string get_intl_dir();
150 std::string get_screenshot_dir();
151 std::string get_addons_dir();
152 
153 /**
154  * Get the next free filename using "name + number (3 digits) + extension"
155  * maximum 1000 files then start always giving 999
156  */
157 std::string get_next_filename(const std::string& name, const std::string& extension);
158 void set_user_config_dir(const std::string& path);
159 void set_user_data_dir(std::string path);
160 
161 std::string get_user_config_dir();
162 std::string get_user_data_dir();
163 std::string get_cache_dir();
164 
166 {
167  /**
168  * Here the version is given as a string instead of a version_info, because the
169  * logic of how many components are significant ("1.16" rather than
170  * "1.16.0") is encapsulated in find_other_version_saves_dirs().
171  */
172  std::string version;
173  std::string path;
174 
175  // constructor because emplace_back() doesn't use aggregate initialization
176  other_version_dir(const std::string& v, const std::string& p)
177  : version(v)
178  , path(p)
179  {
180  }
181 };
182 
183 /**
184  * Searches for directories containing saves created by other versions of Wesnoth.
185  *
186  * The directories returned will exist, but might not contain any saves. Changes to
187  * the filesystem (by running other versions or by deleting old directories) may
188  * change the results returned by the function.
189  */
190 std::vector<other_version_dir> find_other_version_saves_dirs();
191 
192 std::string get_cwd();
193 bool set_cwd(const std::string& dir);
194 
195 std::string get_exe_dir();
196 
197 bool make_directory(const std::string& dirname);
198 bool delete_directory(const std::string& dirname, const bool keep_pbl = false);
199 bool delete_file(const std::string& filename);
200 
201 bool looks_like_pbl(const std::string& file);
202 
203 // Basic disk I/O:
204 
205 /** Basic disk I/O - read file. */
206 std::string read_file(const std::string& fname);
207 filesystem::scoped_istream istream_file(const std::string& fname, bool treat_failure_as_error = true);
208 filesystem::scoped_ostream ostream_file(const std::string& fname, std::ios_base::openmode mode = std::ios_base::binary, bool create_directory = true);
209 /** Throws io_exception if an error occurs. */
210 void write_file(const std::string& fname, const std::string& data);
211 
212 std::string read_map(const std::string& name);
213 
214 /**
215  * Creates a directory if it does not exist already.
216  *
217  * @param dirname Path to directory. All parents should exist.
218  * @returns True if the directory exists or could be
219  * successfully created; false otherwise.
220  */
221 bool create_directory_if_missing(const std::string& dirname);
222 /**
223  * Creates a recursive directory tree if it does not exist already
224  * @param dirname Full path of target directory. Non existing parents
225  * will be created
226  * @return True if the directory exists or could be
227  * successfully created; false otherwise.
228  */
229 bool create_directory_if_missing_recursive(const std::string& dirname);
230 
231 /** Returns true if the given file is a directory. */
232 bool is_directory(const std::string& fname);
233 
234 /** Returns true if a file or directory with such name already exists. */
235 bool file_exists(const std::string& name);
236 
237 /** Get the modification time of a file. */
238 std::time_t file_modified_time(const std::string& fname);
239 
240 /** Returns true if the file ends with '.gz'. */
241 bool is_gzip_file(const std::string& filename);
242 
243 /** Returns true if the file ends with '.bz2'. */
244 bool is_bzip2_file(const std::string& filename);
245 
246 inline bool is_compressed_file(const std::string& filename) {
247  return is_gzip_file(filename) || is_bzip2_file(filename);
248 }
249 
250 /**
251  * Returns whether the given filename is a legal name for a user-created file.
252  *
253  * This is meant to be used for any files created by Wesnoth where user input
254  * is required, including save files and add-on files for uploading to the
255  * add-ons server.
256  *
257  * @param name File name to verify.
258  * @param allow_whitespace Whether whitespace should be allowed.
259  */
260 bool is_legal_user_file_name(const std::string& name, bool allow_whitespace = true);
261 
263 {
265  explicit file_tree_checksum(const config& cfg);
266  void write(config& cfg) const;
267  void reset() {nfiles = 0;modified = 0;sum_size=0;}
268  // @todo make variables private!
269  std::size_t nfiles, sum_size;
270  std::time_t modified;
271  bool operator==(const file_tree_checksum &rhs) const;
272  bool operator!=(const file_tree_checksum &rhs) const
273  { return !operator==(rhs); }
274 };
275 
276 /** Get the time at which the data/ tree was last modified at. */
277 const file_tree_checksum& data_tree_checksum(bool reset = false);
278 
279 /** Returns the size of a file, or -1 if the file doesn't exist. */
280 int file_size(const std::string& fname);
281 
282 /** Returns the sum of the sizes of the files contained in a directory. */
283 int dir_size(const std::string& path);
284 
285 bool ends_with(const std::string& str, const std::string& suffix);
286 
287 /**
288  * Returns the base filename of a file, with directory name stripped.
289  * Equivalent to a portable basename() function.
290  *
291  * If @a remove_extension is true, the filename extension will be stripped
292  * from the returned value.
293  */
294 std::string base_name(const std::string& file, const bool remove_extension = false);
295 
296 /**
297  * Returns the directory name of a file, with filename stripped.
298  * Equivalent to a portable dirname()
299  */
300 std::string directory_name(const std::string& file);
301 
302 /**
303  * Finds the nearest parent in existence for a file or directory.
304  *
305  * @note The file's own existence is not checked.
306  *
307  * @returns An absolute path to the closest parent of the given path, or an
308  * empty string if none could be found. While on POSIX platforms this
309  * cannot happen (unless the original path was already empty), on
310  * Windows it might be the case that the original path refers to a
311  * drive letter or network share that does not exist.
312  */
313 std::string nearest_extant_parent(const std::string& file);
314 
315 /**
316  * Returns the absolute path of a file.
317  *
318  * @param path Original path.
319  * @param normalize_separators Whether to substitute path separators with the
320  * platform's preferred format.
321  * @param resolve_dot_entries Whether to resolve . and .. directory entries.
322  * This requires @a path to refer to a valid
323  * existing object.
324  *
325  * @returns An absolute path -- that is, a path that is independent of the
326  * current working directory for the process. If resolve_dot_entries
327  * is set to true, the returned path has . and .. components resolved;
328  * however, if resolution fails because a component does not exist, an
329  * empty string is returned instead.
330  */
331 std::string normalize_path(const std::string& path,
332  bool normalize_separators = false,
333  bool resolve_dot_entries = false);
334 
335 /**
336  * Sanitizes a path to remove references to the user's name.
337  */
338 std::string sanitize_path(const std::string& path);
339 
340 /**
341  * Returns whether the path is the root of the file hierarchy.
342  *
343  * @note This function is unreliable for paths that do not exist -- it will
344  * always return @a false for those.
345  */
346 bool is_root(const std::string& path);
347 
348 /**
349  * Returns the name of the root device if included in the given path.
350  *
351  * This only properly makes sense on Windows with paths containing a drive
352  * letter or UNC at the start -- otherwise, it will return the empty string. To
353  * ensure that a suitable root name can be found you might want to use
354  * normalize_path() first with @a resolve_dot_entries set to true.
355  */
356 std::string root_name(const std::string& path);
357 
358 /**
359  * Returns whether the path seems to be relative.
360  */
361 bool is_relative(const std::string& path);
362 
363 /**
364  * Returns whether @a c is a path separator.
365  *
366  * @note / is always a path separator. Additionally, on Windows \\ is a
367  * path separator as well.
368  */
369 bool is_path_sep(char c);
370 
371 /**
372  * Returns the standard path separator for the current platform.
373  */
374 char path_separator();
375 
376 /**
377  * The paths manager is responsible for recording the various paths
378  * that binary files may be located at.
379  * It should be passed a config object which holds binary path information.
380  * This is in the format
381  *@verbatim
382  * [binary_path]
383  * path=<path>
384  * [/binary_path]
385  * Binaries will be searched for in [wesnoth-path]/data/<path>/images/
386  *@endverbatim
387  */
389 {
393 
394  void set_paths(const game_config_view& cfg);
395 
396 private:
398  binary_paths_manager& operator=(const binary_paths_manager& o);
399 
400  void cleanup();
401 
402  std::vector<std::string> paths_;
403 };
404 
406 
407 /**
408  * Returns a vector with all possible paths to a given type of binary,
409  * e.g. 'images', 'sounds', etc,
410  */
411 const std::vector<std::string>& get_binary_paths(const std::string& type);
412 
413 /**
414  * Returns a complete path to the actual file of a given @a type
415  * or an empty string if the file isn't present.
416  */
417 std::string get_binary_file_location(const std::string& type, const std::string& filename);
418 
419 /**
420  * Returns a complete path to the actual directory of a given @a type
421  * or an empty string if the directory isn't present.
422  */
423 std::string get_binary_dir_location(const std::string &type, const std::string &filename);
424 
425 /**
426  * Returns a complete path to the actual WML file or directory
427  * or an empty string if the file isn't present.
428  */
429 std::string get_wml_location(const std::string &filename,
430  const std::string &current_dir = std::string());
431 
432 /**
433  * Returns a short path to @a filename, skipping the (user) data directory.
434  */
435 std::string get_short_wml_path(const std::string &filename);
436 
437 /**
438  * Returns an image path to @a filename for binary path-independent use in saved games.
439  *
440  * Example:
441  * units/konrad-fighter.png ->
442  * data/campaigns/Heir_To_The_Throne/images/units/konrad-fighter.png
443  */
444 std::string get_independent_image_path(const std::string &filename);
445 
446 /**
447  * Returns the appropriate invocation for a Wesnoth-related binary, assuming
448  * that it is located in the same directory as the running wesnoth binary.
449  * This is just a string-transformation based on argv[0], so the returned
450  * program is not guaranteed to actually exist. '-debug' variants are handled
451  * correctly.
452  */
453 std::string get_program_invocation(const std::string &program_name);
454 
455 /**
456  * Returns the localized version of the given filename, if it exists.
457  */
458 std::string get_localized_path(const std::string& file, const std::string& suff = "");
459 
460 }
std::string get_binary_dir_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual directory of a given type or an empty string if the directory i...
bool delete_directory(const std::string &dirname, const bool keep_pbl)
Definition: filesystem.cpp:945
std::string get_program_invocation(const std::string &program_name)
Returns the appropriate invocation for a Wesnoth-related binary, assuming that it is located in the s...
bool is_legal_user_file_name(const std::string &name, bool allow_whitespace=true)
Returns whether the given filename is a legal name for a user-created file.
std::string get_next_filename(const std::string &name, const std::string &extension)
Get the next free filename using "name + number (3 digits) + extension" maximum 1000 files then start...
Definition: filesystem.cpp:490
bool delete_file(const std::string &filename)
Definition: filesystem.cpp:984
static bool create_directory_if_missing(const bfs::path &dirpath)
Definition: filesystem.cpp:297
bool looks_like_pbl(const std::string &file)
void add_directory_pattern(const std::string &pattern)
Definition: filesystem.hpp:77
void set_user_data_dir(std::string newprefdir)
Definition: filesystem.cpp:608
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:263
bool ends_with(const std::string &str, const std::string &suffix)
rwops_ptr make_read_RWops(const std::string &path)
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
The paths manager is responsible for recording the various paths that binary files may be located at...
Definition: filesystem.hpp:388
std::string version
Here the version is given as a string instead of a version_info, because the logic of how many compon...
Definition: filesystem.hpp:172
other_version_dir(const std::string &v, const std::string &p)
Definition: filesystem.hpp:176
std::string get_screenshot_dir()
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn&#39;t prese...
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
std::string get_saves_dir()
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
static bfs::path get_dir(const bfs::path &dirpath)
Definition: filesystem.cpp:274
io_exception(const std::string &msg)
Definition: filesystem.hpp:48
void clear_binary_paths_cache()
std::string get_cwd()
Definition: filesystem.cpp:876
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:763
rwops_ptr make_write_RWops(const std::string &path)
std::string get_user_data_dir()
Definition: filesystem.cpp:789
std::vector< std::string > directory_patterns_
Definition: filesystem.hpp:86
std::string get_intl_dir()
void write_file(const std::string &fname, const std::string &data)
Throws io_exception if an error occurs.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
Definition: filesystem.cpp:349
std::string root_name(const std::string &path)
Returns the name of the root device if included in the given path.
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:37
std::string path
Definition: game_config.cpp:38
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::string get_independent_image_path(const std::string &filename)
Returns an image path to filename for binary path-independent use in saved games. ...
std::vector< std::string > file_patterns_
Definition: filesystem.hpp:85
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user&#39;s name.
std::string get_default_prefs_file()
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
Definition: filesystem.cpp:995
void add_file_pattern(const std::string &pattern)
Definition: filesystem.hpp:72
std::string read_map(const std::string &name)
bool is_path_sep(char c)
Returns whether c is a path separator.
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:38
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with &#39;.gz&#39;.
std::string get_cache_dir()
Definition: filesystem.cpp:794
const std::vector< std::string > & get_binary_paths(const std::string &type)
Returns a vector with all possible paths to a given type of binary, e.g.
std::string get_exe_dir()
Definition: filesystem.cpp:904
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
void set_user_config_dir(const std::string &newconfigdir)
Definition: filesystem.cpp:746
int dir_size(const std::string &pname)
Returns the sum of the sizes of the files contained in a directory.
std::string get_wml_location(const std::string &filename, const std::string &current_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn&#39;t pres...
std::vector< std::string > paths_
Definition: filesystem.hpp:402
mock_party p
An exception object used when an IO error occurs.
Definition: filesystem.hpp:46
bool operator==(const config &a, const config &b)
Definition: config.cpp:1450
bool make_directory(const std::string &dirname)
Definition: filesystem.cpp:934
bool is_compressed_file(const std::string &filename)
Definition: filesystem.hpp:246
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
std::unique_ptr< SDL_RWops, void(*)(SDL_RWops *)> rwops_ptr
Definition: filesystem.hpp:40
std::string get_localized_path(const std::string &file, const std::string &suff)
Returns the localized version of the given filename, if it exists.
const file_tree_checksum & data_tree_checksum(bool reset=false)
Get the time at which the data/ tree was last modified at.
char path_separator()
Returns the standard path separator for the current platform.
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
int file_size(const std::string &fname)
Returns the size of a file, or -1 if the file doesn&#39;t exist.
bool set_cwd(const std::string &dir)
Definition: filesystem.cpp:889
std::string get_user_config_dir()
Definition: filesystem.cpp:760
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with &#39;.bz2&#39;.
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:27
std::string get_addons_dir()
std::string get_credentials_file()
bool operator!=(const file_tree_checksum &rhs) const
Definition: filesystem.hpp:272
blacklist_pattern_list(const std::vector< std::string > &file_patterns, const std::vector< std::string > &directory_patterns)
Definition: filesystem.hpp:64
std::vector< other_version_dir > find_other_version_saves_dirs()
Searches for directories containing saves created by other versions of Wesnoth.
Definition: filesystem.cpp:823
std::string get_prefs_file()
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
std::string get_save_index_file()
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
static bool create_directory_if_missing_recursive(const bfs::path &dirpath)
Definition: filesystem.cpp:321
static const blacklist_pattern_list default_blacklist
Definition: filesystem.hpp:89