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