1 /*
2     SPDX-FileCopyrightText: 2009 Nokia Corporation and /or its subsidiary(-ies).
3     Contact: Qt Software Information (qt-info@nokia.com)
4 
5     This file is part of the QtCore module of the Qt Toolkit.
6 
7     $QT_BEGIN_LICENSE:LGPL$
8     Commercial Usage
9     Licensees holding valid Qt Commercial licenses may use this file in
10     accordance with the Qt Commercial License Agreement provided with the
11     Software or, alternatively, in accordance with the terms contained in
12     a written agreement between you and Nokia.
13 
14     GNU Lesser General Public License Usage
15     Alternatively, this file may be used under the terms of the GNU Lesser
16     General Public License version 2.1 as published by the Free Software
17     Foundation and appearing in the file LICENSE.LGPL included in the
18     packaging of this file.  Please review the following information to
19     ensure the GNU Lesser General Public License version 2.1 requirements
20     will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
21 
22     In addition, as a special exception, Nokia gives you certain
23     additional rights. These rights are described in the Nokia Qt LGPL
24     Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
25     package.
26 
27     GNU General Public License Usage
28     Alternatively, this file may be used under the terms of the GNU
29     General Public License version 3.0 as published by the Free Software
30     Foundation and appearing in the file LICENSE.GPL included in the
31     packaging of this file.  Please review the following information to
32     ensure the GNU General Public License version 3.0 requirements will be
33     met: https://www.gnu.org/licenses/gpl-3.0.html.
34 
35     If you are unsure which license is appropriate for your use, please
36     contact the sales department at qt-sales@nokia.com.
37     $QT_END_LICENSE$
38 
39 */
40 
41 #include "qdebug.h"
42 #include "qfsfileengine_iterator_p.h"
43 #include "qfsfileengine_p.h"
44 #include "qplatformdefs.h"
45 
46 #include <qvariant.h>
47 #include <QMutex>
48 #include <private/qmutexpool_p.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 class QFSFileEngineIteratorPlatformSpecificData
53 {
54 public:
QFSFileEngineIteratorPlatformSpecificData()55     inline QFSFileEngineIteratorPlatformSpecificData()
56         : uncShareIndex(-1), findFileHandle(INVALID_HANDLE_VALUE),
57           done(false), uncFallback(false)
58     { }
59 
60     QFSFileEngineIterator *it;
61 
62     QStringList uncShares;
63     int uncShareIndex;
64 
65     HANDLE findFileHandle;
66     WIN32_FIND_DATA findData;
67     bool done;
68     bool uncFallback;
69 
70     void advance();
71     void saveCurrentFileName();
72 };
73 
saveCurrentFileName()74 void QFSFileEngineIteratorPlatformSpecificData::saveCurrentFileName()
75 {
76     if (uncFallback) {
77         // Windows share / UNC path
78         it->currentEntry = uncShares.at(uncShareIndex - 1);
79     } else {
80         // Local directory
81         QT_WA({
82             it->currentEntry = QString::fromUtf16((unsigned short *)findData.cFileName);
83         } , {
84             it->currentEntry = QString::fromLocal8Bit((const char *)findData.cFileName);
85         });
86     }
87 }
88 
advance()89 void QFSFileEngineIterator::advance()
90 {
91     platform->saveCurrentFileName();
92 
93     if (platform->done)
94         return;
95 
96     if (platform->uncFallback) {
97         ++platform->uncShareIndex;
98     } else if (platform->findFileHandle != INVALID_HANDLE_VALUE) {
99         QT_WA({
100             if (!FindNextFile(platform->findFileHandle, &platform->findData)) {
101                 platform->done = true;
102                 FindClose(platform->findFileHandle);
103             }
104         } , {
105             if (!FindNextFileA(platform->findFileHandle, (WIN32_FIND_DATAA *)&platform->findData)) {
106                 platform->done = true;
107                 FindClose(platform->findFileHandle);
108             }
109         });
110     }
111 }
112 
newPlatformSpecifics()113 void QFSFileEngineIterator::newPlatformSpecifics()
114 {
115     platform = new QFSFileEngineIteratorPlatformSpecificData;
116     platform->it = this;
117 }
118 
deletePlatformSpecifics()119 void QFSFileEngineIterator::deletePlatformSpecifics()
120 {
121     delete platform;
122     platform = 0;
123 }
124 
hasNext() const125 bool QFSFileEngineIterator::hasNext() const
126 {
127     if (platform->done)
128         return false;
129 
130     if (platform->uncFallback)
131         return platform->uncShareIndex > 0 && platform->uncShareIndex <= platform->uncShares.size();
132 
133     if (platform->findFileHandle == INVALID_HANDLE_VALUE) {
134         QString path = this->path();
135         // Local directory
136         if (path.endsWith(QLatin1String(".lnk")))
137             path = QFileInfo(path).readLink();
138 
139         if (!path.endsWith(QLatin1Char('/')))
140             path.append(QLatin1Char('/'));
141         path.append(QLatin1String("*.*"));
142 
143         QT_WA({
144             QString fileName = QFSFileEnginePrivate::longFileName(path);
145             platform->findFileHandle = FindFirstFileW((TCHAR *)fileName.utf16(),
146                                                       &platform->findData);
147         }, {
148             // Cast is safe, since char is at end of WIN32_FIND_DATA
149             platform->findFileHandle = FindFirstFileA(QFSFileEnginePrivate::win95Name(path),
150                                                       (WIN32_FIND_DATAA*)&platform->findData);
151         });
152 
153         if (platform->findFileHandle == INVALID_HANDLE_VALUE) {
154             if (path.startsWith(QLatin1String("//"))) {
155                 path = this->path();
156                 // UNC
157                 QStringList parts = QDir::toNativeSeparators(path).split(QLatin1Char('\\'), QString::SkipEmptyParts);
158 
159                 if (parts.count() == 1 && QFSFileEnginePrivate::uncListSharesOnServer(QLatin1String("\\\\") + parts.at(0),
160                                                                                       &platform->uncShares)) {
161                     if (platform->uncShares.isEmpty()) {
162                         platform->done = true;
163                     } else {
164                         platform->uncShareIndex = 1;
165                     }
166                     platform->uncFallback = true;
167                 } else {
168                     platform->done = true;
169                 }
170             } else {
171                 platform->done = true;
172             }
173         }
174 
175         if (!platform->done && (!platform->uncFallback || !platform->uncShares.isEmpty()))
176             platform->saveCurrentFileName();
177     }
178 
179     return !platform->done;
180 }
181 
182 QT_END_NAMESPACE
183