1 #ifndef LIBFILEZILLA_LOCAL_FILESYS_HEADER
2 #define LIBFILEZILLA_LOCAL_FILESYS_HEADER
3 
4 #include "libfilezilla.hpp"
5 #include "time.hpp"
6 
7 #ifdef FZ_WINDOWS
8 #include "glue/windows.hpp"
9 #else
10 #include <dirent.h>
11 #endif
12 
13 /** \file
14  * \brief Declares local_filesys class to enumerate local files and query their metadata such as type, size and modification time.
15  */
16 namespace fz {
17 
18 /**
19  * \brief Small class to return filesystem errors
20  */
21 class FZ_PUBLIC_SYMBOL result final
22 {
23 public:
24 	enum error {
25 		ok,
26 
27 		/// Permission denied
28 		noperm,
29 
30 		/// Requested file does not exist or is not a file
31 		nofile,
32 
33 		/// Requested dir does not exist or is not a dir
34 		nodir,
35 
36 		/// Out of disk space
37 		nospace,
38 
39 		/// Some other error
40 		other
41 	};
42 
operator bool() const43 	explicit operator bool() const { return error_ == 0; }
44 
45 	error error_{};
46 };
47 
48 /**
49  * \brief This class can be used to enumerate the contents of local directories and to query
50  * the metadata of files.
51  *
52  * This class is aware of symbolic links. Under Windows it can handle reparse points as well.
53  */
54 class FZ_PUBLIC_SYMBOL local_filesys final
55 {
56 public:
57 	local_filesys() = default;
58 	~local_filesys();
59 
60 	local_filesys(local_filesys const&) = delete;
61 	local_filesys& operator=(local_filesys const&) = delete;
62 
63 	/// Types of files. While 'everything is a file', a filename can refer to a file proper, a directory or a symbolic link.
64 	enum type {
65 		unknown = -1,
66 		file,
67 		dir,
68 		link
69 	};
70 
71 	/// The system's preferred path separator
72 	static char const path_separator;
73 
74 	/// \brief Checks whether given character is a path separator.
75 	///
76 	/// On most systems, the forward slash is the only separator. The exception is Windows where both forward and backward slashes are separators, with the latter being preferred.
is_separator(wchar_t c)77 	static inline bool is_separator(wchar_t c) {
78 #ifdef FZ_WINDOWS
79 		return c == '/' || c == '\\';
80 #else
81 		return c == '/';
82 #endif
83 	}
84 
85 	/// \brief get_file_type return the type of the passed path.
86 	///
87 	/// Can optionally follow symbolic links.
88 	static type get_file_type(native_string const& path, bool follow_links = false);
89 
90 	/**
91 	 * \brief Gets the info for the passed arguments.
92 	 *
93 	 * Follows symbolic links and stats the target by default, sets is_link to true if path was
94 	 * a link.
95 	 *
96 	 * The returned type can only be \c type::link if \c follow_links is \c false.
97 	 */
98 	static type get_file_info(native_string const& path, bool &is_link, int64_t* size, datetime* modification_time, int* mode, bool follow_links = true);
99 
100 	/// Gets size of file, returns -1 on error.
101 	static int64_t get_size(native_string const& path, bool *is_link = nullptr);
102 
103 	/// \brief Begins enumerating a directory.
104 	///
105 	/// \param dirs_only If true, only directories are enumerated.
106 	result begin_find_files(native_string path, bool dirs_only = false);
107 
108 	/// Gets the next file in the directory. Call until it returns false.
109 	bool get_next_file(native_string& name);
110 
111 	/**
112 	 * \brief Gets the next file in the directory. Call until it returns false.
113 	 *
114 	 * Stores the metadata in any non-null arguments. Follows symbolic links.
115 	 *
116 	 * \param is_link will be set to true iff file is a symbolic link.
117 	 * \param t will receive the type of file, after following any symbolic links. Cannot return \c type::link.
118 	 *
119 	 */
120 	bool get_next_file(native_string& name, bool &is_link, type & t, int64_t* size, datetime* modification_time, int* mode);
121 
122 	/// Ends enumerating files. Automatically called in the destructor.
123 	void end_find_files();
124 
125 	static datetime get_modification_time(native_string const& path);
126 	static bool set_modification_time(native_string const& path, const datetime& t);
127 
128 	/// Get the target path of a symbolic link
129 	static native_string get_link_target(native_string const& path);
130 
131 private:
132 
133 #ifdef FZ_WINDOWS
134 	WIN32_FIND_DATA m_find_data{};
135 	HANDLE m_hFind{INVALID_HANDLE_VALUE};
136 	native_string m_find_path;
137 	bool has_next_{};
138 #else
139 	DIR* dir_{};
140 #endif
141 
142 	// State for directory enumeration
143 	bool dirs_only_{};
144 };
145 
146 enum class mkdir_permissions
147 {
148 	/// Normal permissions, on MSW this means inheriting the parent's permissions,
149 	/// on *nix the current umask is applied.
150 	normal,
151 
152 	/// Only current user
153 	cur_user,
154 
155 	/// Only current user and administrators
156 	cur_user_and_admins
157 };
158 
159 /**
160  * \brief Creates directory if it doesn't yet exist.
161  *
162  * If current_user_only is set, the directory is created with
163  * permissions so that only the current user has access, otherwise
164  * the default permissions are used.
165  *
166  * This function only works with absolute paths.
167  *
168  * \param absolute_path The directory to create
169  * \param recurse If true, creation is recursive. If false, only the last segment gets
170  *                created, all other components already need to exist.
171  * \param permissions When creating the last component, these permissions are applied.
172  *                    Does not change existing permissions or permissings of newly
173  *                    created parent directories during recursive mkdir.
174  * \param last_created If non-null, receives the longest sub-path that was created
175  */
176 result FZ_PUBLIC_SYMBOL mkdir(native_string const& absolute_path, bool recurse, mkdir_permissions permissions = mkdir_permissions::normal, native_string * last_created = nullptr);
177 
178 /**
179  * \brief Rename/move the passed file or directory
180  *
181  * Can rename both files and directories within same filesystem. Can
182  * optionally rename files across filesystems
183  *
184  * If renaming a file, the target file is overwritten.
185  *
186  * Directories cannot be renamed/moved across differnet filesystems/mount points
187  *
188  * param allow_copy If true, files, but not directories, can be moved across
189  *                  file system boundaries. It first copies the file before
190  *                  deleting the old one.
191  */
192 result FZ_PUBLIC_SYMBOL rename_file(native_string const& source, native_string const& dest, bool allow_copy = true);
193 
194 }
195 
196 #endif
197