1 /*****************************************************************************
2 * Copyright (C) 2003 Shie Erlich <erlich@users.sourceforge.net> *
3 * Copyright (C) 2003 Rafi Yanai <yanai@users.sourceforge.net> *
4 * Copyright (C) 2004-2019 Krusader Krew [https://krusader.org] *
5 * *
6 * This file is part of Krusader [https://krusader.org]. *
7 * *
8 * Krusader is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * Krusader is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with Krusader. If not, see [http://www.gnu.org/licenses/]. *
20 *****************************************************************************/
21
22 #include "filesystemprovider.h"
23
24 #ifdef HAVE_POSIX_ACL
25 #include <sys/acl.h>
26 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
27 #include <acl/libacl.h>
28 #endif
29 #endif
30
31 // QtCore
32 #include <QDebug>
33 #include <QDir>
34
35 #include <KIOCore/KMountPoint>
36
37 #include "defaultfilesystem.h"
38 #include "fileitem.h"
39 #include "virtualfilesystem.h"
40 #include "../krservices.h"
41 #include "../JobMan/jobman.h"
42
43
FileSystemProvider()44 FileSystemProvider::FileSystemProvider() : _defaultFileSystem(0), _virtFileSystem(0) {}
45
getFilesystem(const QUrl & url,FileSystem * oldFilesystem)46 FileSystem *FileSystemProvider::getFilesystem(const QUrl &url, FileSystem *oldFilesystem)
47 {
48 const FileSystem::FS_TYPE type = getFilesystemType(url);
49 return oldFilesystem && oldFilesystem->type() == type ? oldFilesystem : createFilesystem(type);
50 }
51
startCopyFiles(const QList<QUrl> & urls,const QUrl & destination,KIO::CopyJob::CopyMode mode,bool showProgressInfo,JobMan::StartMode startMode)52 void FileSystemProvider::startCopyFiles(const QList<QUrl> &urls, const QUrl &destination,
53 KIO::CopyJob::CopyMode mode, bool showProgressInfo,
54 JobMan::StartMode startMode)
55 {
56 FileSystem *fs = getFilesystemInstance(destination);
57 fs->copyFiles(urls, destination, mode, showProgressInfo, startMode);
58 }
59
startDropFiles(QDropEvent * event,const QUrl & destination)60 void FileSystemProvider::startDropFiles(QDropEvent *event, const QUrl &destination)
61 {
62 FileSystem *fs = getFilesystemInstance(destination);
63 fs->dropFiles(destination, event);
64 }
65
startDeleteFiles(const QList<QUrl> & urls,bool moveToTrash)66 void FileSystemProvider::startDeleteFiles(const QList<QUrl> &urls, bool moveToTrash)
67 {
68 if (urls.isEmpty())
69 return;
70
71 // assume all URLs use the same filesystem
72 FileSystem *fs = getFilesystemInstance(urls.first());
73 fs->deleteFiles(urls, moveToTrash);
74 }
75
refreshFilesystems(const QUrl & directory,bool removed)76 void FileSystemProvider::refreshFilesystems(const QUrl &directory, bool removed)
77 {
78 qDebug() << "changed=" << directory.toDisplayString();
79
80 QMutableListIterator<QPointer<FileSystem>> it(_fileSystems);
81 while (it.hasNext()) {
82 if (it.next().isNull()) {
83 it.remove();
84 }
85 }
86
87 QString mountPoint = "";
88 if (directory.isLocalFile()) {
89 KMountPoint::Ptr kMountPoint = KMountPoint::currentMountPoints().findByPath(directory.path());
90 if (kMountPoint)
91 mountPoint = kMountPoint->mountPoint();
92 }
93
94 for(QPointer<FileSystem> fileSystemPointer: _fileSystems) {
95 FileSystem *fs = fileSystemPointer.data();
96 // refresh all filesystems currently showing this directory
97 // and always refresh filesystems showing a virtual directory; it can contain files from
98 // various places, we don't know if they were (re)moved. Refreshing is also fast enough.
99 const QUrl fileSystemDir = fs->currentDirectory();
100 if ((!fs->hasAutoUpdate() && (fileSystemDir == FileSystem::cleanUrl(directory) ||
101 (fs->type() == FileSystem::FS_VIRTUAL && !fs->isRoot())))
102 // also refresh if a parent directory was (re)moved (not detected by file watcher)
103 || (removed && directory.isParentOf(fileSystemDir))) {
104 fs->refresh();
105 // ..or refresh filesystem info if mount point is the same (for free space update)
106 } else if (!mountPoint.isEmpty() && mountPoint == fs->mountPoint()) {
107 fs->updateFilesystemInfo();
108 }
109 }
110 }
111
getFilesystemInstance(const QUrl & directory)112 FileSystem *FileSystemProvider::getFilesystemInstance(const QUrl &directory)
113 {
114 const FileSystem::FS_TYPE type = getFilesystemType(directory);
115 switch (type) {
116 case FileSystem::FS_VIRTUAL:
117 if (!_virtFileSystem)
118 _virtFileSystem = createFilesystem(type);
119 return _virtFileSystem;
120 break;
121 default:
122 if (!_defaultFileSystem)
123 _defaultFileSystem = createFilesystem(type);
124 return _defaultFileSystem;
125 }
126 }
127
createFilesystem(FileSystem::FS_TYPE type)128 FileSystem *FileSystemProvider::createFilesystem(FileSystem::FS_TYPE type)
129 {
130 FileSystem *newFilesystem;
131 switch (type) {
132 case (FileSystem::FS_VIRTUAL): newFilesystem = new VirtualFileSystem(); break;
133 default: newFilesystem = new DefaultFileSystem();
134 }
135
136 QPointer<FileSystem> fileSystemPointer(newFilesystem);
137 _fileSystems.append(fileSystemPointer);
138 connect(newFilesystem, &FileSystem::fileSystemChanged, this, &FileSystemProvider::refreshFilesystems);
139 return newFilesystem;
140 }
141
142 // ==== static ====
143
instance()144 FileSystemProvider &FileSystemProvider::instance()
145 {
146 static FileSystemProvider instance;
147 return instance;
148 }
149
getFilesystemType(const QUrl & url)150 FileSystem::FS_TYPE FileSystemProvider::getFilesystemType(const QUrl &url)
151 {
152 return url.scheme() == QStringLiteral("virt") ? FileSystem::FS_VIRTUAL : FileSystem::FS_DEFAULT;
153 }
154
getACL(FileItem * file,QString & acl,QString & defAcl)155 void FileSystemProvider::getACL(FileItem *file, QString &acl, QString &defAcl)
156 {
157 Q_UNUSED(file);
158 acl.clear();
159 defAcl.clear();
160 #ifdef HAVE_POSIX_ACL
161 QString fileName = FileSystem::cleanUrl(file->getUrl()).path();
162 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
163 if (acl_extended_file(fileName)) {
164 #endif
165 acl = getACL(fileName, ACL_TYPE_ACCESS);
166 if (file->isDir())
167 defAcl = getACL(fileName, ACL_TYPE_DEFAULT);
168 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
169 }
170 #endif
171 #endif
172 }
173
getACL(const QString & path,int type)174 QString FileSystemProvider::getACL(const QString & path, int type)
175 {
176 Q_UNUSED(path);
177 Q_UNUSED(type);
178 #ifdef HAVE_POSIX_ACL
179 acl_t acl = 0;
180 // do we have an acl for the file, and/or a default acl for the dir, if it is one?
181 if ((acl = acl_get_file(path.toLocal8Bit(), type)) != 0) {
182 bool aclExtended = false;
183
184 #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
185 aclExtended = acl_equiv_mode(acl, 0);
186 #else
187 acl_entry_t entry;
188 int ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
189 while (ret == 1) {
190 acl_tag_t currentTag;
191 acl_get_tag_type(entry, ¤tTag);
192 if (currentTag != ACL_USER_OBJ &&
193 currentTag != ACL_GROUP_OBJ &&
194 currentTag != ACL_OTHER) {
195 aclExtended = true;
196 break;
197 }
198 ret = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
199 }
200 #endif
201
202 if (!aclExtended) {
203 acl_free(acl);
204 acl = 0;
205 }
206 }
207
208 if (acl == 0)
209 return QString();
210
211 char *aclString = acl_to_text(acl, 0);
212 QString ret = QString::fromLatin1(aclString);
213 acl_free((void*)aclString);
214 acl_free(acl);
215
216 return ret;
217 #else
218 return QString();
219 #endif
220 }
221