Example #1
0
APIRET DeleteFile (PSZ          pszPath,
                   FILEFINDBUF3 *pFileInfo)
{
  APIRET     rc = NO_ERROR;                                /* API-Returncode */
  ULONG      ulAgeCurrent;             /* canonical file are of current file */
  FDATE      fdAgeCurrent;                             /* filedate structure */
  FILESTATUS fStat;                   /* filestatus structure for attributes */
  int        iAnswer;             /* user answer on the confirmation request */
  CHAR       szFileNameBuffer[MAXPATHLEN];         /* buffer for DosEditName */
  FILESTATUS3 fs3;   /* filestatus level 3 information from DosQueryPathInfo */
  CHAR       szFileDate[32];                     /* buffer for the file date */
  CHAR       szFileAttr[6];                /* buffer for the file attributes */
  CHAR       szTokenizerBuffer[MAXPATHLEN];               /* i hate strtok ! */

  if (!Options.fsDontDeleteFiles)              /* if we have to remove files */
  {
                                                            /* check for age */
    if (Options.fsFileAge)                 /* deletion selective on file age */
    {
      if (Options.fsFileAgeWrite)
      {
        fdAgeCurrent = pFileInfo->fdateLastWrite;
        ulAgeCurrent = ToolsDateToAge(fdAgeCurrent.day,
                                      fdAgeCurrent.month,
                                      fdAgeCurrent.year + 1980);
      }
      else
        if (Options.fsFileAgeAccess)
        {
          fdAgeCurrent = pFileInfo->fdateLastAccess;
          ulAgeCurrent = ToolsDateToAge(fdAgeCurrent.day,
                                   fdAgeCurrent.month,
                                   fdAgeCurrent.year + 1980);
        }
        else
          if (Options.fsFileAgeCreate)
          {
            fdAgeCurrent = pFileInfo->fdateCreation;
            ulAgeCurrent = ToolsDateToAge(fdAgeCurrent.day,
                                 fdAgeCurrent.month,
                                 fdAgeCurrent.year + 1980);
          }
          else
          {
                                     /* none specified, take last-write date */
            fdAgeCurrent = pFileInfo->fdateLastWrite;
            ulAgeCurrent = ToolsDateToAge(fdAgeCurrent.day,
                                     fdAgeCurrent.month,
                                     fdAgeCurrent.year + 1980);
          }

                                         /* now check if it is to be deleted */
      if (Options.fsFileAgeNewer)
      {
        if (ulAgeCurrent < Globals.ulFileDate)
          return (NO_ERROR);               /* abort processing for this file */
      }
      else
      {
        if (ulAgeCurrent > Globals.ulFileDate)
          return (NO_ERROR);               /* abort processing for this file */
      }
    }


                                            /* check with the file name mask */
    if (Options.fsFileNameMask)
    {
      PSZ  pszToken;  /* string pointer points to file token within filemask */
      BOOL fMatch;                         /* match - true, no match - false */

      strcpy (szTokenizerBuffer,                /* strtok is a real PITA !!! */
              Options.pszFileNameMask);

      pszToken = strtok(szTokenizerBuffer,                  /* tokenize this */
                        ",");
      fMatch   = FALSE;                               /* this is the default */

      while ( (pszToken != NULL) && /* as long as there is a name to process */
              (fMatch   == FALSE) )                /* and no match was found */
      {
        rc = DosEditName(1,                /* use OS/2 1.2 editing semantics */
                         pFileInfo->achName,                /* source string */
                         pszToken,                         /* editing string */
                         szFileNameBuffer,              /* local name buffer */
                         sizeof (szFileNameBuffer));        /* buffer length */
        if (rc != NO_ERROR)                              /* check for errors */
          return (rc);                              /* raise error condition */

        if (stricmp(pFileInfo->achName,     /* check if filename has changed */
                    szFileNameBuffer) == 0)
          fMatch = TRUE;                       /* the same, abort processing */

        pszToken = strtok(NULL,                    /* skip to the next token */
                          ",");
      }

      if (fMatch == FALSE)                           /* no match was found ! */
        return (NO_ERROR);                  /* then go not beyond this point */
    }


    StrFAttrToStringShort (pFileInfo->attrFile,        /* map the attributes */
                           szFileAttr);

    StrFDateTimeToString (pFileInfo->fdateLastWrite,   /* map the date       */
                          pFileInfo->ftimeLastWrite,
                          szFileDate);

    if (Options.fsSimulation)                    /* simulate deletion only ? */
      printf ("\n  %9u %s %s %s",
              pFileInfo->cbFile,
              szFileAttr,
              szFileDate,
              pFileInfo->achName);
    else
    {
      if (Options.fsVerbose ||                           /* verbose output ? */
          Options.fsShowFiles ||
          Options.fsConfirmationPrompt)
        printf ("\n  %9u %s %s %s",
                pFileInfo->cbFile,
                szFileAttr,
                szFileDate,
                pFileInfo->achName);

      if (Options.fsConfirmationPrompt)       /* prompt for every deletion ? */
      {
        iAnswer = ToolsConfirmationQuery();                  /* ask the user */
        switch (iAnswer)
        {
          case 0:                                                      /* no */
            return (NO_ERROR);                           /* abort processing */

          case 1:                                                     /* yes */
            break;                                           /* continue ... */

          case 2:                                                  /* escape */
            exit (1);                     /* PH: urgs, terminate the process */
        }
      }


      if (Options.fsForceDelete)
        rc = DosForceDelete(pszPath);        /* file will not be recoverable */
      else
        rc = DosDelete(pszPath);                  /* OK, remove that thing ! */

      if ( (rc == ERROR_ACCESS_DENIED) &&             /* check for READ-ONLY */
          Options.fsRemoveAttributes)
      {
        rc = DosQueryPathInfo (pszPath,            /* query file information */
                               FIL_STANDARD,
                               &fStat,
                               sizeof(fStat));
        if (rc != NO_ERROR)                              /* check for errors */
          return (rc);                              /* raise error condition */

        fStat.attrFile = FILE_NORMAL;                /* reset the attributes */

        rc = DosSetPathInfo (pszPath,                 /* set the information */
                             FIL_STANDARD,
                             &fStat,
                             sizeof(fStat),
                             0L);
        if (rc != NO_ERROR)                              /* check for errors */
          return (rc);                              /* raise error condition */

                                                            /* now try again */
        if (Options.fsForceDelete)
          rc = DosForceDelete(pszPath);      /* file will not be recoverable */
        else
          rc = DosDelete(pszPath);                /* OK, remove that thing ! */
      }
    }

    if (rc == NO_ERROR)             /* if the file has actually been deleted */
    {
      Globals.ulDeletedBytes += pFileInfo->cbFile;
      Globals.ulDeletedAlloc += pFileInfo->cbFileAlloc;
      Globals.ulFilesDeleted++;                     /* update the statistics */
    }
  }

  return (rc);                                                         /* ok */
}
Example #2
0
APIRET ProcessFile (PSZ pszPath,
                    PSZ pszFile)
{
  APIRET rc                      = NO_ERROR;    /* this is an API-returncode */
  char   szFileName[MAXPATHLEN];    /* local buffer for a modified file name */
  char   szFileTemp[MAXPATHLEN];    /* local buffer for a modified file name */
  FILE   *fileInput;                            /* handle for the input file */
  FILE   *fileOutput;                          /* handle for the output file */
  char   szLineBuffer[4096];                /* 4k buffer for line processing */


  if ( (pszPath == NULL) ||                              /* check parameters */
       (pszFile == NULL) )
    return (ERROR_INVALID_PARAMETER);                        /* signal error */


  if (Options.fFileOutput == TRUE)   /* check if output pattern is specified */
  {
               /* first we open all needed files, especially the output file */
    rc = DosEditName(1,                 /* OS/2 1.2 filename semantics apply */
                     pszFile,                              /* source pattern */
                     Options.pszFileOutput,          /* modification pattern */
                     szFileName,                                   /* buffer */
                     sizeof(szFileName));                  /* size of buffer */
    if (rc != NO_ERROR)                         /* check if an error occured */
      return (rc);                                           /* signal error */
  }
  else
  {
               /* first we open all needed files, especially the output file */
    rc = DosEditName(1,                 /* OS/2 1.2 filename semantics apply */
                     pszFile,                              /* source pattern */
                     "*.NEW",                        /* modification pattern */
                     szFileName,                                   /* buffer */
                     sizeof(szFileName));                  /* size of buffer */
    if (rc != NO_ERROR)                         /* check if an error occured */
      return (rc);                                           /* signal error */
  }


  strcpy (szFileTemp,                      /* copy the path information data */
          pszPath);
  strcat (szFileTemp,                          /* this is the open file name */
          pszFile);

  if (Options.fQuiet != TRUE)              /* check if output is appreciated */
    printf ("\n[%-34s] -> ",szFileTemp);

  fileInput = fopen(szFileTemp,"r");                     /* open for reading */
  if (fileInput == NULL)                          /* check if opening failed */
    return (ERROR_OPEN_FAILED);                              /* signal error */



  strcpy (szFileTemp,                      /* copy the path information data */
          pszPath);
  strcat (szFileTemp,                         /* this is the write file name */
          szFileName);

  if (Options.fQuiet != TRUE)              /* check if output is appreciated */
    printf ("[%-34s]",szFileTemp);
                                                /* now open the needed files */
  fileOutput = fopen(szFileTemp, "wb");                  /* open for writing */
  if (fileOutput == NULL)                         /* check if opening failed */
  {
    fclose(fileInput);                        /* close the input file handle */
    return (ERROR_OPEN_FAILED);                              /* signal error */
  }

                                         /* set buffers for input and output */
  setvbuf (fileInput,
           Globals.piobufInput,
           _IOFBF,
           IOBUFFERSIZE);

  setvbuf (fileOutput,
           Globals.piobufOutput,
           _IOFBF,
           IOBUFFERSIZE);


  if (Globals.pBufferHeader != NULL)        /* copy the header file at first */
    fwrite(Globals.pBufferHeader,
           Globals.ulHeaderSize,
           1,
           fileOutput);

  /* apply the replacement rules linewise */
  while (!feof(fileInput))       /* until we reach the end of the input file */
  {
    fgets(szLineBuffer,                                   /* read a new line */
          sizeof(szLineBuffer),
          fileInput);
    if (feof(fileInput))    /* abort processing here if last line is reached */
      break;

    Globals.ulProcessedLines++;                    /* correct the statistics */

    RulesApply (Globals.pReplacementRoot,     /* apply the replacement rules */
                szLineBuffer);

    fwrite(szLineBuffer,            /* write the new line to the output file */
           strlen(szLineBuffer),
           1,
           fileOutput);
  }


  if (Globals.pBufferFooter != NULL)       /* append the footer file at last */
    fwrite(Globals.pBufferFooter,
           Globals.ulFooterSize,
           1,
           fileOutput);

  fclose (fileOutput);                        /* close the used file handles */
  fclose (fileInput);

  return (rc);                                                /* return code */
}
Example #3
0
void scan_attributes (PSZ          pszPath,
                      FILEFINDBUF3 *pFileInfo)
{
  char   szFileNameBuffer[MAXPATHLEN];             /* buffer for DosEditName */
  CHAR   szTokenizerBuffer[MAXPATHLEN];                   /* i hate strtok ! */
  APIRET rc;                                               /* API returncode */

  if (Options.fsExcludeDirectories)              /* shall dirs be included ? */
    if (pFileInfo->attrFile & FILE_DIRECTORY)
      return;

                                            /* check with the file name mask */
  if (Options.fsFileNameMask)
  {
    PSZ  pszToken;  /* string pointer points to file token within filemask */
    BOOL fMatch;                         /* match - true, no match - false */

    strcpy (szTokenizerBuffer,                /* strtok is a real PITA !!! */
            Options.pszFileNameMask);

    pszToken = strtok(szTokenizerBuffer,                  /* tokenize this */
                      ",");
    fMatch   = FALSE;                               /* this is the default */

    while ( (pszToken != NULL) && /* as long as there is a name to process */
            (fMatch   == FALSE) )                /* and no match was found */
    {
      rc = DosEditName(1,                /* use OS/2 1.2 editing semantics */
                       pFileInfo->achName,                /* source string */
                       pszToken,                         /* editing string */
                       szFileNameBuffer,              /* local name buffer */
                       sizeof (szFileNameBuffer));        /* buffer length */
      if (rc != NO_ERROR)                              /* check for errors */
        return;                                   /* raise error condition */

      if (stricmp(pFileInfo->achName,     /* check if filename has changed */
                  szFileNameBuffer) == 0)
        fMatch = TRUE;                       /* the same, abort processing */

      pszToken = strtok(NULL,                    /* skip to the next token */
                        ",");
    }

    if (fMatch == FALSE)                           /* no match was found ! */
      return;                             /* then go not beyond this point */
  }


  sprintf (szFileNameBuffer,
           "%s\\%s",
           pszPath,
           pFileInfo->achName);


  /***************************************************************************
   * display file information                                                *
   ***************************************************************************/

  if (Options.fsFiles2)                               /* very verbose output */
  {
    StrFAttrToStringShort (pFileInfo->attrFile,        /* map the attributes */
                           Globals.szFileAttr);

    printf ("\n  %s %s",                              /* attributes and name */
            Globals.szFileAttr,
            szFileNameBuffer);

    StrFDateTimeToString
                  (pFileInfo->fdateCreation,           /* map the date       */
                   pFileInfo->ftimeCreation,
                   Globals.szFileDate);

    printf ("\n        Creation    %s, Actual    Size %9u",
            Globals.szFileDate,
            pFileInfo->cbFile);

    StrFDateTimeToString
                  (pFileInfo->fdateLastAccess,         /* map the date       */
                   pFileInfo->ftimeLastAccess,
                   Globals.szFileDate);

    printf ("\n        Last Access %s, Allocated Size %9u",
            Globals.szFileDate,
            pFileInfo->cbFileAlloc);

    StrFDateTimeToString
                  (pFileInfo->fdateLastWrite,          /* map the date       */
                   pFileInfo->ftimeLastWrite,
                   Globals.szFileDate);

    printf ("\n        Last Write  %s, Slack space    %9i",
            Globals.szFileDate,
            pFileInfo->cbFileAlloc - pFileInfo->cbFile);

    if ( (pFileInfo->cbFileAlloc != 0) &&
         (pFileInfo->cbFileAlloc < pFileInfo->cbFile) )
      printf ("\n                                      Compression       1:%2.2f",
              (float)pFileInfo->cbFile / (float)pFileInfo->cbFileAlloc);
  }
  else
    if (Options.fsFiles)           /* if we have to display file information */
    {
      StrFAttrToStringShort (pFileInfo->attrFile,      /* map the attributes */
                             Globals.szFileAttr);

      StrFDateTimeToString
                    (pFileInfo->fdateLastWrite,        /* map the date       */
                     pFileInfo->ftimeLastWrite,
                     Globals.szFileDate);

      printf ("\n  %9u %s %s %s",
              pFileInfo->cbFile,
              Globals.szFileAttr,
              Globals.szFileDate,
              szFileNameBuffer);
    }


  /***************************************************************************
   * attribute flags                                                         *
   ***************************************************************************/

  if (pFileInfo->cbFileAlloc < pFileInfo->cbFile)
    Globals.attrCompressed++;

  if (!pFileInfo->attrFile)
    Globals.attrNormal++;

  if (pFileInfo->attrFile & FILE_HIDDEN)
    Globals.attrHidden++;

  if (pFileInfo->attrFile & FILE_READONLY)
    Globals.attrReadonly++;

  if (pFileInfo->attrFile & FILE_DIRECTORY)
    Globals.attrDirectory++;

  if ((pFileInfo->achName[0] == '.') &&
      (( !pFileInfo->achName[1] ||
      ((pFileInfo->achName[1] == '.') && !pFileInfo->achName[2])) ))
      Globals.attrDirpseudo++;

  if (pFileInfo->attrFile & FILE_ARCHIVED)
    Globals.attrArchived++;

  if (pFileInfo->attrFile & FILE_SYSTEM)
    Globals.attrSystem++;

                                                /* Find undefined attributes */
  if (pFileInfo->attrFile & 0xffffffc0)
    Globals.attrUndefined++;


  /***************************************************************************
   * minimum and maximum compression                                         *
   ***************************************************************************/
  {
    float fCompressionRate;

    if ( (pFileInfo->cbFileAlloc != 0) &&                   /* prevent div 0 */
         (pFileInfo->cbFileAlloc < pFileInfo->cbFile) )
    {
      fCompressionRate = (float)pFileInfo->cbFile /
                         (float)pFileInfo->cbFileAlloc;

      Globals.fTotalCompression += fCompressionRate;     /* build up the sum */

      if ( (fCompressionRate > Globals.fMaximumCompression) ||    /* maximum */
           (Globals.bMaximumCompression == FALSE) )
      {
        Globals.fMaximumCompression = fCompressionRate;
        Globals.bMaximumCompression = TRUE;

        strcpy (Globals.pszMaximumCompression,
                szFileNameBuffer);
      }

      if ( (fCompressionRate < Globals.fMinimumCompression) ||    /* minimum */
           (Globals.bMinimumCompression == FALSE) )
      {
        Globals.fMinimumCompression = fCompressionRate;
        Globals.bMinimumCompression = TRUE;

        strcpy (Globals.pszMinimumCompression,
                szFileNameBuffer);
      }
    }
  }


  /***************************************************************************
   * minimum and maximum file and allocation size                            *
   ***************************************************************************/
  {
    int iSlackSpace = pFileInfo->cbFileAlloc - pFileInfo->cbFile;

    if ( (pFileInfo->cbFile > Globals.ulMaximumFileSize) ||
         (Globals.bMaximumFileSize == FALSE) )
    {
      Globals.ulMaximumFileSize = pFileInfo->cbFile;
      Globals.bMaximumFileSize = TRUE;

      strcpy (Globals.pszMaximumFileSize,
              szFileNameBuffer);
    }

    if ( (pFileInfo->cbFileAlloc > Globals.ulMaximumAllocationSize) ||
         (Globals.bMaximumAllocationSize == FALSE) )
    {
      Globals.ulMaximumAllocationSize = pFileInfo->cbFileAlloc;
      Globals.bMaximumAllocationSize = TRUE;

      strcpy (Globals.pszMaximumAllocationSize,
              szFileNameBuffer);
    }

    if ( (iSlackSpace > Globals.iMaximumSlackSpace) ||
         (Globals.bMaximumSlackSpace == FALSE) )
    {
      Globals.iMaximumSlackSpace = iSlackSpace;
      Globals.bMaximumSlackSpace = TRUE;

      strcpy (Globals.pszMaximumSlackSpace,
              szFileNameBuffer);
    }

    if ( (pFileInfo->cbFile < Globals.ulMinimumFileSize) ||
         (Globals.bMinimumFileSize == FALSE) )
    {
      Globals.ulMinimumFileSize = pFileInfo->cbFile;
      Globals.bMinimumFileSize = TRUE;

      strcpy (Globals.pszMinimumFileSize,
              szFileNameBuffer);
    }

    if ( (pFileInfo->cbFileAlloc < Globals.ulMinimumAllocationSize) ||
         (Globals.bMinimumAllocationSize == FALSE) )
    {
      Globals.ulMinimumAllocationSize = pFileInfo->cbFileAlloc;
      Globals.bMinimumAllocationSize = TRUE;

      strcpy (Globals.pszMinimumAllocationSize,
              szFileNameBuffer);
    }

    if ( (iSlackSpace < Globals.iMinimumSlackSpace) ||
         (Globals.bMinimumSlackSpace == FALSE) )
    {
      Globals.iMinimumSlackSpace = iSlackSpace;
      Globals.bMinimumSlackSpace = TRUE;

      strcpy (Globals.pszMinimumSlackSpace,
              szFileNameBuffer);
    }
  }


  /***************************************************************************
   * maximum file dates (most recent files)                                  *
   ***************************************************************************/
  {
    Globals.fTotalAgeCreation   += (float)ToolsDateToAge(pFileInfo->fdateCreation.day,
                                                         pFileInfo->fdateCreation.month,
                                                         pFileInfo->fdateCreation.year + 1980)
                                   - Globals.fTotalAgeCurrent;
    Globals.fTotalAgeLastWrite  += (float)ToolsDateToAge(pFileInfo->fdateLastWrite.day,
                                                         pFileInfo->fdateLastWrite.month,
                                                         pFileInfo->fdateLastWrite.year + 1980)
                                   - Globals.fTotalAgeCurrent;
    Globals.fTotalAgeLastAccess += (float)ToolsDateToAge(pFileInfo->fdateLastAccess.day,
                                                         pFileInfo->fdateLastAccess.month,
                                                         pFileInfo->fdateLastAccess.year + 1980)
                                   - Globals.fTotalAgeCurrent;

    if ( (ToolsDateCompare(pFileInfo->fdateCreation,
                           pFileInfo->ftimeCreation,
                           Globals.fdateMaximumCreation,
                           Globals.ftimeMaximumCreation) > 0 ) ||
         (Globals.bMaximumCreation == FALSE) )
    {
      Globals.fdateMaximumCreation = pFileInfo->fdateCreation;
      Globals.ftimeMaximumCreation = pFileInfo->ftimeCreation;
      Globals.bMaximumCreation = TRUE;

      strcpy (Globals.pszMaximumCreation,
              szFileNameBuffer);
    }

    if ( (ToolsDateCompare(pFileInfo->fdateLastAccess,
                           pFileInfo->ftimeLastAccess,
                           Globals.fdateMaximumLastAccess,
                           Globals.ftimeMaximumLastAccess) > 0 ) ||
         (Globals.bMaximumLastAccess == FALSE) )

    {
      Globals.fdateMaximumLastAccess = pFileInfo->fdateLastAccess;
      Globals.ftimeMaximumLastAccess = pFileInfo->ftimeLastAccess;
      Globals.bMaximumLastAccess = TRUE;

      strcpy (Globals.pszMaximumLastAccess,
              szFileNameBuffer);
    }

    if ( (ToolsDateCompare(pFileInfo->fdateLastWrite,
                           pFileInfo->ftimeLastWrite,
                           Globals.fdateMaximumLastWrite,
                           Globals.ftimeMaximumLastWrite) > 0 ) ||
         (Globals.bMaximumLastWrite == FALSE) )
    {
      Globals.fdateMaximumLastWrite = pFileInfo->fdateLastWrite;
      Globals.ftimeMaximumLastWrite = pFileInfo->ftimeLastWrite;
      Globals.bMaximumLastWrite = TRUE;

      strcpy (Globals.pszMaximumLastWrite,
              szFileNameBuffer);
    }
  }


  /***************************************************************************
   * minimum file dates (oldest files)                                       *
   ***************************************************************************/
  {
    if ( (ToolsDateCompare(pFileInfo->fdateCreation,
                           pFileInfo->ftimeCreation,
                           Globals.fdateMinimumCreation,
                           Globals.ftimeMinimumCreation) < 0 ) ||
         (Globals.bMinimumCreation == FALSE) )
    {
      Globals.fdateMinimumCreation = pFileInfo->fdateCreation;
      Globals.ftimeMinimumCreation = pFileInfo->ftimeCreation;
      Globals.bMinimumCreation = TRUE;

      strcpy (Globals.pszMinimumCreation,
              szFileNameBuffer);
    }

    if ( (ToolsDateCompare(pFileInfo->fdateLastAccess,
                           pFileInfo->ftimeLastAccess,
                           Globals.fdateMinimumLastAccess,
                           Globals.ftimeMinimumLastAccess) < 0 ) ||
         (Globals.bMinimumLastAccess == FALSE) )
    {
      Globals.fdateMinimumLastAccess = pFileInfo->fdateLastAccess;
      Globals.ftimeMinimumLastAccess = pFileInfo->ftimeLastAccess;
      Globals.bMinimumLastAccess = TRUE;

      strcpy (Globals.pszMinimumLastAccess,
              szFileNameBuffer);
    }

    if ( (ToolsDateCompare(pFileInfo->fdateLastWrite,
                           pFileInfo->ftimeLastWrite,
                           Globals.fdateMinimumLastWrite,
                           Globals.ftimeMinimumLastWrite) < 0 ) ||
         (Globals.bMinimumLastWrite == FALSE) )
    {
      Globals.fdateMinimumLastWrite = pFileInfo->fdateLastWrite;
      Globals.ftimeMinimumLastWrite = pFileInfo->ftimeLastWrite;
      Globals.bMinimumLastWrite = TRUE;

      strcpy (Globals.pszMinimumLastWrite,
              szFileNameBuffer);
    }
  }
}
Example #4
0
/**
 * Processes a single file.
 * @returns 0 if successfully processed.
 *          -2 if wrong format.
 *          other error code on failure.
 * @param   pszFile         Name of the file to process.
 * @param   pszFilePattern  File pattern to match pszFile with.
 * @author  knut st. osmundsen ([email protected])
 */
