/*static char *SCCSID = "@(#)fs_finfo.c 6.4 92/02/21";*/
#define _BTXT _BTXT
#define INCL_DOSERRORS
#include <os2.h>
#include <fsh.h>
#include "api.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "pb_ifs.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "fnode.h"
#include "ea.h"
#include "heap.h"
#include "shutdown.h"
#include "pr_fsd.h"
#include "pr_CACHE.h"
#include "pr_EA.h"
#include "pr_FCN.h"
#include "pr_HEAP.h"
#include "pr_DEBUG.h"
#include "pr_misc.h"

int far pascal
FS_FILEINFO (flag, psffsi, psffsd, level, pData, cbData, IOflag)

USHORT            flag;
struct sffsi far *psffsi;
struct sffsd far *psffsd;
USHORT            level;
char far         *pData;
USHORT            cbData;
USHORT            IOflag;
{
   USHORT erc;
   BOOL fLevel = FALSE;
   SHUTDOWN_LOCAL_VARS;
   PFHT   pfht = ((PPB_SFD)(psffsd->sfd_work))->pfht;
   FRAME  frm;
   ULONG  ulEALen;

   frm.usHardErr = NO_ERROR;
   frm.fRecheckAddr = TRUE;
    frm.fFlag = 0;               // Clear Frame flag  @132506

   INCR_WRITE_THREADS;                 /* Tell shutdown we're writing. */

   frm.pvol = pfht->poft->pVolume;

   /* If we retrieve information */

   if (flag == FI_RETRIEVE) {
     if (level == 5) { /* new level to return null EA list if no EAs exist */
        level = 3;
        fLevel = TRUE;
     }

      switch(level) {

         case 1:     /*  return timestamps, length and attribute */
         case 2:     /*  return timestamps, length, attribute, and EA size */

            /* If there is not enough room in the caller's buffer, set the
             * error code and don't bother to go any further.
             */
            if (cbData <
                ((level == 1) ? sizeof(ATTRIBUTES) : sizeof(ATTRIBUTES2))) {
               erc = ERROR_BUFFER_OVERFLOW;
               goto FS_FInfoExit;
            }

            erc = QInfoFromPoft(pfht->poft,(PATTRIBUTES)pData,&ulEALen,&frm);

            if (erc != NO_ERROR) {
               goto FS_FInfoExit;
            }

            /* for level 2 we need to stuff more things in the callers
             * buffer so re-probe before stuffing.
             */
            if (level == 2) {
          /* Use fsh_probebuf since QInfoFromPoft may have
                * re-probed with a smaller size.
                */
               FS_MAYBLOCK (erc = FSH_PROBEBUF(PB_OPWRITE,pData,cbData));
               if (erc != NO_ERROR)
                  goto FS_FInfoExit;

               /* don't forget to include the size of cbList field */
               ((PATTRIBUTES2)pData)->cbList = ulEALen +
                                               FIELD_SIZE (FEALIST, cbList);
            }
            break;

         case 3:     /*  return select EA stuff */
         case 4:     /*  return all EA stuff    */

            if (cbData < sizeof(EAOP)) {
               /* BUGBUG - Are we really suppose to inforce this? */
               erc = ERROR_BUFFER_OVERFLOW;

            } else {

               PFEALIST pfeal;
               PGEALIST pgeal;
               LHANDLE  lhFEA, lhGEA;
               USHORT   oError = 0;
               USHORT   usRet;           /*  return from FSH_PROBEBUF  */

               /*  Lock the FEA list in place, verified for writing.
                *  For level 3, we also need to lock the GEA list
                *  in place.
                */

               if ((erc = LockEAs((PEAOP)pData,
                                  ((level == 3) ? LEAS_LOCKGEAS : 0),
                                  &lhFEA, &lhGEA,
                                  &pfeal, &pgeal, TRUE, &frm)) == NO_ERROR ) {

                  erc = QueryEA(pfht,
                                ((level == 3) ? pgeal : NULL),
                                pfeal,
                                &oError,
            fLevel,
                                &frm);

                  UnlockEAs(lhFEA,lhGEA,&frm);

                  if (erc != NO_ERROR) {
                     /*  There was an error setting EAs, so we need to
                      *  set the oError of the user's EAOP.
                      */
                     FS_MAYBLOCK(usRet = FSH_PROBEBUF(PB_OPWRITE,pData,sizeof(EAOP)))

                     if (usRet == NO_ERROR)
                        ((PEAOP)pData)->oError = oError;
                  }
               }
            }
            break;

         default:
            erc = ERROR_NOT_SUPPORTED;
      }
   } else {
      /*  flag must be FI_SET  */

      switch(level) {

         case 1:

            if (cbData >= sizeof(ATTRIBUTES)) {

                erc = SetInfoToPoft(pfht->poft,
                                    (PATTRIBUTES)pData,
                                    &(psffsi->sfi_DOSattr),
                                    &frm);

            } else {
                erc = ERROR_INSUFFICIENT_BUFFER;
            }
            break;

         case 2:     /*  set EA stuff */

            if (cbData < sizeof(EAOP)) {

                erc = ERROR_INSUFFICIENT_BUFFER;

            } else {
               PFEALIST pfeal;
               PGEALIST pgeal;
               LHANDLE  lhFEA, lhGEA;
               USHORT   oError = 0;
               USHORT   usRet;       /*  return from FSH_PROBEBUF  */

               if ((erc = LockEAs((PEAOP)pData,LEAS_SET,
                                  &lhFEA,&lhGEA,
                                  &pfeal, &pgeal, TRUE, &frm)) == NO_ERROR ) {

                  /*  The FEA list is locked in place, so we can
                   *  use it at lower levels without continually
                   *  probing it.  Proceed with SetFileEA (since
                   *  we're handed the pfht), then unlock the
                   *  FEA list and set the PEAOP error offset.
                   */
                  frm.u.fWrtThru = IOflag & IOFL_WRITETHRU;

                  erc = SetFileEA(pfht,pfeal,&oError,&frm);

                  UnlockEAs(lhFEA,lhGEA,&frm);

                  if (erc != NO_ERROR) {
                     FS_MAYBLOCK(usRet = FSH_PROBEBUF(PB_OPWRITE, pData, sizeof(EAOP)))

                     if (usRet == NO_ERROR)
                        ((PEAOP)pData)->oError = oError;
                  }
               }
            }
            break;

         default:
            erc = ERROR_NOT_SUPPORTED;
      }
   }

#ifdef DEBUG
   VBS ();
#endif

FS_FInfoExit:

   DECR_WRITE_THREADS;                 /* Let shutdown know we're done. */

   return(erc);

   psffsi; IOflag;
}
