/*static char *SCCSID = "@(#)qfpi.c     6.5 92/02/28";*/
/*************************************************************************/
/*                                                                       */
/* QFPI.C - Pre and post processor for aligned data DosQueryFileInfo and */
/*          DosQueryPathInfo                                             */
/*                                                                       */
/*************************************************************************/

/***  Change History:                                             ***/
/***   noto  11/18/93  Define which segment for Page Tuning DLL   ***/
/***                                                              ***/


#define INCL_DOS
#define INCL_DOSFILEMGR
#define INCL_32
#define INCL_DOSERRORS
#define INCL_NOPMAPI

#include <os2.h>
#include "align32.h"





/***    Define which segment for Page Tuning DLL   ***/

APIRET APIENTRY DOS32QUERYPATHINFO(PSZ , ULONG , PVOID , ULONG);
APIRET APIENTRY DOS32QUERYFILEINFO(HFILE , ULONG , PVOID , ULONG);

#pragma code_seg("CODE32_TUNE1", "CODE")
#pragma code_seg()

#pragma code_seg("CODE32_TUNE3", "CODE")
#pragma code_seg()

#pragma alloc_text(CODE32_TUNE1, DOS32QUERYPATHINFO)
#pragma alloc_text(CODE32_TUNE3, DOS32QUERYFILEINFO)





#define FILE_INFO_1         1               /* it's not defined elsewhere */
#define FILE_INFO_2         2               /* it's not defined elsewhere */
#define FILE_INFO_3         3               /* it's not defined elsewhere */
#define FILE_INFO_4         4               /* it's not defined elsewhere */
#define FILE_INFO_5         5               /* it's not defined elsewhere */
#define FILE_INFO_8         8               /* it's not defined elsewhere */

/*** Dos32QueryFileInfo
 *
 *  pre- and post- processor for aligned data API.
 *
 *  ENTRY:
 *
 *  EXIT:       file info returned
 *
 *  ARGUMENTS:  hf -- handle of the file (opened with write access)
 *              ulInfoLevel -- FILE_INFO_1 -> FILESTATUS3 date/time/size/attr
 *                             FILE_INFO_2 -> FILESTATUS4 ditto plus EA size
 *                             FILE_INFO_3 -> EAs (EAOP)
 *              pInfoBuf -- pointer to EAOP or FILESTATUS(2) struct,
 *                                          depending on ulInfoLevel
 *              cbInfoBuf -- size of InfoBuf
 *
 *  RETURNS:    0 or dos error code
 *
 *  CALLS:      DosQueryFileInfo
 *
 *  WARNINGS:   Will change file's information
 *              The function is not documented as returning the EAOP
 *              unchanged, so it doesn't.
 *
 *  PSEUO-CODE:
 *      BEFORE
 *          if (level 3 || level 5) {
 *              pack EAOP's GEA List
 *          }
 *      AFTER
 *          if (level 3 || level 5) {
 *              unpack EAOP's FEA and GEA lists
 *          }
 *          if (level 2) {
 *              unpack FILESTATUS2 to a FILESTATUS4
 *          }
 *          if (level 1) {
 *              unpack FILESTATUS1 to a FILESTATUS3;
 *          }
 */

