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