FileInfo * LocalDirReadJob::stat( const QString & url, DirTree * tree, DirInfo * parent ) { struct stat statInfo; logDebug() << "url: \"" << url << "\"" << endl; if ( lstat( url.toUtf8(), &statInfo ) == 0 ) // lstat() OK { if ( S_ISDIR( statInfo.st_mode ) ) // directory? { DirInfo * dir = new DirInfo( url, &statInfo, tree, parent ); CHECK_NEW( dir ); if ( parent ) parent->insertChild( dir ); if ( dir && parent && ! tree->isTopLevel( dir ) && dir->device() != parent->device() ) { logDebug() << dir << " is a mount point" << endl; dir->setMountPoint(); } return dir; } else // no directory { FileInfo * file = new FileInfo( url, &statInfo, tree, parent ); CHECK_NEW( file ); if ( parent ) parent->insertChild( file ); return file; } } else // lstat() failed { logError() << "lstat() failed for \"" << url << "\"" << endl; return 0; } }
void LocalDirReadJob::startReading() { struct dirent * entry; struct stat statInfo; QString dirName = _dir->url(); QString defaultCacheName = DEFAULT_CACHE_NAME; // logDebug() << _dir << endl; if ( ( _diskDir = opendir( dirName.toUtf8() ) ) ) { _dir->setReadState( DirReading ); while ( ( entry = readdir( _diskDir ) ) ) { QString entryName = entry->d_name; if ( entryName != "." && entryName != ".." ) { QString fullName = dirName + "/" + entryName; if ( lstat( fullName.toUtf8(), &statInfo ) == 0 ) // lstat() OK { if ( S_ISDIR( statInfo.st_mode ) ) // directory child? { DirInfo *subDir = new DirInfo( entryName, &statInfo, _tree, _dir ); CHECK_NEW( subDir ); _dir->insertChild( subDir ); childAdded( subDir ); if ( ExcludeRules::instance()->match( entryName ) ) { subDir->setExcluded(); subDir->setReadState( DirOnRequestOnly ); finishReading( subDir ); } else // No exclude rule matched { if ( _dir->device() == subDir->device() ) // normal case { LocalDirReadJob * job = new LocalDirReadJob( _tree, subDir ); CHECK_NEW( job ); _tree->addJob( job ); } else // The subdirectory we just found is a mount point. { logDebug() << "Found mount point " << subDir << endl; subDir->setMountPoint(); if ( _tree->crossFileSystems() ) { LocalDirReadJob * job = new LocalDirReadJob( _tree, subDir ); CHECK_NEW( job ); _tree->addJob( job ); } else { subDir->setReadState( DirOnRequestOnly ); finishReading( subDir ); } } } } else // non-directory child { if ( entryName == defaultCacheName ) // .qdirstat.cache.gz found? { logDebug() << "Found cache file " << defaultCacheName << endl; // // Read content of this subdirectory from cache file // CacheReadJob * cacheReadJob = new CacheReadJob( _tree, _dir->parent(), fullName ); CHECK_NEW( cacheReadJob ); QString firstDirInCache = cacheReadJob->reader()->firstDir(); if ( firstDirInCache == dirName ) // Does this cache file match this directory? { logDebug() << "Using cache file " << fullName << " for " << dirName << endl; cacheReadJob->reader()->rewind(); // Read offset was moved by firstDir() _tree->addJob( cacheReadJob ); // Job queue will assume ownership of cacheReadJob if ( _dir->parent() ) _dir->parent()->setReadState( DirReading ); // // Clean up partially read directory content // DirTree * tree = _tree; // Copy data members to local variables: DirInfo * dir = _dir; // This object will be deleted soon by killAll() _queue->killAll( _dir, cacheReadJob ); // Will delete this job as well! // All data members of this object are invalid from here on! logDebug() << "Deleting subtree " << dir << endl; tree->deleteSubtree( dir ); return; } else { logWarning() << "NOT using cache file " << fullName << " with dir " << firstDirInCache << " for " << dirName << endl; delete cacheReadJob; } } else { FileInfo *child = new FileInfo( entryName, &statInfo, _tree, _dir ); CHECK_NEW( child ); _dir->insertChild( child ); childAdded( child ); } } } else // lstat() error { logWarning() << "lstat(" << fullName << ") failed: " << strerror( errno ) << endl; /* * Not much we can do when lstat() didn't work; let's at * least create an (almost empty) entry as a placeholder. */ DirInfo *child = new DirInfo( _tree, _dir, entry->d_name ); CHECK_NEW( child ); child->setReadState( DirError ); _dir->insertChild( child ); childAdded( child ); } } } closedir( _diskDir ); _dir->setReadState( DirFinished ); finishReading( _dir ); } else { _dir->setReadState( DirError ); logWarning() << "opendir(" << dirName << ") failed" << endl; // opendir() doesn't set 'errno' according to POSIX :-( finishReading( _dir ); } finished(); // Don't add anything after finished() since this deletes this job! }