APIRET APIENTRY DOS32QUERYFILEINFO(HFILE hf,
                                   ULONG ulInfoLevel,
                                   PVOID pInfoBuf,
                                   ULONG cbInfoBuf) {

   APIRET rc;
   ULONG  cbMaxSize;
   ULONG  cbListTmp;
   PGEA2  pTMP;
   PGEA2  pORG;

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_5) {
      rc = DosAllocMem(&pTMP,(ULONG)(((PEAOP2)pInfoBuf)->fpGEA2List)->cbList,(PAG_COMMIT | PAG_READ | PAG_WRITE));
      if (rc) {
         return(rc);
      }
      rc = PackGEA(((PEAOP2)pInfoBuf)->fpGEA2List,pTMP);
      if (rc) {
         DosFreeMem(pTMP);
         return(rc);
      }
      (PGEA2LIST)pORG = ((PEAOP2)pInfoBuf)->fpGEA2List; /* Save ptr to orginal buffer */
      ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pTMP; /* Point to packed structure */
      ((PEAOP2)pInfoBuf)->oError = 0L;
      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;

   } else if (ulInfoLevel == FILE_INFO_4) {

      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;

   }

   /* If the list is bigger than 64Kb, truncate it to 64Kb for
    * the 16bit call, but remember the real size for unpacking
    */

   /* This could be: if (ulInfoLevel > 2) ...
    * but, that will cause a fault in the case of an invalid level
    * and buffer.
    */

   if ((ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_5) &&
       ((PEAOP2)pInfoBuf)->fpFEA2List->cbList > 0xFFFF) {

      ((PEAOP2)pInfoBuf)->fpFEA2List->cbList = 0xFFFF;
   }

   rc = Dos32PQueryFileInfo(hf,ulInfoLevel,pInfoBuf,cbInfoBuf);

   /*
    * If Infolevel is 1, then the last field of InfoBuf is a short, and
    * must be changed to a long.  Since the 80x86 is little-endian, the
    * least sig. word of the long is first, so the last 2 bytes must be
    * set to zero.
    */
   if (ulInfoLevel == FILE_INFO_1 ) {
      *((PUSHORT)((PBYTE)pInfoBuf + sizeof(FILESTATUS))) = 0;
   }

   if (ulInfoLevel == 2) {

/*    cbListTmp  = ((FILESTATUS2 *)pInfoBuf)->cbList;*/
/*    cbListTmp  =
                     MAKEULONG(((FILESTATUS4 *)pInfoBuf)->cbList,0); */

                cbListTmp = ((FILESTATUS4 *)pInfoBuf)->cbList;

      if (cbListTmp > 4) {
              cbListTmp  *= 2;
              if (cbListTmp > 0xFFFF) {
                  cbListTmp = 0xFFFF;
              }
      }

  /*  Below line not needed since done by the asm code */
  /*    ((FILESTATUS4 *)pInfoBuf)->attrFile =
                     MAKEULONG(((FILESTATUS2 *)pInfoBuf)->attrFile,0); */

      ((FILESTATUS4 *)pInfoBuf)->cbList = cbListTmp;

   }

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_5) {
      BOOL    fAllUnpacked;

      if (ulInfoLevel == FILE_INFO_3 ) {
         ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pORG; /* Point to packed structure */
         DosFreeMem(pTMP);
      }
      if (!rc) {
         fAllUnpacked = UnpackFEA(((PEAOP)pInfoBuf)->fpFEAList,
                                  ((PEAOP2)pInfoBuf)->fpFEA2List,
                                  cbMaxSize,
                                  NULL);

         if (!fAllUnpacked) {
            /* Buffer was not big enough, have to return cbList */
            Dos32PQueryFileInfo(hf,FILE_INFO_2,pInfoBuf,cbInfoBuf);
            rc = ERROR_BUFFER_OVERFLOW;
         }
      }
   }
   return(rc);
}


/*** Dos32ProtectQueryFileInfo
 *
 *  pre- and post- processor for aligned data API.
 *
 *  ENTRY:
 *
 *  EXIT:       file info returned
 *
 *  ARGUMENTS:  hf -- handle of the file (opened with write access)
 *              ulInfoLevel -- FILE_INFO_1 -> FILESTATUS3 date/time/size/attr
 *                             FILE_INFO_2 -> FILESTATUS4 ditto plus EA size
 *                             FILE_INFO_3 -> EAs (EAOP)
 *              pInfoBuf -- pointer to EAOP or FILESTATUS(2) struct,
 *                                          depending on ulInfoLevel
 *              cbInfoBuf -- size of InfoBuf
 *              fhFileHandleLockID -- the key of admittance
 *
 *  RETURNS:    0 or dos error code
 *
 *  CALLS:      DosProtectQueryFileInfo
 *
 *  WARNINGS:   Will change file's information
 *              The function is not documented as returning the EAOP
 *              unchanged, so it doesn't.
 *
 *  PSEUO-CODE:
 *      BEFORE
 *          if (level 3 || level 5) {
 *              pack EAOP's GEA List
 *          }
 *      AFTER
 *          if (level 3 || level 5) {
 *              unpack EAOP's FEA and GEA lists
 *          }
 *          if (level 2) {
 *              unpack FILESTATUS2 to a FILESTATUS4
 *          }
 *          if (level 1) {
 *              unpack FILESTATUS1 to a FILESTATUS3;
 *          }
 */

