Example #1
0
    def __init__(self):
        self.sigFilenameChanged = util.Signal()
        self.sigStatusChanged = util.Signal()
        self.dirty = util.Observable(True)

        self.settingsDict = {'Project Name':"Untitled", 'Project File Version':"1.00", 'Project Author':"Unknown"}
        self.datadirectory = ""
        self.config = ConfigObjProj(callback=self.configObjChanged)
        self._traceManager = TraceManager().register()
        self._traceManager.dirty.connect(self.__dirtyCallback)
        self.setFilename(ProjectFormat.untitledFileName)
        if __debug__: logging.debug('Created: ' + str(self))
Example #2
0
    def __init__(self, prog_name="ChipWhisperer", prog_ver=""):
        self.valid_traces = None
        self._trace_format = None

        self.params = Parameter(name="Project Settings", type="group")
        self.params.addChildren([
            {
                'name': 'Trace Format',
                'type': 'list',
                'values': self.valid_traces,
                'get': self.get_trace_format,
                'set': self.set_trace_format
            },
        ])

        #self.findParam("Trace Format").setValue(TraceContainerNative(project=self), addToList=True)
        self._trace_format = TraceContainerNative(project=self)

        #self.traceParam = Parameter(name="Trace Settings", type='group', addLoadSave=True).register()
        #self.params.getChild('Trace Format').stealDynamicParameters(self.traceParam)

        self.sigFilenameChanged = util.Signal()
        self.sigStatusChanged = util.Signal()
        self.dirty = util.Observable(True)

        self.settingsDict = {
            'Project Name': "Untitled",
            'Project File Version': "1.00",
            'Project Author': "Unknown"
        }
        self.datadirectory = ""
        self.config = ConfigObjProj(callback=self.configObjChanged)
        self._traceManager = TraceManager().register()
        self._traceManager.dirty.connect(self.__dirtyCallback)
        self.setFilename(Project.untitledFileName)

        self.setProgramName(prog_name)
        self.setProgramVersion(prog_ver)

        self._segments = Segments(self)
        self._traces = Traces(self)
        self._keys = IndividualIterable(self._traceManager.get_known_key,
                                        self._traceManager.num_traces)
        self._textins = IndividualIterable(self._traceManager.get_textin,
                                           self._traceManager.num_traces)
        self._textouts = IndividualIterable(self._traceManager.get_textout,
                                            self._traceManager.num_traces)
        self._waves = IndividualIterable(self._traceManager.get_trace,
                                         self._traceManager.num_traces)

        if __debug__:
            logging.debug('Created: ' + str(self))
