1 /* 2 * KDiff3 - Text Diff And Merge Tool 3 * 4 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 5 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #ifndef FILEACCESS_H 10 #define FILEACCESS_H 11 12 #include <type_traits> 13 14 #include <QDateTime> 15 #include <QDir> 16 #include <QFile> 17 #include <QFileInfo> 18 #include <QSharedPointer> 19 #include <QTemporaryFile> 20 #include <QUrl> 21 22 #ifndef AUTOTEST 23 #include <KIO/UDSEntry> 24 #endif 25 26 class t_DirectoryList; 27 class FileAccessJobHandler; 28 class DefaultFileAccessJobHandler; 29 /* 30 Defining a function as virtual in FileAccess is intended to allow testing sub classes to be written 31 more easily. This way the test can use a moc class that emulates the needed conditions with no 32 actual file being present. This would otherwise be a technical and logistical nightmare. 33 */ 34 class FileAccess 35 { 36 public: 37 FileAccess(); 38 39 FileAccess(const FileAccess&); 40 FileAccess(FileAccess&&) noexcept; 41 FileAccess& operator=(const FileAccess&); 42 FileAccess& operator=(FileAccess&&) noexcept; 43 virtual ~FileAccess(); 44 explicit FileAccess(const QString& name, bool bWantToWrite = false); // name: local file or dirname or url (when supported) 45 46 explicit FileAccess(const QUrl& name, bool bWantToWrite = false); // name: local file or dirname or url (when supported) 47 virtual void setFile(const QString& name, bool bWantToWrite = false); 48 virtual void setFile(const QUrl& url, bool bWantToWrite = false); 49 virtual void setFile(FileAccess* pParent, const QFileInfo& fi); 50 51 virtual void loadData(); 52 53 Q_REQUIRED_RESULT bool isNormal() const; 54 Q_REQUIRED_RESULT bool isValid() const; 55 Q_REQUIRED_RESULT virtual bool isFile() const; 56 Q_REQUIRED_RESULT virtual bool isDir() const; 57 Q_REQUIRED_RESULT virtual bool isSymLink() const; 58 Q_REQUIRED_RESULT virtual bool exists() const; 59 Q_REQUIRED_RESULT virtual qint64 size() const; // Size as returned by stat(). 60 Q_REQUIRED_RESULT virtual qint64 sizeForReading(); // If the size can't be determined by stat() then the file is copied to a local temp file. 61 Q_REQUIRED_RESULT virtual bool isReadable() const; 62 Q_REQUIRED_RESULT virtual bool isWritable() const; 63 Q_REQUIRED_RESULT virtual bool isExecutable() const; 64 Q_REQUIRED_RESULT virtual bool isHidden() const; 65 Q_REQUIRED_RESULT QString readLink() const; 66 67 Q_REQUIRED_RESULT QDateTime lastModified() const; 68 displayName()69 Q_REQUIRED_RESULT QString displayName() const { return mDisplayName.isEmpty() ? fileName() : mDisplayName; } 70 Q_REQUIRED_RESULT QString fileName(bool needTmp = false) const; // Just the name-part of the path, without parent directories 71 Q_REQUIRED_RESULT QString fileRelPath() const; // The path relative to base comparison directory 72 Q_REQUIRED_RESULT QString prettyAbsPath() const; 73 Q_REQUIRED_RESULT QUrl url() const; setUrl(const QUrl & inUrl)74 void setUrl(const QUrl& inUrl) { m_url = inUrl; } 75 76 //Workaround for QUrl::toDisplayString/QUrl::toString behavior that does not fit KDiff3's expectations 77 Q_REQUIRED_RESULT QString absoluteFilePath() const; prettyAbsPath(const QUrl & url)78 Q_REQUIRED_RESULT static QString prettyAbsPath(const QUrl& url) 79 { 80 if(!isLocal(url)) return url.toDisplayString(); 81 82 return QFileInfo(url.path()).absoluteFilePath(); 83 } 84 85 //Workaround for QUrl::isLocalFile behavior that does not fit KDiff3's expectations. 86 Q_REQUIRED_RESULT bool isLocal() const; isLocal(const QUrl & url)87 Q_REQUIRED_RESULT static bool isLocal(const QUrl& url) 88 { 89 return url.isLocalFile() || !url.isValid() || url.scheme().isEmpty(); 90 } 91 92 virtual bool readFile(void* pDestBuffer, qint64 maxLength); 93 virtual bool writeFile(const void* pSrcBuffer, qint64 length); 94 bool listDir(t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, 95 const QString& filePattern, const QString& fileAntiPattern, 96 const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore); 97 virtual bool copyFile(const QString& destUrl); 98 virtual bool createBackup(const QString& bakExtension); 99 100 Q_REQUIRED_RESULT QString getTempName() const; 101 virtual bool createLocalCopy(); 102 static void createTempFile(QTemporaryFile&); 103 bool removeFile(); 104 static bool makeDir(const QString&); 105 static bool removeDir(const QString&); 106 static bool exists(const QString&); 107 static QString cleanPath(const QString&); 108 109 //bool chmod( const QString& ); 110 bool rename(const FileAccess&); 111 static bool symLink(const QString& linkTarget, const QString& linkLocation); 112 113 virtual void addPath(const QString& txt, bool reinit = true); 114 Q_REQUIRED_RESULT const QString& getStatusText() const; 115 116 Q_REQUIRED_RESULT FileAccess* parent() const; // !=0 for listDir-results, but only valid if the parent was not yet destroyed. 117 118 void doError(); 119 void filterList(t_DirectoryList* pDirList, const QString& filePattern, 120 const QString& fileAntiPattern, const QString& dirAntiPattern, 121 const bool bUseCvsIgnore); 122 getBaseDirectory()123 Q_REQUIRED_RESULT QDir getBaseDirectory() const { return m_baseDir; } 124 125 bool open(const QFile::OpenMode flags); 126 127 qint64 read(char* data, const qint64 maxlen); 128 void close(); 129 130 const QString& errorString() const; 131 132 //These should be exposed for auto tests 133 protected: 134 #ifndef AUTOTEST 135 friend DefaultFileAccessJobHandler; 136 void setFromUdsEntry(const KIO::UDSEntry& e, FileAccess* parent); 137 #endif 138 void setStatusText(const QString& s); 139 140 void reset(); 141 142 bool interruptableReadFile(void* pDestBuffer, qint64 maxLength); 143 144 QScopedPointer<FileAccessJobHandler> mJobHandler; 145 FileAccess* m_pParent = nullptr; 146 QUrl m_url; 147 bool m_bValidData = false; 148 149 QDir m_baseDir; 150 QFileInfo m_fileInfo; 151 QString m_linkTarget; 152 QString m_name; 153 154 QString mDisplayName; 155 QString m_localCopy; 156 QString mPhysicalPath; 157 QSharedPointer<QTemporaryFile> tmpFile = QSharedPointer<QTemporaryFile>::create(); 158 QSharedPointer<QFile> realFile = nullptr; 159 160 qint64 m_size = 0; 161 QDateTime m_modificationTime = QDateTime::fromMSecsSinceEpoch(0); 162 bool m_bSymLink = false; 163 bool m_bFile = false; 164 bool m_bDir = false; 165 bool m_bExists = false; 166 bool m_bWritable = false; 167 bool m_bReadable = false; 168 bool m_bExecutable = false; 169 bool m_bHidden = false; 170 171 QString m_statusText; // Might contain an error string, when the last operation didn't succeed. 172 173 private: 174 /* 175 These two variables are used to prevent infinate/long running loops when a symlinks true target 176 must be found. isNormal is right now the only place this is needed. 177 178 Never expose these outside FileAccess as they are internal values. 179 */ 180 mutable bool mVisited = false; 181 mutable quint32 mDepth = 0; 182 }; 183 /* 184 FileAccess objects should be copy and move assignable. 185 Used a few places in KDiff3 itself. 186 Also used in std::list<FileAccess> 187 */ 188 static_assert(std::is_copy_assignable<FileAccess>::value, "FileAccess must be copy assignable."); 189 static_assert(std::is_move_assignable<FileAccess>::value, "FileAccess must be move assignable."); 190 191 class t_DirectoryList: public std::list<FileAccess> 192 { 193 }; 194 195 #endif 196