APIRET APIENTRY DOS32PROTECTQUERYFILEINFO(HFILE hf,
                                   ULONG ulInfoLevel,
                                   PVOID pInfoBuf,
                                   ULONG cbInfoBuf,
                                   FHLOCK fhFileHandleLockID) {

   APIRET rc;
   ULONG  cbMaxSize;
   ULONG  cbListTmp;
   PGEA2  pTMP;
   PGEA2  pORG;

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_5) {
      rc = DosAllocMem(&pTMP,(ULONG)(((PEAOP2)pInfoBuf)->fpGEA2List)->cbList,(PAG_COMMIT | PAG_READ | PAG_WRITE));
      if (rc) {
         return(rc);
      }
      rc = PackGEA(((PEAOP2)pInfoBuf)->fpGEA2List,pTMP);
      if (rc) {
         DosFreeMem(pTMP);
         return(rc);
      }
      (PGEA2LIST)pORG = ((PEAOP2)pInfoBuf)->fpGEA2List; /* Save ptr to orginal buffer */
      ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pTMP; /* Point to packed structure */
      ((PEAOP2)pInfoBuf)->oError = 0L;
      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;

   } else if (ulInfoLevel == FILE_INFO_4) {

      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;

   }

   /* If the list is bigger than 64Kb, truncate it to 64Kb for
    * the 16bit call, but remember the real size for unpacking
    */

   /* This could be: if (ulInfoLevel > 2) ...
    * but, that will cause a fault in the case of an invalid level
    * and buffer.
    */

   if ((ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_5) &&
       ((PEAOP2)pInfoBuf)->fpFEA2List->cbList > 0xFFFF) {

      ((PEAOP2)pInfoBuf)->fpFEA2List->cbList = 0xFFFF;
   }

   rc = Dos32PProtectQueryFileInfo(hf,ulInfoLevel,pInfoBuf,cbInfoBuf,fhFileHandleLockID);

   /*
    * If Infolevel is 1, then the last field of InfoBuf is a short, and
    * must be changed to a long.  Since the 80x86 is little-endian, the
    * least sig. word of the long is first, so the last 2 bytes must be
    * set to zero.
    */
   if (ulInfoLevel == FILE_INFO_1 ) {
      *((PUSHORT)((PBYTE)pInfoBuf + sizeof(FILESTATUS))) = 0;
   }

   if (ulInfoLevel == 2) {

/*    cbListTmp  = ((FILESTATUS2 *)pInfoBuf)->cbList;*/
/*    cbListTmp  =
                     MAKEULONG(((FILESTATUS4 *)pInfoBuf)->cbList,0); */

                cbListTmp = ((FILESTATUS4 *)pInfoBuf)->cbList;

      if (cbListTmp > 4) {
              cbListTmp  *= 2;
              if (cbListTmp > 0xFFFF) {
                  cbListTmp = 0xFFFF;
              }
      }

  /*  Below line not needed since done by the asm code */
  /*    ((FILESTATUS4 *)pInfoBuf)->attrFile =
                     MAKEULONG(((FILESTATUS2 *)pInfoBuf)->attrFile,0); */

      ((FILESTATUS4 *)pInfoBuf)->cbList = cbListTmp;

   }

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_5) {
      BOOL    fAllUnpacked;

      if (ulInfoLevel == FILE_INFO_3 ) {
         ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pORG; /* Point to packed structure */
         DosFreeMem(pTMP);
      }
      if (!rc) {
         fAllUnpacked = UnpackFEA(((PEAOP)pInfoBuf)->fpFEAList,
                                  ((PEAOP2)pInfoBuf)->fpFEA2List,
                                  cbMaxSize,
                                  NULL);

         if (!fAllUnpacked) {
            /* Buffer was not big enough, have to return cbList */
            Dos32PProtectQueryFileInfo(hf,FILE_INFO_2,pInfoBuf,cbInfoBuf,fhFileHandleLockID);
            rc = ERROR_BUFFER_OVERFLOW;
         }
      }
   }
   return(rc);
}


/*** Dos32QueryPathInfo
 *
 *  pre- and post- processor for aligned data API.
 *
 *  ENTRY:
 *
 *  EXIT:       file info returned
 *
 *  ARGUMENTS:  pszPathName -- name of the file.
 *              ulInfoLevel -- FIL_STANDARD -> date, time
 *                             FIL_QUERYEASIZE -> EAs
 *              pInfoBuf -- pointer to EAOP or FILESTATUS struct,
 *                                          depending on ulInfoLevel
 *              cbInfoBuf -- size of InfoBuf
 *
 *  RETURNS:    0 or dos error code
 *
 *  CALLS:      DosQueryPathInfo
 *
 *  WARNINGS:   The function is not documented as returning the EAOP
 *              unchanged, so it doesn't.
 *
 *  PSEUO-CODE:
 *      BEFORE
 *          if (level 3 || level 8) {
 *              pack EAOP's  GEA list
 *          }
 *      AFTER
 *          if (level 1) {
 *              unpack FILESTATUS1 to a FILESTATUS3;
 *          }
 *          if (level 2) {
 *              unpack FILESTATUS2 to a FILESTATUS4
 *          }
 *          if (level 3 || level 8) {
 *              unpack EAOP's FEA list
 *          }
 */
