void CollectionScanner::doJob() //SLOT { std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"; std::cout << "<scanner>"; QStringList entries; if( m_restart ) { QFile logFile( m_logfile ); logFile.open( IO_ReadOnly ); QString lastFile = logFile.readAll(); QFile folderFile( amaroK::saveLocation( QString::null ) + "collection_scan.files" ); folderFile.open( IO_ReadOnly ); entries = QStringList::split( "\n", folderFile.readAll() ); for( int count = entries.findIndex( lastFile ) + 1; count; --count ) entries.pop_front(); // debug() << "Restarting at: " << entries.front() << endl; } else { foreachType( QStringList, m_folders ) { if( (*it).isEmpty() ) //apparently somewhere empty strings get into the mix //which results in a full-system scan! Which we can't allow continue; QString dir = *it; if( !dir.endsWith( "/" ) ) dir += '/'; readDir( dir, entries ); } QFile folderFile( amaroK::saveLocation( QString::null ) + "collection_scan.files" ); folderFile.open( IO_WriteOnly ); QTextStream stream( &folderFile ); stream << entries.join( "\n" ); folderFile.close(); } if( !entries.isEmpty() ) { if( !m_restart ) { AttributeMap attributes; attributes["count"] = QString::number( entries.count() ); writeElement( "itemcount", attributes ); } scanFiles( entries ); } std::cout << "</scanner>" << std::endl; quit(); }
FileProvider::FileProvider( const std::string &root ) { scanFiles( root, _files ); printf( "[FileProvider] Scan files: %d\n", _files.size() ); _scan = 0; _exit = false; _loop = true; }
bool FileSystemWatcher::watch(const Path &p) { Path path = p; assert(!path.isEmpty()); std::lock_guard<std::mutex> lock(mMutex); const Path::Type type = path.type(); uint32_t flags = 0; switch (type) { case Path::File: path = path.parentDir(); // fall through case Path::Directory: flags = NOTE_RENAME|NOTE_DELETE|NOTE_EXTEND|NOTE_WRITE|NOTE_ATTRIB|NOTE_REVOKE; break; default: error("FileSystemWatcher::watch() '%s' doesn't seem to be watchable", path.constData()); return false; } if (!path.endsWith('/')) path += '/'; if (isWatching(path)) return false; int ret = ::open(path.nullTerminated(), O_RDONLY); //static int cnt = 0; //printf("wanting to watch [%05d] %s : %d\n", ++cnt, path.nullTerminated(), ret); if (ret != -1) { struct kevent change; struct timespec nullts = { 0, 0 }; EV_SET(&change, ret, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, flags, 0, 0); if (::kevent(mFd, &change, 1, 0, 0, &nullts) == -1) { // bad things have happened error("FileSystemWatcher::watch() kevent failed for '%s' (%d) %s", path.constData(), errno, Rct::strerror().constData()); ::close(ret); return false; } } if (ret == -1) { error("FileSystemWatcher::watch() watch failed for '%s' (%d) %s", path.constData(), errno, Rct::strerror().constData()); return false; } mWatchedByPath[path] = ret; mWatchedById[ret] = path; FSUserData data; data.watcher = this; path.visit([&data](const Path &p) { return scanFiles(p, &data); }); return true; }
uint8_t SFX::setFont(uint8_t font) { //Serial.print("setFont "); Serial.println(font); if (m_numFonts) { if (font != m_currentFont) { m_currentFont = font % m_numFonts; scanFiles(m_currentFont); } } else { m_currentFont = 0; } return m_currentFont; }
void FileProvider::scanFiles( const std::string &root, std::vector<std::string> &files ) { if (fs::exists( root )) { fs::directory_iterator end_itr; for (fs::directory_iterator itr( root ); itr != end_itr; ++itr) { if (fs::is_directory( itr->status() )) { scanFiles( itr->path().string(), files ); } else if (fs::is_regular_file( itr->status() )) { fs::path file = itr->path(); if (file.extension() == ".ts") { files.push_back( file.string() ); } } } } }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ListviewDelegate *delegate = new ListviewDelegate(); model = new QStandardItemModel(); this->setWindowFlags(Qt::FramelessWindowHint); ui->setupUi(this); ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->listView->setItemDelegate(delegate); ui->listView->setModel(model); scanFiles("/mnt/udisk"); on_allSongs_clicked(); currentSongIndex = -1; connect(&controller, SIGNAL(TimeChanged(QString,int)), this, SLOT(timeChanged(QString,int))); connect(&controller, SIGNAL(StatusChanged(bool)), this, SLOT(statusChanged(bool))); connect(&controller, SIGNAL(Finished()), this, SLOT(onFinished())); }
inline Error scanFiles(const FileInfo& fromRoot, const FileScannerOptions& options, tree<FileInfo>* pTree) { return scanFiles(pTree->set_head(fromRoot), options, pTree); }
// register a new file monitor Handle registerMonitor(const FilePath& filePath, bool recursive, const boost::function<bool(const FileInfo&)>& filter, const Callbacks& callbacks) { // allocate file path CFStringRef filePathRef = ::CFStringCreateWithCString( kCFAllocatorDefault, filePath.absolutePath().c_str(), kCFStringEncodingUTF8); if (filePathRef == NULL) { callbacks.onRegistrationError(systemError( boost::system::errc::not_enough_memory, ERROR_LOCATION)); return Handle(); } CFRefScope filePathRefScope(filePathRef); // allocate paths array CFArrayRef pathsArrayRef = ::CFArrayCreate(kCFAllocatorDefault, (const void **)&filePathRef, 1, NULL); if (pathsArrayRef == NULL) { callbacks.onRegistrationError(systemError( boost::system::errc::not_enough_memory, ERROR_LOCATION)); return Handle(); } CFRefScope pathsArrayRefScope(pathsArrayRef); // create and allocate FileEventContext (create auto-ptr in case we // return early, we'll call release later before returning) FileEventContext* pContext = new FileEventContext(); pContext->rootPath = filePath; pContext->recursive = recursive; pContext->filter = filter; std::auto_ptr<FileEventContext> autoPtrContext(pContext); FSEventStreamContext context; context.version = 0; context.info = (void*) pContext; context.retain = NULL; context.release = NULL; context.copyDescription = NULL; // create the stream and save a reference to it pContext->streamRef = ::FSEventStreamCreate( kCFAllocatorDefault, &fileEventCallback, &context, pathsArrayRef, kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagWatchRoot); if (pContext->streamRef == NULL) { callbacks.onRegistrationError(systemError( boost::system::errc::no_stream_resources, ERROR_LOCATION)); return Handle(); } // schedule with the run loop ::FSEventStreamScheduleWithRunLoop(pContext->streamRef, ::CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); // start the event stream (check for errors and release if necessary if (!::FSEventStreamStart(pContext->streamRef)) { invalidateAndReleaseEventStream(pContext->streamRef); callbacks.onRegistrationError(systemError( boost::system::errc::no_stream_resources, ERROR_LOCATION)); return Handle(); } // scan the files Error error = scanFiles(FileInfo(filePath), recursive, filter, &pContext->fileTree); if (error) { // stop, invalidate, release stopInvalidateAndReleaseEventStream(pContext->streamRef); // return error callbacks.onRegistrationError(error); return Handle(); } // now that we have finished the file listing we know we have a valid // file-monitor so set the callbacks pContext->callbacks = callbacks; // we are going to pass the context pointer to the client (as the Handle) // so we release it here to relinquish ownership autoPtrContext.release(); // notify the caller that we have successfully registered callbacks.onRegistered(pContext->handle, pContext->fileTree); // return the handle return pContext->handle; }
void CollectionScanner::doJob() //SLOT { if( !m_restart ) { std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"; std::cout << "<scanner>"; } QStringList entries; if( m_restart ) { QFile logFile( m_logfile ); QString lastFile; if( logFile.open( QIODevice::ReadOnly ) ) { QTextStream logStream; logStream.setDevice(&logFile); logStream.setCodec(QTextCodec::codecForName( "UTF-8" ) ); lastFile = logStream.readAll(); logFile.close(); } QFile folderFile; if( !m_batch ) folderFile.setFileName( m_saveLocation + "collection_scan.files" ); else if( m_incremental ) folderFile.setFileName( "amarokcollectionscanner_batchincrementalscan.files" ); else folderFile.setFileName( "amarokcollectionscanner_batchfullscan.files" ); if( folderFile.open( QIODevice::ReadOnly ) ) { QTextStream folderStream; folderStream.setDevice(&folderFile); folderStream.setCodec( QTextCodec::codecForName( "UTF-8" ) ); entries = folderStream.readAll().split( '\n' ); } for( int count = entries.indexOf( lastFile ) + 1; count; --count ) entries.pop_front(); } else { foreach( QString dir, m_folders ) // krazy:exclude=foreach { if( dir.isEmpty() ) //apparently somewhere empty strings get into the mix //which results in a full-system scan! Which we can't allow continue; // Make sure that all paths are absolute, not relative if( QDir::isRelativePath( dir ) ) dir = QDir::cleanPath( QDir::currentPath() + '/' + dir ); if( !dir.endsWith( '/' ) ) dir += '/'; readDir( dir, entries ); } QFile folderFile; if( !m_batch ) folderFile.setFileName( m_saveLocation + "collection_scan.files" ); else if( m_incremental ) folderFile.setFileName( "amarokcollectionscanner_batchincrementalscan.files" ); else folderFile.setFileName( "amarokcollectionscanner_batchfullscan.files" ); if ( folderFile.open( QIODevice::WriteOnly ) ) { QTextStream stream( &folderFile ); stream.setCodec( QTextCodec::codecForName("UTF-8") ); stream << entries.join( "\n" ); folderFile.close(); } } if( !entries.isEmpty() ) { if( !m_restart ) { AttributeHash attributes; attributes["count"] = QString::number( entries.count() ); writeElement( "itemcount", attributes ); } scanFiles( entries ); } std::cout << "</scanner>" << std::endl; if( m_batch ) { if( m_incremental ) { QFile::remove( "amarokcollectionscanner_batchincrementalscan.files" ); QFile::remove( "amarokcollectionscanner_batchincrementalscan.log" ); } else { QFile::remove( "amarokcollectionscanner_batchfullscan.files" ); QFile::remove( "amarokcollectionscanner_batchfullscan.log" ); } } quit(); }
Error discoverAndProcessFileChanges( const FileInfo& fileInfo, bool recursive, const boost::function<bool(const FileInfo&)>& filter, const boost::function<Error(const FileInfo&)>& onBeforeScanDir, tree<FileInfo>* pTree, const boost::function<void(const std::vector<FileChangeEvent>&)>& onFilesChanged) { // find this path in our fileTree tree<FileInfo>::iterator it = std::find(pTree->begin(), pTree->end(), fileInfo); // if we don't find it then it may have been excluded by a filter, just bail if (it == pTree->end()) return Success(); // scan this directory into a new tree which we can compare to the old tree tree<FileInfo> subdirTree; FileScannerOptions options; options.recursive = recursive; options.yield = true; options.filter = filter; options.onBeforeScanDir = onBeforeScanDir; Error error = scanFiles(fileInfo, options, &subdirTree); if (error) return error; // handle recursive vs. non-recursive scan differnetly if (recursive) { // check for changes on full subtree std::vector<FileChangeEvent> fileChanges; tree<FileInfo> existingSubtree(it); collectFileChangeEvents(existingSubtree.begin(), existingSubtree.end(), subdirTree.begin(), subdirTree.end(), &fileChanges); // fire events onFilesChanged(fileChanges); // wholesale replace subtree pTree->insert_subtree_after(it, subdirTree.begin()); pTree->erase(it); } else { // scan for changes on just the children std::vector<FileChangeEvent> childrenFileChanges; collectFileChangeEvents(pTree->begin(it), pTree->end(it), subdirTree.begin(subdirTree.begin()), subdirTree.end(subdirTree.begin()), &childrenFileChanges); // build up actual file changes and mutate the tree as appropriate std::vector<FileChangeEvent> fileChanges; BOOST_FOREACH(const FileChangeEvent& fileChange, childrenFileChanges) { switch(fileChange.type()) { case FileChangeEvent::FileAdded: { Error error = processFileAdded(it, fileChange, recursive, filter, pTree, &fileChanges); if (error) LOG_ERROR(error); break; } case FileChangeEvent::FileModified: { processFileModified(it, fileChange, pTree, &fileChanges); break; } case FileChangeEvent::FileRemoved: { processFileRemoved(it, fileChange, recursive, pTree, &fileChanges); break; } case FileChangeEvent::None: default: break; } } // fire events onFilesChanged(fileChanges); } return Success(); }