1292 lines
35 KiB
C
1292 lines
35 KiB
C
/*
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fsp_fork.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the entry points for the AFP fork APIs queued to
|
||
the FSP. These are all callable from FSP Only.
|
||
|
||
Author:
|
||
|
||
Jameel Hyder (microsoft!jameelh)
|
||
|
||
|
||
Revision History:
|
||
25 Apr 1992 Initial Version
|
||
|
||
Notes: Tab stop: 4
|
||
--*/
|
||
|
||
#define FILENUM FILE_FSP_FORK
|
||
|
||
#include <afp.h>
|
||
#include <gendisp.h>
|
||
#include <fdparm.h>
|
||
#include <pathmap.h>
|
||
#include <forkio.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
// #pragma alloc_text( PAGE, AfpFspDispOpenFork) // Do not page this out for perf.
|
||
// #pragma alloc_text( PAGE, AfpFspDispCloseFork) // Do not page this out for perf.
|
||
#pragma alloc_text( PAGE, AfpFspDispGetForkParms)
|
||
#pragma alloc_text( PAGE, AfpFspDispSetForkParms)
|
||
// #pragma alloc_text( PAGE, AfpFspDispRead) // Do not page this out for perf.
|
||
// #pragma alloc_text( PAGE, AfpFspDispWrite) // Do not page this out for perf.
|
||
#pragma alloc_text( PAGE, AfpFspDispByteRangeLock)
|
||
#pragma alloc_text( PAGE, AfpFspDispFlushFork)
|
||
#endif
|
||
|
||
/*** AfpFspDispOpenFork
|
||
*
|
||
* This is the worker routine for the AfpOpenFork API.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_AfpSubFunc BYTE Resource/Data Flag
|
||
* sda_ReqBlock PCONNDESC pConnDesc
|
||
* sda_ReqBlock DWORD ParentDirId
|
||
* sda_ReqBlock DWORD Bitmap
|
||
* sda_ReqBlock DWORD AccessMode
|
||
* sda_Name1 ANSI_STRING Path
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispOpenFork(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
DWORD Bitmap, BitmapI;
|
||
AFPSTATUS RetCode = AFP_ERR_NONE, Status = AFP_ERR_PARAM;
|
||
FILEDIRPARM FDParm;
|
||
PVOLDESC pVolDesc;
|
||
PATHMAPENTITY PME;
|
||
PCONNDESC pConnDesc;
|
||
POPENFORKENTRY pOpenForkEntry = NULL;
|
||
BOOLEAN Resource, CleanupLock = False;
|
||
BYTE OpenMode = 0;
|
||
UNICODE_STRING ParentPath;
|
||
struct _RequestPacket
|
||
{
|
||
PCONNDESC _pConnDesc;
|
||
DWORD _ParentDirId;
|
||
DWORD _Bitmap;
|
||
DWORD _AccessMode;
|
||
};
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __Bitmap[2];
|
||
BYTE __OForkRefNum[2];
|
||
};
|
||
#if DBG
|
||
static PBYTE OpenDeny[] = { "None", "Read", "Write", "ReadWrite" };
|
||
#endif
|
||
|
||
PAGED_CODE( );
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: Entered - Session %ld\n", pSda->sda_SessionId));
|
||
|
||
pConnDesc = pReqPkt->_pConnDesc;
|
||
|
||
ASSERT(VALID_CONNDESC(pConnDesc));
|
||
|
||
pVolDesc = pConnDesc->cds_pVolDesc;
|
||
|
||
ASSERT(VALID_VOLDESC(pVolDesc));
|
||
|
||
Bitmap = pReqPkt->_Bitmap;
|
||
|
||
Resource = ((pSda->sda_AfpSubFunc & FORK_RSRC) == FORK_RSRC) ? True : False;
|
||
|
||
if ((Resource && (Bitmap & FILE_BITMAP_DATALEN)) ||
|
||
(!Resource && (Bitmap & FILE_BITMAP_RESCLEN)))
|
||
{
|
||
return AFP_ERR_BITMAP;
|
||
}
|
||
|
||
do
|
||
{
|
||
AfpInitializeFDParms(&FDParm);
|
||
AfpInitializePME(&PME, 0, NULL);
|
||
|
||
// We will use the PME.pme_Handle for open fork handle
|
||
OpenMode = (BYTE)(pReqPkt->_AccessMode & FORK_OPEN_MASK);
|
||
|
||
// Validate volume type and open modes
|
||
if (!IS_CONN_NTFS(pConnDesc) && !IS_CONN_CD_HFS(pConnDesc))
|
||
{
|
||
// Resource fork only supported on NTFS and CD-HFS
|
||
if (Resource)
|
||
{
|
||
Status = AFP_ERR_OBJECT_NOT_FOUND;
|
||
break;
|
||
}
|
||
if (OpenMode & FORK_OPEN_WRITE)
|
||
{
|
||
Status = AFP_ERR_VOLUME_LOCKED;
|
||
break;
|
||
}
|
||
}
|
||
else if ((OpenMode & FORK_OPEN_WRITE) && IS_VOLUME_RO(pVolDesc))
|
||
{
|
||
Status = AFP_ERR_VOLUME_LOCKED;
|
||
break;
|
||
}
|
||
|
||
BitmapI = FILE_BITMAP_FILENUM |
|
||
FD_BITMAP_PARENT_DIRID |
|
||
FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
|
||
|
||
// Encode the open access into the bitmap for pathmap
|
||
// to use when opening the fork.
|
||
if (Resource)
|
||
{
|
||
BitmapI |= FD_INTERNAL_BITMAP_OPENFORK_RESC;
|
||
}
|
||
if (OpenMode & FORK_OPEN_READ)
|
||
{
|
||
BitmapI |= FD_INTERNAL_BITMAP_OPENACCESS_READ;
|
||
}
|
||
if (OpenMode & FORK_OPEN_WRITE)
|
||
{
|
||
BitmapI |= FD_INTERNAL_BITMAP_OPENACCESS_WRITE;
|
||
}
|
||
|
||
// Encode the deny mode into the bitmap for pathmap
|
||
// to use when opening the fork.
|
||
BitmapI |= ((pReqPkt->_AccessMode >> FORK_DENY_SHIFT) &
|
||
FORK_DENY_MASK) <<
|
||
FD_INTERNAL_BITMAP_DENYMODE_SHIFT;
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: OpenMode %s, DenyMode %s\n",
|
||
OpenDeny[(pReqPkt->_AccessMode & FORK_OPEN_MASK)],
|
||
OpenDeny[(pReqPkt->_AccessMode >> FORK_DENY_SHIFT) & FORK_DENY_MASK]));
|
||
|
||
//
|
||
// Don't allow an FpExchangeFiles to occur while we are referencing
|
||
// the DFE FileId -- we want to make sure we put the right ID into
|
||
// the OpenForkDesc!!
|
||
//
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_ExchangeFilesLock);
|
||
CleanupLock = True;
|
||
if ((Status = AfpMapAfpPathForLookup(pConnDesc,
|
||
pReqPkt->_ParentDirId,
|
||
&pSda->sda_Name1,
|
||
pSda->sda_PathType,
|
||
DFE_FILE,
|
||
Bitmap | BitmapI |
|
||
// Need these for drop folder
|
||
// checking
|
||
FILE_BITMAP_DATALEN | FILE_BITMAP_RESCLEN,
|
||
&PME,
|
||
&FDParm)) != AFP_ERR_NONE)
|
||
{
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: AfpMapAfpPathForLookup %lx\n", Status));
|
||
|
||
// If we got a DENY_CONFLICT error, then we still need the parameters
|
||
// Do an open for nothing with no deny modes to get the parameters.
|
||
PME.pme_Handle.fsh_FileHandle = NULL;
|
||
if (Status == AFP_ERR_DENY_CONFLICT)
|
||
{
|
||
AFPSTATUS xxStatus;
|
||
|
||
// Free up any path-buffer allocated
|
||
if (PME.pme_FullPath.Buffer != NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: (DenyConflict) Freeing path buffer %lx\n",
|
||
PME.pme_FullPath.Buffer));
|
||
AfpFreeMemory(PME.pme_FullPath.Buffer);
|
||
}
|
||
AfpInitializePME(&PME, 0, NULL);
|
||
|
||
BitmapI = FILE_BITMAP_FILENUM |
|
||
FD_BITMAP_PARENT_DIRID |
|
||
FD_INTERNAL_BITMAP_RETURN_PMEPATHS;
|
||
if (Resource)
|
||
{
|
||
BitmapI |= FD_INTERNAL_BITMAP_OPENFORK_RESC;
|
||
}
|
||
xxStatus = AfpMapAfpPathForLookup(pConnDesc,
|
||
pReqPkt->_ParentDirId,
|
||
&pSda->sda_Name1,
|
||
pSda->sda_PathType,
|
||
DFE_FILE,
|
||
Bitmap | BitmapI,
|
||
&PME,
|
||
&FDParm);
|
||
if (!NT_SUCCESS(xxStatus))
|
||
{
|
||
PME.pme_Handle.fsh_FileHandle = NULL;
|
||
Status = xxStatus;
|
||
break;
|
||
}
|
||
}
|
||
else break;
|
||
}
|
||
|
||
if (Status == AFP_ERR_NONE)
|
||
{
|
||
Status = AfpForkOpen(pSda,
|
||
pConnDesc,
|
||
&PME,
|
||
&FDParm,
|
||
pReqPkt->_AccessMode,
|
||
Resource,
|
||
&pOpenForkEntry,
|
||
&CleanupLock);
|
||
}
|
||
|
||
// At this point we have either successfully opened the fork,
|
||
// encountered a DENY_CONFLICT or some other error.
|
||
if ((Status != AFP_ERR_NONE) &&
|
||
(Status != AFP_ERR_DENY_CONFLICT))
|
||
break;
|
||
|
||
// Do drop folder sanity check if someone tries to open for Write only
|
||
if ((Status == AFP_ERR_NONE) &&
|
||
(OpenMode == FORK_OPEN_WRITE) &&
|
||
((FDParm._fdp_RescForkLen != 0) ||
|
||
(FDParm._fdp_DataForkLen != 0)))
|
||
{
|
||
ASSERT (VALID_OPENFORKENTRY(pOpenForkEntry));
|
||
|
||
// If either fork is not empty, and one of them is being
|
||
// opened for write, the user must also have READ access
|
||
// to the parent directory.
|
||
ParentPath = pOpenForkEntry->ofe_pOpenForkDesc->ofd_FilePath;
|
||
// adjust the length to not include the filename
|
||
ParentPath.Length -= pOpenForkEntry->ofe_pOpenForkDesc->ofd_FileName.Length;
|
||
if (ParentPath.Length > 0)
|
||
{
|
||
ParentPath.Length -= sizeof(WCHAR);
|
||
}
|
||
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
||
Status = AfpCheckParentPermissions(pConnDesc,
|
||
FDParm._fdp_ParentId,
|
||
&ParentPath,
|
||
DIR_ACCESS_READ,
|
||
NULL,
|
||
NULL);
|
||
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
||
//
|
||
// We are no longer referencing the FileId or path kept
|
||
// in the OpenForkDesc. Ok for FpExchangeFiles to resume.
|
||
//
|
||
AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
|
||
CleanupLock = False;
|
||
|
||
if (Status != AFP_ERR_NONE)
|
||
{
|
||
AfpForkClose(pOpenForkEntry);
|
||
AfpForkDereference(pOpenForkEntry);
|
||
|
||
// set this to null so it wont be upgraded/deref'd
|
||
// in cleanup below
|
||
pOpenForkEntry = NULL;
|
||
|
||
// Set handle to null since it was closed in AfpForkClose
|
||
// and we wont want it to be closed in cleanup below
|
||
PME.pme_Handle.fsh_FileHandle = NULL;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
|
||
CleanupLock = False;
|
||
}
|
||
|
||
if (RetCode == AFP_ERR_NONE)
|
||
{
|
||
pSda->sda_ReplySize = SIZE_RESPPKT +
|
||
EVENALIGN(AfpGetFileDirParmsReplyLength(&FDParm, Bitmap));
|
||
|
||
if ((RetCode = AfpAllocReplyBuf(pSda)) != AFP_ERR_NONE)
|
||
{
|
||
if (pOpenForkEntry != NULL)
|
||
AfpForkClose(pOpenForkEntry);
|
||
break;
|
||
}
|
||
AfpPackFileDirParms(&FDParm,
|
||
Bitmap,
|
||
pSda->sda_ReplyBuf + SIZE_RESPPKT);
|
||
PUTDWORD2SHORT(pRspPkt->__Bitmap, Bitmap);
|
||
PUTDWORD2SHORT(pRspPkt->__OForkRefNum, (pOpenForkEntry == NULL) ?
|
||
0 : pOpenForkEntry->ofe_OForkRefNum);
|
||
if (Status == AFP_ERR_NONE)
|
||
{
|
||
INTERLOCKED_INCREMENT_LONG(&pConnDesc->cds_cOpenForks);
|
||
}
|
||
}
|
||
else Status = RetCode;
|
||
} while (False);
|
||
|
||
|
||
if (CleanupLock)
|
||
{
|
||
AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
|
||
}
|
||
|
||
// update the disk quota for this user
|
||
if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
|
||
{
|
||
if (AfpConnectionReferenceByPointer(pConnDesc) != NULL)
|
||
{
|
||
afpUpdateDiskQuotaInfo(pConnDesc);
|
||
}
|
||
}
|
||
|
||
if (pOpenForkEntry != NULL)
|
||
{
|
||
if (Status == AFP_ERR_NONE)
|
||
AfpUpgradeHandle(&pOpenForkEntry->ofe_FileSysHandle);
|
||
AfpForkDereference(pOpenForkEntry);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
if (PME.pme_Handle.fsh_FileHandle != NULL)
|
||
AfpIoClose(&PME.pme_Handle);
|
||
}
|
||
|
||
if (PME.pme_FullPath.Buffer != NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_FORKS, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: Freeing path buffer %lx\n",
|
||
PME.pme_FullPath.Buffer));
|
||
AfpFreeMemory(PME.pme_FullPath.Buffer);
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispOpenFork: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
/*** AfpFspDispCloseFork
|
||
*
|
||
* This is the worker routine for the AfpCloseFork API.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispCloseFork(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispCloseFork: Entered - Session %ld, Fork %ld\n",
|
||
pSda->sda_SessionId, pReqPkt->_pOpenForkEntry->ofe_ForkId));
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
AfpForkClose(pReqPkt->_pOpenForkEntry);
|
||
|
||
return AFP_ERR_NONE;
|
||
}
|
||
|
||
|
||
|
||
/*** AfpFspDispGetForkParms
|
||
*
|
||
* This is the worker routine for the AfpGetForkParms API.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
* sda_ReqBlock DWORD Bitmap
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispGetForkParms(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
FILEDIRPARM FDParm;
|
||
DWORD Bitmap;
|
||
AFPSTATUS Status = AFP_ERR_PARAM;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
DWORD _Bitmap;
|
||
};
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __Bitmap[2];
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispGetForkParms: Entered Session %ld, Fork %ld\n",
|
||
pSda->sda_SessionId, pReqPkt->_pOpenForkEntry->ofe_ForkId));
|
||
|
||
Bitmap = pReqPkt->_Bitmap;
|
||
|
||
do
|
||
{
|
||
if ((RESCFORK(pReqPkt->_pOpenForkEntry) && (Bitmap & FILE_BITMAP_DATALEN)) ||
|
||
(DATAFORK(pReqPkt->_pOpenForkEntry) && (Bitmap & FILE_BITMAP_RESCLEN)))
|
||
{
|
||
Status = AFP_ERR_BITMAP;
|
||
break;
|
||
}
|
||
|
||
AfpInitializeFDParms(&FDParm);
|
||
|
||
// Optimize for the most common case.
|
||
if ((Bitmap & (FILE_BITMAP_DATALEN | FILE_BITMAP_RESCLEN)) != 0)
|
||
{
|
||
FORKOFFST ForkLength;
|
||
|
||
Status = AfpIoQuerySize(&pReqPkt->_pOpenForkEntry->ofe_FileSysHandle,
|
||
&ForkLength);
|
||
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
if (Bitmap & FILE_BITMAP_DATALEN)
|
||
FDParm._fdp_DataForkLen = ForkLength.LowPart;
|
||
else FDParm._fdp_RescForkLen = ForkLength.LowPart;
|
||
FDParm._fdp_Flags = 0; // Take out the directory flag
|
||
}
|
||
|
||
// If we need more stuff, go get it
|
||
if (Bitmap & ~(FILE_BITMAP_DATALEN | FILE_BITMAP_RESCLEN))
|
||
{
|
||
CONNDESC ConnDesc;
|
||
POPENFORKDESC pOpenForkDesc = pReqPkt->_pOpenForkEntry->ofe_pOpenForkDesc;
|
||
|
||
// Since the following call requires a pConnDesc and we do not
|
||
// really have one, manufacture it
|
||
ConnDesc.cds_pSda = pSda;
|
||
ConnDesc.cds_pVolDesc = pOpenForkDesc->ofd_pVolDesc;
|
||
|
||
// Don't let FpExchangeFiles come in while we are accessing
|
||
// the stored FileId and its corresponding DFE
|
||
AfpSwmrAcquireExclusive(&ConnDesc.cds_pVolDesc->vds_ExchangeFilesLock);
|
||
|
||
Status = AfpMapAfpIdForLookup(&ConnDesc,
|
||
pOpenForkDesc->ofd_FileNumber,
|
||
DFE_FILE,
|
||
Bitmap & ~(FILE_BITMAP_DATALEN | FILE_BITMAP_RESCLEN),
|
||
NULL,
|
||
&FDParm);
|
||
AfpSwmrRelease(&ConnDesc.cds_pVolDesc->vds_ExchangeFilesLock);
|
||
if (Status != AFP_ERR_NONE)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (Status == AFP_ERR_NONE)
|
||
{
|
||
pSda->sda_ReplySize = SIZE_RESPPKT +
|
||
EVENALIGN(AfpGetFileDirParmsReplyLength(&FDParm, Bitmap));
|
||
|
||
if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
|
||
{
|
||
AfpPackFileDirParms(&FDParm, Bitmap, pSda->sda_ReplyBuf + SIZE_RESPPKT);
|
||
PUTDWORD2SHORT(&pRspPkt->__Bitmap, Bitmap);
|
||
}
|
||
}
|
||
} while (False);
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispGetForkParms: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
/*** AfpFspDispSetForkParms
|
||
*
|
||
* This is the worker routine for the AfpSetForkParms API.
|
||
* Only thing that can be set with this API is the fork length.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
* sda_ReqBlock DWORD Bitmap
|
||
* sda_ReqBlock LONG ForkLength
|
||
*
|
||
* LOCKS: vds_IdDbAccessLock (SWMR, Exclusive)
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispSetForkParms(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
AFPSTATUS Status;
|
||
DWORD Bitmap;
|
||
BOOLEAN SetSize = False;
|
||
PVOLDESC pVolDesc;
|
||
PCONNDESC pConnDesc;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
DWORD _Bitmap;
|
||
LONG _ForkLength;
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispSetForkParms: Entered Session %ld Fork %ld, Length %ld\n",
|
||
pSda->sda_SessionId, pReqPkt->_pOpenForkEntry->ofe_ForkId,
|
||
pReqPkt->_ForkLength));
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
Bitmap = pReqPkt->_Bitmap;
|
||
|
||
do
|
||
{
|
||
if ((RESCFORK(pReqPkt->_pOpenForkEntry) &&
|
||
(pReqPkt->_Bitmap & FILE_BITMAP_DATALEN)) ||
|
||
(DATAFORK(pReqPkt->_pOpenForkEntry) &&
|
||
(pReqPkt->_Bitmap & FILE_BITMAP_RESCLEN)))
|
||
{
|
||
Status = AFP_ERR_BITMAP;
|
||
break;
|
||
}
|
||
|
||
if (!(pReqPkt->_pOpenForkEntry->ofe_OpenMode & FORK_OPEN_WRITE))
|
||
{
|
||
Status = AFP_ERR_ACCESS_DENIED;
|
||
break;
|
||
}
|
||
else if (pReqPkt->_ForkLength >= 0)
|
||
{
|
||
FORKSIZE OldSize;
|
||
|
||
// We don't try to catch our own changes for setting
|
||
// forksize because we don't know how many times the mac
|
||
// will set the size before closing the handle. Since
|
||
// a notification will only come in once the handle is
|
||
// closed, we may pile up a whole bunch of our changes
|
||
// in the list, but only one of them will get satisfied.
|
||
//
|
||
// We also do not want to attempt a change if the current length
|
||
// is same as what it is being set to (this happens a lot,
|
||
// unfortunately). Catch this red-handed.
|
||
|
||
Status = AfpIoQuerySize(&pReqPkt->_pOpenForkEntry->ofe_FileSysHandle,
|
||
&OldSize);
|
||
ASSERT (NT_SUCCESS(Status));
|
||
if (!(((LONG)(OldSize.LowPart) == pReqPkt->_ForkLength) &&
|
||
(OldSize.HighPart == 0)))
|
||
{
|
||
SetSize = True;
|
||
Status = AfpIoSetSize(&pReqPkt->_pOpenForkEntry->ofe_FileSysHandle,
|
||
pReqPkt->_ForkLength);
|
||
|
||
// update the disk quota for this user
|
||
pVolDesc = pReqPkt->_pOpenForkEntry->ofe_pConnDesc->cds_pVolDesc;
|
||
|
||
if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
|
||
{
|
||
pConnDesc = pReqPkt->_pOpenForkEntry->ofe_pConnDesc;
|
||
if (AfpConnectionReferenceByPointer(pConnDesc) != NULL)
|
||
{
|
||
afpUpdateDiskQuotaInfo(pConnDesc);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Update the Dfe view of the fork length. Don't update the cached
|
||
// modified time even though it does change on NTFS immediately
|
||
// (LastWriteTime for setting length of data fork, ChangeTime for
|
||
// setting length of resource fork). We will let the
|
||
// change notify update the modified time when the handle is closed.
|
||
// Appleshare 3.0 and 4.0 do not reflect a changed modified time for
|
||
// changing fork length until the fork is closed (or flushed).
|
||
if (NT_SUCCESS(Status) && SetSize)
|
||
{
|
||
PVOLDESC pVolDesc;
|
||
PDFENTRY pDfEntry;
|
||
POPENFORKDESC pOpenForkDesc;
|
||
|
||
pOpenForkDesc = pReqPkt->_pOpenForkEntry->ofe_pOpenForkDesc;
|
||
pVolDesc = pOpenForkDesc->ofd_pVolDesc;
|
||
|
||
// Don't let FpExchangeFiles come in while we are accessing
|
||
// the stored FileId and its corresponding DFE
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_ExchangeFilesLock);
|
||
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
||
|
||
if ((pDfEntry = AfpFindDfEntryById(pVolDesc,
|
||
pOpenForkDesc->ofd_FileNumber,
|
||
DFE_FILE)) != NULL)
|
||
{
|
||
ASSERT (VALID_DFE(pDfEntry));
|
||
|
||
if (RESCFORK(pReqPkt->_pOpenForkEntry))
|
||
{
|
||
// If a FlushFork occurs on resource fork, it should
|
||
// update the modified time to the ChangeTime
|
||
pReqPkt->_pOpenForkEntry->ofe_Flags |= OPEN_FORK_WRITTEN;
|
||
|
||
pDfEntry->dfe_RescLen = pReqPkt->_ForkLength;
|
||
}
|
||
else
|
||
{
|
||
pDfEntry->dfe_DataLen = pReqPkt->_ForkLength;
|
||
}
|
||
}
|
||
|
||
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
||
AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
|
||
}
|
||
|
||
}
|
||
else Status = AFP_ERR_PARAM;
|
||
} while (False);
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispSetForkParms: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
/*** AfpFspDispRead
|
||
*
|
||
* This routine implements the AfpRead API.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
* sda_ReqBlock LONG Offset
|
||
* sda_ReqBlock LONG Size
|
||
* sda_ReqBlock DWORD NewLine Mask
|
||
* sda_ReqBlock DWORD NewLine Char
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispRead(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
AFPSTATUS Status=AFP_ERR_MISC;
|
||
FORKOFFST LOffset;
|
||
FORKSIZE LSize;
|
||
PFAST_IO_DISPATCH pFastIoDisp;
|
||
IO_STATUS_BLOCK IoStsBlk;
|
||
NTSTATUS NtStatus;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
LONG _Offset;
|
||
LONG _Size;
|
||
DWORD _NlMask;
|
||
DWORD _NlChar;
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispRead: Entered, Session %ld Fork %ld, Offset %ld, Size %ld\n",
|
||
pSda->sda_SessionId, pReqPkt->_pOpenForkEntry->ofe_ForkId,
|
||
pReqPkt->_Offset, pReqPkt->_Size));
|
||
|
||
if ((pReqPkt->_Size < 0) ||
|
||
(pReqPkt->_Offset < 0))
|
||
return AFP_ERR_PARAM;
|
||
|
||
if (!(pReqPkt->_pOpenForkEntry->ofe_OpenMode & FORK_OPEN_READ))
|
||
{
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_WARN,
|
||
("AfpFspDispRead: AfpRead on a Fork not opened for read\n"));
|
||
return AFP_ERR_ACCESS_DENIED;
|
||
}
|
||
|
||
if (pReqPkt->_Size >= 0)
|
||
{
|
||
if (pReqPkt->_Size > (LONG)pSda->sda_MaxWriteSize)
|
||
pReqPkt->_Size = (LONG)pSda->sda_MaxWriteSize;
|
||
|
||
Status = AFP_ERR_NONE;
|
||
|
||
if (pReqPkt->_Size > 0)
|
||
{
|
||
pSda->sda_ReadStatus = AFP_ERR_NONE;
|
||
LOffset.QuadPart = pReqPkt->_Offset;
|
||
LSize.QuadPart = pReqPkt->_Size;
|
||
|
||
if ((pReqPkt->_pOpenForkEntry->ofe_pOpenForkDesc->ofd_UseCount == 1) ||
|
||
(Status = AfpForkLockOperation( pSda,
|
||
pReqPkt->_pOpenForkEntry,
|
||
&LOffset,
|
||
&LSize,
|
||
IOCHECK,
|
||
False)) == AFP_ERR_NONE)
|
||
{
|
||
ASSERT (LSize.HighPart == 0);
|
||
ASSERT ((LONG)(LOffset.LowPart) == pReqPkt->_Offset);
|
||
if ((LONG)(LSize.LowPart) != pReqPkt->_Size)
|
||
pSda->sda_ReadStatus = AFP_ERR_LOCK;
|
||
|
||
Status = AFP_ERR_MISC;
|
||
|
||
pSda->sda_ReplySize = (USHORT)LSize.LowPart;
|
||
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
|
||
//
|
||
// if Read is large enough to justify going to the cache mgr, do it
|
||
//
|
||
if (pSda->sda_ReplySize >= CACHEMGR_READ_THRESHOLD)
|
||
{
|
||
NtStatus = AfpBorrowReadMdlFromCM(pSda);
|
||
}
|
||
|
||
//
|
||
// if we didn't go to the cache mgr, or if we did but cache mgr
|
||
// couldn't satisfy our request, continue with the read
|
||
//
|
||
if (NtStatus != STATUS_PENDING)
|
||
{
|
||
Status = AfpFspDispReadContinue(pSda);
|
||
}
|
||
|
||
//
|
||
// our attempt to get CacheMgr's mdl is pending. Return this
|
||
// error code so we don't complete the api as yet
|
||
//
|
||
else
|
||
{
|
||
Status = AFP_ERR_EXTENDED;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispRead: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
/*** AfpFspDispReadContinue
|
||
*
|
||
* This routine implements the AfpRead API if our attempt to get ReadMdl directly
|
||
* from the cache mgr fails.
|
||
*
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispReadContinue(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
AFPSTATUS Status=AFP_ERR_MISC;
|
||
FORKOFFST LOffset;
|
||
FORKSIZE LSize;
|
||
PFAST_IO_DISPATCH pFastIoDisp;
|
||
IO_STATUS_BLOCK IoStsBlk;
|
||
NTSTATUS NtStatus;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
LONG _Offset;
|
||
LONG _Size;
|
||
DWORD _NlMask;
|
||
DWORD _NlChar;
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
// allocate buffer for the read
|
||
AfpIOAllocBackFillBuffer(pSda);
|
||
|
||
if (pSda->sda_IOBuf != NULL)
|
||
{
|
||
#if DBG
|
||
AfpPutGuardSignature(pSda);
|
||
#endif
|
||
|
||
LOffset.QuadPart = pReqPkt->_Offset;
|
||
LSize.QuadPart = pReqPkt->_Size;
|
||
|
||
// Try the fast I/O path first. If that fails, call AfpIoForkRead
|
||
// to use the normal build-an-IRP path.
|
||
pFastIoDisp = pReqPkt->_pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
|
||
if ((pFastIoDisp != NULL) &&
|
||
(pFastIoDisp->FastIoRead != NULL) &&
|
||
pFastIoDisp->FastIoRead(AfpGetRealFileObject(pReqPkt->_pOpenForkEntry->ofe_pFileObject),
|
||
&LOffset,
|
||
LSize.LowPart,
|
||
True,
|
||
pSda->sda_SessionId,
|
||
pSda->sda_ReplyBuf,
|
||
&IoStsBlk,
|
||
pReqPkt->_pOpenForkEntry->ofe_pDeviceObject))
|
||
{
|
||
LONG i, Size;
|
||
PBYTE pBuf;
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispRead: Fast Read Succeeded\n"));
|
||
|
||
#ifdef PROFILING
|
||
// The fast I/O path worked. Update statistics
|
||
INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
|
||
#endif
|
||
INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataRead,
|
||
(ULONG)IoStsBlk.Information,
|
||
&AfpStatisticsLock);
|
||
Status = pSda->sda_ReadStatus;
|
||
Size = (LONG)IoStsBlk.Information;
|
||
#if 0
|
||
// The following code does the right thing as per the spec but
|
||
// the finder seems to think otherwise.
|
||
if (Size < LSize.LowPart)
|
||
{
|
||
pSda->sda_ReadStatus = AFP_ERR_EOF;
|
||
}
|
||
#endif
|
||
if (Size == 0)
|
||
{
|
||
Status = AFP_ERR_EOF;
|
||
AfpIOFreeBackFillBuffer(pSda);
|
||
}
|
||
else if (pReqPkt->_NlMask != 0)
|
||
{
|
||
for (i = 0, pBuf = pSda->sda_ReplyBuf; i < Size; i++, pBuf++)
|
||
{
|
||
if ((*pBuf & (BYTE)(pReqPkt->_NlMask)) == (BYTE)(pReqPkt->_NlChar))
|
||
{
|
||
Size = ++i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
pSda->sda_ReplySize = (USHORT)Size;
|
||
ASSERT((Status != AFP_ERR_EOF) || (pSda->sda_ReplySize == 0));
|
||
}
|
||
else
|
||
{
|
||
|
||
#ifdef PROFILING
|
||
INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
|
||
#endif
|
||
Status = AfpIoForkRead(pSda,
|
||
pReqPkt->_pOpenForkEntry,
|
||
&LOffset,
|
||
LSize.LowPart,
|
||
(BYTE)pReqPkt->_NlMask,
|
||
(BYTE)pReqPkt->_NlChar);
|
||
}
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
/*** AfpFspDispWrite
|
||
*
|
||
* This routine implements the AfpWrite API.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_AfpSubFunc BYTE EndFlag
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
* sda_ReqBlock LONG Offset
|
||
* sda_ReqBlock LONG Size
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispWrite(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
FORKOFFST LOffset;
|
||
FORKSIZE LSize;
|
||
PFAST_IO_DISPATCH pFastIoDisp;
|
||
IO_STATUS_BLOCK IoStsBlk;
|
||
AFPSTATUS Status = AFP_ERR_NONE;
|
||
BOOLEAN EndFlag, FreeWriteBuf = True;
|
||
PVOLDESC pVolDesc;
|
||
PCONNDESC pConnDesc;
|
||
PREQUEST pRequest;
|
||
BOOLEAN fUpdateQuota=FALSE;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
LONG _Offset;
|
||
LONG _Size;
|
||
};
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __RealOffset[4];
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
EndFlag = (pSda->sda_AfpSubFunc & AFP_END_FLAG) ? True : False;
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispWrite: Entered, Session %ld, Fork %ld, Offset %ld, Size %ld %sRelative\n",
|
||
pSda->sda_SessionId, pReqPkt->_pOpenForkEntry->ofe_ForkId,
|
||
pReqPkt->_Offset, pReqPkt->_Size, EndFlag ? "End" : "Begin"));
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_WARN,
|
||
("AfpFspDispWrite: OForkRefNum = %d, pOpenForkEntry = %lx\n",
|
||
pReqPkt->_pOpenForkEntry->ofe_ForkId,pReqPkt->_pOpenForkEntry));
|
||
do
|
||
{
|
||
pRequest = pSda->sda_Request;
|
||
|
||
//
|
||
// if we got this Mdl from the Cache mgr, we must return it. Also, set
|
||
// the status code such that we con't complete the request as yet, but
|
||
// do so only afte cache mgr tells us that the write completed
|
||
//
|
||
if ((pRequest->rq_WriteMdl != NULL) &&
|
||
(pRequest->rq_CacheMgrContext != NULL))
|
||
{
|
||
PDELAYEDALLOC pDelAlloc;
|
||
|
||
pDelAlloc = pRequest->rq_CacheMgrContext;
|
||
|
||
pReqPkt->_pOpenForkEntry->ofe_Flags |= OPEN_FORK_WRITTEN;
|
||
|
||
ASSERT(pRequest->rq_WriteMdl == pDelAlloc->pMdl);
|
||
ASSERT(!(pDelAlloc->Flags & AFP_CACHEMDL_ALLOC_ERROR));
|
||
|
||
pRequest->rq_CacheMgrContext = NULL;
|
||
|
||
AfpReturnWriteMdlToCM(pDelAlloc);
|
||
|
||
FreeWriteBuf = False;
|
||
Status = AFP_ERR_EXTENDED;
|
||
break;
|
||
}
|
||
|
||
pConnDesc = pReqPkt->_pOpenForkEntry->ofe_pConnDesc;
|
||
|
||
ASSERT(VALID_CONNDESC(pConnDesc));
|
||
|
||
if ((pReqPkt->_Size < 0) ||
|
||
(!EndFlag && (pReqPkt->_Offset < 0)))
|
||
{
|
||
Status = AFP_ERR_PARAM;
|
||
break;
|
||
}
|
||
|
||
ASSERT((pReqPkt->_pOpenForkEntry->ofe_OpenMode & FORK_OPEN_WRITE) &&
|
||
((pReqPkt->_Size == 0) ||
|
||
((pReqPkt->_Size > 0) && (pSda->sda_IOBuf != NULL))));
|
||
|
||
if (pReqPkt->_Size > (LONG)pSda->sda_MaxWriteSize)
|
||
pReqPkt->_Size = (LONG)pSda->sda_MaxWriteSize;
|
||
|
||
// Check if we have a lock conflict and also convert the offset &
|
||
// size to absolute values if end relative
|
||
LOffset.QuadPart = pReqPkt->_Offset;
|
||
LSize.QuadPart = pReqPkt->_Size;
|
||
|
||
if (pReqPkt->_Size == 0)
|
||
{
|
||
if (!(EndFlag && (pReqPkt->_Offset < 0)))
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Skip lock-check if this is the only instance of the open fork and I/O is
|
||
// not end-relative.
|
||
if ((!EndFlag &&
|
||
(pReqPkt->_pOpenForkEntry->ofe_pOpenForkDesc->ofd_UseCount == 1)) ||
|
||
(Status = AfpForkLockOperation( pSda,
|
||
pReqPkt->_pOpenForkEntry,
|
||
&LOffset,
|
||
&LSize,
|
||
IOCHECK,
|
||
EndFlag)) == AFP_ERR_NONE)
|
||
{
|
||
ASSERT (LOffset.HighPart == 0);
|
||
if ((LONG)(LSize.LowPart) != pReqPkt->_Size)
|
||
{
|
||
Status = AFP_ERR_LOCK;
|
||
}
|
||
else if (LSize.LowPart > 0)
|
||
{
|
||
ASSERT(VALID_CONNDESC(pReqPkt->_pOpenForkEntry->ofe_pConnDesc));
|
||
|
||
// Assume write will succeed, set flag for FlushFork.
|
||
// This is a one way flag, i.e. only set, never cleared
|
||
pReqPkt->_pOpenForkEntry->ofe_Flags |= OPEN_FORK_WRITTEN;
|
||
|
||
// Try the fast I/O path first. If that fails, call AfpIoForkWrite
|
||
// to use the normal build-an-IRP path.
|
||
pFastIoDisp = pReqPkt->_pOpenForkEntry->ofe_pDeviceObject->DriverObject->FastIoDispatch;
|
||
if ((pFastIoDisp != NULL) &&
|
||
(pFastIoDisp->FastIoWrite != NULL) &&
|
||
pFastIoDisp->FastIoWrite(AfpGetRealFileObject(pReqPkt->_pOpenForkEntry->ofe_pFileObject),
|
||
&LOffset,
|
||
LSize.LowPart,
|
||
True,
|
||
pSda->sda_SessionId,
|
||
pSda->sda_IOBuf,
|
||
&IoStsBlk,
|
||
pReqPkt->_pOpenForkEntry->ofe_pDeviceObject))
|
||
{
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispWrite: Fast Write Succeeded\n"));
|
||
|
||
#ifdef PROFILING
|
||
// The fast I/O path worked. Update statistics
|
||
INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoSucceeded));
|
||
#endif
|
||
INTERLOCKED_ADD_STATISTICS(&AfpServerStatistics.stat_DataWritten,
|
||
(ULONG)IoStsBlk.Information,
|
||
&AfpStatisticsLock);
|
||
Status = AFP_ERR_NONE;
|
||
}
|
||
else
|
||
{
|
||
#ifdef PROFILING
|
||
INTERLOCKED_INCREMENT_LONG((PLONG)(&AfpServerProfile->perf_NumFastIoFailed));
|
||
#endif
|
||
if ((Status = AfpIoForkWrite(pSda,
|
||
pReqPkt->_pOpenForkEntry,
|
||
&LOffset,
|
||
LSize.LowPart)) == AFP_ERR_EXTENDED)
|
||
{
|
||
FreeWriteBuf = False;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
} while (False);
|
||
|
||
if (FreeWriteBuf)
|
||
{
|
||
AfpFreeIOBuffer(pSda);
|
||
}
|
||
|
||
if (Status == AFP_ERR_NONE)
|
||
{
|
||
pSda->sda_ReplySize = SIZE_RESPPKT;
|
||
if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
|
||
{
|
||
PUTDWORD2DWORD(pRspPkt->__RealOffset, LOffset.LowPart+LSize.LowPart);
|
||
}
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispWrite: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
/*** AfpFspDispByteRangeLock
|
||
*
|
||
* This routine implements the AfpByteRangeLock API.
|
||
* We go ahead and call the file system to do the actual locking/unlocking.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_SubFunc BYTE Start/End Flag AND Lock/Unlock Flag
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
* sda_ReqBlock LONG Offset
|
||
* sda_ReqBlock LONG Length
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispByteRangeLock(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
BOOLEAN EndFlag;
|
||
LOCKOP Lock;
|
||
LONG Offset;
|
||
FORKOFFST LOffset;
|
||
FORKSIZE LSize;
|
||
AFPSTATUS Status = AFP_ERR_PARAM;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
LONG _Offset;
|
||
LONG _Length;
|
||
};
|
||
struct _ResponsePacket
|
||
{
|
||
BYTE __RangeStart[4];
|
||
};
|
||
|
||
ASSERT (sizeof(struct _RequestPacket) <= (MAX_REQ_ENTRIES_PLUS_1)*sizeof(DWORD));
|
||
|
||
PAGED_CODE( );
|
||
|
||
Lock = (pSda->sda_AfpSubFunc & AFP_UNLOCK_FLAG) ? UNLOCK : LOCK;
|
||
EndFlag = (pSda->sda_AfpSubFunc & AFP_END_FLAG) ? True : False;
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispByteRangeLock: %sLock - Session %ld, Fork %ld Offset %ld Len %ld %sRelative\n",
|
||
(Lock == LOCK) ? "":"Un", pSda->sda_SessionId,
|
||
pReqPkt->_pOpenForkEntry->ofe_ForkId,
|
||
pReqPkt->_Offset, pReqPkt->_Length, EndFlag ? "End" : "Begin"));
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
if ((EndFlag && (Lock == UNLOCK)) ||
|
||
(pReqPkt->_Length == 0) ||
|
||
(!EndFlag && (pReqPkt->_Offset < 0))||
|
||
((pReqPkt->_Length < 0) && (pReqPkt->_Length != MAXULONG)))
|
||
NOTHING;
|
||
else
|
||
{
|
||
if (pReqPkt->_Length == MAXULONG)
|
||
pReqPkt->_Length = MAXLONG;
|
||
|
||
LOffset.QuadPart = Offset = pReqPkt->_Offset;
|
||
LSize.QuadPart = pReqPkt->_Length;
|
||
|
||
Status = AfpForkLockOperation(pSda,
|
||
pReqPkt->_pOpenForkEntry,
|
||
&LOffset,
|
||
&LSize,
|
||
Lock,
|
||
EndFlag);
|
||
|
||
if (Status == AFP_ERR_NONE)
|
||
{
|
||
ASSERT (LOffset.HighPart == 0);
|
||
ASSERT (EndFlag ||
|
||
((LONG)(LOffset.LowPart) == Offset));
|
||
pSda->sda_ReplySize = SIZE_RESPPKT;
|
||
if ((Status = AfpAllocReplyBuf(pSda)) == AFP_ERR_NONE)
|
||
PUTDWORD2DWORD(pRspPkt->__RangeStart, LOffset.LowPart);
|
||
}
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispByteRangeLock: Returning %ld\n", Status));
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
/*** AfpFspDispFlushFork
|
||
*
|
||
* This routine implements the AfpFlushFork API. We don't actually do a
|
||
* real flush, we just query for the current forklength and modified time
|
||
* for this open fork handle and update our cached data. Note if 2
|
||
* different handles to the same file are flushed, we may end up with
|
||
* different information for each flush.
|
||
*
|
||
* The request packet is represented below.
|
||
*
|
||
* sda_ReqBlock POPENFORKENTRY pOpenForkEntry
|
||
*/
|
||
AFPSTATUS FASTCALL
|
||
AfpFspDispFlushFork(
|
||
IN PSDA pSda
|
||
)
|
||
{
|
||
FORKOFFST ForkLength;
|
||
DWORD Status;
|
||
PCONNDESC pConnDesc;
|
||
struct _RequestPacket
|
||
{
|
||
POPENFORKENTRY _pOpenForkEntry;
|
||
};
|
||
|
||
PAGED_CODE( );
|
||
|
||
DBGPRINT(DBG_COMP_AFPAPI_FORK, DBG_LEVEL_INFO,
|
||
("AfpFspDispFlushFork: Entered\n"));
|
||
|
||
ASSERT(VALID_OPENFORKENTRY(pReqPkt->_pOpenForkEntry));
|
||
|
||
do
|
||
{
|
||
Status = AfpIoQuerySize(&pReqPkt->_pOpenForkEntry->ofe_FileSysHandle,
|
||
&ForkLength);
|
||
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
PVOLDESC pVolDesc;
|
||
PDFENTRY pDfEntry;
|
||
POPENFORKDESC pOpenForkDesc;
|
||
|
||
pOpenForkDesc = pReqPkt->_pOpenForkEntry->ofe_pOpenForkDesc;
|
||
pVolDesc = pOpenForkDesc->ofd_pVolDesc;
|
||
|
||
ASSERT(IS_VOLUME_NTFS(pVolDesc));
|
||
|
||
// Don't let FpExchangeFiles come in while we are accessing
|
||
// the stored FileId and its corresponding DFE
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_ExchangeFilesLock);
|
||
|
||
AfpSwmrAcquireExclusive(&pVolDesc->vds_IdDbAccessLock);
|
||
|
||
if ((pDfEntry = AfpFindDfEntryById(pVolDesc,
|
||
pOpenForkDesc->ofd_FileNumber,
|
||
DFE_FILE)) != NULL)
|
||
{
|
||
ASSERT (VALID_DFE(pDfEntry));
|
||
|
||
AfpIoChangeNTModTime(&pReqPkt->_pOpenForkEntry->ofe_FileSysHandle,
|
||
&pDfEntry->dfe_LastModTime);
|
||
|
||
if (RESCFORK(pReqPkt->_pOpenForkEntry))
|
||
pDfEntry->dfe_RescLen = ForkLength.LowPart;
|
||
else pDfEntry->dfe_DataLen = ForkLength.LowPart;
|
||
}
|
||
|
||
AfpSwmrRelease(&pVolDesc->vds_IdDbAccessLock);
|
||
AfpSwmrRelease(&pVolDesc->vds_ExchangeFilesLock);
|
||
|
||
// update the disk quota for this user
|
||
if (pVolDesc->vds_Flags & VOLUME_DISKQUOTA_ENABLED)
|
||
{
|
||
pConnDesc = pReqPkt->_pOpenForkEntry->ofe_pConnDesc;
|
||
if (AfpConnectionReferenceByPointer(pConnDesc) != NULL)
|
||
{
|
||
afpUpdateDiskQuotaInfo(pConnDesc);
|
||
}
|
||
}
|
||
}
|
||
|
||
} while (False);
|
||
|
||
// Always return success
|
||
return AFP_ERR_NONE;
|
||
}
|
||
|
||
|
||
|