Skip to content

Commit 1cdce41

Browse files
committed
feat: allow symlinks in library
- return symlinks in allElementsInDirectory - use a common file system walker for counting and scanning - skip symlinks leading to duplicate or recursive scans - remove obsolete non-threaded functions
1 parent f779e0c commit 1cdce41

3 files changed

Lines changed: 99 additions & 125 deletions

File tree

src/board/UBFeaturesController.cpp

Lines changed: 76 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -65,88 +65,116 @@ const QString UBFeaturesController::favoritePath = rootPath + "/Favorites";
6565
const QString UBFeaturesController::webSearchPath = rootPath + "/Web search";
6666

6767

68-
void UBFeaturesComputingThread::scanFS(const QUrl & currentPath, const QString & currVirtualPath, const QSet<QUrl> &pFavoriteSet)
68+
void UBFeaturesComputingThread::scanFS(const QUrl& currentPath, const QString& currVirtualPath, FeatureProcessor processFeature)
6969
{
70-
// Q_ASSERT(QFileInfo(currentPath.toLocalFile()).exists());
71-
// if(QFileInfo(currentPath.toLocalFile()).exists())
72-
// return;
70+
QSet<QString> scanRoots;
71+
scanRoots << currentPath.toLocalFile();
7372

73+
scanFS(currentPath, currVirtualPath, scanRoots, processFeature);
74+
}
75+
76+
void UBFeaturesComputingThread::scanFS(const QUrl& currentPath, const QString& currVirtualPath, QSet<QString>& scanRoots, FeatureProcessor processFeature)
77+
{
7478
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currentPath.toLocalFile());
7579

