/* nm_filetype_thread.cc * This file belongs to Worker, a file manager for UN*X/X11. * Copyright (C) 2011,2013 Ralf Hoffmann. * You can contact me at: ralf@boomerangsworld.de * or http://www.boomerangsworld.de/worker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "nm_filetype_thread.hh" #include "simplelist.hh" #include "fileentry.hh" #include "aguix/lowlevelfunc.h" #include "datei.h" #include "fileentry_typecheck.hh" #include "wcfiletype.hh" #include "worker.h" #include "wconfig.h" NM_Filetype_Thread::NM_Filetype_Thread() : m_worker( NULL ), m_running( 0 ), m_order( THREAD_STOP ), m_status( THREAD_STOP ) { m_filetype_copy.filetypes = new List(); } NM_Filetype_Thread::~NM_Filetype_Thread() { result_list_clear(); clear_filetypes(); delete m_filetype_copy.filetypes; } void NM_Filetype_Thread::setWorker( Worker *worker ) { m_worker = worker; } int NM_Filetype_Thread::slave_checkFiletype( const check_entry_t &entry, check_filetype_result &res_return ) { FileEntry *fe1; int pos = -1; WCFiletype *ft, *parentft; std::vector v; check_filetype_result res; res.entry = entry; m_filetype_copy.filetype_ex.lock(); fe1 = new FileEntry(); fe1->fullname = dupstring( entry.fullname.c_str() ); fe1->name = Datei::getFilenameFromPath( entry.fullname.c_str() ); //TODO start check even for corrupt entries without info? if( fe1->readInfos() == 0 ) { ft = FileEntryTypeCheck::checkFiletype( *fe1, m_filetype_copy.filetypes, entry.dont_check_content, &condparser ); if ( ft != NULL ) { // first get vector with filetype position for each child std::vector *tv = ft->getTypePos(); if ( tv ) { v = *tv; // now find root filetype for ( parentft = ft; parentft->getParentType() != NULL; parentft = parentft->getParentType() ); pos = m_filetype_copy.filetypes->getIndex( parentft ); if ( pos >= 0 ) { v.push_back( (unsigned int)pos ); } else { v.clear(); } delete tv; } } } res.ft_index = v; if ( fe1->getCustomColorSet() != 0 ) { res.custom_color = fe1->getCustomColor(); } if ( ! fe1->getFiletypeFileOutput().empty() ) { res.filetype_file_output = fe1->getFiletypeFileOutput(); res.mime_type = fe1->getMimeType(); } delete fe1; res_return = res; m_filetype_copy.filetype_ex.unlock(); return 0; } int NM_Filetype_Thread::switchOrder( thread_order_t neworder ) { if ( m_order != neworder ) { m_ordervar_cv.lock(); m_order = neworder; m_ordervar_cv.signal(); m_ordervar_cv.unlock(); m_statusvar_cv.lock(); while ( m_status != neworder ) { m_statusvar_cv.wait(); } m_statusvar_cv.unlock(); } return 0; } int NM_Filetype_Thread::switchStatus( thread_order_t newstatus ) { m_statusvar_cv.lock(); m_status = newstatus; m_statusvar_cv.signal(); m_statusvar_cv.unlock(); return 0; } int NM_Filetype_Thread::run() { bool ende; int erg; if ( m_running != 0 ) { fprintf( stderr, "Worker: another thread already running!\n"); return 1; } m_running = 1; #ifdef DEBUG printf("entering slave handler\n"); #endif for( ende = false; ende == false; ) { switch ( m_status ) { case NM_Filetype_Thread::THREAD_RUN: #ifdef DEBUG printf("waiting for element\n"); #endif m_ordervar_cv.lock(); // wait for next element or stop while ( m_entries_to_check.empty() && m_order == NM_Filetype_Thread::THREAD_RUN ) m_ordervar_cv.wait(); #ifdef DEBUG printf("wait finished\n"); #endif if ( m_order != NM_Filetype_Thread::THREAD_RUN ) { // new command // switch mode for new command if ( m_order == NM_Filetype_Thread::THREAD_EXIT ) { switchStatus( NM_Filetype_Thread::THREAD_EXIT ); ende = true; } else if ( m_order == NM_Filetype_Thread::THREAD_STOP ) { switchStatus( NM_Filetype_Thread::THREAD_STOP ); } m_ordervar_cv.unlock(); } else { // an element to check check_entry_t entry; if ( ! m_entries_to_check.empty() ) { entry = m_entries_to_check.front(); m_entries_to_check.pop_front(); erg = 0; } else { erg = 1; } m_ordervar_cv.unlock(); if ( erg == 0 && ! entry.fullname.empty() ) { NM_Filetype_Thread::check_filetype_result res; #ifdef DEBUG // printf("erkenne %s\n",filename); #endif slave_checkFiletype( entry, res ); m_result_list.lock(); m_result_list.put_locked( res ); m_result_list.unlock(); if ( m_worker ) m_worker->wakeupMainLoop(); } } break; case NM_Filetype_Thread::THREAD_STOP: m_ordervar_cv.lock(); while ( m_order == NM_Filetype_Thread::THREAD_STOP ) { m_ordervar_cv.wait(); } m_ordervar_cv.unlock(); switchStatus( NM_Filetype_Thread::THREAD_RUN ); break; default: break; } } #ifdef DEBUG printf("leaving slave handler\n"); #endif return 0; } NM_Filetype_Thread::result_list::result_list() { } NM_Filetype_Thread::result_list::~result_list() { lock(); while ( isEmpty_locked() == false ) { remove_locked(); } unlock(); } bool NM_Filetype_Thread::result_list::isEmpty_locked() { if ( entries.empty() ) return true; return false; } int NM_Filetype_Thread::result_list::put_locked( check_filetype_result elem ) { entries.push_back( elem ); return 0; } NM_Filetype_Thread::check_filetype_result NM_Filetype_Thread::result_list::remove_locked() { if ( entries.empty() ) { abort(); } auto te = entries.front(); entries.pop_front(); return te; } void NM_Filetype_Thread::result_list::lock() { ex.lock(); } void NM_Filetype_Thread::result_list::unlock() { ex.unlock(); } void NM_Filetype_Thread::result_list_clear() { m_result_list.lock(); while ( m_result_list.isEmpty_locked() == false ) { m_result_list.remove_locked(); } m_result_list.unlock(); } void NM_Filetype_Thread::result_list_lock() { m_result_list.lock(); } void NM_Filetype_Thread::result_list_unlock() { m_result_list.unlock(); } NM_Filetype_Thread::check_filetype_result NM_Filetype_Thread::result_list_remove_locked() { if ( m_result_list.isEmpty_locked() ) { abort(); } return m_result_list.remove_locked(); } bool NM_Filetype_Thread::result_list_is_empty_locked() { return m_result_list.isEmpty_locked(); } void NM_Filetype_Thread::putRequest( const check_entry_t &req ) { m_ordervar_cv.lock(); m_entries_to_check.push_back( req ); m_ordervar_cv.signal(); m_ordervar_cv.unlock(); } void NM_Filetype_Thread::clearRequests() { m_ordervar_cv.lock(); m_entries_to_check.clear(); m_ordervar_cv.signal(); m_ordervar_cv.unlock(); } void NM_Filetype_Thread::copy_filetypes( List *filetypes ) { WCFiletype *ft; int id; m_filetype_copy.filetype_ex.lock(); clear_filetypes(); id = filetypes->initEnum(); ft = (WCFiletype*)filetypes->getFirstElement( id ); while ( ft != NULL ) { m_filetype_copy.filetypes->addElement( ft->duplicate() ); ft = (WCFiletype*)filetypes->getNextElement( id ); } filetypes->closeEnum( id ); m_filetype_copy.filetype_ex.unlock(); } void NM_Filetype_Thread::clear_filetypes() { WCFiletype *ft; int id; m_filetype_copy.filetype_ex.lock(); id = m_filetype_copy.filetypes->initEnum(); ft = (WCFiletype*)m_filetype_copy.filetypes->getFirstElement( id ); while ( ft != NULL ) { delete ft; m_filetype_copy.filetypes->removeFirstElement(); ft = (WCFiletype*)m_filetype_copy.filetypes->getFirstElement( id ); } m_filetype_copy.filetypes->closeEnum( id ); m_filetype_copy.filetype_ex.unlock(); } WCFiletype *NM_Filetype_Thread::findFiletype( WConfig *config, const std::vector &v ) { unsigned int in1, p, tp; const std::list *subtype; std::list::const_iterator it1; WCFiletype *ft; ft = NULL; // check tree depth p = v.size(); if ( p > 0 ) { // we need at least the root type in1 = v[p - 1]; // get position ft = (WCFiletype*)config->getFiletypes()->getElementAt( in1 ); // root type, no problem if it is NULL // now go for each tree depth p = v.size(); if ( p > 1 ) { // we need one more depth at least p--; // skip root index do { // now for each depth p--; // jump to next level // p is correct entry in "v" if ( ft == NULL ) break; // get position in current tree depth in1 = v[p]; // now find subtype // because of std::list we need to iterate subtype = ft->getSubTypeList(); if ( subtype == NULL ) ft = NULL; // oops, index but no subtype else { // iterate through subtype list and find "in1" position for ( it1 = subtype->begin(), tp = 0; it1 != subtype->end(); it1++, tp++ ) { if ( tp == in1 ) break; } if ( it1 != subtype->end() ) { // found subtype at index "in1" ft = *it1; } else { ft = NULL; } } // stop when we processed last depth } while ( p > 0 ); } } return ft; }