Example #3
0
class Project(Parameterized):
    """Class describing an open ChipWhisperer project.

    Basic capture usage::

        import chipwhisperer as cw
        proj = cw.create_project("project")
        trace = cw.Trace(trace_data, plaintext, ciphertext, key)
        proj.traces.append(trace)
        proj.save()

    Basic analyzer usage::

        import chipwhisperer as cw
        import chipwhisperer.analyzer as cwa
        proj = cw.open_project("project")
        attack = cwa.cpa(proj)
        #run attack

    Use a trace_manager when analyzing traces, since that allows analyzer to
    work with multiple trace segments.

      *  :attr:`project.location <.Project.location>`
      *  :attr:`project.waves <.Project.waves>`
      *  :attr:`project.textins <.Project.textins>`
      *  :attr:`project.textouts <.Project.textouts>`
      *  :attr:`project.keys <.Project.keys>`
      *  :meth:`project.get_filename <.Project.get_filename>`
      *  :meth:`project.trace_manager <.Project.trace_manager>`
      *  :meth:`project.save <.Project.save>`
      *  :meth:`project.export <.Project.export>`
    """
    untitledFileName = os.path.normpath(
        os.path.join(Settings().value("project-home-dir"), "tmp",
                     "default.cwp"))

    def __init__(self, prog_name="ChipWhisperer", prog_ver=""):
        self.valid_traces = None
        self._trace_format = None

        self.params = Parameter(name="Project Settings", type="group")
        self.params.addChildren([
            {
                'name': 'Trace Format',
                'type': 'list',
                'values': self.valid_traces,
                'get': self.get_trace_format,
                'set': self.set_trace_format
            },
        ])

        #self.findParam("Trace Format").setValue(TraceContainerNative(project=self), addToList=True)
        self._trace_format = TraceContainerNative(project=self)

        #self.traceParam = Parameter(name="Trace Settings", type='group', addLoadSave=True).register()
        #self.params.getChild('Trace Format').stealDynamicParameters(self.traceParam)

        self.sigFilenameChanged = util.Signal()
        self.sigStatusChanged = util.Signal()
        self.dirty = util.Observable(True)

        self.settingsDict = {
            'Project Name': "Untitled",
            'Project File Version': "1.00",
            'Project Author': "Unknown"
        }
        self.datadirectory = ""
        self.config = ConfigObjProj(callback=self.configObjChanged)
        self._traceManager = TraceManager().register()
        self._traceManager.dirty.connect(self.__dirtyCallback)
        self.setFilename(Project.untitledFileName)

        self.setProgramName(prog_name)
        self.setProgramVersion(prog_ver)

        self._segments = Segments(self)
        self._traces = Traces(self)
        self._keys = IndividualIterable(self._traceManager.get_known_key,
                                        self._traceManager.num_traces)
        self._textins = IndividualIterable(self._traceManager.get_textin,
                                           self._traceManager.num_traces)
        self._textouts = IndividualIterable(self._traceManager.get_textout,
                                            self._traceManager.num_traces)
        self._waves = IndividualIterable(self._traceManager.get_trace,
                                         self._traceManager.num_traces)

        if __debug__:
            logging.debug('Created: ' + str(self))

    def append_segment(self, segment):
        """ Adds a new trace segment to the project

        Args:
            segment (TraceContainer): Trace segment to add to project
        """
        self._traceManager.appendSegment(copy.copy(segment))

    appendSegment = append_segment

    def new_segment(self):
        """ Returns the __class__() of the trace container used to store traces
        in the project

        You probably want get_new_trace_segment()

        Returns:
            __class()__ of the current trace container
        """
        return self._trace_format.__class__()

    newSegment = new_segment

    def get_trace_format(self):
        """ Gets the TraceContainer used to store traces

        Returns:
            The trace container used in the project
        """
        return self._trace_format

    getTraceFormat = get_trace_format

    def get_new_trace_segment(self):
        """Return a new TraceContainer object for the specified format.

        Once you're done working with this segment, you can readd it to the
        project with append_segment()

        Returns:
            a new TraceContainer object
        """
        tmp = copy.copy(self._trace_format)
        tmp.clear()
        starttime = datetime.now()
        prefix = starttime.strftime('%Y.%m.%d-%H.%M.%S') + "_"
        tmp.config.setConfigFilename(
            os.path.join(self.datadirectory, "traces",
                         "config_" + prefix + ".cfg"))
        tmp.config.setAttr("prefix", prefix)
        tmp.config.setAttr("date", starttime.strftime('%Y-%m-%d %H:%M:%S'))
        return tmp

    getNewTraceSegment = get_new_trace_segment

    @setupSetParam("Trace Format")
    def set_trace_format(self, trace_format):
        self._trace_format = trace_format

    setTraceFormat = util.camel_case_deprecated(set_trace_format)

    def __dirtyCallback(self):
        self.dirty.setValue(self._traceManager.dirty.value()
                            or self.dirty.value())

    def configObjChanged(self, key):
        self.dirty.setValue(True)

    def isUntitled(self):
        return self.filename == Project.untitledFileName

    def trace_manager(self):
        """ Gets the trace manager for the project

        Returns:
            The trace manager for the project
        """
        return self._traceManager

    traceManager = util.camel_case_deprecated(trace_manager)

    def setProgramName(self, name):
        self.settingsDict['Program Name'] = name

    def setProgramVersion(self, ver):
        self.settingsDict['Program Version'] = ver

    def setAuthor(self, author):
        self.settingsDict['Project Author'] = author

    def setProjectName(self, name):
        self.settingsDict['Project Name'] = name

    def setFileVersion(self, ver):
        self.settingsDict['Project File Version'] = ver

    def get_filename(self):
        """Gets the filename associated with the project.

        Returns:
            Filename of the project config file ending with ".cwp".
        """
        return self.filename

    getFilename = util.camel_case_deprecated(get_filename)

    def setFilename(self, f):
        self.filename = f
        self.config.filename = f
        self.datadirectory = os.path.splitext(self.filename)[0] + "_data"
        self.createDataDirectory()
        self.sigStatusChanged.emit()

    def createDataDirectory(self):
        # Check if data-directory exists?
        if not os.path.isdir(self.datadirectory):
            os.makedirs(self.datadirectory)

        # Make trace storage directory too
        if not os.path.isdir(os.path.join(self.datadirectory, 'traces')):
            os.mkdir(os.path.join(self.datadirectory, 'traces'))

        # Make analysis storage directory
        if not os.path.isdir(os.path.join(self.datadirectory, 'analysis')):
            os.mkdir(os.path.join(self.datadirectory, 'analysis'))

        # Make glitchresults storage directory
        if not os.path.isdir(os.path.join(self.datadirectory,
                                          'glitchresults')):
            os.mkdir(os.path.join(self.datadirectory, 'glitchresults'))

    def load(self, f=None):
        if f is not None:
            self.setFilename(os.path.abspath(os.path.expanduser(f)))

        if not os.path.isfile(self.filename):
            raise IOError("File " + self.filename +
                          " does not exist or is not a file")

        self.config = ConfigObjProj(infile=self.filename,
                                    callback=self.configObjChanged)
        self._traceManager.loadProject(self.filename)
        self.dirty.setValue(False)

    def getDataFilepath(self, filename, subdirectory='analysis'):
        datadir = os.path.join(self.datadirectory, subdirectory)
        fname = os.path.join(datadir, filename)
        relfname = os.path.relpath(fname,
                                   os.path.split(self.config.filename)[0])
        fname = os.path.normpath(fname)
        relfname = os.path.normpath(relfname)
        return {"abs": fname, "rel": relfname}

    def convertDataFilepathAbs(self, relativepath):
        return os.path.join(os.path.split(self.filename)[0], relativepath)

    def checkDataConfig(self, config, requiredSettings):
        """Check a configuration section for various settings. Don't use."""
        requiredSettings = util.convert_to_str(requiredSettings)
        config = util.convert_to_str(config)
        return set(requiredSettings.items()).issubset(set(config.items()))

    def getDataConfig(self,
                      sectionName="Aux Data",
                      subsectionName=None,
                      requiredSettings=None):
        """ Don't use.
        Get all configuration sections of data type given in
        __init__() call, and also matching the given sectionName.
        e.g. if dataName='Aux Data' and sectionName='Frequency',
        this would return a list of all sections of the type
        'Aux Data NNNN - Frequency'.
        """
        sections = []

        # Get all section names
        for sname in list(self.config.keys()):
            # Find if starts with 'Aux Data'
            if sname.startswith(sectionName):
                # print "Found %s" % sname
                # Find if module name matches if applicable
                if subsectionName is None or sname.endswith(subsectionName):
                    # print "Found %s" % sname

                    if requiredSettings is None:
                        sections.append(self.config[sname])
                    else:
                        self.checkDataConfig(self.config[sname],
                                             requiredSettings)

        return sections

    def addDataConfig(self,
                      settings=None,
                      sectionName="Aux Data",
                      subsectionName=None):
        # Check configuration file to find incrementing number. Don't use
        maxNumber = 0
        for sname in list(self.config.keys()):
            # Find if starts with 'Aux Data'
            if sname.startswith(sectionName):
                maxNumber = int(re.findall(r'\d+', sname)[0]) + 1

        cfgSectionName = "%s %04d" % (sectionName, maxNumber)
        if subsectionName:
            cfgSectionName += " - %s" % subsectionName

        # Generate the configuration section
        self.config[cfgSectionName] = {}

        if settings is not None:
            for k in list(settings.keys()):
                self.config[cfgSectionName][k] = settings[k]

        return self.config[cfgSectionName]

    def saveAllSettings(self, fname=None, onlyVisibles=False):
        """ Save registered parameters to a file, so it can be loaded again latter. Don't use."""
        if fname is None:
            fname = os.path.join(self.datadirectory, 'settings.cwset')
            logging.info('Saving settings to file: ' + fname)
        Parameter.saveRegistered(fname, onlyVisibles)

    def saveTraceManager(self):
        #Waveform list is Universal across ALL types. Don't use.
        if 'Trace Management' not in self.config:
            self.config['Trace Management'] = {}

        self._traceManager.save_project(self.config, self.filename)

    def save(self):
        """Saves the project.

        Writes the project to the disk. Before this is called your data
        is not saved. Filenames for traces are set in this method.
        """
        if self.filename is None:
            return

        self.saveTraceManager()

        #self.config['Waveform List'] = self.config['Waveform List'] + self.waveList

        #Program-Specific Options
        pn = self.settingsDict['Program Name']

        self.config[pn] = {}
        self.config[pn]['General Settings'] = self.settingsDict

        self.config.write()
        self.sigStatusChanged.emit()
        self.dirty.setValue(False)

    def checkDiff(self):
        """ Don't use.
        Check if there is a difference - returns True if so, and False
        if no changes present. Also updates widget with overview of the
        differences if requested with updateGUI
        """
        self.saveTraceManager()

        disk = util.convert_to_str(ConfigObjProj(infile=self.filename))
        ram = util.convert_to_str(self.config)

    def hasDiffs(self):
        if self.dirty.value(): return True

        #added, removed, changed = self.checkDiff()
        if (len(added) + len(removed) + len(changed)) == 0:
            return False
        return True

    def consolidate(self, keepOriginals=True):
        for indx, t in enumerate(self._traceManager.traceSegments):
            destinationDir = os.path.normpath(
                os.path.join(self.datadirectory, "traces"))
            config = ConfigObj(t.config.configFilename())
            prefix = config['Trace Config']['prefix']
            tracePath = os.path.normpath(
                os.path.split(t.config.configFilename())[0])

            if destinationDir == tracePath: continue

            for traceFile in os.listdir(tracePath):
                if traceFile.startswith(prefix):
                    util.copyFile(
                        os.path.normpath(os.path.join(tracePath, traceFile)),
                        destinationDir, keepOriginals)

            util.copyFile(t.config.configFilename(), destinationDir,
                          keepOriginals)
            t.config.setConfigFilename(
                os.path.normpath(
                    os.path.join(destinationDir,
                                 os.path.split(t.config.configFilename())[1])))
        self.sigStatusChanged.emit()

    def __del__(self):
        if __debug__: logging.debug('Deleted: ' + str(self))

    @property
    def location(self):
        """The directory in which the project is located.

        Example::

            print(project.location)
            '/path/to/the/directory/containing/this/project'

        :Getter:
            (str) Returns the file path of the projects parent directory.

        .. versionadded:: 5.1
            Added **location** attribute to project.
        """
        return os.path.dirname(os.path.abspath(self.get_filename()))

    def export(self, file_path, file_type='zip'):
        """Export a chipwhisperer project.

        Saves project before exporting.

        Supported export types:
          *  zip (default)

        Returns:
            (str) Path to the exported file.

        .. versionadded:: 5.1
            Add **export** method to active project.
        """
        self.save()

        _, cwp_file = os.path.split(self.get_filename())
        name, ext = os.path.splitext(cwp_file)
        data_folder = os.path.join(self.location, '_'.join([name, 'data']))

        file_paths = list()
        file_paths.append(os.path.join(self.location, cwp_file))

        for root, directories, files in os.walk(data_folder):
            for filename in files:
                file_paths.append(os.path.join(root, filename))

        if file_type == 'zip':
            file_path = os.path.abspath(file_path)
            with zipfile.ZipFile(file_path, 'w') as zip:
                common_path = os.path.commonpath(file_paths)
                for file in file_paths:
                    relative_path = os.path.relpath(file, common_path)
                    zip.write(file, arcname=relative_path)
                    export_file_path = os.path.abspath(zip.filename)
        else:
            raise ValueError('{} not supported'.format(file_type))

        return export_file_path

    def close(self, save=True):
        """Closes the project cleanly.

        Saves by default. Then closes all claimed files.

        Args:
            save (bool): Saves the project before closing.
        """
        if save:
            self.save()

        for seg in self.segments:
            seg.unloadAllTraces()

    def remove(self, i_am_sure=False):
        """Remove a project from disk.

        Args:
            i_am_sure (bool): Are you sure you want to remove the project?
        """
        if not i_am_sure:
            raise RuntimeWarning(
                'Project not removed... i_am_sure not set to True.')

        self.close(save=False)

        try:
            shutil.rmtree(self.datadirectory)
        except FileNotFoundError:
            pass

        _, cwp_file = os.path.split(self.get_filename())
        try:
            os.remove(os.path.join(self.location, cwp_file))
        except FileNotFoundError:
            pass

    @property
    def traces(self):
        """The interface to all traces contained in the project.

        Instance of :class:`.Traces`.
        """
        return self._traces

    @property
    def segments(self):
        """The interface to all segments contained in the project.

        Instance of :class:`.Segments`.
        """
        return self._segments

    @property
    def keys(self):
        """Iterable for working with only the known keys.

        Each item in the iterable is a byte array.

        Supports iterating, indexing, and slicing::

            for key in my_project.keys:
                # do something
        """
        return self._keys

    @property
    def textins(self):
        """Iterable for working with only the text in.

        Each item in the iterable is a byte array.

        Supports iterating, indexing, and slicing::

            for textin in my_project.textins:
                # do something
        """
        return self._textins

    @property
    def textouts(self):
        """Iterable for working with only the text out.

        Each item in the iterable is a byte array.

        Supports iterating, indexing, and slicing::

            for textout in my_project.textouts:
                # do something
        """
        return self._textouts

    @property
    def waves(self):
        """Iterable for working with only the trace data.

        Each item in the iterable is a numpy array.

        Supports iterating, indexing, and slicing::

            for wave in my_project.waves:
                # do something
        """
        return self._waves
