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