ScolaSync: Fichier source de src/usbThread.py

ScolaSync 5.1 |

usbThread.py
Aller à la documentation de ce fichier.
1 # $Id: usbThread.py 47 2011-06-13 10:20:14Z georgesk $
2
3 licenceEn="""
4 file usbThread.py
5 this file is part of the project scolasync
6
7 Copyright (C) 2010-2012 Georges Khaznadar <georgesk@ofset.org>
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 """
22
23 import subprocess, threading, re, os, os.path, shutil
24 import time, glob, shlex, io
25 from PyQt5.QtCore import *
26
27
30 _threadNumber=0
31
32
35
36 def ensureDirExists(destpath):
37 os.path.isdir(destpath) or os.makedirs(destpath, mode=0o755)
38 return
39
40
42
43 class ThreadRegister:
44
45
47
48 def __init__(self):
49 self.dico={}
50
51 def __str__(self):
52 return "ThreadRegister: %s" %self.dico
53
54
58
59 def push(self, ud, thread):
60 if ud.getOwner() not in self.dico.keys():
61 self.dico[ud.getOwner()]=[thread]
62 else:
63 self.dico[ud.getOwner()].append(thread)
64
65
69
70 def pop(self, ud, thread):
71 self.dico[ud.getOwner()].remove(thread)
72
73
77
78 def busy(self, owner):
79 if owner in self.dico.keys():
80 return self.dico[owner]
81 return []
82
83
85
86 def threadSet(self):
87 result=set()
88 for o in self.dico.keys():
89 for t in self.dico[o]:
90 result.add(t)
91 return result
92
93
100
101 def _sanitizePath(path):
102 pattern=re.compile(".*([^/]+)")
103 m=pattern.match(str(path))
104 if m:
105 return m.group(1)
106 else:
107 return str(path).replace('/','_')
108
109 # fabrique un nom de thread commençant par th_, suivi d'un nombre unique,
110 # suivi d'une chaîne relative à la clé USB
111 # @param ud une instance de uDisk
112 # @return un nom de thread unique
113 #
114 #
115 # @protected
116
117 def _threadName(ud):
118 global _threadNumber
119 if hasattr(ud, "path"):
120 name="th_%04d_%s" %(_threadNumber,_sanitizePath(ud.path))
121 else:
122 name="th_%04d_%s" %(_threadNumber,"dummy")
123 _threadNumber+=1
124 return name
125
126
131
132 def _date():
133 return time.strftime("%Y/%m/%d-%H:%M:%S")
134
135 # Une classe abstraite, qui sert de creuset pour les classe servant
136 # aux copies et aux effacements.
137 #
138 # Les classes filles doivent redéfinir la méthode \b toDo : c'est celle qui
139 # est démarrée quand le thread est lancé. Cette méthode est appelée dans
140 # le contexte « \b with ud.rlock », qui évite que deux threads en même temps
141 # ne cherchent à accéder au même média.
142 #
143 # Une méthode \b copytree est définie pour remplacer shutils.copytree
144 # qui ne fait pas tout à fait l'affaire.
145 #
146
147 class abstractThreadUSB(threading.Thread):
148 # Constructeur
149 # Crée un thread pour copier une liste de fichiers vers une clé USB.
150 # @param ud l'instance uDisk correspondant à une partition de clé USB
151 # @param fileList la liste des fichiers à traiter
152 # @param subdir un sous-répertoire de la clé USB
153 # @param dest un répertoire de destination si nécessaire, None par défaut
154 # @param logfile un fichier de journalisation, /dev/null par défaut
155 # @param parent un widget qui recevra de signaux en début et en fin
156 # d'exécution
157 #
158
159 def __init__(self,ud, fileList, subdir, dest=None, logfile="/dev/null",
160 parent=None):
161 threading.Thread.__init__(self, name=_threadName(ud))
162 self._args=(ud, fileList, subdir, dest, logfile)
163 self.ud=ud
164 if hasattr(ud,"threadRunning"): ud.threadRunning=True
165 self.fileList=fileList
166 self.subdir=subdir
167 self.dest=dest
168 self.logfile=logfile
169 self.parent=parent
170
171 def run(self):
172 with self.ud.rlock:
173 self.toDo(*self._args)
174
175
178
179 def writeToLog(self, msg):
180 open(os.path.expanduser(self.logfile),"a").write(msg+"\n")
181 return
182
183 # Une version modifiée de shutil.copytree qui accepte que les
184 # repertoires destination soient déjà existants. Cette source dérive
185 # de la documentation fournie avec Python 2.7
186 # @param src un nom de fichier ou de répertoire
187 # @param dst un nom de de répertoire (déjà existant ou à créer)
188 # @param symlinks vrai si on veut recopier les liens tels quels
189 # @param ignore une fonction qui construit une liste de fichiers à ignorer (profil : répertoire, liste de noms de fichiers -> liste de noms de fichiers à ignorer)
190 # @param erase s'il est vrai la source est effacée après copie réussie
191 # @param errors la liste d'erreurs déjà relevées jusque là
192 # @return une liste d'erreurs éventuellement relevées, sinon une liste vide
193 #
194
195 def copytree(self,src, dst, symlinks=False, ignore=None, erase=False, errors=[]):
196 names = os.listdir(src)
197 if ignore is not None:
198 ignored_names = ignore(src, names)
199 else:
200 ignored_names = set()
201
202 try:
203 os.makedirs(dst)
204 except OSError as err:
205 pass
206 for name in names:
207 if name in ignored_names:
208 continue
209 srcname = os.path.join(src, name)
210 dstname = os.path.join(dst, name)
211 try:
212 if symlinks and os.path.islink(srcname):
213 linkto = os.readlink(srcname)
214 os.symlink(linkto, dstname)
215 if not errors and erase:
216 os.unlink(srcname)
217 elif os.path.isdir(srcname):
218 errors=self.copytree(srcname, dstname,
219 symlinks=symlinks, ignore=ignore,
220 erase=erase, errors=errors)
221 if not errors and erase:
222 os.rmdir(srcname)
223 else:
224 shutil.copy2(srcname, dstname)
225 if not errors and erase:
226 os.unlink(srcname)
227 # XXX What about devices, sockets etc.?
228 except IOError as why:
229 errors.append((srcname, dstname, str(why)))
230 # catch the Error from the recursive copytree so that we can
231 # continue with other files
232 except os.error as why:
233 errors.append((srcname, dstname, str(why)))
234 # catch the Error from the recursive copytree so that we can
235 # continue with other files
236 except Exception as err:
237 errors.extend(err.args[0])
238 return errors
239
240
244
245 def __str__(self):
246 result="%s(\n" %self.threadType()
247 result+=" ud = %s\n" %self.ud
248 result+=" fileList = %s\n" %self.fileList
249 result+=" subdir = %s\n" %self.subdir
250 result+=" dest = %s\n" %self.dest
251 result+=" logfile = %s\n" %self.logfile
252 result+="\n"
253 return result
254
255
258
259 def threadType(self):
260 return "abstractThreadUSB"
261
262
269
270 def toDo(self, ud, fileList, subdir, dest, logfile):
271 # ça ne fait rien du tout pour un thread abstrait
272 pass
273
274
276
277 class threadCopyToUSB(abstractThreadUSB):
278 # Constructeur
279 # Crée un thread pour copier une liste de fichiers vers une clé USB.
280 # @param ud l'instance uDisk correspondant à une partition de clé USB
281 # @param fileList la liste des fichiers à copier
282 # @param subdir le sous-répertoire de la clé USB où faire la copie
283 # @param logfile un fichier de journalisation, /dev/null par défaut
284 # @param parent un widget qui recevra de signaux en début et en fin
285 # d'exécution
286 #
287
288 def __init__(self,ud, fileList, subdir, logfile="/dev/null",
289 parent=None):
290 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=None, logfile=logfile, parent=parent)
291
292
294
295 def threadType(self):
296 return "threadCopyToUSB"
297
298 # Copie une liste de fichiers vers une clé USB sous un répertoire donné.
299 # Ce répertoire est composé de ud.visibleDir() joint au
300 # sous-répertoire subdir.
301 # À chaque fichier ou répertoire copié, une ligne est journalisée dans le
302 # fichier de journal de l'application.
303 # @param ud l'instance uDisk correspondant à une partition de clé USB
304 # @param fileList la liste des fichiers à copier
305 # @param logfile un fichier de journalisation
306 # @param subdir le sous-répertoire de la clé USB où faire la copie
307 #
308
309 def toDo(self, ud, fileList, subdir, dest, logfile):
310 while subdir[0]=='/':
311 subdir=subdir[1:]
312 destpath=os.path.join(ud.ensureMounted(),ud.visibleDir(),subdir)
313 ensureDirExists(destpath)
314 # boucle de copie
315 for f in fileList:
316 cmd="Copie de {0} vers {1}".format(f, destpath)
317 if self.parent:
318 self.parent.pushCmdSignal.emit(ud.getOwner(), cmd)
319 destpath1=os.path.join(destpath, os.path.basename(f))
320 # copie d'arbre si on copie un répertoire, ou de simple fichier
321 if os.path.isdir(f):
322 errors=self.copytree(f, destpath1)
323 else:
324 errors=[]
325 try:
326 shutil.copy2(f, destpath1)
327 except Exception as err:
328 errors.append([f, destpath1, str(err)])
329
330 msg="[%s] " %_date()
331 if not errors:
332 msg+="Success: "
333 else:
334 msg+="Error: "
335 msg+=cmd
336 for e in errors:
337 msg+= " <%s>" %str(e)
338 if self.parent:
339 self.parent.popCmdSignal.emit(ud.getOwner(), cmd)
340 self.writeToLog(msg)
341
342
344
345 class threadCopyFromUSB(abstractThreadUSB):
346 # Constructeur
347 # Crée un thread pour copier une liste de fichiers depuis une clé USB
348 # vers un répertoire de disque.
349 # @param ud l'instance uDisk correspondant à une partition de clé USB
350 # @param fileList la liste des fichiers à copier
351 # @param subdir le sous-répertoire de la clé USB d'où faire la copie
352 # @param dest un répertoire de destination
353 # @param logfile un fichier de journalisation, /dev/null par défaut
354 # @param parent un widget qui recevra de signaux en début et en fin
355 # d'exécution
356 #
357
358 def __init__(self,ud, fileList, subdir=".", dest="/tmp",
359 rootPath="/", logfile="/dev/null", parent=None):
360 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=dest,
361 logfile=logfile, parent=parent)
362 self.rootPath=rootPath
363
364 # Copie une liste de fichiers d'une clé USB sous un répertoire donné.
365 # À chaque fichier ou répertoire copié, une ligne est journalisée
366 # dans le fichier de journal de l'application.
367 # @param ud l'instance uDisk correspondant à une partition de clé USB
368 # @param fileList la liste des fichiers à copier, qui peut contenir des jokers
369 # @param dest un répertoire de destination
370 # @param logfile un fichier de journalisation
371 # @param subdir le sous-répertoire de la clé USB où faire la copie
372 #
373
374 def toDo(self, ud, fileList, subdir, dest, logfile):
375 for f in fileList:
376
377 fromPath=os.path.join(ud.ensureMounted(), f)
378 owner=ud.getOwner()
379
380 newName="%s_%s" %(owner,os.path.dirname(f))
381
382 toPath=os.path.join(dest,newName)
383 # crée le répertoire cible si nécessaire
384 ensureDirExists(toPath)
385 cmd="Copie de {0} vers {1}".format(fromPath, toPath)
386 if self.parent:
387 self.parent.pushCmdSignal.emit(ud.getOwner(), cmd)
388 destpath1=os.path.join(toPath, os.path.basename(f))
389 if os.path.isdir(fromPath):
390 errors=self.copytree(fromPath, destpath1)
391 else:
392 errors=[]
393 try:
394 shutil.copy2(fromPath, destpath1)
395 except Exception as err:
396 errors.extend((fromPath, destpath1, str(err)))
397
398 msg="[%s] " %_date()
399 if not errors:
400 msg += "Success: "
401 else:
402 msg += "Error: "
403 msg += cmd
404 for e in errors:
405 msg += " <%s>" %e
406 if self.parent:
407 self.parent.popCmdSignal.emit(ud.getOwner(), msg)
408 self.writeToLog(msg)
409
410
412
413 class threadMoveFromUSB(abstractThreadUSB):
414 # Constructeur
415 # Crée un thread pour déplacer une liste de fichiers depuis une clé USB
416 # vers un répertoire de disque.
417 # @param ud l'instance uDisk correspondant à une partition de clé USB
418 # @param fileList la liste des fichiers à copier
419 # @param subdir le sous-répertoire de la clé USB d'où faire la copie
420 # @param dest un répertoire de destination
421 # @param logfile un fichier de journalisation, /dev/null par défaut
422 # @param parent un widget qui recevra de signaux en début et en fin
423 # d'exécution
424 #
425
426 def __init__(self,ud, fileList, subdir=".", dest="/tmp",
427 rootPath="/", logfile="/dev/null", parent=None):
428 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=dest,
429 logfile=logfile, parent=parent)
430 self.rootPath=rootPath
431
432 # Copie une liste de fichiers d'une clé USB sous un répertoire donné.
433 # Après chaque copie réussie la source est effacée.
434 # À chaque fichier ou répertoire copié, une ligne est journalisée
435 # dans le fichier de journal de l'application.
436 # @param ud l'instance uDisk correspondant à une partition de clé USB
437 # @param fileList la liste des fichiers à copier
438 # @param dest un répertoire de destination
439 # @param logfile un fichier de journalisation
440 # @param subdir le sous-répertoire de la clé USB où faire la copie
441 #
442
443 def toDo(self, ud, fileList, subdir, dest, logfile):
444 for f in fileList:
445
446 fromPath=os.path.join(ud.ensureMounted(), f)
447 owner=ud.getOwner()
448
449 newName="%s_%s" %(owner,os.path.dirname(f))
450
451 toPath=os.path.join(dest,newName)
452 # crée le répertoire cible si nécessaire
453 ensureDirExists(toPath)
454 cmd="copying %s to %s" %(fromPath, toPath)
455 if self.parent:
456 self.parent.pushCmdSignal.emit(ud.getOwner(), cmd)
457 destpath1=os.path.join(toPath, os.path.basename(f))
458 if os.path.isdir(fromPath):
459 errors=self.copytree(fromPath, destpath1, erase=True)
460 try:
461 os.rmdir(fromPath)
462 except Exception as err:
463 errors.extend((fromPath, destpath1, str(err)))
464 else:
465 errors=[]
466 try:
467 shutil.copy2(fromPath, destpath1)
468 os.unlink(fromPath)
469 except Exception as err:
470 errors.extend((fromPath, destpath1, str(err)))
471
472 msg="[%s] " %_date()
473 if not errors:
474 msg += "Success: "
475 else:
476 msg += "Error: "
477 msg += cmd
478 for e in errors:
479 msg += " <%s>" %e
480 if self.parent:
481 self.parent.popCmdSignal.emit(ud.getOwner(), msg)
482 self.writeToLog(msg)
483
484
486
487 class threadDeleteInUSB(abstractThreadUSB):
488 # Constructeur
489 # Crée un thread pour supprimer une liste de fichiers dans une clé USB.
490 # @param ud l'instance uDisk correspondant à une partition de clé USB
491 # @param fileList la liste des fichiers à supprimer
492 # @param subdir le sous-répertoire de la clé USB où faire les suppressions
493 # @param logfile un fichier de journalisation, /dev/null par défaut
494 # @param parent un widget qui recevra de signaux en début et en fin
495 # d'exécution
496 #
497
498 def __init__(self,ud, fileList, subdir, logfile="/dev/null",
499 parent=None):
500 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=None,
501 logfile=logfile, parent=parent)
502
503 # Supprime une liste de fichiers dans une clé USB.
504 # La liste est prise sous un répertoire donné. Le répertoire visible
505 # qui dépend du constructuer d ela clé est pris en compte.
506 # À chaque fichier ou répertoire supprimé, une ligne est
507 # journalisée dans le fichier de journal de l'application.
508 # @param l'instance uDisk correspondant à une partition de clé USB
509 # @param fileList la liste des fichiers à copier
510 # @param dest un répertoire de destination
511 # @param logfile un fichier de journalisation
512 # @param subdir le sous-répertoire de la clé USB où faire la copie
513 #
514
515 def toDo(self, ud, fileList, subdir, dest, logfile):
516 for f in fileList:
517 toDel=os.path.join(ud.ensureMounted(), f)
518 cmd="Effacement de {0}".format(toDel)
519 errors=[]
520 if self.parent:
521 self.parent.pushCmdSignal.emit(ud.getOwner(), cmd)
522 if os.path.isdir(toDel):
523 try:
524 for root, dirs, files in os.walk(toDel, topdown=False):
525 for name in files:
526 os.remove(os.path.join(root, name))
527 for name in dirs:
528 os.rmdir(os.path.join(root, name))
529 os.rmdir(toDel)
530 except Exception as err:
531 errors.expand((toDel,str(err)))
532 else:
533 try:
534 os.unlink(toDel)
535 except Exception as err:
536 errors.expand((toDel,str(err)))
537 msg="[%s] " %_date()
538 if not errors:
539 msg += "Success: "
540 else:
541 msg += "Error: "
542 msg += cmd
543 for e in errors:
544 msg += " <%s>" %e
545 if self.parent:
546 self.parent.popCmdSignal.emit(ud.getOwner(), msg)
547 self.writeToLog(msg)
548
549 if __name__=="__main__":
550 import sys, ownedUsbDisk, subprocess
551
552
553 def test_copytree():
554 t=abstractThreadUSB(None, sys.argv[1:-1], sys.argv[-1])
555 if len(sys.argv) < 3:
556 print("Usage : %s répertoire_source répertoire_destination" %sys.argv[0])
557 print("Ça doit créer sous répertoire_destination la même arborescence que sous répertoire_source")
558 print("et ça crée répertoire_destination à la volée si nécessaire.")
559 sys.exit(-1)
560 errors=t.copytree(sys.argv[1],sys.argv[2])
561 print("Erreurs = %s" %errors)
562 subprocess.call ("diff -ruN %s %s" %(sys.argv[1],sys.argv[2]), shell=True)
563 print ("Ne pas oublier d'effacer %s si nécessaire" %sys.argv[2])
564
565 # Teste la copie d'un fichier vers une destination telle qu'elle est pratiquée
566 # dans la méthode copytree de abstractThreadUSB
567 #
568
569 def test_copy2():
570 if len(sys.argv) < 3:
571 print("Usage : %s fichier répertoire_destination" %sys.argv[0])
572 print("Ça doit créer sous répertoire_destination une copie du fichier")
573 print("et ça crée répertoire_destination à la volée si nécessaire.")
574 sys.exit(-1)
575 srcname=sys.argv[1]
576 dstname=os.path.join(sys.argv[2],sys.argv[1])
577 shutil.copy2(srcname, dstname)
578 print ("fin de la copie de %s vers %s, listing de %s" %(sys.argv[1],sys.argv[2],sys.argv[2]))
579 subprocess.call("ls %s" %sys.argv[2], shell=True)
580
581 #test_copytree()
582 test_copy2()
src.usbThread.abstractThreadUSB.__init__
def __init__(self, ud, fileList, subdir, dest=None, logfile="/dev/null", parent=None)
Definition: usbThread.py:159
src.usbThread.abstractThreadUSB.dest
dest
Definition: usbThread.py:166
src.usbThread.abstractThreadUSB.writeToLog
def writeToLog(self, msg)
Écrit un message dans le fichier de journalisation.
Definition: usbThread.py:179
src.usbThread.abstractThreadUSB.ud
ud
Definition: usbThread.py:162
src.usbThread.threadMoveFromUSB.toDo
def toDo(self, ud, fileList, subdir, dest, logfile)
La fonction abstraite pour les choses à faire.
Definition: usbThread.py:443
src.usbThread.abstractThreadUSB.logfile
logfile
Definition: usbThread.py:167
src.usbThread.ThreadRegister.pop
def pop(self, ud, thread)
Definition: usbThread.py:70
src.usbThread.threadCopyToUSB.__init__
def __init__(self, ud, fileList, subdir, logfile="/dev/null", parent=None)
Definition: usbThread.py:288
src.usbThread.abstractThreadUSB.copytree
def copytree(self, src, dst, symlinks=False, ignore=None, erase=False, errors=[])
Definition: usbThread.py:195
src.usbThread.abstractThreadUSB.__str__
def __str__(self)
Renvoie une chaîne informative sur le thread.
Definition: usbThread.py:245
src.usbThread.abstractThreadUSB
Definition: usbThread.py:147
src.usbThread.abstractThreadUSB.toDo
def toDo(self, ud, fileList, subdir, dest, logfile)
La fonction abstraite pour les choses à faire.
Definition: usbThread.py:270
src.usbThread.threadCopyFromUSB
Classe pour les threads copiant depuis les clés USB.
Definition: usbThread.py:345
src.usbThread.abstractThreadUSB.run
def run(self)
Definition: usbThread.py:171
src.usbThread.threadCopyFromUSB.rootPath
rootPath
Definition: usbThread.py:361
src.usbThread.ThreadRegister.busy
def busy(self, owner)
Indique si le disque est occupé par des threads.
Definition: usbThread.py:78
src.usbThread.ThreadRegister.threadSet
def threadSet(self)
renvoie l'ensemble des threads actifs
Definition: usbThread.py:86
src.usbThread.ensureDirExists
def ensureDirExists(destpath)
force l'existence d'un répertoire, récursivement si nécessaire
Definition: usbThread.py:36
src.usbThread.test_copytree
def test_copytree()
Teste la fonction copytree.
Definition: usbThread.py:553
src.usbThread.ThreadRegister.__str__
def __str__(self)
Definition: usbThread.py:51
src.usbThread.abstractThreadUSB._args
_args
Definition: usbThread.py:161
src.usbThread.threadMoveFromUSB
Classe pour les threads déplaçant des fichiers depuis les clés USB.
Definition: usbThread.py:413
src.usbThread.abstractThreadUSB.threadType
def threadType(self)
information sur le thread.
Definition: usbThread.py:259
src.usbThread.ThreadRegister.__init__
def __init__(self)
Le constructure met en place un dictionnaire.
Definition: usbThread.py:48
src.usbThread.threadCopyFromUSB.toDo
def toDo(self, ud, fileList, subdir, dest, logfile)
La fonction abstraite pour les choses à faire.
Definition: usbThread.py:374
src.usbThread.ThreadRegister.dico
dico
Definition: usbThread.py:49
src.usbThread.abstractThreadUSB.parent
parent
Definition: usbThread.py:168
src.usbThread.abstractThreadUSB.fileList
fileList
Definition: usbThread.py:164
src.usbThread.threadCopyToUSB.toDo
def toDo(self, ud, fileList, subdir, dest, logfile)
La fonction abstraite pour les choses à faire.
Definition: usbThread.py:309
QtCore
src.usbThread.threadMoveFromUSB.__init__
def __init__(self, ud, fileList, subdir=".", dest="/tmp", rootPath="/", logfile="/dev/null", parent=None)
Definition: usbThread.py:426
src.usbThread.threadMoveFromUSB.rootPath
rootPath
Definition: usbThread.py:429
src.usbThread.test_copy2
def test_copy2()
Definition: usbThread.py:569
src.usbThread.threadDeleteInUSB.__init__
def __init__(self, ud, fileList, subdir, logfile="/dev/null", parent=None)
Definition: usbThread.py:498
src.usbThread.abstractThreadUSB.subdir
subdir
Definition: usbThread.py:165
src.usbThread.threadDeleteInUSB.toDo
def toDo(self, ud, fileList, subdir, dest, logfile)
La fonction abstraite pour les choses à faire.
Definition: usbThread.py:515
src.usbThread.threadCopyFromUSB.__init__
def __init__(self, ud, fileList, subdir=".", dest="/tmp", rootPath="/", logfile="/dev/null", parent=None)
Definition: usbThread.py:358
src.usbThread.ThreadRegister
Une classe pour tenir un registre des threads concernant les baladeurs.
Definition: usbThread.py:43
src.usbThread.ThreadRegister.push
def push(self, ud, thread)
Definition: usbThread.py:59
src.usbThread.threadCopyToUSB.threadType
def threadType(self)
Definition: usbThread.py:295
src.usbThread.threadDeleteInUSB
Classe pour les threads effaçant des sous-arbres dans les clés USB.
Definition: usbThread.py:487