File indexing completed on 2024-05-05 17:56:55

0001 /*
0002     SPDX-FileCopyrightText: 2000 Shie Erlich <krusader@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2000 Rafi Yanai <krusader@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #ifndef FILESYSTEM_H
0010 #define FILESYSTEM_H
0011 
0012 #include "dirlisterinterface.h"
0013 
0014 // QtCore
0015 #include <QHash>
0016 #include <QList>
0017 #include <QPointer>
0018 #include <QString>
0019 // QtGui
0020 #include <QDropEvent>
0021 // QtWidgets
0022 #include <QWidget>
0023 
0024 #include <KIO/CopyJob>
0025 #include <KIO/DirectorySizeJob>
0026 
0027 #include "../JobMan/jobman.h"
0028 
0029 class FileItem;
0030 
0031 /**
0032  * An abstract filesystem. Use the implementations of this class for all file operations.
0033  *
0034  * It represents a directory and gives access to its files. All common file operations
0035  * are supported. Methods with absolute URL as argument can be used independently from the current
0036  * directory. Otherwise - if the methods argument is a file name - the operation is performed inside
0037  * the current directory.
0038  *
0039  * Notification signals are emitted if the directory content may have been changed.
0040  */
0041 class FileSystem : public DirListerInterface
0042 {
0043     Q_OBJECT
0044 public:
0045     enum FS_TYPE {
0046         /// Virtual filesystem. Krusaders custom virt:/ protocol
0047         FS_VIRTUAL,
0048         /// Filesystem supporting all KIO protocols (file:/, ftp:/, smb:/, etc.)
0049         FS_DEFAULT
0050     };
0051 
0052     FileSystem();
0053     ~FileSystem() override;
0054 
0055     // DirListerInterface implementation
0056     inline QList<FileItem *> fileItems() const override
0057     {
0058         return _fileItems.values();
0059     }
0060     inline unsigned long numFileItems() const override
0061     {
0062         return _fileItems.count();
0063     }
0064     inline bool isRoot() const override
0065     {
0066         const QString path = _currentDirectory.path();
0067         return path.isEmpty() || path == "/";
0068     }
0069 
0070     /// Copy (copy, move or link) files in this filesystem.
0071     /// Destination is absolute URL. May implemented async.
0072     virtual void copyFiles(const QList<QUrl> &urls,
0073                            const QUrl &destination,
0074                            KIO::CopyJob::CopyMode mode = KIO::CopyJob::Copy,
0075                            bool showProgressInfo = true,
0076                            JobMan::StartMode startMode = JobMan::Default) = 0;
0077     /// Handle file dropping in this filesystem. Destination is absolute URL. May implemented async.
0078     virtual void dropFiles(const QUrl &destination, QDropEvent *event) = 0;
0079 
0080     /// Copy (copy, move or link) files to the current filesystem directory or to "dir", the
0081     /// directory name relative to the current dir. May implemented async.
0082     virtual void addFiles(const QList<QUrl> &fileUrls, KIO::CopyJob::CopyMode mode, const QString &dir = "") = 0;
0083     /// Create a new directory in the current directory. May implemented async.
0084     virtual void mkDir(const QString &name) = 0;
0085     /// Rename file/directory in the current directory. May implemented async.
0086     virtual void rename(const QString &fileName, const QString &newName) = 0;
0087 
0088     /// Return an absolute URL for a single file/directory name in the current directory - with no
0089     /// trailing slash.
0090     virtual QUrl getUrl(const QString &name) const = 0;
0091     /// Return a list of URLs for multiple files/directories in the current directory.
0092     QList<QUrl> getUrls(const QStringList &names) const;
0093     /// Return true if all files can be moved to trash, else false.
0094     virtual bool canMoveToTrash(const QStringList &fileNames) const = 0;
0095 
0096     /// Return the filesystem mount point of the current directory. Empty string by default.
0097     virtual QString mountPoint() const
0098     {
0099         return QString();
0100     }
0101     /// Returns true if this filesystem implementation does not need to be notified about changes in the
0102     /// current directory. Else false.
0103     virtual bool hasAutoUpdate() const
0104     {
0105         return false;
0106     }
0107     /// Notify this filesystem that the filesystem info of the current directory may have changed.
0108     virtual void updateFilesystemInfo()
0109     {
0110     }
0111 
0112     /**
0113      * Scan all files and directories in a directory and create the file items for them. Blocking.
0114      *
0115      * @param directory if given, the lister tries to change to this directory, else the old
0116      * directory is refreshed
0117      * @return true if scan was successful, else (not implemented, scan failed or refresh job
0118      * was killed) false.
0119      */
0120     bool scanDir(const QUrl &directory = QUrl())
0121     {
0122         return scanOrRefresh(directory, false);
0123     }
0124 
0125     /// Change or refresh the current directory and scan it. Blocking.
0126     /// Returns true if directory was scanned. Returns false if failed or scan job was killed.
0127     bool refresh(const QUrl &directory = QUrl())
0128     {
0129         return scanOrRefresh(directory, false);
0130     }
0131 
0132     /// Returns the current directory path of this filesystem.
0133     inline QUrl currentDirectory() const
0134     {
0135         return _currentDirectory;
0136     }
0137     /// Return the file item for a file name in the current directory. Or 0 if not found.
0138     FileItem *getFileItem(const QString &name) const;
0139     /// The total size of all files in the current directory (only valid after scan).
0140     // TODO unused
0141     KIO::filesize_t totalSize() const;
0142     /// Return the filesystem type.
0143     inline FS_TYPE type() const
0144     {
0145         return _type;
0146     }
0147     /// Return true if the current directory is local (without recognizing mount points).
0148     inline bool isLocal() const
0149     {
0150         return _currentDirectory.isLocalFile();
0151     }
0152     /// Return true if the current directory is a remote (network) location.
0153     inline bool isRemote() const
0154     {
0155         const QString sc = _currentDirectory.scheme();
0156         return (sc == "fish" || sc == "ftp" || sc == "sftp" || sc == "nfs" || sc == "smb" || sc == "webdav");
0157     }
0158     /// Returns true if this filesystem is currently refreshing the current directory.
0159     inline bool isRefreshing() const
0160     {
0161         return _isRefreshing;
0162     }
0163 
0164     /// Delete or trash arbitrary files. Implemented async. Universal refresh not fully implemented.
0165     void deleteFiles(const QList<QUrl> &urls, bool moveToTrash);
0166 
0167     /// Return the input URL with a trailing slash if absent.
0168     static QUrl ensureTrailingSlash(const QUrl &url);
0169     /// Return the input URL without trailing slash.
0170     static QUrl cleanUrl(const QUrl &url)
0171     {
0172         return url.adjusted(QUrl::StripTrailingSlash);
0173     }
0174     /// Add 'file' scheme to non-empty URL without scheme
0175     static QUrl preferLocalUrl(const QUrl &url);
0176 
0177     /// Return a file item for a local file inside a directory
0178     static FileItem *createLocalFileItem(const QString &name, const QString &directory, bool virt = false);
0179     /// Return a file item for a KIO result. Returns 0 if entry is not needed
0180     static FileItem *createFileItemFromKIO(const KIO::UDSEntry &entry, const QUrl &directory, bool virt = false);
0181 
0182     /// Read a symlink with an extra precaution
0183     static QString readLinkSafely(const char *path);
0184 
0185     /// Set the parent window to be used for dialogs
0186     void setParentWindow(QWidget *widget)
0187     {
0188         parentWindow = widget;
0189     }
0190 
0191 signals:
0192     /// Emitted when this filesystem is currently refreshing the filesystem directory.
0193     void refreshJobStarted(KIO::Job *job);
0194     /// Emitted when an error occurred in this filesystem during refresh.
0195     void error(const QString &msg);
0196     /// Emitted when the content of a directory was changed by this filesystem.
0197     void fileSystemChanged(const QUrl &directory, bool removed);
0198     /// Emitted when the information for the filesystem of the current directory changed.
0199     /// Information is either
0200     /// * 'metaInfo': a displayable string about the fs, empty by default, OR
0201     /// * 'fsType', 'total' and 'free': filesystem type, size and free space,
0202     ///   empty string or 0 by default
0203     void fileSystemInfoChanged(const QString &metaInfo, const QString &fsType, KIO::filesize_t total, KIO::filesize_t free);
0204     /// Emitted before a directory path is opened for reading. Used for automounting.
0205     void aboutToOpenDir(const QString &path);
0206 
0207 protected:
0208     /// Fill the filesystem dictionary with file items, must be implemented for each filesystem.
0209     virtual bool refreshInternal(const QUrl &origin, bool stayInDir) = 0;
0210 
0211     /// Connect the result signal of a file operation job - source URLs.
0212     void connectJobToSources(KJob *job, const QList<QUrl> &urls);
0213     /// Connect the result signal of a file operation job - destination URL.
0214     void connectJobToDestination(KJob *job, const QUrl &destination);
0215     /// Returns true if showing hidden files is set in config.
0216     bool showHiddenFiles();
0217     /// Add a new file item to the internal dictionary (while refreshing).
0218     void addFileItem(FileItem *item);
0219 
0220     FS_TYPE _type; // the filesystem type.
0221     QUrl _currentDirectory; // the path or file the filesystem originates from.
0222     bool _isRefreshing; // true if filesystem is busy with refreshing
0223     QPointer<QWidget> parentWindow;
0224 
0225 protected slots:
0226     /// Handle result after job (except when refreshing!) finished
0227     void slotJobResult(KJob *job, bool refresh);
0228 
0229 private:
0230     typedef QHash<QString, FileItem *> FileItemDict;
0231 
0232     // optional TODO: add an async version of this
0233     bool scanOrRefresh(const QUrl &directory, bool onlyScan);
0234 
0235     /// Delete and clear file items.
0236     void clear(FileItemDict &fileItems);
0237 
0238     FileItemDict _fileItems; // the list of files in the current dictionary
0239 };
0240 
0241 #endif