Skip to content

Commit b8a3b49

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 fb3f3db commit b8a3b49

3 files changed

Lines changed: 99 additions & 126 deletions

File tree

src/board/UBFeaturesController.cpp

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

6666

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

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

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

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

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

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

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

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

107135
void UBFeaturesComputingThread::scanAll(QList<QPair<QUrl, UBFeature> > pScanningData, const QSet<QUrl> &pFavoriteSet)
108136
{
109-
for (int i = 0; i < pScanningData.count(); i++) {
137+
for (const auto curPair : pScanningData)
138+
{
110139
if (abort) {
111140
return;
112141
}
113-
QPair<QUrl, UBFeature> curPair = pScanningData.at(i);
114142

115143
emit scanCategory(curPair.second.getDisplayName());
116-
scanFS(curPair.first, curPair.second.getFullVirtualPath(), pFavoriteSet);
117-
}
118-
}
119144

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

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

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

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

135-
if (featureType == FEATURE_FOLDER) {
136-
noItems += featuresCount(QUrl::fromLocalFile(fullFileName));
137-
}
158+
if (pFavoriteSet.contains(QUrl::fromLocalFile(fullFileName)))
159+
{
160+
emit sendFeature(UBFeature{UBFeaturesController::favoritePath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType});
161+
}
162+
});
138163
}
139-
140-
return noItems;
141164
}
142165

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

151179
return noItems;
@@ -468,60 +496,6 @@ void UBFeaturesController::scanFS()
468496
}
469497
}
470498

471-
void UBFeaturesController::fileSystemScan(const QUrl & currentPath, const QString & currVirtualPath)
472-
{
473-
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currentPath.toLocalFile());
474-
475-
QFileInfoList::iterator fileInfo;
476-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
477-
QString fullFileName = fileInfo->absoluteFilePath();
478-
UBFeatureElementType featureType = fileTypeFromUrl(fullFileName);
479-
QString fileName = fileInfo->fileName();
480-
481-
QImage icon = getIcon(fullFileName, featureType);
482-
483-
if ( fullFileName.contains(".thumbnail."))
484-
continue;
485-
486-
UBFeature testFeature(currVirtualPath + "/" + fileName, icon, fileName, QUrl::fromLocalFile(fullFileName), featureType);
487-
488-
featuresList->append(testFeature);
489-
490-
if ( favoriteSet->find( QUrl::fromLocalFile( fullFileName ) ) != favoriteSet->end() ) {
491-
featuresList->append( UBFeature( favoritePath + "/" + fileName, icon, fileName, QUrl::fromLocalFile( fullFileName ), featureType ) );
492-
}
493-
494-
if (featureType == FEATURE_FOLDER) {
495-
fileSystemScan(QUrl::fromLocalFile(fullFileName), currVirtualPath + "/" + fileName);
496-
}
497-
}
498-
}
499-
500-
int UBFeaturesController::featuresCount(const QUrl &currPath)
501-
{
502-
int noItems = 0;
503-
504-
QFileInfoList fileInfoList = UBFileSystemUtils::allElementsInDirectory(currPath.toLocalFile());
505-
506-
QFileInfoList::iterator fileInfo;
507-
for ( fileInfo = fileInfoList.begin(); fileInfo != fileInfoList.end(); fileInfo += 1) {
508-
QString fullFileName = fileInfo->absoluteFilePath();
509-
UBFeatureElementType featureType = fileTypeFromUrl(fullFileName);
510-
511-
if (featureType != FEATURE_INVALID && !fullFileName.contains(".thumbnail.")) {
512-
noItems++;
513-
} else {
514-
continue;
515-
}
516-
517-
if (featureType == FEATURE_FOLDER) {
518-
noItems += featuresCount(QUrl::fromLocalFile(fullFileName));
519-
}
520-
}
521-
522-
return noItems;
523-
}
524-
525499
bool UBFeaturesController::isInFavoriteList(QUrl url)
526500
{
527501
return favoriteSet->contains(url);

src/board/UBFeaturesController.h

Lines changed: 22 additions & 23 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,25 +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_FLASH,
112-
FEATURE_TRASH,
113-
FEATURE_FAVORITE,
114-
FEATURE_SEARCH,
115-
FEATURE_DOCUMENT,
116-
FEATURE_INVALID
117-
};
118-
119120
class UBFeature
120121
{
121122
public:
@@ -205,8 +206,6 @@ Q_OBJECT
205206
void importImage(const QByteArray& imageData, const UBFeature &destination, const QString &fileName = QString() );
206207
QStringList getFileNamesInFolders();
207208

208-
void fileSystemScan(const QUrl &currPath, const QString & currVirtualPath);
209-
int featuresCount(const QUrl &currPath);
210209
static UBFeatureElementType fileTypeFromUrl( const QString &path );
211210

212211
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)