You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
698 lines
18 KiB
698 lines
18 KiB
/*
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
forkio.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the routines for performing fork reads and writes
|
|
directly by building IRPs and not using NtReadFile/NtWriteFile. This
|
|
should be used only by the FpRead and FpWrite Apis.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (microsoft!jameelh)
|
|
|
|
|
|
Revision History:
|
|
15 Jan 1993 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#define FILENUM FILE_FORKIO
|
|
|
|
#define FORKIO_LOCALS
|
|
#include <afp.h>
|
|
#include <forkio.h>
|
|
#include <gendisp.h>
|
|
|
|
#if DBG
|
|
PCHAR AfpIoForkFunc[] =
|
|
{
|
|
"",
|
|
"READ",
|
|
"WRITE",
|
|
"LOCK",
|
|
"UNLOCK"
|
|
};
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, AfpIoForkRead)
|
|
#pragma alloc_text( PAGE, AfpIoForkWrite)
|
|
#pragma alloc_text( PAGE, AfpIoForkLockUnlock)
|
|
#endif
|
|
|
|
/*** afpIoGenericComplete
|
|
*
|
|
* This is the generic completion routine for a posted io request.
|
|
*/
|
|
NTSTATUS
|
|
afpIoGenericComplete(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PCMPLCTXT pCmplCtxt
|
|
)
|
|
{
|
|
PSDA pSda; // Not valid for Unlock
|
|
struct _ResponsePacket // For lock/unlock request
|
|
{
|
|
union
|
|
{
|
|
BYTE __RangeStart[4];
|
|
BYTE __LastWritten[4];
|
|
};
|
|
};
|
|
|
|
ASSERT(VALID_CTX(pCmplCtxt));
|
|
|
|
if (pCmplCtxt->cc_Func != FUNC_UNLOCK)
|
|
{
|
|
pSda = (PSDA)(pCmplCtxt->cc_pSda);
|
|
ASSERT(VALID_SDA(pSda));
|
|
|
|
if (pCmplCtxt->cc_Func == FUNC_WRITE)
|
|
{
|
|
AfpFreeIOBuffer(pSda);
|
|
}
|
|
else if (!NT_SUCCESS(pIrp->IoStatus.Status) &&
|
|
(pCmplCtxt->cc_Func == FUNC_READ))
|
|
{
|
|
AfpIOFreeBackFillBuffer(pSda);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(pIrp->IoStatus.Status))
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_WARN,
|
|
("afpIoGenericComplete: %s ERROR %lx\n",
|
|
AfpIoForkFunc[pCmplCtxt->cc_Func], pIrp->IoStatus.Status));
|
|
|
|
if (pCmplCtxt->cc_Func != FUNC_UNLOCK)
|
|
{
|
|
if (pIrp->IoStatus.Status == STATUS_FILE_LOCK_CONFLICT)
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_LOCK;
|
|
else if (pIrp->IoStatus.Status == STATUS_END_OF_FILE)
|
|
{
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_NONE;
|
|
if (pIrp->IoStatus.Information == 0)
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_EOF;
|
|
}
|
|
else if (pIrp->IoStatus.Status == STATUS_DISK_FULL)
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_DISK_FULL;
|
|
else pCmplCtxt->cc_SavedStatus = AFP_ERR_MISC;
|
|
}
|
|
else
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_CANT_UNLOCK,
|
|
pIrp->IoStatus.Status,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
if (pCmplCtxt->cc_Func == FUNC_LOCK)
|
|
{
|
|
DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_ERR,
|
|
("afpIoGenericComplete: ForkLock failed %lx, aborting for range %ld,%ld\n",
|
|
pIrp->IoStatus.Status,
|
|
pCmplCtxt->cc_pForkLock->flo_Offset,
|
|
pCmplCtxt->cc_pForkLock->flo_Offset+pCmplCtxt->cc_pForkLock->flo_Size-1));
|
|
AfpForkLockUnlink(pCmplCtxt->cc_pForkLock);
|
|
}
|
|
}
|
|
|
|
else switch (pCmplCtxt->cc_Func)
|
|
{
|
|
case FUNC_WRITE:
|
|
INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataWritten,
|
|
pCmplCtxt->cc_Offst,
|
|
&AfpStatisticsLock);
|
|
pSda->sda_ReplySize = SIZE_RESPPKT;
|
|
if (AfpAllocReplyBuf(pSda) == AFP_ERR_NONE)
|
|
{
|
|
PUTDWORD2DWORD(pRspPkt->__LastWritten,
|
|
pCmplCtxt->cc_Offst + pCmplCtxt->cc_ReqCount);
|
|
}
|
|
else pCmplCtxt->cc_SavedStatus = AFP_ERR_MISC;
|
|
break;
|
|
|
|
case FUNC_READ:
|
|
{
|
|
LONG i, Size;
|
|
PBYTE pBuf;
|
|
BYTE NlChar = pCmplCtxt->cc_NlChar;
|
|
BYTE NlMask = pCmplCtxt->cc_NlMask;
|
|
|
|
INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataRead,
|
|
(ULONG)pIrp->IoStatus.Information,
|
|
&AfpStatisticsLock);
|
|
|
|
Size = (LONG)pIrp->IoStatus.Information;
|
|
#if 0
|
|
// The following code does the right thing as per the spec but
|
|
// the finder seems to think otherwise.
|
|
if (Size < pCmplCtxt->cc_ReqCount)
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_EOF;
|
|
#endif
|
|
if (Size == 0)
|
|
{
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_EOF;
|
|
AfpIOFreeBackFillBuffer(pSda);
|
|
}
|
|
else if (pCmplCtxt->cc_NlMask != 0)
|
|
{
|
|
for (i = 0, pBuf = pSda->sda_ReplyBuf; i < Size; i++, pBuf++)
|
|
{
|
|
if ((*pBuf & NlMask) == NlChar)
|
|
{
|
|
Size = ++i;
|
|
pCmplCtxt->cc_SavedStatus = AFP_ERR_NONE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pSda->sda_ReplySize = (USHORT)Size;
|
|
}
|
|
ASSERT((pCmplCtxt->cc_SavedStatus != AFP_ERR_EOF) ||
|
|
(pSda->sda_ReplySize == 0));
|
|
break;
|
|
|
|
case FUNC_LOCK:
|
|
INTERLOCKED_ADD_ULONG(&AfpServerStatistics.stat_CurrentFileLocks,
|
|
1,
|
|
&AfpStatisticsLock);
|
|
pSda->sda_ReplySize = SIZE_RESPPKT;
|
|
if (AfpAllocReplyBuf(pSda) == AFP_ERR_NONE)
|
|
PUTDWORD2DWORD(pRspPkt->__RangeStart, pCmplCtxt->cc_pForkLock->flo_Offset);
|
|
else pCmplCtxt->cc_SavedStatus = AFP_ERR_MISC;
|
|
break;
|
|
|
|
case FUNC_UNLOCK:
|
|
INTERLOCKED_ADD_ULONG(
|
|
&AfpServerStatistics.stat_CurrentFileLocks,
|
|
(ULONG)-1,
|
|
&AfpStatisticsLock);
|
|
break;
|
|
|
|
default:
|
|
ASSERTMSG(0, "afpIoGenericComplete: Invalid function\n");
|
|
KeBugCheck(0);
|
|
break;
|
|
}
|
|
|
|
if (pIrp->MdlAddress != NULL)
|
|
AfpFreeMdl(pIrp->MdlAddress);
|
|
|
|
AfpFreeIrp(pIrp);
|
|
|
|
if (pCmplCtxt->cc_Func != FUNC_UNLOCK)
|
|
{
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("afpIoGenericComplete: %s Returning %ld\n",
|
|
AfpIoForkFunc[pCmplCtxt->cc_Func], pCmplCtxt->cc_SavedStatus));
|
|
AfpCompleteApiProcessing(pSda, pCmplCtxt->cc_SavedStatus);
|
|
}
|
|
|
|
AfpFreeCmplCtxtBuf(pCmplCtxt);
|
|
|
|
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
|
|
// will stop working on the IRP.
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpIoForkRead
|
|
*
|
|
* Read a chunk of data from the open fork. The read buffer is always the
|
|
* the reply buffer in the sda (sda_ReplyBuf).
|
|
*/
|
|
AFPSTATUS
|
|
AfpIoForkRead(
|
|
IN PSDA pSda, // The session requesting read
|
|
IN POPENFORKENTRY pOpenForkEntry, // The open fork in question
|
|
IN PFORKOFFST pOffset, // Pointer to fork offset
|
|
IN LONG ReqCount, // Size of read request
|
|
IN BYTE NlMask,
|
|
IN BYTE NlChar
|
|
)
|
|
{
|
|
PIRP pIrp = NULL;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
NTSTATUS Status;
|
|
PMDL pMdl = NULL;
|
|
PCMPLCTXT pCmplCtxt;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkRead: Session %ld, Offset %ld, Size %ld, Fork %ld\n",
|
|
pSda->sda_SessionId, pOffset->LowPart, ReqCount, pOpenForkEntry->ofe_ForkId));
|
|
|
|
do
|
|
{
|
|
|
|
// Allocate and initialize the completion context
|
|
|
|
pCmplCtxt = AfpAllocCmplCtxtBuf(pSda);
|
|
if (pCmplCtxt == NULL)
|
|
{
|
|
AfpFreeIOBuffer(pSda);
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
afpInitializeCmplCtxt(pCmplCtxt,
|
|
FUNC_READ,
|
|
pSda->sda_ReadStatus,
|
|
pSda,
|
|
NULL,
|
|
ReqCount,
|
|
pOffset->LowPart);
|
|
pCmplCtxt->cc_NlChar = NlChar;
|
|
pCmplCtxt->cc_NlMask = NlMask;
|
|
|
|
// Allocate and initialize the IRP for this operation.
|
|
if ((pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize)) == NULL)
|
|
{
|
|
AfpFreeIOBuffer(pSda);
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_BUFFERED_IO) == 0)
|
|
{
|
|
// Allocate an Mdl to describe the read buffer
|
|
if ((pMdl = AfpAllocMdl(pSda->sda_ReplyBuf, ReqCount, pIrp)) == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set up the completion routine.
|
|
IoSetCompletionRoutine( pIrp,
|
|
(PIO_COMPLETION_ROUTINE)afpIoGenericComplete,
|
|
pCmplCtxt,
|
|
True,
|
|
True,
|
|
True);
|
|
|
|
pIrpSp = IoGetNextIrpStackLocation(pIrp);
|
|
|
|
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrp->Tail.Overlay.Thread = AfpThread;
|
|
pIrp->RequestorMode = KernelMode;
|
|
|
|
// Get a pointer to the stack location for the first driver.
|
|
// This will be used to pass the original function codes and
|
|
// parameters.
|
|
|
|
pIrpSp->MajorFunction = IRP_MJ_READ;
|
|
pIrpSp->MinorFunction = IRP_MN_NORMAL;
|
|
pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
|
|
|
|
// Copy the caller's parameters to the service-specific portion of the
|
|
// IRP.
|
|
|
|
pIrpSp->Parameters.Read.Length = ReqCount;
|
|
pIrpSp->Parameters.Read.Key = pSda->sda_SessionId;
|
|
pIrpSp->Parameters.Read.ByteOffset = *pOffset;
|
|
|
|
if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_BUFFERED_IO) != 0)
|
|
{
|
|
pIrp->AssociatedIrp.SystemBuffer = pSda->sda_ReplyBuf;
|
|
pIrp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
|
|
}
|
|
else if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_DIRECT_IO) != 0)
|
|
{
|
|
pIrp->MdlAddress = pMdl;
|
|
}
|
|
else
|
|
{
|
|
pIrp->UserBuffer = pSda->sda_ReplyBuf;
|
|
pIrp->MdlAddress = pMdl;
|
|
}
|
|
|
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
|
IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
|
|
|
|
Status = AFP_ERR_EXTENDED; // This makes the caller do nothing and
|
|
} while (False); // the completion routine handles everything
|
|
|
|
if (Status != AFP_ERR_EXTENDED)
|
|
{
|
|
if (pIrp != NULL)
|
|
AfpFreeIrp(pIrp);
|
|
|
|
if (pMdl != NULL)
|
|
AfpFreeMdl(pMdl);
|
|
|
|
if (pCmplCtxt)
|
|
{
|
|
AfpFreeCmplCtxtBuf(pCmplCtxt);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkRead: Returning %ld\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*** AfpIoForkWrite
|
|
*
|
|
* Write a chunk of data to the open fork. The write buffer is always the
|
|
* the write buffer in the sda (sda_IOBuf).
|
|
*/
|
|
AFPSTATUS
|
|
AfpIoForkWrite(
|
|
IN PSDA pSda, // The session requesting read
|
|
IN POPENFORKENTRY pOpenForkEntry, // The open fork in question
|
|
IN PFORKOFFST pOffset, // Pointer to fork offset
|
|
IN LONG ReqCount // Size of write request
|
|
)
|
|
{
|
|
PIRP pIrp = NULL;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
NTSTATUS Status;
|
|
PMDL pMdl = NULL;
|
|
PCMPLCTXT pCmplCtxt;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkWrite: Session %ld, Offset %ld, Size %ld, Fork %ld\n",
|
|
pSda->sda_SessionId, pOffset->LowPart, ReqCount, pOpenForkEntry->ofe_ForkId));
|
|
|
|
do
|
|
{
|
|
// Allocate and initialize the completion context
|
|
pCmplCtxt = AfpAllocCmplCtxtBuf(pSda);
|
|
if (pCmplCtxt == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
afpInitializeCmplCtxt(pCmplCtxt,
|
|
FUNC_WRITE,
|
|
AFP_ERR_NONE,
|
|
pSda,
|
|
NULL,
|
|
ReqCount,
|
|
pOffset->LowPart);
|
|
|
|
// Allocate and initialize the IRP for this operation.
|
|
if ((pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize)) == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_BUFFERED_IO) == 0)
|
|
{
|
|
// Allocate an Mdl to describe the write buffer
|
|
if ((pMdl = AfpAllocMdl(pSda->sda_IOBuf, ReqCount, pIrp)) == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set up the completion routine.
|
|
IoSetCompletionRoutine( pIrp,
|
|
(PIO_COMPLETION_ROUTINE)afpIoGenericComplete,
|
|
pCmplCtxt,
|
|
True,
|
|
True,
|
|
True);
|
|
|
|
pIrpSp = IoGetNextIrpStackLocation(pIrp);
|
|
|
|
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrp->Tail.Overlay.Thread = AfpThread;
|
|
pIrp->RequestorMode = KernelMode;
|
|
|
|
// Get a pointer to the stack location for the first driver.
|
|
// This will be used to pass the original function codes and
|
|
// parameters.
|
|
|
|
pIrpSp->MajorFunction = IRP_MJ_WRITE;
|
|
pIrpSp->MinorFunction = IRP_MN_NORMAL;
|
|
pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
|
|
|
|
// Copy the caller's parameters to the service-specific portion of the
|
|
// IRP.
|
|
|
|
pIrpSp->Parameters.Write.Length = ReqCount;
|
|
pIrpSp->Parameters.Write.Key = pSda->sda_SessionId;
|
|
pIrpSp->Parameters.Write.ByteOffset = *pOffset;
|
|
|
|
if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_BUFFERED_IO) != 0)
|
|
{
|
|
pIrp->AssociatedIrp.SystemBuffer = pSda->sda_IOBuf;
|
|
pIrp->Flags = IRP_BUFFERED_IO;
|
|
}
|
|
else if ((pOpenForkEntry->ofe_pDeviceObject->Flags & DO_DIRECT_IO) != 0)
|
|
{
|
|
pIrp->MdlAddress = pMdl;
|
|
}
|
|
else
|
|
{
|
|
pIrp->UserBuffer = pSda->sda_IOBuf;
|
|
pIrp->MdlAddress = pMdl;
|
|
}
|
|
|
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
|
IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
|
|
|
|
Status = AFP_ERR_EXTENDED; // This makes the caller do nothing and
|
|
} while (False); // the completion routine handles everything
|
|
|
|
if (Status != AFP_ERR_EXTENDED)
|
|
{
|
|
if (pIrp != NULL)
|
|
AfpFreeIrp(pIrp);
|
|
|
|
if (pMdl != NULL)
|
|
AfpFreeMdl(pMdl);
|
|
|
|
if (pCmplCtxt)
|
|
{
|
|
AfpFreeCmplCtxtBuf(pCmplCtxt);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkWrite: Returning %ld\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpIoForkLock
|
|
*
|
|
* Lock/Unlock a section of the open fork.
|
|
*/
|
|
AFPSTATUS
|
|
AfpIoForkLockUnlock(
|
|
IN PSDA pSda,
|
|
IN PFORKLOCK pForkLock,
|
|
IN PFORKOFFST pForkOffset,
|
|
IN PFORKSIZE pLockSize,
|
|
IN BYTE Func
|
|
)
|
|
{
|
|
PIRP pIrp = NULL;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
POPENFORKENTRY pOpenForkEntry = pForkLock->flo_pOpenForkEntry;
|
|
NTSTATUS Status;
|
|
PCMPLCTXT pCmplCtxt;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
ASSERT(VALID_OPENFORKENTRY(pOpenForkEntry));
|
|
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkLockUnlock: %sLOCK Session %ld, Offset %ld, Size %ld, Fork %ld\n",
|
|
(Func == FUNC_LOCK) ? "" : "UN", pSda->sda_SessionId,
|
|
pForkOffset->LowPart, pLockSize->LowPart, pOpenForkEntry->ofe_ForkId));
|
|
|
|
do
|
|
{
|
|
// Allocate and initialize the completion context
|
|
pCmplCtxt = AfpAllocCmplCtxtBuf(pSda);
|
|
if (pCmplCtxt == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
afpInitializeCmplCtxt(pCmplCtxt,
|
|
Func,
|
|
AFP_ERR_NONE,
|
|
pSda,
|
|
pForkLock,
|
|
pForkOffset->LowPart,
|
|
pLockSize->LowPart);
|
|
|
|
// Allocate and initialize the IRP for this operation.
|
|
if ((pIrp = AfpAllocIrp(pOpenForkEntry->ofe_pDeviceObject->StackSize)) == NULL)
|
|
{
|
|
Status = AFP_ERR_MISC;
|
|
break;
|
|
}
|
|
|
|
// Set up the completion routine.
|
|
IoSetCompletionRoutine( pIrp,
|
|
(PIO_COMPLETION_ROUTINE)afpIoGenericComplete,
|
|
pCmplCtxt,
|
|
True,
|
|
True,
|
|
True);
|
|
|
|
pIrpSp = IoGetNextIrpStackLocation(pIrp);
|
|
|
|
pIrp->Tail.Overlay.OriginalFileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrp->Tail.Overlay.Thread = AfpThread;
|
|
pIrp->RequestorMode = KernelMode;
|
|
|
|
// Get a pointer to the stack location for the first driver.
|
|
// This will be used to pass the original function codes and parameters.
|
|
|
|
pIrpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
|
pIrpSp->MinorFunction = (Func == FUNC_LOCK) ? IRP_MN_LOCK : IRP_MN_UNLOCK_SINGLE;
|
|
pIrpSp->FileObject = AfpGetRealFileObject(pOpenForkEntry->ofe_pFileObject);
|
|
pIrpSp->DeviceObject = pOpenForkEntry->ofe_pDeviceObject;
|
|
|
|
// Copy the caller's parameters to the service-specific portion of the IRP.
|
|
|
|
pIrpSp->Parameters.LockControl.Length = pLockSize;
|
|
pIrpSp->Parameters.LockControl.Key = pSda->sda_SessionId;
|
|
pIrpSp->Parameters.LockControl.ByteOffset = *pForkOffset;
|
|
|
|
pIrp->MdlAddress = NULL;
|
|
pIrpSp->Flags = SL_FAIL_IMMEDIATELY | SL_EXCLUSIVE_LOCK;
|
|
|
|
// Now simply invoke the driver at its dispatch entry with the IRP.
|
|
IoCallDriver(pOpenForkEntry->ofe_pDeviceObject, pIrp);
|
|
|
|
// For lock operation this makes the caller do nothing
|
|
// and the completion routine handles everything
|
|
// For unlock operation we complete the request here.
|
|
Status = (Func == FUNC_LOCK) ? AFP_ERR_EXTENDED : AFP_ERR_NONE;
|
|
} while (False);
|
|
|
|
|
|
if ((Status != AFP_ERR_EXTENDED) && (Status != AFP_ERR_NONE))
|
|
{
|
|
if (pIrp != NULL)
|
|
AfpFreeIrp(pIrp);
|
|
|
|
if (pCmplCtxt)
|
|
{
|
|
AfpFreeCmplCtxtBuf(pCmplCtxt);
|
|
}
|
|
}
|
|
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
|
("AfpIoForkLock: Returning %ld\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
PCMPLCTXT
|
|
AfpAllocCmplCtxtBuf(
|
|
IN PSDA pSda
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PBYTE pRetBuffer;
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
|
|
|
|
ASSERT (sizeof(CMPLCTXT) <= pSda->sda_SizeNameXSpace);
|
|
|
|
if (((pSda->sda_Flags & SDA_NAMEXSPACE_IN_USE) == 0) &&
|
|
(sizeof(CMPLCTXT) <= pSda->sda_SizeNameXSpace))
|
|
{
|
|
pRetBuffer = pSda->sda_NameXSpace;
|
|
pSda->sda_Flags |= SDA_NAMEXSPACE_IN_USE;
|
|
}
|
|
else
|
|
{
|
|
pRetBuffer = AfpAllocNonPagedMemory(sizeof(CMPLCTXT));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
|
|
|
|
return ((PCMPLCTXT)(pRetBuffer));
|
|
}
|
|
|
|
|
|
VOID
|
|
AfpFreeCmplCtxtBuf(
|
|
IN PCMPLCTXT pCmplCtxt
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PSDA pSda;
|
|
|
|
|
|
ASSERT(VALID_CTX(pCmplCtxt));
|
|
|
|
pSda = pCmplCtxt->cc_pSda;
|
|
|
|
ASSERT(VALID_SDA(pSda));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
|
|
|
|
#if DBG
|
|
pCmplCtxt->Signature = 0x12341234;
|
|
pCmplCtxt->cc_Func = 0xff;
|
|
pCmplCtxt->cc_pSda = (PSDA)0x12341234;
|
|
pCmplCtxt->cc_pForkLock = (PFORKLOCK)0x12341234;
|
|
pCmplCtxt->cc_SavedStatus = 0x12341234;
|
|
pCmplCtxt->cc_ReqCount = 0x12341234;
|
|
pCmplCtxt->cc_Offst = 0x12341234;
|
|
#endif
|
|
|
|
if (((PBYTE)pCmplCtxt) == pSda->sda_NameXSpace)
|
|
{
|
|
ASSERT(pSda->sda_Flags & SDA_NAMEXSPACE_IN_USE);
|
|
|
|
pSda->sda_Flags &= ~SDA_NAMEXSPACE_IN_USE;
|
|
}
|
|
else
|
|
{
|
|
AfpFreeMemory((PBYTE)(pCmplCtxt));
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
|
|
}
|
|
|
|
|
|
|