int ProcessFile(const char *pszFile1, unsigned long cbFile1, const char *pszFilePattern)
{
    int             rc = 0;
    FILESTATUS3     fst3;
    int             cchPattern = strlen(pszFilePattern);
    char            szFile2[CCHMAXPATH];
    char            szPattern[CCHMAXPATH];
    const char *    pszFileName;
    const char *    pszPatternName;


    /*
     * Correct the pattern.
     */
    memcpy(szPattern, pszFilePattern, cchPattern+1);
    if (szPattern[cchPattern - 1] == '\\' || szPattern[cchPattern - 1] == '/')
        szPattern[cchPattern++] = '*';
    else
    {
        if (!DosQueryPathInfo((PSZ)pszFilePattern, FIL_STANDARD, &fst3, sizeof(fst3)))
        {
            if (fst3.attrFile & FILE_DIRECTORY)
            {
                szPattern[cchPattern++] = '\\';
                szPattern[cchPattern++] = '*';
            }
        }
    }
    szPattern[cchPattern] = '\0';


    /*
     * Get the filename part of pszFile1.
     */
    pszFileName = strrchr(pszFile1, '\\');
    if (!pszFileName)
        pszFileName = strrchr(pszFile1, '/');
    if (!pszFileName)
        pszFileName = strchr(pszFile1, ':');
    if (!pszFileName)
        pszFileName = pszFile1 - 1;
    pszFileName++;


    /*
     * Get the filename portion of szPattern.
     */
    pszPatternName = strrchr(szPattern, '\\');
    if (!pszPatternName)
        pszPatternName = strrchr(szPattern, '/');
    if (!pszPatternName)
        pszPatternName = strchr(szPattern, ':');
    if (!pszPatternName)
        pszPatternName = szPattern - 1;
    pszPatternName++;


    /*
     * Edit the input name according to the pattern.
     */
    rc = DosEditName(1, (PSZ)pszFileName, (PSZ)pszPatternName, szFile2, sizeof(szFile2));
    if (!rc)
    {
        /*
         * Make fully qualified name.
         */
        if (pszPatternName == szPattern)
        {
            memmove(szFile2 + (int)pszFileName - (int)pszFile1, szFile2, strlen(szFile2) + 1);
            memcpy(szFile2, pszFile1, (int)pszFileName - (int)pszFile1);
        }
        else
        {
            memmove(szFile2 + (int)pszPatternName - (int)szPattern, szFile2, strlen(szFile2) + 1);
            memcpy(szFile2, szPattern, (int)pszPatternName - (int)szPattern);
        }

        /*
         * Check for existance of target.
         */
        rc = DosQueryPathInfo(szFile2, FIL_STANDARD, &fst3, sizeof(fst3));
        if (rc == NO_ERROR && !(fst3.attrFile & FILE_DIRECTORY))
        {
            ULONG   ulAction = 0;
            ULONG   cbFile2 = fst3.cbFile;
            HFILE   hFile1 = NULLHANDLE;
            HFILE   hFile2 = NULLHANDLE;

            rc = DosOpen(szFile2, &hFile2, &ulAction, 0, FILE_NORMAL,
                         OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
                         OPEN_FLAGS_SEQUENTIAL | OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
                         NULL);
            if (!rc)
            {
                ulAction = 0;
                rc = DosOpen((PSZ)pszFile1, &hFile1, &ulAction, 0, FILE_NORMAL,
                             OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
                             OPEN_FLAGS_SEQUENTIAL | OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
                             NULL);
                if (!rc)
                {
                    unsigned long   cMismatches = 0;
                    unsigned long   offRead = 0;

                    while (cbFile1 > 0 && cbFile2 > 0)
                    {
                        static char szBuffer1[0x10000];
                        static char szBuffer2[0x10000];
                        ULONG       cbRead1;
                        ULONG       cbRead2;
                        APIRET      rc1;
                        APIRET      rc2;

                        rc1 = DosRead(hFile1, &szBuffer1[0], min(sizeof(szBuffer1), cbFile1), &cbRead1);
                        cbFile1 -= cbRead1;

                        rc2 = DosRead(hFile2, &szBuffer2[0], min(sizeof(szBuffer2), cbFile2), &cbRead2);
                        cbFile2 -= cbRead2;

                        if (!rc1 && !rc2)
                        {
                            int cbCmp = min(cbRead1, cbRead2);

                            /*
                             * Check if equal using fast compare.
                             */
                            if (memcmp(&szBuffer1[0], &szBuffer2[0], cbCmp))
                            {
                                int i;
                                /*
                                 * Wasn't equal. Display mismatches using slow byte by byte compare.
                                 */
                                for (i = 0; i < cbCmp; i++)
                                {
                                    if (szBuffer1[i] != szBuffer2[i])
                                    {
                                        if (!options.fQuiet)
                                        {
                                            if (cMismatches++ == 0)
                                                printf("Mismatch comparing '%s' and '%s'.\n", pszFile1, szFile2);
                                            printf("at 0x%08x 0x%02x (%c) != 0x%02 (%c)\n",
                                                   offRead + i,
                                                   szBuffer1[i], isprint(szBuffer1[i]) ? szBuffer1[i] : ' ',
                                                   szBuffer2[i], isprint(szBuffer2[i]) ? szBuffer2[i] : ' ');
                                        }
                                        else
                                            cMismatches++;
                                    }
                                }
                            }

                            /*
                             * Check if last read and size is different.
                             */
                            if (cbRead1 != cbRead2)
                            {
                                if (!options.fQuiet)
                                {
                                    if (cMismatches == 0)
                                        printf("Mismatch comparing '%s' and '%s'.\n", pszFile1, szFile2);
                                    printf("Length differs. %d != %d\n",
                                           offRead + cbRead1 + cbFile1,
                                           offRead + cbRead2 + cbFile2);
                                    printf("%d differences so far\n", cMismatches);
                                }
                                rc = 1;
                                break;
                            }

                            /*
                             * Last read?
                             */
                            if (!cbFile1 || !cbFile2)
                            {
                                if (!options.fQuiet)
                                {
                                    if (cMismatches > 0)
                                    {
                                        if (cMismatches == 0)
                                            printf("Mismatch comparing '%s' and '%s'.\n", pszFile1, szFile2);
                                        printf("%d differences\n", cMismatches);
                                    }
                                    else
                                        printf("Successfull. '%s' matches '%s'.\n", pszFile1, szFile2);
                                }
                            }
                        }
                        else
                        {
                            /*
                             * Read Error.
                             */
                            if (rc1)
                                printf("Error: failed to read from '%s'. rc=%d\n", pszFile1, rc1);
                            if (rc2)
                                printf("Error: failed to read from '%s'. rc=%d\n", szFile2, rc2);
                            rc = rc1 ? rc1 : rc2;
                            break;
                        }
                    }

                    DosClose(hFile1);

                    /*
                     * Return number of errors.
                     */
                    if (cMismatches && !rc)
                        rc = cMismatches;
                }
                else
                    fprintf(stderr, "(SYS%04d): Could not open file '%s'.\n", rc, pszFile1);

                DosClose(hFile2);
            }
            else
                fprintf(stderr, "(SYS%04d): Could not open file '%s'.\n", rc, szFile2);
        }
        else
        {
            if (rc)
                fprintf(stderr, "(SYS%04d): File '%s' was not found.\n", rc, szFile2);
            else
                fprintf(stderr, "Error: Can't compare a file with a directory (%s).\n", szFile2);
        }
    }
    else
        fprintf(stderr, "Internal error DosEditName(1, '%s','%s',..) -> rc=%d\n", pszFileName, pszPatternName, rc);

    return rc;
}