76-
QFileInfoList::iterator fileInfo;
77-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
78-
if (abort) {
80+
// new implementation taking care of symlinks
81+
for (const auto& fileInfo : fileInfoList)
82+
{
83+
if (abort)
84+
{
7985
return;
8086
}
8187

82-
QString fullFileName = fileInfo->absoluteFilePath();
83-
UBFeatureElementType featureType = UBFeaturesController::fileTypeFromUrl(fullFileName);
84-
QString fileName = fileInfo->fileName();
85-
86-
QImage icon = UBFeaturesController::getIcon(fullFileName, featureType);
87-
88-
if ( fullFileName.contains(".thumbnail."))
89-
continue;
88+
if (fileInfo.isSymLink())
89+
{
90+
const auto symLinkTarget = QFileInfo(fileInfo.symLinkTarget());
9091

91-
UBFeature testFeature(currVirtualPath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType);
92+
if (symLinkTarget.isDir())
93+
{
94+
bool valid{true};
95+
// add trailing slash to make sure to compare full path segments afterwards
96+
const auto target = symLinkTarget.canonicalFilePath() + "/";
97+
98+
// check target
99+
for (const auto& root : scanRoots)
100+
{
101+
if (root.startsWith(target) || target.startsWith(root))
102+
{
103+
qDebug() << "skipping" << fileInfo << "linking to" << target;
104+
valid = false;
105+
break;
106+
}
107+
}
108+
109+
if (!valid)
110+
{
111+
continue;
112+
}
113+
114+
scanRoots << target;
115+
}
116+
}
92117

93-
emit sendFeature(testFeature);
94-
emit featureSent();
95-
emit scanPath(fullFileName);
118+
const auto fullFileName = fileInfo.canonicalFilePath();
119+
const auto featureType = UBFeaturesController::fileTypeFromUrl(fullFileName);
96120

97-
if ( pFavoriteSet.find(QUrl::fromLocalFile(fullFileName)) != pFavoriteSet.end()) {
98-
//TODO send favoritePath from the controller or make favoritePath public and static
99-
emit sendFeature(UBFeature( UBFeaturesController::favoritePath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType));
121+
if (featureType == UBFeatureElementType::FEATURE_INVALID || fullFileName.contains(".thumbnail."))
122+
{
123+
continue;
100124
}
101125

102-
if (featureType == FEATURE_FOLDER) {
103-
scanFS(QUrl::fromLocalFile(fullFileName), currVirtualPath + "/" + fileName, pFavoriteSet);
126+
processFeature(fileInfo, featureType, currVirtualPath);
127+
128+
if (featureType == UBFeatureElementType::FEATURE_FOLDER)
129+
{
130+
// scan recursive
131+
scanFS(QUrl::fromLocalFile(fullFileName), currVirtualPath + "/" + fileInfo.fileName(), scanRoots, processFeature);
104132
}
105133
}
106134
}
107135

108136
void UBFeaturesComputingThread::scanAll(QList<QPair<QUrl, UBFeature> > pScanningData, const QSet<QUrl> &pFavoriteSet)
109137
{
110-
for (int i = 0; i < pScanningData.count(); i++) {
138+
for (const auto curPair : pScanningData)
139+
{
111140
if (abort) {
112141
return;
113142
}
114-
QPair<QUrl, UBFeature> curPair = pScanningData.at(i);
115143

116144
emit scanCategory(curPair.second.getDisplayName());
117-
scanFS(curPair.first, curPair.second.getFullVirtualPath(), pFavoriteSet);
118-
}
119-
}
120145

121-
int UBFeaturesComputingThread::featuresCount(const QUrl &pPath)
122-
{
123-
int noItems = 0;
146+
const auto currVirtualPath = curPair.second.getFullVirtualPath();
124147

125-
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(pPath.toLocalFile());
148+
scanFS(curPair.first, currVirtualPath, [this, &pFavoriteSet](const QFileInfo& fileInfo, UBFeatureElementType featureType, QString virtualPath){
149+
const auto fileName = fileInfo.fileName();
150+
const auto fullFileName = fileInfo.canonicalFilePath();
151+
QImage icon = UBFeaturesController::getIcon(fullFileName, featureType);
126152

127-
QFileInfoList::iterator fileInfo;
128-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
129-
QString fullFileName = fileInfo->absoluteFilePath();
130-
UBFeatureElementType featureType = UBFeaturesController::fileTypeFromUrl(fullFileName);
153+
UBFeature testFeature{virtualPath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType};
131154

132-
if (featureType != FEATURE_INVALID && !fullFileName.contains(".thumbnail.")) {
133-
noItems++;
134-
}
155+
emit sendFeature(testFeature);
156+
emit featureSent();
157+
emit scanPath(fullFileName);
135158

136-
if (featureType == FEATURE_FOLDER) {
137-
noItems += featuresCount(QUrl::fromLocalFile(fullFileName));
138-
}
159+
if (pFavoriteSet.contains(QUrl::fromLocalFile(fullFileName)))
160+
{
161+
emit sendFeature(UBFeature{UBFeaturesController::favoritePath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType});
162+
}
163+
});
139164
}
140-
141-
return noItems;
142165
}
143166

144167
int UBFeaturesComputingThread::featuresCountAll(QList<QPair<QUrl, UBFeature> > pScanningData)
145168
{
146169
int noItems = 0;
147-
for (int i = 0; i < pScanningData.count(); i++) {
148-
QPair<QUrl, UBFeature> curPair = pScanningData.at(i);
149-
noItems += featuresCount(curPair.first);
170+
171+
for (const auto curPair : pScanningData)
172+
{
173+
const auto currVirtualPath = curPair.second.getFullVirtualPath();
174+
175+
scanFS(curPair.first, currVirtualPath, [this, &noItems](const QFileInfo& fileInfo, UBFeatureElementType featureType, QString virtualPath){
176+
++noItems;
177+
});
150178
}
151179

152180
return noItems;
@@ -452,60 +480,6 @@ void UBFeaturesController::scanFS()
452480
}
453481
}
454482

455-
void UBFeaturesController::fileSystemScan(const QUrl & currentPath, const QString & currVirtualPath)
456-
{
457-
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currentPath.toLocalFile());
458-
459-
QFileInfoList::iterator fileInfo;
460-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
461-
QString fullFileName = fileInfo->absoluteFilePath();
462-
UBFeatureElementType featureType = fileTypeFromUrl(fullFileName);
463-
QString fileName = fileInfo->fileName();
464-
465-
QImage icon = getIcon(fullFileName, featureType);
466-
467-
if ( fullFileName.contains(".thumbnail."))
468-
continue;
469-
470-
UBFeature testFeature(currVirtualPath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType);
471-
472-
featuresList->append(testFeature);
473-
474-
if ( favoriteSet->find( QUrl::fromLocalFile( fullFileName ) ) != favoriteSet->end() ) {
475-
featuresList->append( UBFeature( favoritePath + "/" + fileName, icon, fileName, QUrl::fromLocalFile( fullFileName ), featureType ) );
476-
}
477-
478-
if (featureType == FEATURE_FOLDER) {
479-
fileSystemScan(QUrl::fromLocalFile(fullFileName), currVirtualPath + "/" + fileName);
480-
}
481-
}
482-
}
483-
484-
int UBFeaturesController::featuresCount(const QUrl &currPath)
485-
{
486-
int noItems = 0;
487-
488-
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currPath.toLocalFile());
489-
490-
QFileInfoList::iterator fileInfo;
491-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
492-
QString fullFileName = fileInfo->absoluteFilePath();
493-
UBFeatureElementType featureType = fileTypeFromUrl(fullFileName);
494-
495-
if (featureType != FEATURE_INVALID && !fullFileName.contains(".thumbnail.")) {
496-
noItems++;
497-
} else {
498-
continue;
499-
}
500-
501-
if (featureType == FEATURE_FOLDER) {
502-
noItems += featuresCount(QUrl::fromLocalFile(fullFileName));
503-
}
504-
}
505-
506-
return noItems;
507-
}
508-
509483
bool UBFeaturesController::isInFavoriteList(QUrl url)
510484
{
511485
return favoriteSet->contains(url);

src/board/UBFeaturesController.h

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,25 @@ class UBFeaturesListView;
5757
class UBFeature;
5858

5959

60+
enum UBFeatureElementType
61+
{
62+
FEATURE_CATEGORY,
63+
FEATURE_VIRTUALFOLDER,
64+
FEATURE_FOLDER,
65+
FEATURE_INTERACTIVE,
66+
FEATURE_INTERNAL,
67+
FEATURE_ITEM,
68+
FEATURE_AUDIO,
69+
FEATURE_VIDEO,
70+
FEATURE_IMAGE,
71+
FEATURE_FLASH,
72+
FEATURE_TRASH,
73+
FEATURE_FAVORITE,
74+
FEATURE_SEARCH,
75+
FEATURE_DOCUMENT,
76+
FEATURE_INVALID
77+
};
78+
6079
class UBFeaturesComputingThread : public QThread
6180
{
6281
Q_OBJECT
@@ -80,9 +99,10 @@ class UBFeaturesComputingThread : public QThread
8099
public slots:
81100

82101
private:
83-
void scanFS(const QUrl & currentPath, const QString & currVirtualPath, const QSet<QUrl> &pFavoriteSet);
102+
typedef std::function<void (const QFileInfo&, UBFeatureElementType, QString virtualPath)> FeatureProcessor;
103+
void scanFS(const QUrl& currentPath, const QString & currVirtualPath, FeatureProcessor processFeature);
104+
void scanFS(const QUrl& currentPath, const QString & currVirtualPath, QSet<QString>& scanRoots, FeatureProcessor processFeature);
84105
void scanAll(QList<QPair<QUrl, UBFeature> > pScanningData, const QSet<QUrl> &pFavoriteSet);
85-
int featuresCount(const QUrl &pPath);
86106
int featuresCountAll(QList<QPair<QUrl, UBFeature> > pScanningData);
87107

88108
private:
@@ -97,24 +117,6 @@ public slots:
97117
};
98118

99119

100-
enum UBFeatureElementType
101-
{
102-
FEATURE_CATEGORY,
103-
FEATURE_VIRTUALFOLDER,
104-
FEATURE_FOLDER,
105-
FEATURE_INTERACTIVE,
106-
FEATURE_INTERNAL,
107-
FEATURE_ITEM,
108-
FEATURE_AUDIO,
109-
FEATURE_VIDEO,
110-
FEATURE_IMAGE,
111-
FEATURE_TRASH,
112-
FEATURE_FAVORITE,
113-
FEATURE_SEARCH,
114-
FEATURE_DOCUMENT,
115-
FEATURE_INVALID
116-
};
117-
118120
class UBFeature
119121
{
120122
public:
@@ -204,8 +206,6 @@ Q_OBJECT
204206
void importImage(const QByteArray& imageData, const UBFeature &destination, const QString &fileName = QString() );
205207
QStringList getFileNamesInFolders();
206208

207-
void fileSystemScan(const QUrl &currPath, const QString & currVirtualPath);
208-
int featuresCount(const QUrl &currPath);
209209
static UBFeatureElementType fileTypeFromUrl( const QString &path );
210210

211211
static QString fileNameFromUrl( const QUrl &url );

src/frameworks/UBFileSystemUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ QStringList UBFileSystemUtils::allFiles(const QString& pDirPath, bool isRecursiv
247247
QFileInfoList UBFileSystemUtils::allElementsInDirectory(const QString& pDirPath)
248248
{
249249
QDir dir = QDir(pDirPath);
250-
dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
250+
dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
251251
dir.setSorting(QDir::DirsFirst);
252252

253253
return QFileInfoList(dir.entryInfoList());

0 commit comments

Comments
 (0)