void FileSystem::displayResults() { vector<DirInfo*>::iterator it; DirInfo* dir; cout << "Directory Tree: " << endl; displayTree(0,this->root); for(it = allDirs.begin(); it != allDirs.end(); ++it) { dir = (*it); if( dir->getNumSimilar() > 0 ) { dir->printInfo(); /* // Marks for diplicate listing dir->isStarred(true); displayTree(0,this->root); // Un-Marks in case of no diplicate listing dir->isStarred(false); */ } } }
/** * FileSystem * * if path exists, initialize FileSystem class * * @param path root node to analyze */ FileSystem::FileSystem(string path) { // Display debug messages debug = true; // Create a boost path object boost::filesystem::path p(path); // Counts number of duplicate directories discovered this->dupDirCount = 0; try { // does path exist if( exists(p) ) { // is path a directory if( is_directory(p) ) { try { DirInfo* node = new DirInfo( p.filename().string(), p.parent_path().string() ); node->isDir(true); debugPrint("root path = "+node->getPath()); // Keeps track of node to deconstruct pointer allNodes.push_back(node); // All directories list (for quick dir operations) allDirs.push_back(node); // Spefiy filesystem root and path root = node; path = node->getPath(); //TODO Might remove... depth = 0; } catch (bad_alloc&) { throw "EXPN_BAD_NODE"; } } else { cout << "Error: Not a valid directory"; throw "EXPN_INVALID_ROOT"; } } else { cout << "Error: " << p << " does not exist." << endl; throw "EXPN_PATH_DNE"; } } catch ( const boost::filesystem::filesystem_error& ex ) { cout << ex.what() << endl; } }
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 CacheReader::addItem() { if ( fieldsCount() < 4 ) { _ok = false; emit error(); return; } int n = 0; char * type = field( n++ ); char * raw_path = field( n++ ); char * size_str = field( n++ ); char * mtime_str = field( n++ ); char * blocks_str = 0; char * links_str = 0; while ( fieldsCount() > n+1 ) { char * keyword = field( n++ ); char * val_str = field( n++ ); if ( strcasecmp( keyword, "blocks:" ) == 0 ) blocks_str = val_str; if ( strcasecmp( keyword, "links:" ) == 0 ) links_str = val_str; } // Type mode_t mode = S_IFREG; if ( strcasecmp( type, "F" ) == 0 ) mode = S_IFREG; else if ( strcasecmp( type, "D" ) == 0 ) mode = S_IFDIR; else if ( strcasecmp( type, "L" ) == 0 ) mode = S_IFLNK; else if ( strcasecmp( type, "BlockDev" ) == 0 ) mode = S_IFBLK; else if ( strcasecmp( type, "CharDev" ) == 0 ) mode = S_IFCHR; else if ( strcasecmp( type, "FIFO" ) == 0 ) mode = S_IFIFO; else if ( strcasecmp( type, "Socket" ) == 0 ) mode = S_IFSOCK; // Path if ( *raw_path == '/' ) _lastDir = 0; // Size char * end = 0; FileSize size = strtoll( size_str, &end, 10 ); if ( end ) { switch ( *end ) { case 'K': size *= KB; break; case 'M': size *= MB; break; case 'G': size *= GB; break; case 'T': size *= TB; break; default: break; } } // MTime time_t mtime = strtol( mtime_str, 0, 0 ); // Blocks FileSize blocks = blocks_str ? strtoll( blocks_str, 0, 10 ) : -1; // Links int links = links_str ? atoi( links_str ) : 1; // // Create a new item // char * raw_name = raw_path; if ( *raw_path == '/' && _tree->root() ) { // Split raw_path in path + name raw_name = strrchr( raw_path, '/' ); if ( raw_name ) *raw_name++ = 0; // Overwrite the last '/' with 0 byte - split string there else // No '/' found raw_name = raw_path; } // Using a protocol part to avoid directory names with a colon ":" // being cut off because it looks like a URL protocol. QByteArray protocol = "foo:"; QString path = QUrl::fromEncoded( protocol + QByteArray( raw_path ) ).path(); QString name = QUrl::fromEncoded( protocol + QByteArray( raw_name ) ).path(); if ( _lastExcludedDir ) { if ( path.startsWith( _lastExcludedDirUrl ) ) { // logDebug() << "Excluding " << path << "/" << name << endl; return; } } // Find parent in tree DirInfo * parent = _lastDir; if ( ! parent && _tree->root() ) { if ( ! _tree->root()->hasChildren() ) parent = _tree->root(); // Try the easy way first - the starting point of this cache if ( ! parent && _toplevel ) parent = dynamic_cast<DirInfo *> ( _toplevel->locate( path ) ); // Fallback: Search the entire tree if ( ! parent ) parent = dynamic_cast<DirInfo *> ( _tree->locate( path ) ); if ( ! parent ) // Still nothing? { logError() << _fileName << ":" << _lineNo << ": " << "Could not locate parent " << path << endl; return; // Ignore this cache line completely } } if ( strcasecmp( type, "D" ) == 0 ) { QString url = ( parent == _tree->root() ) ? path + "/" + name : name; // logDebug() << "Creating DirInfo for " << url << " with parent " << parent << endl; DirInfo * dir = new DirInfo( _tree, parent, url, mode, size, mtime ); dir->setReadState( DirReading ); _lastDir = dir; if ( parent ) parent->insertChild( dir ); if ( ! _tree->root() ) { _tree->setRoot( dir ); _toplevel = dir; } if ( ! _toplevel ) _toplevel = dir; _tree->childAddedNotify( dir ); if ( dir != _toplevel ) { if ( ExcludeRules::instance()->match( dir->url(), dir->name() ) ) { logDebug() << "Excluding " << name << endl; dir->setExcluded(); dir->setReadState( DirOnRequestOnly ); _tree->sendFinalizeLocal( dir ); dir->finalizeLocal(); _tree->sendReadJobFinished( dir ); _lastExcludedDir = dir; _lastExcludedDirUrl = _lastExcludedDir->url(); _lastDir = 0; } } } else { if ( parent ) { // logDebug() << "Creating FileInfo for " << parent->debugUrl() << "/" << name << endl; FileInfo * item = new FileInfo( _tree, parent, name, mode, size, mtime, blocks, links ); parent->insertChild( item ); _tree->childAddedNotify( item ); } else { logError() << _fileName << ":" << _lineNo << ": " << "No parent for item " << name << endl; } } }
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! }
/** * scan * * starts from the given node and iterates through all * child directories and builds vectors of all file * and directory nodes in the FS * * @param pnode pointer to DirInfo node to scan */ bool FileSystem::scan(DirInfo* pnode) { debugPrint("Scanning Node: " + pnode->getPath()); // Check if given path exists if ( !boost::filesystem::exists( pnode->getPath() ) ) { cout << pnode->getPath() << " doesn't exist" << endl; return false; } if (pnode->isHidden()) { return false; } // Create a boost directory iterator boost::filesystem::directory_iterator end_itr; try { for ( boost::filesystem::directory_iterator itr( pnode->getPath() ); itr != end_itr; ++itr ) { // Is iterated object a directory if ( is_directory(itr->status()) ) { DirInfo* dir = new DirInfo(itr->path().filename().string(), pnode); // Keeps track of node to deconstruct pointer allNodes.push_back(dir); // All directories list (for quick dir operations) allDirs.push_back(dir); // Add this node to it's parent children list pnode->addChild(dir); // Create a boost path object to extract fs info boost::filesystem::path p(dir->getPath()); dir->setModifyTime( last_write_time(p) ); dir->isDir(true); // Recursively scan dirs scan(dir); // directory size is only available after all dir and files add their // sizes to their parent dirs to be added here pnode->addSize(dir->getSize()); // If iterated object is not directory, then it must be a file } else { FileInfo* file = new FileInfo(itr->path().filename().string(), pnode); // Keeps track of node to deconstruct pointer allNodes.push_back(file); // All files list (for quick file operations) allFiles.push_back(file); // Add this node to it's parent children list pnode->addChild(file); // Create a boost path object to extract fs info boost::filesystem::path p(file->getPath()); try { file->setSize( file_size(p) ); } catch (boost::filesystem::filesystem_error err) { file->setSize( 0 ); } try { file->setModifyTime( last_write_time(p) ); } catch (boost::filesystem::filesystem_error err) { file->setModifyTime( 0 ); } // Update parent size file->getParent()->addSize(file->getSize()); } } } catch (boost::filesystem::filesystem_error) { cout << "Cannot open file: " << pnode->getPath() << ". Permission denied!" << endl; } return true; }