File indexing completed on 2024-04-28 17:00:58

0001 // clang-format off
0002 /*
0003  * KDiff3 - Text Diff And Merge Tool
0004  *
0005  * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de
0006  * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com
0007  * SPDX-License-Identifier: GPL-2.0-or-later
0008  */
0009 // clang-format on
0010 
0011 #ifndef FILEACCESS_H
0012 #define FILEACCESS_H
0013 
0014 #include "DirectoryList.h"
0015 
0016 #include <type_traits>
0017 
0018 #include <QDateTime>
0019 #include <QDir>
0020 #include <QFile>
0021 #include <QFileInfo>
0022 #include <QScopedPointer>
0023 #include <QSharedPointer>
0024 #include <QTemporaryFile>
0025 #include <QUrl>
0026 
0027 #if HAS_KFKIO && !defined AUTOTEST
0028 #include <KIO/UDSEntry>
0029 #endif
0030 
0031 class FileAccessJobHandler;
0032 class DefaultFileAccessJobHandler;
0033 class IgnoreList;
0034 /*
0035   Defining a function as virtual in FileAccess is intended to allow testing sub classes to be written
0036   more easily. This way the test can use a moc class that emulates the needed conditions with no
0037   actual file being present. This would otherwise be a technical and logistical nightmare.
0038 */
0039 class FileAccess
0040 {
0041   public:
0042     FileAccess();
0043 
0044     FileAccess(const FileAccess&);
0045     FileAccess(FileAccess&&) noexcept;
0046     FileAccess& operator=(const FileAccess&);
0047     FileAccess& operator=(FileAccess&&) noexcept;
0048     virtual ~FileAccess();
0049     explicit FileAccess(const QString& name, bool bWantToWrite = false); // name: local file or dirname or url (when supported)
0050 
0051     explicit FileAccess(const QUrl& name, bool bWantToWrite = false); // name: local file or dirname or url (when supported)
0052     void setFile(const QString& name, bool bWantToWrite = false);
0053     void setFile(const QUrl& url, bool bWantToWrite = false);
0054     void setFile(FileAccess* pParent, const QFileInfo& fi);
0055 
0056     virtual void loadData();
0057 
0058     [[nodiscard]] bool isNormal() const;
0059     [[nodiscard]] bool isValid() const;
0060     [[nodiscard]] bool isBrokenLink() const { return m_bBrokenLink; }
0061     [[nodiscard]] virtual bool isFile() const;
0062     [[nodiscard]] virtual bool isDir() const;
0063     [[nodiscard]] virtual bool isSymLink() const;
0064     [[nodiscard]] virtual bool exists() const;
0065     [[nodiscard]] virtual qint64 size() const;     // Size as returned by stat().
0066     [[nodiscard]] virtual qint64 sizeForReading(); // If the size can't be determined by stat() then the file is copied to a local temp file.
0067     [[nodiscard]] virtual bool isReadable() const;
0068     [[nodiscard]] virtual bool isWritable() const;
0069     [[nodiscard]] virtual bool isExecutable() const;
0070     [[nodiscard]] virtual bool isHidden() const;
0071     [[nodiscard]] const QString& readLink() const;
0072 
0073     [[nodiscard]] const QDateTime& lastModified() const;
0074 
0075     [[nodiscard]] const QString& displayName() const { return mDisplayName.isEmpty() ? fileName() : mDisplayName; }
0076     [[nodiscard]] const QString& fileName(bool needTmp = false) const; // Just the name-part of the path, without parent directories
0077     [[nodiscard]] QString fileRelPath() const;                  // The path relative to base comparison directory
0078     [[nodiscard]] QString prettyAbsPath() const;
0079     [[nodiscard]] const QUrl& url() const;
0080     void setUrl(const QUrl& inUrl) { m_url = inUrl; }
0081 
0082     //Workaround for QUrl::toDisplayString/QUrl::toString behavior that does not fit KDiff3's expectations
0083     [[nodiscard]] QString absoluteFilePath() const;
0084     [[nodiscard]] static QString prettyAbsPath(const QUrl& url)
0085     {
0086         if(!isLocal(url)) return url.toDisplayString();
0087 
0088         //work around for bad path in windows drop event urls. (Qt 5.15.2 affected)
0089         const QString path = url.toLocalFile();
0090         if(!path.isEmpty() && !path.startsWith('/'))
0091           return path;
0092 
0093         return QFileInfo(url.path()).absoluteFilePath();
0094     }
0095 
0096     //Workaround for QUrl::isLocalFile behavior that does not fit KDiff3's expectations.
0097     [[nodiscard]] bool isLocal() const;
0098     [[nodiscard]] static bool isLocal(const QUrl& url)
0099     {
0100         return url.isLocalFile() || !url.isValid() || url.scheme().isEmpty();
0101     }
0102 
0103     virtual bool readFile(void* pDestBuffer, qint64 maxLength);
0104     virtual bool writeFile(const void* pSrcBuffer, qint64 length);
0105     bool listDir(DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
0106                  const QString& filePattern, const QString& fileAntiPattern,
0107                  const QString& dirAntiPattern, bool bFollowDirLinks, IgnoreList& ignoreList) const;
0108     virtual bool copyFile(const QString& destUrl);
0109     virtual bool createBackup(const QString& bakExtension);
0110 
0111     [[nodiscard]] QString getTempName() const;
0112     virtual bool createLocalCopy();
0113     static void createTempFile(QTemporaryFile&);
0114     bool removeFile();
0115     static bool makeDir(const QString&);
0116     static bool removeDir(const QString&);
0117     static bool exists(const QString&);
0118     static QString cleanPath(const QString&);
0119 
0120     //bool chmod( const QString& );
0121     bool rename(const FileAccess&);
0122     static bool symLink(const QString& linkTarget, const QString& linkLocation);
0123 
0124     virtual void addPath(const QString& txt, bool reinit = true);
0125     [[nodiscard]] const QString& getStatusText() const;
0126 
0127     [[nodiscard]] FileAccess* parent() const; // !=0 for listDir-results, but only valid if the parent was not yet destroyed.
0128 
0129     void doError();
0130     void filterList(const QString& dir, DirectoryList* pDirList, const QString& filePattern,
0131                     const QString& fileAntiPattern, const QString& dirAntiPattern,
0132                     const IgnoreList& ignoreList);
0133 
0134     [[nodiscard]] QDir getBaseDirectory() const { return m_baseDir; }
0135 
0136     bool open(const QFile::OpenMode flags);
0137 
0138     qint64 read(char* data, const qint64 maxlen);
0139     void close();
0140 
0141     [[nodiscard]] const QString& errorString() const;
0142 
0143     //These should be exposed for auto tests
0144   protected:
0145 #if HAS_KFKIO && !defined AUTOTEST
0146     friend DefaultFileAccessJobHandler;
0147     void setFromUdsEntry(const KIO::UDSEntry& e, FileAccess* parent);
0148 #endif
0149     void setStatusText(const QString& s);
0150 
0151     void reset();
0152 
0153     bool interruptableReadFile(void* pDestBuffer, qint64 maxLength);
0154 
0155     QScopedPointer<FileAccessJobHandler> mJobHandler;
0156     FileAccess* m_pParent = nullptr;
0157     QUrl m_url;
0158     bool m_bValidData = false;
0159 
0160     QDir m_baseDir;
0161     QFileInfo m_fileInfo;
0162     QString m_linkTarget;
0163     QString m_name;
0164 
0165     QString mDisplayName;
0166     QString m_localCopy;
0167     QString mPhysicalPath;
0168     QSharedPointer<QTemporaryFile> tmpFile = QSharedPointer<QTemporaryFile>::create();
0169     QSharedPointer<QFile> realFile = nullptr;
0170 
0171     qint64 m_size = 0;
0172     QDateTime m_modificationTime = QDateTime::fromMSecsSinceEpoch(0);
0173     bool m_bBrokenLink = false;
0174     bool m_bSymLink = false;
0175     bool m_bFile = false;
0176     bool m_bDir = false;
0177     bool m_bExists = false;
0178     bool m_bWritable = false;
0179     bool m_bReadable = false;
0180     bool m_bExecutable = false;
0181     bool m_bHidden = false;
0182 
0183     QString m_statusText; // Might contain an error string, when the last operation didn't succeed.
0184 
0185   private:
0186     /*
0187     These two variables are used to prevent infinate/long running loops when a symlinks true target
0188     must be found. isNormal is right now the only place this is needed.
0189 
0190     Never expose these outside FileAccess as they are internal values.
0191     */
0192     mutable bool mVisited = false;
0193 };
0194 /*
0195  FileAccess objects should be copy and move assignable.
0196   Used a few places in KDiff3 itself.
0197   Also used in std::list<FileAccess>
0198 */
0199 static_assert(std::is_copy_assignable<FileAccess>::value, "FileAccess must be copy assignable.");
0200 static_assert(std::is_move_assignable<FileAccess>::value, "FileAccess must be move assignable.");
0201 
0202 #endif