| 1 | /* |
| 2 | This software is a contribution of the LiMux project of the city of Munich. |
| 3 | SPDX-FileCopyrightText: 2021 Robert Hoffmann <robert@roberthoffmann.de> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 6 | */ |
| 7 | #ifndef KNETWORKMOUNTS_H |
| 8 | #define KNETWORKMOUNTS_H |
| 9 | |
| 10 | #include <memory> |
| 11 | |
| 12 | #include <QObject> |
| 13 | #include <kcoreaddons_export.h> |
| 14 | |
| 15 | /*! |
| 16 | * \class KNetworkMounts |
| 17 | * \inmodule KCoreAddons |
| 18 | * |
| 19 | * Performance control on network mounts. |
| 20 | * |
| 21 | * This class provides methods for deciding whether operations |
| 22 | * on slow network mounts should be performed or not. |
| 23 | * |
| 24 | * Configuration is read from a configuration file network_mounts in |
| 25 | * the user's QStandardPaths::ConfigLocation. This file can be filled by using |
| 26 | * the network mounts performance configuration module or directly via setEnabled, |
| 27 | * setPaths, addPath and setOption |
| 28 | * \code |
| 29 | * KNetworkMounts::self()->setEnabled(true); |
| 30 | * KNetworkMounts::self()->setOption(KNetworkMounts::LowSideEffectsOptimizations, true); |
| 31 | * KNetworkMounts::self()->addPath(path1, KNetworkMounts::NfsPaths); |
| 32 | * KNetworkMounts::self()->addPath(path2, KNetworkMounts::NfsPaths); |
| 33 | * KNetworkMounts::self()->setPaths(listOfPaths, KNetworkMounts::SmbPaths); |
| 34 | * \endcode |
| 35 | * |
| 36 | * Use KNetworkMounts like this to check if the given url is on a |
| 37 | * configured slow path and the KNetworkMountOption LowSideEffectsOptimizations |
| 38 | * is enabled: |
| 39 | * \code |
| 40 | * if (KNetworkMounts::self()->isOptionEnabledForPath(url.toLocalFile(), |
| 41 | * KNetworkMounts::LowSideEffectsOptimizations)) |
| 42 | * { |
| 43 | * // skip operations which are slow on the given url if |
| 44 | * // KNetworkMountOption LowSideEffectsOptimizations is enabled |
| 45 | * } else { |
| 46 | * // given url is not configured being slow or the KNetworkMountOption |
| 47 | * // LowSideEffectsOptimizations is not enabled |
| 48 | * } |
| 49 | * \endcode |
| 50 | * |
| 51 | * If called for the first time, this creates a singleton instance and reads |
| 52 | * the config file. Subsequent calls just use this instance without reading |
| 53 | * the config file again. |
| 54 | * |
| 55 | * \since 5.85 |
| 56 | **/ |
| 57 | class KCOREADDONS_EXPORT KNetworkMounts : public QObject |
| 58 | { |
| 59 | Q_OBJECT |
| 60 | |
| 61 | public: |
| 62 | /*! |
| 63 | * Returns (and creates if necessary) the singleton instance |
| 64 | */ |
| 65 | static KNetworkMounts *self(); |
| 66 | |
| 67 | /*! |
| 68 | * The KNetworkMountOption enum |
| 69 | * |
| 70 | * \value LowSideEffectsOptimizations |
| 71 | * Don't run KDiskFreeSpaceInfo if slow path. |
| 72 | * Don't check for manually mounted drives. |
| 73 | * Don't check with QFileInfo::isWritable if it is writable, if not yet known, return true. |
| 74 | * Don't check with QFileInfo::isReadable if it is readable, return false. |
| 75 | * Don't check for desktop files just return false. |
| 76 | * Ignore .hidden files on slow paths. |
| 77 | * Don't read mime comment from .desktop or .directory files. |
| 78 | * Don't get the size with QFileInfo::size, just return 0, if not yet known. |
| 79 | * Don't determine mime type from file content, use file extension. |
| 80 | * Don't check for desktop files just return false. |
| 81 | * Don't call KFileSystemType::fileSystemType to check if the filesystem is slow, just return true. |
| 82 | * Don't count files/directories in subdirectories. |
| 83 | * Don't calculate sizes of subdirectories. |
| 84 | * Avoid check for dir at Kate startup. |
| 85 | * \value MediumSideEffectsOptimizations |
| 86 | * Don't return project for dir, avoid QFileInfo().absoluteDir(). |
| 87 | * Don't search for .kateconfig recursively |
| 88 | * Ignore recent files on slow paths |
| 89 | * \value StrongSideEffectsOptimizations |
| 90 | * Turn off symbolic link resolution |
| 91 | * \value KDirWatchDontAddWatches |
| 92 | * Disables dir watching completely for slow paths, avoids stat() calls on added dirs and subdirs |
| 93 | * \value SymlinkPathsUseCache |
| 94 | * Cache resolved symlink paths |
| 95 | */ |
| 96 | enum KNetworkMountOption { |
| 97 | LowSideEffectsOptimizations, |
| 98 | MediumSideEffectsOptimizations, |
| 99 | StrongSideEffectsOptimizations, |
| 100 | KDirWatchDontAddWatches, |
| 101 | SymlinkPathsUseCache |
| 102 | }; |
| 103 | Q_ENUM(KNetworkMountOption) |
| 104 | |
| 105 | /*! |
| 106 | * The KNetworkMountsType enum |
| 107 | * |
| 108 | * \value NfsPaths NFS paths |
| 109 | * \value SmbPaths SMB paths |
| 110 | * \value SymlinkDirectory Paths to directories which contain symbolic links to network mounts |
| 111 | * \value SymlinkToNetworkMount Paths which are symbolic links to network mounts |
| 112 | * \value Any Any slow path type. Do not use with setPaths or addPath |
| 113 | */ |
| 114 | enum KNetworkMountsType { NfsPaths, SmbPaths, SymlinkDirectory, SymlinkToNetworkMount, Any }; |
| 115 | Q_ENUM(KNetworkMountsType) |
| 116 | |
| 117 | /*! |
| 118 | * Query if \a path is configured to be a slow path of type \a type |
| 119 | * |
| 120 | * \a path the path to query |
| 121 | * |
| 122 | * \a type the type to query. If omitted, any type matches |
| 123 | * |
| 124 | * Returns \c true if \a path is a configured slow path of type \a type |
| 125 | * |
| 126 | * This function is also used to determine the filesystem type in KFileSystemType::fileSystemType |
| 127 | * (KFileSystemType::Smb or KFileSystemType::Nfs) without an expensive call to stafs(). For this |
| 128 | * to work the types of paths need to be correctly assigned in setPath or addPath |
| 129 | */ |
| 130 | bool isSlowPath(const QString &path, KNetworkMountsType type = Any); |
| 131 | |
| 132 | /*! |
| 133 | * Query if \a path is configured to be a slow path and \a option is enabled |
| 134 | * |
| 135 | * \a path the path to query |
| 136 | * |
| 137 | * \a option the option to query |
| 138 | * |
| 139 | * Returns \c true if \a path is a configured slow path and option \a option is enabled |
| 140 | */ |
| 141 | bool isOptionEnabledForPath(const QString &path, KNetworkMountOption option); |
| 142 | |
| 143 | /*! |
| 144 | * Query if the performance optimizations are switched on |
| 145 | * |
| 146 | * Returns \c true if on, \c false otherwise |
| 147 | */ |
| 148 | bool isEnabled() const; |
| 149 | |
| 150 | /*! |
| 151 | * Switch the performance optimizations on or off |
| 152 | * |
| 153 | * \a value the value to set |
| 154 | */ |
| 155 | void setEnabled(bool value); |
| 156 | |
| 157 | /*! |
| 158 | * Query a performance option |
| 159 | * |
| 160 | * \a option the option to query |
| 161 | * |
| 162 | * \a defaultValue the value to return if the option is not configured |
| 163 | * |
| 164 | * Returns \c true if option is on, \c false if not |
| 165 | * \sa KNetworkMountOption |
| 166 | */ |
| 167 | bool isOptionEnabled(const KNetworkMountOption option, const bool defaultValue = false) const; |
| 168 | |
| 169 | /*! |
| 170 | * Switch a performance option on or off |
| 171 | * |
| 172 | * \a option the option to change |
| 173 | * |
| 174 | * \a value the value to set |
| 175 | * |
| 176 | * \sa KNetworkMountOption |
| 177 | */ |
| 178 | void setOption(const KNetworkMountOption option, const bool value); |
| 179 | |
| 180 | /*! |
| 181 | * Query the configured paths for which optimizations are to take place |
| 182 | * |
| 183 | * Returns a list of paths |
| 184 | */ |
| 185 | QStringList paths(KNetworkMountsType type = Any) const; |
| 186 | |
| 187 | /*! |
| 188 | * Set the paths for which optimizations are to take place |
| 189 | * |
| 190 | * \a paths the paths to set |
| 191 | * |
| 192 | * \a type the type of paths. Do not use Any |
| 193 | * |
| 194 | * \sa KNetworkMountsType |
| 195 | */ |
| 196 | void setPaths(const QStringList &paths, KNetworkMountsType type); |
| 197 | |
| 198 | /*! |
| 199 | * Add a path for which optimizations are to take place |
| 200 | * |
| 201 | * \a path the path to add |
| 202 | * |
| 203 | * \a type the type of the path. Do not use Any |
| 204 | * |
| 205 | * \sa KNetworkMountsType |
| 206 | */ |
| 207 | void addPath(const QString &path, KNetworkMountsType type); |
| 208 | |
| 209 | /*! |
| 210 | * Resolves a \a path that may contain symbolic links to mounted network shares. |
| 211 | * |
| 212 | * A symlink path is either a directory which contains symbolic links to slow network mounts |
| 213 | * (SymlinkDirectory) or a direct symbolic link to a slow network mount ( * SymlinkToNfsOrSmbPaths). |
| 214 | * |
| 215 | * Example: |
| 216 | * There are some Samba shares mounted below /mnt. These are paths of type SmbPaths |
| 217 | * \code |
| 218 | * /mnt/server1/share1 |
| 219 | * /mnt/server1/share2 |
| 220 | * /mnt/server2/share3 |
| 221 | * \endcode |
| 222 | * |
| 223 | * A (logged in) user may have symbolic links to them in his home directory below netshares. The |
| 224 | * directory /home/user/netshares is a SymlinkDirectory: |
| 225 | * \code |
| 226 | * /home/user/netshares/share1 -> /mnt/server1/share1 |
| 227 | * /home/user/netshares/share2 -> /mnt/server1/share2 |
| 228 | * /home/user/netshares/share3 -> /mnt/server2/share3 |
| 229 | * \endcode |
| 230 | * |
| 231 | * There is a direct symbolic link from /home/user/share1 to /mnt/server1/share1. This is of type |
| 232 | * SymlinkToNfsOrSmbPaths: |
| 233 | * \code |
| 234 | * /home/user/share1 -> /mnt/server1/share1 |
| 235 | * \endcode |
| 236 | * |
| 237 | * Both types of symbolic links from symlink paths to the real mounted shares are resolved even if |
| 238 | * KNetworkMountOption StrongSideEffectsOptimizations is enabled. |
| 239 | * |
| 240 | * If the setup is like above a \a path |
| 241 | * \code |
| 242 | * /home/user/netshares/share1/Documents/file.txt |
| 243 | * \endcode |
| 244 | * |
| 245 | * would be resolved to |
| 246 | * \code |
| 247 | * /mnt/server1/share1/Documents/file.txt |
| 248 | * \endcode |
| 249 | * |
| 250 | * and a \a path |
| 251 | * \code |
| 252 | * /home/user/share1/Documents/file.txt |
| 253 | * \endcode |
| 254 | * |
| 255 | * would also be resolved to |
| 256 | * \code |
| 257 | * /mnt/server1/share1/Documents/file.txt |
| 258 | * \endcode |
| 259 | * |
| 260 | * Resolved paths are cached in a hash. |
| 261 | * |
| 262 | * \a path the path to resolve |
| 263 | * |
| 264 | * Returns the resolved path or \a path if \a path is not a symlink path or no symlink found |
| 265 | * \sa KNetworkMountsType |
| 266 | * \sa clearCache |
| 267 | * \sa isSlowPath |
| 268 | */ |
| 269 | QString canonicalSymlinkPath(const QString &path); |
| 270 | |
| 271 | /*! |
| 272 | * Clears the canonical symlink path cache |
| 273 | * |
| 274 | * Call this if directory structures on mounted network drives changed. Don't enable the |
| 275 | * cache (SymlinkPathsUseCache) if this happens often and the drives are usually accessed |
| 276 | * via the symlinks. This method exists mainly for the KCM. |
| 277 | * \sa canonicalSymlinkPath |
| 278 | */ |
| 279 | void clearCache(); |
| 280 | |
| 281 | /*! |
| 282 | * Synchronizes to config file |
| 283 | * |
| 284 | * QSettings synchronization also takes place automatically at regular intervals and from |
| 285 | * QSettings destructor, see QSettings::sync() documentation. |
| 286 | * |
| 287 | * Calls QSettings::sync() |
| 288 | */ |
| 289 | void sync(); |
| 290 | |
| 291 | private: |
| 292 | /// Creates a new KNetworkMounts object |
| 293 | KCOREADDONS_NO_EXPORT KNetworkMounts(); |
| 294 | |
| 295 | /// Destructor |
| 296 | KCOREADDONS_NO_EXPORT ~KNetworkMounts() override; |
| 297 | |
| 298 | std::unique_ptr<class KNetworkMountsPrivate> const d; |
| 299 | }; |
| 300 | |
| 301 | #endif // KNETWORKMOUNTS_H |
| 302 | |