File indexing completed on 2024-05-05 17:56:55
0001 /* 0002 SPDX-FileCopyrightText: 2003 Shie Erlich <erlich@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2003 Rafi Yanai <yanai@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 #include "filesystemprovider.h" 0010 0011 #ifdef HAVE_POSIX_ACL 0012 #include <sys/acl.h> 0013 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS 0014 #include <acl/libacl.h> 0015 #endif 0016 #endif 0017 0018 // QtCore 0019 #include <QDebug> 0020 #include <QDir> 0021 0022 #include <KIOCore/KMountPoint> 0023 0024 #include "../JobMan/jobman.h" 0025 #include "../krservices.h" 0026 #include "defaultfilesystem.h" 0027 #include "fileitem.h" 0028 #include "virtualfilesystem.h" 0029 0030 FileSystemProvider::FileSystemProvider() 0031 : _defaultFileSystem(nullptr) 0032 , _virtFileSystem(nullptr) 0033 { 0034 } 0035 0036 FileSystem *FileSystemProvider::getFilesystem(const QUrl &url, FileSystem *oldFilesystem) 0037 { 0038 const FileSystem::FS_TYPE type = getFilesystemType(url); 0039 return oldFilesystem && oldFilesystem->type() == type ? oldFilesystem : createFilesystem(type); 0040 } 0041 0042 void FileSystemProvider::startCopyFiles(const QList<QUrl> &urls, 0043 const QUrl &destination, 0044 KIO::CopyJob::CopyMode mode, 0045 bool showProgressInfo, 0046 JobMan::StartMode startMode) 0047 { 0048 FileSystem *fs = getFilesystemInstance(destination); 0049 fs->copyFiles(urls, destination, mode, showProgressInfo, startMode); 0050 } 0051 0052 void FileSystemProvider::startDropFiles(QDropEvent *event, const QUrl &destination) 0053 { 0054 FileSystem *fs = getFilesystemInstance(destination); 0055 fs->dropFiles(destination, event); 0056 } 0057 0058 void FileSystemProvider::startDeleteFiles(const QList<QUrl> &urls, bool moveToTrash) 0059 { 0060 if (urls.isEmpty()) 0061 return; 0062 0063 // assume all URLs use the same filesystem 0064 FileSystem *fs = getFilesystemInstance(urls.first()); 0065 fs->deleteFiles(urls, moveToTrash); 0066 } 0067 0068 void FileSystemProvider::refreshFilesystems(const QUrl &directory, bool removed) 0069 { 0070 qDebug() << "changed=" << directory.toDisplayString(); 0071 0072 QMutableListIterator<QPointer<FileSystem>> it(_fileSystems); 0073 while (it.hasNext()) { 0074 if (it.next().isNull()) { 0075 it.remove(); 0076 } 0077 } 0078 0079 QString mountPoint = ""; 0080 if (directory.isLocalFile()) { 0081 KMountPoint::Ptr kMountPoint = KMountPoint::currentMountPoints().findByPath(directory.path()); 0082 if (kMountPoint) 0083 mountPoint = kMountPoint->mountPoint(); 0084 } 0085 0086 for (const QPointer<FileSystem> &fileSystemPointer : _fileSystems) { 0087 FileSystem *fs = fileSystemPointer.data(); 0088 // refresh all filesystems currently showing this directory 0089 // and always refresh filesystems showing a virtual directory; it can contain files from 0090 // various places, we don't know if they were (re)moved. Refreshing is also fast enough. 0091 const QUrl fileSystemDir = fs->currentDirectory(); 0092 if ((!fs->hasAutoUpdate() && (fileSystemDir == FileSystem::cleanUrl(directory) || (fs->type() == FileSystem::FS_VIRTUAL && !fs->isRoot()))) 0093 // also refresh if a parent directory was (re)moved (not detected by file watcher) 0094 || (removed && directory.isParentOf(fileSystemDir))) { 0095 fs->refresh(); 0096 // ..or refresh filesystem info if mount point is the same (for free space update) 0097 } else if (!mountPoint.isEmpty() && mountPoint == fs->mountPoint()) { 0098 fs->updateFilesystemInfo(); 0099 } 0100 } 0101 } 0102 0103 FileSystem *FileSystemProvider::getFilesystemInstance(const QUrl &directory) 0104 { 0105 const FileSystem::FS_TYPE type = getFilesystemType(directory); 0106 switch (type) { 0107 case FileSystem::FS_VIRTUAL: 0108 if (!_virtFileSystem) 0109 _virtFileSystem = createFilesystem(type); 0110 return _virtFileSystem; 0111 break; 0112 default: 0113 if (!_defaultFileSystem) 0114 _defaultFileSystem = createFilesystem(type); 0115 return _defaultFileSystem; 0116 } 0117 } 0118 0119 FileSystem *FileSystemProvider::createFilesystem(FileSystem::FS_TYPE type) 0120 { 0121 FileSystem *newFilesystem; 0122 switch (type) { 0123 case (FileSystem::FS_VIRTUAL): 0124 newFilesystem = new VirtualFileSystem(); 0125 break; 0126 default: 0127 newFilesystem = new DefaultFileSystem(); 0128 } 0129 0130 QPointer<FileSystem> fileSystemPointer(newFilesystem); 0131 _fileSystems.append(fileSystemPointer); 0132 connect(newFilesystem, &FileSystem::fileSystemChanged, this, &FileSystemProvider::refreshFilesystems); 0133 return newFilesystem; 0134 } 0135 0136 // ==== static ==== 0137 0138 FileSystemProvider &FileSystemProvider::instance() 0139 { 0140 static FileSystemProvider instance; 0141 return instance; 0142 } 0143 0144 FileSystem::FS_TYPE FileSystemProvider::getFilesystemType(const QUrl &url) 0145 { 0146 return url.scheme() == QStringLiteral("virt") ? FileSystem::FS_VIRTUAL : FileSystem::FS_DEFAULT; 0147 } 0148 0149 void FileSystemProvider::getACL(FileItem *file, QString &acl, QString &defAcl) 0150 { 0151 Q_UNUSED(file); 0152 acl.clear(); 0153 defAcl.clear(); 0154 #ifdef HAVE_POSIX_ACL 0155 QString fileName = FileSystem::cleanUrl(file->getUrl()).path(); 0156 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS 0157 if (acl_extended_file(fileName)) { 0158 #endif 0159 acl = getACL(fileName, ACL_TYPE_ACCESS); 0160 if (file->isDir()) 0161 defAcl = getACL(fileName, ACL_TYPE_DEFAULT); 0162 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS 0163 } 0164 #endif 0165 #endif 0166 } 0167 0168 QString FileSystemProvider::getACL(const QString &path, int type) 0169 { 0170 Q_UNUSED(path); 0171 Q_UNUSED(type); 0172 #ifdef HAVE_POSIX_ACL 0173 acl_t acl = nullptr; 0174 // do we have an acl for the file, and/or a default acl for the dir, if it is one? 0175 if ((acl = acl_get_file(path.toLocal8Bit(), type)) != nullptr) { 0176 bool aclExtended = false; 0177 0178 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS 0179 aclExtended = acl_equiv_mode(acl, 0); 0180 #else 0181 acl_entry_t entry; 0182 int ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); 0183 while (ret == 1) { 0184 acl_tag_t currentTag; 0185 acl_get_tag_type(entry, ¤tTag); 0186 if (currentTag != ACL_USER_OBJ && currentTag != ACL_GROUP_OBJ && currentTag != ACL_OTHER) { 0187 aclExtended = true; 0188 break; 0189 } 0190 ret = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); 0191 } 0192 #endif 0193 0194 if (!aclExtended) { 0195 acl_free(acl); 0196 acl = nullptr; 0197 } 0198 } 0199 0200 if (acl == nullptr) 0201 return QString(); 0202 0203 char *aclString = acl_to_text(acl, nullptr); 0204 QString ret = QString::fromLatin1(aclString); 0205 acl_free((void *)aclString); 0206 acl_free(acl); 0207 0208 return ret; 0209 #else 0210 return QString(); 0211 #endif 0212 }