File indexing completed on 2025-04-13 13:47:57
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