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