/*static char *SCCSID = "@(#)fs_pthin.c 6.6 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 "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "notify.h"
#include "fnode.h"
#include "ea.h"
#include "heap.h"
#include "shutdown.h"
#include "log.h"                                                 // @76193
#include "pr_fsd.h"
#include "pr_CACHE.h"
#include "pr_DIR.h"
#include "pr_EA.h"
#include "pr_FCN.h"
#include "pr_HEAP.h"
#include "pr_MISC.h"
#include "pr_WRSUB.h"
#include "pr_DEBUG.h"

/*
 * HISTORY:
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 */

int far pascal
FS_PATHINFO (flag, pcdfsi, pcdfsd, pName, iCurDirEnd, level, pData, cbData)
USHORT            flag;
struct cdfsi far *pcdfsi;
struct cdfsd far *pcdfsd;
PCHAR             pName;
USHORT            iCurDirEnd;
USHORT            level;
PCHAR             pData;
USHORT            cbData;
{
   PCRACKEDPATH pcp;
   USHORT       erc;
   PBUFNODE     pbuf;
   PDIRBLK      pdb;
   PDIRENT      pde;
   FRAME        frm;
   BOOL fLevel = FALSE;
   SHUTDOWN_LOCAL_VARS;

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

   frm.usHardErr = NO_ERROR;
   frm.fRecheckAddr = TRUE;

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

   if (level == 7) {
      /* erc is already set to NO_ERROR, from the call to CrackPath. */

      erc = QueryPathCasePerserve(pcdfsi->cdi_hVPB,pName,pData,cbData,&frm);
      goto PthInExit2;
   }

   if ((erc = CrackPath(pcdfsi->cdi_hVPB,pName,&pcp,&frm)) != NO_ERROR) {
      goto PthInExit;
   }

   /*  If we were just checking validity of the filename (level 6),
    *  then exit before trying to lookup the directory entry.
    */
   if (level == 6) {
      /* erc is already set to NO_ERROR, from the call to CrackPath. */
      goto PthInExit;
   }

   /*  Use LookFile to find the directory entry.  If LookFile succeeds,
    *  the subdir will be held, but the directory entry's buffer will
    *  not;  if it fails, neither will be held.  LookFile also returns
    *  the appropriate error code.  FindDir will put the subdir for the
    *  parent directory in the frame area; save that value in a local
    *  for later use by NotifyCheck.
    */
   erc = LookFile(pcp,&pdb,&pde,&pbuf,&frm);

   if (erc == NO_ERROR) {
      PFEALIST pfeal;
      PGEALIST pgeal;
      LHANDLE  lhFEA,lhGEA;
      USHORT   oError = 0;

      /*  The buffer for the dirblk and dirent is held
       *  so they may be used in SetPathEA.
       */
      IncrHoldsBUF( pbuf );  // @76193

      if (!(flag & PI_SET)) {
         /*  doing a path query */

         switch(level) {


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

               if (cbData >= sizeof (ATTRIBUTES2)) {

                  /* Probe the buffer before we stuff in the size of
                   * EA's.  We need to do this here since in level 1 below
                   * we do not probe for a attribtes2 struct.
                   */
                  FS_MAYBLOCK (
                     erc = FSH_PROBEBUF(PB_OPWRITE,
                                        pData,
                                        sizeof(ATTRIBUTES2))
                  )

                  if (erc != NO_ERROR) {
                     break;
                  }

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

               } else {
                 erc = ERROR_BUFFER_OVERFLOW;
                 break;
               }

               /* fall thru to do combined level 1 - level 2 stuff */

            case 1:

               if (cbData >= sizeof(ATTRIBUTES)) {

                  erc = QInfoFromPde(pde,MAKETYPE(pData,PATTRIBUTES),&frm);

               } else {

                  erc = ERROR_BUFFER_OVERFLOW;
               }
               break;

            case 3:     /* Return subset EA     */
            case 4:     /* Return all EA stuff  */

               if (cbData >= sizeof (EAOP)) {
                  /* Lock the FEA list in place, verified for
                   * writing.  For level 3, we also have to lock
                   * the GEA list.
                   */

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

                     erc = QPathEA((level == 3 ? pgeal : NULL),
                                   pfeal, pdb, pde,
                                   &oError,
               fLevel,
                                   &frm);

                     UnlockEAs(lhFEA,lhGEA,&frm);

                     if (erc != NO_ERROR) {

                        USHORT usRet;
                        /*  An error occurred processing EAs.  Set
                         *  the oError field of the user's EAOP.
                         */
                        FS_MAYBLOCK(
                             usRet = FSH_PROBEBUF(PB_OPWRITE,
                                                  pData,
                                                  sizeof (EAOP))
                        )
                        if (usRet == NO_ERROR)
                           ((PEAOP)pData)->oError = oError;
                     }
                  }

               } else {
                 erc = ERROR_INSUFFICIENT_BUFFER;
               }

               break;

            default:
               erc = ERROR_NOT_SUPPORTED;
               break;

         } /* switch (level) */

      } else {
         /*  Set information */

         switch(level) {

            case 1:     /* Set timestamps and file attributes */

               if (cbData >= sizeof(ATTRIBUTES)) {
                  /* The notify check must be done here since we don't
                   * have the SUBDIR ptr available in SetInfoToPde.
                   */

                  if ((erc = SetInfoToPde(pde, pbuf,
                                          MAKETYPE(pData,PATTRIBUTES),
                                          flag & IOFL_WRITETHRU,&frm)) == 0) {

                     NotifyCheck(N_SETTIMES,frm.psbd,pde,&frm);
                  }
               } else {
                    erc = ERROR_INSUFFICIENT_BUFFER;
               }
               break;

            case 2:     /*      set EA stuff */

               if (cbData >= sizeof(EAOP)) {
                  /* Lock the FEA list into place, verified
                   * for reading.
                   */
                  if ((erc = LockEAs((PEAOP)pData,
                                     LEAS_SET,
                                     &lhFEA,&lhGEA,
                                     &pfeal,&pgeal,TRUE,&frm)) == NO_ERROR) {

                     frm.u.fWrtThru = flag & IOFL_WRITETHRU;

                     /*      As required by SetPathEA, the subdir
                      *      and buffer are held.
                      */
                     erc = SetPathEA(pfeal,
                                     pdb,
                                     pde,
                                     pbuf,
                                     &oError,
                                     &frm);

                     UnlockEAs(lhFEA,lhGEA,&frm);

                     if (erc != NO_ERROR) {

                        USHORT usRet;
                        /*  An error occurred processing EAs.  Set
                         *  the oError field of the user's EAOP.
                         */
                        FS_MAYBLOCK(
                               usRet = FSH_PROBEBUF(PB_OPWRITE,
                                                    pData,
                                                    sizeof(EAOP))
                        )
                        if (usRet == NO_ERROR) {
                           ((PEAOP)pData)->oError = oError;
                        }
                     }
                  }
               } else {
                   erc = ERROR_INSUFFICIENT_BUFFER;
               }
               break;

            default:
               erc = ERROR_NOT_SUPPORTED;

         } /* switch (level) */
      }
      DecrHoldsBUF (pbuf);  // @76193
      UnHoldDir_(frm.psbd);   /* Release the hold placed by LookFile */

   } /* if of NO_ERROR after LookFile call */

PthInExit:

#ifdef DEBUG
   VBS ();
#endif

   if (pcp != NULL)
      RetHeap (pcp);

PthInExit2:

   DECR_WRITE_THREADS;                 /* Tell shutdown we're done. */
   return(erc);

   pcdfsi, pcdfsd, iCurDirEnd;
}
