/*static char *SCCSID = "@(#)delete.c   6.2 92/01/31";*/
#define BSWAP2 BSWAP2

#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include "heap.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 "fnode.h"
#include "assert.h"
#include "api.h"
#include "lw.h"
#include "superb.h"
#include "pb_ifs.h"
#include "frame.h"
#include "fsdata.h"
#include "notify.h"
#include "pbmacros.h"
#include "ea.h"
#include "log.h"
#include "pr_ALLOC.h"
#include "pr_BITMP.h"
#include "pr_CACHE.h"
#include "pr_DEL.h"
#include "pr_DIR.h"
#include "pr_EA.h"
#include "pr_HEAP.h"
#include "pr_FSSUB.h"
#include "pr_MISC.h"
#include "pr_MOVE.h"

// @76193  #ifdef DEBUG
#include "pr_DEBUG.h"
// @76193  #endif

/*
 ***    Delete - Delete File
 *
 *      ENTRY   fFullDelete = full delete OR just delete entry
 *                       (not fnode & file)
 *          pcp = pointer to cracked path
 *          fTranList = TRUE if there is a transition list entry
 *                  which must be deleted
 *          lsnTranFNode = lsn of FNode in transition list
 *                  (only if fTranList is TRUE)
 *
 *
 *      BUGBUG - 386 code had this comment:
 *          (esi) = user descriptor
 *         - but esi was clobbered in the first few ops.
 *
 *      BUGBUG - 386 code had note:  Check OFT and delay delete if open.
 *           Take out of directory, but leave allocation for continued
 *           access
 *
 *      EXIT    Returns 0 if OK
 *          Returns non-zero error code if error
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *          19-Sep-89 by JR (John Rogers, JohnRo@Microsoft)
 *              - Avoid warnings from Microsoft C 5.2 (on slash-slash comments).
 *          27-Oct-1988 14:37:16 by Mark Hitch [markh] - Update to JGL's 10/24
 *          10-Oct-1988 10:51:54 by Mark Hitch [markh] defined the prototype.
 */

