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