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