USHORT
Delete (fFullDelete, pcp, pfrm)
BOOL          fFullDelete;
PCRACKEDPATH  pcp;
PFRAME        pfrm;
{
    USHORT  usRet = 0;      /* return code */
    PDIRBLK pdbFound = 0xffff; /* pointer to DIRBLK found */
    PBUFNODE pbufFound;      /* pointer to BUFNODE found */
    PSUBDIR psbdFound;      /* pointer to SUBDIR found */

    PBUFNODE pbufEntry;      /* pointer to BUFNODE of actual entry */
    PDIRBLK pdbEntry = 0xffff; /* pointer to DIRBLK of actual entry */
    PDIRENT pdeEntry;       /* pointer to DIRENT of actual entry */
    LSN     lsnTemp;    /* temporary LSN for faster compares */
    PBUFNODE pbufFNode;
    PFNODE  pfnFNode;
    PVOLTAB pvol;

    if (FindDir (pcp, &pdbFound, &pbufFound, &psbdFound,pfrm)) {

        pvol = pfrm->pvol;
        ASSERT_DB (pdbFound);
        ASSERT_BUF (pbufFound);
        ASSERT_SBD (psbdFound);

        /* convert hold to a lock on this directory */
        DecrHoldsSBD (psbdFound);
        if ( (psbdFound->cusHolds != 0) || (psbdFound->bFlags != 0) ) {
            /* the directory has a pending lock or is held by others.
             *
             * Note that we'll yield here and the directory can be
             * arbitrarily munged, but it won't be deleted so the
             * topmost block is still there.  We just gotta hold the
             * sector in the cache.
             */

            IncrHoldsBUF (pbufFound);  // @76193

            /* LOGL "DLCK", eax */

            LockDir (psbdFound,pfrm);

            /* LOGL "DLGT", eax */

            DecrHoldsBUF (pbufFound);  // @76193
        }

        /* del2: */

        SetLockSBD(psbdFound);

        /* Got the directory.  Look for our file. */

        /* del3: */

        if (LDE (pdbFound,
                 OAC_OF,     /* open file */
                 FALSE,      /* no write thru */
                 pbufFound,
                 FILE_NAME (pcp),
                 &pbufEntry,
                 &pdbEntry,
                 &pdeEntry,
                 FALSE,                          //#90495
                 pfrm) != LDE_NOT_FOUND) {

                                                         //#85759
            if (pbufEntry->bBadMask) {
              UnLockDir ();
	           return (ERROR_READ_FAULT);
            }

            ASSERT_DB (pdbEntry);

            /*
             * Got a match; can't do a full delete on a directory, so we
             * need to check.  We can delete hidden and system files.
             * Also, check to make sure that we aren't trying to delete
             * a file or directory that has an ACL.
             */

            if ((fFullDelete && (pdeEntry->fAttr & ATTR_DIRECTORY)) ||
                ((pdeEntry->fFlags & DF_ACL) != 0) ||
                ((pdeEntry->fAttr & ATTR_READ_ONLY ) != 0)    ) {
#ifdef DEBUG
                if ((pdeEntry->fFlags & DF_ACL) != 0) {
                    dprintf ("Delete: contains ACL, ERROR_ACCESS_DENIED\n");
                }
#endif
                usRet = ERROR_ACCESS_DENIED;
            }


            /* del5: */

            /* put lsnFNode in a local var */
            lsnTemp = pdeEntry->lsnFNode;

            /* Check to see if the file is currently open
             *
             * NOTE:  We don't do OFT hashing!
             *
             * NOTE:  We don't have to check for open files, (file sharing).
             *        The kernel does the check for us.
             */

            if (usRet == 0) {

                /* del10: */

                /* BUGBUG ifndef FULLNODE */

                NotifyCheck(N_DELETE, psbdFound, pdeEntry, pfrm);

                DelEntry (pdbEntry, pdeEntry, pbufEntry, pfrm);

                DecrHoldsBUF (pbufEntry);  // @76193

                UnLockDir ();

                if (!fFullDelete) {
                    /* del20: partial delete exit */
                    return (0);
                }
                else {
                    /* BUGBUG ifndef FULLNODE */

                    if( (pfnFNode = RdBuf (lsnTemp,
                                           BP_TOSS,
                                           &pbufFNode,pfrm)) == NULL) {
                            /* hard error reading fnode */
                        goto del18;
                    }

#ifndef MINIFSD
                    if (pbufFNode->fFlag & BFL_LZREAD) {
                      if (LazyRead (pbufFNode, pfrm))
                        goto del18;
                    }
#endif

                    ASSERT_FN (pfnFNode);

                    IncrHoldsBUF (pbufFNode);  // @76193

                    /* BUGBUG ifdef FULLNODE */

                    /* Deallocate the file */

                    /* write the deallocation via lazy I/O to disk */
                    if (TFA (&pfnFNode->fst.alb,
                             0L, FALSE, pfrm) != TFA_RET_BIT_BLKDEL) {

                        /* hard error with allocation */
                            goto del17;
                    }

                    /*
                     * We've deleted the file's space. Now delete the EA stuff
                     */
#ifdef EAFIX
                    if( (pfnFNode->aiEA.usFNL +
                         (USHORT) pfnFNode->aiEA.sp.cbRun) != 0 ) {

                        USHORT usErr;

                        LOCKSWAP(&swapBSWAP0);
                        usErr = DelEA( pfnFNode,pfrm );
                        UNLOCKSWAP(&swapBSWAP0);

                        if( usErr == ERROR_READ_FAULT  ) {
                            /* Hard Error */
                            goto del17;
                        }

                       /*
                        * Note that for now we just
                        * ignore out of memory errors and just
                        * let chkdsk clean up any orphaned disk
                        * space.
                        */
                    }
#endif

                    /* Everything is gone except for the FNODE.
                     * Clear its signature and release it.
                     */

                    /* del15: */

                    /* wipe that signature off your face
                                   (quote from 386 code) */
                    pfnFNode->sig = 0;

                    DecrHoldsBUF (pbufFNode);  // @76193

                    SetDirt(pfnFNode, pbufFNode, FALSE, pfrm);

                                                            //#85759
                    if (!SetBit(lsnTemp,
                                (ULONG) (sizeof (FNODE) / SECSIZE), pfrm))
                     /* Hard Error */
                      goto del19;
                }
            }
        }
        else
            /* del902: File not Found
             *
             * pbufEntry is still held & directory is locked.
             */
            usRet = ERROR_FILE_NOT_FOUND;

        if (usRet != 0) {
            /* an error has occurred:  we must unlock the directory and
             * unhold the buffer before returning.
             *
             * pbufEntry points to the held buffer.
             * pfrm points to the lock directory.
             */

            UnLockDir ();
            DecrHoldsBUF (pbufEntry);  // @76193
        }
    } else {
     if (pdbFound == NULL)               //#85759
	     usRet = ERROR_READ_FAULT;
       else
       /* del900: Invalid directory */
        usRet = ERROR_PATH_NOT_FOUND;
    }

#ifdef DEBUG
    if (fFullDelete) {
        VBS ();
    }
#endif

    return GetHardErr(usRet);



    /*
     ** Hard error - fnode buffer is still held
     */
del17:
    DecrHoldsBUF( pbufFNode );  // @76193

    /*
     ** Hard error - mark the disk corrupt.  We've removed the directory
     *  name, so we don't need to mark the file corrupt.
     */
del18:
    MarkBadDisk(pfrm);
del19:
    return GetHrdErr_();
}
