[Forensics-changes] [SCM] debian-forensics/guymager branch, debian, updated. debian/0.4.2-2-5-g966019b

Michael Prokop mika at debian.org
Thu Apr 1 23:13:15 UTC 2010


The following commit has been merged in the debian branch:
commit 6b50bd7cb7a6a5c22ee834070473518bb5bfe2a6
Author: Michael Prokop <mika at debian.org>
Date:   Thu Apr 1 22:22:18 2010 +0200

    Merging upstream version 0.5.2.

diff --git a/aaff.cpp b/aaff.cpp
index b153ad2..6ff4994 100644
--- a/aaff.cpp
+++ b/aaff.cpp
@@ -14,8 +14,8 @@
 
 #include <netinet/in.h>
 #include <string.h>
+#include <time.h>    //lint !e537 repeated include file
 #include <stdlib.h>
-#include <time.h>
 #include <zlib.h>
 
 #include <QString>
@@ -61,6 +61,7 @@ typedef struct
    unsigned int NameLen;
    unsigned int DataLen;
    unsigned int Argument;          // Named "flags" in original aff source, named "arg" in afinfo output.
+   char         Name[];
 } t_AffSegmentHeader;
 
 // Between header and footer lie the segment name and the data
@@ -79,10 +80,14 @@ typedef struct
 typedef struct _t_Aaff
 {
    FILE               *pFile;
+   bool                 OpenedForWrite;
    unsigned long long   PagesWritten;
+   unsigned long long   PagesRead;
 
    t_AffSegmentHeader   SegmentHeader;  // Optimisation: This header and this footer only need to be
    t_AffSegmentFooter   SegmentFooter;  // allocated and initialised once, and can be used again and again
+   unsigned char      *pUncompressBuffer;
+   unsigned int         UncompressBufferLen;
 } t_Aaff;
 
 #define AAFF_MD5_LEN                16
@@ -103,10 +108,10 @@ unsigned char AaffBadSectorMarker[AAFF_BADSECTORMARKER_MAXLEN];
 //  Utility functions
 // -------------------
 
-static bool AaffIsZero (unsigned char *pData, int DataLen)
+static bool AaffIsZero (unsigned char *pData, unsigned int DataLen)
 {
-   long long *pBuff    = (long long *)pData;
-   const int   CmpSize = sizeof (long long);   // 64 bit operations for optimal performance on amd64 processors
+   long long          *pBuff    = (long long *)pData;   //lint !e826   Suspicious pointer-to-pointer conversion
+   const unsigned int   CmpSize = sizeof (long long);   // 64 bit operations for optimal performance on amd64 processors
 
    while (DataLen >= CmpSize)
    {
@@ -131,7 +136,7 @@ static bool AaffIsZero (unsigned char *pData, int DataLen)
 
 static APIRET AaffWriteSegment (t_pAaff pAaff, const char *pName, unsigned int Argument, const unsigned char *pData, unsigned int DataLen)
 {
-   int NameLen0 = strlen(pName);
+   unsigned int NameLen0 = strlen(pName);
 
    pAaff->SegmentHeader.NameLen    = htonl(NameLen0);
    pAaff->SegmentHeader.DataLen    = htonl(DataLen);
@@ -184,30 +189,67 @@ static APIRET AaffWriteSegmentGID (t_pAaff pAaff)
    return NO_ERROR;
 }
 
-
 // ---------------
 //  API functions
 // ---------------
 
+APIRET AaffCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len)
+{
+   if (Len > AAFF_BADSECTORMARKER_MAXLEN)
+      CHK (ERROR_AAFF_SECTORSIZE_TOO_BIG)
+
+   memcpy (pBuffer, &AaffBadSectorMarker[0], Len);
+
+   return NO_ERROR;
+}
+
+// ---------------------
+//  API write functions
+// ---------------------
+
+static APIRET AaffCreateHandle (t_pAaff *ppAaff)
+{
+   *ppAaff = (t_pAaff) UTIL_MEM_ALLOC(sizeof(t_Aaff));
+   if (*ppAaff == NULL)
+      CHK (ERROR_AAFF_MEMALLOC_FAILED)
+
+   memset (*ppAaff, 0, sizeof(t_Aaff));
+
+   return NO_ERROR;
+}
+
+static APIRET AaffDestroyHandle (t_pAaff *ppAaff)
+{
+   if ((*ppAaff)->pUncompressBuffer)
+      free ((*ppAaff)->pUncompressBuffer);  // Must released with free, as realloc is used for allocating it
+
+   memset (*ppAaff, 0, sizeof(t_Aaff));
+   UTIL_MEM_FREE (*ppAaff);
+   *ppAaff = NULL;
+
+   return NO_ERROR;
+}
+
+//lint -save -esym(613,pAaff)   Possible use of null pointer pAaff
 APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int PageSize)
 {
    t_pAaff pAaff;
    char     Buff[512];
 
+   *ppAaff = NULL;
+
    // Open file and intialise
    // -----------------------
    if (SectorSize > AAFF_BADSECTORMARKER_MAXLEN)
       CHK (ERROR_AAFF_SECTORSIZE_TOO_BIG)
 
-   *ppAaff = NULL;
-   pAaff = (t_pAaff) UTIL_MEM_ALLOC(sizeof(t_Aaff));
-   if (pAaff == NULL)
-      CHK (ERROR_AAFF_MEMALLOC_FAILED)
+   CHK (AaffCreateHandle (&pAaff))
 
+   pAaff->OpenedForWrite = true;
    pAaff->pFile = fopen64 (pFilename, "w");
    if (pAaff->pFile == NULL)
    {
-      UTIL_MEM_FREE (pAaff);
+      CHK (AaffDestroyHandle (ppAaff))
       CHK (ERROR_AAFF_CANNOT_CREATE_FILE)
    }
    *ppAaff = pAaff;
@@ -235,9 +277,12 @@ APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long Devi
 
    return NO_ERROR;
 }
+//lint -restore
 
-APIRET AaffClose (t_pAaff pAaff, unsigned long long BadSectors, unsigned char *pMD5, unsigned char *pSHA256, int Duration)
+APIRET AaffClose (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, int Duration)
 {
+   t_pAaff pAaff = *ppAaff;
+
    CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_BADSECTORS  , BadSectors))
    CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_MD5         , 0, pMD5   , AAFF_MD5_LEN   ))
    CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_SHA256      , 0, pSHA256, AAFF_SHA256_LEN))
@@ -252,9 +297,12 @@ APIRET AaffClose (t_pAaff pAaff, unsigned long long BadSectors, unsigned char *p
    if (fclose (pAaff->pFile))
       CHK (ERROR_AAFF_CANNOT_CLOSE_FILE)
 
+   CHK (AaffDestroyHandle (ppAaff))
+
    return NO_ERROR;
 }
 
+//lint -save -esym(613,pPreProcess)   Possible use of null pointer
 APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut)
 {
    t_pAaffPreprocess pPreProcess;
@@ -291,8 +339,9 @@ APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn,
 
    return NO_ERROR;
 }
+//lint -restore
 
-APIRET AaffWrite (t_pAaff pAaff, t_pAaffPreprocess pPreprocess, unsigned char *pData, unsigned int DataLen)
+APIRET AaffWrite (t_pAaff pAaff, t_pAaffPreprocess pPreprocess, const unsigned char *pData, unsigned int DataLen)
 {
    char SegmentName[64];
 
@@ -300,29 +349,174 @@ APIRET AaffWrite (t_pAaff pAaff, t_pAaffPreprocess pPreprocess, unsigned char *p
 
    if (pPreprocess->Zero)
    {
-      int Len = htonl(DataLen);
-      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZERO, (unsigned char *) &Len, 4))
+      unsigned int Len = htonl(DataLen);
+      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZERO, (unsigned char *) &Len, sizeof (Len)))
    }
    else if (pPreprocess->Compressed)
-      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZLIB, pData, pPreprocess->DataLenOut))
-   else
-      CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_UNCOMPRESSED   , pData, DataLen))
+        CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_COMPRESSED_ZLIB, pData, pPreprocess->DataLenOut))
+   else CHK (AaffWriteSegment (pAaff, &SegmentName[0], AFF_PAGEFLAGS_UNCOMPRESSED   , pData, DataLen))
 
    UTIL_MEM_FREE (pPreprocess);
 
    return NO_ERROR;
 }
 
-APIRET AaffCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len)
+// ---------------------
+//  API read functions
+// ---------------------
+
+APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename)
 {
-   if (Len > AAFF_BADSECTORMARKER_MAXLEN)
-      CHK (ERROR_AAFF_SECTORSIZE_TOO_BIG)
+   t_pAaff pAaff;
+   char     Signature[strlen(AFF_HEADER)+1];
 
-   memcpy (pBuffer, &AaffBadSectorMarker[0], Len);
+   *ppAaff = NULL;
+   CHK (AaffCreateHandle (&pAaff))
+
+   pAaff->OpenedForWrite = false;
+   pAaff->pUncompressBuffer   = NULL;
+   pAaff->UncompressBufferLen = 0;
+   pAaff->PagesRead           = 0;
+   pAaff->pFile = fopen64 (pFilename, "r");
+   if (pAaff->pFile == NULL)
+   {
+      UTIL_MEM_FREE (pAaff);
+      CHK (ERROR_AAFF_CANNOT_OPEN_FILE)
+   }
+
+   // Check signature
+   // ---------------
+   if (fread (&Signature, sizeof(Signature), 1, pAaff->pFile) != 1)
+      return ERROR_AAFF_CANNOT_READ_SIGNATURE;
+
+   if (memcmp (Signature, AFF_HEADER, sizeof(Signature)) != 0)
+      return ERROR_AAFF_INVALID_SIGNATURE;
+
+   *ppAaff = pAaff;
+
+   return NO_ERROR;
+}
+
+APIRET AaffClose (t_pAaff *ppAaff)
+{
+   if (fclose ((*ppAaff)->pFile))
+      CHK (ERROR_AAFF_CANNOT_CLOSE_FILE)
+
+   CHK (AaffDestroyHandle (ppAaff))
+
+   return NO_ERROR;
+}
+
+
+APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDataLen)
+{
+   t_AffSegmentHeader Header;
+   t_AffSegmentFooter Footer;
+   char               SegmentName[100];
+   char             *pSegmentNamePageNumber;
+   char             *pTail;
+   bool               Found=false;
+   uLongf             DataLen = *pDataLen;
+   int                rc;
+
+   // Search for the next segment whose name starts with "page"
+   // ---------------------------------------------------------
+   do
+   {
+      if (fread  (&Header, offsetof(t_AffSegmentHeader, Name), 1, pAaff->pFile) != 1)
+         return ERROR_AAFF_CANNOT_READ_HEADER;
+      if (strcmp (&Header.Magic[0], AFF_SEGMENT_HEADER_MAGIC) != 0)
+         return ERROR_AAFF_INVALID_HEADER;
+      Header.NameLen  = ntohl (Header.NameLen );
+      Header.DataLen  = ntohl (Header.DataLen );
+      Header.Argument = ntohl (Header.Argument);
+
+      if (Header.NameLen >= sizeof(SegmentName))
+         return ERROR_AAFF_INVALID_SEGMENT_NAME;
+
+      if (fread  (&SegmentName[0], Header.NameLen, 1, pAaff->pFile) != 1)
+         return ERROR_AAFF_CANNOT_READ_HEADER;
+      SegmentName[Header.NameLen] = '\0';
+
+      Found            = (strncmp (&SegmentName[0], AFF_SEGNAME_PAGE, strlen(AFF_SEGNAME_PAGE)) == 0); // The segment name must start with "page"
+      if (Found) Found = (strlen  (&SegmentName[0]) > strlen(AFF_SEGNAME_PAGE));                       // The string "page" must be followed by at least 1 digit
+      if (Found) Found = isdigit  ( SegmentName[strlen(AFF_SEGNAME_PAGE)]);                            // Check if the following char is a digit (Some checking done after strtol, see below)
+
+      if (!Found)
+      {
+         rc = fseeko64 (pAaff->pFile, Header.DataLen+sizeof(t_AffSegmentFooter), SEEK_CUR);
+         if (rc)
+            return ERROR_AAFF_CANNOT_SEEK;
+      }
+   } while (!Found);
+
+   // Check page number
+   // -----------------
+   pSegmentNamePageNumber  = &SegmentName[strlen(AFF_SEGNAME_PAGE)];
+   unsigned int PageNumber = strtol (pSegmentNamePageNumber, &pTail, 10);
+   if (*pTail != '\0')                 return ERROR_AAFF_INVALID_PAGE_NUMBER;  // There should be no extra chars after the number
+   if (PageNumber != pAaff->PagesRead) return ERROR_AAFF_INVALID_PAGE_ORDER;
+   pAaff->PagesRead++;
+
+   // Get data
+   // --------
+   if (Header.DataLen > *pDataLen)
+      return ERROR_AAFF_PAGE_LARGER_THAN_BUFFER;
+
+   switch (Header.Argument)
+   {
+      case AFF_PAGEFLAGS_UNCOMPRESSED:
+         if (fread (pData, Header.DataLen, 1, pAaff->pFile) != 1)
+            return ERROR_AAFF_CANNOT_READ_DATA;
+         *pDataLen = Header.DataLen;
+         break;
+      case AFF_PAGEFLAGS_COMPRESSED_ZERO:
+         unsigned int Len;
+         if (fread (&Len, sizeof(Len), 1, pAaff->pFile) != 1)
+            return ERROR_AAFF_CANNOT_READ_DATA;
+         Len = ntohl (Len);
+         memset (pData, 0, Len);
+         *pDataLen = Len;
+         break;
+      case AFF_PAGEFLAGS_COMPRESSED_ZLIB:
+         if (pAaff->UncompressBufferLen < Header.DataLen)
+         {
+            pAaff->pUncompressBuffer = (unsigned char *) realloc (pAaff->pUncompressBuffer, Header.DataLen);
+            if (pAaff->pUncompressBuffer == NULL)
+               CHK (ERROR_AAFF_MEMALLOC_FAILED)
+            pAaff->UncompressBufferLen = Header.DataLen;
+         }
+         if (fread (pAaff->pUncompressBuffer, Header.DataLen, 1, pAaff->pFile) != 1)
+            return ERROR_AAFF_CANNOT_READ_DATA;
+
+         rc = uncompress (pData, &DataLen, pAaff->pUncompressBuffer, Header.DataLen);
+         *pDataLen = DataLen;
+         if (rc != Z_OK)
+         {
+            LOG_ERROR ("Zlib uncompress returned %d", rc)
+               return ERROR_AAFF_UNCOMPRESS_FAILED;
+         }
+         break;
+      default:
+         LOG_INFO ("Invalid page argument: %d", Header.Argument)
+         CHK (ERROR_AAFF_INVALID_PAGE_ARGUMENT)
+   }
+
+   // Check footer
+   // ------------
+   if (fread (&Footer, sizeof(Footer), 1, pAaff->pFile) != 1)
+      return ERROR_AAFF_CANNOT_READ_FOOTER;
+   if (strcmp (&Footer.Magic[0], AFF_SEGMENT_FOOTER_MAGIC) != 0)
+      return ERROR_AAFF_INVALID_FOOTER;
+
+   unsigned int SegmentLen = sizeof (t_AffSegmentHeader) + sizeof(t_AffSegmentFooter) + Header.NameLen + Header.DataLen;
+   if (ntohl(Footer.SegmentLen) != SegmentLen)
+      return ERROR_AAFF_INVALID_SEGMENTLEN;
 
    return NO_ERROR;
 }
 
+
 // -----------------------
 //  Module initialisation
 // -----------------------
@@ -331,13 +525,30 @@ APIRET AaffInit (void)
 {
    int i;
 
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_MEMALLOC_FAILED   ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CREATE_FILE))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_WRITE_FILE ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CLOSE_FILE ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_FLUSH_FILE ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_SECTORSIZE_TOO_BIG))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_COMPRESSION_FAILED))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_MEMALLOC_FAILED        ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CREATE_FILE     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_OPEN_FILE       ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_WRITE_FILE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CLOSE_FILE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_FLUSH_FILE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_SIGNATURE  ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_HEADER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_FOOTER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_DATA       ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_SEEK            ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_SECTORSIZE_TOO_BIG     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_COMPRESSION_FAILED     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SIGNATURE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_HEADER         ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_FOOTER         ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENTLEN     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_ORDER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_ARGUMENT  ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENT_NAME   ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_NUMBER    ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_PAGE_LARGER_THAN_BUFFER))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_UNCOMPRESS_FAILED      ))
+
 
    srandom (time (0));
 
diff --git a/aaff.h b/aaff.h
index 75e319a..160de1f 100644
--- a/aaff.h
+++ b/aaff.h
@@ -32,10 +32,17 @@ typedef struct
 //              Functions
 // ------------------------------------
 
-APIRET AaffOpen       (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int PageSize);
-APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut);
-APIRET AaffWrite      (t_pAaff   pAaff, t_pAaffPreprocess pPreprocess, unsigned char *pData, unsigned int DataLen);
-APIRET AaffClose      (t_pAaff   pAaff, unsigned long long BadSectors, unsigned char *pMD5, unsigned char *pSHA256, int Duration);
+// Write access functions
+APIRET AaffOpen         (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int PageSize);
+APIRET AaffPreprocess   (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut);
+APIRET AaffWrite        (t_pAaff   pAaff, t_pAaffPreprocess pPreprocess, const unsigned char *pData, unsigned int DataLen);
+APIRET AaffClose        (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, int Duration);
+
+// Read access functions
+APIRET AaffOpen         (t_pAaff *ppAaff, const char *pFilename);
+APIRET AaffReadNextPage (t_pAaff   pAaff, unsigned char *pData, unsigned int *pDataLen);
+APIRET AaffClose        (t_pAaff *ppAaff);
+
 
 APIRET AaffWriteSegmentStr (t_pAaff pAaff, const char *pName, unsigned int Argument, const char *pStr);
 
@@ -53,13 +60,30 @@ enum
 {
    ERROR_AAFF_MEMALLOC_FAILED   = ERROR_BASE_AAFF + 1,
    ERROR_AAFF_CANNOT_CREATE_FILE,
+   ERROR_AAFF_CANNOT_OPEN_FILE,
    ERROR_AAFF_CANNOT_WRITE_FILE,
    ERROR_AAFF_CANNOT_CLOSE_FILE,
    ERROR_AAFF_CANNOT_FLUSH_FILE,
+   ERROR_AAFF_CANNOT_READ_SIGNATURE,
+   ERROR_AAFF_CANNOT_READ_HEADER,
+   ERROR_AAFF_CANNOT_READ_FOOTER,
+   ERROR_AAFF_CANNOT_READ_DATA,
+   ERROR_AAFF_CANNOT_SEEK,
    ERROR_AAFF_SECTORSIZE_TOO_BIG,
    ERROR_AAFF_COMPRESSION_FAILED,
+   ERROR_AAFF_INVALID_SIGNATURE,
+   ERROR_AAFF_INVALID_HEADER,
+   ERROR_AAFF_INVALID_FOOTER,
+   ERROR_AAFF_INVALID_SEGMENTLEN,
+   ERROR_AAFF_INVALID_PAGE_ORDER,
+   ERROR_AAFF_INVALID_PAGE_ARGUMENT,
+   ERROR_AAFF_INVALID_SEGMENT_NAME,
+   ERROR_AAFF_INVALID_PAGE_NUMBER,
+   ERROR_AAFF_PAGE_LARGER_THAN_BUFFER,
+   ERROR_AAFF_UNCOMPRESS_FAILED
 };
 
 #endif
 
 
+
diff --git a/common.h b/common.h
index 292b1ee..650464f 100644
--- a/common.h
+++ b/common.h
@@ -52,10 +52,23 @@ extern void *pOffsetOfNullPointer;
 #endif
 
 
-class t_Device;                      // As t_Device is the core structure of guymager and as it is needed
+class   t_Device;                    // As t_Device is the core structure of guymager and as it is needed
 typedef t_Device       *t_pDevice;   // all the time, it is easiest to declare it here (eventhough I don't
 typedef t_Device const *t_pcDevice;  // like that style too much, but we won't change C++ at this time).
 
-
 #define EWF_MULTITHREADED_COMPRESSION_CHUNK_SIZE       32768
 
+#define GETMAX(a,b) ((a)>(b)?(a):(b))
+#define GETMIN(a,b) ((a)<(b)?(a):(b))
+
+
+typedef unsigned char      t_uint8;
+typedef unsigned short     t_uint16;
+typedef unsigned int       t_uint32;
+typedef unsigned long long t_uint64;
+
+typedef char               t_int8;
+typedef short              t_int16;
+typedef int                t_int32;
+typedef long long          t_int64;
+
diff --git a/config.cpp b/config.cpp
index 5465f79..f5ecfb0 100644
--- a/config.cpp
+++ b/config.cpp
@@ -108,7 +108,6 @@ static APIRET CfgDlgAcquireRuleEnd                                            (t
 static APIRET CfgIniLang (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText);
 static APIRET CfgIniCPUs (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText);
 static APIRET CfgIniMem  (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText);
-static APIRET CfgIniFifo (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText);
 
 // ------------------------------------
 //     Configuration parameter table
@@ -260,6 +259,20 @@ static t_ToolCfgSet SetArrCompressionThreads[] =
 };
 
 
+static t_ToolCfgSet SetArrDeviceScanMethod[] =
+{
+   // Name in cfg file  Corresponding value
+   // ----------------------------------------
+   { "LibParted",  SCANMETHOD_LIBPARTED },
+   { "Parted",     SCANMETHOD_LIBPARTED },
+   { "DBusHAL",    SCANMETHOD_DBUSHAL   },
+   { "HAL",        SCANMETHOD_DBUSHAL   },
+   { "DBusDevKit", SCANMETHOD_DBUSDEVKIT},
+   { "DevKit",     SCANMETHOD_DBUSDEVKIT},
+   {  NULL,        0                    }
+};
+
+
 #define ELT(Elt)      ((long) &CfgLocal.CfgData.Elt)
 #define ELT_SIZ(Elt)  ELT(Elt), (sizeof (CfgLocal.CfgData.Elt)-1)                      // for strings only, thus substract 1 byte (for terminating 0)
 #define INIARR(Arr)   ((t_pToolCfgSet) (t_pvoid)&Arr)
@@ -299,14 +312,14 @@ static t_ToolCfgParamDesc CfgParamDescArr[] =
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"EwfSegmentSize"                , CFGTYPE_INTEGER, ELT(EwfSegmentSize)                ,                0,       1,    2047, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"SpecialFilenameChars"          , CFGTYPE_STRING , ELT_SIZ(SpecialFilenameChars)      ,                         0,       0, NULL                            }, CFG_FILLUP_FORLINT},
 
-   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"ScanUsingDbusHal"              , CFGTYPE_SET    , ELT(ScanUsingDbusHal)              ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"DeviceScanMethod"              , CFGTYPE_SET    , ELT(DeviceScanMethod)              ,                0,       0,       0, INIARR(SetArrDeviceScanMethod)  }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"ScanInterval"                  , CFGTYPE_INTEGER, ELT(ScanInterval                  ),                0,       1, 8640000, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"CommandGetSerialNumber"        , CFGTYPE_STRING , ELT_SIZ(CommandGetSerialNumber    ),                         0,       0, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeDD"               , CFGTYPE_INTEGER, ELT(FifoBlockSizeDD               ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeEWF"              , CFGTYPE_INTEGER, ELT(FifoBlockSizeEWF              ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeAFF"              , CFGTYPE_INTEGER, ELT(FifoBlockSizeAFF              ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
-   {CFGASSIGN_BOTH_MULTIPLE, CfgIniMem  , {"FifoMaxMem"                    , CFGTYPE_INTEGER, ELT(FifoMaxMem                    ),                0,       0, 1000000, NULL                            }, CFG_FILLUP_FORLINT},
-   {CFGASSIGN_BOTH_MULTIPLE, CfgIniFifo , {"FifoMaxEntries"                , CFGTYPE_INTEGER, ELT(FifoMaxEntries                ),                0,       0, 9999999, NULL                            }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, CfgIniMem  , {"FifoMaxMem"                    , CFGTYPE_INTEGER, ELT(FifoMaxMem                    ),                0,       0,    2000, NULL                            }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoMemoryManager"             , CFGTYPE_SET    , ELT(FifoMemoryManager)             ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"UseSeparateHashThread"         , CFGTYPE_SET    , ELT(UseSeparateHashThread)         ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, CfgIniCPUs , {"CompressionThreads"            , CFGTYPE_SET    , ELT(CompressionThreads)            ,                0,       0,    1024, INIARR(SetArrCompressionThreads)}, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"SignalHandling"                , CFGTYPE_SET    , ELT(SignalHandling)                ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
@@ -434,13 +447,14 @@ static t_pCfgBuffDlgAcquireField pFld0 = NULL;
 
 static t_ToolCfgDataDesc CfgDescArrDlgAcquireField[] =
 {
-   // ParameterName   Type (see        DestinationOfs    Len  Min  Max  SetArray
-   // in cfg file     t_ToolCfgType)   type is long                     (CFGTYPE_SET only)
-   // ------------------------------------------------------------------------------------
-   {  "FieldName"   , CFGTYPE_STRING , ELT_SIZ(FieldName)   ,   0,   0, NULL           },
-   {  "EntryMode"   , CFGTYPE_SET    , ELT(EntryMode)   ,  0,   0,   0, SetArrEntryMode},
-   {  "DefaultValue", CFGTYPE_STRING , ELT_SIZ(DefaultValue),   0,   0, NULL           },
-   {  NULL          , CFGTYPE_NULL   , 0                ,  0,   0,   0, NULL           }
+   // ParameterName     Type (see        DestinationOfs     Len  Min  Max  SetArray
+   // in cfg file       t_ToolCfgType)   type is long                      (CFGTYPE_SET only)
+   // ---------------------------------------------------------------------------------------
+   {  "FieldName"     , CFGTYPE_STRING , ELT_SIZ(FieldName)     ,  0,   0, NULL           },
+   {  "EntryModeImage", CFGTYPE_SET    , ELT(EntryModeImage),  0,  0,   0, SetArrEntryMode},
+   {  "EntryModeClone", CFGTYPE_SET    , ELT(EntryModeClone),  0,  0,   0, SetArrEntryMode},
+   {  "DefaultValue"  , CFGTYPE_STRING , ELT_SIZ(DefaultValue)  ,  0,   0, NULL           },
+   {  NULL            , CFGTYPE_NULL   , 0                  ,  0,  0,   0, NULL           }
 };
 
 
@@ -539,7 +553,7 @@ APIRET CfgIniLang (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText)
    if (Language.compare ("AUTO", Qt::CaseInsensitive) == 0)
    {
       QString LocaleName = QLocale::system().name();
-      QString Language = LocaleName.split('_')[0];
+      Language = LocaleName.split('_')[0];
       snprintf (CONFIG(Language), sizeof(CONFIG(Language)), "%s", QSTR_TO_PSZ(Language));
 
       LOG_INFO ("Parameter %s set to 'AUTO', switching to language '%s'", pCfgParamDesc->DataDesc.pName, CONFIG(Language))
@@ -579,26 +593,10 @@ APIRET CfgIniMem (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText)
    meminfo();
    if (CONFIG (FifoMaxMem) == 0)
    {
-      CONFIG (FifoMaxMem) = std::max (1, (int)(kb_main_total / (6*1024))); // Use one sixth of the available mem, convert KB to MB
+      CONFIG (FifoMaxMem) = GETMAX (1, (int)(kb_main_total / (8*1024)));   // Use one eighth of the available mem, convert KB to MB
+      CONFIG (FifoMaxMem) = GETMIN (CONFIG (FifoMaxMem), 64);              // Stay below 64MB
       LOG_INFO ("Parameter %s set to 0 (auto); %lu MB of RAM detected.", pParamName, kb_main_total/1024)
-      LOG_INFO ("Setting %s to %d.", pParamName, CONFIG (FifoMaxMem))
-   }
-
-   return NO_ERROR;
-}
-
-APIRET CfgIniFifo (t_pToolCfgParamDesc pCfgParamDesc, t_pchar *ppErrorText)
-{
-   t_pcchar pParamName;
-
-   *ppErrorText = NULL;
-   pParamName = pCfgParamDesc->DataDesc.pName;
-
-   meminfo();
-   if (CONFIG (FifoMaxEntries) == 0)
-   {
-      CONFIG (FifoMaxEntries) = 8;
-      LOG_INFO ("Parameter %s set to 0 (auto); setting it to %d.", pParamName, CONFIG (FifoMaxEntries))
+      LOG_INFO ("Setting %s to %d (i.e. using %d MB per acquisition as FIFO memory)", pParamName, CONFIG (FifoMaxMem), CONFIG (FifoMaxMem))
    }
 
    return NO_ERROR;
@@ -936,6 +934,10 @@ static APIRET CfgInitializeDlgAcquireFieldNames (void)
       CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_DEST_IMAGEFILENAME;
       CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_DEST_INFODIRECTORY;
       CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_DEST_INFOFILENAME;
+      CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_HASH_CALC_MD5;
+      CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_HASH_CALC_SHA256;
+      CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_HASH_VERIFY_SRC;
+      CfgLocal.DlgAcquireFieldNames += CFG_DLGACQUIRE_HASH_VERIFY_DST;
    }
    return NO_ERROR;
 }
@@ -953,7 +955,7 @@ static APIRET CfgDestroyDlgAcquireFields (void)
 static APIRET CfgDlgAcquireFieldStart (t_pchar /*pTableId*/, long *pBaseAddr, t_pcchar *ppErrorText)
 {
    CHK (CfgInitializeDlgAcquireFieldNames ())
-   CHK (CfgDestroyDlgAcquireFields())
+//   CHK (CfgDestroyDlgAcquireFields())
    *pBaseAddr = (long) &CfgLocal.CfgBuffDlgAcquireField;
    *ppErrorText = NULL;
 
@@ -964,33 +966,33 @@ static APIRET CfgDlgAcquireFieldSaveAndNext (long *pBaseAddr, t_pcchar *ppErrorT
 {
    t_pCfgBuffDlgAcquireField pBuff;
    t_pCfgDlgAcquireField     pField;
+   bool                       Found=false;
 
    *ppErrorText = NULL;
    pBuff = &CfgLocal.CfgBuffDlgAcquireField;
 
-   if (strcmp(pBuff->FieldName, CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY_ALT) == 0)  // For compatibility. Treat the old, common (image and info)
-      strcpy (pBuff->FieldName, CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY);           // directory name just like the new image directory name
-
    if (CfgLocal.DlgAcquireFieldNames.contains(pBuff->FieldName))
    {
-      for (int i=0; i<CfgLocal.DlgAcquireFields.count(); i++)
+      for (int i=0; (i<CfgLocal.DlgAcquireFields.count()) && !Found; i++)
       {
-         if (CfgLocal.DlgAcquireFields[i]->FieldName == pBuff->FieldName)
-         {
-            *ppErrorText = "This field name figures twice in the table";
-            return NO_ERROR;
-         }
+         pField = CfgLocal.DlgAcquireFields[i];
+         Found = (pField->FieldName == pBuff->FieldName);
+      }
+      if (!Found)
+      {
+         pField = new (t_CfgDlgAcquireField);
+         pField->FieldName = pBuff->FieldName;
+         pField->EwfField  = pField->FieldName.startsWith (CFG_DLGACQUIRE_EWF_FIELDID , Qt::CaseInsensitive);
+         pField->HashField = pField->FieldName.startsWith (CFG_DLGACQUIRE_HASH_FIELDID, Qt::CaseInsensitive);
+         pField->DstField  = pField->FieldName.startsWith (CFG_DLGACQUIRE_DST_FIELDID , Qt::CaseInsensitive);
+         pField->DirField  = pField->FieldName.contains   (CFG_DLGACQUIRE_DIR_FIELDID , Qt::CaseInsensitive);
+         CfgLocal.DlgAcquireFields.append (pField);
       }
-      pField = new (t_CfgDlgAcquireField);
-      pField->FieldName    = pBuff->FieldName;
-      pField->EntryMode    = pBuff->EntryMode;
-      pField->DefaultValue = pBuff->DefaultValue;
-      pField->pLineEdit    = NULL;
-      pField->EwfField = pField->FieldName.startsWith (CFG_DLGACQUIRE_EWF_FIELDID, Qt::CaseInsensitive);
-      pField->DstField = pField->FieldName.startsWith (CFG_DLGACQUIRE_DST_FIELDID, Qt::CaseInsensitive);
-      pField->DirField = pField->FieldName.contains   (CFG_DLGACQUIRE_DIR_FIELDID, Qt::CaseInsensitive);
-
-      CfgLocal.DlgAcquireFields.append (pField);
+      pField->EntryModeImage = pBuff->EntryModeImage;
+      pField->EntryModeClone = pBuff->EntryModeClone;
+      pField->DefaultValue   = pBuff->DefaultValue;
+      pField->pLineEdit      = NULL;
+      pField->pCheckBox      = NULL;
    }
    else
    {
diff --git a/config.h b/config.h
index 97673ac..c6a4b6f 100644
--- a/config.h
+++ b/config.h
@@ -74,10 +74,19 @@ typedef enum
    COLOR_DEFAULT  // Not really a color, but used for specifying, that a widget should switch to its default color (grey for a button, for instance)
 } t_CfgColor;
 
+typedef enum
+{
+   SCANMETHOD_LIBPARTED=0,
+   SCANMETHOD_DBUSHAL,
+   SCANMETHOD_DBUSDEVKIT,
+
+   SCANMETHOD_COUNT
+} t_CfgScanMethod;
 
 // ATTENTION: The data of the following structure is filled in by the CFG tool. As this
 // one doesn't know about 'bool' (it's written in ANSI C), bool MUST not be used here.
 // ------------------------------------------------------------------------------------
+#undef  bool
 #define bool "Do not use bool, take int instead"
 typedef struct
 {
@@ -97,7 +106,7 @@ typedef struct
    int                  ScreenRefreshInterval;
    int                  UseFileDialogFromQt;
 
-   int                  ScanUsingDbusHal;
+   t_CfgScanMethod      DeviceScanMethod;
    int                  ScanInterval;
    char                 CommandGetSerialNumber[CFG_MAX_PATH_LEN+1];
 
@@ -113,7 +122,7 @@ typedef struct
    int                  FifoBlockSizeEWF;
    int                  FifoBlockSizeAFF;
    int                  FifoMaxMem;
-   int                  FifoMaxEntries;
+   int                  FifoMemoryManager;
    int                  UseSeparateHashThread;
    int                  CompressionThreads;
    int                  SignalHandling;
@@ -162,9 +171,12 @@ typedef struct
 // DlgAcquire fields and rules
 // ---------------------------
 
-#define CFG_DLGACQUIRE_EWF_FIELDID    "Ewf"
-#define CFG_DLGACQUIRE_DST_FIELDID    "Dest"
-#define CFG_DLGACQUIRE_DIR_FIELDID    "Directory"
+#define CFG_DLGACQUIRE_EWF_FIELDID        "Ewf"
+#define CFG_DLGACQUIRE_HASH_FIELDID       "Hash"
+#define CFG_DLGACQUIRE_HASHCALC_FIELDID   "HashCalc"
+#define CFG_DLGACQUIRE_HASHVERIFY_FIELDID "HashVerify"
+#define CFG_DLGACQUIRE_DST_FIELDID        "Dest"
+#define CFG_DLGACQUIRE_DIR_FIELDID        "Directory"
 
 #define CFG_DLGACQUIRE_EWF_CASENUMBER          QT_TRANSLATE_NOOP("t_DlgAcquire", "EwfCaseNumber"     )
 #define CFG_DLGACQUIRE_EWF_EVIDENCENUMBER      QT_TRANSLATE_NOOP("t_DlgAcquire", "EwfEvidenceNumber" )
@@ -172,16 +184,19 @@ typedef struct
 #define CFG_DLGACQUIRE_EWF_DESCRIPTION         QT_TRANSLATE_NOOP("t_DlgAcquire", "EwfDescription"    )
 #define CFG_DLGACQUIRE_EWF_NOTES               QT_TRANSLATE_NOOP("t_DlgAcquire", "EwfNotes"          )
 #define CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY     QT_TRANSLATE_NOOP("t_DlgAcquire", "DestImageDirectory")
-#define CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY_ALT QT_TRANSLATE_NOOP("t_DlgAcquire", "DestDirectory"     ) // Alternate name for compatibility with old Guymager versions
 #define CFG_DLGACQUIRE_DEST_IMAGEFILENAME      QT_TRANSLATE_NOOP("t_DlgAcquire", "DestImageFilename" )
 #define CFG_DLGACQUIRE_DEST_INFODIRECTORY      QT_TRANSLATE_NOOP("t_DlgAcquire", "DestInfoDirectory" )
 #define CFG_DLGACQUIRE_DEST_INFOFILENAME       QT_TRANSLATE_NOOP("t_DlgAcquire", "DestInfoFilename"  )
-
+#define CFG_DLGACQUIRE_HASH_CALC_MD5           QT_TRANSLATE_NOOP("t_DlgAcquire", "HashCalcMD5"       )
+#define CFG_DLGACQUIRE_HASH_CALC_SHA256        QT_TRANSLATE_NOOP("t_DlgAcquire", "HashCalcSHA256"    )
+#define CFG_DLGACQUIRE_HASH_VERIFY_SRC         QT_TRANSLATE_NOOP("t_DlgAcquire", "HashVerifySrc"     )
+#define CFG_DLGACQUIRE_HASH_VERIFY_DST         QT_TRANSLATE_NOOP("t_DlgAcquire", "HashVerifyDst"     )
 
 typedef struct
 {
    char            FieldName   [CFG_MAX_FIELDNAME_LEN+1];
-   t_CfgEntryMode  EntryMode;
+   t_CfgEntryMode  EntryModeImage;
+   t_CfgEntryMode  EntryModeClone;
    char            DefaultValue[CFG_MAX_MISC_LEN     +1];
 } t_CfgBuffDlgAcquireField, *t_pCfgBuffDlgAcquireField;
 
@@ -192,18 +207,22 @@ typedef struct
    char Value           [CFG_MAX_MISC_LEN     +1];
 } t_CfgBuffDlgAcquireRule, *t_pCfgBuffDlgAcquireRule;
 
+class QCheckBox;
 class t_DlgAcquireLineEdit;
 class t_CfgDlgAcquireField
 {
    public:
       QString                FieldName;
-      t_CfgEntryMode         EntryMode;
+      t_CfgEntryMode         EntryModeImage;
+      t_CfgEntryMode         EntryModeClone;
       QString                DefaultValue;
       QString                LastEnteredValue; // not set by config, used by DlgAcquire
       bool                   EwfField;         // This field is part of the EWF fields
+      bool                   HashField;        // This field is part of the hash calculation/verification fields
       bool                   DstField;         // This field is part of the fields for entering the image/info destination
       bool                   DirField;         // This is a directory field with a browse button
       t_DlgAcquireLineEdit *pLineEdit;
+      QCheckBox            *pCheckBox;
 };
 typedef t_CfgDlgAcquireField       *t_pCfgDlgAcquireField;
 typedef QList<t_pCfgDlgAcquireField> t_CfgDlgAcquireFields;
diff --git a/device.cpp b/device.cpp
index 7d8f159..f5cc82b 100644
--- a/device.cpp
+++ b/device.cpp
@@ -19,6 +19,7 @@
 #include "toolconstants.h"
 
 #include "common.h"
+#include "qtutil.h"
 #include "config.h"
 #include "mainwindow.h"
 #include "main.h"
@@ -40,6 +41,7 @@ void t_Device::Initialise (void)
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DEVICE_BAD_STATE                  ))
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DEVICE_BAD_ABORTREASON            ))
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DEVICE_NOT_CLEAN                  ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DEVICE_INVALID_MEDIAINFOSTATE     ))
       Initialised = true;
    }
 
@@ -50,16 +52,19 @@ void t_Device::Initialise (void)
    this->SectorSize           = 0;
    this->SectorSizePhys       = 0;
    this->Size                 = 0;
+   this->SpecialDevice        = false;
    this->Removable            = false;
 
    this->State                = Idle;
 //   this->Acquisition.Message       = QString();
    this->AbortRequest         = false;
    this->AbortReason          = None;
+   this->AbortCount           = 0;
    this->DeleteAfterAbort     = false;
+   this->pFifoMemory          = NULL;
    this->pFifoRead            = NULL;
    this->pThreadRead          = NULL;
-   this->pFileSrc             = NULL;
+   this->FileDescSrc          = t_Device::FileDescEmpty;
    this->CurrentReadPos       = 0;
 //   this->BadSectors
 //   this->BadSectorsVerify
@@ -70,16 +75,19 @@ void t_Device::Initialise (void)
 
    this->pThreadWrite         = NULL;
    this->CurrentWritePos      = 0;
-   this->CurrentVerifyPos     = 0;
+   this->CurrentVerifyPosSrc  = 0;
+   this->CurrentVerifyPosDst  = 0;
    this->pFifoWrite           = NULL;
 
    this->pThreadHash          = NULL;
    this->pFifoHashIn          = NULL;
    this->pFifoHashOut         = NULL;
-   memset (&this->MD5Digest         , 0, sizeof(this->MD5Digest         ));
-   memset (&this->MD5DigestVerify   , 0, sizeof(this->MD5DigestVerify   ));
-   memset (&this->SHA256Digest      , 0, sizeof(this->SHA256Digest      ));
-   memset (&this->SHA256DigestVerify, 0, sizeof(this->SHA256DigestVerify));
+   memset (&this->MD5Digest            , 0, sizeof(this->MD5Digest            ));
+   memset (&this->MD5DigestVerifySrc   , 0, sizeof(this->MD5DigestVerifySrc   ));
+   memset (&this->MD5DigestVerifyDst   , 0, sizeof(this->MD5DigestVerifyDst   ));
+   memset (&this->SHA256Digest         , 0, sizeof(this->SHA256Digest         ));
+   memset (&this->SHA256DigestVerifySrc, 0, sizeof(this->SHA256DigestVerifySrc));
+   memset (&this->SHA256DigestVerifyDst, 0, sizeof(this->SHA256DigestVerifyDst));
 
    this->pFifoCompressIn      = NULL;
    this->pFifoCompressOut     = NULL;
@@ -89,9 +97,12 @@ void t_Device::Initialise (void)
 //   this->Acquisition.Path          = QString();
 //   this->Acquisition.ImageFilename = QString();
 //   this->Acquisition.InfoFilename  = QString();
+   this->Acquisition.Clone         = false;
    this->Acquisition.Format        = t_File::NotSet;
-   this->Acquisition.CalcHashes    = false;
-   this->Acquisition.VerifySource  = false;
+   this->Acquisition.CalcMD5       = false;
+   this->Acquisition.CalcSHA256    = false;
+   this->Acquisition.VerifySrc     = false;
+   this->Acquisition.VerifyDst     = false;
 //   this->Acquisition.CaseNumber    = QString();
 //   this->Acquisition.EvidenceNumber= QString();
 //   this->Acquisition.Examiner      = QString();
@@ -116,8 +127,8 @@ void t_Device::InitialiseDeviceSpecific (const QString &SerialNumber, const QStr
    this->SectorSize     = SectorSize;
    this->SectorSizePhys = SectorSizePhys;
    this->Size           = Size;
-//   this->Size           = std::min (10737418240ULL, Size;  // For faster testing (we make guymager believe that the device is smaller)
-//   this->Size           = std::min (1073741824ULL, Size);  // For faster testing (we make guymager believe that the device is smaller)
+//   this->Size           = GETMIN (10737418240ULL, Size;  // For faster testing (we make guymager believe that the device is smaller)
+//   this->Size           = GETMIN (1073741824ULL, Size);  // For faster testing (we make guymager believe that the device is smaller)
 }
 
 t_Device::t_Device (const QString &SerialNumber, const QString &LinuxDevice, const QString &Model,
@@ -137,21 +148,17 @@ t_Device::t_Device (const QString &SerialNumber, const PedDevice *pPedDev)
 
 t_Device::~t_Device()
 {
-   if (pThreadRead   || pFifoRead    ||
-       pThreadHash   || pFifoHashIn  ||
-       pThreadWrite  || pFifoHashOut ||
-       pFileSrc      || pFifoWrite )
+   if (pFifoRead    || pThreadRead  ||
+       pFifoHashIn  || pThreadHash  ||
+       pFifoHashOut || pThreadWrite ||
+       pFifoWrite   || (FileDescSrc != t_Device::FileDescEmpty))
       CHK_EXIT (ERROR_DEVICE_NOT_CLEAN)
-
-   pThreadRead  = NULL; pFifoRead    = NULL;
-   pThreadHash  = NULL; pFifoHashIn  = NULL;
-   pThreadWrite = NULL; pFifoHashOut = NULL;
-   pFileSrc     = NULL; pFifoWrite   = NULL;
 }
 
 bool t_Device::HasHashThread (void) const
 {
-   return Acquisition.CalcHashes && CONFIG (UseSeparateHashThread);
+   return CONFIG (UseSeparateHashThread) && (Acquisition.CalcMD5 ||
+                                             Acquisition.CalcSHA256);
 }
 
 bool t_Device::HasCompressionThreads (void) const
@@ -180,38 +187,81 @@ QVariant t_Device::GetModel (t_pDevice pDevice)
 
 QVariant t_Device::GetState (t_pDevice pDevice)
 {
-   QString State;
+   QString StrState;
 
    switch (pDevice->State)
    {
-      case Idle        : if (pDevice->Local)
-                             State = t_MainWindow::tr("Local device");
-                         else State = t_MainWindow::tr("Idle");
-                         break;
-      case Acquire      : State = t_MainWindow::tr("Acquisition running" ); break;
-      case Verify       : State = t_MainWindow::tr("Verification running"); break;
-      case AcquirePaused: State = t_MainWindow::tr("Device disconnected, acquisition paused" ); break;
-      case VerifyPaused : State = t_MainWindow::tr("Device disconnected, verification paused"); break;
-      case Cleanup      : State = t_MainWindow::tr("Cleanup" ); break;
-      case Finished     : if (pDevice->Acquisition.VerifySource)
+      case Idle         : if (pDevice->Local)
+                                    StrState = t_MainWindow::tr("Local device");
+                          else if (MainGetDeviceList()->UsedAsCloneDestination(pDevice))
+                                    StrState = t_MainWindow::tr("Used in clone operation");
+                               else StrState = t_MainWindow::tr("Idle");
+                          break;
+      case Acquire      : if (pDevice->AbortRequest)
+                               StrState = t_MainWindow::tr("Aborting..."        );
+                          else StrState = t_MainWindow::tr("Acquisition running");
+
+                          if (pDevice->AbortRequest)
+                          {
+                             switch (pDevice->AbortCount)
+                             {
+                                case  0:
+                                case  1: break;
+                                case  2: StrState += " please be patient"; break;
+                                case  3: StrState += " just keep cool"   ; break;
+                                case  4: StrState += " I said KEEP COOL!"; break;
+                                case  5: StrState += " you start annoying me"; break;
+                                case  6: StrState += " just shut up"; break;
+                                case  7: StrState += " SHUT UP!"; break;
+                                case  8: StrState += " you want a segmentation fault?"; break;
+                                case  9: StrState += " you can have it if you want"; break;
+                                case 10: StrState += " I warn you"; break;
+                                case 11: StrState += " last warning"; break;
+                                case 12: StrState += " ultimate warning"; break;
+                                case 13: StrState += " one more time and I'll seg fault"; break;
+                                case 14: static bool JokeOver = false;
+                                         if (!JokeOver)
+                                         {
+                                            JokeOver = true;
+                                            printf ("\n%c[1;37;41m", ASCII_ESC);  // white on red
+                                            printf ("Signal no. 11 received: Segmentation fault");
+                                            printf ("%c[0m"      , ASCII_ESC);  // standard
+                                            (void) QtUtilSleep (4000);
+                                            printf ("     Just kidding  :-)");
+                                         }
+                                         StrState += " just kidding :-)";
+                                default: break;
+                             }
+                          }
+                          break;
+      case Verify       : StrState = t_MainWindow::tr("Verification running"); break;
+      case AcquirePaused: StrState = t_MainWindow::tr("Device disconnected, acquisition paused" ); break;
+      case VerifyPaused : StrState = t_MainWindow::tr("Device disconnected, verification paused"); break;
+      case Cleanup      : StrState = t_MainWindow::tr("Cleanup" ); break;
+      case Finished     : if ((pDevice->Acquisition.VerifySrc) || (pDevice->Acquisition.VerifyDst))
                           {
-                             if (HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerify   ) &&
-                                 HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerify))
-                                  State = t_MainWindow::tr("Finished - hashes verified & ok"      );
-                             else State = t_MainWindow::tr("Finished - hash verification mismatch");
+                             bool Match = true;
+                             if (pDevice->Acquisition.VerifySrc) Match = Match && HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerifySrc   )
+                                                                               && HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerifySrc);
+                             if (pDevice->Acquisition.VerifyDst) Match = Match && HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerifyDst   )
+                                                                               && HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerifyDst);
+                             if (Match)
+                                  StrState = t_MainWindow::tr("Finished - Verified & ok"      );
+                             else StrState = t_MainWindow::tr("Finished - Verification failed");
                           }
                           else
                           {
-                             State = t_MainWindow::tr("Finished");
+                             StrState = t_MainWindow::tr("Finished");
                           }
                           break;
       case Aborted : switch (pDevice->AbortReason)
                      {
-                        case t_Device::None                : State = t_MainWindow::tr("Aborted - Error: Reason is 'none'" ); break;
-                        case t_Device::UserRequest         : State = t_MainWindow::tr("Aborted by user" );                   break;
-                        case t_Device::ThreadWriteFileError: State = t_MainWindow::tr("Aborted - Image file write error" );  break;
-                        case t_Device::ThreadReadFileError : State = t_MainWindow::tr("Aborted - Device read error" );       break;
-                        default                            : CHK_EXIT (ERROR_DEVICE_BAD_ABORTREASON)
+                        case t_Device::None                  : StrState = t_MainWindow::tr("Aborted - Error: Reason is 'none'" ); break;
+                        case t_Device::UserRequest           : StrState = t_MainWindow::tr("Aborted by user" );                   break;
+                        case t_Device::ThreadWriteWriteError : StrState = t_MainWindow::tr("Aborted - Image file write error" );  break;
+                        case t_Device::ThreadWriteVerifyError: StrState = t_MainWindow::tr("Aborted - Image file verify error" ); break;
+                        case t_Device::ThreadReadFileError   : StrState = t_MainWindow::tr("Aborted - Device read error" );       break;
+                        default                              : CHK_EXIT (ERROR_DEVICE_BAD_ABORTREASON)
                      }
                      break;
       default      : CHK_EXIT (ERROR_DEVICE_BAD_STATE)
@@ -221,10 +271,10 @@ QVariant t_Device::GetState (t_pDevice pDevice)
       QString Msg;
       CHK_EXIT (pDevice->GetMessage (Msg))
       if (!Msg.isEmpty())
-         State += " - " + Msg;
+         StrState += " - " + Msg;
    }
 
-   return State;
+   return StrState;
 }
 
 QVariant t_Device::GetSectorSize (t_pDevice pDevice)
@@ -246,6 +296,7 @@ QVariant t_Device::GetSize (t_pDevice pDevice)
 QVariant t_Device::GetSizeHumanFrac (t_pDevice pDevice, bool SI, int FracLen, int UnitThreshold)
 {
    QString      SizeHuman;
+   const char *pBaseUnit = "Byte";
    const char *pUnit;
    double       Sz;
    double       Divisor;
@@ -258,7 +309,7 @@ QVariant t_Device::GetSizeHumanFrac (t_pDevice pDevice, bool SI, int FracLen, in
       UnitThreshold = (int) Divisor;
 
    Sz = pDevice->Size;
-   pUnit = "Byte";
+   pUnit = pBaseUnit;
    if (Sz >= UnitThreshold) { Sz = Sz / Divisor; pUnit = SI ? "kB" : "KiB"; }
    if (Sz >= UnitThreshold) { Sz = Sz / Divisor; pUnit = SI ? "MB" : "MiB"; }
    if (Sz >= UnitThreshold) { Sz = Sz / Divisor; pUnit = SI ? "GB" : "GiB"; }
@@ -270,9 +321,10 @@ QVariant t_Device::GetSizeHumanFrac (t_pDevice pDevice, bool SI, int FracLen, in
 
    if (FracLen == AutoFracLen)
    {
-      if      (Sz >= 100) FracLen = 0;
-      else if (Sz >= 10 ) FracLen = 1;
-      else                FracLen = 2;
+      if (pUnit == pBaseUnit) FracLen = 0; // no frac if unit is bytes
+      else if (Sz >= 100)     FracLen = 0;
+      else if (Sz >= 10 )     FracLen = 1;
+      else                    FracLen = 2;
    }
    SizeHuman = MainGetpNumberLocale()->toString (Sz, 'f', FracLen) + pUnit;
 
@@ -284,6 +336,34 @@ QVariant t_Device::GetSizeHuman (t_pDevice pDevice)
    return GetSizeHumanFrac (pDevice, true, 1);
 }
 
+static QString DeviceMediaInfoStr (t_MediaInfo::t_MediaState State)
+{
+   QString Str;
+   switch (State)
+   {
+      case t_MediaInfo::Unknown: Str = t_MainWindow::tr("Unknown", "Media info string for informing about hidden areas (HPA/DCO)"); break;
+      case t_MediaInfo::No     : Str = t_MainWindow::tr("No"     , "Media info string for informing about hidden areas (HPA/DCO)"); break;
+      case t_MediaInfo::Yes    : Str = t_MainWindow::tr("Yes"    , "Media info string for informing about hidden areas (HPA/DCO)"); break;
+      default: CHK_EXIT (ERROR_DEVICE_INVALID_MEDIAINFOSTATE)
+   }
+   return Str;
+}
+
+QVariant t_Device::GetHiddenAreas (t_pDevice pDevice)
+{
+   QString Str;
+
+   if      ((pDevice->MediaInfo.HasHPA == t_MediaInfo::No     ) && (pDevice->MediaInfo.HasDCO == t_MediaInfo::No     )) Str = "none";
+   else if ((pDevice->MediaInfo.HasHPA == t_MediaInfo::Unknown) && (pDevice->MediaInfo.HasDCO == t_MediaInfo::Unknown)) Str = "unknown";
+   else
+   {
+      Str  = "HPA:"    + DeviceMediaInfoStr(pDevice->MediaInfo.HasHPA);
+      Str += " / DCO:" + DeviceMediaInfoStr(pDevice->MediaInfo.HasDCO);
+   }
+
+   return Str;
+}
+
 QVariant t_Device::GetBadSectorCount (t_pDevice pDevice)
 {
    if (!pDevice->StartTimestamp.isNull())
@@ -295,7 +375,8 @@ static void DeviceGetProgress (t_pDevice pDevice, quint64 *pCurrent=NULL, quint6
 {
    quint64 Current, Total;
 
-   if (pDevice->Acquisition.VerifySource)
+   if ((pDevice->Acquisition.VerifySrc) ||
+       (pDevice->Acquisition.VerifyDst))
    {
       Total = 2 * pDevice->Size;
       if (pDevice->StartTimestampVerify.isNull())
@@ -390,8 +471,8 @@ QVariant t_Device::GetRemaining (t_pDevice pDevice)
    int     hh, mm, ss;
    quint64 Current, Total;
 
-   if ((pDevice->State == Acquire) || // Don't display anything if no acquisition is running
-       (pDevice->State == Verify ))
+   if (!pDevice->AbortRequest && ((pDevice->State == Acquire) || // Don't display anything if no acquisition is running
+                                  (pDevice->State == Verify )))
    {
       time (&Now);
       TotalSeconds = pDevice->StartTimestamp.secsTo (QDateTime::currentDateTime());
@@ -403,7 +484,7 @@ QVariant t_Device::GetRemaining (t_pDevice pDevice)
       {
          DeviceGetProgress (pDevice, &Current, &Total);
          ss  = (int) ((double)Total / Current * TotalSeconds); // Estimated total time
-         ss -= TotalSeconds;                                    // Estimated remaining time
+         ss -= TotalSeconds;                                   // Estimated remaining time
          hh = ss / SECONDS_PER_HOUR;   ss %= SECONDS_PER_HOUR;
          mm = ss / SECONDS_PER_MINUTE; ss %= SECONDS_PER_MINUTE;
          snprintf (Buff, sizeof(Buff), "%02d:%02d:%02d", hh, mm, ss);
@@ -453,9 +534,26 @@ QVariant t_Device::GetFifoStatus (t_pDevice pDevice)
    return Result;
 }
 
-
 //lint -restore
 
+const char *t_Device::StateStr (void)
+{
+   const char *pStr;
+   switch (State)
+   {
+      case Idle         : pStr = "Idle";            break;
+      case Acquire      : pStr = "Acquire";         break;
+      case AcquirePaused: pStr = "AcquirePaused";   break;
+      case Verify       : pStr = "Verify";          break;
+      case VerifyPaused : pStr = "VerifyPaused";    break;
+      case Cleanup      : pStr = "Cleanup";         break;
+      case Finished     : pStr = "Finished";        break;
+      case Aborted      : pStr = "Aborte";          break;
+      default           : pStr = "Unknown";
+   }
+
+   return pStr;
+}
 
 // ---------------------------
 //        t_DeviceList
@@ -470,6 +568,7 @@ t_DeviceList::t_DeviceList(void)
    {
       Initialised = true;
       qRegisterMetaType<t_pDeviceList>("t_pDeviceList");
+      qRegisterMetaType<t_pDevice>    ("t_pDevice"    );
    }
 }
 
@@ -502,34 +601,6 @@ t_pDevice t_DeviceList::AppendNew (const QString &SerialNumber, const QString &L
    return pDev;
 }
 
-//t_pDevice t_DeviceList::SearchLinuxDevice  (const QString &LinuxDevice)
-//{
-//   t_pDevice pDev;
-//   int        i;
-//
-//   for (i=0; i<count(); i++)
-//   {
-//      pDev = at(i);
-//      if (pDev->LinuxDevice == LinuxDevice)
-//         return pDev;
-//   }
-//   return NULL;
-//}
-//
-//t_pDevice t_DeviceList::SearchSerialNumber (const QString &SerialNumber)
-//{
-//   t_pDevice pDev;
-//   int        i;
-//
-//   for (i=0; i<count(); i++)
-//   {
-//      pDev = at(i);
-//      if (pDev->SerialNumber == SerialNumber)
-//         return pDev;
-//   }
-//   return NULL;
-//}
-
 APIRET t_DeviceList::MatchDevice (t_pcDevice pDevCmp, t_pDevice &pDevMatch)
 {
    bool Found = false;
@@ -538,6 +609,13 @@ APIRET t_DeviceList::MatchDevice (t_pcDevice pDevCmp, t_pDevice &pDevMatch)
    for (i=0; (i<count()) && !Found; i++)
    {
       pDevMatch = at(i);
+      if ( pDevCmp  ->SpecialDevice &&
+          (pDevMatch->LinuxDevice == pDevCmp->LinuxDevice))
+      {
+         Found = true;
+         break;
+      }
+
       if (pDevMatch->SerialNumber.isEmpty())
       {
          Found = (pDevCmp->SerialNumber.isEmpty() && (pDevMatch->State != t_Device::AcquirePaused) &&
@@ -571,22 +649,21 @@ APIRET t_DeviceList::MatchDevice (t_pcDevice pDevCmp, t_pDevice &pDevMatch)
    return NO_ERROR;
 }
 
-const char *t_Device::StateStr (void)
+bool t_DeviceList::UsedAsCloneDestination (t_pcDevice pDevChk)
 {
-   const char *pStr;
-   switch (State)
+   t_pcDevice pDevCmp;
+   int         i;
+
+   for (i=0; i<count(); i++)
    {
-      case Idle         : pStr = "Idle";            break;
-      case Acquire      : pStr = "Acquire";         break;
-      case AcquirePaused: pStr = "AcquirePaused";   break;
-      case Verify       : pStr = "Verify";          break;
-      case VerifyPaused : pStr = "VerifyPaused";    break;
-      case Cleanup      : pStr = "Cleanup";         break;
-      case Finished     : pStr = "Finished";        break;
-      case Aborted      : pStr = "Aborte";          break;
-      default           : pStr = "Unknown";
+      pDevCmp = at(i);
+      if ( (pDevCmp->State != t_Device::Idle    ) &&
+           (pDevCmp->State != t_Device::Finished) &&
+           (pDevCmp->State != t_Device::Aborted ) &&
+           (pDevCmp->Acquisition.Clone          ) &&
+          ((pDevCmp->Acquisition.ImagePath + pDevCmp->Acquisition.ImageFilename) == pDevChk->LinuxDevice))
+         return true;
    }
-
-   return pStr;
+   return false;
 }
 
diff --git a/device.h b/device.h
index 9e9bdc7..d245337 100644
--- a/device.h
+++ b/device.h
@@ -22,6 +22,7 @@
 #include "fifo.h"
 #include "info.h"
 #include "file.h"
+#include "media.h"
 
 class t_ThreadRead;
 class t_ThreadHash;
@@ -50,28 +51,33 @@ class t_Device
       {
          None,
          UserRequest,
-         ThreadWriteFileError,
+         ThreadWriteWriteError,
+         ThreadWriteVerifyError,
          ThreadReadFileError
       } t_AbortReason;
 
       static const int AutoFracLen       = -1;   // Use up to 2 digits after decimal point (min. 3 significant digits)
       static const int AutoUnitThreshold = -1;
+      static const int FileDescEmpty     = -1;
 
       class t_Acquisition
       {
          public:
-            QString         ImagePath;        // Always end with /
-            QString         InfoPath;         // Always end with /
-            QString         ImageFilename;    // Image filename, without extension
-            QString         InfoFilename;     // Info filename, without extension
-            t_File::Format  Format;
-            bool            CalcHashes;
-            bool            VerifySource;
-            QString         CaseNumber;
-            QString         EvidenceNumber;
-            QString         Examiner;
-            QString         Description;
-            QString         Notes;
+            QString        ImagePath;        // Always end with /
+            QString        InfoPath;         // Always end with /
+            QString        ImageFilename;    // Image filename, without extension
+            QString        InfoFilename;     // Info filename, without extension
+            t_File::Format Format;
+            bool           Clone;
+            bool           CalcMD5;
+            bool           CalcSHA256;
+            bool           VerifySrc;
+            bool           VerifyDst;
+            QString        CaseNumber;
+            QString        EvidenceNumber;
+            QString        Examiner;
+            QString        Description;
+            QString        Notes;
       };
 
    public:
@@ -91,6 +97,7 @@ class t_Device
       static QVariant GetSize                (t_pDevice pDevice);
       static QVariant GetSizeHuman           (t_pDevice pDevice);
       static QVariant GetSizeHumanFrac       (t_pDevice pDevice, bool SI=true, int FracLen=AutoFracLen, int UnitThreshold=AutoUnitThreshold);
+      static QVariant GetHiddenAreas         (t_pDevice pDevice);
       static QVariant GetProgress            (t_pDevice pDevice);
       static QVariant GetCurrentSpeed        (t_pDevice pDevice);
       static QVariant GetAverageSpeed        (t_pDevice pDevice);
@@ -120,27 +127,51 @@ class t_Device
          return Pos;
       }
 
-      inline void SetCurrentVerifyPos (quint64 Pos)
+      inline void SetCurrentVerifyPosSrc (quint64 Pos)
       {
-         SemCurrentVerifyPos.lockForWrite ();
-         CurrentVerifyPos = Pos;
-         SemCurrentVerifyPos.unlock ();
+         SemCurrentVerifyPosSrc.lockForWrite ();
+         CurrentVerifyPosSrc = Pos;
+         SemCurrentVerifyPosSrc.unlock ();
       }
 
-      inline void IncCurrentVerifyPos (int Inc)
+      inline void IncCurrentVerifyPosSrc (int Inc)
       {
-         SemCurrentVerifyPos.lockForWrite ();
-         CurrentVerifyPos += Inc; //lint !e737 Loss of sign
-         SemCurrentVerifyPos.unlock ();
+         SemCurrentVerifyPosSrc.lockForWrite ();
+         CurrentVerifyPosSrc += Inc; //lint !e737 Loss of sign
+         SemCurrentVerifyPosSrc.unlock ();
+      }
+
+      inline void SetCurrentVerifyPosDst (quint64 Pos)
+      {
+         SemCurrentVerifyPosDst.lockForWrite ();
+         CurrentVerifyPosDst = Pos;
+         SemCurrentVerifyPosDst.unlock ();
+      }
+
+      inline void IncCurrentVerifyPosDst (int Inc)
+      {
+         SemCurrentVerifyPosDst.lockForWrite ();
+         CurrentVerifyPosDst += Inc; //lint !e737 Loss of sign
+         SemCurrentVerifyPosDst.unlock ();
       }
 
       inline quint64 GetCurrentVerifyPos (void)
       {
-         quint64 Pos;
-         SemCurrentVerifyPos.lockForRead ();
-         Pos = CurrentVerifyPos;
-         SemCurrentVerifyPos.unlock ();
-         return Pos;
+         quint64 PosSrc;
+         quint64 PosDst;
+
+         SemCurrentVerifyPosSrc.lockForRead ();
+         PosSrc = CurrentVerifyPosSrc;
+         SemCurrentVerifyPosSrc.unlock ();
+
+         SemCurrentVerifyPosDst.lockForRead ();
+         PosDst = CurrentVerifyPosDst;
+         SemCurrentVerifyPosDst.unlock ();
+
+         if      ( Acquisition.VerifySrc &&  Acquisition.VerifyDst) return GETMIN (PosSrc, PosDst);
+         else if ( Acquisition.VerifySrc && !Acquisition.VerifyDst) return PosSrc;
+         else if (!Acquisition.VerifySrc &&  Acquisition.VerifyDst) return PosDst;
+         else                                                       return 0;
       }
 
       inline void AddBadSector (quint64 Sector)
@@ -152,21 +183,21 @@ class t_Device
          SemBadSectors.unlock ();
       }
 
-      APIRET GetBadSectors (QList<quint64> &BadSectorsCopy, bool Verify)
+      APIRET GetBadSectors (QList<quint64> &BadSectorsCopy, bool GetVerify)
       {
          SemBadSectors.lock ();
-         if (Verify)
+         if (GetVerify)
               BadSectorsCopy = BadSectorsVerify;
          else BadSectorsCopy = BadSectors;
          SemBadSectors.unlock ();
          return NO_ERROR;
       }
 
-      quint64 GetBadSectorCount (bool Verify)
+      quint64 GetBadSectorCount (bool GetVerify)
       {
          quint64 Count;
          SemBadSectors.lock ();
-         if (Verify)
+         if (GetVerify)
               Count = BadSectorsVerify.count();  //lint !e732 Loss of sign
          else Count = BadSectors      .count();  //lint !e732 Loss of sign
          SemBadSectors.unlock ();
@@ -214,24 +245,28 @@ class t_Device
             quint64                   SectorSize;
             quint64                   SectorSizePhys;
             quint64                   Size;
+            bool                      SpecialDevice;    // Special device that has been added manually to the device table
             bool                      Removable;
+            t_MediaInfo               MediaInfo;
 
             t_State                   State;
    private: QString                   Message;          // Used by the threads to communicate messages displayed in spreadsheet field "state"
    public:  bool                      AbortRequest;
+            int                       AbortCount;       // Little easter egg  ;-)
             t_AbortReason             AbortReason;
             bool                      DeleteAfterAbort;
 
             t_Acquisition             Acquisition;
             t_Info                    Info;             // Must only be used if Aqcuisition.InfoFilename is valid!
 
-            FILE                    *pFileSrc;
-            quint64                   CurrentReadPos;   // Accessed from different threads, but never at the same time. During acquisition, it is exclusively accessed by the read threads. Using a mutex would be nicer, but could decrease performance.
-   private: quint64                   CurrentVerifyPos; // Accessed concurrently, use appropriate functions
-   private: quint64                   CurrentWritePos;  // Accessed concurrently, use appropriate functions
-   private: QList<quint64>            BadSectors;       // Accessed concurrently, use appropriate functions
-   private: QList<quint64>            BadSectorsVerify; // Accessed concurrently, use appropriate functions
-   public:  bool                      FallbackMode;     // Set if an error occurs while reading a large block. If set, sectors are read individually until the next large block boundary.
+            int                       FileDescSrc;
+            quint64                   CurrentReadPos;      // Accessed from different threads, but never at the same time. During acquisition, it is exclusively accessed by the read threads. Using a mutex would be nicer, but could decrease performance.
+   private: quint64                   CurrentVerifyPosSrc; // Accessed concurrently, use appropriate functions
+   private: quint64                   CurrentVerifyPosDst; // Accessed concurrently, use appropriate functions
+   private: quint64                   CurrentWritePos;     // Accessed concurrently, use appropriate functions
+   private: QList<quint64>            BadSectors;          // Accessed concurrently, use appropriate functions
+   private: QList<quint64>            BadSectorsVerify;    // Accessed concurrently, use appropriate functions
+   public:  bool                      FallbackMode;        // Set if an error occurs while reading a large block. If set, sectors are read individually until the next large block boundary.
             QDateTime                 StartTimestamp;
             QDateTime                 StartTimestampVerify;
             QDateTime                 StopTimestamp;
@@ -241,20 +276,24 @@ class t_Device
             t_ThreadWrite           *pThreadWrite;
             QList<t_ThreadCompress *> ThreadCompressList;
 
-   public:  t_pFifo                  pFifoRead;         // Pointers to the Fifos used by the different
+   public:  t_pFifoMemory            pFifoMemory;
+            t_pFifo                  pFifoRead;         // Pointers to the Fifos used by the different
             t_pFifo                  pFifoHashIn;       // threads. Some of them point to the same Fifos,
             t_pFifo                  pFifoHashOut;      // for instance pFifoRead and pFifoHashIn.
             t_pFifo                  pFifoWrite;
             t_pFifoCompressIn        pFifoCompressIn;
             t_pFifoCompressOut       pFifoCompressOut;
             int                       FifoMaxBlocks;
-            unsigned int              FifoBlockSize;
+            unsigned int              FifoBlockSize;       // The pure size as it would be required by for the data
+            unsigned int              FifoAllocBlockSize;  // The block size as it is used for real allocation
 
 
             t_HashMD5Digest           MD5Digest;
-            t_HashMD5Digest           MD5DigestVerify;
+            t_HashMD5Digest           MD5DigestVerifySrc;
+            t_HashMD5Digest           MD5DigestVerifyDst;
             t_HashSHA256Digest        SHA256Digest;
-            t_HashSHA256Digest        SHA256DigestVerify;
+            t_HashSHA256Digest        SHA256DigestVerifySrc;
+            t_HashSHA256Digest        SHA256DigestVerifyDst;
 
    public:  quint64                   PrevPos;          // Some variables for
             QTime                     PrevTimestamp;    // the current speed
@@ -262,7 +301,8 @@ class t_Device
             bool                      Checked;          // Helper variable for matching algorithm in SlotScanFinished, not used elsewhere.
 
    private: QReadWriteLock            SemCurrentWritePos;
-   private: QReadWriteLock            SemCurrentVerifyPos;
+   private: QReadWriteLock            SemCurrentVerifyPosSrc;
+   private: QReadWriteLock            SemCurrentVerifyPosDst;
    private: QMutex                    SemBadSectors;
    private: QMutex                    SemMessage;
 };
@@ -276,7 +316,9 @@ class t_DeviceList: public QList<t_pDevice>
       t_pDevice AppendNew (const QString &SerialNumber, const PedDevice *pPedDev);
       t_pDevice AppendNew (const QString &SerialNumber, const QString &LinuxDevice, const QString &Model,
                            quint64 SectorSize, quint64 SectorSizePhys, quint64 Size=0);
-      APIRET MatchDevice (t_pcDevice pDevCmp, t_pDevice &pDeviceMatch);
+
+      APIRET MatchDevice            (t_pcDevice pDevCmp, t_pDevice &pDevMatch);
+      bool   UsedAsCloneDestination (t_pcDevice pDevChk);
 };
 
 typedef t_DeviceList *t_pDeviceList;
@@ -294,7 +336,8 @@ enum
    ERROR_DEVICE_SERNR_MATCH_LENGTH_MISMATCH,
    ERROR_DEVICE_BAD_STATE,
    ERROR_DEVICE_BAD_ABORTREASON,
-   ERROR_DEVICE_NOT_CLEAN
+   ERROR_DEVICE_NOT_CLEAN,
+   ERROR_DEVICE_INVALID_MEDIAINFOSTATE
 };
 
 
diff --git a/dlgabort.cpp b/dlgabort.cpp
index 936a4d9..faeb067 100644
--- a/dlgabort.cpp
+++ b/dlgabort.cpp
@@ -59,11 +59,15 @@ t_DlgAbort::t_DlgAbort (t_pcDevice pDevice, QWidget *pParent, Qt::WFlags Flags)
    QLabel      *pLabel       = new QLabel      (Text, this);
    QPushButton *pButtonOk    = new QPushButton (QObject::tr("Ok"    ), this);
    QPushButton *pButtonCancel= new QPushButton (QObject::tr("Cancel"), this);
-   pOwn->pCheckBoxDelete     = new QCheckBox   (tr("Delete partial image files"), this);
-   pOwn->pCheckBoxDelete->setChecked (Acquisition);
+   if (!pDevice->Acquisition.Clone)
+   {
+      pOwn->pCheckBoxDelete = new QCheckBox (tr("Delete partial image files"), this);
+      pOwn->pCheckBoxDelete->setChecked (Acquisition);
+   }
 
    pMainLayout->addWidget   (pLabel);
-   pMainLayout->addWidget   (pOwn->pCheckBoxDelete);
+   if (!pDevice->Acquisition.Clone)
+      pMainLayout->addWidget   (pOwn->pCheckBoxDelete);
    pMainLayout->addLayout   (pButtonLayout);
    pButtonLayout->addWidget (pButtonOk);
    pButtonLayout->addWidget (pButtonCancel);
@@ -91,7 +95,9 @@ APIRET t_DlgAbort::Show (t_pcDevice pDevice, bool &Abort, bool &Delete)
    pDlg->setModal  (true);
    Result = pDlg->exec();
    Abort  = (Result == QDialog::Accepted);
-   Delete = (Abort && pDlg->pOwn->pCheckBoxDelete->isChecked());
+   if (pDevice->Acquisition.Clone)
+        Delete = false;
+   else Delete = (Abort && pDlg->pOwn->pCheckBoxDelete->isChecked());
    delete pDlg;
 
    return NO_ERROR;
diff --git a/dlgacquire.cpp b/dlgacquire.cpp
index 925b56c..a2b70c8 100644
--- a/dlgacquire.cpp
+++ b/dlgacquire.cpp
@@ -10,21 +10,23 @@
 // ****************************************************************************
 
 #include <QtGui>
+#include <QDesktopWidget>
 
 #include "common.h"
 #include "compileinfo.h"
 #include "config.h"
 #include "qtutil.h"
-#include "main.h"
 #include "dlgdirsel.h"
+#include "devicelistmodel.h"
 #include "dlgacquire.h"
 #include "dlgacquire_private.h"
+#include "main.h"
 
 // -----------------------------
 //           Constants
 // -----------------------------
 
-const char *DLG_ACQUIRE_DEFAULT_EMPTY_FILENAME  = "Out";  // Default image file name if - after removing special chars - the file name is empty.
+const char *DLGACQUIRE_DEFAULT_EMPTY_FILENAME   = "Out";  // Default image file name if - after removing special chars - the file name is empty.
 const char *DLGACQUIRE_PROPERTY_SENDER_LINEEDIT = "SenderLineEdit";
 
 // -----------------------------
@@ -34,20 +36,19 @@ const char *DLGACQUIRE_PROPERTY_SENDER_LINEEDIT = "SenderLineEdit";
 class t_DlgAcquireLocal
 {
    public:
+      bool              Clone;
       QRadioButton    *pRadioButtonFormatDD;
       QRadioButton    *pRadioButtonFormatEWF;
       QRadioButton    *pRadioButtonFormatAFF;
 
       QList<QWidget*>   EwfWidgetsList;                  // Used to comfortably enable / disable EWF related entry fields and labels
 
-      QCheckBox       *pCheckBoxCalcHashes;
-      QCheckBox       *pCheckBoxVerifySource;
+      QTableWidget    *pDeviceTable;                     // Only created and displayed when cloning a device
+      int               DeviceTableLinuxDeviceCol;
 
       QPushButton     *pButtonOk;
       QPushButton     *pButtonCancel;
 
-      QFileDialog     *pDlg;
-
       t_pDevice        pDevice;
 };
 
@@ -130,8 +131,11 @@ static APIRET DlgAcquireResolveSpecialSequences (t_pDevice pDevice, bool Conside
       for (i=0; i<pDlgAcquireFields->count(); i++)
       {
          pDlgAcquireField = pDlgAcquireFields->at(i);
-         Search = "%" + pDlgAcquireField->FieldName + "%";
-         Out.replace (Search, pDlgAcquireField->pLineEdit->text());
+         if (pDlgAcquireField->pLineEdit)
+         {
+            Search = "%" + pDlgAcquireField->FieldName + "%";
+            Out.replace (Search, pDlgAcquireField->pLineEdit->text());
+         }
       }
    }
 
@@ -139,9 +143,22 @@ static APIRET DlgAcquireResolveSpecialSequences (t_pDevice pDevice, bool Conside
 }
 
 
-static APIRET DlgAcquireGetFieldValue (t_pDevice pDevice, t_pCfgDlgAcquireField pDlgAcquireField, QString &Set)
+static APIRET DlgAcquireGetFieldValue (t_pDevice pDevice, bool Clone, t_pCfgDlgAcquireField pDlgAcquireField, QString &Set)
 {
-   switch (pDlgAcquireField->EntryMode)
+   t_CfgEntryMode EntryMode;
+
+   if (Clone && ((pDlgAcquireField->FieldName == CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY) ||
+                 (pDlgAcquireField->FieldName == CFG_DLGACQUIRE_DEST_IMAGEFILENAME )))
+   {
+      Set = QString();
+      return NO_ERROR;
+   }
+
+   if (Clone)
+        EntryMode = pDlgAcquireField->EntryModeClone;
+   else EntryMode = pDlgAcquireField->EntryModeImage;
+
+   switch (EntryMode)
    {
       case CFG_ENTRYMODE_HIDE:
       case CFG_ENTRYMODE_SHOWLAST:
@@ -169,24 +186,52 @@ static APIRET DlgAcquireGetFieldValue (t_pDevice pDevice, t_pCfgDlgAcquireField
 //         t_DlgAcquire
 // -----------------------------
 
-APIRET t_DlgAcquire::AddField (t_pDevice pDevice, t_pCfgDlgAcquireField pField, QGridLayout *pLayout, int *pRow)
+static bool DlgAcquireStrToBool (const QString &Set)
+{
+   return !Set.isEmpty() && (Set.compare ("NO"         , Qt::CaseInsensitive) != 0)  &&
+          !Set.isNull () && (Set.compare ("OFF"        , Qt::CaseInsensitive) != 0)  &&
+                            (Set.compare ("FALSE"      , Qt::CaseInsensitive) != 0)  &&
+                            (Set.compare ("0"          , Qt::CaseInsensitive) != 0)  &&
+                            (Set.compare ("DISABLED"   , Qt::CaseInsensitive) != 0)  &&
+                            (Set.compare ("DEACTIVATED", Qt::CaseInsensitive) != 0);
+}
+
+
+APIRET t_DlgAcquire::AddField (t_pDevice pDevice, t_pCfgDlgAcquireField pField, QGridLayout *pLayout, int *pRow, int *pCol)
 {
    t_pDlgAcquireLineEdit  pLineEdit     = NULL;
+   QCheckBox             *pCheckBox     = NULL;
    QLabel                *pLabel        = NULL;
+   QWidget               *pEntryWidget  = NULL;
    QPushButton           *pButtonBrowse = NULL;
    QString                 Set;
    QSize                   MinButtonSize;
+   t_CfgEntryMode          EntryMode;
 
-   pLabel    = new QLabel (tr(QSTR_TO_PSZ(pField->FieldName)), this);
-   pLineEdit = new t_DlgAcquireLineEdit (this, pField->FieldName);
-   if ((pField->DirField) && (pField->EntryMode != CFG_ENTRYMODE_HIDE))
+   if (pOwn->Clone)
+        EntryMode = pField->EntryModeClone;
+   else EntryMode = pField->EntryModeImage;
+
+   if (pField->HashField)
+   {
+      pEntryWidget = pCheckBox = new QCheckBox (tr(QSTR_TO_PSZ(pField->FieldName)), this);
+   }
+   else
+   {
+      pEntryWidget = pLineEdit = new t_DlgAcquireLineEdit (this, pField->FieldName);
+      pLabel       = new QLabel (tr(QSTR_TO_PSZ(pField->FieldName)), this);
+   }
+
+   if ((pField->DirField) && (EntryMode != CFG_ENTRYMODE_HIDE))
       pButtonBrowse = new QPushButton (tr("...", "The directory browse button"), this);
 
    pField->pLineEdit = pLineEdit;
-   if (pField->EntryMode == CFG_ENTRYMODE_HIDE)
+   pField->pCheckBox = pCheckBox;
+   if (EntryMode == CFG_ENTRYMODE_HIDE)
    {
-      pLabel   ->hide();
-      pLineEdit->hide();
+      if (pLabel)
+         pLabel->hide();
+      pEntryWidget->hide();
    }
    else
    {
@@ -199,63 +244,227 @@ APIRET t_DlgAcquire::AddField (t_pDevice pDevice, t_pCfgDlgAcquireField pField,
          pButtonBrowse->setSizePolicy (QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred));   // Allow to shrink horizontal size below preferred minimum
          pButtonBrowse->setMinimumSize(MinButtonSize);
       }
-      else
+      else if (pLabel)
       {
          pLayout->addWidget (pLabel, *pRow, 0, 1, 2);        // if there's no button then use the first 2 columns for the label
       }
-      pLayout->addWidget (pLineEdit, *pRow, 2);
-      if (pField->EwfField)
+      if (pLineEdit)
       {
-         pOwn->EwfWidgetsList.append (pLabel   );
-         pOwn->EwfWidgetsList.append (pLineEdit);
+         pLayout->addWidget (pLineEdit, *pRow, 2);
+         if (pField->EwfField)
+         {
+            pOwn->EwfWidgetsList.append (pLabel   );
+            pOwn->EwfWidgetsList.append (pLineEdit);
+         }
+         (*pRow)++;
+      }
+      if (pCheckBox)
+      {
+         if (pField->FieldName.startsWith (CFG_DLGACQUIRE_HASHCALC_FIELDID))
+         {
+            pLayout->addWidget (pCheckBox, 0, *pCol);  // Put all HashCalc field in the first row
+            (*pCol)++;
+         }
+         else
+         {
+            pLayout->addWidget (pCheckBox, (*pRow)+1, 0, 1, 2); // Put each verification field in an own row below
+            (*pRow)++;
+         }
       }
-      (*pRow)++;
    }
-   CHK_EXIT (DlgAcquireGetFieldValue (pDevice, pField, Set))
+   CHK_EXIT (DlgAcquireGetFieldValue (pDevice, pOwn->Clone, pField, Set))
    if (pField->DirField)
    {
       pLineEdit->setReadOnly (true);
       if (!Set.endsWith ("/"))
          Set += "/";
    }
-   pLineEdit->setText (Set);
-   CHK_QT_EXIT (connect (pLineEdit, SIGNAL (SignalTextEdited (t_DlgAcquireLineEdit *, const QString &)),
-                              this, SLOT   (SlotTextEdited   (t_DlgAcquireLineEdit *, const QString &))))
+   if (pLineEdit)
+   {
+      pLineEdit->setText (Set);
+      CHK_QT_EXIT (connect (pLineEdit, SIGNAL (SignalTextEdited (t_DlgAcquireLineEdit *, const QString &)),
+                                 this, SLOT   (SlotTextEdited   (t_DlgAcquireLineEdit *, const QString &))))
+   }
+
+   if (pField->DstField)
+      CHK_QT_EXIT (connect (pLineEdit, SIGNAL (textChanged(const QString &)), this, SLOT(UpdateDialogState(const QString &))))
+
+   if (pCheckBox)
+      pCheckBox->setChecked (DlgAcquireStrToBool(Set));
+
    if (pButtonBrowse)
    {
       (void) pButtonBrowse->setProperty (DLGACQUIRE_PROPERTY_SENDER_LINEEDIT, qVariantFromValue ((void *)pLineEdit));
       CHK_QT_EXIT (connect (pButtonBrowse, SIGNAL (released()), this, SLOT(SlotBrowse())))
    }
 
-   if (pField->DstField)
-      CHK_QT_EXIT (connect (pLineEdit, SIGNAL (textChanged(const QString &)), this, SLOT(UpdateButtonState(const QString &))))
+   return NO_ERROR;
+}
+
+APIRET t_DlgAcquire::InsertDeviceTableRow (QTableWidget *pTable, int Row, t_pDeviceList pDeviceList, t_pDevice pDevSrc, t_pDevice pDevDst)
+{
+   QTableWidgetItem *pItem;
+   int                Col;
+   QVariant           SizeHuman;
+   QString            Remark;
+   bool               Selectable = false;
+
+   if (Row == 0)
+   {
+      Col = 0;
+      pTable->setHorizontalHeaderItem (Col++, new QTableWidgetItem(t_DeviceListModel::tr("Serial\nnr."  , "Column of device table")));
+      pOwn->DeviceTableLinuxDeviceCol = Col;
+      pTable->setHorizontalHeaderItem (Col++, new QTableWidgetItem(t_DeviceListModel::tr("Linux\ndevice", "Column of device table")));
+      pTable->setHorizontalHeaderItem (Col++, new QTableWidgetItem(t_DeviceListModel::tr("Model"        , "Column of device table")));
+      pTable->setHorizontalHeaderItem (Col++, new QTableWidgetItem(t_DeviceListModel::tr("Size"         , "Column of device table")));
+      pTable->setHorizontalHeaderItem (Col++, new QTableWidgetItem(t_DeviceListModel::tr("Remarks"      , "Column of device table")));
+   }
+
+   Col = 0;
+   SizeHuman = t_Device::GetSizeHuman (pDevDst);
+
+   bool InUse = (pDevDst->State != t_Device::Idle    ) &&
+                (pDevDst->State != t_Device::Finished) &&
+                (pDevDst->State != t_Device::Aborted );
+
+   if      (pDevDst->Local)                               Remark = tr("Local device, cannot be written");
+   else if (pDevDst == pDevSrc)                           Remark = tr("Device to be cloned");
+   else if (pDevDst->Size < pDevSrc->Size)                Remark = tr("Too small");
+   else if (InUse)                                        Remark = tr("In use");
+   else if (pDeviceList->UsedAsCloneDestination(pDevDst)) Remark = tr("Used in another clone operation");
+   else                                                 { Remark = tr("Ok for cloning"); Selectable = true;}
+
+   #define SET_ITEM(Str)                                            \
+      pItem = new QTableWidgetItem (Str);                           \
+      pTable->setItem (Row, Col++, pItem);                          \
+      pItem->setFlags (Selectable ? (Qt::ItemIsSelectable | Qt::ItemIsEnabled) : Qt::ItemFlags(0));
+
+   SET_ITEM (pDevDst->SerialNumber);
+   SET_ITEM (pDevDst->LinuxDevice );
+   SET_ITEM (pDevDst->Model       );
+   SET_ITEM (SizeHuman.toString() );
+   SET_ITEM (Remark               );
+   #undef SET_ITEM
 
    return NO_ERROR;
 }
 
 
+APIRET t_DlgAcquire::CreateDeviceTable (t_pDeviceList pDeviceList, t_pDevice pDeviceSrc, QTableWidget **ppTable)
+{
+   QTableWidget *pTable;
+   t_pDevice     pDev;
+   int            i=0;
+   int            ColWidth=0;
+   int            ExtraWidth;
+   int            ScreenWidth;
+   int            Width=0;
+
+   pTable = new QTableWidget(0, 5, this);
+   *ppTable = pTable;
+   pOwn->pDeviceTable = pTable;
+
+   pTable->setSelectionBehavior (QAbstractItemView::SelectRows     );
+   pTable->setSelectionMode     (QAbstractItemView::SingleSelection);
+
+   pTable->setRowCount(pDeviceList->count());
+   for (i=0; i<pDeviceList->count(); i++)
+   {
+      pDev = pDeviceList->at (i);
+      CHK (InsertDeviceTableRow (pTable, i, pDeviceList, pDeviceSrc, pDev))
+   }
+   ExtraWidth = pTable->columnWidth(0);  // Somehow, the table widget always gets this value larger when calling setMinimumWidth...
+   pTable->resizeColumnsToContents();
+   pTable->resizeRowsToContents   ();
+   pTable->verticalHeader  ()->hide ();
+//   pTable->horizontalHeader()->setClickable          (true);
+//   pTable->horizontalHeader()->setSortIndicatorShown (true);
+   pTable->setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
+   pTable->setVerticalScrollMode   (QAbstractItemView::ScrollPerPixel);
+
+   for (i=0; i<pTable->columnCount(); i++)
+      ColWidth += pTable->columnWidth(i);
+
+   ScreenWidth = QApplication::desktop()->availableGeometry().width();
+   Width = GETMIN ((int)(0.8 * ScreenWidth), ColWidth - ExtraWidth);   // Do not use more than 80% of the screen width
+   pTable->setMinimumWidth (Width);
+
+   CHK_QT (connect (pTable, SIGNAL(itemSelectionChanged ()), this, SLOT(SlotDeviceTableSelectionChanged())))
+
+   return NO_ERROR;
+}
+
 t_DlgAcquire::t_DlgAcquire ()
 {
    CHK_EXIT (ERROR_DLGACQUIRE_CONSTRUCTOR_NOT_SUPPORTED)
 } //lint !e1401 pOwn not initialised
 
-t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, QWidget *pParent, Qt::WFlags Flags)
+
+class t_DlgAcquireLayoutScroller: public QScrollArea // This class makes layouts scrollable.
+{
+   public:
+      t_DlgAcquireLayoutScroller (QWidget *pParent, QLayout *pLayout)
+         : QScrollArea (pParent)
+      {
+         setFrameStyle      (QFrame::NoFrame);  // We do not want any frames
+         setLineWidth       (0);                // nor margins
+         setMidLineWidth    (0);
+         setContentsMargins (0,0,0,0);
+         setWidgetResizable (true);      // necessary to have the layout inside the ScrollArea follow the dialog's resizing
+
+         QWidget   *pWidget = new QWidget (this);  // we need an intermediate widget, as QScrollArea only accepts
+         setWidget (pWidget);                      // a widget and does ont allow for setting a layout directly
+         pWidget->setLayout (pLayout);             // We then put the layout in the widget
+
+         setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff); // Only scroll vertically
+      }
+
+     ~t_DlgAcquireLayoutScroller ()
+      {
+      }
+
+      virtual QSize sizeHint () const
+      {
+         QWidget *pWidget;
+         QLayout *pLayout;
+
+         pWidget = widget();
+         if (pWidget)
+         {
+            pLayout = pWidget->layout();
+            if (pLayout)                       // Give the layout's minimal size as size hint. So, when putting the whole
+               return pLayout->minimumSize (); // scroll area in a layout, it should be displayed just big enough to have
+         }                                     // the scroll bar hidden.
+         return QScrollArea::sizeHint();
+      }
+
+      virtual QSize minimumSizeHint () const                      // In hor. direction, the area must never be smaller then
+      {                                                           // the minimum required by the layout inside (as we do not
+         return QSize (sizeHint().width(),                        // want a hor. scrollbar and thus switched it off, see
+                       QScrollArea::minimumSizeHint().height());  // constructor above). Verticallym the default minimum
+      }                                                           // of QScrollArea is used (whatever this might be).
+};
+
+
+t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDeviceList, QWidget *pParent, Qt::WFlags Flags)
    :QDialog (pParent, Flags)
 {
-   static bool             Initialised = false;
-   t_pCfgDlgAcquireFields pDlgAcquireFields;
-   t_pCfgDlgAcquireField  pDlgAcquireField;
-   QVBoxLayout           *pLayout;
-   QLabel                *pLabel;
-   QString                 DefaultFilename;
-   QString                 Path;
-   QString                 Str;
-   QString                 ButtonTextDD;
-   QString                 ButtonTextEWF;
-   QString                 ButtonTextAFF;
-   QString                 Set;
-   int                     Row;
-   int                     i;
+   static bool                  Initialised = false;
+   t_pCfgDlgAcquireFields      pDlgAcquireFields;
+   t_pCfgDlgAcquireField       pDlgAcquireField;
+   t_DlgAcquireLayoutScroller *pLayoutScroller;
+   QVBoxLayout                *pTopLayout;
+   QVBoxLayout                *pLayout;
+   QLabel                     *pLabel;
+   QString                      DefaultFilename;
+   QString                      Path;
+   QString                      Str;
+   QString                      ButtonTextDD;
+   QString                      ButtonTextEWF;
+   QString                      ButtonTextAFF;
+   QString                      Set;
+   int                          Row, Col;
+   int                          i;
 
    if (!Initialised)
    {
@@ -264,64 +473,91 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, QWidget *pParent, Qt::WFlags Flag
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DLGACQUIRE_UNKNOWN_FILEDIALOG_SIZE))
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DLGACQUIRE_INVALID_ENTRYMODE))
       CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DLGACQUIRE_INVALID_FORMAT))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_DLGACQUIRE_INVALID_SELECTION))
    }
 
-   setWindowTitle (tr ("Acquisition parameters for %1", "Dialog title, %1 is the device (for instance /dev/hdc)") .arg(pDevice->LinuxDevice));
+   if (Clone)
+        setWindowTitle (tr ("Clone %1"           , "Dialog title, %1 is the device (for instance /dev/hdc)") .arg(pDevice->LinuxDevice));
+   else setWindowTitle (tr ("Acquire image of %1", "Dialog title, %1 is the device (for instance /dev/hdc)") .arg(pDevice->LinuxDevice));
 
    pOwn    = new t_DlgAcquireLocal;
-   pOwn->pDevice = pDevice;
+   pOwn->pDevice      = pDevice;
+   pOwn->Clone        = Clone;
+   pOwn->pDeviceTable = NULL;
+
+   // Organisation of the whole dialog
+   //     Dialog
+   //        TopLayout
+   //           ScrollArea    - t_DlgAcquireLayoutScroller
+   //              Widget     - see t_DlgAcquireLayoutScroller
+   //                 Layout  - see t_DlgAcquireLayoutScroller
+   //           LayoutButtons
+
+   pTopLayout = new QVBoxLayout(this);
+   pTopLayout->setSpacing(0);  // We do not want extra margins everywhere (see t_DlgAcquireScrollArea as well)
+   pTopLayout->setMargin (0);
+
+   pLayout = new QVBoxLayout();
+   pLayout->setSizeConstraint (QLayout::SetMinAndMaxSize);
+   pLayoutScroller = new t_DlgAcquireLayoutScroller (this, pLayout);
+   pTopLayout->addWidget(pLayoutScroller);
 
-   pLayout = new QVBoxLayout (this);
-   setLayout (pLayout);
+   CHK_EXIT (CfgGetDlgAcquireFields (&pDlgAcquireFields))
 
 //   pLayout->addWidget (new QLabel(("<b>" + tr("Acquisition parameters for %1") + "</b>") .arg(pDevice->LinuxDevice) , this));
 
-   // Format box (with EWF fields)
-   // ----------------------------
-   QGroupBox   *pGroupBoxFormat = new QGroupBox (tr("File format"), this);
-   QVBoxLayout *pLayoutFormat   = new QVBoxLayout;
-   QGridLayout *pLayoutEwf      = new QGridLayout ();
-
-   pGroupBoxFormat->setLayout (pLayoutFormat);
-   pLayout->addWidget (pGroupBoxFormat);
-   pLayout->addStretch (1);
-
-   CHK_EXIT (t_File::GetFormatDescription (t_File::DD , Str))            ButtonTextDD  = "&" + Str;
-   CHK_EXIT (t_File::GetFormatDescription (t_File::EWF, Str))            ButtonTextEWF = "&" + Str;
-   CHK_EXIT (t_File::GetFormatDescription (t_File::AFF, Str))            ButtonTextAFF = "&" + Str;
-   CHK_EXIT (t_File::GetFormatExtension   (t_File::DD , NULL, &Str))     ButtonTextDD += " " + tr("(file extension %1)") .arg (Str);
-   CHK_EXIT (t_File::GetFormatExtension   (t_File::EWF, NULL, &Str))     ButtonTextEWF+= " " + tr("(file extension %1)") .arg (Str);
-   CHK_EXIT (t_File::GetFormatExtension   (t_File::AFF, NULL, &Str))     ButtonTextAFF+= " " + tr("(file extension %1)") .arg (Str);
-
-   pOwn->pRadioButtonFormatDD  = new QRadioButton (ButtonTextDD , this);
-   pOwn->pRadioButtonFormatEWF = new QRadioButton (ButtonTextEWF, this);
-   pOwn->pRadioButtonFormatAFF = new QRadioButton (ButtonTextAFF, this);
-
-   pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatDD );
-   pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatEWF);
-   pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatAFF);
-   pLayoutFormat->addLayout  (pLayoutEwf);
-
-   CHK_EXIT (CfgGetDlgAcquireFields (&pDlgAcquireFields))
-
-   Row = 0;
-   for (i=0; i<pDlgAcquireFields->count(); i++)
+   if (!Clone)
    {
-      pDlgAcquireField = pDlgAcquireFields->at(i);
-      if (pDlgAcquireField->EwfField)
-         CHK_EXIT (AddField (pDevice, pDlgAcquireField, pLayoutEwf, &Row))
+      // Format box (with EWF fields)
+      // ----------------------------
+      QGroupBox   *pGroupBoxFormat = new QGroupBox (tr("File format"), this);
+      QVBoxLayout *pLayoutFormat   = new QVBoxLayout;
+      QGridLayout *pLayoutEwf      = new QGridLayout ();
+
+      pGroupBoxFormat->setLayout (pLayoutFormat);
+      pLayout->addWidget       (pGroupBoxFormat);
+
+      CHK_EXIT (t_File::GetFormatDescription (t_File::DD , false, Str))            ButtonTextDD  = "&" + Str;
+      CHK_EXIT (t_File::GetFormatDescription (t_File::EWF, false, Str))            ButtonTextEWF = "&" + Str;
+      CHK_EXIT (t_File::GetFormatDescription (t_File::AFF, false, Str))            ButtonTextAFF = "&" + Str;
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::DD , false, NULL, &Str))     ButtonTextDD += " " + tr("(file extension %1)") .arg (Str);
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::EWF, false, NULL, &Str))     ButtonTextEWF+= " " + tr("(file extension %1)") .arg (Str);
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::AFF, false, NULL, &Str))     ButtonTextAFF+= " " + tr("(file extension %1)") .arg (Str);
+
+      pOwn->pRadioButtonFormatDD  = new QRadioButton (ButtonTextDD , this);
+      pOwn->pRadioButtonFormatEWF = new QRadioButton (ButtonTextEWF, this);
+      pOwn->pRadioButtonFormatAFF = new QRadioButton (ButtonTextAFF, this);
+
+      pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatDD );
+      pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatEWF);
+      pLayoutFormat->addWidget  (pOwn->pRadioButtonFormatAFF);
+      pLayoutFormat->addLayout  (pLayoutEwf);
+
+      Row = Col = 0;
+      for (i=0; i<pDlgAcquireFields->count(); i++)
+      {
+         pDlgAcquireField = pDlgAcquireFields->at(i);
+         if (pDlgAcquireField->EwfField)
+            CHK_EXIT (AddField (pDevice, pDlgAcquireField, pLayoutEwf, &Row, &Col))
+      }
+      pLayoutEwf->setColumnMinimumWidth (0, 20);
    }
-   pLayoutEwf->setColumnMinimumWidth (0, 20);
 
    // Destination box
    // ---------------
+
    QGroupBox   *pGroupBoxDest = new QGroupBox(tr("Destination"), this);
    QGridLayout *pLayoutDest   = new QGridLayout ();
    pGroupBoxDest->setLayout (pLayoutDest);
    pLayout->addWidget (pGroupBoxDest);
-   pLayout->addStretch (1);
+   Row = Col = 0;
+
+   if (Clone)
+   {
+      CHK_EXIT (CreateDeviceTable (pDeviceList, pDevice, &pOwn->pDeviceTable))
+      pLayoutDest->addWidget (pOwn->pDeviceTable, Row++, 0, 1, 3);
+   }
 
-   Row = 0;
    if (CONFIG(WriteToDevNull))
    {
       pLabel = new QLabel(tr("Configuration flag WriteToDevNull is set!"), this);
@@ -333,26 +569,34 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, QWidget *pParent, Qt::WFlags Flag
    {
       pDlgAcquireField = pDlgAcquireFields->at(i);
       if (pDlgAcquireField->DstField)
-         CHK_EXIT (AddField (pDevice, pDlgAcquireField, pLayoutDest, &Row))
+         CHK_EXIT (AddField (pDevice, pDlgAcquireField, pLayoutDest, &Row, &Col))
    }
 
-   // Hash
-   // ----
-   QGroupBox   *pGroupBoxHash = new QGroupBox(tr("Hash computation"), this);
+   // Hash box
+   // --------
+   Row = Col = 0;
+   QGroupBox   *pGroupBoxHash = new QGroupBox(tr("Hash calculation / verification"), this);
    QGridLayout *pLayoutHash   = new QGridLayout ();
    pGroupBoxHash->setLayout (pLayoutHash);
    pLayout->addWidget (pGroupBoxHash);
-   pLayout->addStretch (1);
 
-   pOwn->pCheckBoxCalcHashes   = new QCheckBox (tr("Calculate hashes (MD5 and SHA-256)"), this);
-   pOwn->pCheckBoxVerifySource = new QCheckBox (tr("Re-read source after acquisition for verification (takes twice as long)"), this);
-   pLayoutHash->addWidget (pOwn->pCheckBoxCalcHashes  , 0, 0);
-   pLayoutHash->addWidget (pOwn->pCheckBoxVerifySource, 1, 0);
+   for (i=0; i<pDlgAcquireFields->count(); i++)
+   {
+      pDlgAcquireField = pDlgAcquireFields->at(i);
+      if (pDlgAcquireField->HashField)
+      {
+         CHK_EXIT (AddField (pDevice, pDlgAcquireField, pLayoutHash, &Row, &Col))
+         if (pDlgAcquireField->FieldName.startsWith (CFG_DLGACQUIRE_HASHCALC_FIELDID))
+            CHK_QT_EXIT (connect (pDlgAcquireField->pCheckBox, SIGNAL (stateChanged(int)), this, SLOT(UpdateHashState(int))))
+      }
+   }
 
    // Dialog buttons
    // --------------
-   QHBoxLayout *pLayoutButtons = new QHBoxLayout ();
-   pLayout->addLayout (pLayoutButtons);
+   QHBoxLayout *pLayoutButtons = new QHBoxLayout (); // The new layout would normally use the margin of its parent layout
+   pLayoutButtons->setMargin  (pLayout->margin ());  // (TopLayout), but those have been set to set zero. Instead, we tell
+   pLayoutButtons->setSpacing (pLayout->spacing());  // the button layout top use the same margins as the main layout in
+   pTopLayout->addLayout (pLayoutButtons);           // order to have everything appear nicely and the same way on the screen).
 
    pOwn->pButtonOk     = new QPushButton (QObject::tr("Ok"    ), this);
    pOwn->pButtonCancel = new QPushButton (QObject::tr("Cancel"), this);
@@ -362,39 +606,72 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, QWidget *pParent, Qt::WFlags Flag
 
    // Set other defaults
    // ------------------
-   if (DlgAcquireLastUsedFormat == t_File::NotSet)
-      DlgAcquireLastUsedFormat = (t_File::Format) CONFIG (DefaultFormat);
-
-   switch (DlgAcquireLastUsedFormat)
+   if (!Clone)
    {
-      case t_File::DD : pOwn->pRadioButtonFormatDD ->setChecked (true); break;
-      case t_File::EWF: pOwn->pRadioButtonFormatEWF->setChecked (true); break;
-      case t_File::AFF: pOwn->pRadioButtonFormatAFF->setChecked (true); break;
-      default         : CHK_EXIT (ERROR_DLGACQUIRE_INVALID_FORMAT)
+      if (DlgAcquireLastUsedFormat == t_File::NotSet)
+         DlgAcquireLastUsedFormat = (t_File::Format) CONFIG (DefaultFormat);
+
+      switch (DlgAcquireLastUsedFormat)
+      {
+         case t_File::DD : pOwn->pRadioButtonFormatDD ->setChecked (true); break;
+         case t_File::EWF: pOwn->pRadioButtonFormatEWF->setChecked (true); break;
+         case t_File::AFF: pOwn->pRadioButtonFormatAFF->setChecked (true); break;
+         default         : CHK_EXIT (ERROR_DLGACQUIRE_INVALID_FORMAT)
+      }
    }
-   pOwn->pCheckBoxCalcHashes->setChecked (true);
 
-   UpdateCheckboxState (pOwn->pCheckBoxCalcHashes->isChecked() ? Qt::Checked : Qt::Unchecked);
-   UpdateButtonState   ();
+   UpdateHashState  ();
+   UpdateDialogState();
 
    // Connections
    // -----------
-   CHK_QT_EXIT (connect (pOwn->pCheckBoxCalcHashes, SIGNAL (stateChanged(int)), this, SLOT(UpdateCheckboxState(int))))
-
-   CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatDD , SIGNAL (released()), this, SLOT(UpdateFieldState())))
-   CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatEWF, SIGNAL (released()), this, SLOT(UpdateFieldState())))
-   CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatAFF, SIGNAL (released()), this, SLOT(UpdateFieldState())))
-
+   if (!Clone)
+   {
+      CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatDD , SIGNAL (released()), this, SLOT(UpdateFieldState())))
+      CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatEWF, SIGNAL (released()), this, SLOT(UpdateFieldState())))
+      CHK_QT_EXIT (connect (pOwn->pRadioButtonFormatAFF, SIGNAL (released()), this, SLOT(UpdateFieldState())))
+      UpdateFieldState();
+   }
    CHK_QT_EXIT (connect (pOwn->pButtonOk    , SIGNAL (released()), this, SLOT(SlotAccept())))
    CHK_QT_EXIT (connect (pOwn->pButtonCancel, SIGNAL (released()), this, SLOT(reject    ())))
 }
 
-void t_DlgAcquire::UpdateCheckboxState (int State)
+void t_DlgAcquire::UpdateHashState (int /*State*/)
 {
-   pOwn->pCheckBoxVerifySource->setEnabled (State == Qt::Checked);
+   t_pCfgDlgAcquireFields pDlgAcquireFields;
+   t_pCfgDlgAcquireField  pDlgAcquireField;
+   bool                    Hash = false;
+   int                     i;
+
+   CHK_EXIT (CfgGetDlgAcquireFields (&pDlgAcquireFields))
+   for (i=0; i<pDlgAcquireFields->count(); i++)
+   {
+      pDlgAcquireField = pDlgAcquireFields->at(i);
+      if (pDlgAcquireField->FieldName.startsWith (CFG_DLGACQUIRE_HASHCALC_FIELDID))
+         Hash = Hash || pDlgAcquireField->pCheckBox->isChecked();
+   }
+
+   for (i=0; i<pDlgAcquireFields->count(); i++)
+   {
+      pDlgAcquireField = pDlgAcquireFields->at(i);
+      if (pDlgAcquireField->FieldName.startsWith (CFG_DLGACQUIRE_HASHVERIFY_FIELDID))
+      {
+         if (!Hash)
+            pDlgAcquireField->pCheckBox->setChecked (false);
+         pDlgAcquireField->pCheckBox->setEnabled (Hash);
+      }
+   }
+
+//   if (!Hash)
+//   {
+//      pOwn->pCheckBoxVerifySrc->setChecked (false);
+//      pOwn->pCheckBoxVerifyDst->setChecked (false);
+//   }
+//   pOwn->pCheckBoxVerifySrc->setEnabled (Hash);
+//   pOwn->pCheckBoxVerifyDst->setEnabled (Hash);
 }
 
-void t_DlgAcquire::UpdateButtonState (const QString & /*NewText*/)
+void t_DlgAcquire::UpdateDialogState (const QString & /*NewText*/)
 {
    t_pCfgDlgAcquireFields pFields;
    t_pCfgDlgAcquireField  pField;
@@ -407,12 +684,55 @@ void t_DlgAcquire::UpdateButtonState (const QString & /*NewText*/)
    {
       pField = pFields->at(i);
       if (pField->DstField)
-         Enabled = !pField->pLineEdit->text().isEmpty();
+         Enabled = Enabled && !pField->pLineEdit->text().isEmpty();
    }
 
    pOwn->pButtonOk->setEnabled (Enabled);
 }
 
+void t_DlgAcquire::SlotDeviceTableSelectionChanged (void)
+{
+   t_pDlgAcquireLineEdit     pLineEditDirectory;
+   t_pDlgAcquireLineEdit     pLineEditFilename;
+   QTableWidgetItem         *pItem;
+   QList<QTableWidgetItem*>   SelectedItemsList = pOwn->pDeviceTable->selectedItems();
+   QFileInfo                  FileInfo;
+   int                        Row;
+   int                        Selected;
+   QString                    LinuxDevice;
+   QString                    Directory;
+
+   pLineEditDirectory = DlgAcquireGetField (CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY)->pLineEdit;
+   pLineEditFilename  = DlgAcquireGetField (CFG_DLGACQUIRE_DEST_IMAGEFILENAME )->pLineEdit;
+
+   Selected = SelectedItemsList.count();
+   if (Selected == 0)
+   {
+      pLineEditDirectory->setText (QString());
+      pLineEditFilename ->setText (QString());
+   }
+   else
+   {
+      if (Selected != pOwn->pDeviceTable->columnCount())
+      {
+         LOG_INFO ("%d devices in device tabel for clone destination", Selected)
+         CHK_EXIT (ERROR_DLGACQUIRE_INVALID_SELECTION)
+      }
+      Row   = SelectedItemsList[0]->row();
+      pItem = pOwn->pDeviceTable->item (Row, pOwn->DeviceTableLinuxDeviceCol);
+      LinuxDevice = pItem->text();
+      FileInfo.setFile (LinuxDevice);
+      Directory = FileInfo.dir().absolutePath();
+      if (!Directory.endsWith ("/"))
+         Directory += "/";
+
+      pLineEditDirectory->setText (Directory);
+      pLineEditFilename ->setText (FileInfo.fileName());
+   }
+
+   // No need to call UpdateDialogState, as the LineEdit widget will emit a textChanged signal which is connected to UpdateDialogState.
+}
+
 void t_DlgAcquire::UpdateFieldState (void)
 {
    QWidget *pWidget;
@@ -514,7 +834,7 @@ static APIRET DlgAcquireCheckFilename (const QString &In, bool &Clean, QString &
       else Clean = false;
    }
    if (Out.isEmpty())
-      Out = DLG_ACQUIRE_DEFAULT_EMPTY_FILENAME;
+      Out = DLGACQUIRE_DEFAULT_EMPTY_FILENAME;
 
    return NO_ERROR;
 }
@@ -528,6 +848,7 @@ APIRET t_DlgAcquire::CheckWriteAccess (const QString &Path, const QString &Filen
    QString      TestFileName = Path + Filename + ".test";
    int          wr;
 
+   LOG_INFO ("Trying write access to test file %s.", QSTR_TO_PSZ(TestFileName))
    pFile = fopen (QSTR_TO_PSZ(TestFileName), "w");
    Ok = (pFile != NULL);
    if (!Ok)
@@ -548,6 +869,14 @@ APIRET t_DlgAcquire::CheckWriteAccess (const QString &Path, const QString &Filen
          LOG_INFO ("Closing test file %s failed", QSTR_TO_PSZ(TestFileName))
       }
 
+      QDir          Dir(Path);                                                                                           // Check if the test file really exists with that
+      QFileInfoList FileInfoList = Dir.entryInfoList (QStringList(Filename + ".test"), QDir::Files | QDir::NoSymLinks);  // name (Otherwise, strange things may happen with
+      if (FileInfoList.isEmpty())                                                                                        // the : character, as it used for alternate data
+      {                                                                                                                  // streams in some DOS-based OSs.
+         Ok = false;
+         LOG_INFO ("The test file %s doesn't exist with the correct name", QSTR_TO_PSZ(TestFileName))
+      }
+
       if (!QFile::remove (TestFileName))
       {
          Ok = false;
@@ -555,12 +884,13 @@ APIRET t_DlgAcquire::CheckWriteAccess (const QString &Path, const QString &Filen
       }
    }
 
-   if (!Ok)
-      QMessageBox::information (this, tr ("Access denied", "Dialog title"),
-                                      tr ("Guymager cannot write to the directory"
-                                          "\n\t%1"
-                                          "\nThis may be due to insufficient access rights. Please choose another directory.")
-                                          .arg(Path), QMessageBox::Ok);
+   if (Ok)
+        LOG_INFO ("Write access test succeeded")
+   else QMessageBox::information (this, tr ("Access denied", "Dialog title"),
+                                        tr ("Guymager cannot write to the directory"
+                                            "\n\t%1"
+                                            "\nThis may be due to insufficient access rights or unsupported filename characters. Please choose another directory.")
+                                            .arg(Path), QMessageBox::Ok);
    return NO_ERROR;
 }
 
@@ -569,34 +899,46 @@ void t_DlgAcquire::SlotAccept (void)
 {
    t_Device::t_Acquisition      Acquisition;
    t_pDlgAcquireLineEdit       pLineEditDestImageFilename;
-   t_pDlgAcquireLineEdit       pLineEditDestInfoFilename ;
+   t_pDlgAcquireLineEdit       pLineEditDestInfoFilename;
    QMessageBox::StandardButton  Button;
    QString                      ImageFilenameCorrected;
    QString                      InfoFilenameCorrected;
+   QString                      Message;
    bool                         ImageFilenameClean;
    bool                         InfoFilenameClean;
 
-   CHK_EXIT (GetParameters (Acquisition, false))
-
    // Check for strange characters in filenames
    // -----------------------------------------
 
    pLineEditDestImageFilename = DlgAcquireGetField (CFG_DLGACQUIRE_DEST_IMAGEFILENAME)->pLineEdit;
    pLineEditDestInfoFilename  = DlgAcquireGetField (CFG_DLGACQUIRE_DEST_INFOFILENAME )->pLineEdit;
 
-   CHK_EXIT (DlgAcquireCheckFilename (pLineEditDestImageFilename->text(), ImageFilenameClean, ImageFilenameCorrected))
-   CHK_EXIT (DlgAcquireCheckFilename (pLineEditDestInfoFilename ->text(), InfoFilenameClean,  InfoFilenameCorrected ))
+   ImageFilenameClean     = true;
+   ImageFilenameCorrected = pLineEditDestImageFilename->text();
+   if (pOwn->Clone)
+   {
+      ImageFilenameClean     = true;
+      ImageFilenameCorrected = pLineEditDestImageFilename->text();
+   }
+   else
+   {
+      CHK_EXIT (DlgAcquireCheckFilename (pLineEditDestImageFilename->text(), ImageFilenameClean, ImageFilenameCorrected))
+   }
+   CHK_EXIT (DlgAcquireCheckFilename (pLineEditDestInfoFilename->text(), InfoFilenameClean, InfoFilenameCorrected))
 
    if (!ImageFilenameClean || !InfoFilenameClean)
    {
       LOG_INFO ("Unallowed characters in filenames found")
-      Button = QMessageBox::question (this, tr ("Special characters", "Dialog title"),
-                                            tr ("The filenames contain special characters which are not allowed. Guymager suggests the "
-                                                "following changes:"
-                                                "\n\tImage filename: %1"
-                                                "\n\tInfo filename: %2"
-                                                "\nDo you accept these changes?") .arg(ImageFilenameCorrected) .arg(InfoFilenameCorrected),
-                                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+      if (pOwn->Clone)
+           Message = tr ("The info filename contains special characters which are not allowed. Guymager suggests the following changes:"
+                         "\n\t%1"
+                         "\nDo you accept these changes?") .arg(InfoFilenameCorrected);
+      else Message = tr ("The filenames contain special characters which are not allowed. Guymager suggests the following changes:"
+                         "\n\tImage filename: %1"
+                         "\n\tInfo filename: %2"
+                         "\nDo you accept these changes?") .arg(ImageFilenameCorrected) .arg(InfoFilenameCorrected);
+
+      Button = QMessageBox::question (this, tr ("Special characters", "Dialog title"), Message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
       if (Button == QMessageBox::Yes)
       {
          LOG_INFO ("User accepts filename changes")
@@ -614,11 +956,16 @@ void t_DlgAcquire::SlotAccept (void)
    // ------------------------------------------------
    bool Ok;
 
-   CHK_EXIT (t_DlgAcquire::CheckWriteAccess (Acquisition.InfoPath , Acquisition.InfoFilename , Ok))
-   if (Ok)
-      CHK_EXIT (t_DlgAcquire::CheckWriteAccess (Acquisition.ImagePath, Acquisition.ImageFilename, Ok))
-   if (!Ok)
-      return;
+   CHK_EXIT (GetParameters (Acquisition, false))
+
+   if (!pOwn->Clone)
+   {
+      CHK_EXIT (t_DlgAcquire::CheckWriteAccess (Acquisition.InfoPath, Acquisition.InfoFilename, Ok))
+      if (Ok && (Acquisition.InfoPath != Acquisition.ImagePath))
+         CHK_EXIT (t_DlgAcquire::CheckWriteAccess (Acquisition.ImagePath, Acquisition.ImageFilename, Ok))
+      if (!Ok)
+         return;
+   }
 
    // Check if image file already exists
    // ----------------------------------
@@ -628,7 +975,7 @@ void t_DlgAcquire::SlotAccept (void)
    bool    Empty;
    QString NameFilter;
 
-   CHK_EXIT (t_File::GetFormatExtension (Acquisition.Format, &ExtensionImage))
+   CHK_EXIT (t_File::GetFormatExtension (Acquisition.Format, Acquisition.Clone, &ExtensionImage))
    NameFilter = Acquisition.ImageFilename + ExtensionImage;
    Empty = Dir.entryInfoList (QStringList(NameFilter), QDir::Files, QDir::Name).isEmpty();
    if (Empty)
@@ -640,9 +987,9 @@ void t_DlgAcquire::SlotAccept (void)
 
    if (!Empty)
    {
-      LOG_INFO ("Images files already exist")
-      Button = QMessageBox::question (this, tr ("Images files exist", "Dialog title"),
-                                            tr ("The image files already exist. Do you want to overwrite them?"),
+      LOG_INFO ("Image file / info files already exist")
+      Button = QMessageBox::question (this, tr ("Files exist", "Dialog title"),
+                                            tr ("The image or info files already exist. Do you want to overwrite them?"),
                                                 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
       if (Button == QMessageBox::Yes)
       {
@@ -662,30 +1009,51 @@ APIRET t_DlgAcquire::GetParameters (t_Device::t_Acquisition &Acquisition, bool R
 {
    t_pCfgDlgAcquireField pDlgAcquireField;
 
-   Acquisition.CalcHashes   = pOwn->pCheckBoxCalcHashes  ->isChecked();
-   Acquisition.VerifySource = pOwn->pCheckBoxVerifySource->isChecked();
-   if      (pOwn->pRadioButtonFormatDD ->isChecked()) Acquisition.Format = t_File::DD;
-   else if (pOwn->pRadioButtonFormatEWF->isChecked()) Acquisition.Format = t_File::EWF;
-   else                                               Acquisition.Format = t_File::AFF;
-   if (RememberLastUsedValues)
-      DlgAcquireLastUsedFormat = Acquisition.Format;
+   Acquisition.Clone = pOwn->Clone;
+   if (pOwn->Clone)
+   {
+      Acquisition.Format = t_File::DD;
+   }
+   else
+   {
+      if      (pOwn->pRadioButtonFormatDD ->isChecked()) Acquisition.Format = t_File::DD;
+      else if (pOwn->pRadioButtonFormatEWF->isChecked()) Acquisition.Format = t_File::EWF;
+      else                                               Acquisition.Format = t_File::AFF;
+      if (RememberLastUsedValues)
+         DlgAcquireLastUsedFormat = Acquisition.Format;
+   }
 
-   #define COPY_VALUE(Acq, FieldName)                    \
+   #define COPY_LINEENTRY(Acq, FieldName, Remember)      \
       pDlgAcquireField = DlgAcquireGetField (FieldName); \
       Acq = pDlgAcquireField->pLineEdit->text();         \
-      if (RememberLastUsedValues)                        \
+      if (Remember)                                      \
          pDlgAcquireField->LastEnteredValue = Acq;
 
-   COPY_VALUE (Acquisition.CaseNumber    , CFG_DLGACQUIRE_EWF_CASENUMBER     )
-   COPY_VALUE (Acquisition.EvidenceNumber, CFG_DLGACQUIRE_EWF_EVIDENCENUMBER )
-   COPY_VALUE (Acquisition.Examiner      , CFG_DLGACQUIRE_EWF_EXAMINER       )
-   COPY_VALUE (Acquisition.Description   , CFG_DLGACQUIRE_EWF_DESCRIPTION    )
-   COPY_VALUE (Acquisition.Notes         , CFG_DLGACQUIRE_EWF_NOTES          )
-   COPY_VALUE (Acquisition.ImagePath     , CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY)
-   COPY_VALUE (Acquisition.ImageFilename , CFG_DLGACQUIRE_DEST_IMAGEFILENAME )
-   COPY_VALUE (Acquisition.InfoPath      , CFG_DLGACQUIRE_DEST_INFODIRECTORY )
-   COPY_VALUE (Acquisition.InfoFilename  , CFG_DLGACQUIRE_DEST_INFOFILENAME  )
-   #undef COPY_VALUE
+   if (!pOwn->Clone)
+   {
+      COPY_LINEENTRY (Acquisition.CaseNumber    , CFG_DLGACQUIRE_EWF_CASENUMBER     , RememberLastUsedValues)
+      COPY_LINEENTRY (Acquisition.EvidenceNumber, CFG_DLGACQUIRE_EWF_EVIDENCENUMBER , RememberLastUsedValues)
+      COPY_LINEENTRY (Acquisition.Examiner      , CFG_DLGACQUIRE_EWF_EXAMINER       , RememberLastUsedValues)
+      COPY_LINEENTRY (Acquisition.Description   , CFG_DLGACQUIRE_EWF_DESCRIPTION    , RememberLastUsedValues)
+      COPY_LINEENTRY (Acquisition.Notes         , CFG_DLGACQUIRE_EWF_NOTES          , RememberLastUsedValues)
+   }
+   COPY_LINEENTRY (Acquisition.ImagePath     , CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY, pOwn->Clone ? false : RememberLastUsedValues)
+   COPY_LINEENTRY (Acquisition.ImageFilename , CFG_DLGACQUIRE_DEST_IMAGEFILENAME , pOwn->Clone ? false : RememberLastUsedValues)
+   COPY_LINEENTRY (Acquisition.InfoPath      , CFG_DLGACQUIRE_DEST_INFODIRECTORY , RememberLastUsedValues)
+   COPY_LINEENTRY (Acquisition.InfoFilename  , CFG_DLGACQUIRE_DEST_INFOFILENAME  , RememberLastUsedValues)
+   #undef COPY_LINEENTRY
+
+   #define COPY_CHECKBOX(Acq, FieldName)                 \
+      pDlgAcquireField = DlgAcquireGetField (FieldName); \
+      Acq = pDlgAcquireField->pCheckBox->isChecked();    \
+      if (RememberLastUsedValues)                        \
+         pDlgAcquireField->LastEnteredValue = Acq  ? "1" : "0";
+
+   COPY_CHECKBOX (Acquisition.CalcMD5   , CFG_DLGACQUIRE_HASH_CALC_MD5   )
+   COPY_CHECKBOX (Acquisition.CalcSHA256, CFG_DLGACQUIRE_HASH_CALC_SHA256)
+   COPY_CHECKBOX (Acquisition.VerifySrc , CFG_DLGACQUIRE_HASH_VERIFY_SRC )
+   COPY_CHECKBOX (Acquisition.VerifyDst , CFG_DLGACQUIRE_HASH_VERIFY_DST )
+   #undef COPY_CHECKBOX
 
    return NO_ERROR;
 }
diff --git a/dlgacquire.h b/dlgacquire.h
index 94ffcca..b068099 100644
--- a/dlgacquire.h
+++ b/dlgacquire.h
@@ -37,21 +37,24 @@ class t_DlgAcquire: public QDialog
 
    public:
       t_DlgAcquire ();
-      t_DlgAcquire (t_pDevice pDevice, QWidget *pParent=NULL, Qt::WFlags Flags=0);
+      t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDeviceList, QWidget *pParent=NULL, Qt::WFlags Flags=0);
      ~t_DlgAcquire ();
 
       APIRET GetParameters (t_Device::t_Acquisition &Acquisition, bool RememberLastUsedValues=true);
    private:
-      APIRET AddField         (t_pDevice pDevice, t_pCfgDlgAcquireField pField, QGridLayout *pLayout, int *pRow);
-      APIRET CheckWriteAccess (const QString &Path, const QString &Filename, bool &Ok);
+      APIRET AddField             (t_pDevice pDevice, t_pCfgDlgAcquireField pField, QGridLayout *pLayout, int *pRow, int *pCol);
+      APIRET CheckWriteAccess     (const QString &Path, const QString &Filename, bool &Ok);
+      APIRET CreateDeviceTable    (t_pDeviceList pDeviceList, t_pDevice pDeviceSrc, QTableWidget **ppTable);
+      APIRET InsertDeviceTableRow (QTableWidget *pTable, int Row, t_pDeviceList pDeviceList, t_pDevice pDevSrc, t_pDevice pDev);
 
    private slots:
-      void UpdateCheckboxState (int State);
-      void UpdateButtonState   (const QString & NewText = QString());
+      void UpdateHashState     (int State=0);
+      void UpdateDialogState   (const QString & NewText = QString());
       void UpdateFieldState    (void);
       void SlotBrowse          (void);
       void SlotAccept          (void);
       void SlotTextEdited      (t_DlgAcquireLineEdit *pLineEdit, const QString &NewVal);
+      void SlotDeviceTableSelectionChanged (void);
 
    private:
       t_DlgAcquireLocal *pOwn;
@@ -62,7 +65,8 @@ enum
    ERROR_DLGACQUIRE_CONSTRUCTOR_NOT_SUPPORTED = ERROR_BASE_DLGACQUIRE + 1,
    ERROR_DLGACQUIRE_UNKNOWN_FILEDIALOG_SIZE,
    ERROR_DLGACQUIRE_INVALID_ENTRYMODE,
-   ERROR_DLGACQUIRE_INVALID_FORMAT
+   ERROR_DLGACQUIRE_INVALID_FORMAT,
+   ERROR_DLGACQUIRE_INVALID_SELECTION,
 };
 
 #endif
diff --git a/dlgacquire_private.h b/dlgacquire_private.h
index 7f1a792..69278a0 100755
--- a/dlgacquire_private.h
+++ b/dlgacquire_private.h
@@ -19,6 +19,10 @@
    #include "common.h"
 #endif
 
+#ifndef __DLGACQUIRE_H__
+   #include "dlgacquire.h"
+#endif
+
 class   t_DlgAcquireLineEdit;
 typedef t_DlgAcquireLineEdit *t_pDlgAcquireLineEdit;
 
@@ -27,8 +31,13 @@ class   t_DlgAcquireLineEdit: public QLineEdit
    Q_OBJECT
 
    public:
+      t_DlgAcquireLineEdit(void)
+      {
+         CHK_EXIT (ERROR_DLGACQUIRE_CONSTRUCTOR_NOT_SUPPORTED)
+      }
+
       t_DlgAcquireLineEdit (QWidget *pParent, const QString &Name)
-         :QLineEdit (pParent)
+         :QLineEdit (pParent)                                      //lint !e578: Declaration of symbol 'Name' hides ...
       {
          this->Name = Name;
          CHK_QT_EXIT (connect (this, SIGNAL (textEdited     (const QString &)),
diff --git a/dlgmessage.cpp b/dlgmessage.cpp
index cabdd8b..6a50b19 100644
--- a/dlgmessage.cpp
+++ b/dlgmessage.cpp
@@ -83,8 +83,8 @@ void t_DlgMessage::AdjustGeometry (void)
    Dx += frameGeometry().width () - pOwn->pTextBox->width ();  // Add the space surrounding the Textbox required by the dialog
    Dy += frameGeometry().height() - pOwn->pTextBox->height();
 
-   Dx = std::min (Dx, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->width ()) / 100);  // Limit to a certain amount
-   Dy = std::min (Dy, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->height()) / 100);  // of the available screen space
+   Dx = GETMIN (Dx, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->width ()) / 100);  // Limit to a certain amount
+   Dy = GETMIN (Dy, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->height()) / 100);  // of the available screen space
 
    X = (QApplication::desktop()->width  () - Dx) / 2;
    Y = (QApplication::desktop()->height () - Dy) / 2;
diff --git a/fifo.cpp b/fifo.cpp
index 10427d3..5af266f 100644
--- a/fifo.cpp
+++ b/fifo.cpp
@@ -9,11 +9,18 @@
 //  Module:         The central queues for pipelined data processing
 // ****************************************************************************
 
-#include "QSemaphore"
-#include "QMutex"
+#include "common.h"
+#include "unistd.h"
+
+#include <QSemaphore>
+#include <QMutex>
+#include <QString>
+#include <QStack>
 
 #include "util.h"
+#include "config.h"
 #include "fifo.h"
+#include "stdlib.h"
 
 class t_FifoStdLocal
 {
@@ -23,6 +30,7 @@ class t_FifoStdLocal
       QSemaphore          *pSemEmptyBlocks;
       QSemaphore          *pSemUsedBlocks;
       QMutex              *pMutexQueue;
+      t_pFifoMemory        pFifoMemory;
 };
 
 
@@ -32,20 +40,140 @@ static quint64 Frees    =0;
 static qint64  Allocated=0;  // let's use signed, so we can detect underruns
 
 
-// We use ANSI C malloc/free for the FIFO blocks, as we want to be sure that it's fast
+// ------------------------------
+//  FIFO block memory management
+// ------------------------------
 
+class t_FifoMemory
+{
+   public:
+       t_FifoMemory (unsigned int TotalBlocks, unsigned int AllocBlockSize);
+      ~t_FifoMemory ();
+
+       char *GetBlock      (unsigned int Size);
+       void  ReleaseBlock  (char *pBlock);
+       void  LogBlock      (char *pBlock, char Marker);
+
+   private:
+      unsigned int   oTotalBlocks;
+      unsigned int   oAllocBlockSize;
+      char         *poBuf;
+      char         *poBufFirstBlock;
+      QStack<char*>  oFreeBlocks;
+      QMutex         oMutex;
+};
 
-APIRET t_Fifo::Create (t_pFifoBlock &pBlock, unsigned int BufferSize)
+t_FifoMemory::t_FifoMemory (unsigned int TotalBlocks, unsigned int AllocBlockSize)
 {
-   int TotalSize;
+   unsigned int i;
+   unsigned int FirstBlockOffset = 0;
+   unsigned int BufferOffset     = offsetof (t_FifoBlock, Buffer);
+   int          PageSize         = getpagesize();
+
+   oTotalBlocks    = TotalBlocks;
+   oAllocBlockSize = AllocBlockSize;
+
+   poBuf = (char *) malloc (TotalBlocks * AllocBlockSize + PageSize);
+   if (poBuf == NULL)
+      CHK_EXIT (ERROR_FIFO_MEMORY_ALLOC_FAILED)
+
+   // Calculate offset to have the buffers always lie on a page boundary
+   // ------------------------------------------------------------------
+   if (((long long)poBuf+BufferOffset) % PageSize)
+      FirstBlockOffset = PageSize - ((long long)(poBuf+BufferOffset) % PageSize);
+   poBufFirstBlock = poBuf + FirstBlockOffset;
+
+   for (i=0; i<TotalBlocks; i++)
+      oFreeBlocks.push (&poBufFirstBlock[i*AllocBlockSize]);
+}
+
+t_FifoMemory::~t_FifoMemory (void)
+{
+   if ((unsigned) oFreeBlocks.count() != oTotalBlocks)
+      LOG_ERROR ("Some FIFO blocks have not been released (total: %d, released %d)", oTotalBlocks, oFreeBlocks.count())
+   free (poBuf);
+}
+
+
+char *t_FifoMemory::GetBlock (unsigned int Size)
+{
+   char *pBlock = NULL;
+
+   if (Size > oAllocBlockSize)
+   {
+      LOG_ERROR ("The requested block size is %u, but only %u sized blocks are available", Size, oAllocBlockSize)
+      CHK_EXIT (ERROR_FIFO_MEMORY_INVALID_BLOCKSIZE)
+   }
+   oMutex.lock();
+      if (!oFreeBlocks.isEmpty())
+         pBlock = oFreeBlocks.pop();
+   oMutex.unlock();
+
+   return pBlock;
+}
+
+
+void t_FifoMemory::ReleaseBlock (char *pBlock)
+{
+   unsigned int Ofs, i;
+
+   // Safety first
+   // ------------
+   if (pBlock < poBufFirstBlock)
+      CHK_EXIT (ERROR_FIFO_POINTER_TOO_LOW)
+
+   Ofs = pBlock - poBufFirstBlock;
+   if ((Ofs % oAllocBlockSize) != 0)
+      CHK_EXIT (ERROR_FIFO_POINTER_NOT_ON_BOUNDARY)
+
+   i = Ofs / oAllocBlockSize;
+   if (i >= oTotalBlocks)
+      CHK_EXIT (ERROR_FIFO_POINTER_TOO_HIGH)
+
+   // Give back the pointer
+   // ---------------------
+   oMutex.lock();
+      oFreeBlocks.push (pBlock);
+   oMutex.unlock();
+}
+
+
+void t_FifoMemory::LogBlock (char *pBlock, char Marker) // For debugging purposes
+{
+   int i;
+
+   i = (pBlock - poBuf) / oAllocBlockSize;
+   oMutex.lock();
+   printf ("%c%d ", Marker, i);
+   oMutex.unlock();
+}
+
+
+APIRET FifoMemoryAlloc (t_pFifoMemory *ppFifoMemory, unsigned int TotalBlocks, unsigned int AllocBlockSize)
+{
+   *ppFifoMemory = new t_FifoMemory (TotalBlocks, AllocBlockSize);
+
+   return NO_ERROR;
+}
+
+
+// ----------------------------
+//            FIFO
+// ----------------------------
+
+// We use ANSI C malloc/free for the FIFO blocks, as we want to be sure that it's fast
+
+APIRET t_Fifo::Create (t_pFifoMemory pFifoMemory, t_pFifoBlock &pBlock, unsigned int AllocSize)
+{
+   if (CONFIG(FifoMemoryManager))
+        pBlock = (t_pFifoBlock) pFifoMemory->GetBlock (AllocSize);
+   else pBlock = (t_pFifoBlock) UTIL_MEM_ALLOC        (AllocSize);
 
-   TotalSize = BufferSize + sizeof(t_FifoBlock);
-   pBlock = (t_pFifoBlock) UTIL_MEM_ALLOC (TotalSize);
    if (pBlock == NULL)
       CHK_CONST (ERROR_FIFO_MALLOC_FAILED)
 //   memset (pBlock, 0xAA, sizeof(t_FifoBlock) + BufferSize);
    pBlock->MagicStart         = FIFO_MAGIC_START;
-   pBlock->BufferSize         = BufferSize;
+   pBlock->BufferSize         = AllocSize - sizeof (t_FifoBlock);
    pBlock->DataSize           = 0;
    pBlock->LastBlock          = false;
 
@@ -59,32 +187,20 @@ APIRET t_Fifo::Create (t_pFifoBlock &pBlock, unsigned int BufferSize)
 
    pBlock->Nr                 = FIFO_NR_NOTSET;
 
-   //lint -save e826 suspicious ptr to ptr conversion
+   //lint -save -e826 suspicious ptr to ptr conversion
    FIFO_SET_MAGIC_END (pBlock)
    //lint -restore
 
    MutexGlobal.lock();
    Allocs++;
-   Allocated += TotalSize;
+   Allocated += AllocSize;
    MutexGlobal.unlock();
 
    return NO_ERROR;
 }
 
-unsigned int t_Fifo::GetCompressionOptimisedBufferSize (int CompressionBlockSize)
-{
-   return CompressionBlockSize + 4096 - sizeof(t_FifoBlock);
-}
-
-APIRET t_Fifo::CreateCompressionOptimised (t_pFifoBlock &pBlock, int CompressionBlockSize)
-{
-   CHK (Create (pBlock, GetCompressionOptimisedBufferSize (CompressionBlockSize)))
-
-   return NO_ERROR;
-}
-
 //lint -save -e661 -e826 -esym(613,pBlock) Possible access of out-of-bounds pointer, suspicious ptr to ptr conversion, possible use of NULL pointer
-APIRET t_Fifo::Destroy (t_pFifoBlock &pBlock)
+APIRET t_Fifo::Destroy (t_pFifoMemory pFifoMemory, t_pFifoBlock &pBlock)
 {
    int TotalSize;
 
@@ -105,7 +221,10 @@ APIRET t_Fifo::Destroy (t_pFifoBlock &pBlock)
    TotalSize = pBlock->BufferSize + sizeof(t_FifoBlock);
 
 //   memset (pBlock, 0xBB, TotalSize);
-   UTIL_MEM_FREE (pBlock);
+
+   if (CONFIG(FifoMemoryManager))
+        pFifoMemory->ReleaseBlock ((char *)pBlock);
+   else UTIL_MEM_FREE             (        pBlock);
    pBlock = NULL;
 
    MutexGlobal.lock();
@@ -123,22 +242,34 @@ APIRET t_Fifo::Destroy (t_pFifoBlock &pBlock)
 }
 //lint -restore
 
-t_FifoStd::t_FifoStd (int MaxBlocks)
+void t_Fifo::LogBlock (t_pFifoMemory pFifoMemory, t_pFifoBlock pBlock, char Marker)
+{
+   pFifoMemory->LogBlock ((char *)pBlock, Marker);
+}
+
+
+t_FifoStd::t_FifoStd (t_pFifoMemory pFifoMemory, int MaxBlocks)
 {
    static bool Initialised = false;
 
    if (!Initialised)
    {
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MALLOC_FAILED  ))
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_DOUBLE_FREE    ))
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_EMPTY          ))
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_END_CORRUPTED  ))
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_START_CORRUPTED))
-      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MEMORY_UNDERUN ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MALLOC_FAILED           ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_DOUBLE_FREE             ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_EMPTY                   ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_END_CORRUPTED           ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_START_CORRUPTED         ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MEMORY_UNDERUN          ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MEMORY_ALLOC_FAILED     ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_MEMORY_INVALID_BLOCKSIZE))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_POINTER_TOO_LOW         ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_POINTER_NOT_ON_BOUNDARY ))
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_FIFO_POINTER_TOO_HIGH        ))
       Initialised = true;
    }
    pOwn = new t_FifoStdLocal;
-   pOwn->MaxBlocks = MaxBlocks;
+   pOwn->pFifoMemory = pFifoMemory;
+   pOwn->MaxBlocks   = MaxBlocks;
 
    pOwn->pSemEmptyBlocks = new QSemaphore (MaxBlocks);
    pOwn->pSemUsedBlocks  = new QSemaphore (0);
@@ -153,7 +284,7 @@ t_FifoStd::~t_FifoStd ()
    {
       CHK_EXIT (t_FifoStd::Get (pBlock))
       if (pBlock)
-         CHK_EXIT (Destroy (pBlock))
+         CHK_EXIT (Destroy (pOwn->pFifoMemory, pBlock))
    }
 
    delete pOwn->pSemEmptyBlocks;
@@ -204,7 +335,7 @@ APIRET t_FifoStd::Usage (int &Percent)
 {
    int Cnt;
 
-   Count(Cnt);
+   CHK (Count(Cnt))
    Percent = (100LL * Cnt) / pOwn->MaxBlocks;
    return NO_ERROR;
 }
@@ -233,7 +364,7 @@ APIRET t_FifoStd::WakeWaitingThreads (void)
    {
       CHK (Get (pBlock))
       if (pBlock)
-         CHK (t_Fifo::Destroy (pBlock))
+         CHK (t_Fifo::Destroy (pOwn->pFifoMemory, pBlock))
    }
    else
    {
@@ -259,7 +390,7 @@ class t_FifoCompressLocal   // used as well for t_FifoCompressOut
       int           NextSubFifoNr;
 };
 
-static APIRET FifoCompressInit (t_FifoCompressLocal **ppOwn, int SubFifos, int MaxBlocks)
+static APIRET FifoCompressInit (t_FifoCompressLocal **ppOwn, t_pFifoMemory pFifoMemory, int SubFifos, int MaxBlocks)
 {
    *ppOwn = new t_FifoCompressLocal;
    (*ppOwn)->TotalMaxBlocks = SubFifos * MaxBlocks;
@@ -267,7 +398,7 @@ static APIRET FifoCompressInit (t_FifoCompressLocal **ppOwn, int SubFifos, int M
    (*ppOwn)->ppFifoArr      = (t_pFifoStd *) UTIL_MEM_ALLOC ((size_t)SubFifos * sizeof(t_pFifoStd));
 
    for (int i=0; i<SubFifos; i++)
-      (*ppOwn)->ppFifoArr[i] = new t_FifoStd (MaxBlocks);
+      (*ppOwn)->ppFifoArr[i] = new t_FifoStd (pFifoMemory, MaxBlocks);
 
    (*ppOwn)->NextSubFifoNr = 0;
    (*ppOwn)->pMutexQueue   = new QMutex();
@@ -293,9 +424,9 @@ t_FifoCompressIn::t_FifoCompressIn (void)
    CHK_EXIT (ERROR_FIFO_CONSTRUCTOR_NOT_SUPPORTED)
 }
 
-t_FifoCompressIn::t_FifoCompressIn (int SubFifos, int MaxBlocks)
+t_FifoCompressIn::t_FifoCompressIn (t_pFifoMemory pFifoMemory, int SubFifos, int MaxBlocks)
 {
-   CHK_EXIT (FifoCompressInit (&pOwn, SubFifos, MaxBlocks))
+   CHK_EXIT (FifoCompressInit (&pOwn, pFifoMemory, SubFifos, MaxBlocks))
 }
 
 t_FifoCompressIn::~t_FifoCompressIn ()
@@ -360,9 +491,9 @@ APIRET t_FifoCompressIn::Usage (int &Percent)
 {
    int Cnt;
 
-   Count(Cnt);
+   CHK (Count(Cnt))
    Percent = (100LL * Cnt) / pOwn->TotalMaxBlocks;
-   Percent = std::min (Percent, 100); // In some cases, the usage could be above 100% (see remarks for t_FifoCompressIn::Count); so we limit to 100
+   Percent = GETMIN (Percent, 100); // In some cases, the usage could be above 100% (see remarks for t_FifoCompressIn::Count); so we limit to 100
    return NO_ERROR;
 }
 
@@ -390,9 +521,9 @@ t_FifoCompressOut::t_FifoCompressOut (void)
    CHK_EXIT (ERROR_FIFO_CONSTRUCTOR_NOT_SUPPORTED)
 }
 
-t_FifoCompressOut::t_FifoCompressOut (int SubFifos, int MaxBlocks)
+t_FifoCompressOut::t_FifoCompressOut (t_pFifoMemory pFifoMemory, int SubFifos, int MaxBlocks)
 {
-   CHK_EXIT (FifoCompressInit (&pOwn, SubFifos, MaxBlocks))
+   CHK_EXIT (FifoCompressInit (&pOwn, pFifoMemory, SubFifos, MaxBlocks))
 }
 
 t_FifoCompressOut::~t_FifoCompressOut ()
@@ -464,9 +595,9 @@ APIRET t_FifoCompressOut::Usage (int &Percent)
 {
    int Cnt;
 
-   Count(Cnt);
+   CHK (Count(Cnt))
    Percent = (100LL * Cnt) / pOwn->TotalMaxBlocks;
-   Percent = std::min (Percent, 100); // In some cases, the usage could be above 100% (see remarks for t_FifoCompressIn::Count); so we limit to 100
+   Percent = GETMIN (Percent, 100); // In some cases, the usage could be above 100% (see remarks for t_FifoCompressIn::Count); so we limit to 100
    return NO_ERROR;
 }
 
@@ -499,3 +630,4 @@ APIRET FifoGetStatistics (quint64 &AllocCalls, quint64 &FreeCalls, qint64 &Alloc
    return NO_ERROR;
 }
 
+
diff --git a/fifo.h b/fifo.h
index f7edc14..e3450cc 100644
--- a/fifo.h
+++ b/fifo.h
@@ -24,6 +24,15 @@
 #include "aaff.h"
 
 
+
+class   t_FifoMemory;
+typedef t_FifoMemory *t_pFifoMemory;
+
+APIRET FifoMemoryAlloc   (t_pFifoMemory *ppFifoMemory, unsigned int TotalBlocks, unsigned int BlockSize);
+APIRET FifoGetStatistics (quint64 &AllocCalls, quint64 &FreeCalls, qint64 &AllocatedMemory);
+
+
+
 class t_FifoStdLocal;
 class t_FifoCompressLocal;
 
@@ -58,11 +67,12 @@ class t_Fifo
    public:
       virtual ~t_Fifo  (void) {};
 
-      static  APIRET CreateCompressionOptimised (t_pFifoBlock &pBlock, int CompressionBlockSize);
-      static  APIRET Create                     (t_pFifoBlock &pBlock, unsigned int BufferSize);
-      static  APIRET Destroy                    (t_pFifoBlock &pBlock);
+      static  APIRET Create   (t_pFifoMemory pFifoMemory, t_pFifoBlock &pBlock, unsigned int AllocSize);
+      static  APIRET Destroy  (t_pFifoMemory pFifoMemory, t_pFifoBlock &pBlock);
+      static  void   LogBlock (t_pFifoMemory pFifoMemory, t_pFifoBlock  pBlock, char Marker);
 
-      static  unsigned int GetCompressionOptimisedBufferSize (int CompressionBlockSize);
+      static  unsigned int GetBufferOverhead      (void);
+      static  unsigned int GetOptimisedBufferSize (int BlockSize);
 
       virtual APIRET Insert             (t_pFifoBlock  pBlock) = 0;
       virtual APIRET InsertDummy        (void)                 = 0;
@@ -77,7 +87,7 @@ typedef t_Fifo *t_pFifo;
 class t_FifoStd: public t_Fifo
 {
    public:
-      t_FifoStd (int MaxBlocks=128);
+      t_FifoStd (t_pFifoMemory pFifoMemory, int MaxBlocks=128);
      ~t_FifoStd ();
 
       APIRET Insert             (t_pFifoBlock  pBlock);
@@ -97,7 +107,7 @@ class t_FifoCompressIn: public t_Fifo
 {
    public:
       t_FifoCompressIn (void);
-      t_FifoCompressIn (int SubFifos, int MaxBlocks=128);
+      t_FifoCompressIn (t_pFifoMemory pFifoMemory, int SubFifos, int MaxBlocks=128);
      ~t_FifoCompressIn ();
 
       APIRET Insert             (t_pFifoBlock  pBlock);
@@ -117,7 +127,7 @@ class t_FifoCompressOut: public t_Fifo
 {
    public:
       t_FifoCompressOut (void);
-      t_FifoCompressOut (int SubFifos, int MaxBlocks=128);
+      t_FifoCompressOut (t_pFifoMemory pFifoMemory, int SubFifos, int MaxBlocks=128);
       virtual ~t_FifoCompressOut ();
 
       APIRET Insert             (t_pFifoBlock  pBlock);
@@ -139,9 +149,6 @@ typedef t_FifoCompressIn  *t_pFifoCompressIn;
 typedef t_FifoCompressOut *t_pFifoCompressOut;
 
 
-APIRET FifoGetStatistics (quint64 &AllocCalls, quint64 &FreeCalls, qint64 &AllocatedMemory);
-
-
 // ------------------------------------
 //             Error codes
 // ------------------------------------
@@ -156,7 +163,12 @@ APIRET FifoGetStatistics (quint64 &AllocCalls, quint64 &FreeCalls, qint64 &Alloc
          ERROR_FIFO_START_CORRUPTED,
          ERROR_FIFO_MEMORY_UNDERUN,
          ERROR_FIFO_FUNCTION_NOT_IMPLEMENTED,
-         ERROR_FIFO_CONSTRUCTOR_NOT_SUPPORTED
+         ERROR_FIFO_CONSTRUCTOR_NOT_SUPPORTED,
+         ERROR_FIFO_MEMORY_ALLOC_FAILED,
+         ERROR_FIFO_MEMORY_INVALID_BLOCKSIZE,
+         ERROR_FIFO_POINTER_TOO_LOW,
+         ERROR_FIFO_POINTER_NOT_ON_BOUNDARY,
+         ERROR_FIFO_POINTER_TOO_HIGH
       };
    #endif
 
diff --git a/file.cpp b/file.cpp
index 4c3fbc2..9ababe8 100644
--- a/file.cpp
+++ b/file.cpp
@@ -19,11 +19,8 @@
 
 #include "device.h"
 #include "config.h"
-//#include "dlgwait.h"
-
-
-const char *t_File::pExtensionInfo     = ".info";
 
+const char *t_File::pExtensionInfo = ".info";
 
 APIRET t_File::Init (void)
 {
@@ -43,13 +40,15 @@ APIRET t_File::Init (void)
    return NO_ERROR;
 }
 
-APIRET t_File::GetFormatDescription (t_Format F, QString &Str)
+APIRET t_File::GetFormatDescription (t_Format Format, bool Clone, QString &Str)
 {
    QString SubFormat;
-   switch (F)
+   switch (Format)
    {
       case DD:
-         Str = QObject::tr("Linux dd raw image");
+         if (Clone)
+              Str = QObject::tr("Creation of a clone");
+         else Str = QObject::tr("Linux dd raw image");
          break;
       case EWF:
          switch (CONFIG(EwfFormat))
@@ -59,6 +58,7 @@ APIRET t_File::GetFormatDescription (t_Format F, QString &Str)
             case LIBEWF_FORMAT_ENCASE3: SubFormat="Encase3"; break;
             case LIBEWF_FORMAT_ENCASE4: SubFormat="Encase4"; break;
             case LIBEWF_FORMAT_ENCASE5: SubFormat="Encase5"; break;
+            case LIBEWF_FORMAT_ENCASE6: SubFormat="Encase6"; break;
             case LIBEWF_FORMAT_FTK    : SubFormat="FTK"    ; break;
             case LIBEWF_FORMAT_SMART  : SubFormat="Smart"  ; break;
             case LIBEWF_FORMAT_LVF    : SubFormat="LVF"    ; break;
@@ -75,15 +75,15 @@ APIRET t_File::GetFormatDescription (t_Format F, QString &Str)
    return NO_ERROR;
 }
 
-APIRET t_File::GetFormatExtension (t_Format F, QString *pExtWildCards, QString *pExtHumanReadable)
+APIRET t_File::GetFormatExtension (t_Format Format, bool Clone, QString *pExtWildCards, QString *pExtHumanReadable)
 {
    QString Wild, Human;
 
-   switch (F)
+   switch (Format)
    {
       case DD:
-         Wild = ".dd";
-         Human = Wild;
+         if (!Clone)
+            Human = Wild = ".dd";
          break;
       case EWF:
          switch (CONFIG(EwfFormat))
@@ -93,6 +93,7 @@ APIRET t_File::GetFormatExtension (t_Format F, QString *pExtWildCards, QString *
             case LIBEWF_FORMAT_ENCASE3:
             case LIBEWF_FORMAT_ENCASE4:
             case LIBEWF_FORMAT_ENCASE5:
+            case LIBEWF_FORMAT_ENCASE6:
             case LIBEWF_FORMAT_LINEN5 :
             case LIBEWF_FORMAT_FTK    : Wild=".E??"; Human=".Exx"; break;
             case LIBEWF_FORMAT_SMART  : Wild=".s??"; Human=".sxx"; break;
@@ -112,4 +113,3 @@ APIRET t_File::GetFormatExtension (t_Format F, QString *pExtWildCards, QString *
 
    return NO_ERROR;
 }
-
diff --git a/file.h b/file.h
index a9da738..87bb11a 100644
--- a/file.h
+++ b/file.h
@@ -33,8 +33,8 @@ namespace t_File
    extern const char *pExtensionInfo;
 
 
-   APIRET GetFormatDescription (t_Format F, QString &Str);
-   APIRET GetFormatExtension   (t_Format F, QString *pExtWildcards, QString *pExtHumanReadable=NULL);
+   APIRET GetFormatDescription (t_Format Format, bool Clone, QString &Str);
+   APIRET GetFormatExtension   (t_Format Format, bool Clone, QString *pExtWildcards, QString *pExtHumanReadable=NULL);
    APIRET Init                 (void);
 }
 
diff --git a/guymager.cfg b/guymager.cfg
index 3ba33b6..c53b01f 100644
--- a/guymager.cfg
+++ b/guymager.cfg
@@ -195,6 +195,15 @@ REM    DestInfoDirectory   The directory that will be used for storing the info
 REM    DestImageFilename   The filename of the image files (without the extension)
 REM    DestInfoFilename    The filename of the info file (without the extension)
 REM
+REM Finally, there are some checkboxes in the acquisition dialog that are controlled by the following
+REM entry fields:
+REM    HashCalcMD5         The checkbox for MD5 hash
+REM    HashCalcSHA256      The checkbox for SHA-256 hash
+REM    HashVerifySrc       The checkbox for the source verification (re-read source and chek if it
+REM                        returns the same data than during acquisition)
+REM    HashVerifyDst       The checkbox for the imager verification (read and check the image after
+REM                        the acquisition has been done)
+REM
 REM For each one of these fields, there is an entry in configuration table DlgAcquireField. It has the
 REM following structure:
 REM    FieldName    The name of the field, as indicated above
@@ -214,8 +223,8 @@ REM                                 is filled in with the default value. On subs
 REM                                 appearances, the field contains the value entered previously (which
 REM                                 may still be the default value, if it was not edited).
 REM
-REM    DefaultValue The default value for the field. It may contain any text you like. Guymager knows
-REM                 several special sequences, that will be replaced automatically:
+REM    DefaultValue The default value for the field. It may contain any text you like (for the checkboxes:
+REM                 see below). Guymager knows several special sequences, that will be replaced automatically:
 REM                    %d%       the day as number without a leading zero (1 to 31)
 REM                    %dd%      the day as number with a leading zero (01 to 31)
 REM                    %ddd%     the abbreviated localized day name (e.g. 'Mon' to 'Sun')
@@ -244,6 +253,9 @@ REM                    %size%    the device's size in human readable format (e.g
 REM                    %version% guymager software version
 REM                 Remark: The date/time sequences have been copied from Trolltech's Qt documentation.
 REM
+REM                 Checkboxes: Simply put '1' if you want to have the checkbox enabled or '0' for having it
+REM                 disabled. Attention: Putting other values may lead to unpredictable results.
+REM
 REM Note that all the 8 fields must by contained exactely once in the configuration table DlgAcquireField.
 REM *** EXAMPLE A ***
 REM    TABLE DlgAcquireField NoName
@@ -271,20 +283,25 @@ REM With this setting, the acquisition dialog would open up with the examiner fi
 REM something similar to 'Marc Murrsky acquired it on 5. December 2007'
 
 TABLE DlgAcquireField NoName
-   REM Field                Entry        Default
-   REM name                 mode         value
-   REM -------------------------------------------------------------------------
-       'EwfCaseNumber'      ShowLast     ''
-       'EwfEvidenceNumber'  ShowDefault  ''
-       'EwfExaminer'        ShowLast     ''
-       'EwfDescription'     ShowDefault  ''
-       'EwfNotes'           ShowDefault  '%serial%'
-       'DestImageDirectory' ShowLast     ''
-       'DestInfoDirectory'  Hide         ''
-       'DestImageFilename'  ShowDefault  ''
-       'DestInfoFilename'   ShowDefault  ''
+   REM Field                Entry mode  Entry mode  Default
+   REM name                 image       clone       value
+   REM ------------------------------------------------------------------------------------
+       'EwfCaseNumber'      ShowLast    Hide        ''
+       'EwfEvidenceNumber'  ShowDefault Hide        ''
+       'EwfExaminer'        ShowLast    Hide        ''
+       'EwfDescription'     ShowDefault Hide        ''
+       'EwfNotes'           ShowDefault Hide        '%serial%'
+       'DestImageDirectory' ShowLast    Hide        ''
+       'DestInfoDirectory'  Hide        ShowLast    ''
+       'DestImageFilename'  ShowDefault Hide        ''
+       'DestInfoFilename'   ShowDefault ShowDefault ''
+       'HashCalcMD5'        ShowLast    ShowLast    '1'
+       'HashCalcSHA256'     ShowLast    ShowLast    '0'
+       'HashVerifySrc'      ShowLast    ShowLast    '0'
+       'HashVerifyDst'      ShowLast    ShowLast    '1'
 ENDTABLE
 
+
 REM There is a another configuration table, DlgAcquireRule, which allows to copy the contents of some
 REM fields automatically to others while typing. The entries in this table are processed one after the
 REM other everytime you hit a key in any of the 8 fields.
@@ -356,16 +373,23 @@ REM ==================
 REM
 REM Device list scanning
 REM --------------------
-REM Guymager knows 2 methods for getting the list of the available memory devices: The old one, that uses libparted
-REM and the new one one that uses DBUS/HAL. Select the method you want with the configuration parameter ScanUsingDbusHal:
+REM DeviceScanMethod        Guymager knows 3 methods for getting the list of the available memory devices: The old one,
+REM                         that uses libparted, the new one that uses DBUS/HAL and the even newer one that uses
+REM                         DeviceKit-Disks. Select your method by setting this parameter to:
+REM
+REM                            DBusDevKit   Use the newest method. You need a Linux supporting DeviceKit-Disks for
+REM                                         this setting (for example Ubuntu 9.10).
 REM
-REM ScanUsingDbusHal = 1    Use the new method (recommended).
+REM                            DBusHAL      Use the new method (recommended).
 REM
-REM ScanUsingDbusHal = 0    Use the old method. It was observed that the internal scan function hung while an acquisition
-REM                         was running. This leads to the problem that the devices shown in guymager possibly cannot be
-REM                         updated while an acquisition is running. When using this method, the command specified in
-REM                         configuration parameter CommandGetSerialNumber (see below) is used for finding the serial
-REM                         number of each device (not really elegant). Again, ScanUsingDbusHal = 1 is the recommended way.
+REM                            libparted    Use the old method. It was observed that the internal scan function hung
+REM                                         while an acquisition was running. This leads to the problem that the devices
+REM                                         shown in guymager possibly cannot be updated while an acquisition is running.
+REM                                         When using this method, the command specified in configuration parameter
+REM                                         CommandGetSerialNumber (see below) is used for finding the serial number of
+REM                                         each device (not really elegant). Again, DBusHAL is the recommended setting.
+REM                         When chossing an unsupported scan method, Guymager shows the user a dialog asking to fall back
+REM                         to a supported one.
 REM
 REM CommandGetSerialNumber  is used to extract the serial number from a device when setting ScanUsingDbusHal to 0 (not
 REM                         recommended). The placeholder %dev in the command string will be replaced by the device
@@ -377,7 +401,7 @@ REM ScanInterval            [s] Speficies how often an automatic device scan (fo
 REM                         should launched. Keep in mind, that the device scan can be launched as well manually.
 REM
 
-ScanUsingDbusHal        = 1
+DeviceScanMethod        = DBusDevKit
 CommandGetSerialNumber  = 'bash -c "smartctl -i %dev | grep -i serial | awk ''{print $3 $4 $5 $6 $7 $8 $9}'' "'
 ScanInterval            = 6000
 
@@ -398,16 +422,15 @@ REM FifoBlockSizeEWF        The block size for dd images (in bytes). Recommended
 REM
 REM FifoBlockSizeAFF        The block size for dd images (in bytes). Recommended value: 10485760 (10MB).
 REM
+REM FifoMaxMem              The amount of memory used for the internal FIFO queues of an acquisition. The value is indicated in
+REM                         Megabytes. If you set it to 0, Guymager uses 1/8 of the available RAM. Keep in mind, that the amount
+REM                         amount of memory used by Guymager may be much higher. With a value of 256 and 4 acquisitions running
+REM                         in parallel, a total of 1GB RAM would be used by Guymager - only for the FIFOs, not counting the
+REM                         overhead required by Guymager and the libs it uses (Qt, libewf, ...).
+REM                         The recommended value is 0 (automatic memory usage calculation).
 REM
-REM FifoMaxMem and FifoMaxEntries  Both parameters control the amount of memory used for the internal fifo queues. In different
-REM                         ways. FifoMaxMem sets an upper limit per acquisition in MB. FifoMaxEntries indicates how many data
-REM                         blocks may be waiting in a queue; this number, multiplied by the block size and the number of queues
-REM                         leads to a memory size. Guymager finally uses the smallest of both memory sizes.
-REM                         The fifo memory should be big enough to buffer temporary throughput variations of the different threads.
-REM                         Too large fifos only consume memory and are of no help.
-REM                         Be aware that using wrong parameters may lead to memory overflows and stopping Guymager in the middle
-REM                         of an acquisition.
-REM                         It is recommended to set both values to 0 for automatic memory usage calculation.
+REM FifoMemoryManager       Set to on to use the internal FIFO memory manager. if set to off, the classical C functions mallox and
+REM                         free are used.
 REM
 REM UseSeparatehashThread   The hash calculation can be done in a separate thread or in the read thread (i.e. the thread reading
 REM                         the data from the source). Using a separate thread led to a slight performance advantage on the
@@ -420,11 +443,11 @@ REM                         Set to AUTO will use the number of CPUs installed in
 REM                         Set to 0 for disabling multi-threaded compression and build EWF file the conventional way.
 REM
 
-FifoBlockSizeDD  = 262144
-FifoBlockSizeEWF = 32768
-FifoBlockSizeAFF = 10485760
-FifoMaxMem       = 0
-FifoMaxEntries   = 0
+FifoBlockSizeDD   = 262144
+FifoBlockSizeEWF  = 32768
+FifoBlockSizeAFF  = 10485760
+FifoMaxMem        = 0
+FifoMemoryManager = On
 
 UseSeparatehashThread = Yes
 CompressionThreads    = AUTO
diff --git a/guymager.pro b/guymager.pro
index 4866c6d..1246b0f 100644
--- a/guymager.pro
+++ b/guymager.pro
@@ -32,7 +32,7 @@
 
 
 TEMPLATE = app
-CONFIG   = qt release warn_on qdbus
+CONFIG   = qt debug warn_on qdbus
 TARGET   = guymager
 MOC_DIR  = ./moc
 
@@ -77,6 +77,7 @@ SOURCES += itemdelegate.cpp
 SOURCES += main.cpp
 SOURCES += mainwindow.cpp
 SOURCES += md5.c
+SOURCES += media.cpp
 SOURCES += memwatch.c
 SOURCES += qtutil.cpp
 #SOURCES += sha256.cpp
@@ -100,6 +101,7 @@ HEADERS += dlgwait.h
 HEADERS += infofield.h
 HEADERS += itemdelegate.h
 HEADERS += mainwindow.h
+HEADERS += media.h
 HEADERS += memwatch.h
 HEADERS += table.h
 HEADERS += threadcompress.h
diff --git a/guymager_de.ts b/guymager_de.ts
index 0ae7856..48ce646 100644
--- a/guymager_de.ts
+++ b/guymager_de.ts
@@ -1,159 +1,157 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS><TS version="1.1" language="de">
+<!DOCTYPE TS><TS>
 <context>
     <name>QObject</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Missing root rights</source>
         <comment>Dialog title</comment>
         <translation>Keine Root-Rechte</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Guymager needs to be started with root rights in order to perform acquisitions. You are not root and thus won't be able to acquire devices.
 Continue anyway?</source>
         <translation>Guymager muss mit Root-Rechten gestartet werden um Akquisitionen ausführen zu können. Sie haben keine Root-Rechte und daher werden Sie keine Geräte akquirieren können.
 Trotzdem fortfahren?</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Deleting %1</source>
         <translation>Lösche %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Ok</source>
         <translation>Ok</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Cancel</source>
         <translation>Abbruch</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Linux dd raw image</source>
         <translation>Linux dd-Image</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Expert Witness Format, sub-format %1</source>
         <translation>EWF-Format, Unterformat %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Advanced forensic image</source>
         <translation>AFF format</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>%1 not accessible</source>
-        <comment>Dialog title</comment>
-        <translation>%1nicht verfügbar</translation>
+        <source>Guymager cannot scan the devices connected to this computer.</source>
+        <translation>Guymager kann die angeschlossenen Geräte nicht abfragen.</translation>
+    </message>
+    <message>
+        <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
+        <translation>Die gewählte Abfragemethode ("%1") steht nicht zur Verfügung. Möchten Sie eine  andere Methode versuchen?</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation>Abbruch</translation>
+    </message>
+    <message>
+        <source>Try method "%1"</source>
+        <translation>Methode "%1"</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Guymager is configured to use %1 for scanning the connected devices, but this did not work. Alternatively, you may use %2. Do you want to switch to %2?</source>
-        <translation>Guymager ist so konfiguriert, dass es zur Geräte-Suche %1 benutzt, was jedoch nicht funktionierte. Alternativ können Sie %2 benutzen. Möchten Sie zu %2 umschalten?</translation>
+        <source>Creation of a clone</source>
+        <translation>Erstellen eines Klons</translation>
     </message>
 </context>
 <context>
     <name>t_DeviceListModel</name>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Serial
-nr.</source>
-        <comment>Column on main screen</comment>
-        <translation>Serien-
-nummer</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Linux
 device</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Linux
 Gerät</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Model</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Modell</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
+        <source>Serial
+nr.</source>
+        <comment>Column of device table</comment>
+        <translation>Serien-
+nummer</translation>
+    </message>
+    <message>
         <source>Size</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Größe</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
+        <source>Remarks</source>
+        <comment>Column of device table</comment>
+        <translation>Bemerkungen</translation>
+    </message>
+    <message>
+        <source>State</source>
+        <comment>Column of device table</comment>
+        <translation>Status</translation>
+    </message>
+    <message>
+        <source>Hidden
+Areas</source>
+        <comment>Column of device table</comment>
+        <translation>Versteckte
+Bereiche</translation>
+    </message>
+    <message>
         <source>Bad
 sectors</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Defekte
 Sektoren</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Progress</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Fortschritt</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Average
 Speed
 [MB/s]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Mittlere
 Geschw.
 [MB/s]</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Time
 remaining</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Restzeit</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>FIFO queues
 usage
 [%]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>FIFO-
 Belegung
 [%]</translation>
     </message>
-    <message>
-        <location filename="" line="136084940"/>
-        <source>State</source>
-        <comment>Column on main screen</comment>
-        <translation>Status</translation>
-    </message>
 </context>
 <context>
     <name>t_DlgAbort</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Do you want to abort the acquisition of %1?</source>
         <translation>Möchten Sie die Akquisition von %1 abbrechen?</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Delete partial image files</source>
         <translation>Partielle Image-Dateien löschen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Do you want to abort the verification of %1?</source>
         <translation>Möchten Sie die Verifizierung von %1 abbrechen?</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Abort?</source>
         <comment>Dialog title</comment>
         <translation>Abbrechen?</translation>
@@ -162,73 +160,51 @@ Belegung
 <context>
     <name>t_DlgAcquire</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>EwfCaseNumber</source>
         <translation>Fallnummer</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>EwfEvidenceNumber</source>
         <translation>Asservatennummer</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>EwfExaminer</source>
         <translation>Bearbeiter</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>EwfDescription</source>
         <translation>Beschreibung</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>EwfNotes</source>
         <translation>Notizen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>DestDirectory</source>
-        <translation>Zielverzeichnis</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>DestImageFilename</source>
         <translation>Image-Dateiname (ohne Endung)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>DestInfoFilename</source>
         <translation>Info-Dateiname (ohne Endung)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>File format</source>
         <translation>Dateiformat</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Destination</source>
         <translation>Ziel</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Configuration flag WriteToDevNull is set!</source>
         <translation>Konfigurationsparameter WriteToDevNull ist gesetzt!</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Hash computation</source>
-        <translation>Hash-Berechnung</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation>Zielverzeichnis auswählen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>The filenames contain special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>Image filename: %1
 <byte value="x9"/>Info filename: %2
@@ -239,100 +215,125 @@ Do you accept these changes?</source>
 Sind Sie mit diesen Änderungen einverstanden?</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>(file extension %1)</source>
         <translation>(Datei-Endung %1)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Special characters</source>
         <comment>Dialog title</comment>
         <translation>Sonderzeichen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>DestImageDirectory</source>
         <translation>Image-Verzeichnis</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>DestInfoDirectory</source>
         <translation>Info-Verzeichnis</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>...</source>
         <comment>The directory browse button</comment>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Acquisition parameters for %1</source>
-        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
-        <translation>Akquisitionsparameter für %1</translation>
+        <source>Access denied</source>
+        <comment>Dialog title</comment>
+        <translation>Kein Zugriff</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Re-read source after acquisition for verification (takes twice as long)</source>
-        <translation>Quellmedium nach Akquisition erneut lesen und verifizieren (benötigt die doppelte Zeit)</translation>
+        <source>HashCalcMD5</source>
+        <translation>MD5 berechnen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Images files exist</source>
-        <comment>Dialog title</comment>
-        <translation>Image-Dateien existieren bereits</translation>
+        <source>HashCalcSHA256</source>
+        <translation>SHA-256 berechnen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>The image files already exist. Do you want to overwrite them?</source>
-        <translation>Die Image-Dateien existieren bereits. Möchten Sie sie überschreiben?</translation>
+        <source>HashVerifySrc</source>
+        <translation>Quellmedium nach Akquisition erneut lesen und verifizieren (benötigt die doppelte Zeit)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Access denied</source>
-        <comment>Dialog title</comment>
-        <translation>Kein Zugriff</translation>
+        <source>HashVerifyDst</source>
+        <translation>Image nach Akquisition verifizieren (benötigt die doppelte Zeit)</translation>
+    </message>
+    <message>
+        <source>Hash calculation / verification</source>
+        <translation>Hash-Berechnung und Verifizierung</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Guymager cannot write to the directory
 <byte value="x9"/>%1
-This may be due to insufficient access rights. Please choose another directory.</source>
-        <translation>Der Schreibzugriff auf das Verzeichnis
+This may be due to insufficient access rights or unsupported filename characters. Please choose another directory.</source>
+        <translation>Der Schreibzugriff auf das Verzeichnis<byte value="x9"/>%1schlug fehl. Dies könnte an unzureichenden Zugriffsrechten oder an Sonderzeichen im Dateinamen liegen. Bitte wählen Sie ein anderes Verzeichnis.</translation>
+    </message>
+    <message>
+        <source>Local device, cannot be written</source>
+        <translation>Lokales Gerät, nicht beschreibbar</translation>
+    </message>
+    <message>
+        <source>Too small</source>
+        <translation>Zu klein</translation>
+    </message>
+    <message>
+        <source>In use</source>
+        <translation>Wird bereits benutzt</translation>
+    </message>
+    <message>
+        <source>Ok for cloning</source>
+        <translation>Bereit zum Klonen</translation>
+    </message>
+    <message>
+        <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>%1
-schlug fehl. Dies könnte an unzureichenden Zugriffsrechten liegen. Bitte wählen Sie ein anderes Verzeichnis.</translation>
+Do you accept these changes?</source>
+        <translation>Der Info-Dateiname enthält unerlaubte Sonderzeichen. Guymager schlägt stattdessen folgenden Namen vor:<byte value="x9"/> %1
+Sind Sie mit diesen Änderungen einverstanden?</translation>
+    </message>
+    <message>
+        <source>Files exist</source>
+        <comment>Dialog title</comment>
+        <translation>Dateien existieren bereits</translation>
+    </message>
+    <message>
+        <source>The image or info files already exist. Do you want to overwrite them?</source>
+        <translation>Die Image- oder Info-Dateien existieren bereits. Möchten Sie sie überschreiben?</translation>
+    </message>
+    <message>
+        <source>Clone %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation>Gerät %1 klonen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Calculate MD5</source>
-        <translation></translation>
+        <source>Acquire image of %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation>Image von %1 erstellen</translation>
+    </message>
+    <message>
+        <source>Device to be cloned</source>
+        <translation>Zu klonendes Gerät</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Calculate SHA-256</source>
-        <translation></translation>
+        <source>Used in another clone operation</source>
+        <translation>Durch andere Klon-Operation belegt</translation>
     </message>
 </context>
 <context>
     <name>t_DlgDirSel</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>New directory</source>
         <translation>Neues Verzeichnis</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Remove directory</source>
         <translation>Verzeichnis entfernen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation>Zielverzeichnis auswählen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>NewDirectory</source>
         <comment>Name of the new directory that will be created</comment>
         <translation>NeuesVerzeichnis</translation>
@@ -341,7 +342,6 @@ schlug fehl. Dies könnte an unzureichenden Zugriffsrechten liegen. Bitte wähle
 <context>
     <name>t_DlgMessage</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Close</source>
         <translation>Schliessen</translation>
     </message>
@@ -349,17 +349,14 @@ schlug fehl. Dies könnte an unzureichenden Zugriffsrechten liegen. Bitte wähle
 <context>
     <name>t_Info</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Command executed: %1</source>
         <translation>Ausgeführter Befehl: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>No information can be displayed as a timeout occured while executing the command.</source>
         <translation>Der Befehl benötigte zu lange; keine Informationen vorhanden.</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Information returned:</source>
         <translation>Ausgabe:</translation>
     </message>
@@ -367,161 +364,131 @@ schlug fehl. Dies könnte an unzureichenden Zugriffsrechten liegen. Bitte wähle
 <context>
     <name>t_InfoField</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Size</source>
         <translation>Größe</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Sector size</source>
         <translation>Sektorgröße</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Image file</source>
         <translation>Image-Datei</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Info file</source>
         <translation>Info-Datei</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Current speed</source>
         <translation>Aktuelle Geschwindigkeit</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>bytes</source>
         <translation>Bytes</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Hash calculation</source>
         <translation>Hash-Berechnung</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Source verification</source>
         <translation>Verifikation Quellmedium</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>on</source>
-        <comment>Display that source verification is on</comment>
-        <translation>ein</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
-        <source>off</source>
-        <comment>Display that source verification is off</comment>
-        <translation>aus</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
         <translation>Läuft seit</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>MD5 and SHA-256</source>
         <comment>Both hashes are calculated</comment>
         <translation>MD5 und SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>MD5</source>
         <translation>MD5</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>SHA-256</source>
         <translation>SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>off</source>
         <comment>Hash calculation is off</comment>
         <translation>aus</translation>
     </message>
+    <message>
+        <source>Image verification</source>
+        <translation>Verifikation Image</translation>
+    </message>
+    <message>
+        <source>on</source>
+        <comment>Display that verification is on</comment>
+        <translation>ein</translation>
+    </message>
+    <message>
+        <source>off</source>
+        <comment>Display that verification is off</comment>
+        <translation>aus</translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Local device</source>
         <translation>Lokales Gerät</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Idle</source>
         <translation>--</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Cleanup</source>
         <translation>Aufräumen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Finished</source>
         <translation>Fertig</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted - Error: Reason is 'none'</source>
         <translation>Abbruch - Fehler "Reason none"</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted by user</source>
         <translation>Abbruch durch Benutzer</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted - Image file write error</source>
         <translation>Abbruch - Image-Schreibfehler</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted - Device read error</source>
         <translation>Abbruch - Lesefehler</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>&Rescan</source>
         <translation>&Auffrischen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>F5</source>
         <translation>F5</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Rescan devices and update list</source>
-        <translation>Geräte neu einlesen und Liste auffrischen</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>There are active acquisitions. Do you really want to abort them and quit?</source>
         <translation>GUYMAGER hat noch Akquisitionen laufen. Möchten Sie diese abbrechen und das Programm verlassen?</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Debug information</source>
         <translation>Debug-Informationen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>About GUYMAGER</source>
         <comment>Dialog title</comment>
         <translation>Über GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>GUYMAGER is a Linux-based forensic imaging tool
 
 Version: %1
@@ -538,391 +505,464 @@ Benutzt libewf %4
 Benutzt libguytools %5</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>About Qt</source>
         <comment>Dialog title</comment>
         <translation>Über Qt</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Exit GUYMAGER</source>
         <comment>Dialog title</comment>
         <translation>GUYMAGER verlassen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>&Devices</source>
         <translation>&Geräte</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>&Misc</source>
         <comment>Menu entry</comment>
         <translation>&Verschiedenes</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Debug</source>
         <comment>Menu entry</comment>
         <translation>Debug</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>&Help</source>
         <comment>Menu entry</comment>
         <translation>&Hilfe</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>About &GUYMAGER</source>
         <comment>Menu entry</comment>
         <translation>Über &GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>About &Qt</source>
         <comment>Menu entry</comment>
         <translation>Über &Qt</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Acquisition running</source>
         <translation>Akquisition läuft</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Verification running</source>
         <translation>Verifikation läuft</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Device disconnected, acquisition paused</source>
         <translation>Gerät abgeschaltet, Akquisition unterbrochen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Device disconnected, verification paused</source>
         <translation>Gerät abgeschaltet, Verifikation unterbrochen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Finished - Verified & ok</source>
         <translation>Fertig - Verifiziert & ok</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Finished - Verification failed</source>
         <translation>Fertig- Verifizierung fehlgeschlagen</translation>
     </message>
+    <message>
+        <source>Aborted - Image file verify error</source>
+        <translation>Abgebrochen - Fehler bei Verifizierung</translation>
+    </message>
+    <message>
+        <source>Unknown</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>k.A.</translation>
+    </message>
+    <message>
+        <source>No</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>Nein</translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>Ja</translation>
+    </message>
+    <message>
+        <source>Rescan devices and update table</source>
+        <translation>Geräte neu einlesen und Tabelle auffrischen</translation>
+    </message>
+    <message>
+        <source>Add special device</source>
+        <comment>Menu entry</comment>
+        <translation>Sondergerät hinzufügen</translation>
+    </message>
+    <message>
+        <source>Open File</source>
+        <translation>Datei öffnen</translation>
+    </message>
+    <message>
+        <source>Invalid device</source>
+        <comment>Dialog title</comment>
+        <translation>Ungültiges Gerät</translation>
+    </message>
+    <message>
+        <source>Manually added special device</source>
+        <translation>Manuell hinzugefügtes Sondergerät</translation>
+    </message>
+    <message>
+        <source>Device alrady contained</source>
+        <comment>Dialog title</comment>
+        <translation>Gerät bereits vorhanden</translation>
+    </message>
+    <message>
+        <source>The selected file or device already is contained in the table.</source>
+        <translation>Das Gerät bzw. die Datei ist bereits in der Tabelle enthalten.</translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because its size is unknown.</source>
+        <translation>Das Gerät bzw. die Datei kann nicht ausgewählt werden da seine Grösse unbekannt ist.</translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because it contains 0 bytes.</source>
+        <translation>Das Gerät bzw. die Datei kann nicht ausgewählt werden da seine Grösse 0 Byte beträgt.</translation>
+    </message>
+    <message>
+        <source>Used in clone operation</source>
+        <translation>Belegt durch Klon-Operation</translation>
+    </message>
+    <message>
+        <source>Aborting...</source>
+        <translation>Abbruch angefragt...</translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
     <message>
-        <location filename="" line="136084940"/>
         <source>Local Device - cannot be acquired</source>
         <translation>Lokales Gerät - kann nicht akquiriert werden</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Acquire</source>
-        <comment>Context menu</comment>
-        <translation>Akquisition starten</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
-        <source>Abort acquisition</source>
-        <comment>Context menu</comment>
-        <translation>Akquisition abbrechen</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Info</source>
         <comment>Context menu</comment>
         <translation>Info</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Device info</source>
         <comment>Dialog title</comment>
         <translation>Geräte-Informationen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>GUYMAGER ACQUISITION INFO FILE</source>
         <comment>Info file</comment>
         <translation>GUYMAGER INFO-DATEI ZUR AKQUISITION</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Guymager</source>
         <comment>Info file</comment>
         <translation>Guymager</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Device information</source>
         <comment>Info file</comment>
         <translation>Geräte-Informationen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Image</source>
-        <comment>Info file</comment>
-        <translation>Image</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Finished successfully</source>
         <comment>Info file</comment>
         <translation>Erfolgreich beendet</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>(with %1 bad sectors)</source>
         <comment>Info file, may be appended to 'finished successfully' message</comment>
         <translation>(mit %1 defekten Sektoren)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted by user</source>
         <comment>Info file</comment>
         <translation>Abbruch durch Benutzer</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted because of image write error</source>
         <comment>Info file</comment>
         <translation>Abbruch wegen Fehler beim Schreiben der Image-Datei</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Aborted, strange reason (%1)</source>
         <comment>Info file</comment>
         <translation>Abbruch, unbekannter Grund (%1)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Strange state (%1)</source>
         <comment>Info file</comment>
         <translation>Unbekannter Zustand (%1)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>State: %1</source>
         <comment>Info file</comment>
         <translation>Status: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>During verification, %1 bad sectors have been encountered. The sector numbers are:</source>
         <comment>Info file</comment>
         <translation>Während der MD5-Verifizierung wurden %1 defekte Sektoren festgestellt. Die Sektor-Nummern sind:</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>During acquisition, %1 bad sectors have been encountered. They have been replaced by zeroed sectors. The sector numbers are:</source>
         <comment>Info file</comment>
         <translation>Während der Akquisition wurden %1 defekte Sektoren festgestellt. Die Sektor-Nummern sind:</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>No bad sectors encountered during verification.</source>
         <comment>Info file</comment>
         <translation>Bei der Verifizierung wurden keine defekte Sektoren entdeckt.</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>No bad sectors encountered during acquisition.</source>
         <comment>Info file</comment>
         <translation>Bei der Akquisition wurden keine defekte Sektoren entdeckt.</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>(during acquisition)</source>
         <comment>Info file</comment>
         <translation>(während der Akquisition)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>(ISO format YYYY-MM-DD HH:MM:SS)</source>
         <translation>(ISO-Format JJJJ-MM-TT SS:MM:ss)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Acquisition aborted before start of verification</source>
         <translation>Akquisition vor Beginn der MD5-Verifizierung abgebrochen</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Linux device:: %1</source>
         <comment>Info file</comment>
         <translation>Linux-Gerät:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Device size:: %1 (%2)</source>
         <comment>Info file</comment>
         <translation>Grösse:: %1 (%2)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Image format:: %1 - file extension is %2</source>
-        <comment>Info file</comment>
-        <translation>Image-Format:: %1 - mit Datei-Endung %2</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Acquisition started:: %1</source>
         <comment>Info file</comment>
         <translation>Beginn Akquisition:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Verification started:: %1</source>
         <comment>Info file</comment>
         <translation>Beginn MD5-Verifikation:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Ended:: %1 (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Ende:: %1 (%2 Stunden, %3 Minuten und %4 Sekunden)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Acquisition speed:: %1 MByte/s (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Geschwindigkeit Akquisition:: %1 MByte/s (%2 Stunden, %3 Minuten und %4 Sekunden)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>--</source>
         <comment>Info file</comment>
         <translation>--</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>MD5 hash:: %1</source>
         <comment>Info file</comment>
         <translation>MD5-Hash:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>MD5 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation>MD5-Hash verifiziert:: %1</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Version:: %1</source>
         <comment>Info file</comment>
         <translation>Version:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Compilation timestamp:: %1</source>
         <comment>Info file</comment>
         <translation>Zeitstempel der Kompilation:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Compiled with:: %1 %2</source>
         <comment>Info file</comment>
         <translation>Kompiliert mit:: %1 %2</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>libewf version:: %1</source>
         <comment>Info file</comment>
         <translation>Version libewf:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>libguytools version:: %1</source>
         <comment>Info file</comment>
         <translation>Version libguytools:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Verification speed:: %1 MByte/s (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Geschwindigkeit MD5-Verifizierung:: %1 MByte/s (%2 Stunden, %3 Minuten und %4 Sekunden)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>Image path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation>Image-Pfad und Datei:: %1 %2</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
-        <source>Info  path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation>Info-Pfad und Datei:: %1 %2</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Hash calculation:: off</source>
         <comment>Info file</comment>
         <translation>Hash-Berechnung:: aus</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Source verification:: on</source>
         <comment>Info file</comment>
         <translation>Verifikation Quellmedium:: ein</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Source verification:: off</source>
         <comment>Info file</comment>
         <translation>Verifikation Quellmedium:: aus</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>(during source verification)</source>
         <comment>Info file</comment>
         <translation>(während der Verifikation des Quellmediums)</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>SHA256 hash:: %1</source>
         <comment>Info file</comment>
         <translation>SHA256-Hash:: %1</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>SHA256 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation>SHA256-Hash verifiziert:: %1</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
-        <source>The hash values are identical. The device delivered the same data during acquisition and verification.</source>
-        <translation>Die Hash-Werte sind identisch. Das Gerät lieferte die gleichen Daten während der Akquisition und der Verifikation.</translation>
-    </message>
-    <message>
-        <location filename="" line="136084940"/>
         <source>Hash calculation:: MD5 and SHA-256</source>
         <comment>Info file</comment>
         <translation>Hash-Berechnung:: MD5 und SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Hash calculation:: MD5</source>
         <comment>Info file</comment>
         <translation>Hash-Berechnung:: MD5</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
         <source>Hash calculation:: SHA-256</source>
         <comment>Info file</comment>
         <translation>Hash-Berechnung:: SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="136084940"/>
-        <source>The hash values differ. The device didn't deliver the same data during acquisition and verification. Maybe you try to acquire the device again. Check as well if the defect sector list was the same during acquisition and verification (see above).</source>
-        <translation>Die Hash-Werte sind verschieden. Das Gerät lieferte unterschiedliche Daten während der Akquisition und der Verifikation. Versuchen Sie ev. eine weitere Akquisition. Überprüfen Sie, ob die Liste der defekten Sektoren für Akquisition und Verifikation gleich ist (siehe oben).</translation>
+        <source>Image path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation>Image-Pfad und Datei:: %1</translation>
+    </message>
+    <message>
+        <source>Info  path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation>Info -Pfad und Datei:: %1</translation>
+    </message>
+    <message>
+        <source>Image verification:: on</source>
+        <comment>Info file</comment>
+        <translation>Verifikation Image-Datei:: ein</translation>
+    </message>
+    <message>
+        <source>Image verification:: off</source>
+        <comment>Info file</comment>
+        <translation>Verifikation Image-Datei:: aus</translation>
+    </message>
+    <message>
+        <source>Aborted because of image read error during verification</source>
+        <comment>Info file</comment>
+        <translation>Abbruch wegen Image-Lesefehler während der Verifizierung</translation>
+    </message>
+    <message>
+        <source>MD5 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation>MD5-Hash Quellmedium verifiziert:: %1</translation>
+    </message>
+    <message>
+        <source>MD5 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation>MD5-Hash Image verifiziert:: %1</translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation>SHA256-Hash Quellmedium verifiziert:: %1</translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation>SHA256-Hash Image verifiziert:: %1</translation>
+    </message>
+    <message>
+        <source>Source verification OK. The device delivered the same data during acquisition and verification.</source>
+        <translation>Verifizierung Quellmedium in Ordnung. Das Gerät lieferte die gleichen Daten während der Akquisition und der Verifikation.</translation>
+    </message>
+    <message>
+        <source>Source verification FAILED. The device didn't deliver the same data during acquisition and verification. Check if the defect sector list was the same during acquisition and verification (see above).</source>
+        <translation>Verifizierung Quellmedium schlug fehl. Das Gerät lieferte unterschiedliche Daten während der Akquisition und der Verifikation. Versuchen Sie ev. eine weitere Akquisition. Überprüfen Sie, ob die Liste der defekten Sektoren für Akquisition und Verifikation gleich ist (siehe oben).</translation>
+    </message>
+    <message>
+        <source>Image verification OK. The image contains exactely the data that was written.</source>
+        <translation>Verifizierung Image in Ordnung. Das Image enhält genau die Daten, die bei der Akquisition geschrieben wurden.</translation>
+    </message>
+    <message>
+        <source>Image verification FAILED. The data in the image is different from what was written.</source>
+        <translation>Verifizierung Image schlug fehl: Die Daten im Image sind andere als die, die bei der Akquisition geschrieben wurden.</translation>
+    </message>
+    <message>
+        <source>Maybe you try to acquire the device again.</source>
+        <translation>Versuchen Sie eine erneute Akquisition.</translation>
+    </message>
+    <message>
+        <source>Remove special device</source>
+        <comment>Context menu</comment>
+        <translation>Sondergerät entfernen</translation>
+    </message>
+    <message>
+        <source>Image meta data</source>
+        <comment>Info file</comment>
+        <translation>Image Meta-Daten </translation>
+    </message>
+    <message>
+        <source> - file extension is %1</source>
+        <comment>Info file</comment>
+        <translation> - mit Datei-Endung %1</translation>
+    </message>
+    <message>
+        <source>Acquire image</source>
+        <comment>Context menu</comment>
+        <translation>Image-Datei erstellen</translation>
+    </message>
+    <message>
+        <source>Clone device</source>
+        <comment>Context menu</comment>
+        <translation>Gerät klonen</translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <comment>Context menu</comment>
+        <translation>Abbrechen</translation>
+    </message>
+    <message>
+        <source>Acquisition</source>
+        <comment>Info file</comment>
+        <translation>Akquisition</translation>
+    </message>
+    <message>
+        <source>Format:: %1</source>
+        <comment>Info file</comment>
+        <translation>Format:: %1</translation>
+    </message>
+    <message>
+        <source>Device used for cloning - cannot be acquired</source>
+        <translation>Gerät durch Klon-Operation belegt - kann nicht akquiriert werden</translation>
+    </message>
+</context>
+<context>
+    <name>t_ThreadScan</name>
+    <message>
+        <source>Cannot scan devices</source>
+        <comment>Dialog title</comment>
+        <translation>Geräteabfrage funktioniert nicht</translation>
+    </message>
+    <message>
+        <source>None of the device scan methods worked. Exiting now.</source>
+        <translation>Keine der Methoden zum Abfragen der angeschlossenen Geräte funktionierte. Guymager wird nun beendet.</translation>
     </message>
 </context>
 </TS>
diff --git a/guymager_en.ts b/guymager_en.ts
index 6c0e066..111eceb 100644
--- a/guymager_en.ts
+++ b/guymager_en.ts
@@ -36,73 +36,95 @@ Continue anyway?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>%1 not accessible</source>
-        <comment>Dialog title</comment>
+        <source>Guymager cannot scan the devices connected to this computer.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Try method "%1"</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Guymager is configured to use %1 for scanning the connected devices, but this did not work. Alternatively, you may use %2. Do you want to switch to %2?</source>
+        <source>Creation of a clone</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>t_DeviceListModel</name>
     <message>
+        <source>Linux
+device</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Model</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source>Serial
 nr.</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Linux
-device</source>
-        <comment>Column on main screen</comment>
+        <source>Size</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Model</source>
-        <comment>Column on main screen</comment>
+        <source>Remarks</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Size</source>
-        <comment>Column on main screen</comment>
+        <source>State</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hidden
+Areas</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Bad
 sectors</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Progress</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Average
 Speed
 [MB/s]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Time
 remaining</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>FIFO queues
 usage
 [%]</source>
-        <comment>Column on main screen</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>State</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -141,10 +163,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash computation</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>The filenames contain special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>Image filename: %1
 <byte value="x9"/>Info filename: %2
@@ -172,10 +190,6 @@ Do you accept these changes?</source>
         <translation>Notes</translation>
     </message>
     <message>
-        <source>DestDirectory</source>
-        <translation>Directory</translation>
-    </message>
-    <message>
         <source>DestImageFilename</source>
         <translation>Image filename (without extension)</translation>
     </message>
@@ -211,40 +225,83 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Acquisition parameters for %1</source>
-        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <source>Access denied</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HashCalcMD5</source>
+        <translation>Calculate MD5</translation>
+    </message>
+    <message>
+        <source>HashCalcSHA256</source>
+        <translation>Calculate SHA-256</translation>
+    </message>
+    <message>
+        <source>HashVerifySrc</source>
+        <translation>Re-read source after acquisition for verification (takes twice as long)</translation>
+    </message>
+    <message>
+        <source>HashVerifyDst</source>
+        <translation>Verify image after acquisition (takes twice as long)</translation>
+    </message>
+    <message>
+        <source>Hash calculation / verification</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Re-read source after acquisition for verification (takes twice as long)</source>
+        <source>Guymager cannot write to the directory
+<byte value="x9"/>%1
+This may be due to insufficient access rights or unsupported filename characters. Please choose another directory.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Images files exist</source>
-        <comment>Dialog title</comment>
+        <source>Local device, cannot be written</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The image files already exist. Do you want to overwrite them?</source>
+        <source>Too small</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Access denied</source>
-        <comment>Dialog title</comment>
+        <source>In use</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Guymager cannot write to the directory
+        <source>Ok for cloning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>%1
-This may be due to insufficient access rights. Please choose another directory.</source>
+Do you accept these changes?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Files exist</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The image or info files already exist. Do you want to overwrite them?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clone %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate MD5</source>
+        <source>Acquire image of %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device to be cloned</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate SHA-256</source>
+        <source>Used in another clone operation</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -326,16 +383,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>on</source>
-        <comment>Display that source verification is on</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>off</source>
-        <comment>Display that source verification is off</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
         <translation type="unfinished"></translation>
@@ -358,6 +405,20 @@ This may be due to insufficient access rights. Please choose another directory.<
         <comment>Hash calculation is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Image verification</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>on</source>
+        <comment>Display that verification is on</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>off</source>
+        <comment>Display that verification is off</comment>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -402,10 +463,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Rescan devices and update list</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>There are active acquisitions. Do you really want to abort them and quit?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -491,21 +548,77 @@ Using libguytools %5</source>
         <source>Finished - Verification failed</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>t_Table</name>
     <message>
-        <source>Local Device - cannot be acquired</source>
+        <source>Aborted - Image file verify error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Acquire</source>
-        <comment>Context menu</comment>
+        <source>Unknown</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Abort acquisition</source>
-        <comment>Context menu</comment>
+        <source>No</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rescan devices and update table</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add special device</source>
+        <comment>Menu entry</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Invalid device</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manually added special device</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device alrady contained</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The selected file or device already is contained in the table.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because its size is unknown.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because it contains 0 bytes.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Used in clone operation</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>t_Table</name>
+    <message>
+        <source>Local Device - cannot be acquired</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
@@ -534,11 +647,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Finished successfully</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -617,11 +725,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image format:: %1 - file extension is %2</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Acquisition started:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -652,11 +755,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>MD5 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Version:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -687,66 +785,164 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image path and file name:: %1 %2</source>
+        <source>Hash calculation:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Info  path and file name:: %1 %2</source>
+        <source>Source verification:: on</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: off</source>
+        <source>Source verification:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Source verification:: on</source>
+        <source>(during source verification)</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Source verification:: off</source>
+        <source>SHA256 hash:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>(during source verification)</source>
+        <source>Hash calculation:: MD5 and SHA-256</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>SHA256 hash:: %1</source>
+        <source>Hash calculation:: MD5</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hash calculation:: SHA-256</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>SHA256 hash verified:: %1</source>
+        <source>Image path and file name:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The hash values are identical. The device delivered the same data during acquisition and verification.</source>
+        <source>Info  path and file name:: %1</source>
+        <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: MD5 and SHA-256</source>
+        <source>Image verification:: on</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: MD5</source>
+        <source>Image verification:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: SHA-256</source>
+        <source>Aborted because of image read error during verification</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified image:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The hash values differ. The device didn't deliver the same data during acquisition and verification. Maybe you try to acquire the device again. Check as well if the defect sector list was the same during acquisition and verification (see above).</source>
+        <source>SHA256 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification OK. The device delivered the same data during acquisition and verification.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification FAILED. The device didn't deliver the same data during acquisition and verification. Check if the defect sector list was the same during acquisition and verification (see above).</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification OK. The image contains exactely the data that was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification FAILED. The data in the image is different from what was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Maybe you try to acquire the device again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove special device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image meta data</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source> - file extension is %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquire image</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clone device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquisition</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Format:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device used for cloning - cannot be acquired</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>t_ThreadScan</name>
+    <message>
+        <source>Cannot scan devices</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>None of the device scan methods worked. Exiting now.</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
diff --git a/guymager_fr.ts b/guymager_fr.ts
index e3fcad2..d098616 100644
--- a/guymager_fr.ts
+++ b/guymager_fr.ts
@@ -3,159 +3,187 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Ok</source>
         <translation>Ok</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Cancel</source>
         <translation>Annuler</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Linux dd raw image</source>
         <translation>Image brute Linux dd </translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Expert Witness Format, sub-format %1</source>
         <translation>Format EWF, sous-format %1 </translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Missing root rights</source>
         <comment>Dialog title</comment>
         <translation>Droits «root»</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Guymager needs to be started with root rights in order to perform acquisitions. You are not root and thus won't be able to acquire devices.
 Continue anyway?</source>
         <translation>Guymager doit être lancé comme «root» pour pouvoir effectuer des acquisitions.
 Continuer quand-même?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Deleting %1</source>
         <translation>Efface %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Advanced forensic image</source>
         <translation>Format AFF</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>%1 not accessible</source>
-        <comment>Dialog title</comment>
-        <translation>%1 non-accessible</translation>
+        <location filename="" line="137886436"/>
+        <source>Guymager cannot scan the devices connected to this computer.</source>
+        <translation>Guymager ne peut déterminer les médias connectés.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
+        <translation>La méthode de recherche de médias sélectionnée ("%1") n'est pas accessible. Voulez vous en essayer une autre?</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Abort</source>
+        <translation>Terminer</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Try method "%1"</source>
+        <translation>Essayer la méthode "%1"</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Guymager is configured to use %1 for scanning the connected devices, but this did not work. Alternatively, you may use %2. Do you want to switch to %2?</source>
-        <translation>La configuration de Guymager prévoit l'utilisation de %1 pour la recherche des médias. Comme %1 n'est pas accessible sur ce système, vous pouvez utiliser %2 comme alternative. Voulez vous changer sur %2?</translation>
+        <location filename="" line="137886436"/>
+        <source>Creation of a clone</source>
+        <translation>Création d'un clone</translation>
     </message>
 </context>
 <context>
     <name>t_DeviceListModel</name>
     <message>
-        <location filename="" line="0"/>
-        <source>Serial
-nr.</source>
-        <comment>Column on main screen</comment>
-        <translation>Nº de
-série</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Linux
 device</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Média
 Linux</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Model</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Modèle</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
+        <source>Serial
+nr.</source>
+        <comment>Column of device table</comment>
+        <translation>Nº de
+série</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
         <source>Size</source>
-        <comment>Column on main screen</comment>
-        <translation>Capa-
+        <comment>Column of device table</comment>
+        <translation type="unfinished">Capa-
 cité</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
+        <source>Remarks</source>
+        <comment>Column of device table</comment>
+        <translation>Remarques</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>State</source>
+        <comment>Column of device table</comment>
+        <translation>Etat</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Hidden
+Areas</source>
+        <comment>Column of device table</comment>
+        <translation>Espaces
+cachés</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
         <source>Bad
 sectors</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Mauvais
 secteurs</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Progress</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Progrès</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Average
 Speed
 [MB/s]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Vitesse
 moyenne
 [MB/s]</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Time
 remaining</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Temps
 restant</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>FIFO queues
 usage
 [%]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation>Utilisation
 des FIFOs
 [%]</translation>
     </message>
-    <message>
-        <location filename="" line="0"/>
-        <source>State</source>
-        <comment>Column on main screen</comment>
-        <translation>Etat</translation>
-    </message>
 </context>
 <context>
     <name>t_DlgAbort</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Do you want to abort the acquisition of %1?</source>
         <translation>Voulez vous abandonner l'acquisition de %1?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Delete partial image files</source>
         <translation>Effacer les images partiellement écrits?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Do you want to abort the verification of %1?</source>
         <translation>Voulez vous abandonner la vérification de %1?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Abort?</source>
         <comment>Dialog title</comment>
         <translation>Abandonner?</translation>
@@ -164,84 +192,74 @@ des FIFOs
 <context>
     <name>t_DlgAcquire</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>EwfCaseNumber</source>
         <translation>Numéro d'affaire</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>EwfEvidenceNumber</source>
         <translation>No. de pièce</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>EwfExaminer</source>
         <translation>Examinateur</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>EwfDescription</source>
         <translation>Description</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>EwfNotes</source>
         <translation>Notes</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>DestDirectory</source>
-        <translation>Répertoire</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>DestImageFilename</source>
         <translation>Nom du fichier image</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>DestInfoFilename</source>
         <translation>Nom du fichier info</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>File format</source>
         <translation>Format fichier</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>(file extension %1)</source>
         <translation>(extension %1)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Destination</source>
         <translation>Destination</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Configuration flag WriteToDevNull is set!</source>
         <translation>Paramètre de configuration WriteToDevNull activé!</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Hash computation</source>
-        <translation>Calculation de valeurs «hash»</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation>Sélectionner le répertoire de destination</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Special characters</source>
         <comment>Dialog title</comment>
         <translation>Charactères spéciaux</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>The filenames contain special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>Image filename: %1
 <byte value="x9"/>Info filename: %2
@@ -252,89 +270,142 @@ Do you accept these changes?</source>
 Acceptez-vous ces changement?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>DestImageDirectory</source>
         <translation>Répertoire image</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>DestInfoDirectory</source>
         <translation>Répertoire info</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>...</source>
         <comment>The directory browse button</comment>
         <translation>...</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Acquisition parameters for %1</source>
-        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
-        <translation>Paramètres d'acquisition pour %1</translation>
+        <location filename="" line="137886436"/>
+        <source>Access denied</source>
+        <comment>Dialog title</comment>
+        <translation>Accès refusé</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Re-read source after acquisition for verification (takes twice as long)</source>
-        <translation>Relire média après acquisition pour verification (prend le double du temps)</translation>
+        <location filename="" line="137886436"/>
+        <source>HashCalcMD5</source>
+        <translation>Calculer MD5</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Images files exist</source>
-        <comment>Dialog title</comment>
-        <translation>Fichier image existe</translation>
+        <location filename="" line="137886436"/>
+        <source>HashCalcSHA256</source>
+        <translation>Calculer SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>The image files already exist. Do you want to overwrite them?</source>
-        <translation>Des fichiers image de ce nom existent déjà. Voulez vous les réécrire?</translation>
+        <location filename="" line="137886436"/>
+        <source>HashVerifySrc</source>
+        <translation>Vérifier (relire) le média source après acquisition (prend le double de temps)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Access denied</source>
-        <comment>Dialog title</comment>
-        <translation>Accès refusé</translation>
+        <location filename="" line="137886436"/>
+        <source>HashVerifyDst</source>
+        <translation>Vérifier l'image après l'acquisition (prend le double de temps)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
+        <source>Hash calculation / verification</source>
+        <translation>Calcul / vérification de valuers hash</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
         <source>Guymager cannot write to the directory
 <byte value="x9"/>%1
-This may be due to insufficient access rights. Please choose another directory.</source>
+This may be due to insufficient access rights or unsupported filename characters. Please choose another directory.</source>
         <translation>Guymager n'a pu écrire dans le répertoire
+<byte value="x9"/>%1,
+possiblement à cause de droits d'accès insuffisants. Veuillez choisir un autre répertoire.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Local device, cannot be written</source>
+        <translation>Média local - ne peut être modifié</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Too small</source>
+        <translation>Trop petit</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>In use</source>
+        <translation>Occupé</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Ok for cloning</source>
+        <translation>Bon pour clonage</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
 <byte value="x9"/>%1
-,possiblement à cause de droits d'accès insuffisants. Veuillez choisir un autre répertoire.</translation>
+Do you accept these changes?</source>
+        <translation>Les noms du fichier info contient des charactères spéciaux qui ne peuvent être utilisés. Guymager vous propose de modifier le nom comme suit:<byte value="x9"/>%2Acceptez-vous ces changement?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Calculate MD5</source>
-        <translation>Calculer MD5</translation>
+        <location filename="" line="137886436"/>
+        <source>Files exist</source>
+        <comment>Dialog title</comment>
+        <translation>Fichier existe</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Calculate SHA-256</source>
-        <translation>Calculer SHA-256</translation>
+        <location filename="" line="137886436"/>
+        <source>The image or info files already exist. Do you want to overwrite them?</source>
+        <translation>Les fichiers image ou info de ce nom existent déjà. Voulez vous les réécrire?</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Clone %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation>Cloner %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Acquire image of %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation>Acquérir image de %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Device to be cloned</source>
+        <translation>Média à cloner</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Used in another clone operation</source>
+        <translation>Occupé par un autre clonage</translation>
     </message>
 </context>
 <context>
     <name>t_DlgDirSel</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation>Sélectionner le répertoire de destination</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>New directory</source>
         <translation>Nouveau répertoire</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Remove directory</source>
         <translation>Effacer répertoire</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>NewDirectory</source>
         <comment>Name of the new directory that will be created</comment>
         <translation>Nom du nouveau répertoire à créer</translation>
@@ -343,7 +414,7 @@ This may be due to insufficient access rights. Please choose another directory.<
 <context>
     <name>t_DlgMessage</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Close</source>
         <translation>Fermer</translation>
     </message>
@@ -351,17 +422,17 @@ This may be due to insufficient access rights. Please choose another directory.<
 <context>
     <name>t_Info</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Command executed: %1</source>
         <translation>Commande  exécutée: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>No information can be displayed as a timeout occured while executing the command.</source>
         <translation>Aucune information n'est disponible suite au dépassement du temps d'exécution maximal.</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Information returned:</source>
         <translation>Information retournée:</translation>
     </message>
@@ -369,202 +440,202 @@ This may be due to insufficient access rights. Please choose another directory.<
 <context>
     <name>t_InfoField</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Size</source>
         <translation>Capacité</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Sector size</source>
         <translation>Capacité secteur</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Image file</source>
         <translation>Nom du fichier image</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Info file</source>
         <translation>Nom du fichier info</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Current speed</source>
         <translation>Vitesse actuelle</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>bytes</source>
         <translation>octets</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Hash calculation</source>
         <translation>Calculer valeurs «hash»</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Source verification</source>
         <translation>Relire et vérifier media</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>on</source>
-        <comment>Display that source verification is on</comment>
-        <translation>oui</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
-        <source>off</source>
-        <comment>Display that source verification is off</comment>
-        <translation>non</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
         <translation>Démarré</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>MD5 and SHA-256</source>
         <comment>Both hashes are calculated</comment>
         <translation>MD5 et SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>MD5</source>
         <translation>MD5</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>SHA-256</source>
         <translation>SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>off</source>
         <comment>Hash calculation is off</comment>
         <translation>non</translation>
     </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image verification</source>
+        <translation>Vérification image</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>on</source>
+        <comment>Display that verification is on</comment>
+        <translation>oui</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>off</source>
+        <comment>Display that verification is off</comment>
+        <translation>non</translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Local device</source>
         <translation>Média local</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Idle</source>
         <translation>Libre</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Cleanup</source>
         <translation>Nettoyage</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Finished</source>
         <translation>Fini</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted - Error: Reason is 'none'</source>
         <translation>Abandon - raison «none»</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted by user</source>
         <translation>Abandonné par l'utilisateur</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted - Image file write error</source>
         <translation>Abandon - erreur d'écriture</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted - Device read error</source>
         <translation>Abandon - erreur grave de lecture </translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>&Rescan</source>
         <translation>&Actualiser</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>F5</source>
         <translation>F5</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Rescan devices and update list</source>
-        <translation>Actualiser la liste des médias connectés</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>&Devices</source>
         <translation>&Médias</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>&Misc</source>
         <comment>Menu entry</comment>
         <translation>&Divers</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Debug</source>
         <comment>Menu entry</comment>
         <translation>Debug</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>&Help</source>
         <comment>Menu entry</comment>
         <translation>&Aide</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>About &GUYMAGER</source>
         <comment>Menu entry</comment>
         <translation>A propos de &GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>About &Qt</source>
         <comment>Menu entry</comment>
         <translation>A propos de &Qt</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Exit GUYMAGER</source>
         <comment>Dialog title</comment>
         <translation>Quitter GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>There are active acquisitions. Do you really want to abort them and quit?</source>
         <translation>Il y a toujours des acquisitions en cours. Voulez-vous vraiment quitter le programme?</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Debug information</source>
         <translation>Information «debug»</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>About GUYMAGER</source>
         <comment>Dialog title</comment>
         <translation>A propos de GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>GUYMAGER is a Linux-based forensic imaging tool
 
 Version: %1
@@ -581,350 +652,519 @@ Utilise libewf %4
 Utilise libguytools %5</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>About Qt</source>
         <comment>Dialog title</comment>
         <translation>A propos de Qt</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Acquisition running</source>
         <translation>Acquisition en cours</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Verification running</source>
         <translation>Vérification en cours</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Device disconnected, acquisition paused</source>
         <translation>Média déconnecté, acquisition suspendue</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Device disconnected, verification paused</source>
         <translation>Média déconnecté, vérification suspendue</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Finished - Verified & ok</source>
         <translation>Fini - Vérification réussie</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Finished - Verification failed</source>
         <translation>Fini - Vérification échouée</translation>
     </message>
-</context>
-<context>
-    <name>t_Table</name>
     <message>
-        <location filename="" line="0"/>
-        <source>Acquire</source>
-        <comment>Context menu</comment>
-        <translation>Acquisition</translation>
+        <location filename="" line="137886436"/>
+        <source>Aborted - Image file verify error</source>
+        <translation>Abandon - erreur d'écriture</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Abort acquisition</source>
-        <comment>Context menu</comment>
-        <translation>Abandon de l'acquisition</translation>
+        <location filename="" line="137886436"/>
+        <source>Unknown</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>Inconnu</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>No</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>Non</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Yes</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation>Oui</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Rescan devices and update table</source>
+        <translation>Actualiser la liste des médias connectés</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Add special device</source>
+        <comment>Menu entry</comment>
+        <translation>Ajouter média spécial</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Open File</source>
+        <translation>Ouvrir fichier</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
+        <source>Invalid device</source>
+        <comment>Dialog title</comment>
+        <translation>Média non-utilisable</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Manually added special device</source>
+        <translation>Média spécial ajouté manuellement</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Device alrady contained</source>
+        <comment>Dialog title</comment>
+        <translation>Média déjà existant</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>The selected file or device already is contained in the table.</source>
+        <translation>Le fichier ou média sélectionné figure déja dans la liste.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>The device or file cannot be selected because its size is unknown.</source>
+        <translation>Le fichier ou média ne peut être sélectionné parce que sa taille est inconnu.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>The device or file cannot be selected because it contains 0 bytes.</source>
+        <translation>Le fichier ou média ne peut être sélectionné parce que sa taille est de 0 octets.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Used in clone operation</source>
+        <translation>Occupé par clonage</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Aborting...</source>
+        <translation>Abandon en cours...</translation>
+    </message>
+</context>
+<context>
+    <name>t_Table</name>
+    <message>
+        <location filename="" line="137886436"/>
         <source>Info</source>
         <comment>Context menu</comment>
         <translation>Info</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Local Device - cannot be acquired</source>
         <translation>Média local - ne peut être acquéré</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Device info</source>
         <comment>Dialog title</comment>
         <translation>Info média</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>GUYMAGER ACQUISITION INFO FILE</source>
         <comment>Info file</comment>
         <translation>FICHIER D'INFORMATION POUR ACQUISITION GUYMAGER</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Guymager</source>
         <comment>Info file</comment>
         <translation>Guymager</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Device information</source>
         <comment>Info file</comment>
         <translation>Information média</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Image</source>
-        <comment>Info file</comment>
-        <translation>Image</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Finished successfully</source>
         <comment>Info file</comment>
         <translation>Fini avec succées</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>(with %1 bad sectors)</source>
         <comment>Info file, may be appended to 'finished successfully' message</comment>
         <translation>(avec %1 mauvais secteurs)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted by user</source>
         <comment>Info file</comment>
         <translation>Abandonné par l'utilisateur</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted because of image write error</source>
         <comment>Info file</comment>
         <translation>Abandonné à cause d'une erreur d'écriture</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Aborted, strange reason (%1)</source>
         <comment>Info file</comment>
         <translation>Abandonné pour une raison inconnue (%1)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Strange state (%1)</source>
         <comment>Info file</comment>
         <translation>Etat inconnu (%1)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>State: %1</source>
         <comment>Info file</comment>
         <translation>Etat: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>During verification, %1 bad sectors have been encountered. The sector numbers are:</source>
         <comment>Info file</comment>
         <translation>Pendant la vérification, %1 mauvais secteurs ont été rencontrés. Leurs numéros sont les suivants:</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>During acquisition, %1 bad sectors have been encountered. They have been replaced by zeroed sectors. The sector numbers are:</source>
         <comment>Info file</comment>
         <translation>Pendant l'acquisition, %1 mauvais secteurs ont été rencontrés. Leurs numéros sont les suivants:</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>No bad sectors encountered during verification.</source>
         <comment>Info file</comment>
         <translation>Aucun mauvais secteur n'a été renconté pendant la vérification.</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>No bad sectors encountered during acquisition.</source>
         <comment>Info file</comment>
         <translation>Aucun mauvais secteur n'a été renconté pendant l'acquisition.</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>(during acquisition)</source>
         <comment>Info file</comment>
         <translation>(pendant l'acquisition)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>(ISO format YYYY-MM-DD HH:MM:SS)</source>
         <translation>(format ISO AAAA-MM-JJ HH:MM:SS)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Acquisition aborted before start of verification</source>
         <translation>Acquisition abandonnée avant de commencer vérification</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Linux device:: %1</source>
         <comment>Info file</comment>
         <translation>Média Linux:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Device size:: %1 (%2)</source>
         <comment>Info file</comment>
         <translation>Capacité:: %1 (%2)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Image format:: %1 - file extension is %2</source>
-        <comment>Info file</comment>
-        <translation>Format de l'image:: %1 - l'extension fichier est %2</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Acquisition started:: %1</source>
         <comment>Info file</comment>
         <translation>Début de l'acquisition:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Verification started:: %1</source>
         <comment>Info file</comment>
         <translation>Début de la vérification:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Ended:: %1 (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Fin:: %1 (%2 heures, %3 minutes et %4 secondes)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Acquisition speed:: %1 MByte/s (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Vitesse de l'acquisition:: %1 MByte/s (%2 heures, %3 minutes et %4 secondes)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>--</source>
         <comment>Info file</comment>
         <translation>--</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>MD5 hash:: %1</source>
         <comment>Info file</comment>
         <translation>Hash MD5:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>MD5 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation>Hash MD5 vérifié:: %1</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Version:: %1</source>
         <comment>Info file</comment>
         <translation>Version:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Compilation timestamp:: %1</source>
         <comment>Info file</comment>
         <translation>Date et heure de compilation:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Compiled with:: %1 %2</source>
         <comment>Info file</comment>
         <translation>Compilé avec gcc:: %1 %2</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>libewf version:: %1</source>
         <comment>Info file</comment>
         <translation>Version:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>libguytools version:: %1</source>
         <comment>Info file</comment>
         <translation>Version libguytools:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Verification speed:: %1 MByte/s (%2 hours, %3 minutes and %4 seconds)</source>
         <comment>Info file</comment>
         <translation>Vitesse de la vérification:: %1 MByte/s (%2 heures, %3 minutes et %4 secondes)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>Image path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation>Répertoire et fichier image:: %1 %2</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
-        <source>Info  path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation>Répertoire et fichier info:: %1 %2</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Hash calculation:: off</source>
         <comment>Info file</comment>
         <translation>Calculer valeurs hash:: non</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Source verification:: on</source>
         <comment>Info file</comment>
         <translation>Relire et vérifier media:: oui</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Source verification:: off</source>
         <comment>Info file</comment>
         <translation>Relire et vérifier media:: non</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>(during source verification)</source>
         <comment>Info file</comment>
         <translation>(pendant la vérification)</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>SHA256 hash:: %1</source>
         <comment>Info file</comment>
         <translation>SHA256 hash:: %1</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>SHA256 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation>SHA256 hash vérifié:: %1</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
-        <source>The hash values are identical. The device delivered the same data during acquisition and verification.</source>
-        <translation>Les valeurs hash sont identiques. Le média fournissait les mêmes données pendant l'acquisition et la vérification.</translation>
-    </message>
-    <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Hash calculation:: MD5 and SHA-256</source>
         <comment>Info file</comment>
         <translation>Calculer valeurs hash:: MD5 et SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Hash calculation:: MD5</source>
         <comment>Info file</comment>
         <translation>Calculer valeurs hash:: MD5</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
+        <location filename="" line="137886436"/>
         <source>Hash calculation:: SHA-256</source>
         <comment>Info file</comment>
         <translation>Calculer valeurs hash:: SHA-256</translation>
     </message>
     <message>
-        <location filename="" line="0"/>
-        <source>The hash values differ. The device didn't deliver the same data during acquisition and verification. Maybe you try to acquire the device again. Check as well if the defect sector list was the same during acquisition and verification (see above).</source>
-        <translation>Les valeurs hash diffèrent. Le média ne fournissait pas les mêmes données pendant l'acquisition et la vérification. Vous aimeriez peut-être relancer l'acquisition. Veuillez aussi vérifier si la liste des mauvais secteurs est la même pour l'acquisition comme pour la vérification (voir en haut).</translation>
+        <location filename="" line="137886436"/>
+        <source>Image path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation>Répertoire et fichier image:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Info  path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation>Répertoire et fichier info:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image verification:: on</source>
+        <comment>Info file</comment>
+        <translation>Vérification image:: oui</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image verification:: off</source>
+        <comment>Info file</comment>
+        <translation>Vérification image:: non</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Aborted because of image read error during verification</source>
+        <comment>Info file</comment>
+        <translation></translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>MD5 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation>Hash MD5 source vérifié:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>MD5 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation>Hash MD5 image vérifié:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>SHA256 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation>Hash SHA256 source vérifié:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>SHA256 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation>Hash SHA256 image vérifié:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Source verification OK. The device delivered the same data during acquisition and verification.</source>
+        <translation>Vérification source réussie. Les valeurs hash sont identiques. Le média fournissait les mêmes données pendant l'acquisition et la vérification.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Source verification FAILED. The device didn't deliver the same data during acquisition and verification. Check if the defect sector list was the same during acquisition and verification (see above).</source>
+        <translation>Vérification source échouée. Les valeurs hash diffèrent. Le média ne fournissait pas les mêmes données pendant l'acquisition et la vérification. Vous aimeriez peut-être relancer l'acquisition. Veuillez aussi vérifier si la liste des mauvais secteurs est la même pour l'acquisition comme pour la vérification (voir en haut).</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image verification OK. The image contains exactely the data that was written.</source>
+        <translation>Vérification image réussie.  Le fichier image contient exactement les données qui ont été écrites lors de l'acquisition.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image verification FAILED. The data in the image is different from what was written.</source>
+        <translation>Vérification image échouée. le fichier image ne contient pas les données qui ont été écrites lors de l'acquisition.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Maybe you try to acquire the device again.</source>
+        <translation>Vous pouvez essayer une nouvelle acquisition du média.</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Remove special device</source>
+        <comment>Context menu</comment>
+        <translation>Effacer média spécial</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Image meta data</source>
+        <comment>Info file</comment>
+        <translation>Méta-données du fichier image</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source> - file extension is %1</source>
+        <comment>Info file</comment>
+        <translation> - l'extension fichier est %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Acquire image</source>
+        <comment>Context menu</comment>
+        <translation>Acquérir image</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Clone device</source>
+        <comment>Context menu</comment>
+        <translation>Créer clone</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Abort</source>
+        <comment>Context menu</comment>
+        <translation>Abandonner</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Acquisition</source>
+        <comment>Info file</comment>
+        <translation>Acquisition</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Format:: %1</source>
+        <comment>Info file</comment>
+        <translation>Format:: %1</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Device used for cloning - cannot be acquired</source>
+        <translation>Occupé par opération de clonage - ne peut être  acquéré</translation>
+    </message>
+</context>
+<context>
+    <name>t_ThreadScan</name>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>Cannot scan devices</source>
+        <comment>Dialog title</comment>
+        <translation>Recherche médias échouée</translation>
+    </message>
+    <message>
+        <location filename="" line="137886436"/>
+        <source>None of the device scan methods worked. Exiting now.</source>
+        <translation>Toutes les méthodes pour établir la liste médias ont échoués. Le programme sera terminé.</translation>
     </message>
 </context>
 </TS>
diff --git a/guymager_it.ts b/guymager_it.ts
index 2025b29..e9470e9 100644
--- a/guymager_it.ts
+++ b/guymager_it.ts
@@ -36,73 +36,95 @@ Continue anyway?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>%1 not accessible</source>
-        <comment>Dialog title</comment>
+        <source>Guymager cannot scan the devices connected to this computer.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Try method "%1"</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Guymager is configured to use %1 for scanning the connected devices, but this did not work. Alternatively, you may use %2. Do you want to switch to %2?</source>
+        <source>Creation of a clone</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>t_DeviceListModel</name>
     <message>
+        <source>Linux
+device</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Model</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source>Serial
 nr.</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Linux
-device</source>
-        <comment>Column on main screen</comment>
+        <source>Size</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Model</source>
-        <comment>Column on main screen</comment>
+        <source>Remarks</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Size</source>
-        <comment>Column on main screen</comment>
+        <source>State</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hidden
+Areas</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Bad
 sectors</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Progress</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Average
 Speed
 [MB/s]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Time
 remaining</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>FIFO queues
 usage
 [%]</source>
-        <comment>Column on main screen</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>State</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -149,10 +171,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>DestDirectory</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>DestImageFilename</source>
         <translation type="unfinished"></translation>
     </message>
@@ -177,10 +195,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash computation</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
@@ -211,40 +225,83 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Acquisition parameters for %1</source>
-        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <source>Access denied</source>
+        <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Re-read source after acquisition for verification (takes twice as long)</source>
+        <source>HashCalcMD5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Images files exist</source>
-        <comment>Dialog title</comment>
+        <source>HashCalcSHA256</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The image files already exist. Do you want to overwrite them?</source>
+        <source>HashVerifySrc</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Access denied</source>
-        <comment>Dialog title</comment>
+        <source>HashVerifyDst</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hash calculation / verification</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Guymager cannot write to the directory
 <byte value="x9"/>%1
-This may be due to insufficient access rights. Please choose another directory.</source>
+This may be due to insufficient access rights or unsupported filename characters. Please choose another directory.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Local device, cannot be written</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Too small</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>In use</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Ok for cloning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
+<byte value="x9"/>%1
+Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate MD5</source>
+        <source>Files exist</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The image or info files already exist. Do you want to overwrite them?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clone %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate SHA-256</source>
+        <source>Acquire image of %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device to be cloned</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Used in another clone operation</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -326,16 +383,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>on</source>
-        <comment>Display that source verification is on</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>off</source>
-        <comment>Display that source verification is off</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
         <translation type="unfinished"></translation>
@@ -358,6 +405,20 @@ This may be due to insufficient access rights. Please choose another directory.<
         <comment>Hash calculation is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Image verification</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>on</source>
+        <comment>Display that verification is on</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>off</source>
+        <comment>Display that verification is off</comment>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -402,10 +463,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Rescan devices and update list</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>&Devices</source>
         <translation type="unfinished"></translation>
     </message>
@@ -491,19 +548,75 @@ Using libguytools %5</source>
         <source>Finished - Verification failed</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>t_Table</name>
     <message>
-        <source>Acquire</source>
-        <comment>Context menu</comment>
+        <source>Aborted - Image file verify error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Abort acquisition</source>
-        <comment>Context menu</comment>
+        <source>Unknown</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rescan devices and update table</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add special device</source>
+        <comment>Menu entry</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Invalid device</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manually added special device</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device alrady contained</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The selected file or device already is contained in the table.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because its size is unknown.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because it contains 0 bytes.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Used in clone operation</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborting...</source>
         <translation type="unfinished"></translation>
     </message>
+</context>
+<context>
+    <name>t_Table</name>
     <message>
         <source>Info</source>
         <comment>Context menu</comment>
@@ -534,11 +647,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Finished successfully</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -617,11 +725,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image format:: %1 - file extension is %2</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Acquisition started:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -652,11 +755,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>MD5 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Version:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -687,66 +785,164 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image path and file name:: %1 %2</source>
+        <source>Hash calculation:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Info  path and file name:: %1 %2</source>
+        <source>Source verification:: on</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: off</source>
+        <source>Source verification:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Source verification:: on</source>
+        <source>(during source verification)</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Source verification:: off</source>
+        <source>SHA256 hash:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>(during source verification)</source>
+        <source>Hash calculation:: MD5 and SHA-256</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>SHA256 hash:: %1</source>
+        <source>Hash calculation:: MD5</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hash calculation:: SHA-256</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>SHA256 hash verified:: %1</source>
+        <source>Image path and file name:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The hash values are identical. The device delivered the same data during acquisition and verification.</source>
+        <source>Info  path and file name:: %1</source>
+        <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: MD5 and SHA-256</source>
+        <source>Image verification:: on</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: MD5</source>
+        <source>Image verification:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash calculation:: SHA-256</source>
+        <source>Aborted because of image read error during verification</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified image:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The hash values differ. The device didn't deliver the same data during acquisition and verification. Maybe you try to acquire the device again. Check as well if the defect sector list was the same during acquisition and verification (see above).</source>
+        <source>SHA256 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification OK. The device delivered the same data during acquisition and verification.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification FAILED. The device didn't deliver the same data during acquisition and verification. Check if the defect sector list was the same during acquisition and verification (see above).</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification OK. The image contains exactely the data that was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification FAILED. The data in the image is different from what was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Maybe you try to acquire the device again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove special device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image meta data</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source> - file extension is %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquire image</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clone device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquisition</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Format:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device used for cloning - cannot be acquired</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>t_ThreadScan</name>
+    <message>
+        <source>Cannot scan devices</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>None of the device scan methods worked. Exiting now.</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
diff --git a/guymager_nl.ts b/guymager_nl.ts
index 9db5f41..d62857f 100644
--- a/guymager_nl.ts
+++ b/guymager_nl.ts
@@ -36,73 +36,95 @@ Continue anyway?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>%1 not accessible</source>
-        <comment>Dialog title</comment>
+        <source>Guymager cannot scan the devices connected to this computer.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Guymager is configured to use %1 for scanning the connected devices, but this did not work. Alternatively, you may use %2. Do you want to switch to %2?</source>
+        <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Try method "%1"</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Creation of a clone</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>t_DeviceListModel</name>
     <message>
+        <source>Linux
+device</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Model</source>
+        <comment>Column of device table</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
         <source>Serial
 nr.</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Linux
-device</source>
-        <comment>Column on main screen</comment>
+        <source>Size</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Model</source>
-        <comment>Column on main screen</comment>
+        <source>Remarks</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>State</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Size</source>
-        <comment>Column on main screen</comment>
+        <source>Hidden
+Areas</source>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Bad
 sectors</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Progress</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Average
 Speed
 [MB/s]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Time
 remaining</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>FIFO queues
 usage
 [%]</source>
-        <comment>Column on main screen</comment>
+        <comment>Column of device table</comment>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -153,10 +175,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>DestDirectory</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>DestImageFilename</source>
         <translation type="unfinished"></translation>
     </message>
@@ -174,11 +192,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Acquisition parameters for %1</source>
-        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>File format</source>
         <translation type="unfinished"></translation>
     </message>
@@ -195,14 +208,6 @@ usage
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Hash computation</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Re-read source after acquisition for verification (takes twice as long)</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
@@ -220,31 +225,83 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Images files exist</source>
+        <source>Access denied</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The image files already exist. Do you want to overwrite them?</source>
+        <source>HashCalcMD5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Access denied</source>
-        <comment>Dialog title</comment>
+        <source>HashCalcSHA256</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HashVerifySrc</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HashVerifyDst</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hash calculation / verification</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Guymager cannot write to the directory
 <byte value="x9"/>%1
-This may be due to insufficient access rights. Please choose another directory.</source>
+This may be due to insufficient access rights or unsupported filename characters. Please choose another directory.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Local device, cannot be written</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Too small</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>In use</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Ok for cloning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
+<byte value="x9"/>%1
+Do you accept these changes?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Files exist</source>
+        <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate MD5</source>
+        <source>The image or info files already exist. Do you want to overwrite them?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Calculate SHA-256</source>
+        <source>Clone %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquire image of %1</source>
+        <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device to be cloned</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Used in another clone operation</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -326,16 +383,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>on</source>
-        <comment>Display that source verification is on</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>off</source>
-        <comment>Display that source verification is off</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
         <translation type="unfinished"></translation>
@@ -358,6 +405,20 @@ This may be due to insufficient access rights. Please choose another directory.<
         <comment>Hash calculation is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Image verification</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>on</source>
+        <comment>Display that verification is on</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>off</source>
+        <comment>Display that verification is off</comment>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -418,10 +479,6 @@ This may be due to insufficient access rights. Please choose another directory.<
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Rescan devices and update list</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>&Devices</source>
         <translation type="unfinished"></translation>
     </message>
@@ -491,20 +548,76 @@ Using libguytools %5</source>
         <source>Finished - Verification failed</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>t_Table</name>
     <message>
-        <source>Acquire</source>
-        <comment>Context menu</comment>
+        <source>Aborted - Image file verify error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Abort acquisition</source>
-        <comment>Context menu</comment>
+        <source>Unknown</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Yes</source>
+        <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rescan devices and update table</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add special device</source>
+        <comment>Menu entry</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Invalid device</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manually added special device</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device alrady contained</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The selected file or device already is contained in the table.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The device or file cannot be selected because its size is unknown.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
+        <source>The device or file cannot be selected because it contains 0 bytes.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Used in clone operation</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>t_Table</name>
+    <message>
         <source>Info</source>
         <comment>Context menu</comment>
         <translation type="unfinished"></translation>
@@ -559,11 +672,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Linux device:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -574,21 +682,6 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Image path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Info  path and file name:: %1 %2</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Image format:: %1 - file extension is %2</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Hash calculation:: off</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
@@ -679,25 +772,11 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>MD5 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>SHA256 hash:: %1</source>
         <comment>Info file</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>SHA256 hash verified:: %1</source>
-        <comment>Info file</comment>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>The hash values are identical. The device delivered the same data during acquisition and verification.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>(ISO format YYYY-MM-DD HH:MM:SS)</source>
         <translation type="unfinished"></translation>
     </message>
@@ -746,7 +825,124 @@ Using libguytools %5</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The hash values differ. The device didn't deliver the same data during acquisition and verification. Maybe you try to acquire the device again. Check as well if the defect sector list was the same during acquisition and verification (see above).</source>
+        <source>Image path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Info  path and file name:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification:: on</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification:: off</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborted because of image read error during verification</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MD5 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified source:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>SHA256 hash verified image:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification OK. The device delivered the same data during acquisition and verification.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Source verification FAILED. The device didn't deliver the same data during acquisition and verification. Check if the defect sector list was the same during acquisition and verification (see above).</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification OK. The image contains exactely the data that was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image verification FAILED. The data in the image is different from what was written.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Maybe you try to acquire the device again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove special device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Image meta data</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source> - file extension is %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquire image</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clone device</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Abort</source>
+        <comment>Context menu</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Acquisition</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Format:: %1</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Device used for cloning - cannot be acquired</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>t_ThreadScan</name>
+    <message>
+        <source>Cannot scan devices</source>
+        <comment>Dialog title</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>None of the device scan methods worked. Exiting now.</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
diff --git a/hash.cpp b/hash.cpp
index bc7d63a..9525b0d 100644
--- a/hash.cpp
+++ b/hash.cpp
@@ -31,7 +31,7 @@ APIRET HashMD5Init (t_pHashContextMD5 pContext)
    return NO_ERROR;
 }
 
-APIRET HashMD5Append (t_pHashContextMD5 pContext, void *pData, int DataLen)
+APIRET HashMD5Append (t_pHashContextMD5 pContext, const void *pData, int DataLen)
 {
    #ifdef USE_MD5_FROM_OPENSSL
       (void) MD5_Update (pContext, pData, (unsigned long) DataLen); // Same remark as for MD5_Init
diff --git a/hash.h b/hash.h
index 75a907c..26977bf 100644
--- a/hash.h
+++ b/hash.h
@@ -47,7 +47,7 @@ typedef struct
 } t_HashSHA256Digest, *t_pHashSHA256Digest;
 
 APIRET HashMD5Init      (t_pHashContextMD5 pContext);
-APIRET HashMD5Append    (t_pHashContextMD5 pContext, void *pData, int DataLen);
+APIRET HashMD5Append    (t_pHashContextMD5 pContext, const void *pData, int DataLen);
 APIRET HashMD5Digest    (t_pHashContextMD5 pContext, t_pHashMD5Digest pDigest);
 APIRET HashMD5DigestStr (t_pHashMD5Digest pDigest, QString &Str);
 bool   HashMD5Match     (t_pHashMD5Digest pDigest1, t_pHashMD5Digest pDigest2);
diff --git a/info.cpp b/info.cpp
index f9fb146..8c41a27 100644
--- a/info.cpp
+++ b/info.cpp
@@ -244,7 +244,7 @@ APIRET t_Info::WriteTable (void)
       {
          if (c >= ColWidth.count())
             ColWidth.append (0);
-         ColWidth[c] = std::max (ColWidth[c], ColList[c].length());
+         ColWidth[c] = GETMAX (ColWidth[c], ColList[c].length());
       }
    }
 
@@ -252,13 +252,13 @@ APIRET t_Info::WriteTable (void)
    // -------------
    for (r=0; r<pOwn->TableRows.count(); r++)
    {
-      WriteLn ();
+      CHK (WriteLn ())
       ColList = pOwn->TableRows[r].split (pOwn->ColSep);
       for (c=0; c<ColList.count(); c++)
       {
-         Write (ColList[c].leftJustified (ColWidth[c]));
+         CHK (Write (ColList[c].leftJustified (ColWidth[c])))
          if (c<ColList.count()-1)
-            Write (pOwn->ColSepReplace);
+            CHK (Write (pOwn->ColSepReplace))
       }
    }
    pOwn->TableRows.clear();
diff --git a/infofield.cpp b/infofield.cpp
index 32dc749..cca2a26 100644
--- a/infofield.cpp
+++ b/infofield.cpp
@@ -51,7 +51,8 @@ t_InfoField::t_InfoField (QWidget *pParent)
                                 + "\n" + tr("Current speed")
                                 + "\n" + tr("Started", "Start timestamp and running time")
                                 + "\n" + tr("Hash calculation")
-                                + "\n" + tr("Source verification"));
+                                + "\n" + tr("Source verification")
+                                + "\n" + tr("Image verification"));
 }
 
 t_InfoField::~t_InfoField ()
@@ -91,7 +92,7 @@ void t_InfoField::SlotShowInfo (t_pDevice pDevice)
       }
       else
       {
-         CHK_EXIT (t_File::GetFormatExtension   (pDevice->Acquisition.Format, NULL, &Format))
+         CHK_EXIT (t_File::GetFormatExtension   (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, NULL, &Format))
          StrValue += "\n" + pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + QSTR_TO_PSZ(Format);
          StrValue += "\n" + pDevice->Acquisition.InfoPath  + pDevice->Acquisition.InfoFilename  + t_File::pExtensionInfo;
       }
@@ -115,8 +116,10 @@ void t_InfoField::SlotShowInfo (t_pDevice pDevice)
 
          StrValue += "\n" + pDevice->StartTimestamp.toString ("d. MMMM hh:mm:ss");
 
-         if ((pDevice->State == t_Device::Acquire) ||  // Don't display anything if no acquisition is running
-             (pDevice->State == t_Device::Verify ))
+         if ((pDevice->State == t_Device::Acquire      ) ||  // Don't display anything if no acquisition is running
+             (pDevice->State == t_Device::AcquirePaused) ||
+             (pDevice->State == t_Device::Verify       ) ||
+             (pDevice->State == t_Device::VerifyPaused ))
               Seconds = pDevice->StartTimestamp.secsTo (QDateTime::currentDateTime());
          else Seconds = pDevice->StartTimestamp.secsTo (pDevice->StopTimestamp);
          Hours    = Seconds / SECONDS_PER_HOUR  ; Seconds -= Hours   * SECONDS_PER_HOUR;
@@ -127,16 +130,24 @@ void t_InfoField::SlotShowInfo (t_pDevice pDevice)
 
       // Hash
       // ----
-      if (pDevice->Acquisition.CalcHashes)
-           StrValue += "\n" + tr("on" , "Display that hash calculation is on");
-      else StrValue += "\n" + tr("off", "Display that hash calculation is off");
+      if     ((pDevice->Acquisition.CalcMD5) &&
+              (pDevice->Acquisition.CalcSHA256)) StrValue += "\n" + tr("MD5 and SHA-256" , "Both hashes are calculated");
+      else if (pDevice->Acquisition.CalcMD5)     StrValue += "\n" + tr("MD5"    );
+      else if (pDevice->Acquisition.CalcSHA256)  StrValue += "\n" + tr("SHA-256");
+      else                                       StrValue += "\n" + tr("off", "Hash calculation is off");
 
       // Source verification
       // -------------------
-      if (pDevice->Acquisition.VerifySource)
-           StrValue += "\n" + tr("on" , "Display that source verification is on");
-      else StrValue += "\n" + tr("off", "Display that source verification is off");
-   }
+      if (pDevice->Acquisition.VerifySrc)
+           StrValue += "\n" + tr("on" , "Display that verification is on");
+      else StrValue += "\n" + tr("off", "Display that verification is off");
+
+      // Image verification
+      // -------------------
+      if (pDevice->Acquisition.VerifyDst)
+           StrValue += "\n" + tr("on" , "Display that verification is on");
+      else StrValue += "\n" + tr("off", "Display that verification is off");
+}
    pOwn->pLabelValues->setText (StrValue);
 }
 
diff --git a/itemdelegate.cpp b/itemdelegate.cpp
index e1fe7f6..a7ba131 100644
--- a/itemdelegate.cpp
+++ b/itemdelegate.cpp
@@ -114,14 +114,14 @@ void t_ItemDelegate::PaintState (QPainter *pPainter, const QStyleOptionViewItem
    int                  CircleCenterDistance;
    t_CfgColor           CircleColor;
    QRect                CircleRect;
-   t_pDevice           pDevice;
+   t_pDevice           pDev;
 
    pPainter->save();
    PaintDefaults (pPainter, Option, Index, ColorPen);
 
-   pDevice = (t_pDevice) Index.data(DeviceRole).value<void *>();
+   pDev = (t_pDevice) Index.data(DeviceRole).value<void *>();
 
-   switch (pDevice->State)
+   switch (pDev->State)
    {
       case t_Device::Idle         : CircleColor = COLOR_STATE_IDLE;           break;
       case t_Device::Acquire      : CircleColor = COLOR_STATE_ACQUIRE;        break;
@@ -129,12 +129,12 @@ void t_ItemDelegate::PaintState (QPainter *pPainter, const QStyleOptionViewItem
       case t_Device::Verify       : CircleColor = COLOR_STATE_VERIFY;         break;
       case t_Device::VerifyPaused : CircleColor = COLOR_STATE_VERIFY_PAUSED;  break;
       case t_Device::Cleanup      : CircleColor = COLOR_STATE_CLEANUP;        break;
-      case t_Device::Finished     : if (pDevice->Acquisition.VerifySource && (!HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerify   ) ||
-                                                                              !HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerify)))
+      case t_Device::Finished     : if ((pDev->Acquisition.VerifySrc && (!HashMD5Match (&pDev->MD5Digest, &pDev->MD5DigestVerifySrc) || !HashSHA256Match(&pDev->SHA256Digest, &pDev->SHA256DigestVerifySrc))) ||
+                                        (pDev->Acquisition.VerifyDst && (!HashMD5Match (&pDev->MD5Digest, &pDev->MD5DigestVerifyDst) || !HashSHA256Match(&pDev->SHA256Digest, &pDev->SHA256DigestVerifyDst))))
                                          CircleColor = COLOR_STATE_FINISHED_BADVERIFY;
                                     else CircleColor = COLOR_STATE_FINISHED;
                                     break;
-      case t_Device::Aborted      : if (pDevice->AbortReason==t_Device::UserRequest)
+      case t_Device::Aborted      : if (pDev->AbortReason==t_Device::UserRequest)
                                          CircleColor = COLOR_STATE_ABORTED_USER;
                                     else CircleColor = COLOR_STATE_ABORTED_OTHER;
                                     break;
@@ -143,7 +143,7 @@ void t_ItemDelegate::PaintState (QPainter *pPainter, const QStyleOptionViewItem
 
    // Draw circle and text
    // --------------------
-   if (!pDevice->Local)
+   if (!pDev->Local)
    {
       pPainter->setBrush (QBrush (CONFIG_COLOR(CircleColor)));
 
diff --git a/main.cpp b/main.cpp
index e681fd7..9ca1aaa 100644
--- a/main.cpp
+++ b/main.cpp
@@ -529,3 +529,8 @@ int main (int argc, char *argv[])
    return rc;
 }
 
+t_pDeviceList MainGetDeviceList (void)
+{
+   return MainLocal.pDeviceList;
+}
+
diff --git a/main.h b/main.h
index fd306dc..f2d6325 100644
--- a/main.h
+++ b/main.h
@@ -10,7 +10,11 @@
 // ****************************************************************************
 
 
-APIRET   MainPocessEvents     (void);
-APIRET   MainGetCommandLine   (char **ppCommandLine);
-QLocale *MainGetpNumberLocale (void);
+APIRET        MainPocessEvents     (void);
+APIRET        MainGetCommandLine   (char **ppCommandLine);
+QLocale      *MainGetpNumberLocale (void);
+
+#ifdef __DEVICE_H__
+   t_pDeviceList MainGetDeviceList (void);
+#endif
 
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 7ec93b3..42ec235 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -63,19 +63,20 @@ t_DeviceListModel::t_DeviceListModel (t_pDeviceList pDeviceList)
    #define RIGHT  (Qt::AlignRight   | Qt::AlignVCenter)
    #define CENTER (Qt::AlignHCenter | Qt::AlignVCenter)
 
-      COL_ASSOC (tr("Serial\nnr."            , "Column on main screen"), t_Device::GetSerialNumber  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
-      COL_ASSOC (tr("Linux\ndevice"          , "Column on main screen"), t_Device::GetLinuxDevice   , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
-      COL_ASSOC (tr("Model"                  , "Column on main screen"), t_Device::GetModel         , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
-      COL_ASSOC (tr("State"                  , "Column on main screen"), t_Device::GetState         , t_ItemDelegate::DISPLAYTYPE_STATE   , LEFT  , 200)
-      COL_ASSOC (tr("Size"                   , "Column on main screen"), t_Device::GetSizeHuman     , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
-      COL_ASSOC (tr("Bad\nsectors"           , "Column on main screen"), t_Device::GetBadSectorCount, t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
-      COL_ASSOC (tr("Progress"               , "Column on main screen"), t_Device::GetProgress      , t_ItemDelegate::DISPLAYTYPE_PROGRESS, LEFT  ,   0)
-      COL_ASSOC (tr("Average\nSpeed\n[MB/s]" , "Column on main screen"), t_Device::GetAverageSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
-      COL_ASSOC (tr("Time\nremaining"        , "Column on main screen"), t_Device::GetRemaining     , t_ItemDelegate::DISPLAYTYPE_STANDARD, CENTER,   0)
-      COL_ASSOC (tr("FIFO queues\nusage\n[%]", "Column on main screen"), t_Device::GetFifoStatus    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
-//      COL_ASSOC (tr("Sector\nsize\nlog."    , "Column on main screen"), t_Device::GetSectorSize    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
-//      COL_ASSOC (tr("Sector\nsize\nphys."   , "Column on main screen"), t_Device::GetSectorSizePhys, t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
-//      COL_ASSOC (tr("Current\nSpeed\n[MB/s]", "Column on main screen"), t_Device::GetCurrentSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
+      COL_ASSOC (tr("Serial\nnr."            , "Column of device table"), t_Device::GetSerialNumber  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+      COL_ASSOC (tr("Linux\ndevice"          , "Column of device table"), t_Device::GetLinuxDevice   , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+      COL_ASSOC (tr("Model"                  , "Column of device table"), t_Device::GetModel         , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+      COL_ASSOC (tr("State"                  , "Column of device table"), t_Device::GetState         , t_ItemDelegate::DISPLAYTYPE_STATE   , LEFT  , 200)
+      COL_ASSOC (tr("Size"                   , "Column of device table"), t_Device::GetSizeHuman     , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
+      COL_ASSOC (tr("Hidden\nAreas"          , "Column of device table"), t_Device::GetHiddenAreas   , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
+      COL_ASSOC (tr("Bad\nsectors"           , "Column of device table"), t_Device::GetBadSectorCount, t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
+      COL_ASSOC (tr("Progress"               , "Column of device table"), t_Device::GetProgress      , t_ItemDelegate::DISPLAYTYPE_PROGRESS, LEFT  ,   0)
+      COL_ASSOC (tr("Average\nSpeed\n[MB/s]" , "Column of device table"), t_Device::GetAverageSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
+      COL_ASSOC (tr("Time\nremaining"        , "Column of device table"), t_Device::GetRemaining     , t_ItemDelegate::DISPLAYTYPE_STANDARD, CENTER,   0)
+      COL_ASSOC (tr("FIFO queues\nusage\n[%]", "Column of device table"), t_Device::GetFifoStatus    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+//    COL_ASSOC (tr("Sector\nsize\nlog."     , "Column of device table"), t_Device::GetSectorSize    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
+//    COL_ASSOC (tr("Sector\nsize\nphys."    , "Column of device table"), t_Device::GetSectorSizePhys, t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
+//    COL_ASSOC (tr("Current\nSpeed\n[MB/s]" , "Column of device table"), t_Device::GetCurrentSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
    #undef COL_ASSOC
    #undef LEFT
    #undef RIGHT
@@ -193,6 +194,7 @@ static APIRET MainWindowRegisterErrorCodes (void)
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_MAINWINDOW_CONSTRUCTOR_NOT_SUPPORTED))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_MAINWINDOW_INVALID_COLUMN))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_MAINWINDOW_INVALID_DATATYPE))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_MAINWINDOW_DEVICE_NOT_FOUND))
 
    return NO_ERROR;
 }
@@ -207,12 +209,13 @@ APIRET t_MainWindow::CreateMenu (void)
    // -------
    pOwn->pActionRescan = new QAction (tr("&Rescan"), this);
    pOwn->pActionRescan->setShortcut  (tr("F5"));
-   pOwn->pActionRescan->setToolTip   (tr("Rescan devices and update list"));
+   pOwn->pActionRescan->setToolTip   (tr("Rescan devices and update table"));
 
    // Menu
    // ----
    pMenu = pMenuBar->addMenu (tr("&Devices"));
    pMenu->addAction (pOwn->pActionRescan);
+   pMenu->addAction (tr("Add special device", "Menu entry"), this, SLOT(SlotAddSpecialDevice()));
 
    pMenu = pMenuBar->addMenu (tr("&Misc", "Menu entry"));
    pMenu->addAction (tr("Debug", "Menu entry"), this, SLOT(SlotDebug()));
@@ -262,7 +265,7 @@ t_MainWindow::t_MainWindow (t_pDeviceList pDeviceList, QWidget *pParent, Qt::WFl
    pOwn->pCentralWidget = new QWidget (this);
    QVBoxLayout *pLayout = new QVBoxLayout (pOwn->pCentralWidget);
 
-   pOwn->pTable                      = new t_Table (pOwn->pCentralWidget, pDeviceList);
+   pOwn->pTable                      = new t_Table (pOwn->pCentralWidget, this, pDeviceList);
    pOwn->pDeviceListModel            = new t_DeviceListModel     (pDeviceList);
    pOwn->pProxyModel                 = new QSortFilterProxyModel (pOwn->pCentralWidget);
    pOwn->pProxyModel->setSourceModel (pOwn->pDeviceListModel);
@@ -305,6 +308,81 @@ void t_MainWindow::SlotRefresh (void)
    pOwn->pInfoField->SlotShowInfo (pDevice);
 }
 
+
+void t_MainWindow::SlotAddSpecialDevice (void)
+{
+   static QDir  LastDir("/");
+   QString      FileName;
+   QFileInfo    FileInfo ;
+   t_pDevice   pDevice;
+   t_pDevice   pDeviceFound;
+   FILE       *pFile = NULL;
+   bool         Error;
+   qint64       Size;
+
+   for (;;)
+   {
+      FileName = QFileDialog::getOpenFileName (this, tr("Open File"), LastDir.canonicalPath ());
+      FileInfo.setFile (FileName);
+      LastDir = FileInfo.dir();
+      if (FileName.isNull())
+         return;
+      Size = FileInfo.size();
+      if (Size <= 0)
+      {
+         LOG_INFO ("Qt thinks the file size for %s is %lld, trying seek to get it", QSTR_TO_PSZ(FileName), Size)
+         pFile = fopen64 (QSTR_TO_PSZ(FileName), "r");
+         Error = (pFile == NULL);
+         if (!Error)
+            Error = (fseeko64 (pFile, 0, SEEK_END) != 0);
+         if (!Error)
+         {
+            Size  = ftello64 (pFile);
+            Error = (Size < 0);
+         }
+
+         if (Error)
+            QMessageBox::information (this, tr ("Invalid device", "Dialog title"), tr("The device or file cannot be selected because its size is unknown."), QMessageBox::Ok);
+         else if (Size <= 0)
+            QMessageBox::information (this, tr ("Invalid device", "Dialog title"), tr("The device or file cannot be selected because it contains 0 bytes."), QMessageBox::Ok);
+         if (Size <= 0)
+            continue;
+      }
+      pDevice = new t_Device ("", FileName, tr("Manually added special device"), 512, 512, Size);
+      pDevice->SpecialDevice = true;
+      CHK_EXIT (pOwn->pDeviceList->MatchDevice (pDevice, pDeviceFound))
+      if (pDeviceFound)
+      {
+         delete pDevice;
+         QMessageBox::information (this, tr ("Device alrady contained", "Dialog title"), tr("The selected file or device already is contained in the table."), QMessageBox::Ok);
+         continue;
+      }
+      break;
+   }
+   LOG_INFO ("Adding special device %s with size %lld", QSTR_TO_PSZ(FileName), Size)
+
+   pOwn->pDeviceList->append (pDevice);
+   pOwn->pDeviceListModel->SlotRefresh();
+   pOwn->pTable->resizeColumnsToContents();
+}
+
+
+APIRET t_MainWindow::RemoveSpecialDevice (t_pDevice pDevice)
+{
+   int i;
+
+   i = pOwn->pDeviceList->indexOf (pDevice);
+   if (i < 0)
+      return ERROR_MAINWINDOW_DEVICE_NOT_FOUND;
+   pOwn->pDeviceList->removeAt(i);
+
+   pOwn->pDeviceListModel->SlotRefresh();
+   pOwn->pTable->resizeColumnsToContents();
+
+   return NO_ERROR;
+}
+
+
 // SlotScanFinished provides us with the new device list. Now, our current device list needs to be updated. The rules are:
 //  (1) For devices, who are in both lists:
 //        Set the state of the device in the current list to Connected. Thus, devices that were temporarly disconnected
@@ -328,7 +406,9 @@ void t_MainWindow::SlotScanFinished (t_pDeviceList pNewDeviceList)
    for (i=0; i<pDeviceList->count(); i++)
    {
       pDev = pDeviceList->at (i);
-      pDev->Checked = false;  // Checked is used to remember which devices we have seen and which ones not
+      if (pDev->SpecialDevice)
+           pDev->Checked = true;   // Checked is used to remember which devices we have seen and which ones not. Treat
+      else pDev->Checked = false;  // special devices as already seen, thus, they are going to be removed from the list.
    }
 
    for (i=0; i<pNewDeviceList->count(); i++)
@@ -418,6 +498,7 @@ void t_MainWindow::closeEvent (QCloseEvent *pEvent)
    }
 }
 
+
 void t_MainWindow::SlotDebug (void)
 {
    QString DebugInfo;
diff --git a/mainwindow.h b/mainwindow.h
index 4113b55..a011f2c 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -31,6 +31,8 @@ class t_MainWindow: public QMainWindow
       t_MainWindow (t_pDeviceList pDeviceList, QWidget *pParent = 0, Qt::WFlags Flags = 0);
      ~t_MainWindow ();
 
+   APIRET RemoveSpecialDevice (t_pDevice pDevice);
+
    private:
       APIRET CreateMenu (void);
 
@@ -38,16 +40,18 @@ class t_MainWindow: public QMainWindow
       void closeEvent (QCloseEvent *pEvent);
 
    private slots:
-      void SlotDebug         (void);
-      void SlotAboutGuymager (void);
-      void SlotAboutQt       (void);
-      void SlotScanFinished  (t_pDeviceList);
-      void SlotRefresh       ();
+      void SlotAddSpecialDevice (void);
+      void SlotDebug            (void);
+      void SlotAboutGuymager    (void);
+      void SlotAboutQt          (void);
+      void SlotScanFinished     (t_pDeviceList);
+      void SlotRefresh          ();
 
    private:
       t_MainWindowLocal *pOwn;
 };
 
+
 // ------------------------------------
 //             Error codes
 // ------------------------------------
@@ -56,7 +60,8 @@ enum
 {
    ERROR_MAINWINDOW_CONSTRUCTOR_NOT_SUPPORTED = ERROR_BASE_MAINWINDOW + 1,
    ERROR_MAINWINDOW_INVALID_COLUMN,
-   ERROR_MAINWINDOW_INVALID_DATATYPE
+   ERROR_MAINWINDOW_INVALID_DATATYPE,
+   ERROR_MAINWINDOW_DEVICE_NOT_FOUND
 };
 
 
diff --git a/media.cpp b/media.cpp
new file mode 100644
index 0000000..36ff087
--- /dev/null
+++ b/media.cpp
@@ -0,0 +1,843 @@
+// ****************************************************************************
+//  Project:        GUYMAGER
+// ****************************************************************************
+//  Programmer:     Guy Voncken
+//                  Police Grand-Ducale
+//                  Service de Police Judiciaire
+//                  Section Nouvelles Technologies
+// ****************************************************************************
+//  Module:         Module for special media function, like HPA/DCO and others
+//                  Important parts of the code found in this file have been
+//                  copied from Mark Lord's famous hdparm.
+// ****************************************************************************
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <asm/byteorder.h>
+#include <linux/hdreg.h>
+#include <scsi/sg.h>
+
+#include "common.h"
+#include "media.h"
+
+// -----------------------
+//  ATA/ATAPI definitions
+// -----------------------
+
+#define MEDIA_ATAFLAGS_LBA48         0x0400
+#define MEDIA_ATAFLAGS_CHECK         0xC000
+#define MEDIA_ATAFLAGS_CHECK_OK      0x4000
+#define MEDIA_ATAFLAGS_HPA_ENABLED   0x0400
+#define MEDIA_ATAFLAGS_DCO_SUPPORTED 0x0800
+
+typedef union
+{
+   unsigned short     Arr[256];             // Organised as 256 words of 16 bits each
+   struct hd_driveid  Identify;
+} t_MediaDriveResult;
+
+typedef struct __attribute__ ((__packed__)) // Must be "packed" in order to have field Result on correct offset (i.e. 4)
+{                                           // on any machine (otherwise, for example, the offset would be 8 on amd64)
+   struct hd_drive_cmd_hdr Request;
+   t_MediaDriveResult      Result;
+} t_MediaDriveCmd, *t_pMediaDriveCmd;
+
+
+// -------------------------------
+//  Structures copied from hdparm
+// -------------------------------
+
+typedef struct
+{
+   t_uint8 feat;
+   t_uint8 nsect;
+   t_uint8 lbal;
+   t_uint8 lbam;
+   t_uint8 lbah;
+} t_ata_lba_regs;
+
+typedef struct
+{
+   t_uint8        dev;
+   t_uint8        command;
+   t_uint8        error;
+   t_uint8        status;
+   t_uint8        is_lba48;
+   t_ata_lba_regs lob;
+   t_ata_lba_regs hob;
+} t_ata_tf;
+
+typedef struct
+{
+   int            interface_id;
+   int            dxfer_direction;
+   unsigned char  cmd_len;
+   unsigned char  mx_sb_len;
+   unsigned short iovec_count;
+   unsigned int   dxfer_len;
+   void          *dxferp;
+   unsigned char *cmdp;
+   void          *sbp;
+   unsigned int   timeout;
+   unsigned int   flags;
+   int            pack_id;
+   void          *usr_ptr;
+   unsigned char  status;
+   unsigned char  masked_status;
+   unsigned char  msg_status;
+   unsigned char  sb_len_wr;
+   unsigned short host_status;
+   unsigned short driver_status;
+   int            resid;
+   unsigned int   duration;
+   unsigned int   info;
+} t_scsi_sg_io_hdr;
+
+enum
+{
+   TASKFILE_CMD_REQ_NODATA = 0,
+   TASKFILE_CMD_REQ_IN     = 2,
+   TASKFILE_CMD_REQ_OUT    = 3,
+   TASKFILE_CMD_REQ_RAW_OUT= 4,
+
+   TASKFILE_DPHASE_NONE    = 0,
+   TASKFILE_DPHASE_PIO_IN  = 1,
+   TASKFILE_DPHASE_PIO_OUT = 4
+};
+
+typedef struct
+{
+   unsigned char data;
+   unsigned char feat;
+   unsigned char nsect;
+   unsigned char lbal;
+   unsigned char lbam;
+   unsigned char lbah;
+   unsigned char dev;
+   unsigned char command;
+} t_taskfile_regs;
+
+typedef union
+{
+   unsigned all            : 16;
+   union
+   {
+      unsigned lob_all     : 8;
+      struct
+      {
+         unsigned data     : 1;
+         unsigned feat     : 1;
+         unsigned lbal     : 1;
+         unsigned nsect    : 1;
+         unsigned lbam     : 1;
+         unsigned lbah     : 1;
+         unsigned dev      : 1;
+         unsigned command  : 1;
+      } lob;
+   };
+   union
+   {
+      unsigned hob_all     : 8;
+      struct
+      {
+         unsigned data     : 1;
+         unsigned feat     : 1;
+         unsigned lbal     : 1;
+         unsigned nsect    : 1;
+         unsigned lbam     : 1;
+         unsigned lbah     : 1;
+         unsigned dev      : 1;
+         unsigned command  : 1;
+      } hob;
+   };
+} t_reg_flags;
+
+typedef struct
+{
+   t_taskfile_regs lob;
+   t_taskfile_regs hob;
+   t_reg_flags     oflags;
+   t_reg_flags     iflags;
+   int             dphase;
+   int             cmd_req;              // IDE command_type
+   unsigned long   obytes;
+   unsigned long   ibytes;
+   unsigned short  data[0];
+} t_hdio_taskfile;
+
+enum
+{
+   ATA_USING_LBA = (1 << 6),
+   ATA_STAT_DRQ  = (1 << 3),
+   ATA_STAT_ERR  = (1 << 0)
+};
+
+#ifndef SG_DXFER_NONE
+#define SG_DXFER_NONE        -1
+#define SG_DXFER_TO_DEV      -2
+#define SG_DXFER_FROM_DEV    -3
+#define SG_DXFER_TO_FROM_DEV -4
+#endif
+
+#define SG_READ                      0
+#define SG_WRITE                     1
+#define SG_PIO                       0
+#define SG_DMA                       1
+#define SG_ATA_16_LEN               16
+#define SG_ATA_LBA48                 1
+#define SG_ATA_PROTO_NON_DATA ( 3 << 1)
+#define SG_ATA_PROTO_PIO_IN   ( 4 << 1)
+#define SG_ATA_PROTO_PIO_OUT  ( 5 << 1)
+#define SG_ATA_PROTO_DMA      ( 6 << 1)
+#define SG_ATA_PROTO_UDMA_IN  (11 << 1)  // not yet supported in libata
+#define SG_ATA_PROTO_UDMA_OUT (12 << 1)  // not yet supported in libata
+#define SG_ATA_12                  0xa1
+#define SG_ATA_16                  0x85
+#define SG_ATA_12_LEN                12
+#define SG_ATA_16_LEN                16
+#define SG_DRIVER_SENSE            0x08
+#define SG_CHECK_CONDITION         0x02
+
+#define lba28_limit ((t_uint64)(1<<28) - 1)
+
+enum
+{
+   ATA_OP_DSM                      = 0x06, // Data Set Management (TRIM)
+   ATA_OP_READ_PIO                 = 0x20,
+   ATA_OP_READ_PIO_ONCE            = 0x21,
+   ATA_OP_READ_LONG                = 0x22,
+   ATA_OP_READ_LONG_ONCE           = 0x23,
+   ATA_OP_READ_PIO_EXT             = 0x24,
+   ATA_OP_READ_DMA_EXT             = 0x25,
+   ATA_OP_READ_FPDMA               = 0x60, // NCQ
+   ATA_OP_WRITE_PIO                = 0x30,
+   ATA_OP_WRITE_LONG               = 0x32,
+   ATA_OP_WRITE_LONG_ONCE          = 0x33,
+   ATA_OP_WRITE_PIO_EXT            = 0x34,
+   ATA_OP_WRITE_DMA_EXT            = 0x35,
+   ATA_OP_WRITE_FPDMA              = 0x61, // NCQ
+   ATA_OP_READ_VERIFY              = 0x40,
+   ATA_OP_READ_VERIFY_ONCE         = 0x41,
+   ATA_OP_READ_VERIFY_EXT          = 0x42,
+   ATA_OP_WRITE_UNC_EXT            = 0x45, // lba48, no data, uses feat reg
+   ATA_OP_FORMAT_TRACK             = 0x50,
+   ATA_OP_DOWNLOAD_MICROCODE       = 0x92,
+   ATA_OP_STANDBYNOW2              = 0x94,
+   ATA_OP_CHECKPOWERMODE2          = 0x98,
+   ATA_OP_SLEEPNOW2                = 0x99,
+   ATA_OP_PIDENTIFY                = 0xa1,
+   ATA_OP_READ_NATIVE_MAX          = 0xf8,
+   ATA_OP_READ_NATIVE_MAX_EXT      = 0x27,
+   ATA_OP_SMART                    = 0xb0,
+   ATA_OP_DCO                      = 0xb1,
+   ATA_OP_ERASE_SECTORS            = 0xc0,
+   ATA_OP_READ_DMA                 = 0xc8,
+   ATA_OP_WRITE_DMA                = 0xca,
+   ATA_OP_DOORLOCK                 = 0xde,
+   ATA_OP_DOORUNLOCK               = 0xdf,
+   ATA_OP_STANDBYNOW1              = 0xe0,
+   ATA_OP_IDLEIMMEDIATE            = 0xe1,
+   ATA_OP_SETIDLE                  = 0xe3,
+   ATA_OP_SET_MAX                  = 0xf9,
+   ATA_OP_SET_MAX_EXT              = 0x37,
+   ATA_OP_SET_MULTIPLE             = 0xc6,
+   ATA_OP_CHECKPOWERMODE1          = 0xe5,
+   ATA_OP_SLEEPNOW1                = 0xe6,
+   ATA_OP_FLUSHCACHE               = 0xe7,
+   ATA_OP_FLUSHCACHE_EXT           = 0xea,
+   ATA_OP_IDENTIFY                 = 0xec,
+   ATA_OP_SETFEATURES              = 0xef,
+   ATA_OP_SECURITY_SET_PASS        = 0xf1,
+   ATA_OP_SECURITY_UNLOCK          = 0xf2,
+   ATA_OP_SECURITY_ERASE_PREPARE   = 0xf3,
+   ATA_OP_SECURITY_ERASE_UNIT      = 0xf4,
+   ATA_OP_SECURITY_FREEZE_LOCK     = 0xf5,
+   ATA_OP_SECURITY_DISABLE         = 0xf6
+};
+
+enum
+{
+   SG_CDB2_TLEN_NODATA   = 0 << 0,
+   SG_CDB2_TLEN_FEAT     = 1 << 0,
+   SG_CDB2_TLEN_NSECT    = 2 << 0,
+   SG_CDB2_TLEN_BYTES    = 0 << 2,
+   SG_CDB2_TLEN_SECTORS  = 1 << 2,
+   SG_CDB2_TDIR_TO_DEV   = 0 << 3,
+   SG_CDB2_TDIR_FROM_DEV = 1 << 3,
+   SG_CDB2_CHECK_COND    = 1 << 5
+};
+
+
+// -------------------------
+//  Code copied from hdparm
+// -------------------------
+
+static inline int needs_lba48 (t_uint8 ata_op, t_uint64 lba, unsigned int nsect)
+{
+   switch (ata_op)
+   {
+      case ATA_OP_DSM:
+      case ATA_OP_READ_PIO_EXT:
+      case ATA_OP_READ_DMA_EXT:
+      case ATA_OP_WRITE_PIO_EXT:
+      case ATA_OP_WRITE_DMA_EXT:
+      case ATA_OP_READ_VERIFY_EXT:
+      case ATA_OP_WRITE_UNC_EXT:
+      case ATA_OP_READ_NATIVE_MAX_EXT:
+      case ATA_OP_SET_MAX_EXT:
+      case ATA_OP_FLUSHCACHE_EXT:
+         return 1;
+   }
+   if (lba >= lba28_limit)
+      return 1;
+   if (nsect)
+   {
+      if (nsect > 0xff)
+         return 1;
+      if ((lba + nsect - 1) >= lba28_limit)
+         return 1;
+   }
+   return 0;
+}
+
+
+static inline int is_dma (t_uint8 ata_op)
+{
+   switch (ata_op)
+   {
+      case ATA_OP_DSM:
+      case ATA_OP_READ_DMA_EXT:
+      case ATA_OP_READ_FPDMA:
+      case ATA_OP_WRITE_DMA_EXT:
+      case ATA_OP_WRITE_FPDMA:
+      case ATA_OP_READ_DMA:
+      case ATA_OP_WRITE_DMA:
+         return SG_DMA;
+      default:
+         return SG_PIO;
+   }
+}
+
+
+static void tf_init (t_ata_tf *tf, t_uint8 ata_op, t_uint64 lba, unsigned int nsect)
+{
+   memset(tf, 0, sizeof(*tf));
+   tf->command  = ata_op;
+   tf->dev      = ATA_USING_LBA;
+   tf->lob.lbal = lba;
+   tf->lob.lbam = lba >>  8;
+   tf->lob.lbah = lba >> 16;
+   tf->lob.nsect = nsect;
+   if (needs_lba48(ata_op, lba, nsect))
+   {
+      tf->is_lba48 = 1;
+      tf->hob.nsect = nsect >> 8;
+      tf->hob.lbal = lba >> 24;
+      tf->hob.lbam = lba >> 32;
+      tf->hob.lbah = lba >> 40;
+   }
+   else
+   {
+      tf->dev |= (lba >> 24) & 0x0f;
+   }
+}
+
+
+static t_uint64 tf_to_lba (t_ata_tf *tf)
+{
+   t_uint32 lba24, lbah;
+   t_uint64 lba64;
+
+   lba24 = (tf->lob.lbah << 16) | (tf->lob.lbam << 8) | (tf->lob.lbal);
+   if (tf->is_lba48)
+        lbah = (tf->hob.lbah << 16) | (tf->hob.lbam << 8) | (tf->hob.lbal);
+   else lbah = (tf->dev & 0x0f);
+
+   lba64 = (((t_uint64)lbah) << 24) | (t_uint64)lba24;
+   return lba64;
+}
+
+
+static int sg16 (int fd, int rw, int dma, t_ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs)
+{
+   unsigned char cdb[SG_ATA_16_LEN];
+   unsigned char sb[32], *desc;
+   t_scsi_sg_io_hdr io_hdr;
+
+   memset(&cdb, 0, sizeof(cdb));
+   memset(&sb,     0, sizeof(sb));
+   memset(&io_hdr, 0, sizeof(t_scsi_sg_io_hdr));
+
+   if (dma)
+        cdb[1] = data ? SG_ATA_PROTO_DMA : SG_ATA_PROTO_NON_DATA;
+   else cdb[1] = data ? (rw ? SG_ATA_PROTO_PIO_OUT : SG_ATA_PROTO_PIO_IN) : SG_ATA_PROTO_NON_DATA;
+
+   cdb[ 2] = SG_CDB2_CHECK_COND;
+   if (data)
+   {
+      cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS;
+      cdb[2] |= rw ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV;
+   }
+
+   //	if (!prefer_ata12 || tf->is_lba48) {
+   if (tf->is_lba48)
+   {
+      cdb[ 0] = SG_ATA_16;
+      cdb[ 4] = tf->lob.feat;
+      cdb[ 6] = tf->lob.nsect;
+      cdb[ 8] = tf->lob.lbal;
+      cdb[10] = tf->lob.lbam;
+      cdb[12] = tf->lob.lbah;
+      cdb[13] = tf->dev;
+      cdb[14] = tf->command;
+      if (tf->is_lba48)
+      {
+         cdb[ 1] |= SG_ATA_LBA48;
+         cdb[ 3]  = tf->hob.feat;
+         cdb[ 5]  = tf->hob.nsect;
+         cdb[ 7]  = tf->hob.lbal;
+         cdb[ 9]  = tf->hob.lbam;
+         cdb[11]  = tf->hob.lbah;
+      }
+      io_hdr.cmd_len = SG_ATA_16_LEN;
+   }
+   else
+   {
+      cdb[ 0] = SG_ATA_12;
+      cdb[ 3] = tf->lob.feat;
+      cdb[ 4] = tf->lob.nsect;
+      cdb[ 5] = tf->lob.lbal;
+      cdb[ 6] = tf->lob.lbam;
+      cdb[ 7] = tf->lob.lbah;
+      cdb[ 8] = tf->dev;
+      cdb[ 9] = tf->command;
+      io_hdr.cmd_len = SG_ATA_12_LEN;
+   }
+
+   io_hdr.interface_id  = 'S';
+   io_hdr.mx_sb_len  = sizeof(sb);
+   io_hdr.dxfer_direction  = data ? (rw ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV) : SG_DXFER_NONE;
+   io_hdr.dxfer_len  = data ? data_bytes : 0;
+   io_hdr.dxferp     = data;
+   io_hdr.cmdp    = cdb;
+   io_hdr.sbp     = sb;
+   io_hdr.pack_id    = tf_to_lba(tf);
+   io_hdr.timeout    = (timeout_secs ? timeout_secs : 5) * 1000; // msecs
+
+   if (ioctl(fd, SG_IO, &io_hdr) == -1)
+      return -1;                                                 // SG_IO not supported
+
+   if (io_hdr.host_status || io_hdr.driver_status != SG_DRIVER_SENSE
+      || (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION))
+   {
+      errno = EBADE;
+      return -1;
+   }
+
+   desc = sb + 8;
+   if (sb[0] != 0x72 || sb[7] < 14 || desc[0] != 0x09 || desc[1] < 0x0c)
+   {
+      errno = EBADE;
+      return -1;
+   }
+
+   tf->is_lba48  = desc[ 2] & 1;
+   tf->error     = desc[ 3];
+   tf->lob.nsect = desc[ 5];
+   tf->lob.lbal  = desc[ 7];
+   tf->lob.lbam  = desc[ 9];
+   tf->lob.lbah  = desc[11];
+   tf->dev       = desc[12];
+   tf->status    = desc[13];
+   tf->hob.feat  = 0;
+   if (tf->is_lba48)
+   {
+      tf->hob.nsect = desc[ 4];
+      tf->hob.lbal  = desc[ 6];
+      tf->hob.lbam  = desc[ 8];
+      tf->hob.lbah  = desc[10];
+   }
+   else
+   {
+      tf->hob.nsect = 0;
+      tf->hob.lbal  = 0;
+      tf->hob.lbam  = 0;
+      tf->hob.lbah  = 0;
+   }
+
+   if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ))
+   {
+      errno = EIO;
+      return -1;
+   }
+
+   return 0;
+}
+
+
+static int do_taskfile_cmd (int fd, t_hdio_taskfile *r, unsigned int timeout_secs)
+{
+   int rc;
+   t_ata_tf tf;
+   void *data = NULL;
+   unsigned int data_bytes = 0;
+   int rw = SG_READ;
+
+   // Reformat and try to issue via SG_IO:
+   tf_init(&tf, 0, 0, 0);
+
+   if (r->oflags.lob.feat)    tf.lob.feat  = r->lob.feat;
+   if (r->oflags.lob.lbal)    tf.lob.lbal  = r->lob.lbal;
+   if (r->oflags.lob.nsect)   tf.lob.nsect = r->lob.nsect;
+   if (r->oflags.lob.lbam)    tf.lob.lbam  = r->lob.lbam;
+   if (r->oflags.lob.lbah)    tf.lob.lbah  = r->lob.lbah;
+   if (r->oflags.lob.dev)     tf.dev       = r->lob.dev;
+   if (r->oflags.lob.command) tf.command   = r->lob.command;
+   if (needs_lba48(tf.command,0,0) || r->oflags.hob_all || r->iflags.hob_all)
+   {
+      tf.is_lba48 = 1;
+      if (r->oflags.hob.feat) tf.hob.feat  = r->hob.feat;
+      if (r->oflags.hob.lbal) tf.hob.lbal  = r->hob.lbal;
+      if (r->oflags.hob.nsect)tf.hob.nsect = r->hob.nsect;
+      if (r->oflags.hob.lbam) tf.hob.lbam  = r->hob.lbam;
+      if (r->oflags.hob.lbah) tf.hob.lbah  = r->hob.lbah;
+   }
+   switch (r->cmd_req)
+   {
+      case TASKFILE_CMD_REQ_OUT:
+      case TASKFILE_CMD_REQ_RAW_OUT:
+         data_bytes = r->obytes;
+         data       = r->data;
+         rw         = SG_WRITE;
+         break;
+      case TASKFILE_CMD_REQ_IN:
+         data_bytes = r->ibytes;
+         data       = r->data;
+         break;
+   }
+
+   rc = sg16(fd, rw, is_dma(tf.command), &tf, data, data_bytes, timeout_secs);
+   if (rc == -1)
+   {
+      if (errno == EINVAL || errno == ENODEV)
+         goto use_legacy_ioctl;
+   }
+
+   if (rc == 0 || errno == EIO)
+   {
+      if (r->iflags.lob.feat)    r->lob.feat  = tf.error;
+      if (r->iflags.lob.lbal)    r->lob.lbal  = tf.lob.lbal;
+      if (r->iflags.lob.nsect)   r->lob.nsect = tf.lob.nsect;
+      if (r->iflags.lob.lbam)    r->lob.lbam  = tf.lob.lbam;
+      if (r->iflags.lob.lbah)    r->lob.lbah  = tf.lob.lbah;
+      if (r->iflags.lob.dev)     r->lob.dev   = tf.dev;
+      if (r->iflags.lob.command) r->lob.command = tf.status;
+      if (r->iflags.hob.feat)    r->hob.feat  = tf.hob.feat;
+      if (r->iflags.hob.lbal)    r->hob.lbal  = tf.hob.lbal;
+      if (r->iflags.hob.nsect)   r->hob.nsect = tf.hob.nsect;
+      if (r->iflags.hob.lbam)    r->hob.lbam  = tf.hob.lbam;
+      if (r->iflags.hob.lbah)    r->hob.lbah  = tf.hob.lbah;
+   }
+
+   return rc;
+
+use_legacy_ioctl:
+   errno = 0;
+   rc = ioctl(fd, HDIO_DRIVE_TASKFILE, r);
+
+   return rc;
+}
+
+
+static int do_drive_cmd (int fd, unsigned char *args)
+{
+   t_ata_tf tf;
+   void *data = NULL;
+   unsigned int data_bytes = 0;
+   int rc;
+
+   if (args == NULL)
+      goto use_legacy_ioctl;
+
+   // Reformat and try to issue via SG_IO:
+   if (args[3])
+   {
+      data_bytes = args[3] * 512;
+      data       = args + 4;
+   }
+
+   tf_init(&tf, args[0], 0, args[1]);
+   tf.lob.feat = args[2];
+   if (tf.command == ATA_OP_SMART)
+   {
+      tf.lob.nsect = args[3];
+      tf.lob.lbal  = args[1];
+      tf.lob.lbam  = 0x4f;
+      tf.lob.lbah  = 0xc2;
+   }
+
+   rc = sg16(fd, SG_READ, is_dma(tf.command), &tf, data, data_bytes, 0);
+   if (rc == -1)
+   {
+      if (errno == EINVAL || errno == ENODEV)
+         goto use_legacy_ioctl;
+   }
+
+   if (rc == 0 || errno == EIO)
+   {
+      args[0] = tf.status;
+      args[1] = tf.error;
+      args[2] = tf.lob.nsect;
+   }
+   return rc;
+
+use_legacy_ioctl:
+   return ioctl(fd, HDIO_DRIVE_CMD, args);
+}
+
+
+static APIRET MediaIdentify (int fd, t_pMediaDriveCmd pDriveCmd)
+{
+   int i;
+
+   memset(pDriveCmd, 0, sizeof(*pDriveCmd));
+   pDriveCmd->Request.command      = ATA_OP_IDENTIFY;
+   pDriveCmd->Request.sector_count = 1;
+   if (do_drive_cmd(fd, (unsigned char *)pDriveCmd))
+   {
+      pDriveCmd->Request.command       = ATA_OP_PIDENTIFY;
+      pDriveCmd->Request.sector_number = 0;
+      pDriveCmd->Request.feature       = 0;
+      pDriveCmd->Request.sector_count  = 1;
+      if (do_drive_cmd (fd, (unsigned char *)pDriveCmd))
+         return ERROR_MEDIA_IDENTIFY_FAILED;
+   }
+   /* byte-swap the little-endian IDENTIFY data to match byte-order on host CPU */
+   for (i = 0; i < 0x100; ++i)
+      __le16_to_cpus (&pDriveCmd->Result.Arr[i]);
+
+   return NO_ERROR;
+}
+
+
+// --------------------------------
+//  End of code copied from hdparm
+// --------------------------------
+
+void t_MediaInfo::InitUnknown (void)
+{
+   SerialNumber.clear();
+   Model       .clear();
+   SupportsLBA48 = t_MediaInfo::Unknown;
+   SupportsHPA   = t_MediaInfo::Unknown;
+   SupportsDCO   = t_MediaInfo::Unknown;
+   HasHPA        = t_MediaInfo::Unknown;
+   HasDCO        = t_MediaInfo::Unknown;
+   HPASize       = 0;
+   DCOSize       = 0;
+   RealSize      = 0;
+}
+
+
+t_MediaInfo::t_MediaInfo ()
+{
+   static bool Initialised = false;
+
+   if (!Initialised)
+   {
+      Initialised = true;
+      CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_MEDIA_MEMALLOC_FAILED))
+         CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_MEDIA_IDENTIFY_FAILED))
+   }
+
+   InitUnknown ();
+}
+
+
+t_MediaInfo::~t_MediaInfo ()
+{
+}
+
+
+static APIRET MediaExtractString (QString &QStr, char *pStr, int Len)
+{
+   char Ch;
+   int  i = 0;
+
+   while ((i+1) < Len)
+   {
+      Ch = pStr[i+1]; if (Ch != 0) QStr += Ch; // As stated in hdparm (see identify.c ), strings
+      Ch = pStr[i  ]; if (Ch != 0) QStr += Ch; // from old devices might contain NULLs
+      i += 2;
+   }
+   QStr = QStr.trimmed();
+
+   return NO_ERROR;
+}
+
+
+static APIRET MediaGetSectorCount (int File, const char *pLinuxDevice, bool SupportsLBA48, t_uint64 *pSectorCountDeviceConfigIdentify, t_uint64 *pSectorCountReadNativeMax)
+{
+   t_MediaDriveCmd Cmd;
+   int             rc=0;
+   t_hdio_taskfile r;
+
+   *pSectorCountDeviceConfigIdentify = 0;
+   *pSectorCountReadNativeMax        = 0;
+
+   // ATA command: Device Configuration Identity
+   // ------------------------------------------
+   memset (&Cmd, 0, (sizeof(Cmd)));
+   Cmd.Request.command = 0xb1;  Cmd.Request.sector_number = 0;
+   Cmd.Request.feature = 0xc2;  Cmd.Request.sector_count  = 1;
+   rc = ioctl(File, HDIO_DRIVE_CMD, &Cmd);
+   if (rc)
+        LOG_INFO ("ATA command DEVICE_CONFIGURATION_IDENTITY failed for device %s (%d / %d)", pLinuxDevice, rc, errno)
+   else *pSectorCountDeviceConfigIdentify = 1 + *((t_uint64 *)(&Cmd.Result.Arr[3]));
+
+   // ATA command: Read Native Max Address (Ext)
+   // ------------------------------------------
+   memset(&r, 0, sizeof(r));
+   r.cmd_req = TASKFILE_CMD_REQ_NODATA;
+   r.dphase  = TASKFILE_DPHASE_NONE;
+   r.oflags.lob.dev     = 1;  r.iflags.lob.lbal = 1;  r.iflags.hob.lbal  = 1;
+   r.oflags.lob.command = 1;  r.iflags.lob.lbam = 1;  r.iflags.hob.lbam  = 1;
+   r.iflags.lob.command = 1;  r.iflags.lob.lbah = 1;  r.iflags.hob.lbah  = 1;
+   r.lob.dev     = 0x40;
+   r.lob.command = ATA_OP_READ_NATIVE_MAX_EXT;
+   rc = do_taskfile_cmd (File, &r, 10);
+   if (rc)
+   {
+      LOG_INFO ("ATA command READ_NATIVE_MAX_ADDRESS_EXT failed for device %s (%d / %d)", pLinuxDevice, rc, errno)
+      if (!SupportsLBA48) // If the device supports LBA48, then READ_NATIVE_MAX_ADDRESS_EXT should have work, so, only try READ_NATIVE_MAX_ADDRESS if LBA48 is not supported.
+      {
+         LOG_INFO ("LBA48 is not supported, retrying with READ_NATIVE_MAX_ADDRESS")
+         memset(&r, 0, sizeof(r));
+         r.cmd_req = TASKFILE_CMD_REQ_NODATA;
+         r.dphase  = TASKFILE_DPHASE_NONE;
+         r.oflags.lob.dev     = 1;  r.iflags.lob.lbal = 1;
+         r.oflags.lob.command = 1;  r.iflags.lob.lbam = 1;
+         r.iflags.lob.command = 1;  r.iflags.lob.lbah = 1;
+         r.iflags.lob.dev     = 1;
+         r.lob.dev            = 0x40;
+         r.lob.command        = WIN_READ_NATIVE_MAX;
+         rc = do_taskfile_cmd (File, &r, 10);
+         if (rc)
+              LOG_INFO ("ATA command READ_NATIVE_MAX_ADDRESS failed for device %s (%d / %d)", pLinuxDevice, rc, errno)
+         else *pSectorCountReadNativeMax = (((r.lob.dev & 0x0F) << 24) | (r.lob.lbah << 16) |
+                                             (r.lob.lbam        <<  8) |  r.lob.lbal      ) + 1;
+      }
+   }
+   else
+   {
+      *pSectorCountReadNativeMax = ((((t_uint64) r.hob.lbah) << 40) | (((t_uint64) r.hob.lbam) << 32) |
+                                    (((t_uint64) r.hob.lbal) << 24) | (((t_uint64) r.lob.lbah) << 16) |
+                                    (((t_uint64) r.lob.lbam) << 8 ) | (((t_uint64) r.lob.lbal)      )) +1;
+   }
+
+   return NO_ERROR;
+}
+
+
+APIRET t_MediaInfo::QueryDevice (const char *pLinuxDevice)
+{
+   t_pMediaDriveCmd   pMediaDriveCmdATA;
+   APIRET              rc;
+   int                 File;
+   struct hd_driveid *pIdentify;
+
+   // Init and submit ATA command IDENTIFY DEVICE
+   // -------------------------------------------
+   InitUnknown();
+
+   pMediaDriveCmdATA   = (t_pMediaDriveCmd) malloc (sizeof(t_MediaDriveCmd));
+
+   File = open (pLinuxDevice, O_RDONLY);
+   if (File < 0)
+   {
+      LOG_INFO ("open failed for %s (%d)", pLinuxDevice, File);
+      return NO_ERROR;
+   }
+
+   // Extract result
+   // --------------
+   rc = MediaIdentify (File, pMediaDriveCmdATA);
+   if (rc == ERROR_MEDIA_IDENTIFY_FAILED)
+   {
+      LOG_INFO ("ioctl identify failed for %s", pLinuxDevice);
+   }
+   else
+   {
+      CHK (rc)
+      t_uint64 SectorCountIdentifyDevice;
+      t_uint64 SectorCountDeviceConfigIdentify;
+      t_uint64 SectorCountReadNativeMax;
+
+      pIdentify = &pMediaDriveCmdATA->Result.Identify;
+      SectorCountIdentifyDevice = GETMAX (pIdentify->lba_capacity, pIdentify->lba_capacity_2);
+
+      CHK (MediaExtractString (SerialNumber, (char*)pIdentify->serial_no, sizeof(pIdentify->serial_no)))
+      CHK (MediaExtractString (Model       , (char*)pIdentify->model    , sizeof(pIdentify->model    )))
+
+      #define FLAG(Val, Flag) (((Val) & (Flag)) == (Flag)) ? t_MediaInfo::Yes : t_MediaInfo::No
+      SupportsLBA48 = FLAG(pIdentify->command_set_2, MEDIA_ATAFLAGS_LBA48 | MEDIA_ATAFLAGS_CHECK) ;
+      SupportsHPA   = FLAG(pIdentify->cfs_enable_1 , MEDIA_ATAFLAGS_HPA_ENABLED  );
+      SupportsDCO   = FLAG(pIdentify->command_set_2, MEDIA_ATAFLAGS_DCO_SUPPORTED);
+      #undef FLAG
+
+      CHK (MediaGetSectorCount (File, pLinuxDevice, SupportsLBA48, &SectorCountDeviceConfigIdentify, &SectorCountReadNativeMax))
+
+      LOG_INFO ("Identification of %s: [%s] [%s] %llu / %llu / %llu", pLinuxDevice, QSTR_TO_PSZ(Model), QSTR_TO_PSZ(SerialNumber), SectorCountIdentifyDevice, SectorCountReadNativeMax, SectorCountDeviceConfigIdentify)
+//      printf ("\n[%s] [%s] [%s]", pLinuxDevice, QSTR_TO_PSZ(Model), QSTR_TO_PSZ(SerialNumber));
+//      printf ("\nIdentify       %16llu %16llX", SectorCountIdentifyDevice      , SectorCountIdentifyDevice      );
+//      printf ("\nNative         %16llu %16llX", SectorCountReadNativeMax       , SectorCountReadNativeMax       );
+//      printf ("\nConfigIdentify %16llu %16llX", SectorCountDeviceConfigIdentify, SectorCountDeviceConfigIdentify);
+
+      if (SupportsHPA)
+      {
+         if      (SectorCountReadNativeMax == 0                        ) HasHPA = t_MediaInfo::Unknown;
+         else if (SectorCountReadNativeMax >  SectorCountIdentifyDevice) HasHPA = t_MediaInfo::Yes;
+         else if (SectorCountReadNativeMax == SectorCountIdentifyDevice) HasHPA = t_MediaInfo::No;
+         else
+         {
+            LOG_INFO ("Strange, sector count NativeMax less than IdentifyDevice: %s %llu < %llu", pLinuxDevice, SectorCountReadNativeMax, SectorCountIdentifyDevice)
+               HasHPA = t_MediaInfo::Unknown;
+            SectorCountReadNativeMax = 0;
+         }
+      }
+      else                         // Maybe the media supports HPA, but the feature has been switched off by means
+      {                            // of DCO. In that case the flag MediaInfo.SupportsHPA is wrong, but that doesn't
+         HasHPA = t_MediaInfo::No; // make problems, as we only are interested if there's a HPA or not. If HPA
+      }                            // has been disabled by DCO, we know that no HPA has been set on the media.
+
+      if (SupportsDCO)
+      {
+         if      ((SectorCountDeviceConfigIdentify == 0) || (SectorCountReadNativeMax == 0)) HasDCO = t_MediaInfo::Unknown;
+         else if  (SectorCountDeviceConfigIdentify >  SectorCountReadNativeMax)              HasDCO = t_MediaInfo::Yes;
+         else if  (SectorCountDeviceConfigIdentify == SectorCountReadNativeMax)              HasDCO = t_MediaInfo::No;
+         else
+         {
+            LOG_INFO ("Strange, sector count DeviceConfigIdentify less than NativeMax: %s %llu < %llu", pLinuxDevice, SectorCountDeviceConfigIdentify, SectorCountReadNativeMax)
+            HasDCO = t_MediaInfo::Unknown;
+            SectorCountDeviceConfigIdentify = 0;
+         }
+      }
+      else
+      {
+         HasDCO = t_MediaInfo::No;
+      }
+   }
+
+   // Free resources
+   // --------------
+   if (close (File) != 0)
+      LOG_INFO ("Close failed for %s", pLinuxDevice);
+
+   free (pMediaDriveCmdATA);
+
+   return NO_ERROR;
+}
+
diff --git a/media.h b/media.h
new file mode 100644
index 0000000..c94cc89
--- /dev/null
+++ b/media.h
@@ -0,0 +1,63 @@
+// ****************************************************************************
+//  Project:        GUYMAGER
+// ****************************************************************************
+//  Programmer:     Guy Voncken
+//                  Police Grand-Ducale
+//                  Service de Police Judiciaire
+//                  Section Nouvelles Technologies
+// ****************************************************************************
+//  Module:         Module for special media function, like HPA/DCO and others
+// ****************************************************************************
+
+#ifndef __MEDIA_H__
+#define __MEDIA_H__
+
+#include <QString>
+
+class t_MediaInfo
+{
+   public:
+       t_MediaInfo ();
+      ~t_MediaInfo ();
+
+       APIRET QueryDevice (const char *pLinuxDevice);
+
+   private:
+      void InitUnknown (void);
+
+   public:
+      typedef enum
+      {
+         Unknown = 0,
+         No,
+         Yes
+      } t_MediaState;
+
+   public:
+      QString            SerialNumber;
+      QString            Model;
+      t_MediaState       SupportsLBA48;
+      t_MediaState       SupportsDCO;
+      t_MediaState       SupportsHPA;
+      t_MediaState       HasHPA;
+      t_MediaState       HasDCO;
+      unsigned long long HPASize;   // A size of 0
+      unsigned long long DCOSize;   // means "unknown"
+      unsigned long long RealSize;
+};
+typedef t_MediaInfo *t_pMediaInfo;
+
+
+// ------------------------------------
+//             Error codes
+// ------------------------------------
+
+enum
+{
+   ERROR_MEDIA_MEMALLOC_FAILED = ERROR_BASE_MEDIA + 1,
+   ERROR_MEDIA_IDENTIFY_FAILED
+};
+
+#endif
+
+
diff --git a/modules.h b/modules.h
index 6980ec7..07effd5 100644
--- a/modules.h
+++ b/modules.h
@@ -43,6 +43,7 @@ CREATE_MODULE_IDS (DLGDIRSEL      , 23)
 CREATE_MODULE_IDS (DLGWAIT        , 24)
 CREATE_MODULE_IDS (HASH           , 25)
 CREATE_MODULE_IDS (AAFF           , 26)
+CREATE_MODULE_IDS (MEDIA          , 27)
 
 CREATE_MODULE_IDS (QT             , 99)
 
diff --git a/qtutil.cpp b/qtutil.cpp
index e73510a..7a775f4 100644
--- a/qtutil.cpp
+++ b/qtutil.cpp
@@ -59,8 +59,8 @@ APIRET QtUtilSetGeometryCentered (QWidget *pWidget, int Dx, int Dy)
    ScreenDx = QApplication::desktop()->width ();
    ScreenDy = QApplication::desktop()->height();
 
-   Dx = std::min (Dx, (int)(ScreenDx * QTUTIL_GEOMETRY_MAXFACTOR_X)); // Take care that the window size never gets bigger
-   Dy = std::min (Dy, (int)(ScreenDy * QTUTIL_GEOMETRY_MAXFACTOR_Y)); // than the screen minus a certain border.
+   Dx = GETMIN (Dx, (int)(ScreenDx * QTUTIL_GEOMETRY_MAXFACTOR_X)); // Take care that the window size never gets bigger
+   Dy = GETMIN (Dy, (int)(ScreenDy * QTUTIL_GEOMETRY_MAXFACTOR_Y)); // than the screen minus a certain border.
 
    if (pWidget->windowFlags() & Qt::Dialog)
         pParent = NULL;
diff --git a/sha256.cpp b/sha256.cpp
index b2fbc60..390ff54 100644
--- a/sha256.cpp
+++ b/sha256.cpp
@@ -1,5 +1,5 @@
 // Guy: This file has been downloaded from www.spale.com/download/scrypt/scrypt1.0/sha256.c. It
-// has been optimised for speedon i386 and amd64 architecture and corrected for powerpc.
+// has been optimised for speed on i386 and amd64 architecture and corrected for powerpc.
 
 // sha256 calculation on i386 and amd64 processors.
 /*
diff --git a/sha256.h b/sha256.h
index c2dc048..1248aca 100644
--- a/sha256.h
+++ b/sha256.h
@@ -17,8 +17,7 @@ typedef struct
     uint32 total[2];
     uint32 state[8];
     uint8 buffer[64];
-}
-sha256_context;
+} sha256_context;
 
 void sha256_starts( sha256_context *ctx );
 void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
diff --git a/shatest/cc.sh b/shatest/cc.sh
new file mode 100755
index 0000000..33244ba
--- /dev/null
+++ b/shatest/cc.sh
@@ -0,0 +1 @@
+g++ -ggdb -O1 -DTEST sha256.cpp -o o1.out 2>&1 | grep -vE "matching constraint does not allow a register|In function |At global scope:"
diff --git a/table.cpp b/table.cpp
index 7dbd1b8..da08450 100644
--- a/table.cpp
+++ b/table.cpp
@@ -22,6 +22,7 @@
 #include "dlgacquire.h"
 #include "itemdelegate.h"
 #include "table.h"
+#include "mainwindow.h"
 #include "compileinfo.h"
 #include "dlgabort.h"
 #include "file.h"
@@ -31,9 +32,12 @@ class t_TableLocal
 {
    public:
       t_pDeviceList  pDeviceList;
+      t_MainWindow  *pMainWindow;
       QAction       *pActionAcquire;
+      QAction       *pActionClone;
       QAction       *pActionAbort;
       QAction       *pActionDeviceInfo;
+      QAction       *pActionRemoveSpecialDevice;
       bool            SlowDownAcquisitions;
 };
 
@@ -42,7 +46,7 @@ t_Table::t_Table ()
    CHK_EXIT (ERROR_TABLE_CONSTRUCTOR_NOT_SUPPORTED)
 } //lint !e1401 not initialised
 
-t_Table::t_Table (QWidget *pParent, t_pDeviceList pDeviceList)
+t_Table::t_Table (QWidget *pParent, t_MainWindow *pMainWindow, t_pDeviceList pDeviceList)
    :QTableView (pParent)
 {
    CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_TABLE_INVALID_ACTION                ))
@@ -61,15 +65,20 @@ t_Table::t_Table (QWidget *pParent, t_pDeviceList pDeviceList)
 
    pOwn = new t_TableLocal;
    pOwn->pDeviceList          = pDeviceList;
+   pOwn->pMainWindow          = pMainWindow;
    pOwn->SlowDownAcquisitions = false;
 
    verticalHeader  ()->hide                  ();
    horizontalHeader()->setClickable          (true);
    horizontalHeader()->setSortIndicatorShown (true);
+   setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
+   setVerticalScrollMode   (QAbstractItemView::ScrollPerPixel);
 
-   pOwn->pActionAcquire    = new QAction(tr("Acquire"          , "Context menu"), this);  addAction (pOwn->pActionAcquire   );
-   pOwn->pActionAbort      = new QAction(tr("Abort acquisition", "Context menu"), this);  addAction (pOwn->pActionAbort     );
-   pOwn->pActionDeviceInfo = new QAction(tr("Info"             , "Context menu"), this);  addAction (pOwn->pActionDeviceInfo);
+   pOwn->pActionAcquire             = new QAction(tr("Acquire image"        , "Context menu"), this);  addAction (pOwn->pActionAcquire            );
+   pOwn->pActionClone               = new QAction(tr("Clone device"         , "Context menu"), this);  addAction (pOwn->pActionClone              );
+   pOwn->pActionAbort               = new QAction(tr("Abort"                , "Context menu"), this);  addAction (pOwn->pActionAbort              );
+   pOwn->pActionDeviceInfo          = new QAction(tr("Info"                 , "Context menu"), this);  addAction (pOwn->pActionDeviceInfo         );
+   pOwn->pActionRemoveSpecialDevice = new QAction(tr("Remove special device", "Context menu"), this);  addAction (pOwn->pActionRemoveSpecialDevice);
 
    CHK_QT_EXIT (connect (this, SIGNAL(clicked (const QModelIndex &)), this, SLOT(SlotMouseClick(const QModelIndex &))))
 
@@ -107,7 +116,8 @@ APIRET t_Table::GetDeviceUnderCursor (t_pDevice &pDevice)
 void t_Table::contextMenuEvent (QContextMenuEvent *pEvent)
 {
    QAction     *pAction;
-   QAction       LocalIndicator (tr("Local Device - cannot be acquired"), this);
+   QAction       LocalIndicator (tr("Local Device - cannot be acquired"           ), this);
+   QAction       CloneIndicator (tr("Device used for cloning - cannot be acquired"), this);
    QMenu         Menu;
    QPoint        Pos;
    t_pDevice    pDevice;
@@ -133,6 +143,7 @@ void t_Table::contextMenuEvent (QContextMenuEvent *pEvent)
    Running = pDevice->pThreadRead || pDevice->pThreadWrite;
 
    pOwn->pActionAcquire->setEnabled (!Running);
+   pOwn->pActionClone  ->setEnabled (!Running);
    pOwn->pActionAbort  ->setEnabled ( Running);
 
    if (pDevice->Local)
@@ -141,19 +152,34 @@ void t_Table::contextMenuEvent (QContextMenuEvent *pEvent)
       Menu.addAction (&LocalIndicator);
       Menu.addSeparator ();
    }
+   else if (pOwn->pDeviceList->UsedAsCloneDestination(pDevice))
+   {
+      CloneIndicator.setEnabled (false);
+      Menu.addAction (&CloneIndicator);
+      Menu.addSeparator ();
+   }
    else
    {
       Menu.addAction (pOwn->pActionAcquire);
+      Menu.addAction (pOwn->pActionClone  );
       Menu.addAction (pOwn->pActionAbort  );
    }
    Menu.addAction (pOwn->pActionDeviceInfo);
 
+   if (pDevice->SpecialDevice)
+   {
+      pOwn->pActionRemoveSpecialDevice->setEnabled (!Running);
+      Menu.addAction (pOwn->pActionRemoveSpecialDevice);
+   }
+
    pAction = Menu.exec (pEvent->globalPos());
 
 //   pAction = QMenu::exec (actions(), pEvent->globalPos());
-   if      (pAction == pOwn->pActionAcquire   ) CHK_EXIT (StartAcquisition  (pDevice))
-   if      (pAction == pOwn->pActionAbort     ) CHK_EXIT (AbortAcquisition  (pDevice))
-   else if (pAction == pOwn->pActionDeviceInfo) CHK_EXIT (ShowDeviceInfo    (pDevice))
+   if      (pAction == pOwn->pActionAcquire            ) CHK_EXIT (StartAcquisition    (pDevice, false))
+   else if (pAction == pOwn->pActionClone              ) CHK_EXIT (StartAcquisition    (pDevice, true ))
+   else if (pAction == pOwn->pActionAbort              ) CHK_EXIT (AbortAcquisition    (pDevice))
+   else if (pAction == pOwn->pActionDeviceInfo         ) CHK_EXIT (ShowDeviceInfo      (pDevice))
+   else if (pAction == pOwn->pActionRemoveSpecialDevice) CHK_EXIT (pOwn->pMainWindow->RemoveSpecialDevice(pDevice))
    else
    {
 //      CHK_EXIT (ERROR_TABLE_INVALID_ACTION)
@@ -183,6 +209,7 @@ APIRET t_Table::ShowDeviceInfo (t_pcDevice pDevice)
    return NO_ERROR;
 }
 
+
 // ----------------------------------------------------------------------------------------------------------------
 //
 //                                                     Acquistion start
@@ -197,6 +224,7 @@ APIRET t_Table::InfoAcquisitionStart (t_pDevice pDevice)
    const char *pLibEwfVersionInstalled;
    QString      FormatDescription;
    QString      FormatExtension;
+   QString      Str;
 
    CHK (pDevice->Info.Create())
    CHK (pDevice->Info.Title   (tr("GUYMAGER ACQUISITION INFO FILE", "Info file")))
@@ -220,175 +248,249 @@ APIRET t_Table::InfoAcquisitionStart (t_pDevice pDevice)
    CHK (pDevice->Info.WriteLn ())
    CHK (pDevice->Info.WriteDeviceInfo ())
 
+
    CHK (pDevice->Info.WriteLn ())
    CHK (pDevice->Info.WriteLn ())
-   CHK (pDevice->Info.Title   (tr("Image", "Info file")))
+   CHK (pDevice->Info.Title   (tr("Acquisition", "Info file")))
    CHK (pDevice->Info.WriteLn ())
-   CHK (pDevice->Info.AddRow (tr("Linux device:: %1"    , "Info file").arg(pDevice->LinuxDevice) ))
+   CHK (t_File::GetFormatDescription (pDevice->Acquisition.Format, pDevice->Acquisition.Clone,        FormatDescription))
+   CHK (t_File::GetFormatExtension   (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, NULL, &FormatExtension))
+   CHK (pDevice->Info.AddRow (tr("Linux device:: %1"    , "Info file").arg(pDevice->LinuxDevice)))
    CHK (pDevice->Info.AddRow (tr("Device size:: %1 (%2)", "Info file").arg(pDevice->Size) .arg(t_Device::GetSizeHuman(pDevice).toString())))
-   CHK (pDevice->Info.AddRow (tr("Image path and file name:: %1 %2" , "Info file").arg(pDevice->Acquisition.ImagePath) .arg(pDevice->Acquisition.ImageFilename)))
-   CHK (pDevice->Info.AddRow (tr("Info  path and file name:: %1 %2" , "Info file").arg(pDevice->Acquisition.InfoPath ) .arg(pDevice->Acquisition.InfoFilename )))
-
-   CHK (t_File::GetFormatDescription (pDevice->Acquisition.Format, FormatDescription))
-   CHK (t_File::GetFormatExtension   (pDevice->Acquisition.Format, NULL, &FormatExtension))
+   Str = tr("Format:: %1", "Info file") .arg(FormatDescription);
+   if (!FormatExtension.isEmpty())
+      Str += tr(" - file extension is %1", "Info file") .arg(FormatExtension);
+   CHK (pDevice->Info.AddRow (Str))
+   if (pDevice->Acquisition.Format != t_File::DD)
+   {
+      CHK (pDevice->Info.AddRow (tr("Image meta data", "Info file")))
+      CHK (pDevice->Info.AddRow ("   " + t_DlgAcquire::tr("EwfCaseNumber"    ) + QString(":: %1") .arg(pDevice->Acquisition.CaseNumber    )))
+      CHK (pDevice->Info.AddRow ("   " + t_DlgAcquire::tr("EwfEvidenceNumber") + QString(":: %1") .arg(pDevice->Acquisition.EvidenceNumber)))
+      CHK (pDevice->Info.AddRow ("   " + t_DlgAcquire::tr("EwfExaminer"      ) + QString(":: %1") .arg(pDevice->Acquisition.Examiner      )))
+      CHK (pDevice->Info.AddRow ("   " + t_DlgAcquire::tr("EwfDescription"   ) + QString(":: %1") .arg(pDevice->Acquisition.Description   )))
+      CHK (pDevice->Info.AddRow ("   " + t_DlgAcquire::tr("EwfNotes"         ) + QString(":: %1") .arg(pDevice->Acquisition.Notes         )))
 
-   CHK (pDevice->Info.AddRow (tr("Image format:: %1 - file extension is %2", "Info file")  .arg(FormatDescription) .arg(FormatExtension)))
+   }
+   CHK (pDevice->Info.AddRow (tr("Image path and file name:: %1", "Info file").arg(pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + FormatExtension)))
+   CHK (pDevice->Info.AddRow (tr("Info  path and file name:: %1", "Info file").arg(pDevice->Acquisition.InfoPath  + pDevice->Acquisition.InfoFilename  + t_File::pExtensionInfo)))
 
-   if (pDevice->Acquisition.CalcHashes)
-        CHK (pDevice->Info.AddRow (tr("Hash calculation:: on" , "Info file")))
-   else CHK (pDevice->Info.AddRow (tr("Hash calculation:: off", "Info file")))
+   if     ((pDevice->Acquisition.CalcMD5) &&
+           (pDevice->Acquisition.CalcSHA256)) CHK (pDevice->Info.AddRow (tr("Hash calculation:: MD5 and SHA-256", "Info file")))
+   else if (pDevice->Acquisition.CalcMD5)     CHK (pDevice->Info.AddRow (tr("Hash calculation:: MD5"            , "Info file")))
+   else if (pDevice->Acquisition.CalcSHA256)  CHK (pDevice->Info.AddRow (tr("Hash calculation:: SHA-256"        , "Info file")))
+   else                                       CHK (pDevice->Info.AddRow (tr("Hash calculation:: off"            , "Info file")))
 
-   if (pDevice->Acquisition.VerifySource)
+   if (pDevice->Acquisition.VerifySrc)
         CHK (pDevice->Info.AddRow (tr("Source verification:: on" , "Info file")))
    else CHK (pDevice->Info.AddRow (tr("Source verification:: off", "Info file")))
+
+   if (pDevice->Acquisition.VerifyDst)
+        CHK (pDevice->Info.AddRow (tr("Image verification:: on" , "Info file")))
+   else CHK (pDevice->Info.AddRow (tr("Image verification:: off", "Info file")))
+
    CHK (pDevice->Info.WriteTable ());
 
    return NO_ERROR;
 }
 
-APIRET t_Table::StartAcquisition (t_pDevice pDevice)
+APIRET TableFifoCalcSizeAndAlloc (t_pDevice pDevice, unsigned int Fifos, unsigned int *pMaxBlocksInUse)
 {
-   t_DlgAcquire Dlg (pDevice, this);
-   QString      Format;
-   int          Fifos=0;
+   const unsigned int PageSize = getpagesize();
+   unsigned int       MaxBlocksInUse;
 
-   if (Dlg.exec() == QDialog::Accepted)
+   // Set the data block size
+   // -----------------------
+   switch (pDevice->Acquisition.Format)
    {
-      pOwn->SlowDownAcquisitions = true;
-      LOG_INFO ("Starting acquisition for %s", QSTR_TO_PSZ(pDevice->LinuxDevice))
-      CHK (Dlg.GetParameters (pDevice->Acquisition))
-      CHK (t_File::GetFormatExtension   (pDevice->Acquisition.Format, NULL, &Format))
-      LOG_INFO ("Image %s%s%s", QSTR_TO_PSZ(pDevice->Acquisition.ImagePath), QSTR_TO_PSZ(pDevice->Acquisition.ImageFilename), QSTR_TO_PSZ(Format))
-      LOG_INFO ("Info  %s%s%s" , QSTR_TO_PSZ(pDevice->Acquisition.InfoPath ), QSTR_TO_PSZ(pDevice->Acquisition.InfoFilename ), t_File::pExtensionInfo)
-
-      CHK (pDevice->SetMessage (QString()))
-      pDevice->State               = t_Device::Acquire;
-      pDevice->AbortReason         = t_Device::None;
-      pDevice->AbortRequest        = false;
-      pDevice->DeleteAfterAbort    = false;
-      pDevice->StartTimestampVerify= QDateTime();
-      pDevice->StopTimestamp       = QDateTime();
-      pDevice->PrevTimestamp       = QTime();
-      pDevice->PrevSpeed           = 0.0;
-      pDevice->PrevPos             = 0;
-      pDevice->SetCurrentWritePos (0LL);
-      pDevice->SetCurrentVerifyPos(0LL);
-      CHK (pDevice->ClearBadSectors ())
-
-      memset (&pDevice->MD5Digest         , 0, sizeof(pDevice->MD5Digest         ));
-      memset (&pDevice->MD5DigestVerify   , 0, sizeof(pDevice->MD5DigestVerify   ));
-      memset (&pDevice->SHA256Digest      , 0, sizeof(pDevice->SHA256Digest      ));
-      memset (&pDevice->SHA256DigestVerify, 0, sizeof(pDevice->SHA256DigestVerify));
-      pDevice->StartTimestamp = QDateTime::currentDateTime();
-      CHK (InfoAcquisitionStart (pDevice))
-
-      if (pDevice->pThreadRead  != NULL) CHK_EXIT (ERROR_TABLE_THREADREAD_ALREADY_RUNNING)
-      if (pDevice->pThreadWrite != NULL) CHK_EXIT (ERROR_TABLE_THREADWRITE_ALREADY_RUNNING)
-      if (pDevice->pThreadHash  != NULL) CHK_EXIT (ERROR_TABLE_THREADHASH_ALREADY_RUNNING)
-      if (!pDevice->ThreadCompressList.isEmpty()) CHK_EXIT (ERROR_TABLE_THREADCOMPRESS_ALREADY_RUNNING)
-      if ((pDevice->pFifoRead        != NULL) ||
-          (pDevice->pFifoHashIn      != NULL) ||
-          (pDevice->pFifoHashOut     != NULL) ||
-          (pDevice->pFifoCompressIn  != NULL) ||
-          (pDevice->pFifoCompressOut != NULL))
-         CHK_EXIT (ERROR_TABLE_FIFO_EXISTS)
-
-      // Create threads
-      // --------------
-      pDevice->pThreadRead  = new t_ThreadRead  (pDevice, &pOwn->SlowDownAcquisitions);
-      pDevice->pThreadWrite = new t_ThreadWrite (pDevice, &pOwn->SlowDownAcquisitions);
-      CHK_QT_EXIT (connect (pDevice->pThreadRead , SIGNAL(SignalEnded(t_pDevice)), this, SLOT(SlotThreadReadFinished (t_pDevice))))
-      CHK_QT_EXIT (connect (pDevice->pThreadWrite, SIGNAL(SignalEnded(t_pDevice)), this, SLOT(SlotThreadWriteFinished(t_pDevice))))
-
-      if (pDevice->HasHashThread())
-      {
-         pDevice->pThreadHash = new t_ThreadHash (pDevice);
-         CHK_QT_EXIT (connect (pDevice->pThreadHash, SIGNAL(SignalEnded(t_pDevice)), this, SLOT(SlotThreadHashFinished (t_pDevice))))
-      }
+      case t_File::DD : pDevice->FifoBlockSize = CONFIG(FifoBlockSizeDD );   break;
+      case t_File::AFF: pDevice->FifoBlockSize = CONFIG(FifoBlockSizeAFF);   break;
+      case t_File::EWF:
+         if (pDevice->HasCompressionThreads())
+              pDevice->FifoBlockSize = EWF_MULTITHREADED_COMPRESSION_CHUNK_SIZE;
+         else pDevice->FifoBlockSize = CONFIG(FifoBlockSizeEWF);
+         if (pDevice->FifoBlockSize != (unsigned int) CONFIG(FifoBlockSizeEWF))
+            LOG_INFO ("Running with FifoBlockSize of %d (no other size supported when running with multithreaded EWF compression)", pDevice->FifoBlockSize)
+         break;
+      default:  CHK (ERROR_TABLE_INVALID_FORMAT)
+   }
 
-      if (pDevice->HasCompressionThreads())
-      {
-         for (int i=0; i < CONFIG(CompressionThreads); i++)
-         {
-            t_pThreadCompress pThread;
+   // Calc the real amount of memory used for every block
+   // ---------------------------------------------------
+   pDevice->FifoAllocBlockSize = pDevice->FifoBlockSize;    // Start with the standard data size
+
+   if (pDevice->HasCompressionThreads())                    // Add what might be necessary for compressed  data
+      pDevice->FifoAllocBlockSize += (int)(pDevice->FifoBlockSize * 0.001) + 12;  // Reserve enough room so that compressed data its in the block.
+
+   pDevice->FifoAllocBlockSize += sizeof (t_FifoBlock);     // Add the structure overhead
+
+//   if (!CONFIG (FifoMemoryManager))                       // Go to the next boundary when working with C-Lib memory management
+//   {
+      if ((pDevice->FifoAllocBlockSize % PageSize) != 0)
+         pDevice->FifoAllocBlockSize += PageSize - (pDevice->FifoAllocBlockSize % PageSize);
+//   }
+
+   // Calc the number of entries for each FIFO
+   // ----------------------------------------
+   pDevice->FifoMaxBlocks = (int)((((long long)CONFIG(FifoMaxMem))*BYTES_PER_MEGABYTE) / ((long long)pDevice->FifoAllocBlockSize * Fifos));
+   if (pDevice->FifoMaxBlocks == 0)
+      pDevice->FifoMaxBlocks = 1;
+
+   // Calc the amount of memory for the blocks and allocate it
+   // --------------------------------------------------------
+   MaxBlocksInUse = pDevice->FifoMaxBlocks * Fifos;  // Data in the FIFOs
+   MaxBlocksInUse += 1;                              // ThreadRead might allocate an additional block that can't yet be written to the full FIFO
+   if ((pDevice->Acquisition.Format == t_File::AFF) && !pDevice->HasCompressionThreads())
+      MaxBlocksInUse += 1;                           // ThreadWrite might use an additional buffer if it does the AFF preprocessing
+   if (pDevice->HasCompressionThreads())
+      MaxBlocksInUse += CONFIG(CompressionThreads);  // Each compression thread might have one additional block for writing the compressed data
+   MaxBlocksInUse += Fifos;
+   *pMaxBlocksInUse = MaxBlocksInUse;
+
+   if (CONFIG (FifoMemoryManager))
+      CHK (FifoMemoryAlloc (&pDevice->pFifoMemory, MaxBlocksInUse, pDevice->FifoAllocBlockSize))
 
-            pThread = new t_ThreadCompress (pDevice, i);
-            pDevice->ThreadCompressList.append (pThread);
-            CHK_QT_EXIT (connect (pThread, SIGNAL(SignalEnded(t_pDevice,int)), this, SLOT(SlotThreadCompressFinished (t_pDevice,int))))
-         }
-      }
+   return NO_ERROR;
+}
 
-      // Create fifos and assign threads
-      // -------------------------------
+APIRET t_Table::StartAcquisition (t_pDevice pDevice, bool Clone)
+{
+   t_DlgAcquire Dlg (pDevice, Clone, pOwn->pDeviceList, this);
+   QString      Format;
+   int          Fifos = 0;
 
-      switch (pDevice->Acquisition.Format)
-      {
-         case t_File::DD : pDevice->FifoBlockSize = CONFIG(FifoBlockSizeDD );   break;
-         case t_File::AFF: pDevice->FifoBlockSize = CONFIG(FifoBlockSizeAFF);   break;
-         case t_File::EWF:
-            if (pDevice->HasCompressionThreads())
-                 pDevice->FifoBlockSize = EWF_MULTITHREADED_COMPRESSION_CHUNK_SIZE;
-            else pDevice->FifoBlockSize = CONFIG(FifoBlockSizeEWF);
-            if (pDevice->FifoBlockSize != (unsigned int) CONFIG(FifoBlockSizeEWF))
-               LOG_INFO ("Running with FifoBlockSize of %d (no other size supported when running with multithreaded EWF compression)", pDevice->FifoBlockSize)
-            break;
-         default:  CHK (ERROR_TABLE_INVALID_FORMAT)
-      }
+   if (Dlg.exec() != QDialog::Accepted)
+      return NO_ERROR;
 
-      #define FIFO_MAX_BLOCKS(Fifos0)   std::max ((int)((((long long)CONFIG(FifoMaxMem))*BYTES_PER_MEGABYTE) / ((long long)pDevice->FifoBlockSize * (Fifos0))), 1)
+   pOwn->SlowDownAcquisitions = true;
+   LOG_INFO ("Starting acquisition (%s) for %s", Clone ? "clone":"image", QSTR_TO_PSZ(pDevice->LinuxDevice))
+   CHK (Dlg.GetParameters (pDevice->Acquisition))
+   CHK (t_File::GetFormatExtension  (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, NULL, &Format))
+   if (Clone)
+      Format = " (clone)";
+   LOG_INFO ("Image %s%s%s", QSTR_TO_PSZ(pDevice->Acquisition.ImagePath), QSTR_TO_PSZ(pDevice->Acquisition.ImageFilename), QSTR_TO_PSZ(Format))
+   LOG_INFO ("Info  %s%s%s", QSTR_TO_PSZ(pDevice->Acquisition.InfoPath ), QSTR_TO_PSZ(pDevice->Acquisition.InfoFilename ), t_File::pExtensionInfo)
+
+   CHK (pDevice->SetMessage (QString()))
+   pDevice->State               = t_Device::Acquire;
+   pDevice->AbortReason         = t_Device::None;
+   pDevice->AbortRequest        = false;
+   pDevice->AbortCount          = 0;
+   pDevice->DeleteAfterAbort    = false;
+   pDevice->StartTimestampVerify= QDateTime();
+   pDevice->StopTimestamp       = QDateTime();
+   pDevice->PrevTimestamp       = QTime();
+   pDevice->PrevSpeed           = 0.0;
+   pDevice->PrevPos             = 0;
+   pDevice->SetCurrentWritePos    (0LL);
+   pDevice->SetCurrentVerifyPosSrc(0LL);
+   pDevice->SetCurrentVerifyPosDst(0LL);
+   CHK (pDevice->ClearBadSectors ())
+
+   memset (&pDevice->MD5Digest            , 0, sizeof(pDevice->MD5Digest            ));
+   memset (&pDevice->MD5DigestVerifySrc   , 0, sizeof(pDevice->MD5DigestVerifySrc   ));
+   memset (&pDevice->MD5DigestVerifyDst   , 0, sizeof(pDevice->MD5DigestVerifyDst   ));
+   memset (&pDevice->SHA256Digest         , 0, sizeof(pDevice->SHA256Digest         ));
+   memset (&pDevice->SHA256DigestVerifySrc, 0, sizeof(pDevice->SHA256DigestVerifySrc));
+   memset (&pDevice->SHA256DigestVerifyDst, 0, sizeof(pDevice->SHA256DigestVerifyDst));
+   pDevice->StartTimestamp = QDateTime::currentDateTime();
+   CHK (InfoAcquisitionStart (pDevice))
+
+   if (pDevice->pThreadRead  != NULL) CHK_EXIT (ERROR_TABLE_THREADREAD_ALREADY_RUNNING )
+   if (pDevice->pThreadWrite != NULL) CHK_EXIT (ERROR_TABLE_THREADWRITE_ALREADY_RUNNING)
+   if (pDevice->pThreadHash  != NULL) CHK_EXIT (ERROR_TABLE_THREADHASH_ALREADY_RUNNING )
+   if (!pDevice->ThreadCompressList.isEmpty()) CHK_EXIT (ERROR_TABLE_THREADCOMPRESS_ALREADY_RUNNING)
+   if ((pDevice->pFifoRead        != NULL) ||
+       (pDevice->pFifoHashIn      != NULL) ||
+       (pDevice->pFifoHashOut     != NULL) ||
+       (pDevice->pFifoCompressIn  != NULL) ||
+       (pDevice->pFifoCompressOut != NULL))
+      CHK_EXIT (ERROR_TABLE_FIFO_EXISTS)
+
+   // Create threads
+   // --------------
+   pDevice->pThreadRead  = new t_ThreadRead  (pDevice, &pOwn->SlowDownAcquisitions);
+   pDevice->pThreadWrite = new t_ThreadWrite (pDevice, &pOwn->SlowDownAcquisitions);
+   CHK_QT_EXIT (connect (pDevice->pThreadRead , SIGNAL(SignalEnded       (t_pDevice)), this, SLOT(SlotThreadReadFinished    (t_pDevice))))
+   CHK_QT_EXIT (connect (pDevice->pThreadWrite, SIGNAL(SignalEnded       (t_pDevice)), this, SLOT(SlotThreadWriteFinished   (t_pDevice))))
+   CHK_QT_EXIT (connect (pDevice->pThreadWrite, SIGNAL(SignalFreeMyHandle(t_pDevice)), this, SLOT(SlotThreadWriteWakeThreads(t_pDevice))))
+
+   if (pDevice->HasHashThread())
+   {
+      pDevice->pThreadHash = new t_ThreadHash (pDevice);
+      CHK_QT_EXIT (connect (pDevice->pThreadHash, SIGNAL(SignalEnded(t_pDevice)), this, SLOT(SlotThreadHashFinished (t_pDevice))))
+   }
 
-      if      (!pDevice->HasHashThread() && !pDevice->HasCompressionThreads())
-      {
-         Fifos = 1;
-         pDevice->FifoMaxBlocks = FIFO_MAX_BLOCKS (Fifos);
-         pDevice->pFifoRead     = new t_FifoStd (pDevice->FifoMaxBlocks);
-         pDevice->pFifoWrite    = pDevice->pFifoRead;
-      }
-      else if ( pDevice->HasHashThread() && !pDevice->HasCompressionThreads())
-      {
-         Fifos = 2;
-         pDevice->FifoMaxBlocks = FIFO_MAX_BLOCKS (Fifos);
-         pDevice->pFifoRead     = new t_FifoStd (pDevice->FifoMaxBlocks);
-         pDevice->pFifoHashIn   = pDevice->pFifoRead;
-         pDevice->pFifoHashOut  = new t_FifoStd (pDevice->FifoMaxBlocks);
-         pDevice->pFifoWrite    = pDevice->pFifoHashOut;
-      }
-      else if (!pDevice->HasHashThread() &&  pDevice->HasCompressionThreads())
-      {
-         Fifos = 2 * CONFIG(CompressionThreads);
-         pDevice->FifoMaxBlocks    = FIFO_MAX_BLOCKS (Fifos);
-         pDevice->pFifoCompressIn  = new t_FifoCompressIn  (CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
-         pDevice->pFifoRead        = pDevice->pFifoCompressIn;
-         pDevice->pFifoCompressOut = new t_FifoCompressOut (CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
-         pDevice->pFifoWrite       = pDevice->pFifoCompressOut;
-      }
-      else if ( pDevice->HasHashThread() &&  pDevice->HasCompressionThreads())
+   if (pDevice->HasCompressionThreads())
+   {
+      for (int i=0; i < CONFIG(CompressionThreads); i++)
       {
-         Fifos = 1 + 2 * CONFIG(CompressionThreads);
-         pDevice->FifoMaxBlocks    = FIFO_MAX_BLOCKS (Fifos);
-         pDevice->pFifoRead        = new t_FifoStd (pDevice->FifoMaxBlocks);
-         pDevice->pFifoHashIn      = pDevice->pFifoRead;
-         pDevice->pFifoCompressIn  = new t_FifoCompressIn  (CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
-         pDevice->pFifoHashOut     = pDevice->pFifoCompressIn;
-         pDevice->pFifoCompressOut = new t_FifoCompressOut (CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
-         pDevice->pFifoWrite       = pDevice->pFifoCompressOut;
+         t_pThreadCompress pThread;
+
+         pThread = new t_ThreadCompress (pDevice, i);
+         pDevice->ThreadCompressList.append (pThread);
+         CHK_QT_EXIT (connect (pThread, SIGNAL(SignalEnded(t_pDevice,int)), this, SLOT(SlotThreadCompressFinished (t_pDevice,int))))
       }
-      #undef FIFO_MAX_BLOCKS
-      LOG_INFO ("Acquisition runs with %d fifos, each one with space for %d blocks of %d bytes (%0.1f MB per acquisition)",
-                Fifos, pDevice->FifoMaxBlocks, pDevice->FifoBlockSize, (double)(Fifos * pDevice->FifoMaxBlocks * pDevice->FifoBlockSize) / BYTES_PER_MEGABYTE)
-
-      // Start threads
-      // -------------
-      pDevice->pThreadRead ->start(QThread::LowPriority);
-      if (pDevice->HasHashThread())
-         pDevice->pThreadHash->start(QThread::LowPriority);
-      for (int i=0; i < pDevice->ThreadCompressList.count(); i++)
-         pDevice->ThreadCompressList[i]->start(QThread::LowPriority);
-      pDevice->pThreadWrite->start(QThread::LowPriority);
-
-      pOwn->SlowDownAcquisitions = false;
    }
 
+   // Create fifos and assign threads
+   // -------------------------------
+   unsigned int MaxBlocksInUse;
+
+   if      (!pDevice->HasHashThread() && !pDevice->HasCompressionThreads())
+   {
+      Fifos = 1;
+      CHK (TableFifoCalcSizeAndAlloc (pDevice, Fifos, &MaxBlocksInUse))
+      pDevice->pFifoRead  = new t_FifoStd (pDevice->pFifoMemory, pDevice->FifoMaxBlocks);
+      pDevice->pFifoWrite = pDevice->pFifoRead;
+   }
+   else if ( pDevice->HasHashThread() && !pDevice->HasCompressionThreads())
+   {
+      Fifos = 2;
+      CHK (TableFifoCalcSizeAndAlloc (pDevice, Fifos, &MaxBlocksInUse))
+      pDevice->pFifoRead    = new t_FifoStd (pDevice->pFifoMemory, pDevice->FifoMaxBlocks);
+      pDevice->pFifoHashIn  = pDevice->pFifoRead;
+      pDevice->pFifoHashOut = new t_FifoStd (pDevice->pFifoMemory, pDevice->FifoMaxBlocks);
+      pDevice->pFifoWrite   = pDevice->pFifoHashOut;
+   }
+   else if (!pDevice->HasHashThread() &&  pDevice->HasCompressionThreads())
+   {
+      Fifos = 2 * CONFIG(CompressionThreads);
+      CHK (TableFifoCalcSizeAndAlloc (pDevice, Fifos, &MaxBlocksInUse))
+      pDevice->pFifoCompressIn  = new t_FifoCompressIn  (pDevice->pFifoMemory, CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
+      pDevice->pFifoRead        = pDevice->pFifoCompressIn;
+      pDevice->pFifoCompressOut = new t_FifoCompressOut (pDevice->pFifoMemory, CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
+      pDevice->pFifoWrite       = pDevice->pFifoCompressOut;
+   }
+   else if ( pDevice->HasHashThread() &&  pDevice->HasCompressionThreads())
+   {
+      Fifos = 1 + 2 * CONFIG(CompressionThreads);
+      CHK (TableFifoCalcSizeAndAlloc (pDevice, Fifos, &MaxBlocksInUse))
+      pDevice->pFifoRead        = new t_FifoStd (pDevice->pFifoMemory, pDevice->FifoMaxBlocks);
+      pDevice->pFifoHashIn      = pDevice->pFifoRead;
+      pDevice->pFifoCompressIn  = new t_FifoCompressIn  (pDevice->pFifoMemory, CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
+      pDevice->pFifoHashOut     = pDevice->pFifoCompressIn;
+      pDevice->pFifoCompressOut = new t_FifoCompressOut (pDevice->pFifoMemory, CONFIG(CompressionThreads), pDevice->FifoMaxBlocks);
+      pDevice->pFifoWrite       = pDevice->pFifoCompressOut;
+   }
+
+   LOG_INFO ("Acquisition runs with %d fifos, each one with space for %d blocks of %d bytes (%0.1f MB FIFO space)",
+             Fifos, pDevice->FifoMaxBlocks, pDevice->FifoBlockSize,
+             ((double)Fifos * pDevice->FifoMaxBlocks * pDevice->FifoBlockSize) / BYTES_PER_MEGABYTE)
+   LOG_INFO ("Including the overhead, %u blocks of %d bytes have been allocated (%0.1f MB)",
+             MaxBlocksInUse, pDevice->FifoAllocBlockSize,
+             ((double)MaxBlocksInUse * pDevice->FifoAllocBlockSize) / BYTES_PER_MEGABYTE)
+
+   // Start threads
+   // -------------
+   pDevice->pThreadRead ->start(QThread::LowPriority);
+   if (pDevice->HasHashThread())
+      pDevice->pThreadHash->start(QThread::LowPriority);
+   for (int i=0; i < pDevice->ThreadCompressList.count(); i++)
+      pDevice->ThreadCompressList[i]->start(QThread::LowPriority);
+   pDevice->pThreadWrite->start(QThread::LowPriority);
+
+   pOwn->SlowDownAcquisitions = false;
+
    return NO_ERROR;
 }
 
@@ -486,23 +588,29 @@ static APIRET TableTimestampToISO (const QDateTime &Timestamp, QString &Str)
 APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
 {
    QString    MD5;
-   QString    MD5Verify;
+   QString    MD5VerifySrc;
+   QString    MD5VerifyDst;
    QString    SHA256;
-   QString    SHA256Verify;
+   QString    SHA256VerifySrc;
+   QString    SHA256VerifyDst;
    QString    StateStr;
    quint64    BadSectors;
    QString    StartStr, StopStr, VerifyStr;
    int        Hours, Minutes, Seconds;
    double     Speed;
+   bool       MatchSrc = true;
+   bool       MatchDst = true;
 
    CHK (pDevice->Info.WriteLn ())
    CHK (InfoAcquisitionBadSectors (pDevice, false))
-   if (!pDevice->StartTimestampVerify.isNull())
+   if (pDevice->Acquisition.VerifySrc)
       CHK (InfoAcquisitionBadSectors (pDevice, true))
    MD5 = tr("--", "Info file");
-   MD5Verify    = MD5;
-   SHA256       = MD5;
-   SHA256Verify = MD5;
+   MD5VerifySrc    = MD5;
+   MD5VerifyDst    = MD5;
+   SHA256          = MD5;
+   SHA256VerifySrc = MD5;
+   SHA256VerifyDst = MD5;
 
    switch (pDevice->State)
    {
@@ -511,15 +619,17 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
          BadSectors = t_Device::GetBadSectorCount(pDevice).toULongLong();
          if (BadSectors)
             StateStr += " " + tr("(with %1 bad sectors)", "Info file, may be appended to 'finished successfully' message") .arg(BadSectors);
-         if (pDevice->Acquisition.CalcHashes)
+         if (pDevice->Acquisition.CalcMD5   ) CHK (HashMD5DigestStr    (&pDevice->MD5Digest   , MD5   ))
+         if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256))
+         if (pDevice->Acquisition.VerifySrc)
          {
-            CHK (HashMD5DigestStr    (&pDevice->MD5Digest   , MD5   ))
-            CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256))
+            if (pDevice->Acquisition.CalcMD5   ) CHK (HashMD5DigestStr    (&pDevice->MD5DigestVerifySrc   , MD5VerifySrc   ))
+            if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256DigestVerifySrc, SHA256VerifySrc))
          }
-         if (pDevice->Acquisition.VerifySource)
+         if (pDevice->Acquisition.VerifyDst)
          {
-            CHK (HashMD5DigestStr    (&pDevice->MD5DigestVerify   , MD5Verify   ))
-            CHK (HashSHA256DigestStr (&pDevice->SHA256DigestVerify, SHA256Verify))
+            if (pDevice->Acquisition.CalcMD5   ) CHK (HashMD5DigestStr    (&pDevice->MD5DigestVerifyDst   , MD5VerifyDst   ))
+            if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256DigestVerifyDst, SHA256VerifyDst))
          }
          break;
 
@@ -535,15 +645,13 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
                else
                {
                   StateStr += tr("(during source verification)", "Info file");
-                  if (pDevice->Acquisition.CalcHashes)                            // If the user interrupted during verification (i.e. after
-                  {                                                               // acquisition), we can calculate the acquisition hash.
-                     CHK (HashMD5DigestStr    (&pDevice->MD5Digest   , MD5   ))
-                     CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256))
-                  }
+                  if (pDevice->Acquisition.CalcMD5   ) CHK (HashMD5DigestStr    (&pDevice->MD5Digest   , MD5   )) // If the user interrupted during verification (i.e. after
+                  if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256)) // acquisition), we can calculate the acquisition hash.
                }
                break;
-            case t_Device::ThreadWriteFileError: StateStr = tr("Aborted because of image write error", "Info file"); break;
-            default:                             StateStr = tr("Aborted, strange reason (%1)"        , "Info file") .arg(pDevice->AbortReason); break;
+            case t_Device::ThreadWriteWriteError : StateStr = tr("Aborted because of image write error"                   , "Info file"); break;
+            case t_Device::ThreadWriteVerifyError: StateStr = tr("Aborted because of image read error during verification", "Info file"); break;
+            default:                               StateStr = tr("Aborted, strange reason (%1)"                           , "Info file") .arg(pDevice->AbortReason); break;
          }
          break;
 
@@ -553,21 +661,34 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
    CHK (pDevice->Info.WriteLn (tr("State: %1", "Info file") .arg(StateStr)))
    CHK (pDevice->Info.WriteLn ())
 
-   CHK (pDevice->Info.AddRow (tr("MD5 hash:: %1"            , "Info file") .arg(MD5         )))
-   CHK (pDevice->Info.AddRow (tr("MD5 hash verified:: %1"   , "Info file") .arg(MD5Verify   )))
-   CHK (pDevice->Info.AddRow (tr("SHA256 hash:: %1"         , "Info file") .arg(SHA256      )))
-   CHK (pDevice->Info.AddRow (tr("SHA256 hash verified:: %1", "Info file") .arg(SHA256Verify)))
+   CHK (pDevice->Info.AddRow (tr("MD5 hash:: %1"                   , "Info file") .arg(MD5            )))
+   CHK (pDevice->Info.AddRow (tr("MD5 hash verified source:: %1"   , "Info file") .arg(MD5VerifySrc   )))
+   CHK (pDevice->Info.AddRow (tr("MD5 hash verified image:: %1"    , "Info file") .arg(MD5VerifyDst   )))
+   CHK (pDevice->Info.AddRow (tr("SHA256 hash:: %1"                , "Info file") .arg(SHA256         )))
+   CHK (pDevice->Info.AddRow (tr("SHA256 hash verified source:: %1", "Info file") .arg(SHA256VerifySrc)))
+   CHK (pDevice->Info.AddRow (tr("SHA256 hash verified image:: %1" , "Info file") .arg(SHA256VerifyDst)))
    CHK (pDevice->Info.WriteTable ());
-   if ((pDevice->State == t_Device::Finished) && pDevice->Acquisition.CalcHashes &&
-                                                 pDevice->Acquisition.VerifySource)
+
+   if ((pDevice->State == t_Device::Finished) && pDevice->Acquisition.VerifySrc)
    {
-      if (HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerify   ) &&
-          HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerify))
-           CHK (pDevice->Info.WriteLn (tr ("The hash values are identical. The device delivered the same data during acquisition and verification.")))
-      else CHK (pDevice->Info.WriteLn (tr ("The hash values differ. The device didn't deliver the same data during acquisition and verification. "
-                                           "Maybe you try to acquire the device once again. Check as well if the defect sector list was "
-                                           "the same during acquisition and verification (see above).")))
+      if (pDevice->Acquisition.CalcMD5)    MatchSrc =            HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerifySrc   );
+      if (pDevice->Acquisition.CalcSHA256) MatchSrc = MatchSrc | HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerifySrc);
+
+      if (MatchSrc) CHK (pDevice->Info.WriteLn (tr ("Source verification OK. The device delivered the same data during acquisition and verification.")))
+      else          CHK (pDevice->Info.WriteLn (tr ("Source verification FAILED. The device didn't deliver the same data during acquisition and verification. "
+                                                    "Check if the defect sector list was the same during acquisition and verification (see above).")))
    }
+   if ((pDevice->State == t_Device::Finished) && pDevice->Acquisition.VerifyDst)
+   {
+      if (pDevice->Acquisition.CalcMD5)    MatchDst =            HashMD5Match   (&pDevice->MD5Digest   , &pDevice->MD5DigestVerifyDst   );
+      if (pDevice->Acquisition.CalcSHA256) MatchDst = MatchDst | HashSHA256Match(&pDevice->SHA256Digest, &pDevice->SHA256DigestVerifyDst);
+
+      if (MatchDst) CHK (pDevice->Info.WriteLn (tr ("Image verification OK. The image contains exactely the data that was written.")))
+      else          CHK (pDevice->Info.WriteLn (tr ("Image verification FAILED. The data in the image is different from what was written.")))
+   }
+   if (!MatchSrc || !MatchDst)
+      CHK (pDevice->Info.WriteLn (tr ("Maybe you try to acquire the device again.")))
+
    CHK (pDevice->Info.WriteLn ())
 
    // Performance
@@ -579,7 +700,7 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
    Hours    = Seconds / SECONDS_PER_HOUR  ; Seconds -= Hours   * SECONDS_PER_HOUR;
    Minutes  = Seconds / SECONDS_PER_MINUTE; Seconds -= Minutes * SECONDS_PER_MINUTE;
 
-   if (pDevice->Acquisition.VerifySource)
+   if (pDevice->Acquisition.VerifySrc || pDevice->Acquisition.VerifyDst)
    {
       if (!pDevice->StartTimestampVerify.isNull())
            CHK (TableTimestampToISO (pDevice->StartTimestampVerify , VerifyStr))
@@ -590,8 +711,8 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
       CHK (pDevice->Info.AddRow (tr("Ended:: %1 (%2 hours, %3 minutes and %4 seconds)", "Info file").arg(StopStr ) .arg(Hours) .arg(Minutes) .arg(Seconds)))
 
       if (pDevice->StartTimestampVerify.isNull())
-           Seconds = pDevice->StartTimestamp.secsTo (pDevice->StopTimestamp);
-      else Seconds = pDevice->StartTimestamp.secsTo (pDevice->StartTimestampVerify);
+           Seconds = GETMAX (pDevice->StartTimestamp.secsTo (pDevice->StopTimestamp)       , 1);
+      else Seconds = GETMAX (pDevice->StartTimestamp.secsTo (pDevice->StartTimestampVerify), 1);
       Speed = (double) pDevice->CurrentReadPos / ((double)BYTES_PER_MEGABYTE * (double)Seconds);
       Hours   = Seconds / SECONDS_PER_HOUR  ; Seconds -= Hours   * SECONDS_PER_HOUR;
       Minutes = Seconds / SECONDS_PER_MINUTE; Seconds -= Minutes * SECONDS_PER_MINUTE;
@@ -599,7 +720,7 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
 
       if (!pDevice->StartTimestampVerify.isNull())
       {
-         Seconds = pDevice->StartTimestampVerify.secsTo (pDevice->StopTimestamp);
+         Seconds = GETMAX (pDevice->StartTimestampVerify.secsTo (pDevice->StopTimestamp), 1);
          Speed = (double) pDevice->CurrentReadPos / ((double)BYTES_PER_MEGABYTE * (double)Seconds);
          Hours   = Seconds / SECONDS_PER_HOUR  ; Seconds -= Hours   * SECONDS_PER_HOUR;
          Minutes = Seconds / SECONDS_PER_MINUTE; Seconds -= Minutes * SECONDS_PER_MINUTE;
@@ -612,7 +733,7 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
       CHK (pDevice->Info.AddRow (tr("Acquisition started:: %1"                        , "Info file").arg(StartStr)))
       CHK (pDevice->Info.AddRow (tr("Ended:: %1 (%2 hours, %3 minutes and %4 seconds)", "Info file").arg(StopStr ) .arg(Hours) .arg(Minutes) .arg(Seconds)))
 
-      Seconds = pDevice->StartTimestamp.secsTo (pDevice->StopTimestamp);
+      Seconds = GETMAX (pDevice->StartTimestamp.secsTo (pDevice->StopTimestamp), 1);
       Speed = (double) pDevice->CurrentReadPos / ((double)BYTES_PER_MEGABYTE * (double)Seconds);
       Hours   = Seconds / SECONDS_PER_HOUR  ; Seconds -= Hours   * SECONDS_PER_HOUR;
       Minutes = Seconds / SECONDS_PER_MINUTE; Seconds -= Minutes * SECONDS_PER_MINUTE;
@@ -632,6 +753,8 @@ APIRET t_Table::FinaliseThreadStructs (t_pDevice pDevice)
        (pDevice->pThreadHash  == NULL) &&        // we must not kill vital structures as long as any threads are
        (pDevice->ThreadCompressList.isEmpty()))  // still running).
    {
+      pDevice->StopTimestamp = QDateTime::currentDateTime();
+
       if      (!pDevice->HasHashThread() && !pDevice->HasCompressionThreads())
       {
          delete pDevice->pFifoRead;
@@ -678,7 +801,7 @@ APIRET t_Table::FinaliseThreadStructs (t_pDevice pDevice)
 
 void t_Table::SlotThreadReadFinished (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Reading thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("Acquisition of %s: Read thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
    pDevice->pThreadRead->deleteLater();
    pDevice->pThreadRead = NULL;
 
@@ -729,7 +852,7 @@ void t_Table::SlotThreadCompressFinished (t_pDevice pDevice, int ThreadNr)
 
 void t_Table::SlotThreadWriteFinished (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Writing thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("Acquisition of %s: Write thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
 
    pDevice->pThreadWrite->deleteLater();
    pDevice->pThreadWrite = NULL;
@@ -740,11 +863,22 @@ void t_Table::SlotThreadWriteFinished (t_pDevice pDevice)
    CHK_EXIT (FinaliseThreadStructs (pDevice))
 }
 
+void t_Table::SlotThreadWriteWakeThreads (t_pDevice pDevice)
+{
+   LOG_INFO ("Acquisition of %s: Write thread asks other threads for releasing its handle", QSTR_TO_PSZ (pDevice->LinuxDevice))
+
+   if (pDevice->AbortRequest)
+   {
+      LOG_INFO ("Acquisition of %s: Calling WakeWaitingThreads", QSTR_TO_PSZ (pDevice->LinuxDevice))
+      CHK_EXIT (WakeWaitingThreads(pDevice))
+   }
+}
+
 APIRET t_Table::AbortAcquisition0 (t_pDevice pDevice)
 {
-   if (pDevice->pThreadRead == NULL)
+   if (pDevice->AbortRequest)
    {
-      LOG_INFO ("User pressed abort, but acquisition on %s is no longer running (it probably ended between the user's click and this message)", QSTR_TO_PSZ(pDevice->LinuxDevice))
+      LOG_INFO ("User pressed abort, but abort flag for acquisition on %s is already set.", QSTR_TO_PSZ(pDevice->LinuxDevice))
       return NO_ERROR;
    }
 
@@ -761,10 +895,15 @@ APIRET t_Table::AbortAcquisition (t_pDevice pDevice)
 {
    bool Abort;
 
-   CHK (t_DlgAbort::Show (pDevice, Abort, pDevice->DeleteAfterAbort))
+   if (pDevice->AbortRequest)
+        Abort = true;
+   else CHK (t_DlgAbort::Show (pDevice, Abort, pDevice->DeleteAfterAbort))
+
    if (Abort)
+   {
+      pDevice->AbortCount++;
       CHK (AbortAcquisition0 (pDevice))
-
+   }
    return NO_ERROR;
 }
 
diff --git a/table.h b/table.h
index 36a5acb..2102965 100644
--- a/table.h
+++ b/table.h
@@ -25,6 +25,7 @@
 #endif
 
 class t_TableLocal;
+class t_MainWindow;
 
 class t_Table: public QTableView
 {
@@ -32,7 +33,7 @@ class t_Table: public QTableView
 
    public:
       t_Table ();
-      t_Table (QWidget *pParent, t_pDeviceList pDeviceList);
+      t_Table (QWidget *pParent, t_MainWindow *pMainWindow, t_pDeviceList pDeviceList);
      ~t_Table ();
 
       APIRET AbortAllAcquisitions (void);
@@ -40,7 +41,7 @@ class t_Table: public QTableView
 
    private:
       APIRET ShowDeviceInfo            (t_pcDevice pDevice);
-      APIRET StartAcquisition          (t_pDevice  pDevice);
+      APIRET StartAcquisition          (t_pDevice  pDevice, bool Clone);
       APIRET AbortAcquisition0         (t_pDevice  pDevice);
       APIRET AbortAcquisition          (t_pDevice  pDevice);
       APIRET InfoAcquisitionStart      (t_pDevice  pDevice);
@@ -58,6 +59,7 @@ class t_Table: public QTableView
       void SlotThreadWriteFinished    (t_pDevice pDevice);
       void SlotThreadHashFinished     (t_pDevice pDevice);
       void SlotThreadCompressFinished (t_pDevice pDevice, int ThreadNr);
+      void SlotThreadWriteWakeThreads (t_pDevice pDevice);
 
    signals:
       void SignalDeviceSelected (t_pDevice pDevice);
diff --git a/threadcompress.cpp b/threadcompress.cpp
index cc92069..a1cd1c2 100644
--- a/threadcompress.cpp
+++ b/threadcompress.cpp
@@ -82,11 +82,7 @@ void t_ThreadCompress::run (void)
    pDevice  = pOwn->pDevice;
 
    if (pDevice->Acquisition.Format == t_File::EWF)
-   {
-      CompressedMaxSize = (size_t) (pDevice->FifoBlockSize *1.001) + 12; // see zlib documentation
-      if (CompressedMaxSize > t_Fifo::GetCompressionOptimisedBufferSize (pDevice->FifoBlockSize))
-         CHK_EXIT (ERROR_THREADCOMPRESS_COMPRESSION_BUFFER_TOO_SMALL)
-   }
+      CompressedMaxSize = (size_t) (pDevice->FifoBlockSize * 1.001) + 12; // see zlib documentation
 
    CHK_EXIT (pDevice->pThreadWrite->GetpFileHandle ((void **)&pEwfHandle))
    CHK_EXIT (pDevice->pFifoCompressIn ->GetSubFifo (SubFifoNr, pFifoIn ))
@@ -101,7 +97,7 @@ void t_ThreadCompress::run (void)
          switch (pDevice->Acquisition.Format)
          {
             case t_File::EWF:
-               CHK_EXIT (t_Fifo::CreateCompressionOptimised (pFifoBlockOut, pDevice->FifoBlockSize))
+               CHK_EXIT (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlockOut, pDevice->FifoAllocBlockSize))
 
                CompressedSize          = CompressedMaxSize;   // Must be initialised with the max buffer size (we use this one instead of MULTITHREADED_COMPRESSION_FIFO_BLOCK_SIZE in order to check if ti works as tols in the zlib docu)
                pFifoBlockOut->Nr       = pFifoBlockIn->Nr;
@@ -115,7 +111,7 @@ void t_ThreadCompress::run (void)
                if (pFifoBlockOut->EwfCompressionUsed)
                {
                   pFifoBlockOut->EwfDataSize = CompressedSize;   // Data to be forwarded is contained in
-                  CHK_EXIT (t_Fifo::Destroy (pFifoBlockIn))      // pFifoBlockOut, pFifoBlockIn no longer needed.
+                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))     // pFifoBlockOut, pFifoBlockIn no longer needed.
                }
                else
                {
@@ -123,8 +119,8 @@ void t_ThreadCompress::run (void)
                   pFifoBlockIn->EwfCompressionUsed = pFifoBlockOut->EwfCompressionUsed;
                   pFifoBlockIn->EwfChunkCRC        = pFifoBlockOut->EwfChunkCRC;
                   pFifoBlockIn->EwfWriteCRC        = pFifoBlockOut->EwfWriteCRC;
-                  CHK_EXIT (t_Fifo::Destroy (pFifoBlockOut))                     // No compression, we'll forward the
-                  pFifoBlockOut = pFifoBlockIn;                                  // original block we received
+                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockOut))    // No compression, we'll forward the
+                  pFifoBlockOut = pFifoBlockIn;                                       // original block we received
                }
 
                if (rc != (ssize_t) pFifoBlockOut->EwfDataSize)
@@ -138,7 +134,7 @@ void t_ThreadCompress::run (void)
 
             case t_File::AFF:
 //               LOG_ERROR ("AaffPreprocess")
-               CHK_EXIT (t_Fifo::CreateCompressionOptimised (pFifoBlockOut, pDevice->FifoBlockSize))
+               CHK_EXIT (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlockOut, pDevice->FifoAllocBlockSize))
                pFifoBlockOut->Nr       = pFifoBlockIn->Nr;
                pFifoBlockOut->DataSize = pFifoBlockIn->DataSize;
 
@@ -146,12 +142,12 @@ void t_ThreadCompress::run (void)
 
                if (pFifoBlockOut->pAaffPreprocess->Compressed)
                {
-                  CHK_EXIT (t_Fifo::Destroy (pFifoBlockIn))
+                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))
                }
                else
                {
                   pFifoBlockIn->pAaffPreprocess = pFifoBlockOut->pAaffPreprocess;
-                  CHK_EXIT (t_Fifo::Destroy (pFifoBlockOut))
+                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockOut))
                   pFifoBlockOut = pFifoBlockIn;
                }
                break;
@@ -167,6 +163,7 @@ void t_ThreadCompress::run (void)
          Finished = true;
       }
    }
+   CHK_EXIT (pDevice->pThreadWrite->ReleaseFileHandle ())
 
    LOG_INFO ("Compression thread #%d exits now (device %s, %Ld blocks processed)", pOwn->ThreadNr, QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks)
 }
diff --git a/threadhash.cpp b/threadhash.cpp
index be3e644..0ed966c 100644
--- a/threadhash.cpp
+++ b/threadhash.cpp
@@ -70,20 +70,20 @@ void t_ThreadHash::run (void)
    {
       *pBlocks = 0;
       Finished = false;
-      CHK_EXIT (HashMD5Init    (&HashContextMD5   ))
-      CHK_EXIT (HashSHA256Init (&HashContextSHA256))
+      if (pDevice->Acquisition.CalcMD5   ) CHK_EXIT (HashMD5Init    (&HashContextMD5   ))
+      if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Init (&HashContextSHA256))
       do
       {
          CHK_EXIT (pDevice->pFifoHashIn->Get (pFifoBlock))
          if (pFifoBlock)
          {
             (*pBlocks)++;
-            CHK_EXIT (HashMD5Append    (&HashContextMD5   , pFifoBlock->Buffer, pFifoBlock->DataSize))
-            CHK_EXIT (HashSHA256Append (&HashContextSHA256, pFifoBlock->Buffer, pFifoBlock->DataSize))
+            if (pDevice->Acquisition.CalcMD5   ) CHK_EXIT (HashMD5Append    (&HashContextMD5   , pFifoBlock->Buffer, pFifoBlock->DataSize))
+            if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Append (&HashContextSHA256, pFifoBlock->Buffer, pFifoBlock->DataSize))
             if (VerifyLoop)
             {
-               pDevice->IncCurrentVerifyPos(pFifoBlock->DataSize);
-               CHK_EXIT (t_Fifo::Destroy              (pFifoBlock))
+               pDevice->IncCurrentVerifyPosSrc (pFifoBlock->DataSize);
+               CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlock))
             }
             else
             {
@@ -102,26 +102,28 @@ void t_ThreadHash::run (void)
       }
       else if (VerifyLoop)
       {
-         CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5DigestVerify   ))
-         CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256DigestVerify))
+         if (pDevice->Acquisition.CalcMD5   ) CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5DigestVerifySrc   ))
+         if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256DigestVerifySrc))
          break;
       }
-      else if (pDevice->Acquisition.VerifySource)
-      {
-         CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5Digest   ))
-         CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256Digest))
-         pBlocks = &BlocksVerified;
-         VerifyLoop = true;
-      }
       else
       {
-         CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5Digest   ))
-         CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256Digest))
-         break;
+         if (pDevice->Acquisition.CalcMD5   ) CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5Digest   ))
+         if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256Digest))
+         if (pDevice->Acquisition.VerifySrc)
+         {
+            pBlocks = &BlocksVerified;
+            VerifyLoop = true;
+            CHK_EXIT (pDevice->pFifoHashOut->InsertDummy ())  // Make compression threads know they can end
+         }
+         else
+         {
+            break;
+         }
       }
    }
 
-   if (pDevice->Acquisition.VerifySource)
+   if (pDevice->Acquisition.VerifySrc)
         LOG_INFO ("Hash thread exits now (device %s, %Ld blocks processed, %Ld blocks verified)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated, BlocksVerified)
    else LOG_INFO ("Hash thread exits now (device %s, %Ld blocks processed)"                     , QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated)
 }
diff --git a/threadread.cpp b/threadread.cpp
index 07bb582..a851b91 100644
--- a/threadread.cpp
+++ b/threadread.cpp
@@ -20,7 +20,7 @@
 #include "threadwrite.h"
 
 #include "fcntl.h"
-//##define _GNU_SOURCE
+//#define _GNU_SOURCE
 
 const int THREADREAD_CHECK_CONNECTED_SLEEP = 1000;
 const int THREADREAD_SLOWDOWN_SLEEP        =  700;
@@ -29,8 +29,8 @@ const int THREADREAD_SLOWDOWN_SLEEP        =  700;
 class t_ThreadReadLocal
 {
    public:
-      t_pDevice     pDevice;
-      bool         *pSlowDownRequest;
+      t_pDevice  pDevice;
+      bool      *pSlowDownRequest;
 };
 
 t_ThreadRead::t_ThreadRead(void)
@@ -86,86 +86,67 @@ static APIRET ThreadReadCheckDeviceExists (t_pcDevice pDevice, bool &DeviceExist
    return NO_ERROR;
 }
 
-static APIRET ThreadReadDeviceDisconnected (t_pDevice pDevice)
+static APIRET ThreadReadDeviceDisconnected (t_pDevice pDevice, const char* pStrAction)
 {
-   if (pDevice->pFileSrc)
+   if (pDevice->FileDescSrc != t_Device::FileDescEmpty)
    {
-      (void) fclose (pDevice->pFileSrc);
-      pDevice->pFileSrc = NULL;
+      (void) close (pDevice->FileDescSrc);
+      pDevice->FileDescSrc = t_Device::FileDescEmpty;
    }
    if (pDevice->State == t_Device::Acquire)
         pDevice->State = t_Device::AcquirePaused;
    else pDevice->State = t_Device::VerifyPaused;
-   LOG_INFO ("Device %s disconnected, switching device state to %s", QSTR_TO_PSZ(pDevice->LinuxDevice), pDevice->StateStr())
+   LOG_INFO ("Device %s disconnected (%s, %d, %s), switching device state to %s", QSTR_TO_PSZ(pDevice->LinuxDevice), pStrAction, errno, strerror(errno), pDevice->StateStr())
 
    return ERROR_THREADREAD_DEVICE_DISCONNECTED;
 }
 
 static APIRET ThreadReadAdjustSeek (t_pDevice pDevice)        // According to the GNU Clib docu, a seek should be done after read errors
 {
-   int rc;
+   off64_t rc;
 
-   if (pDevice->pFileSrc == NULL)
+   if (pDevice->FileDescSrc == t_Device::FileDescEmpty)
       CHK (ERROR_THREADREAD_FILESRC_NOT_OPEN)
 
    if (ThreadReadEOF (pDevice))
       return NO_ERROR;
 
-   rc = fseeko64 (pDevice->pFileSrc, (off64_t)pDevice->CurrentReadPos, SEEK_SET);
-   if (rc)
-      CHK_RET (ThreadReadDeviceDisconnected (pDevice))
+   rc = lseek64 (pDevice->FileDescSrc, (off64_t)pDevice->CurrentReadPos, SEEK_SET);
+   if (rc < 0)
+      CHK_RET (ThreadReadDeviceDisconnected (pDevice, "seek"))
 
    return NO_ERROR;
 }
 
-//static APIRET ThreadReadDirectMode (FILE *pFileSrc, bool Enable)
-//{
-//   int OldFlags, NewFlags, rc;
-//   int FileDescriptor;
-//
-//   FileDescriptor = fileno (pFileSrc);
-//   if (FileDescriptor == -1)
-//      CHK (ERROR_THREADREAD_BAD_FILE_HANDLE)
-//
-//   OldFlags = fcntl (FileDescriptor, F_GETFL);
-//   if (OldFlags > 0)
-//   {
-//      NewFlags = (Enable ? (OldFlags |  O_DIRECT)
-//                         : (OldFlags & ~O_DIRECT));
-//      if (NewFlags != OldFlags)
-//      {
-//         rc = fcntl (FileDescriptor, F_SETFL, NewFlags);
-//         if (rc == -1)
-//            LOG_INFO ("Setting flags with fcntl failed. Direct mode state unknown.")
-//      }
-//      LOG_INFO ("Direct mode %s", Enable ? "enabled" : "disabled")
-//   }
-//   else
-//   {
-//      LOG_INFO ("Reading flags with fcntl failed. Direct mode remains unchanged")
-//   }
-//
-//   return NO_ERROR;
-//}
 
 static APIRET ThreadReadBlock0 (t_pDevice pDevice, unsigned char *pBuffer, unsigned int Size)
 {
-   bool DeviceExists;
-   int  Read;
+   bool    DeviceExists;
+   ssize_t Read;
+   int     OpenFlags;
 
    errno = 0;
-   if (pDevice->pFileSrc == NULL)
+   if (pDevice->FileDescSrc == t_Device::FileDescEmpty)
    {
-      pDevice->pFileSrc = fopen64 (QSTR_TO_PSZ(pDevice->LinuxDevice), "r");
-      if (!pDevice->pFileSrc)
-         CHK_RET (ThreadReadDeviceDisconnected (pDevice))
+      OpenFlags = O_RDONLY | O_NOATIME;
+      if (CONFIG (FifoMemoryManager))     // We need the buffers to be located on page size (4K) boundaries; this only
+      {                                   // is guaranteed when working with Guymager's internal memory manager (see t_FifoMemory::t_FifoMemory)
+         LOG_INFO ("Trying direct mode for %s", QSTR_TO_PSZ(pDevice->LinuxDevice))
+         OpenFlags |= O_DIRECT;
+      }
+      pDevice->FileDescSrc = open64 (QSTR_TO_PSZ(pDevice->LinuxDevice), OpenFlags);
+      if ((pDevice->FileDescSrc < 0) && (OpenFlags & O_DIRECT) && (errno == EINVAL))   // If an invalid parameter is reported, O_DIRECT might have
+      {                                                                                // caused problems. This was observed when opening files
+         OpenFlags &= ~O_DIRECT;                                                       // (added as special device) on the cases server (dd reported
+         pDevice->FileDescSrc = open64 (QSTR_TO_PSZ(pDevice->LinuxDevice), OpenFlags); // the same error with iflag=direct). Try again without it.
+      }
+      LOG_INFO ("Direct mode for %s switched %s", QSTR_TO_PSZ(pDevice->LinuxDevice), (OpenFlags & O_DIRECT) ? "on":"off")
+      if (pDevice->FileDescSrc < 0)
+         CHK_RET (ThreadReadDeviceDisconnected (pDevice, "open"))
       CHK_RET (ThreadReadAdjustSeek (pDevice))
-
-//      CHK (ThreadReadDirectMode (pDevice->pFileSrc, true))
    }
 
-   Read = (int) fread (pBuffer, Size, 1, pDevice->pFileSrc); //lint !e732 !e712 loss of sign/precision arg 2
-   // ev. zusaetzlich ferror abfragen
+   Read = read (pDevice->FileDescSrc, pBuffer, Size);
 
 // Bad sector simulation
 //   if ((pDevice->CurrentReadPos > 500000) && (pDevice->CurrentReadPos < 600000) ||
@@ -173,29 +154,23 @@ static APIRET ThreadReadBlock0 (t_pDevice pDevice, unsigned char *pBuffer, unsig
 //       (pDevice->CurrentReadPos == 0) || (pDevice->CurrentReadPos == 512) || (pDevice->CurrentReadPos == 1024))
 //      Read = 0;
 
-   switch (Read)
+   if (Read == (ssize_t)Size)
    {
-      case  1: pDevice->CurrentReadPos += Size;
-               return NO_ERROR;
-
-      case  0:
-//               LOG_INFO ("Read error at position %lld", pDevice->CurrentReadPos)
-
-               CHK (ThreadReadCheckDeviceExists (pDevice, DeviceExists))
-               if (DeviceExists)
-               {
-//                  LOG_DEBUG ("Device still exists")
-                  CHK_RET (ThreadReadAdjustSeek (pDevice))
-//                  LOG_DEBUG ("Seek adjusted")
-                  return ERROR_THREADREAD_NO_DATA;
-               }
-               else
-               {
-                  CHK_RET (ThreadReadDeviceDisconnected (pDevice))
-               }
-               break;
-
-      default: CHK_CONST (ERROR_THREADREAD_UNEXPECTED_FAILURE)
+      pDevice->CurrentReadPos += Size;
+      return NO_ERROR;
+   }
+   else
+   {
+      CHK (ThreadReadCheckDeviceExists (pDevice, DeviceExists))
+      if (DeviceExists)
+      {
+         CHK_RET (ThreadReadAdjustSeek (pDevice))
+         return ERROR_THREADREAD_NO_DATA;
+      }
+      else
+      {
+         CHK_RET (ThreadReadDeviceDisconnected (pDevice, "read"))
+      }
    }
 
    return NO_ERROR;
@@ -225,9 +200,7 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
    if (BytesToRead > INT_MAX)
       CHK (ERROR_THREADREAD_BLOCKSIZE)
 
-   if (pDevice->HasCompressionThreads())
-        CHK (t_Fifo::CreateCompressionOptimised (pFifoBlock, pDevice->FifoBlockSize))
-   else CHK (t_Fifo::Create (pFifoBlock, (unsigned int) BytesToRead))
+   CHK (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlock, pDevice->FifoAllocBlockSize))
 
    pFifoBlock->DataSize = (unsigned int) BytesToRead;
    pBuffer = pFifoBlock->Buffer;
@@ -249,9 +222,8 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
             if (!pDevice->FallbackMode)
             {
                pDevice->FallbackMode = true;
-//               ReadTry = (int) std::min (pDevice->SectorSize, pDevice->SectorSizePhys);
+//               ReadTry = (int) GETMIN (pDevice->SectorSize, pDevice->SectorSizePhys);
                ReadTry = pDevice->SectorSize;
-//               CHK (ThreadReadDirectMode (pDevice->pFileSrc, true))
                LOG_INFO ("Device read error, switching %s to slow fallback mode. Reading sectors individually from now on.", QSTR_TO_PSZ(pDevice->LinuxDevice))
             }
             else
@@ -291,14 +263,14 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
    if ((pDevice->State == t_Device::AcquirePaused) ||
        (pDevice->State == t_Device::VerifyPaused ))
    {
-      CHK (t_Fifo::Destroy (pFifoBlock))
+      CHK (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlock))
       pDevice->CurrentReadPos = PrevReadPos;
 
       return ERROR_THREADREAD_DEVICE_DISCONNECTED;
    }
    else if (pDevice->AbortRequest)
    {
-      CHK (t_Fifo::Destroy (pFifoBlock))
+      CHK (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlock))
 
       return ERROR_THREADREAD_DEVICE_ABORTED;
    }
@@ -306,7 +278,6 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
    {
       pDevice->FallbackMode = false;  // Switch to fast reading mode if last read was good
       LOG_INFO ("Device read ok again. Switching %s to fast block read.", QSTR_TO_PSZ(pDevice->LinuxDevice))
-//      CHK (ThreadReadDirectMode (pDevice->pFileSrc, false))
    }
 
    pFifoBlock->LastBlock = ThreadReadEOF (pDevice);
@@ -320,7 +291,8 @@ void t_ThreadRead::run (void)
    t_pFifoBlock       pFifoBlock;
    APIRET              rc;
    int                 rcf;
-   bool                CalcHashes;
+   bool                CalcHashMD5;
+   bool                CalcHashSHA256;
    quint64           *pBlocks;
    quint64             BlocksRead     = 0;
    quint64             BlocksVerified = 0;
@@ -329,22 +301,21 @@ void t_ThreadRead::run (void)
    t_HashContextMD5    HashContextMD5;
    t_HashContextSHA256 HashContextSHA256;
 
-   LOG_INFO ("Acquisition of %s: Reading thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   LOG_INFO ("Acquisition of %s: Read thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
    pDevice = pOwn->pDevice;
-   CalcHashes = pDevice->Acquisition.CalcHashes && !CONFIG (UseSeparateHashThread);
+   CalcHashMD5    = pDevice->Acquisition.CalcMD5    && !CONFIG (UseSeparateHashThread);
+   CalcHashSHA256 = pDevice->Acquisition.CalcSHA256 && !CONFIG (UseSeparateHashThread);
+
    pBlocks = &BlocksRead;
    pDevice->State = t_Device::Acquire;
    for (;;)
    {
-      pDevice->pFileSrc       = NULL;
+      pDevice->FileDescSrc    = t_Device::FileDescEmpty;
       pDevice->CurrentReadPos = 0;
       pDevice->FallbackMode   = false;
       *pBlocks = 0;
-      if (CalcHashes)
-      {
-         CHK_EXIT (HashMD5Init    (&HashContextMD5   ))
-         CHK_EXIT (HashSHA256Init (&HashContextSHA256))
-      }
+      if (CalcHashMD5)    CHK_EXIT (HashMD5Init    (&HashContextMD5   ))
+      if (CalcHashSHA256) CHK_EXIT (HashSHA256Init (&HashContextSHA256))
       do
       {
          if (*(pOwn->pSlowDownRequest))
@@ -356,15 +327,13 @@ void t_ThreadRead::run (void)
             case NO_ERROR:
                pFifoBlock->Nr = (*pBlocks);
 
-               if (CalcHashes)
-               {
-                  CHK_EXIT (HashMD5Append    (&HashContextMD5   , pFifoBlock->Buffer, pFifoBlock->DataSize))
-                  CHK_EXIT (HashSHA256Append (&HashContextSHA256, pFifoBlock->Buffer, pFifoBlock->DataSize))
-               }
-               if ((pDevice->State == t_Device::Verify) && CalcHashes)
+               if (CalcHashMD5)    CHK_EXIT (HashMD5Append    (&HashContextMD5   , pFifoBlock->Buffer, pFifoBlock->DataSize))
+               if (CalcHashSHA256) CHK_EXIT (HashSHA256Append (&HashContextSHA256, pFifoBlock->Buffer, pFifoBlock->DataSize))
+
+               if ((pDevice->State == t_Device::Verify) && (CalcHashMD5 || CalcHashSHA256))
                {
-                  pDevice->IncCurrentVerifyPos(pFifoBlock->DataSize);
-                  CHK_EXIT (t_Fifo::Destroy (pFifoBlock))
+                  pDevice->IncCurrentVerifyPosSrc (pFifoBlock->DataSize);
+                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlock))
                }
                else
                {
@@ -387,39 +356,38 @@ void t_ThreadRead::run (void)
          }
       } while (!ThreadReadEOF(pDevice) && !pDevice->AbortRequest);
 
+      if (pDevice->AbortRequest)
+         break;
+
       if (pDevice->State == t_Device::Acquire)
            BytesRead     = pDevice->CurrentReadPos;
       else BytesVerified = pDevice->CurrentReadPos;
 
-      if (pDevice->AbortRequest)
-         break;
-
       if (pDevice->State == t_Device::Verify)
       {
-         if (CalcHashes)
-         {
-            CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5DigestVerify   ))
-            CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256DigestVerify))
-         }
+         if (CalcHashMD5)    CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5DigestVerifySrc   ))
+         if (CalcHashSHA256) CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256DigestVerifySrc))
          LOG_INFO ("Source verification completed (device %s)", QSTR_TO_PSZ (pDevice->LinuxDevice))
          break;
       }
 
-      if (CalcHashes)
+      if (CalcHashMD5)    CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5Digest   ))
+      if (CalcHashSHA256) CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256Digest))
+
+      if ((pDevice->Acquisition.VerifySrc) ||
+          (pDevice->Acquisition.VerifyDst))
       {
-         CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5Digest   ))
-         CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256Digest))
+         pDevice->State = t_Device::Verify;
+         pDevice->StartTimestampVerify = QDateTime::currentDateTime();
       }
 
-      if (pDevice->Acquisition.VerifySource)
+      if (pDevice->Acquisition.VerifySrc)
       {
-         (void) fclose (pDevice->pFileSrc);
+         (void) close (pDevice->FileDescSrc);
          LOG_INFO ("All data has been read (device %s), now re-reading for source verification", QSTR_TO_PSZ (pDevice->LinuxDevice))
-         pDevice->State = t_Device::Verify;
-         pDevice->StartTimestampVerify = QDateTime::currentDateTime();
          pBlocks = &BlocksVerified;
-         if (!CalcHashes)
-            CHK_EXIT (pDevice->pFifoRead->InsertDummy ())
+//         if (CONFIG (UseSeparateHashThread))
+         CHK_EXIT (pDevice->pFifoRead->InsertDummy ())
       }
       else
       {
@@ -428,21 +396,21 @@ void t_ThreadRead::run (void)
       }
    }
 
-   if (pDevice->pFileSrc)
+   if (pDevice->FileDescSrc != t_Device::FileDescEmpty)
    {
-      rcf = fclose (pDevice->pFileSrc);
-      pDevice->pFileSrc = NULL;
+      rcf = close (pDevice->FileDescSrc);
+      pDevice->FileDescSrc = t_Device::FileDescEmpty;
       if (rcf)
       {
-         LOG_INFO ("Unexpected error on fclose, errno = %d", errno)
+         LOG_INFO ("Unexpected error on close, errno = %d", errno)
          pDevice->AbortReason  = t_Device::ThreadReadFileError;
          pDevice->AbortRequest = true;
       }
    }
 
-   LOG_INFO ("Reading thread exits now (device %s, %Ld blocks read, %llu bytes)", QSTR_TO_PSZ (pDevice->LinuxDevice), BlocksRead, BytesRead)
-   if (pDevice->Acquisition.VerifySource)
-   LOG_INFO ("                    (for the verification: %Ld blocks read, %llu bytes)", BlocksVerified, BytesVerified)
+   LOG_INFO ("Read thread exits now (device %s, %Ld blocks read, %llu bytes)", QSTR_TO_PSZ (pDevice->LinuxDevice), BlocksRead, BytesRead)
+   if (pDevice->Acquisition.VerifySrc)
+   LOG_INFO ("             (for the source verification: %Ld blocks read, %llu bytes)", BlocksVerified, BytesVerified)
 }
 
 void t_ThreadRead::SlotFinished (void)
diff --git a/threadscan.cpp b/threadscan.cpp
index 63284bf..ba248c2 100644
--- a/threadscan.cpp
+++ b/threadscan.cpp
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "device.h"
 #include "qtutil.h"
+#include "media.h"
 #include "threadscan.h"
 
 // --------------------------
@@ -29,7 +30,8 @@
 const int THREADSCAN_WAIT_MAX         = 5000;
 const int THREADSCAN_WAIT_GRANULARITY = 100;
 
-#define   LIBPARTED  "libparted.so"
+const QString ThreadScanLibPartedSearchDirs    = "/lib,/usr/lib,/usr/local/lib";       // Separate directories by commas
+const QString ThreadScanLibPartedSearchPattern = "libparted-*.so*";
 
 // -----------------------------------
 //  Utility functions used by workers
@@ -46,7 +48,8 @@ static APIRET ThreadScanMarkLocalDevices (const t_pDeviceList pDeviceList)
    {
       pDevice = pDeviceList->at (i);
       pDevice->Local = pLocalDevices->contains (pDevice->SerialNumber) ||
-                       pLocalDevices->contains (pDevice->LinuxDevice );
+                       pLocalDevices->contains (pDevice->LinuxDevice ) ||
+                       pLocalDevices->contains (pDevice->Model       );
    }
    return NO_ERROR;
 }
@@ -98,37 +101,91 @@ static APIRET ThreadScanGetSerialNumber (char const *pcDeviceName, QString &Seri
    return NO_ERROR;
 }
 
-t_ThreadScanWorkerParted::t_ThreadScanWorkerParted (APIRET &rc)
+
+static APIRET ThreadScanFindLibparted (QStringList &Files)
 {
-   char *pErrStr;
+   QStringList    SearchDirs;
+   QDir         *pSearchDir;
+   QFileInfoList  FileInfoList;
+   QFileInfo      FileInfo;
+   int            i;
 
-   pOwn = new t_ThreadScanWorkerPartedLocal();
+   SearchDirs = ThreadScanLibPartedSearchDirs.split(",");
 
-   pOwn->pLibPartedHandle = dlopen (LIBPARTED, RTLD_NOW);
-   if (pOwn->pLibPartedHandle == NULL)
+   for (i=0; i<SearchDirs.size(); i++)
    {
-      LOG_INFO ("%s cannot be found (%s).", LIBPARTED, dlerror());
-      rc = ERROR_THREADSCAN_LIBPARTED_NOTWORKING;
-      return;
+      pSearchDir = new QDir (SearchDirs[i]);
+      FileInfoList = pSearchDir->entryInfoList (QStringList(ThreadScanLibPartedSearchPattern),
+                                                 QDir::Files | QDir::NoSymLinks,
+                                                 QDir::Name);
+      delete pSearchDir;
+      while (!FileInfoList.isEmpty())
+      {
+         FileInfo = FileInfoList.takeFirst();
+         LOG_INFO ("libparted found: %s", QSTR_TO_PSZ(FileInfo.absoluteFilePath()));
+         Files += FileInfo.absoluteFilePath();
+      }
    }
+   if (Files.empty())
+      LOG_INFO ("\nNo libparted could be found")
+
+   return NO_ERROR;
+}
+
+
+t_ThreadScanWorkerParted::t_ThreadScanWorkerParted (APIRET &rc)
+{
+   QStringList   FilenameList;
+   QString       Filename;
+   char        *pErrStr;
+   int           i;
+   bool          Found = false;
 
-   // GETFN: See dlsym documentation concerning the usage of dlerror for error checking
-   #define GETFN(pFn, Type, pFnName)                                           \
-      dlerror();                                                               \
-      pFn = (Type)dlsym (pOwn->pLibPartedHandle, pFnName);                     \
-      pErrStr = dlerror();                                                     \
-      if (pErrStr)                                                             \
-      {                                                                        \
-         LOG_INFO ("Function %s cannot be found (%s).", pFnName, pErrStr);     \
-         rc = ERROR_THREADSCAN_LIBPARTED_NOTWORKING;                           \
-         return;                                                               \
+   rc   = ERROR_THREADSCAN_LIBPARTED_NOTWORKING;
+   pOwn = new t_ThreadScanWorkerPartedLocal();
+   CHK_EXIT (ThreadScanFindLibparted (FilenameList))
+
+   for (i=0; (i<FilenameList.size()) && (!Found); i++)
+   {
+      Filename = FilenameList[i];
+      pOwn->pLibPartedHandle = dlopen (QSTR_TO_PSZ(Filename), RTLD_NOW);
+      if (pOwn->pLibPartedHandle == NULL)
+      {
+         LOG_INFO ("Trying %s -- dlopen returns (%s)", QSTR_TO_PSZ(Filename), dlerror())
+         continue;
       }
+      LOG_INFO ("Trying %s -- dlopen ok", QSTR_TO_PSZ(Filename))
+
+      // GETFN: See dlsym documentation concerning the usage of dlerror for error checking
+      #define GETFN(pFn, Type, pFnName)                                                    \
+         dlerror();                                                                        \
+         pFn = (Type)dlsym (pOwn->pLibPartedHandle, pFnName);                              \
+         pErrStr = dlerror();                                                              \
+         if (pErrStr)                                                                      \
+         {                                                                                 \
+            LOG_INFO ("Trying %s -- dlsym for %s returns (%s)", QSTR_TO_PSZ(Filename), pFnName, dlerror()); \
+            dlclose (pOwn->pLibPartedHandle);                                              \
+            pOwn->pLibPartedHandle    = NULL;                                              \
+            pOwn->pFnLibPartedProbeAll= NULL;                                              \
+            pOwn->pFnLibPartedGetNext = NULL;                                              \
+            pOwn->pFnLibPartedFreeAll = NULL;                                              \
+            continue;                                                                      \
+         }                                                                                 \
+         else                                                                              \
+         {                                                                                 \
+            LOG_INFO ("Trying %s -- dlsym for %s ok", QSTR_TO_PSZ(Filename), pFnName);     \
+         }
 
-   GETFN (pOwn->pFnLibPartedProbeAll, t_pFnLibPartedProbeAll, "ped_device_probe_all")
-   GETFN (pOwn->pFnLibPartedGetNext , t_pFnLibPartedGetNext , "ped_device_get_next" )
-   GETFN (pOwn->pFnLibPartedFreeAll , t_pFnLibPartedFreeAll , "ped_device_free_all" )
+      GETFN (pOwn->pFnLibPartedProbeAll, t_pFnLibPartedProbeAll, "ped_device_probe_all")
+      GETFN (pOwn->pFnLibPartedGetNext , t_pFnLibPartedGetNext , "ped_device_get_next" )
+      GETFN (pOwn->pFnLibPartedFreeAll , t_pFnLibPartedFreeAll , "ped_device_free_all" )
+      #undef GETFN
 
-   rc = NO_ERROR;
+      Found = true;
+   }
+
+   if (Found)
+      rc = NO_ERROR;
 }
 
 t_ThreadScanWorkerParted::~t_ThreadScanWorkerParted (void)
@@ -403,6 +460,205 @@ void t_ThreadScanWorkerHAL::SlotRescan (void)
 
 //         if (SerialNumber.toString().contains("Hitachi", Qt::CaseInsensitive))
 //            Size  = QVariant ((qulonglong)1024*1024*1024*32);  // for test purposes
+//         Size  = QVariant ((qulonglong)283 + 1024*1024*50); printf ("\nATTENTION: TEST CODE activated");
+         pDevice = pDeviceList->AppendNew (SerialNumber.toString(), LinuxDevice.toString(), Model,
+                                           DEVICE_DEFAULT_SECTOR_SIZE, DEVICE_DEFAULT_SECTOR_SIZE, Size.toULongLong());
+         pDevice->Removable = Removable.toBool();
+
+         CHK_EXIT (pDevice->MediaInfo.QueryDevice(QSTR_TO_PSZ(LinuxDevice.toString())))
+      }
+   }
+   CHK_EXIT (ThreadScanMarkLocalDevices (pDeviceList))
+   LOG_INFO ("Device scan finished")
+
+   emit (SignalScanFinished (pDeviceList));
+}
+
+// --------------------------
+//  t_ThreadScanWorkerDevKit
+// --------------------------
+
+// Scan the devices using DBUS/DeviceKit-Disks
+
+#define DEVKIT_SERVICE       "org.freedesktop.DeviceKit.Disks"
+#define DEVKIT_DISKS_IF      "org.freedesktop.DeviceKit.Disks"
+#define DEVKIT_DISKS_PATH    "/org/freedesktop/DeviceKit/Disks"
+#define DEVKIT_DEVICE_IF     "org.freedesktop.DeviceKit.Disks.Device"
+#define DEVKIT_PROPERTIES_IF "org.freedesktop.DBus.Properties"
+class t_ThreadScanWorkerDevKitLocal
+{
+   public:
+      t_ThreadScanWorkerDevKitLocal (void)
+      {
+         pDBusConnection = new QDBusConnection (QDBusConnection::systemBus());
+         pDBusInterface  = NULL;
+      }
+
+     ~t_ThreadScanWorkerDevKitLocal ()
+      {
+         QDBusConnection::disconnectFromBus (pDBusConnection->baseService());
+         delete pDBusConnection;
+         pDBusConnection = NULL;
+         pDBusInterface  = NULL;
+      }
+
+   public:
+      QDBusConnection          *pDBusConnection;
+      QDBusConnectionInterface *pDBusInterface;
+};
+
+
+t_ThreadScanWorkerDevKit::t_ThreadScanWorkerDevKit (APIRET &rc)
+{
+   pOwn = new t_ThreadScanWorkerDevKitLocal;
+   if (!pOwn->pDBusConnection->isConnected())
+   {
+      LOG_INFO ("DBus connection failed")
+      rc = ERROR_THREADSCAN_DBUSDEVKIT_NOTWORKING;
+      return;
+   }
+
+   pOwn->pDBusInterface = pOwn->pDBusConnection->interface();
+   if (!pOwn->pDBusInterface->isServiceRegistered (DEVKIT_SERVICE))
+   {
+      LOG_INFO ("DeviceKit-Disks not registered")
+      rc = ERROR_THREADSCAN_DBUSDEVKIT_NOTWORKING;
+      return;
+   }
+   rc = NO_ERROR;
+}
+
+t_ThreadScanWorkerDevKit::~t_ThreadScanWorkerDevKit (void)
+{
+   delete pOwn;
+}
+
+QList<QVariant> t_ThreadScanWorkerDevKit::CallMethod (const QString &Device, const QString &Method, const QString &Argument)
+{
+   QList<QVariant> Args;
+   QDBusMessage    Message = QDBusMessage::createMethodCall (DEVKIT_SERVICE, Device, DEVKIT_DEVICE_IF, Method);
+   QDBusMessage    Reply;
+
+   Args += Argument;
+   Message.setArguments (Args);
+   Reply = pOwn->pDBusConnection->call (Message);
+
+   if (Reply.type() == QDBusMessage::ErrorMessage)
+   {
+      LOG_ERROR ("DBus returned '%s' for method %s on device %s", QSTR_TO_PSZ (Reply.errorName()),
+                                                                  QSTR_TO_PSZ (Method),
+                                                                  QSTR_TO_PSZ (Device))
+      return QList<QVariant>(); // return empty list
+   }
+
+   return Reply.arguments();
+}
+
+APIRET t_ThreadScanWorkerDevKit::GetProperty (const QString &Device, const QString &Property, QVariant &Var)
+{
+   QDBusMessage             Message = QDBusMessage::createMethodCall (DEVKIT_SERVICE, Device, DEVKIT_PROPERTIES_IF, "Get");  // Query DBUS object properties
+   QList     <QVariant>     Args;
+   QDBusReply<QDBusVariant> Reply;
+
+   Args << Device << Property;
+   Message.setArguments (Args);
+   Reply = pOwn->pDBusConnection->call (Message);
+
+   if (!Reply.isValid())
+   {
+      // TODO: Extract error from Reply.error()
+      //LOG_ERROR ("DBus returned '%s' while retrieving property %s for device %s", QSTR_TO_PSZ (Reply.error()),
+      //                                                                            QSTR_TO_PSZ (Property),
+      //                                                                            QSTR_TO_PSZ (Device))
+      Var = QVariant(); // return empty QVariant
+   }
+   else
+   {
+      QVariant ReplyArg = Reply.value().variant();  // The method returns a QDBusVariant, that must be
+      if (ReplyArg.isNull())                        // converted to a QVariant before it can be used!
+           Var = QVariant();
+      else Var = ReplyArg;
+   }
+
+   return NO_ERROR;
+}
+
+void t_ThreadScanWorkerDevKit::SlotRescan (void)
+{
+   t_pDeviceList   pDeviceList=NULL;
+   t_pDevice       pDevice;
+   QDBusMessage    Message;
+   QStringList     DeviceList;
+   QVariant        Category;
+   QVariant        SerialNumber;
+   QVariant        LinuxDevice;
+   QVariant        Vendor;
+   QVariant        Product;
+   QVariant        Size;
+   QVariant        Drive;
+   QVariant        Removable;
+   QVariant        RemovableAvailable;
+   QString         Model;
+
+   if (thread() != QThread::currentThread())
+      CHK_EXIT (ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD) // As Qt's DBus system is quite sensible to this kind of
+                                                           // mistake (resulting in many QTimer "cannot be stopped/started
+                                                           // from another thread) we prefer to do the check here!
+   emit (SignalScanStarted ());
+   LOG_INFO ("Device scan started")
+
+   Message = QDBusMessage::createMethodCall (DEVKIT_SERVICE, DEVKIT_DISKS_PATH, DEVKIT_DISKS_IF, "EnumerateDevices");
+   QDBusReply<QDBusArgument> Reply = pOwn->pDBusConnection->call(Message);
+   if (!Reply.isValid())
+   {
+      LOG_ERROR ("DBus DevKit::EnumerateDevices failed")
+   }
+   else
+   {
+      pDeviceList = new t_DeviceList;
+
+      // EnumerateDevices returns a QDBusArgument argument containing a list of QDBusObjectPath objects.
+      // Using qdbus_cast was the only method I found that converted the whole crap to a normal QStringList.
+      QDBusArgument  ReplyArgument = Reply.value();
+      QList<QString> DevKitDevices = qdbus_cast<QList<QString> >(ReplyArgument);
+
+      //lint -save -e155 -e521
+      foreach (QString DevKitDevice, DevKitDevices)
+      //lint -restore
+      {
+         CHK_EXIT (GetProperty (DevKitDevice, "device-file", LinuxDevice))
+         if (!LinuxDevice.isValid ())     continue;
+         if ( LinuxDevice.toString()=="") continue;
+
+         CHK_EXIT (GetProperty (DevKitDevice, "device-is-drive", Drive))
+         if(!Drive.isValid()) continue;
+         if(!Drive.toBool ()) continue;
+
+         CHK_EXIT (GetProperty (DevKitDevice, "device-is-removable", Removable))
+         if (!Removable.isValid())
+         {
+            LOG_INFO ("Strange, %s is a block device but has no device-is-removable property", QSTR_TO_PSZ(DevKitDevice))
+            continue;
+         }
+
+         if (Removable.toBool())
+         {
+            CHK_EXIT (GetProperty (DevKitDevice, "device-is-media-available", RemovableAvailable))
+            if (!RemovableAvailable.toBool())
+               continue;
+         }
+
+         CHK_EXIT (GetProperty (DevKitDevice, "device-size" , Size        ))
+         CHK_EXIT (GetProperty (DevKitDevice, "drive-serial", SerialNumber))
+         CHK_EXIT (GetProperty (DevKitDevice, "drive-vendor", Vendor      ))
+         CHK_EXIT (GetProperty (DevKitDevice, "drive-model" , Product     ))
+         if (!SerialNumber.isValid())
+            SerialNumber = "";  // Attention: Empty string must be used, else t_DeviceList::MatchDevice doesn't work
+         if (!Vendor.isValid() && !Product.isValid())
+              Model = "--";
+         else Model = Vendor.toString() + " " + Product.toString();
+         Model = Model.trimmed();
+
          pDevice = pDeviceList->AppendNew (SerialNumber.toString(), LinuxDevice.toString(), Model,
                                            DEVICE_DEFAULT_SECTOR_SIZE, DEVICE_DEFAULT_SECTOR_SIZE, Size.toULongLong());
          pDevice->Removable = Removable.toBool();
@@ -430,10 +686,12 @@ static APIRET ThreadScanRegisterErrorCodes (void)
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_EXITCODE_NONZERO        ))
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_PROCESS_NOTSTARTED      ))
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_PROCESS_NOTFINISHED     ))
-      CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_DBUSHAL_NOTWORKING      ))
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_LIBPARTED_NOTWORKING    ))
+      CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_DBUSHAL_NOTWORKING      ))
+      CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_DBUSDEVKIT_NOTWORKING   ))
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_PROPERTY_NONEXISTENT    ))
       CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD))
+      CHK (TOOL_ERROR_REGISTER_CODE (ERROR_THREADSCAN_INVALID_SCAN_METHOD     ))
    }
    return NO_ERROR;
 }
@@ -445,37 +703,72 @@ t_ThreadScan::t_ThreadScan (void)
 }
 
 
-static APIRET ThreadScanAskUser (bool SwitchToDBusHAL, bool &Ok)
+static const char *ThreadScanMethodToString (t_CfgScanMethod Method)
 {
-   QMessageBox::StandardButton   Button;
-   const char                  *pFrom, *pTo;
-
-   pFrom =  SwitchToDBusHAL ? "libparted" : "DBus/HAL";
-   pTo   = !SwitchToDBusHAL ? "libparted" : "DBus/HAL";
-   LOG_INFO ("%s not accessible, asking user if he wants to switch to %s...", pFrom, pTo)
-   Button = QMessageBox::question (NULL, QObject::tr ("%1 not accessible", "Dialog title") .arg(pFrom),
-                                         QObject::tr ("Guymager is configured to use %1 for scanning the connected devices, but this "
-                                                      "did not work. Alternatively, you may use %2. Do you want to switch to %2?")
-                                                      .arg(pFrom) .arg(pTo), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
-   Ok = (Button == QMessageBox::Yes);
+   const char *pStr=NULL;
+
+   switch (Method)
+   {
+      case SCANMETHOD_DBUSDEVKIT: pStr = "DBus/DeviceKit"; break;
+      case SCANMETHOD_DBUSHAL:    pStr = "DBus/HAL"      ; break;
+      case SCANMETHOD_LIBPARTED:  pStr = "libparted"     ; break;
+      default: CHK_EXIT (ERROR_THREADSCAN_INVALID_SCAN_METHOD)
+   }
+   return pStr;
+}
+
+
+static APIRET ThreadScanAskUser (bool &Ok)
+{
+   static QList<t_CfgScanMethod>   MethodsAlreadyTried;
+   const char                    *pMethodStr;
+   QPushButton                   *pButton;
+   QPushButton                   *pButtonAbort;
+   QButtonGroup                    ButtonGroup;
+   QMessageBox                     MessageBox;
+   t_CfgScanMethod                 Method;
+
+   MethodsAlreadyTried.append (CONFIG (DeviceScanMethod));
+   pMethodStr = ThreadScanMethodToString (CONFIG (DeviceScanMethod));
+   LOG_INFO ("Scan method %s not accessible, asking user if he wants to switch to another one", pMethodStr)
+
+   MessageBox.setText           (QObject::tr("Guymager cannot scan the devices connected to this computer."));
+   MessageBox.setInformativeText(QObject::tr("The selected scan method (\"%1\") is not available. Do you want to try another scan method?") .arg (pMethodStr));
+   pButtonAbort = MessageBox.addButton (QObject::tr("Abort"), QMessageBox::AcceptRole);
+
+   for (Method = (t_CfgScanMethod)0;
+        Method < SCANMETHOD_COUNT;
+        Method = (t_CfgScanMethod)(Method+1))
+   {
+      if (!MethodsAlreadyTried.contains (Method))
+      {
+         pMethodStr = ThreadScanMethodToString (Method);
+         pButton = MessageBox.addButton (QObject::tr("Try method \"%1\"") .arg(pMethodStr), QMessageBox::AcceptRole);
+         ButtonGroup.addButton (pButton, Method);
+      }
+   }
+
+   MessageBox.exec();
+   Ok = (MessageBox.clickedButton() != pButtonAbort);
    if (Ok)
    {
-      LOG_INFO ("User switches to %s", pTo)
-      CONFIG (ScanUsingDbusHal) = SwitchToDBusHAL;
+      Method = (t_CfgScanMethod) ButtonGroup.id (MessageBox.clickedButton());
+      LOG_INFO ("User switches to %s", ThreadScanMethodToString (Method))
+      CONFIG (DeviceScanMethod) = Method;
    }
    else
    {
-      LOG_INFO ("User doesn't want to switch. Exiting now.")
+      LOG_INFO ("User wants to abort. Exiting now.")
    }
-
    return NO_ERROR;
 }
 
+
 APIRET t_ThreadScan::Start (t_ThreadScanWorker **ppWorker)
 {
    int  Wait;
+   int  Tries;
    bool Ok;
-   bool SwitchToDBusHAL;
 
    #define LAUNCH_WORKER                                                                    \
    {                                                                                        \
@@ -490,15 +783,27 @@ APIRET t_ThreadScan::Start (t_ThreadScanWorker **ppWorker)
          msleep (THREADSCAN_WAIT_GRANULARITY);                                              \
    }
 
-   LAUNCH_WORKER;
-
-   if ((oWorkerRc == ERROR_THREADSCAN_DBUSHAL_NOTWORKING) ||
-       (oWorkerRc == ERROR_THREADSCAN_LIBPARTED_NOTWORKING))
+   for (Tries=1;;Tries++)  // Try all scan methods if necessary
    {
-      SwitchToDBusHAL = (oWorkerRc == ERROR_THREADSCAN_LIBPARTED_NOTWORKING);
-      CHK (ThreadScanAskUser (SwitchToDBusHAL, Ok))
-      if (Ok)
-         LAUNCH_WORKER;
+      LAUNCH_WORKER;
+      if ((oWorkerRc == ERROR_THREADSCAN_LIBPARTED_NOTWORKING ) ||
+          (oWorkerRc == ERROR_THREADSCAN_DBUSHAL_NOTWORKING   ) ||
+          (oWorkerRc == ERROR_THREADSCAN_DBUSDEVKIT_NOTWORKING))
+      {
+         if (Tries == SCANMETHOD_COUNT)
+         {
+            QMessageBox::critical (NULL, tr ("Cannot scan devices", "Dialog title"),
+                                         tr ("None of the device scan methods worked. Exiting now."));
+            break;
+         }
+         CHK (ThreadScanAskUser (Ok))
+         if (!Ok)
+            break;
+      }
+      else
+      {
+         break;
+      }
    }
    #undef LAUNCH_WORKER
 
@@ -538,10 +843,15 @@ void t_ThreadScan::run (void)
 
    LOG_INFO ("Thread Scan started")
 
-   if (CONFIG(ScanUsingDbusHal))
-        *ppoWorker = new t_ThreadScanWorkerHAL    (oWorkerRc); // We have to create this object as we want to work with signals
-   else *ppoWorker = new t_ThreadScanWorkerParted (oWorkerRc); // and slots in this new thread. t_ThreadScan itself belongs to
-                                                               // the main thread and thus can't be used for signals and slots.
+   switch (CONFIG(DeviceScanMethod))
+   {
+      // We have to create the following object as we want to work with signals and slots in this new thread.
+      // t_ThreadScan itself belongs to the main thread and thus can't be used for signals and slots.
+      case SCANMETHOD_DBUSDEVKIT: *ppoWorker = new t_ThreadScanWorkerDevKit (oWorkerRc); break;
+      case SCANMETHOD_DBUSHAL:    *ppoWorker = new t_ThreadScanWorkerHAL    (oWorkerRc); break;
+      case SCANMETHOD_LIBPARTED:  *ppoWorker = new t_ThreadScanWorkerParted (oWorkerRc); break;
+      default: CHK_EXIT (ERROR_THREADSCAN_INVALID_SCAN_METHOD)
+   }
    if (oWorkerRc)
       return;
 
diff --git a/threadscan.h b/threadscan.h
index 2faaa46..b471f61 100644
--- a/threadscan.h
+++ b/threadscan.h
@@ -70,9 +70,31 @@ class t_ThreadScanWorkerHAL: public t_ThreadScanWorker
       t_ThreadScanWorkerHALLocal *pOwn;
 };
 
+class t_ThreadScanWorkerDevKitLocal;
+class t_ThreadScanWorkerDevKit: public t_ThreadScanWorker
+{
+   Q_OBJECT
+
+   public:
+      t_ThreadScanWorkerDevKit (APIRET &rc);
+     ~t_ThreadScanWorkerDevKit (void);
+
+   private:
+      QList<QVariant> CallMethod        (const QString &Device, const QString &Method, const QString &Argument);
+      APIRET          GetProperty       (const QString &Device, const QString &Property, QVariant &Var);
+
+   public slots:
+      void SlotRescan (void);
+
+   private:
+      t_ThreadScanWorkerDevKitLocal *pOwn;
+};
+
 
 class t_ThreadScan: public QThread
 {
+   Q_OBJECT
+
    public:
       t_ThreadScan (void);
       APIRET Start (t_ThreadScanWorker **ppWorker);  // Return ptr to worker, so calling fn may emit signals to it
@@ -93,9 +115,11 @@ enum
    ERROR_THREADSCAN_EXITCODE_NONZERO,
    ERROR_THREADSCAN_PROCESS_NOTSTARTED,
    ERROR_THREADSCAN_PROCESS_NOTFINISHED,
-   ERROR_THREADSCAN_DBUSHAL_NOTWORKING,
    ERROR_THREADSCAN_LIBPARTED_NOTWORKING,
+   ERROR_THREADSCAN_DBUSHAL_NOTWORKING,
+   ERROR_THREADSCAN_DBUSDEVKIT_NOTWORKING,
    ERROR_THREADSCAN_PROPERTY_NONEXISTENT,
-   ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD
+   ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD,
+   ERROR_THREADSCAN_INVALID_SCAN_METHOD
 };
 
diff --git a/threadwrite.cpp b/threadwrite.cpp
index 4a9a7ee..82bbd0d 100644
--- a/threadwrite.cpp
+++ b/threadwrite.cpp
@@ -25,7 +25,7 @@
 #include "config.h"
 #include "device.h"
 #include "main.h"
-#include "aaff.h"
+#include "qtutil.h"
 #include "threadwrite.h"
 
 
@@ -33,24 +33,26 @@ const unsigned long THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY =   100; // ms
 const unsigned long THREADWRITE_WAIT_FOR_HANDLE             = 30000; // ms
 const unsigned long THREADWRITE_SLOWDOWN_SLEEP              =   700; // ms
 
-const int           THREADWRITE_AFF_MODE                    =  0666; // file mode flags
-
 class t_OutputFile
 {
    public:
       virtual        ~t_OutputFile  (void) {};
-      virtual APIRET  Open          (t_pDevice pDevice)       = 0;
-      virtual APIRET  Write         (t_pFifoBlock pFifoBlock) = 0;
-      virtual APIRET  Close         (void)                    = 0;
-      virtual bool    Opened        (void)                    = 0;
-      virtual void *  GetFileHandle (void)                    = 0;
+      virtual APIRET  Open          (t_pDevice pDevice, bool Verify) = 0;
+      virtual APIRET  Write         (t_pFifoBlock pFifoBlock)        = 0;
+      virtual APIRET  Verify        (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos) = 0;
+      virtual APIRET  Close         (void)                           = 0;
+      virtual bool    Opened        (void)                           = 0;
+      virtual void *  GetFileHandle (void)                           = 0;
 };
 
 class t_OutputFileDD: public t_OutputFile
 {
    public:
       t_OutputFileDD (void) :
-         poFile (NULL)
+          oFile       (-1),
+          oLastCheckT (0),
+         poVerifyBuff (NULL),
+         poDevice     (NULL)
       {
       } //lint -esym(613, t_OutputFileDD::poFile)  Possible use of NULL pointer
         //lint -esym(668, fclose, fwrite)  Possibly passing NULL pointer
@@ -61,38 +63,117 @@ class t_OutputFileDD: public t_OutputFile
             (void) t_OutputFileDD::Close();
       } //lint !e1740
 
-      APIRET Open (t_pDevice pDevice)
+      APIRET Open (t_pDevice pDevice, bool /* Verify */)
       {
          QString Extension;
-         QString FileName;
+         int     Flags;
 
+         poDevice = pDevice;
          if (CONFIG (WriteToDevNull))
          {
-            FileName = "/dev/null";
+            oFilename = "/dev/null";
          }
          else
          {
-            CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, &Extension))
-            FileName = pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + Extension;
+            CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, &Extension))
+            oFilename = pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + Extension;
          }
 
-         poFile = fopen64 (QSTR_TO_PSZ (FileName), "w");
-         if (poFile == NULL)
+//         Flags = O_NOATIME | Verify ? O_RDONLY : O_WRONLY; // Doesn't work... !??
+         Flags = O_NOATIME | O_RDWR;
+         if (!pDevice->Acquisition.Clone)
+            Flags |= O_CREAT;              // Create it if doesn't exist
+
+         oFile = open64 (QSTR_TO_PSZ (oFilename), Flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+         if (oFile < 0)
          {
-            LOG_ERROR ("fopen on %s failed, errno=%d '%s'", QSTR_TO_PSZ (FileName), errno, ToolErrorTranslateErrno (errno))
+            LOG_ERROR ("open64 on %s failed, errno=%d '%s'", QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
             return ERROR_THREADWRITE_OPEN_FAILED;
          }
+         time (&oLastCheckT);
+
          return NO_ERROR;
       }
 
       APIRET Write (t_pFifoBlock pFifoBlock)
       {
-         unsigned int Written = fwrite (pFifoBlock->Buffer, pFifoBlock->DataSize, 1, poFile);
-         if (Written != 1)
+         size_t  Remaining = pFifoBlock->DataSize;
+         size_t  Offset = 0;
+         ssize_t Written;
+         time_t  NowT;
+
+         while (Remaining)
          {
-            LOG_ERROR ("fwrite failed, errno=%d '%s'", errno, ToolErrorTranslateErrno (errno))
-            return ERROR_THREADWRITE_WRITE_FAILED;
+            Written = write (oFile, &pFifoBlock->Buffer[Offset], Remaining);
+            if (Written < 0)
+            {
+               LOG_ERROR ("write failed, oFile %d, errno=%d '%s'", oFile, errno, ToolErrorTranslateErrno (errno))
+               return ERROR_THREADWRITE_WRITE_FAILED;
+            }
+            Remaining -= Written;
+            Offset    += Written;
          }
+
+         if (poDevice->Acquisition.Clone)    // It was observed, that the write or fwrite functions do not detect device removal! It is unknown
+         {                                   // how this is possible... Therefore, we check the existence of the device every 2 seconds by means
+            time (&NowT);                    // of a seperate fopen/flclose.
+            if ((NowT - oLastCheckT) >=2)
+            {
+               FILE *pFile;
+               bool   Error;
+
+               pFile = fopen64 (QSTR_TO_PSZ (oFilename), "r");
+               Error = (pFile == NULL);
+               if (!Error)
+                  Error = (fclose (pFile) != 0);
+               if (Error)
+               {
+                  LOG_ERROR ("Check for destination clone %s failed (%d '%s')", QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
+                  return ERROR_THREADWRITE_WRITE_FAILED;
+               }
+               oLastCheckT = NowT;
+            }
+         }
+
+         return NO_ERROR;
+      }
+
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      {
+         unsigned int ToRead;
+         unsigned int Remaining;
+         quint64      TotalRemaining;
+         off64_t      rc;
+         ssize_t      Read;
+         ssize_t      Offset=0;
+
+         if (*pPos == 0)
+         {
+            rc = lseek64 (oFile, 0, SEEK_SET);
+            if (rc < 0)
+               return ERROR_THREADWRITE_VERIFY_FAILED;
+            poVerifyBuff = UTIL_MEM_ALLOC (poDevice->FifoBlockSize);
+            if (poVerifyBuff == NULL)
+               CHK (ERROR_THREADWRITE_MALLOC_FAILED);
+         }
+         TotalRemaining = poDevice->Size - *pPos;
+         Remaining = GETMIN (TotalRemaining, poDevice->FifoBlockSize);
+         ToRead    = Remaining;
+
+         while (Remaining)
+         {
+            Read = read (oFile, (char*)poVerifyBuff + Offset, ToRead);
+            if (Read < 0)
+               return ERROR_THREADWRITE_VERIFY_FAILED;
+            Remaining -= Read;
+            Offset    += Read;
+         }
+
+         if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, ToRead))
+         if (pHashContextSHA256) CHK_EXIT (HashSHA256Append (pHashContextSHA256, poVerifyBuff, ToRead))
+
+         *pPos += ToRead;
+
          return NO_ERROR;
       }
 
@@ -100,39 +181,43 @@ class t_OutputFileDD: public t_OutputFile
       {
          int Res;
 
-         if (poFile == NULL)
+         if (oFile == -1)
             CHK (ERROR_THREADWRITE_NOT_OPENED)
 
-         Res = fflush (poFile);
-         if (Res)
+         Res = close (oFile);
+         oFile = -1;
+         if (Res != 0)
          {
-            (void) fclose (poFile);
-            LOG_ERROR ("fflush failed, errno=%d '%s'", errno, ToolErrorTranslateErrno (errno))
+            LOG_ERROR ("close failed, errno=%d '%s'", errno, ToolErrorTranslateErrno (errno))
             return ERROR_THREADWRITE_CLOSE_FAILED;
          }
 
-         Res = fclose (poFile);
-         poFile = NULL;
-         if (Res)
+         if (poVerifyBuff)
          {
-            LOG_ERROR ("fclose failed, errno=%d '%s'", errno, ToolErrorTranslateErrno (errno))
-            return ERROR_THREADWRITE_CLOSE_FAILED;
+            UTIL_MEM_FREE (poVerifyBuff);
+            poVerifyBuff = NULL;
          }
          return NO_ERROR;
       }
 
       void * GetFileHandle (void)
       {
-         return poFile;
+         if (oFile == -1)
+              return NULL;
+         else return &oFile;
       }
 
       bool Opened (void)
       {
-         return (poFile != NULL);
+         return (oFile != -1);
       }
 
    private:
-      FILE *poFile;
+      int        oFile;
+      time_t     oLastCheckT; // Only used when cloning, see above
+      QString    oFilename;
+      void     *poVerifyBuff;
+      t_pDevice poDevice;
 };
 
 #define CHK_LIBEWF(Fn)                                                 \
@@ -150,9 +235,13 @@ class t_OutputFileEWF: public t_OutputFile
    public:
       t_OutputFileEWF (void)
       {
-         poFile   = NULL;
-         poDevice = NULL;   //lint -esym(613,t_OutputFileEWF::poDevice)  Prevent lint from telling us about possible null pointers in the following code
+         poFile                  = NULL;
+         poDevice                = NULL;   //lint -esym(613,t_OutputFileEWF::poDevice)  Prevent lint from telling us about possible null pointers in the following code
+         poVerifyBuff            = NULL;
+         poImageFilenameArr      = NULL;
+          oImageFileCount        = 0;
           oHasCompressionThreads = false;
+          oVerification          = false;
       }
 
       ~t_OutputFileEWF (void)
@@ -161,49 +250,81 @@ class t_OutputFileEWF: public t_OutputFile
             (void) t_OutputFileEWF::Close();
       } //lint !e1740
 
-      APIRET Open (t_pDevice pDevice)
+      APIRET Open (t_pDevice pDevice, bool Verify)
       {
          QString         Uname;
          QString         GuymagerVersion;
          LIBEWF_HANDLE *pFile;
+         char          *pAsciiFileName;
          QByteArray      AsciiFileName = (pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename).toAscii();
-         char          *pAsciiFileName = AsciiFileName.data();
 
          oHasCompressionThreads = pDevice->HasCompressionThreads();
          poDevice               = pDevice;
+         oVerification          = Verify;
 
-         pFile = libewf_open (&pAsciiFileName, 1, LIBEWF_OPEN_WRITE);
-         if (pFile == NULL)
-            return ERROR_THREADWRITE_OPEN_FAILED;
-
-
-         #define STR_AND_LEN(QStr) QStr.toAscii().data(), strlen(QStr.toAscii().data())
+         if (Verify)
+         {
+            QFileInfoList FileInfoList;
+            QString       ExtensionImage;
+            QFileInfo     FileInfo;
+            QDir          Dir(pDevice->Acquisition.ImagePath);
+            int           i;
+
+            CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, &ExtensionImage))
+            FileInfoList = Dir.entryInfoList (QStringList(pDevice->Acquisition.ImageFilename + ExtensionImage), QDir::Files, QDir::Name);
+            oImageFileCount = FileInfoList.count();
+            poImageFilenameArr = (char **) malloc (oImageFileCount * sizeof (char*));
+            for (i=0; i<oImageFileCount; i++)
+            {
+               FileInfo       = FileInfoList.takeFirst();
+               AsciiFileName  = FileInfo.absoluteFilePath().toAscii();
+               pAsciiFileName = AsciiFileName.data();
+               poImageFilenameArr[i] = (char *) malloc (strlen(pAsciiFileName)+1);
+               strcpy (poImageFilenameArr[i], pAsciiFileName);
+            }
+            pFile = libewf_open (poImageFilenameArr, oImageFileCount, libewf_get_flags_read());
+            if (pFile == NULL)
+            {
+               LOG_INFO ("Error while reopening EWF for verification. The files are:")
+               for (i=0; i<oImageFileCount; i++)
+                  LOG_INFO ("%s", poImageFilenameArr[i])
+               return ERROR_THREADWRITE_OPEN_FAILED;
+            }
+         }
+         else
+         {
+            char *pAsciiFileName = AsciiFileName.data();
 
+            pFile = libewf_open (&pAsciiFileName, 1, LIBEWF_OPEN_WRITE);
+            if (pFile == NULL)
+               return ERROR_THREADWRITE_OPEN_FAILED;
 
-         libewf_set_notify_values(stderr, 1);
+            #define STR_AND_LEN(QStr) QStr.toAscii().data(), strlen(QStr.toAscii().data())
+            libewf_set_notify_values(stderr, 1);
 
-         CHK_LIBEWF (libewf_set_sectors_per_chunk  (pFile, 64))
-         CHK_LIBEWF (libewf_set_bytes_per_sector   (pFile, pDevice->SectorSize))
-         CHK_LIBEWF (libewf_set_segment_file_size  (pFile, (unsigned int) (CONFIG (EwfSegmentSize) * BYTES_PER_MEGABYTE)))
-         CHK_LIBEWF (libewf_set_compression_values (pFile, CONFIG (EwfCompression), 1))
-         CHK_LIBEWF (libewf_set_media_type         (pFile, pDevice->Removable ? LIBEWF_MEDIA_TYPE_REMOVABLE : LIBEWF_MEDIA_TYPE_FIXED))
-         CHK_LIBEWF (libewf_set_volume_type        (pFile, LIBEWF_VOLUME_TYPE_PHYSICAL))
-         CHK_LIBEWF (libewf_set_format             (pFile, (uint8_t) CONFIG (EwfFormat)))
-         CHK_LIBEWF (libewf_set_media_size         (pFile, pDevice->Size))
+            CHK_LIBEWF (libewf_set_media_size         (pFile, pDevice->Size))
+            CHK_LIBEWF (libewf_set_bytes_per_sector   (pFile, pDevice->SectorSize))
+            CHK_LIBEWF (libewf_set_sectors_per_chunk  (pFile, 64))
+            CHK_LIBEWF (libewf_set_segment_file_size  (pFile, (unsigned int) (CONFIG (EwfSegmentSize) * BYTES_PER_MEGABYTE)))
+            CHK_LIBEWF (libewf_set_compression_values (pFile, CONFIG (EwfCompression), 1))
+            CHK_LIBEWF (libewf_set_media_type         (pFile, pDevice->Removable ? LIBEWF_MEDIA_TYPE_REMOVABLE : LIBEWF_MEDIA_TYPE_FIXED))
+            CHK_LIBEWF (libewf_set_volume_type        (pFile, LIBEWF_VOLUME_TYPE_PHYSICAL))
+            CHK_LIBEWF (libewf_set_format             (pFile, (uint8_t) CONFIG (EwfFormat)))
 
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"case_number"    , STR_AND_LEN(pDevice->Acquisition.CaseNumber    )))
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"description"    , STR_AND_LEN(pDevice->Acquisition.Description   )))
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"examiner_name"  , STR_AND_LEN(pDevice->Acquisition.Examiner      )))
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"evidence_number", STR_AND_LEN(pDevice->Acquisition.EvidenceNumber)))
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"notes"          , STR_AND_LEN(pDevice->Acquisition.Notes         )))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"case_number"    , STR_AND_LEN(pDevice->Acquisition.CaseNumber    )))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"description"    , STR_AND_LEN(pDevice->Acquisition.Description   )))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"examiner_name"  , STR_AND_LEN(pDevice->Acquisition.Examiner      )))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"evidence_number", STR_AND_LEN(pDevice->Acquisition.EvidenceNumber)))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"notes"          , STR_AND_LEN(pDevice->Acquisition.Notes         )))
 
-         CHK (ToolSysInfoUname (Uname))
-         GuymagerVersion = QString("guymager ") + QString(pCompileInfoVersion);
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_operating_system", STR_AND_LEN(Uname)))
-         CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_software_version", STR_AND_LEN(GuymagerVersion)))
+            CHK (ToolSysInfoUname (Uname))
+            GuymagerVersion = QString("guymager ") + QString(pCompileInfoVersion);
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_operating_system", STR_AND_LEN(Uname)))
+            CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_software_version", STR_AND_LEN(GuymagerVersion)))
 
-         #undef STR_AND_LEN
+            #undef STR_AND_LEN
 
+         }
          poFile = pFile; // Only set poFile at the very end, so the CompressionThreads won't use it until everything is initialised
          return NO_ERROR;
       }
@@ -229,6 +350,7 @@ class t_OutputFileEWF: public t_OutputFile
             Size = pFifoBlock->DataSize;
             Written = libewf_write_buffer (poFile, pFifoBlock->Buffer, Size);
          }
+
          if (Written != Size)
          {
             LOG_ERROR ("Written %d/%d bytes", Written, Size)
@@ -238,14 +360,44 @@ class t_OutputFileEWF: public t_OutputFile
          return NO_ERROR;
       }
 
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      {
+         quint64      Remaining;
+         unsigned int ToRead;
+         ssize_t      Read;
+
+
+         if (*pPos == 0)
+         {
+            poVerifyBuff = UTIL_MEM_ALLOC (poDevice->FifoBlockSize);
+            if (poVerifyBuff == NULL)
+               CHK (ERROR_THREADWRITE_MALLOC_FAILED);
+         }
+         Remaining = poDevice->Size - *pPos;
+         ToRead = GETMIN (Remaining, poDevice->FifoBlockSize);
+         Read = libewf_read_buffer (poFile, poVerifyBuff, ToRead);
+         if (Read != (ssize_t)ToRead)
+         {
+            LOG_INFO ("Reading from EWF file failed (%zu)", Read);
+            return ERROR_THREADWRITE_VERIFY_FAILED;
+         }
+         if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, ToRead))
+         if (pHashContextSHA256) CHK_EXIT (HashSHA256Append (pHashContextSHA256, poVerifyBuff, ToRead))
+
+         *pPos += ToRead;
+
+         return NO_ERROR;
+      }
+
       APIRET Close (void)
       {
          int rc;
+         int i;
 
          if (poFile == NULL)
             CHK (ERROR_THREADWRITE_NOT_OPENED)
 
-         if (poDevice->HasCompressionThreads())
+         if (!oVerification && poDevice->HasCompressionThreads() && poDevice->Acquisition.CalcMD5)
             CHK_LIBEWF (libewf_set_md5_hash (poFile, (uint8_t*)&poDevice->MD5Digest, HASH_MD5_DIGEST_LENGTH))
 
          rc = libewf_close (poFile);
@@ -255,6 +407,16 @@ class t_OutputFileEWF: public t_OutputFile
             return ERROR_THREADWRITE_LIBEWF_FAILED;
          }
 
+         if (poVerifyBuff)
+         {
+            UTIL_MEM_FREE (poVerifyBuff);
+            poVerifyBuff = NULL;
+         }
+
+         for (i=0; i<oImageFileCount; i++)
+            free (poImageFilenameArr[i]);
+         free (poImageFilenameArr);
+
          poFile = NULL;
          return NO_ERROR;
       }
@@ -272,6 +434,10 @@ class t_OutputFileEWF: public t_OutputFile
    private:
       LIBEWF_HANDLE *poFile;
       t_pDevice      poDevice;
+      bool            oVerification;
+      void          *poVerifyBuff;
+      int             oImageFileCount;
+      char         **poImageFilenameArr;
       bool            oHasCompressionThreads;
 };
 
@@ -280,8 +446,11 @@ class t_OutputFileAFF: public t_OutputFile
 {
    public:
       t_OutputFileAFF (void) :
-         poFile   (NULL),
-         poDevice (NULL)
+         poFile                (NULL ),
+         poDevice              (NULL ),
+         poVerifyBuff          (NULL ),
+         oHasCompressionThreads(false),
+         oVerification         (false)
       {
       }
 
@@ -291,7 +460,7 @@ class t_OutputFileAFF: public t_OutputFile
             (void) t_OutputFileAFF::Close();
       } //lint !e1740
 
-      APIRET Open (t_pDevice pDevice)
+      APIRET Open (t_pDevice pDevice, bool Verify)
       {
          QString               Extension;
          QString               FileName;
@@ -302,67 +471,77 @@ class t_OutputFileAFF: public t_OutputFile
          t_pAaff              pFile;
          APIRET                rc;
 
-//         printf ("\nCalling AaffOpen");
-         poDevice = pDevice;
+         poDevice      = pDevice;
+         oVerification =  Verify;
          oHasCompressionThreads = pDevice->HasCompressionThreads();
 
-
-         CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, &Extension))
+         CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, &Extension))
          FileName = pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + Extension;
 
-
-         CHK (AaffOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size, pDevice->SectorSizePhys, pDevice->FifoBlockSize))
-
-         rc = ToolSysInfoGetMacAddr (&MacAddr);
-         if (rc == TOOLSYSINFO_ERROR_NO_ADDR)
+         if (oVerification)
          {
-            Mac = "none";
+            rc = AaffOpen (&pFile, QSTR_TO_PSZ(FileName));
+            if (rc)
+            {
+               LOG_INFO ("AFF image verification failed: %s", ToolErrorMessage (rc))
+               return ERROR_THREADWRITE_VERIFY_FAILED;
+            }
          }
          else
          {
-            CHK (rc)
-            Mac = &MacAddr.AddrStr[0];
+            CHK (AaffOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size, pDevice->SectorSizePhys, pDevice->FifoBlockSize))
+
+            rc = ToolSysInfoGetMacAddr (&MacAddr);
+            if (rc == TOOLSYSINFO_ERROR_NO_ADDR)
+            {
+               Mac = "none";
+            }
+            else
+            {
+               CHK (rc)
+               Mac = &MacAddr.AddrStr[0];
+            }
+
+            DateTimeStr  = poDevice->StartTimestamp.toString ("yyyy-MM-dd hh:mm:ss");
+            DateTimeStr += " localtime";
+            CHK (MainGetCommandLine (&pCommandLine))
+
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_COMMAND_LINE, 0, pCommandLine))
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_MACADDR     , 0, QSTR_TO_PSZ(Mac                                 )))
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_DATE        , 0, QSTR_TO_PSZ(DateTimeStr                         )))
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_DEVICE      , 0, QSTR_TO_PSZ(poDevice->LinuxDevice               )))
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_MODEL       , 0, QSTR_TO_PSZ(poDevice->Model                     )))
+            CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_SN          , 0, QSTR_TO_PSZ(poDevice->SerialNumber              )))
+            CHK (AaffWriteSegmentStr (pFile, "CaseNumber"             , 0, QSTR_TO_PSZ(poDevice->Acquisition.CaseNumber    )))
+            CHK (AaffWriteSegmentStr (pFile, "EvidenceNumber"         , 0, QSTR_TO_PSZ(poDevice->Acquisition.EvidenceNumber)))
+            CHK (AaffWriteSegmentStr (pFile, "Examiner"               , 0, QSTR_TO_PSZ(poDevice->Acquisition.Examiner      )))
+            CHK (AaffWriteSegmentStr (pFile, "Description"            , 0, QSTR_TO_PSZ(poDevice->Acquisition.Description   )))
+            CHK (AaffWriteSegmentStr (pFile, "Notes"                  , 0, QSTR_TO_PSZ(poDevice->Acquisition.Notes         )))
          }
 
-         DateTimeStr  = poDevice->StartTimestamp.toString ("yyyy-MM-dd hh:mm:ss");
-         DateTimeStr += " localtime";
-         CHK (MainGetCommandLine (&pCommandLine))
-
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_COMMAND_LINE, 0, pCommandLine))
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_MACADDR     , 0, QSTR_TO_PSZ(Mac                                 )))
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_DATE        , 0, QSTR_TO_PSZ(DateTimeStr                         )))
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_DEVICE      , 0, QSTR_TO_PSZ(poDevice->LinuxDevice               )))
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_MODEL       , 0, QSTR_TO_PSZ(poDevice->Model                     )))
-         CHK (AaffWriteSegmentStr (pFile, AAFF_SEGNAME_SN          , 0, QSTR_TO_PSZ(poDevice->SerialNumber              )))
-         CHK (AaffWriteSegmentStr (pFile, "CaseNumber"             , 0, QSTR_TO_PSZ(poDevice->Acquisition.CaseNumber    )))
-         CHK (AaffWriteSegmentStr (pFile, "EvidenceNumber"         , 0, QSTR_TO_PSZ(poDevice->Acquisition.EvidenceNumber)))
-         CHK (AaffWriteSegmentStr (pFile, "Examiner"               , 0, QSTR_TO_PSZ(poDevice->Acquisition.Examiner      )))
-         CHK (AaffWriteSegmentStr (pFile, "Description"            , 0, QSTR_TO_PSZ(poDevice->Acquisition.Description   )))
-         CHK (AaffWriteSegmentStr (pFile, "Notes"                  , 0, QSTR_TO_PSZ(poDevice->Acquisition.Notes         )))
-
-//         printf ("\nAaffOpen finished");
          poFile = pFile; // Only set poFile at the very end, so the CompressionThreads won't use it until everything is initialised
          return NO_ERROR;
       }
 
+      //lint -save -esym(613,t_OutputFileAFF::poDevice)   Possible use of null pointer
       APIRET Write (t_pFifoBlock pFifoBlock)
       {
          if (!oHasCompressionThreads) // Do preprocessing if not already done in compression threads
          {
             t_pFifoBlock pPreprocessBlock;
 
-            CHK_EXIT (t_Fifo::CreateCompressionOptimised (pPreprocessBlock, poDevice->FifoBlockSize))
+            CHK_EXIT (t_Fifo::Create (poDevice->pFifoMemory, pPreprocessBlock, poDevice->FifoAllocBlockSize))
             pPreprocessBlock->DataSize = pFifoBlock->DataSize;
             CHK_EXIT (AaffPreprocess (&pPreprocessBlock->pAaffPreprocess, pFifoBlock->Buffer, pFifoBlock->DataSize, pPreprocessBlock->Buffer, pPreprocessBlock->BufferSize))
             if (pPreprocessBlock->pAaffPreprocess->Compressed)
             {
-               CHK_EXIT (t_Fifo::Destroy (pFifoBlock))
+               CHK_EXIT (t_Fifo::Destroy (poDevice->pFifoMemory, pFifoBlock))
                pFifoBlock = pPreprocessBlock;
             }
             else
             {
                pFifoBlock->pAaffPreprocess = pPreprocessBlock->pAaffPreprocess;
-               CHK_EXIT (t_Fifo::Destroy (pPreprocessBlock))
+               CHK_EXIT (t_Fifo::Destroy (poDevice->pFifoMemory, pPreprocessBlock))
             }
          }
 
@@ -370,7 +549,35 @@ class t_OutputFileAFF: public t_OutputFile
 
          return NO_ERROR;
       }
+      //lint -restore
+
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      {
+         unsigned int DataLen = poDevice->FifoBlockSize;
+         APIRET       rc;
+
+         if (*pPos == 0)
+         {
+            poVerifyBuff = UTIL_MEM_ALLOC (poDevice->FifoBlockSize);
+            if (poVerifyBuff == NULL)
+               CHK (ERROR_THREADWRITE_MALLOC_FAILED);
+         }
+         rc = AaffReadNextPage (poFile, (unsigned char *) poVerifyBuff, &DataLen);
+         if (rc)
+         {
+            LOG_INFO ("AFF image verification failed: %s", ToolErrorMessage (rc))
+            return ERROR_THREADWRITE_VERIFY_FAILED;
+         }
+
+         if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, DataLen))
+         if (pHashContextSHA256) CHK_EXIT (HashSHA256Append (pHashContextSHA256, poVerifyBuff, DataLen))
 
+         *pPos += DataLen;
+
+         return NO_ERROR;
+      }
+
+      //lint -save -esym(613,t_OutputFileAFF::poDevice)   Possible use of null pointer
       APIRET Close (void)
       {
          QList<quint64> BadSectors;
@@ -379,15 +586,28 @@ class t_OutputFileAFF: public t_OutputFile
          if (poFile == NULL)
             CHK (ERROR_THREADWRITE_NOT_OPENED)
 
-         CHK (poDevice->GetBadSectors (BadSectors, false))
-         Seconds  = poDevice->StartTimestamp.secsTo (QDateTime::currentDateTime());
+         if (oVerification)
+         {
+            CHK (AaffClose (&poFile))
+            if (poVerifyBuff)
+            {
+               UTIL_MEM_FREE (poVerifyBuff);
+               poVerifyBuff = NULL;
+            }
+         }
+         else
+         {
+            CHK (poDevice->GetBadSectors (BadSectors, false))
+            Seconds  = poDevice->StartTimestamp.secsTo (QDateTime::currentDateTime());
 
-         CHK (AaffClose (poFile, BadSectors.count(), (unsigned char*)&poDevice->MD5Digest, (unsigned char*)&poDevice->SHA256Digest, Seconds))
+            CHK (AaffClose (&poFile, BadSectors.count(), (unsigned char*)&poDevice->MD5Digest, (unsigned char*)&poDevice->SHA256Digest, Seconds))
+         }
 
          poFile = NULL;
 
          return NO_ERROR;
       }
+      //lint -restore
 
       void *GetFileHandle (void)
       {
@@ -402,19 +622,28 @@ class t_OutputFileAFF: public t_OutputFile
    private:
       t_pAaff    poFile;
       t_pDevice  poDevice;
+      void      *poVerifyBuff;
       bool        oHasCompressionThreads;
+      bool        oVerification;
 };
 
 
 class t_ThreadWriteLocal
 {
    public:
-      t_ThreadWriteLocal (void) :  pOutputFile(NULL), pDevice(NULL) {}
+      t_ThreadWriteLocal (void) :
+         pOutputFile        (NULL),
+         pSlowDownRequest   (NULL),
+         pDevice            (NULL),
+         FileHandleRequests (0)
+      {}
 
    public:
       t_OutputFile *pOutputFile;
       bool         *pSlowDownRequest;
       t_pDevice     pDevice;
+      int            FileHandleRequests;
+      QMutex         SemHandle;
 };
 
 
@@ -446,9 +675,10 @@ t_ThreadWrite::t_ThreadWrite (t_pDevice pDevice, bool *pSlowDownRequest)
    }
 
    pOwn = new t_ThreadWriteLocal;
-   pOwn->pDevice          = pDevice;
-   pOwn->pOutputFile      = NULL;
-   pOwn->pSlowDownRequest = pSlowDownRequest;
+   pOwn->pDevice            = pDevice;
+   pOwn->pOutputFile        = NULL;
+   pOwn->pSlowDownRequest   = pSlowDownRequest;
+   pOwn->FileHandleRequests = 0;
 
    CHK_QT_EXIT (connect (this, SIGNAL(finished()), this, SLOT(SlotFinished())))
 }
@@ -459,7 +689,7 @@ t_ThreadWrite::~t_ThreadWrite (void)
 }
 
 
-APIRET ThreadWriteCheckData (t_pFifoBlock pFifoBlock)
+static APIRET ThreadWriteDebugCheckLibewfData (t_pFifoBlock pFifoBlock)
 {
    unsigned char *pBufferUncompressed;
    uLongf          UncompressedSize;
@@ -521,21 +751,23 @@ APIRET ThreadWriteCheckData (t_pFifoBlock pFifoBlock)
    return NO_ERROR;
 }
 
+//lint -save -esym(613,pOutputFile)   Possible use of null pointer
 void t_ThreadWrite::run (void)
 {
    t_pDevice     pDevice;
    t_pFifoBlock  pFifoBlock;
    t_OutputFile *pOutputFile= NULL;
    bool           Finished  = false;
+   bool           FileHandleReleased;
    quint64        Blocks    = 0;
+   quint64        Written   = 0;
    APIRET         rc;
 
-   LOG_INFO ("Acquisition of %s: Writing thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   LOG_INFO ("Acquisition of %s: Write thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
 
    pDevice = pOwn->pDevice;
    pDevice->SetCurrentWritePos (0LL);
 
-   LOG_INFO ("Deleting existing image files of the same name")
    CHK_EXIT (DeleteImageFiles (false))
 
    switch (pDevice->Acquisition.Format)
@@ -546,11 +778,11 @@ void t_ThreadWrite::run (void)
       default: CHK_EXIT (ERROR_THREADWRITE_INVALID_FORMAT)
    }
 
-   rc = pOutputFile->Open (pDevice);
+   rc = pOutputFile->Open (pDevice, false);
    if (rc == ERROR_THREADWRITE_OPEN_FAILED)
    {
       LOG_INFO ("Could not open destination file %s", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
-      pDevice->AbortReason  = t_Device::ThreadWriteFileError;
+      pDevice->AbortReason  = t_Device::ThreadWriteWriteError;
       pDevice->AbortRequest = true;
    }
    else
@@ -558,8 +790,9 @@ void t_ThreadWrite::run (void)
       CHK_EXIT (rc)
    }
 
+   pOwn->SemHandle.lock ();
    pOwn->pOutputFile = pOutputFile;  // Only set pOwn->pOutputFile here, after initialisation completed successfully. The reason is,
-                                     // that other threads should remain blocked in t_ThreadWrite::GetpFileHandle until this point.
+   pOwn->SemHandle.unlock ();        // that other threads should remain blocked in t_ThreadWrite::GetpFileHandle until this point.
 
    while (!Finished && !pDevice->AbortRequest)
    {
@@ -569,11 +802,13 @@ void t_ThreadWrite::run (void)
       CHK_EXIT (pDevice->pFifoWrite->Get (pFifoBlock))
       if (pFifoBlock)
       {
+//         t_Fifo::LogBlock (pDevice->pFifoMemory, pFifoBlock, 'w');
          if (pFifoBlock->Nr != Blocks)
          {
             LOG_ERROR ("Fifo block number out of sequence. Expected: %Ld Received: %Ld", Blocks, pFifoBlock->Nr)
+//            t_Fifo::LogBlock (pDevice->pFifoMemory, pFifoBlock, 'e');
             CHK_EXIT (ERROR_THREADWRITE_OUT_OF_SEQUENCE_BLOCK)
-         }
+        }
          Blocks++;
          rc = pOwn->pOutputFile->Write (pFifoBlock);
 
@@ -582,7 +817,7 @@ void t_ThreadWrite::run (void)
          {
             LOG_ERROR ("Could not write to destination file %s", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
             LOG_INFO ("Last block sizes: %d - %d - %zd ", pFifoBlock->BufferSize, pFifoBlock->DataSize, pFifoBlock->EwfDataSize)
-            pDevice->AbortReason  = t_Device::ThreadWriteFileError;
+            pDevice->AbortReason  = t_Device::ThreadWriteWriteError;
             pDevice->AbortRequest = true;
          }
          else
@@ -590,8 +825,12 @@ void t_ThreadWrite::run (void)
             CHK_EXIT (rc)
          }
          if (pDevice->HasCompressionThreads() && (pDevice->Acquisition.Format == t_File::EWF) && CONFIG(CheckEwfData))
-            CHK_EXIT (ThreadWriteCheckData (pFifoBlock))
-         CHK_EXIT (t_Fifo::Destroy (pFifoBlock))
+            CHK_EXIT (ThreadWriteDebugCheckLibewfData (pFifoBlock))
+
+         Written += pFifoBlock->DataSize;
+         Finished = (Written >= pDevice->Size);
+
+         CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlock))
       }
       else
       {
@@ -600,13 +839,26 @@ void t_ThreadWrite::run (void)
       }
    }
 
+   // Wait until file handle released and close it
+   // --------------------------------------------
    LOG_INFO ("Waiting for all other threads using the file handle to finish")
-   while ((pDevice->pThreadRead != NULL) ||
-          (pDevice->pThreadHash != NULL) ||                // Wait until all threads that might use the file handle have finished
-          !pDevice->ThreadCompressList.isEmpty())
+   do
    {
-      msleep (THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY);
-   }
+      bool AskedForRelease = false;
+
+      pOwn->SemHandle.lock();
+      FileHandleReleased = (pOwn->FileHandleRequests == 0);
+      pOwn->SemHandle.unlock();
+      if (!FileHandleReleased)
+      {
+         if (!AskedForRelease)
+         {
+            emit SignalFreeMyHandle (pOwn->pDevice);
+            AskedForRelease = true;
+         }
+         msleep (THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY);
+      }
+   } while (!FileHandleReleased);
 
    LOG_INFO ("Closing output file")
    if (pOwn->pOutputFile->Opened())
@@ -614,21 +866,91 @@ void t_ThreadWrite::run (void)
       rc = pOwn->pOutputFile->Close ();
       if (rc == ERROR_THREADWRITE_CLOSE_FAILED)
       {
-         pDevice->AbortReason  = t_Device::ThreadWriteFileError;
+         pDevice->AbortReason  = t_Device::ThreadWriteWriteError;
+         pDevice->AbortRequest = true;
+      }
+   }
+
+   // Image verification
+   // ------------------
+   if (pDevice->Acquisition.VerifyDst && !pDevice->AbortRequest)
+   {
+      t_HashContextMD5      HashContextMD5;
+      t_HashContextSHA256   HashContextSHA256;
+      t_pHashContextMD5    pHashContextMD5    = &HashContextMD5;
+      t_pHashContextSHA256 pHashContextSHA256 = &HashContextSHA256;
+      quint64               Pos = 0;
+
+      if (pDevice->Acquisition.CalcMD5)
+           CHK_EXIT (HashMD5Init (pHashContextMD5))
+      else pHashContextMD5 = NULL;
+
+      if (pDevice->Acquisition.CalcSHA256)
+           CHK_EXIT (HashSHA256Init (pHashContextSHA256))
+      else pHashContextSHA256 = NULL;
+
+      LOG_INFO ("Reopening output file for verification")
+
+      rc = pOutputFile->Open (pDevice, true);
+      if (rc == ERROR_THREADWRITE_OPEN_FAILED)
+      {
+         LOG_INFO ("Could not open destination file %s for verification", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+         pDevice->AbortReason  = t_Device::ThreadWriteVerifyError;
          pDevice->AbortRequest = true;
       }
+      else
+      {
+         CHK_EXIT (rc)
+      }
+
+      Finished = false;
+      while (!Finished && !pDevice->AbortRequest)
+      {
+         rc = pOwn->pOutputFile->Verify (pHashContextMD5, pHashContextSHA256, &Pos);
+         if (rc == ERROR_THREADWRITE_VERIFY_FAILED)
+         {
+            LOG_ERROR ("Could not verify image %s", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+            pDevice->AbortReason  = t_Device::ThreadWriteVerifyError;
+            pDevice->AbortRequest = true;
+         }
+         else
+         {
+            CHK_EXIT (rc)
+            pDevice->SetCurrentVerifyPosDst (Pos);
+            Finished = (Pos >= pDevice->Size);
+            if (Finished)
+            {
+               if (pDevice->Acquisition.CalcMD5)    CHK_EXIT (HashMD5Digest    (pHashContextMD5   , &pDevice->MD5DigestVerifyDst   ))
+               if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Digest (pHashContextSHA256, &pDevice->SHA256DigestVerifyDst))
+            }
+         }
+      }
+      LOG_INFO ("Verification finished, closing output file")
+      if (pOwn->pOutputFile->Opened())
+      {
+         rc = pOwn->pOutputFile->Close ();
+         if (rc == ERROR_THREADWRITE_CLOSE_FAILED)
+         {
+            pDevice->AbortReason  = t_Device::ThreadWriteVerifyError;
+            pDevice->AbortRequest = true;
+         }
+      }
    }
+
+   // Finish
+   // ------
    delete pOwn->pOutputFile;
    pOwn->pOutputFile = NULL;
-   pDevice->State = t_Device::Cleanup;
 
-   if (pDevice->DeleteAfterAbort)
+   if (pDevice->AbortRequest && pDevice->DeleteAfterAbort)
+   {
+      pDevice->State = t_Device::Cleanup;
       CHK_EXIT (DeleteImageFiles (true))
+   }
 
-   pDevice->StopTimestamp = QDateTime::currentDateTime();
-
-   LOG_INFO ("Writing thread exits now (device %s, %Ld blocks processed, %Ld bytes written to output file)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks, pDevice->GetCurrentWritePos ())
+   LOG_INFO ("Write thread exits now (device %s, %Ld blocks processed, %Ld bytes written to output file)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks, pDevice->GetCurrentWritePos ())
 }
+//lint -restore
 
 static APIRET DeleteImageFiles0 (t_pDevice pDevice, const QDir &Dir, const QStringList &NameFilter)
 {
@@ -661,12 +983,17 @@ APIRET t_ThreadWrite::DeleteImageFiles (bool AlsoDeleteInfoFile)
    QDir       DirInfo  (pDevice->Acquisition.InfoPath );
    QString    ExtensionImage;
 
-   CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, &ExtensionImage))
-   CHK (DeleteImageFiles0 (pDevice, DirImage, QStringList(pDevice->Acquisition.ImageFilename + ExtensionImage)))
-
+   if (!pDevice->Acquisition.Clone)
+   {
+      LOG_INFO ("Deleting existing image files of the same name")
+      CHK (t_File::GetFormatExtension (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, &ExtensionImage))
+      CHK (DeleteImageFiles0 (pDevice, DirImage, QStringList(pDevice->Acquisition.ImageFilename + ExtensionImage)))
+   }
    if (AlsoDeleteInfoFile)
+   {
+      LOG_INFO ("Deleting existing info file of the same name")
       CHK (DeleteImageFiles0 (pDevice, DirImage, QStringList(pDevice->Acquisition.InfoFilename + t_File::pExtensionInfo)))
-
+   }
    CHK (pDevice->SetMessage (QString()))
 
    return NO_ERROR;
@@ -681,21 +1008,15 @@ APIRET t_ThreadWrite::GetpFileHandle0 (void **ppHandle)
 {
    *ppHandle = NULL;
 
-   if (!isRunning())
-      return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;
-
-   if (!pOwn->pOutputFile)
-      return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;
+   if (!isRunning())       return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;   // This should normally never happen, as the threads are all created together and only started after that
+   if (!pOwn->pOutputFile) return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;
 
    *ppHandle = pOwn->pOutputFile->GetFileHandle();
-
-   if (!*ppHandle)
-      return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;
+   if (!*ppHandle)         return ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE;
 
    return NO_ERROR;
 }
 
-
 APIRET t_ThreadWrite::GetpFileHandle (void **ppHandle)
 {
    unsigned int Wait=0;
@@ -704,20 +1025,40 @@ APIRET t_ThreadWrite::GetpFileHandle (void **ppHandle)
    *ppHandle = NULL;
    do
    {
-      rc = GetpFileHandle0 (ppHandle);
-      if (rc != ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE)
-         CHK (rc)
-
       if (pOwn->pDevice->AbortRequest)  // May happen, for example, if the write thread wasn't able to open the destination file.
          break;
 
-      Wait += THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY;
-      if (Wait > THREADWRITE_WAIT_FOR_HANDLE)
-         CHK_EXIT (ERROR_THREADWRITE_HANDLE_TIMEOUT)
+      pOwn->SemHandle.lock();
+      rc = GetpFileHandle0 (ppHandle);
+      if ((rc != ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE) && (rc != NO_ERROR))
+      {
+         pOwn->SemHandle.unlock();
+         CHK (rc)
+      }
+      if (*ppHandle == NULL)
+      {
+         pOwn->SemHandle.unlock();
+
+         Wait += THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY;
+         if (Wait > THREADWRITE_WAIT_FOR_HANDLE)
+            CHK_EXIT (ERROR_THREADWRITE_HANDLE_TIMEOUT)
 
-      msleep (THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY);
+         msleep (THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY);
+      }
    } while (*ppHandle == NULL);
 
+   pOwn->FileHandleRequests++;
+   pOwn->SemHandle.unlock();
+
+   return NO_ERROR;
+}
+
+APIRET t_ThreadWrite::ReleaseFileHandle (void)
+{
+   pOwn->SemHandle.lock();
+   pOwn->FileHandleRequests--;
+   pOwn->SemHandle.unlock();
+
    return NO_ERROR;
 }
 
diff --git a/threadwrite.h b/threadwrite.h
index a802f3b..9c9b520 100644
--- a/threadwrite.h
+++ b/threadwrite.h
@@ -31,8 +31,10 @@ class t_ThreadWrite: public QThread
       t_ThreadWrite (t_pDevice pDevice, bool *pSlowDownRequest);
      ~t_ThreadWrite ();
 
-      APIRET GetpFileHandle0 (void **ppHandle);
-      APIRET GetpFileHandle  (void **ppHandle);
+      APIRET GetpFileHandle    (void **ppHandle);
+      APIRET ReleaseFileHandle (void);
+   private:
+      APIRET GetpFileHandle0   (void **ppHandle);
 
    protected:
       void run (void);
@@ -41,7 +43,8 @@ class t_ThreadWrite: public QThread
       APIRET DeleteImageFiles (bool AlsoDeleteInfoFile);
 
    signals:
-      void SignalEnded (t_pDevice pDevice);
+      void SignalEnded        (t_pDevice pDevice);
+      void SignalFreeMyHandle (t_pDevice pDevice);
 
    private slots:
       void SlotFinished (void);
@@ -58,6 +61,7 @@ enum
 {
    ERROR_THREADWRITE_OPEN_FAILED = ERROR_BASE_THREADWRITE + 1,
    ERROR_THREADWRITE_WRITE_FAILED,
+   ERROR_THREADWRITE_VERIFY_FAILED,
    ERROR_THREADWRITE_CLOSE_FAILED,
    ERROR_THREADWRITE_NOT_OPENED,
    ERROR_THREADWRITE_INVALID_FORMAT,
@@ -66,7 +70,8 @@ enum
    ERROR_THREADWRITE_OUT_OF_SEQUENCE_BLOCK,
    ERROR_THREADWRITE_HANDLE_NOT_YET_AVAILABLE,
    ERROR_THREADWRITE_HANDLE_TIMEOUT,
-   ERROR_THREADWRITE_LIBEWF_FAILED
+   ERROR_THREADWRITE_LIBEWF_FAILED,
+   ERROR_THREADWRITE_MALLOC_FAILED,
 };
 
 #endif

-- 
debian-forensics/guymager



More information about the forensics-changes mailing list