Changeset View
Changeset View
Standalone View
Standalone View
krusader/FileSystem/filesystem.cpp
Show All 25 Lines | |||||
26 | * * | 26 | * * | ||
27 | * This program is free software; you can redistribute it and/or modify * | 27 | * This program is free software; you can redistribute it and/or modify * | ||
28 | * it under the terms of the GNU General Public License as published by * | 28 | * it under the terms of the GNU General Public License as published by * | ||
29 | * the Free Software Foundation; either version 2 of the License, or * | 29 | * the Free Software Foundation; either version 2 of the License, or * | ||
30 | * (at your option) any later version. * | 30 | * (at your option) any later version. * | ||
31 | * * | 31 | * * | ||
32 | ***************************************************************************/ | 32 | ***************************************************************************/ | ||
33 | 33 | | |||
34 | #include <memory> | ||||
35 | | ||||
34 | #include "filesystem.h" | 36 | #include "filesystem.h" | ||
35 | 37 | | |||
36 | // QtCore | 38 | // QtCore | ||
37 | #include <QDebug> | 39 | #include <QDebug> | ||
38 | #include <QDir> | 40 | #include <QDir> | ||
39 | #include <QList> | 41 | #include <QList> | ||
40 | // QtWidgets | 42 | // QtWidgets | ||
41 | #include <qplatformdefs.h> | 43 | #include <qplatformdefs.h> | ||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Line(s) | |||||
211 | { | 213 | { | ||
212 | _fileItems.insert(item->getName(), item); | 214 | _fileItems.insert(item->getName(), item); | ||
213 | } | 215 | } | ||
214 | 216 | | |||
215 | FileItem *FileSystem::createLocalFileItem(const QString &name, const QString &directory, bool virt) | 217 | FileItem *FileSystem::createLocalFileItem(const QString &name, const QString &directory, bool virt) | ||
216 | { | 218 | { | ||
217 | const QDir dir = QDir(directory); | 219 | const QDir dir = QDir(directory); | ||
218 | const QString path = dir.filePath(name); | 220 | const QString path = dir.filePath(name); | ||
219 | const QByteArray filePath = path.toLocal8Bit(); | 221 | const QByteArray pathByteArray = path.toLocal8Bit(); | ||
222 | const QString fileItemName = virt ? path : name; | ||||
223 | const QUrl fileItemUrl = QUrl::fromLocalFile(path); | ||||
220 | 224 | | |||
225 | // read file status | ||||
221 | QT_STATBUF stat_p; | 226 | QT_STATBUF stat_p; | ||
222 | stat_p.st_size = 0; | 227 | memset(&stat_p, 0, sizeof(stat_p)); | ||
223 | stat_p.st_mode = 0; | 228 | if (QT_LSTAT(pathByteArray.data(), &stat_p) < 0) | ||
224 | stat_p.st_mtime = 0; | 229 | return FileItem::createBroken(fileItemName, fileItemUrl); | ||
225 | stat_p.st_uid = 0; | | |||
226 | stat_p.st_gid = 0; | | |||
227 | QT_LSTAT(filePath.data(), &stat_p); | | |||
228 | const KIO::filesize_t size = stat_p.st_size; | | |||
229 | 230 | | |||
231 | const KIO::filesize_t size = stat_p.st_size; | ||||
230 | bool isDir = S_ISDIR(stat_p.st_mode); | 232 | bool isDir = S_ISDIR(stat_p.st_mode); | ||
231 | const bool isLink = S_ISLNK(stat_p.st_mode); | 233 | const bool isLink = S_ISLNK(stat_p.st_mode); | ||
232 | 234 | | |||
235 | // for links, read link destination and determing whether it's broken or not | ||||
233 | QString linkDestination; | 236 | QString linkDestination; | ||
234 | bool brokenLink = false; | 237 | bool brokenLink = false; | ||
235 | if (isLink) { | 238 | if (isLink) { | ||
236 | // find where the link is pointing to | 239 | linkDestination = readLinkSafely(pathByteArray.data()); | ||
237 | qDebug() << "link name=" << path; | 240 | | ||
238 | // the path of the symlink target cannot be longer than the file size of the symlink | 241 | if (linkDestination.isNull()) | ||
239 | char buffer[stat_p.st_size]; | 242 | brokenLink = true; | ||
240 | memset(buffer, 0, sizeof(buffer)); | 243 | else { | ||
241 | int bytesRead = readlink(filePath.data(), buffer, sizeof(buffer)); | | |||
242 | if (bytesRead != -1) { | | |||
243 | linkDestination = QString::fromLocal8Bit(buffer, bytesRead); // absolute or relative | | |||
244 | const QFileInfo linkFile(dir, linkDestination); | 244 | const QFileInfo linkFile(dir, linkDestination); | ||
245 | if (!linkFile.exists()) | 245 | if (!linkFile.exists()) | ||
246 | brokenLink = true; | 246 | brokenLink = true; | ||
247 | else if (linkFile.isDir()) | 247 | else if (linkFile.isDir()) | ||
248 | isDir = true; | 248 | isDir = true; | ||
249 | } else { | | |||
250 | qWarning() << "failed to read link, path=" << path; | | |||
251 | } | 249 | } | ||
252 | } | 250 | } | ||
253 | 251 | | |||
254 | return new FileItem(virt ? path : name, QUrl::fromLocalFile(path), isDir, | 252 | return new FileItem(fileItemName, fileItemUrl, isDir, | ||
255 | size, stat_p.st_mode, | 253 | size, stat_p.st_mode, | ||
256 | stat_p.st_mtime, stat_p.st_ctime, stat_p.st_atime, | 254 | stat_p.st_mtime, stat_p.st_ctime, stat_p.st_atime, | ||
257 | stat_p.st_uid, stat_p.st_gid, QString(), QString(), | 255 | stat_p.st_uid, stat_p.st_gid, QString(), QString(), | ||
258 | isLink, linkDestination, brokenLink); | 256 | isLink, linkDestination, brokenLink); | ||
259 | } | 257 | } | ||
260 | 258 | | |||
259 | QString FileSystem::readLinkSafely(const char *path) | ||||
260 | { | ||||
261 | // inspired by the areadlink_with_size function from gnulib, which is used for coreutils | ||||
262 | // idea: start with a small buffer and gradually increase it as we discover it wasn't enough | ||||
263 | | ||||
264 | QT_OFF_T bufferSize = 1024; // start with 1 KiB | ||||
265 | QT_OFF_T maxBufferSize = std::numeric_limits<QT_OFF_T>::max(); | ||||
266 | | ||||
267 | while (true) { | ||||
268 | // try to read the link | ||||
269 | std::unique_ptr<char[]> buffer(new char[bufferSize]); | ||||
270 | auto nBytesRead = readlink(path, buffer.get(), bufferSize); | ||||
271 | if (nBytesRead > bufferSize) // should never happen, asserted by readlink | ||||
272 | return QString(); | ||||
273 | | ||||
274 | if (nBytesRead < 0) { | ||||
275 | qDebug() << "Failed to read the link " << path; | ||||
276 | return QString(); | ||||
277 | } | ||||
278 | if (nBytesRead < bufferSize || nBytesRead == maxBufferSize) | ||||
279 | return QString::fromLocal8Bit(buffer.get(), nBytesRead); | ||||
280 | | ||||
281 | // increase the buffer | ||||
282 | // bufferSize < maxBufferSize is implied from previous checks | ||||
283 | if (bufferSize <= maxBufferSize / 2) | ||||
284 | bufferSize *= 2; | ||||
285 | else | ||||
286 | bufferSize = maxBufferSize; | ||||
287 | } | ||||
288 | } | ||||
289 | | ||||
261 | FileItem *FileSystem::createFileItemFromKIO(const KIO::UDSEntry &entry, const QUrl &directory, bool virt) | 290 | FileItem *FileSystem::createFileItemFromKIO(const KIO::UDSEntry &entry, const QUrl &directory, bool virt) | ||
262 | { | 291 | { | ||
263 | const KFileItem kfi(entry, directory, true, true); | 292 | const KFileItem kfi(entry, directory, true, true); | ||
264 | 293 | | |||
265 | const QString name = kfi.text(); | 294 | const QString name = kfi.text(); | ||
266 | // ignore un-needed entries | 295 | // ignore un-needed entries | ||
267 | if (name.isEmpty() || name == "." || name == "..") { | 296 | if (name.isEmpty() || name == "." || name == "..") { | ||
268 | return 0; | 297 | return 0; | ||
▲ Show 20 Lines • Show All 44 Lines • Show Last 20 Lines |