APIRET APIENTRY DOS32QUERYPATHINFO(PSZ   pszPathName,
                                   ULONG ulInfoLevel,
                                   PVOID pInfoBuf,
                                   ULONG cbInfoBuf) {

   APIRET rc;
   ULONG  cbMaxSize;
   ULONG  cbListTmp;
   ULONG  cbListT2;
   PGEA2  pTMP;
   PGEA2  pORG;

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_8 ) {
      rc = DosAllocMem(&pTMP,(ULONG)(((PEAOP2)pInfoBuf)->fpGEA2List)->cbList,(PAG_COMMIT | PAG_READ | PAG_WRITE));
      if (rc) {
         return(rc);
      }
      rc = PackGEA( ((PEAOP2)pInfoBuf)->fpGEA2List, pTMP );
      if (rc) {
         DosFreeMem(pTMP);
         return(rc);
      }
      (PGEA2LIST)pORG = ((PEAOP2)pInfoBuf)->fpGEA2List; /* Save ptr to orginal buffer */
      ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pTMP; /* Point to packed structure */
      ((PEAOP2)pInfoBuf)->oError = 0L;
      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;

   } else if (ulInfoLevel == FILE_INFO_4) {
      cbMaxSize = ((PEAOP2)pInfoBuf)->fpFEA2List->cbList;
   }

   /* If the list is bigger than 64Kb, truncate it to 64Kb for
    * the 16bit call, but remember the real size for unpacking
    */

   /* This could be: if (ulInfoLevel > 2) ...
    * but, that will cause a fault in the case of an invlaid level
    * and buffer.
    */

   if ((ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_8) &&
       ((PEAOP2)pInfoBuf)->fpFEA2List->cbList > 0xFFFF) {

      ((PEAOP2)pInfoBuf)->fpFEA2List->cbList = 0xFFFF;
   }

   rc = Dos32PQueryPathInfo(pszPathName,ulInfoLevel,pInfoBuf,cbInfoBuf);

   /*
    * If Infolevel is 1, then the last field of InfoBuf is a short, and
    * must be changed to a long.  Since the 80x86 is little-endian, the
    * least sig. word of the long is first, so the last 2 bytes must be
    * set to zero.
    */
   if (ulInfoLevel == 1) {
      ((FILESTATUS3 *)pInfoBuf)->attrFile = ((FILESTATUS *)pInfoBuf)->attrFile;
   }

   if (ulInfoLevel == 2) {

/*    cbListTmp  = ((FILESTATUS2 *)pInfoBuf)->cbList;  */
/*    cbListTmp  =
                     MAKEULONG(((FILESTATUS4 *)pInfoBuf)->cbList,0); */

      cbListTmp  =
                     ((FILESTATUS4 *)pInfoBuf)->cbList;

      if (cbListTmp > 4) {
              cbListTmp  *= 2;
              if (cbListTmp > 0xFFFF) {
                  cbListTmp = 0xFFFF;
              }
      }

  /*  Below line not needed since done by the asm code */
  /*  ((FILESTATUS4 *)pInfoBuf)->attrFile =
                     MAKEULONG(((FILESTATUS2 *)pInfoBuf)->attrFile,0); */

      ((FILESTATUS4 *)pInfoBuf)->cbList = cbListTmp;

   }

   if (ulInfoLevel == FILE_INFO_3 || ulInfoLevel == FILE_INFO_4 || ulInfoLevel == FILE_INFO_8) {
      BOOL    fAllUnpacked;
      if (ulInfoLevel == FILE_INFO_3 ) {
         ((PEAOP2)pInfoBuf)->fpGEA2List = (PGEA2LIST)pORG; /* Point to packed structure */
         DosFreeMem(pTMP);
      }
      if (!rc) {
         fAllUnpacked = UnpackFEA(((PEAOP)pInfoBuf)->fpFEAList,
                                  ((PEAOP2)pInfoBuf)->fpFEA2List,
                                  cbMaxSize,
                                  NULL);
         if (!fAllUnpacked) {
            /* Buffer was not big enough, have to return cbList */
            Dos32PQueryPathInfo(pszPathName,FILE_INFO_2,pInfoBuf,cbInfoBuf);
            rc = ERROR_BUFFER_OVERFLOW;
         }
      }
   }
   return(rc);
}
