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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
//Copyright: See COPYING file that comes with this distribution
#include "../../config.h"
#include "Config.h"
#include "debug.h"
#include <dirent.h>
#include "fileTree.h"
#include <fstab.h>
#include "localLister.h"
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <tqapplication.h> //postEvent()
#include <tqfile.h>
#include "scan.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace Filelight
{
TQStringList LocalLister::s_remoteMounts;
TQStringList LocalLister::s_localMounts;
LocalLister::LocalLister( const TQString &path, Chain<Directory> *cachedTrees, TQObject *parent )
: TQThread()
, m_path( path )
, m_trees( cachedTrees )
, m_parent( parent )
{
//add empty directories for any mount points that are in the path
//TODO empty directories is not ideal as adds to fileCount incorrectly
TQStringList list( Config::skipList );
if( !Config::scanAcrossMounts ) list += s_localMounts;
if( !Config::scanRemoteMounts ) list += s_remoteMounts;
for( TQStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it )
if( (*it).startsWith( path ) )
//prevent scanning of these directories
m_trees->append( new Directory( (*it).local8Bit() ) );
start();
}
void
LocalLister::run()
{
//recursively scan the requested path
const TQCString path = TQFile::encodeName( m_path );
Directory *tree = scan( path, path );
//delete the list of trees useful for this scan,
//in a sucessful scan the contents would now be transfered to 'tree'
delete m_trees;
if( ScanManager::s_abort ) //scan was cancelled
{
debug() << "Scan succesfully aborted\n";
delete tree;
tree = 0;
}
TQCustomEvent *e = new TQCustomEvent( 1000 );
e->setData( tree );
TQApplication::postEvent( m_parent, e );
}
// from system.h in GNU coreutils package
/* Extract or fake data from a `struct stat'.
ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
#ifndef HAVE_STRUCT_STAT_ST_BLOCKS
#define ST_BLKSIZE(statbuf) DEV_BSIZE
#if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
#define ST_NBLOCKS(statbuf) ((statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0))
#else /* !_POSIX_SOURCE && BSIZE */
#define ST_NBLOCKS(statbuf) (S_ISREG ((statbuf).st_mode) || S_ISDIR ((statbuf).st_mode) ? st_blocks ((statbuf).st_size) : 0)
#endif /* !_POSIX_SOURCE && BSIZE */
#else /* HAVE_STRUCT_STAT_ST_BLOCKS */
/* Some systems, like Sequents, return st_blksize of 0 on pipes.
Also, when running `rsh hpux11-system cat any-file', cat would
determine that the output stream had an st_blksize of 2147421096.
So here we arbitrarily limit the `optimal' block size to 4MB.
If anyone knows of a system for which the legitimate value for
st_blksize can exceed 4MB, please report it as a bug in this code. */
#define ST_BLKSIZE(statbuf) ((0 < (statbuf).st_blksize && (statbuf).st_blksize <= (1 << 22)) /* 4MiB */ ? (statbuf).st_blksize : DEV_BSIZE)
#if defined hpux || defined __hpux__ || defined __hpux
/* HP-UX counts st_blocks in 1024-byte units.
This loses when mixing HP-UX and BSD filesystems with NFS. */
#define ST_NBLOCKSIZE 1024
#else /* !hpux */
#if defined _AIX && defined _I386
/* AIX PS/2 counts st_blocks in 4K units. */
#define ST_NBLOCKSIZE (4 * 1024)
#else /* not AIX PS/2 */
#if defined _CRAY
#define ST_NBLOCKS(statbuf) (S_ISREG ((statbuf).st_mode) || S_ISDIR ((statbuf).st_mode) ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
#endif /* _CRAY */
#endif /* not AIX PS/2 */
#endif /* !hpux */
#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
#ifndef ST_NBLOCKS
#define ST_NBLOCKS(statbuf) ((statbuf).st_blocks)
#endif
#ifndef ST_NBLOCKSIZE
#define ST_NBLOCKSIZE 512
#endif
//some GNU systems don't support big files for some reason
#ifdef __USE_LARGEFILE64 //see dirent.h
#define dirent dirent64
#define scandir scandir64
#define stat stat64
#define statstruct stat64
#define lstat lstat64
#define readdir readdir64
#endif
#ifndef NULL
#define NULL 0
#endif
#include <errno.h>
static void
outputError( TQCString path )
{
///show error message that stat or opendir may give
#define out( s ) error() << s ": " << path << endl; break
switch( errno ) {
case EACCES:
out( "Inadequate access permisions" );
case EMFILE:
out( "Too many file descriptors in use by Filelight" );
case ENFILE:
out( "Too many files are currently open in the system" );
case ENOENT:
out( "A component of the path does not exist, or the path is an empty string" );
case ENOMEM:
out( "Insufficient memory to complete the operation" );
case ENOTDIR:
out( "A component of the path is not a directory" );
case EBADF:
out( "Bad file descriptor" );
case EFAULT:
out( "Bad address" );
case ELOOP: //NOTE shouldn't ever happen
out( "Too many symbolic links encountered while traversing the path" );
case ENAMETOOLONG:
out( "File name too long" );
}
#undef out
}
Directory*
LocalLister::scan( const TQCString &path, const TQCString &dirname )
{
Directory *cwd = new Directory( dirname );
DIR *dir = opendir( path );
if( !dir ) {
outputError( path );
return cwd;
}
struct stat statbuf;
dirent *ent;
while ((ent = readdir( dir )))
{
if( ScanManager::s_abort )
return cwd;
if( qstrcmp( ent->d_name, "." ) == 0 || qstrcmp( ent->d_name, ".." ) == 0 )
continue;
TQCString new_path = path; new_path += ent->d_name;
//get file information
if( lstat( new_path, &statbuf ) == -1 ) {
outputError( new_path );
continue;
}
if( S_ISLNK( statbuf.st_mode ) ||
S_ISCHR( statbuf.st_mode ) ||
S_ISBLK( statbuf.st_mode ) ||
S_ISFIFO( statbuf.st_mode ) ||
S_ISSOCK( statbuf.st_mode ) )
{
continue;
}
if( S_ISREG( statbuf.st_mode ) ) //file
//using units of KiB as 32bit max is 4GiB and 64bit ints are expensive
cwd->append( ent->d_name, (ST_NBLOCKS( statbuf ) * ST_NBLOCKSIZE) / 1024 );
else if( S_ISDIR( statbuf.st_mode ) ) //directory
{
Directory *d = 0;
TQCString new_dirname = ent->d_name;
new_dirname += '/';
new_path += '/';
//check to see if we've scanned this section already
for( Iterator<Directory> it = m_trees->iterator(); it != m_trees->end(); ++it )
{
if( new_path == (*it)->name8Bit() )
{
debug() << "Tree pre-completed: " << (*it)->name() << "\n";
d = it.remove();
ScanManager::s_files += d->children();
//**** ideally don't have this redundant extra somehow
cwd->append( d, new_dirname );
}
}
if( !d ) //then scan
if ((d = scan( new_path, new_dirname ))) //then scan was successful
cwd->append( d );
}
++ScanManager::s_files;
}
closedir( dir );
return cwd;
}
bool
LocalLister::readMounts()
{
#define INFO_PARTITIONS "/proc/partitions"
#define INFO_MOUNTED_PARTITIONS "/etc/mtab" /* on Linux... */
//**** SHAMBLES
// ** mtab should have priority as mount points don't have to follow fstab
// ** no removable media detection
// ** no updates if mounts change
// ** you want a KDE extension that handles this for you really
struct fstab *fstab_ent;
#ifdef HAVE_MNTENT_H
struct mntent *mnt_ent;
#endif
TQString str;
#ifdef HAVE_MNTENT_H
FILE *fp;
if( setfsent() == 0 || !( fp = setmntent( INFO_MOUNTED_PARTITIONS, "r" ) ) )
#else
if( setfsent() == 0 )
#endif
return false;
#define FS_NAME fstab_ent->fs_spec // device-name
#define FS_FILE fstab_ent->fs_file // mount-point
#define FS_TYPE fstab_ent->fs_vfstype // fs-type
#define FS_MNTOPS fstab_ent->fs_mntops // mount-options
TQStringList remoteFsTypes;
remoteFsTypes << "smbfs" ;
#ifdef MNTTYPE_NFS
remoteFsTypes << MNTTYPE_NFS;
#else
remoteFsTypes << "nfs";
#endif
// What about afs?
while( (fstab_ent = getfsent()) != NULL )
{
str = TQString( FS_FILE );
if( str == "/" ) continue;
str += '/';
if( remoteFsTypes.contains( FS_TYPE ) )
s_remoteMounts.append( str ); //**** NO! can't be sure won't have trailing slash, need to do a check first dummy!!
else
s_localMounts.append( str ); //**** NO! can't be sure won't have trailing slash, need to do a check first dummy!!
kdDebug() << "FSTAB: " << FS_TYPE << "\n";
}
endfsent(); /* close fstab.. */
#undef FS_NAME
#undef FS_FILE
#undef FS_TYPE
#undef FS_MNTOPS
#define FS_NAME mnt_ent->mnt_fsname // device-name
#define FS_FILE mnt_ent->mnt_dir // mount-point
#define FS_TYPE mnt_ent->mnt_type // fs-type
#define FS_MNTOPS mnt_ent->mnt_opts // mount-options
//scan mtab, **** mtab should take priority, but currently it isn't
#ifdef HAVE_MNTENT_H
while( ( mnt_ent = getmntent( fp ) ) != NULL )
{
bool b = false;
str = TQString( FS_FILE );
if( str == "/" ) continue;
str += "/";
if( remoteFsTypes.contains( FS_TYPE ) )
if( b = !s_remoteMounts.contains( str ) )
s_remoteMounts.append( str ); //**** NO! can't be sure won't have trailing slash, need to do a check first dummy!!
else if( b = !s_localMounts.contains( str ) )
s_localMounts.append( str ); //**** NO! can't be sure won't have trailing slash, need to do a check first dummy!!
if( b ) kdDebug() << "MTAB: " << FS_TYPE << "\n";
}
endmntent( fp ); /* close mtab.. */
#endif
return true;
}
}
|