Example #4
0
class ProjectFormat(object):
    untitledFileName = os.path.normpath(os.path.join(Settings().value("project-home-dir"), "tmp/default.cwp"))

    def __init__(self):
        self.sigFilenameChanged = util.Signal()
        self.sigStatusChanged = util.Signal()
        self.dirty = util.Observable(True)

        self.settingsDict = {'Project Name':"Untitled", 'Project File Version':"1.00", 'Project Author':"Unknown"}
        self.datadirectory = ""
        self.config = ConfigObjProj(callback=self.configObjChanged)
        self._traceManager = TraceManager().register()
        self._traceManager.dirty.connect(self.__dirtyCallback)
        self.setFilename(ProjectFormat.untitledFileName)
        if __debug__: logging.debug('Created: ' + str(self))

    def __dirtyCallback(self):
        self.dirty.setValue(self._traceManager.dirty.value() or self.dirty.value())

    def configObjChanged(self, key):
        self.dirty.setValue(True)

    def isUntitled(self):
        return self.filename == ProjectFormat.untitledFileName

    def traceManager(self):
        return self._traceManager

    def setProgramName(self, name):
        self.settingsDict['Program Name']=name
    
    def setProgramVersion(self, ver):
        self.settingsDict['Program Version']=ver
        
    def setAuthor(self, author):
        self.settingsDict['Project Author']=author
    
    def setProjectName(self, name):
        self.settingsDict['Project Name']=name
    
    def setFileVersion(self, ver):
        self.settingsDict['Project File Version']=ver
        
    def addWave(self, configfile):
        return       
        
    def getFilename(self):
        return self.filename

    def setFilename(self, f):
        self.filename = f
        self.config.filename = f        
        self.datadirectory = os.path.splitext(self.filename)[0] + "_data/"
        self.createDataDirectory()
        self.sigStatusChanged.emit()
        
    def createDataDirectory(self):
        # Check if data-directory exists?
        if not os.path.isdir(self.datadirectory):
            os.makedirs(self.datadirectory)

        # Make trace storage directory too
        if not os.path.isdir(os.path.join(self.datadirectory, 'traces')):
            os.mkdir(os.path.join(self.datadirectory, 'traces'))

        # Make analysis storage directory
        if not os.path.isdir(os.path.join(self.datadirectory, 'analysis')):
            os.mkdir(os.path.join(self.datadirectory, 'analysis'))

        # Make glitchresults storage directory
        if not os.path.isdir(os.path.join(self.datadirectory, 'glitchresults')):
            os.mkdir(os.path.join(self.datadirectory, 'glitchresults'))

    def load(self, f = None):
        if f is not None:
            self.setFilename(f)

        self.config = ConfigObjProj(infile=self.filename, callback=self.configObjChanged)
        self._traceManager.loadProject(self.filename)
        self.dirty.setValue(False)

    def getDataFilepath(self, filename, subdirectory='analysis'):
        datadir = os.path.join(self.datadirectory, subdirectory)
        fname = os.path.join(datadir, filename)
        relfname = os.path.relpath(fname, os.path.split(self.config.filename)[0])
        fname = os.path.normpath(fname)
        relfname = os.path.normpath(relfname)
        return {"abs":fname, "rel":relfname}

    def convertDataFilepathAbs(self, relativepath):
        return os.path.join(os.path.split(self.filename)[0], relativepath)

    def checkDataConfig(self, config, requiredSettings):
        """Check a configuration section for various settings"""
        requiredSettings = util.convert_to_str(requiredSettings)
        config = util.convert_to_str(config)
        return set(requiredSettings.items()).issubset(set(config.items()))

    def getDataConfig(self, sectionName="Aux Data", subsectionName=None, requiredSettings=None):
        """
        Get all configuration sections of data type given in
        __init__() call, and also matching the given sectionName.
        e.g. if dataName='Aux Data' and sectionName='Frequency',
        this would return a list of all sections of the type
        'Aux Data NNNN - Frequency'.
        """
        sections = []

        # Get all section names
        for sname in self.config.keys():
            # Find if starts with 'Aux Data'
            if sname.startswith(sectionName):
                # print "Found %s" % sname
                # Find if module name matches if applicable
                if subsectionName is None or sname.endswith(subsectionName):
                    # print "Found %s" % sname

                    if requiredSettings is None:
                        sections.append(self.config[sname])
                    else:
                        self.checkDataConfig(self.config[sname], requiredSettings)

        return sections

    def addDataConfig(self, settings=None, sectionName="Aux Data", subsectionName=None):
        # Check configuration file to find incrementing number
        maxNumber = 0
        for sname in self.config.keys():
            # Find if starts with 'Aux Data'
            if sname.startswith(sectionName):
                maxNumber = int(re.findall(r'\d+', sname)[0]) + 1

        cfgSectionName = "%s %04d" % (sectionName, maxNumber)
        if subsectionName:
            cfgSectionName += " - %s" % subsectionName

        # Generate the configuration section
        self.config[cfgSectionName] = {}

        if settings is not None:
            for k in settings.keys():
                self.config[cfgSectionName][k] = settings[k]

        return self.config[cfgSectionName]

    def saveAllSettings(self, fname=None, onlyVisibles=False):
        """ Save registered parameters to a file, so it can be loaded again latter."""
        if fname is None:
            fname = os.path.join(self.datadirectory, 'settings.cwset')
            logging.info('Saving settings to file: ' + fname)
        Parameter.saveRegistered(fname, onlyVisibles)

    def saveTraceManager(self):
        #Waveform list is Universal across ALL types
        if 'Trace Management' not in self.config:
            self.config['Trace Management'] = {}
            
        self._traceManager.saveProject(self.config, self.filename)

    def save(self):
        if self.filename is None:
            return

        self.saveTraceManager()
            
        #self.config['Waveform List'] = self.config['Waveform List'] + self.waveList

        #Program-Specific Options
        pn = self.settingsDict['Program Name']
       
        self.config[pn] = {}
        self.config[pn]['General Settings'] =  self.settingsDict

        self.config.write()
        self.sigStatusChanged.emit()
        self.dirty.setValue(False)

    def checkDiff(self):
        """
        Check if there is a difference - returns True if so, and False
        if no changes present. Also updates widget with overview of the
        differences if requested with updateGUI
        """
        self.saveTraceManager()

        disk = util.convert_to_str(ConfigObjProj(infile=self.filename))
        ram = util.convert_to_str(self.config)
        diff = DictDiffer(ram, disk)

        added = diff.added()
        removed = diff.removed()
        changed = diff.changed() #TODO: bug when comparing projects with template sections. It is returning changes when there is not.

        return added, removed, changed

    def hasDiffs(self):
        if self.dirty.value(): return True

        added, removed, changed = self.checkDiff()
        if (len(added) + len(removed) + len(changed)) == 0:
            return False
        return True

    def consolidate(self, keepOriginals = True):
        for indx, t in enumerate(self._traceManager.traceSegments):
            destinationDir = os.path.normpath(self.datadirectory + "traces/")
            config = ConfigObj(t.config.configFilename())
            prefix = config['Trace Config']['prefix']
            tracePath = os.path.normpath(os.path.split(t.config.configFilename())[0])

            if destinationDir == tracePath: continue

            for traceFile in os.listdir(tracePath):
                if traceFile.startswith(prefix):
                    util.copyFile(os.path.normpath(tracePath + "/" + traceFile), destinationDir, keepOriginals)

            util.copyFile(t.config.configFilename(), destinationDir, keepOriginals)
            t.config.setConfigFilename(os.path.normpath(destinationDir + "/" + os.path.split(t.config.configFilename())[1]))
        self.sigStatusChanged.emit()

    def __del__(self):
        if __debug__: logging.debug('Deleted: ' + str(self))