1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
//Author: Max Howell <[email protected]>, (C) 2003-4
//Copyright: See COPYING file that comes with this distribution
#include "debug.h"
#include "fileTree.h"
#include <kcursor.h>
#include "localLister.h"
#include <qapplication.h>
#include "remoteLister.h"
#include "scan.h"
namespace Filelight
{
bool ScanManager::s_abort = false;
uint ScanManager::s_files = 0;
ScanManager::ScanManager( QObject *parent )
: QObject( parent )
, m_thread( 0 )
, m_cache( new Chain<Directory> )
{
Filelight::LocalLister::readMounts();
}
ScanManager::~ScanManager()
{
if( m_thread ) {
debug() << "Attempting to abort scan operation...\n";
s_abort = true;
m_thread->wait();
}
delete m_cache;
//RemoteListers are QObjects and get automatically deleted
}
bool
ScanManager::running() const
{
//FIXME not complete
return m_thread && m_thread->running();
}
bool
ScanManager::start( const KURL &url )
{
//url is guarenteed clean and safe
debug() << "Scan requested for: " << url.prettyURL() << endl;
if( running() ) {
//shouldn't happen, but lets prevent mega-disasters just in case eh?
kdWarning() << "Attempted to run 2 scans concurrently!\n";
//TODO give user an error
return false;
}
s_files = 0;
s_abort = false;
if( url.protocol() == "file" )
{
const QString path = url.path( 1 );
Chain<Directory> *trees = new Chain<Directory>;
/* CHECK CACHE
* user wants: /usr/local/
* cached: /usr/
*
* user wants: /usr/
* cached: /usr/local/, /usr/include/
*/
for( Iterator<Directory> it = m_cache->iterator(); it != m_cache->end(); ++it )
{
QString cachePath = (*it)->name();
if( path.startsWith( cachePath ) ) //then whole tree already scanned
{
//find a pointer to the requested branch
debug() << "Cache-(a)hit: " << cachePath << endl;
QStringList split = QStringList::split( '/', path.mid( cachePath.length() ) );
Directory *d = *it;
Iterator<File> jt;
while( !split.isEmpty() && d != NULL ) //if NULL we have got lost so abort!!
{
jt = d->iterator();
const Link<File> *end = d->end();
QString s = split.first(); s += '/';
for( d = 0; jt != end; ++jt )
if( s == (*jt)->name() )
{
d = (Directory*)*jt;
break;
}
split.pop_front();
}
if( d )
{
delete trees;
//we found a completed tree, thus no need to scan
debug() << "Found cache-handle, generating map..\n";
//1001 indicates that this should not be cached
QCustomEvent *e = new QCustomEvent( 1001 );
e->setData( d );
QApplication::postEvent( this, e );
return true;
}
else
{
//something went wrong, we couldn't find the directory we were expecting
error() << "Didn't find " << path << " in the cache!\n";
delete it.remove(); //safest to get rid of it
break; //do a full scan
}
}
else if( cachePath.startsWith( path ) ) //then part of the requested tree is already scanned
{
debug() << "Cache-(b)hit: " << cachePath << endl;
it.transferTo( *trees );
}
}
m_url.setPath( path ); //FIXME stop switching between paths and KURLs all the time
QApplication::setOverrideCursor( KCursor::workingCursor() );
//starts listing by itself
m_thread = new Filelight::LocalLister( path, trees, this );
return true;
}
m_url = url;
QApplication::setOverrideCursor( KCursor::workingCursor() );
//will start listing straight away
QObject *o = new Filelight::RemoteLister( url, (QWidget*)parent() );
insertChild( o );
o->setName( "remote_lister" );
return true;
}
bool
ScanManager::abort()
{
s_abort = true;
delete child( "remote_lister" );
return m_thread && m_thread->running();
}
void
ScanManager::emptyCache()
{
s_abort = true;
if( m_thread && m_thread->running() )
m_thread->wait();
emit aboutToEmptyCache();
m_cache->empty();
}
void
ScanManager::customEvent( QCustomEvent *e )
{
Directory *tree = (Directory*)e->data();
if( m_thread ) {
m_thread->terminate();
m_thread->wait();
delete m_thread; //note the lister deletes itself
m_thread = 0;
}
emit completed( tree );
if( tree ) {
//we don't cache foreign stuff
//we don't recache stuff (thus only type 1000 events)
if( e->type() == 1000 && m_url.protocol() == "file" )
//TODO sanity check the cache
m_cache->append( tree );
}
else //scan failed
m_cache->empty(); //FIXME this is safe but annoying
QApplication::restoreOverrideCursor();
}
}
#include "scan.moc"
|