1 /* nm_filetype_thread.cc
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2011,2013 Ralf Hoffmann.
4  * You can contact me at: ralf@boomerangsworld.de
5  *   or http://www.boomerangsworld.de/worker
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "nm_filetype_thread.hh"
23 #include "simplelist.hh"
24 #include "fileentry.hh"
25 #include "aguix/lowlevelfunc.h"
26 #include "datei.h"
27 #include "fileentry_typecheck.hh"
28 #include "wcfiletype.hh"
29 #include "worker.h"
30 #include "wconfig.h"
31 
NM_Filetype_Thread()32 NM_Filetype_Thread::NM_Filetype_Thread() : m_worker( NULL ), m_running( 0 ),
33                                            m_order( THREAD_STOP ), m_status( THREAD_STOP )
34 {
35     m_filetype_copy.filetypes = new List();
36 }
37 
~NM_Filetype_Thread()38 NM_Filetype_Thread::~NM_Filetype_Thread()
39 {
40     result_list_clear();
41 
42     clear_filetypes();
43     delete m_filetype_copy.filetypes;
44 }
45 
setWorker(Worker * worker)46 void NM_Filetype_Thread::setWorker( Worker *worker )
47 {
48     m_worker = worker;
49 }
50 
slave_checkFiletype(const check_entry_t & entry,check_filetype_result & res_return)51 int NM_Filetype_Thread::slave_checkFiletype( const check_entry_t &entry,
52                                              check_filetype_result &res_return )
53 {
54     FileEntry *fe1;
55     int pos = -1;
56     WCFiletype *ft, *parentft;
57     std::vector<unsigned int> v;
58     check_filetype_result res;
59 
60     res.entry = entry;
61 
62     m_filetype_copy.filetype_ex.lock();
63 
64     fe1 = new FileEntry();
65     fe1->fullname = dupstring( entry.fullname.c_str() );
66     fe1->name = Datei::getFilenameFromPath( entry.fullname.c_str() );
67 
68     //TODO start check even for corrupt entries without info?
69     if( fe1->readInfos() == 0 ) {
70         ft = FileEntryTypeCheck::checkFiletype( *fe1, m_filetype_copy.filetypes, entry.dont_check_content, &condparser );
71         if ( ft != NULL ) {
72             // first get vector with filetype position for each child
73             std::vector<unsigned int> *tv = ft->getTypePos();
74 
75             if ( tv ) {
76                 v = *tv;
77 
78                 // now find root filetype
79 
80                 for ( parentft = ft; parentft->getParentType() != NULL; parentft = parentft->getParentType() );
81                 pos = m_filetype_copy.filetypes->getIndex( parentft );
82                 if ( pos >= 0 ) {
83                     v.push_back( (unsigned int)pos );
84                 } else {
85                     v.clear();
86                 }
87 
88                 delete tv;
89             }
90         }
91     }
92     res.ft_index = v;
93 
94     if ( fe1->getCustomColorSet() != 0 ) {
95         res.custom_color = fe1->getCustomColor();
96     }
97 
98     if ( ! fe1->getFiletypeFileOutput().empty() ) {
99         res.filetype_file_output = fe1->getFiletypeFileOutput();
100         res.mime_type = fe1->getMimeType();
101     }
102 
103     delete fe1;
104 
105     res_return = res;
106 
107     m_filetype_copy.filetype_ex.unlock();
108     return 0;
109 }
110 
switchOrder(thread_order_t neworder)111 int NM_Filetype_Thread::switchOrder( thread_order_t neworder )
112 {
113     if ( m_order != neworder ) {
114         m_ordervar_cv.lock();
115         m_order = neworder;
116         m_ordervar_cv.signal();
117         m_ordervar_cv.unlock();
118 
119         m_statusvar_cv.lock();
120         while ( m_status != neworder ) {
121             m_statusvar_cv.wait();
122         }
123         m_statusvar_cv.unlock();
124     }
125     return 0;
126 }
127 
switchStatus(thread_order_t newstatus)128 int NM_Filetype_Thread::switchStatus( thread_order_t newstatus )
129 {
130     m_statusvar_cv.lock();
131     m_status = newstatus;
132     m_statusvar_cv.signal();
133     m_statusvar_cv.unlock();
134     return 0;
135 }
136 
run()137 int NM_Filetype_Thread::run()
138 {
139     bool ende;
140     int erg;
141 
142     if ( m_running != 0 ) {
143         fprintf( stderr, "Worker: another thread already running!\n");
144         return 1;
145     }
146     m_running = 1;
147 
148 #ifdef DEBUG
149     printf("entering slave handler\n");
150 #endif
151 
152     for( ende = false; ende == false; ) {
153 
154         switch ( m_status ) {
155             case NM_Filetype_Thread::THREAD_RUN:
156 #ifdef DEBUG
157                 printf("waiting for element\n");
158 #endif
159 
160                 m_ordervar_cv.lock();
161                 // wait for next element or stop
162                 while ( m_entries_to_check.empty() && m_order == NM_Filetype_Thread::THREAD_RUN )
163                     m_ordervar_cv.wait();
164 
165 #ifdef DEBUG
166                 printf("wait finished\n");
167 #endif
168 
169                 if ( m_order != NM_Filetype_Thread::THREAD_RUN ) {
170                     // new command
171                     // switch mode for new command
172                     if ( m_order == NM_Filetype_Thread::THREAD_EXIT ) {
173                         switchStatus( NM_Filetype_Thread::THREAD_EXIT );
174                         ende = true;
175                     } else if ( m_order == NM_Filetype_Thread::THREAD_STOP ) {
176                         switchStatus( NM_Filetype_Thread::THREAD_STOP );
177                     }
178                     m_ordervar_cv.unlock();
179                 } else {
180                     // an element to check
181                     check_entry_t entry;
182 
183                     if ( ! m_entries_to_check.empty() ) {
184                         entry = m_entries_to_check.front();
185                         m_entries_to_check.pop_front();
186                         erg = 0;
187                     } else {
188                         erg = 1;
189                     }
190                     m_ordervar_cv.unlock();
191 
192                     if ( erg == 0 && ! entry.fullname.empty() ) {
193                         NM_Filetype_Thread::check_filetype_result res;
194 #ifdef DEBUG
195                         //            printf("erkenne %s\n",filename);
196 #endif
197                         slave_checkFiletype( entry, res );
198                         m_result_list.lock();
199 
200                         m_result_list.put_locked( res );
201                         m_result_list.unlock();
202 
203                         if ( m_worker ) m_worker->wakeupMainLoop();
204                     }
205                 }
206                 break;
207             case NM_Filetype_Thread::THREAD_STOP:
208                 m_ordervar_cv.lock();
209                 while ( m_order == NM_Filetype_Thread::THREAD_STOP ) {
210                     m_ordervar_cv.wait();
211                 }
212                 m_ordervar_cv.unlock();
213                 switchStatus( NM_Filetype_Thread::THREAD_RUN );
214                 break;
215             default:
216                 break;
217         }
218     }
219 
220 #ifdef DEBUG
221     printf("leaving slave handler\n");
222 #endif
223     return 0;
224 }
225 
result_list()226 NM_Filetype_Thread::result_list::result_list()
227 {
228 }
229 
~result_list()230 NM_Filetype_Thread::result_list::~result_list()
231 {
232     lock();
233     while ( isEmpty_locked() == false ) {
234         remove_locked();
235     }
236     unlock();
237 }
238 
isEmpty_locked()239 bool NM_Filetype_Thread::result_list::isEmpty_locked()
240 {
241     if ( entries.empty() ) return true;
242     return false;
243 }
244 
put_locked(check_filetype_result elem)245 int NM_Filetype_Thread::result_list::put_locked( check_filetype_result elem )
246 {
247     entries.push_back( elem );
248     return 0;
249 }
250 
remove_locked()251 NM_Filetype_Thread::check_filetype_result NM_Filetype_Thread::result_list::remove_locked()
252 {
253     if ( entries.empty() ) {
254         abort();
255     }
256 
257     auto te = entries.front();
258     entries.pop_front();
259     return te;
260 }
261 
lock()262 void NM_Filetype_Thread::result_list::lock()
263 {
264     ex.lock();
265 }
266 
unlock()267 void NM_Filetype_Thread::result_list::unlock()
268 {
269     ex.unlock();
270 }
271 
result_list_clear()272 void NM_Filetype_Thread::result_list_clear()
273 {
274     m_result_list.lock();
275     while ( m_result_list.isEmpty_locked() == false ) {
276         m_result_list.remove_locked();
277     }
278     m_result_list.unlock();
279 }
280 
result_list_lock()281 void NM_Filetype_Thread::result_list_lock()
282 {
283     m_result_list.lock();
284 }
285 
result_list_unlock()286 void NM_Filetype_Thread::result_list_unlock()
287 {
288     m_result_list.unlock();
289 }
290 
result_list_remove_locked()291 NM_Filetype_Thread::check_filetype_result NM_Filetype_Thread::result_list_remove_locked()
292 {
293     if ( m_result_list.isEmpty_locked() ) {
294         abort();
295     }
296 
297     return m_result_list.remove_locked();
298 }
299 
result_list_is_empty_locked()300 bool NM_Filetype_Thread::result_list_is_empty_locked()
301 {
302     return m_result_list.isEmpty_locked();
303 }
304 
putRequest(const check_entry_t & req)305 void NM_Filetype_Thread::putRequest( const check_entry_t &req )
306 {
307     m_ordervar_cv.lock();
308 
309     m_entries_to_check.push_back( req );
310 
311     m_ordervar_cv.signal();
312     m_ordervar_cv.unlock();
313 }
314 
clearRequests()315 void NM_Filetype_Thread::clearRequests()
316 {
317     m_ordervar_cv.lock();
318     m_entries_to_check.clear();
319     m_ordervar_cv.signal();
320     m_ordervar_cv.unlock();
321 }
322 
copy_filetypes(List * filetypes)323 void NM_Filetype_Thread::copy_filetypes( List *filetypes )
324 {
325     WCFiletype *ft;
326     int id;
327 
328     m_filetype_copy.filetype_ex.lock();
329 
330     clear_filetypes();
331 
332     id = filetypes->initEnum();
333     ft = (WCFiletype*)filetypes->getFirstElement( id );
334     while ( ft != NULL ) {
335         m_filetype_copy.filetypes->addElement( ft->duplicate() );
336         ft = (WCFiletype*)filetypes->getNextElement( id );
337     }
338     filetypes->closeEnum( id );
339 
340     m_filetype_copy.filetype_ex.unlock();
341 }
342 
clear_filetypes()343 void NM_Filetype_Thread::clear_filetypes()
344 {
345     WCFiletype *ft;
346     int id;
347 
348     m_filetype_copy.filetype_ex.lock();
349 
350     id = m_filetype_copy.filetypes->initEnum();
351     ft = (WCFiletype*)m_filetype_copy.filetypes->getFirstElement( id );
352     while ( ft != NULL ) {
353         delete ft;
354         m_filetype_copy.filetypes->removeFirstElement();
355         ft = (WCFiletype*)m_filetype_copy.filetypes->getFirstElement( id );
356     }
357     m_filetype_copy.filetypes->closeEnum( id );
358 
359     m_filetype_copy.filetype_ex.unlock();
360 }
361 
findFiletype(WConfig * config,const std::vector<unsigned int> & v)362 WCFiletype *NM_Filetype_Thread::findFiletype( WConfig *config,
363                                               const std::vector<unsigned int> &v )
364 {
365     unsigned int in1, p, tp;
366     const std::list<WCFiletype*> *subtype;
367     std::list<WCFiletype*>::const_iterator it1;
368     WCFiletype *ft;
369 
370     ft = NULL;
371 
372     // check tree depth
373     p = v.size();
374     if ( p > 0 ) {
375         // we need at least the root type
376         in1 = v[p - 1];  // get position
377 
378         ft =  (WCFiletype*)config->getFiletypes()->getElementAt( in1 );
379         // root type, no problem if it is NULL
380 
381         // now go for each tree depth
382         p = v.size();
383         if ( p > 1 ) {
384             // we need one more depth at least
385 
386             p--; // skip root index
387 
388             do {
389                 // now for each depth
390 
391                 p--; // jump to next level
392                 // p is correct entry in "v"
393 
394                 if ( ft == NULL ) break;
395 
396                 // get position in current tree depth
397                 in1 = v[p];
398 
399                 // now find subtype
400                 // because of std::list we need to iterate
401                 subtype = ft->getSubTypeList();
402                 if ( subtype == NULL ) ft = NULL;  // oops, index but no subtype
403                 else {
404                     // iterate through subtype list and find "in1" position
405                     for ( it1 = subtype->begin(), tp = 0; it1 != subtype->end(); it1++, tp++ ) {
406                         if ( tp == in1 ) break;
407                     }
408 
409                     if ( it1 != subtype->end() ) {
410                         // found subtype at index "in1"
411                         ft = *it1;
412                     } else {
413                         ft = NULL;
414                     }
415                 }
416                 // stop when we processed last depth
417             } while ( p > 0 );
418         }
419     }
420     return ft;
421 }
422