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.
1185 lines
31 KiB
1185 lines
31 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
webdav.h
|
|
|
|
Abstract:
|
|
|
|
This module defines the data structures and functions related to the
|
|
WebDav protocol.
|
|
|
|
Author:
|
|
|
|
Rohan Kumar [rohank] 17-Mar-1999
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef _WEBDAV_H
|
|
#define _WEBDAV_H
|
|
|
|
#ifdef RX_PRIVATE_BUILD
|
|
#undef IoGetTopLevelIrp
|
|
#undef IoSetTopLevelIrp
|
|
#endif
|
|
|
|
//
|
|
// The miniredir dipatch vector used by RDBSS.
|
|
//
|
|
extern struct _MINIRDR_DISPATCH MRxDAVDispatch;
|
|
|
|
//
|
|
// A serialization mutex used for various things.
|
|
//
|
|
extern FAST_MUTEX MRxDAVSerializationMutex;
|
|
|
|
//
|
|
// A pointer to the process that the RDBSS posts to. This is a non disappearing
|
|
// process!
|
|
//
|
|
extern PEPROCESS MRxDAVSystemProcess;
|
|
|
|
//
|
|
// The DavWinInetCachePath which is used in satisfying volume related queries.
|
|
//
|
|
extern WCHAR DavWinInetCachePath[MAX_PATH];
|
|
|
|
//
|
|
// The ProcessId of the svchost.exe process that loads the webclnt.dll.
|
|
//
|
|
extern ULONG DavSvcHostProcessId;
|
|
|
|
//
|
|
// The exchange device name will be stored in this KEY_VALUE_PARTIAL_INFORMATION
|
|
// structure.
|
|
//
|
|
extern PBYTE DavExchangeDeviceName;
|
|
|
|
//
|
|
// Name cache stuff. These values are read from the registry during init time.
|
|
//
|
|
extern ULONG FileInformationCacheLifeTimeInSec;
|
|
extern ULONG FileNotFoundCacheLifeTimeInSec;
|
|
extern ULONG NameCacheMaxEntries;
|
|
|
|
//
|
|
// The timeout values for various operations used by the MiniRedir. If an
|
|
// operation is not completed within the timeout value specified for it, is
|
|
// cancelled. The user can set the value to 0xffffffff to disable the
|
|
// timeout/cancel logic. In other words, if the timeout value is 0xffffffff,
|
|
// the requests will never timeout.
|
|
//
|
|
extern ULONG CreateRequestTimeoutValueInSec;
|
|
extern ULONG CreateVNetRootRequestTimeoutValueInSec;
|
|
extern ULONG QueryDirectoryRequestTimeoutValueInSec;
|
|
extern ULONG CloseRequestTimeoutValueInSec;
|
|
extern ULONG CreateSrvCallRequestTimeoutValueInSec;
|
|
extern ULONG FinalizeSrvCallRequestTimeoutValueInSec;
|
|
extern ULONG FinalizeFobxRequestTimeoutValueInSec;
|
|
extern ULONG FinalizeVNetRootRequestTimeoutValueInSec;
|
|
extern ULONG ReNameRequestTimeoutValueInSec;
|
|
extern ULONG SetFileInfoRequestTimeoutValueInSec;
|
|
extern ULONG QueryFileInfoRequestTimeoutValueInSec;
|
|
extern ULONG QueryVolumeInfoRequestTimeoutValueInSec;
|
|
extern ULONG LockRefreshRequestTimeoutValueInSec;
|
|
|
|
//
|
|
// The timer thread wakes up every "TimerThreadSleepTimeInSec" and cancels all
|
|
// the requests which haven't completed in their specified timeout value. This
|
|
// value is set to the min of the timeout values of all the requests mentioned
|
|
// above.
|
|
//
|
|
extern ULONG TimerThreadSleepTimeInSec;
|
|
|
|
//
|
|
// The timer object used by the timer thread that cancels the requests which
|
|
// have not completed in a specified time.
|
|
//
|
|
extern KTIMER DavTimerObject;
|
|
|
|
//
|
|
// This is used to indicate the timer thread to shutdown. When the system is
|
|
// being shutdown this is set to TRUE. MRxDAVTimerThreadLock is the resource
|
|
// used to gain access to this variable.
|
|
//
|
|
extern BOOL TimerThreadShutDown;
|
|
extern ERESOURCE MRxDAVTimerThreadLock;
|
|
|
|
//
|
|
// The handle of the timer thread that is created using PsCreateSystemThread
|
|
// is stored this global.
|
|
//
|
|
extern HANDLE TimerThreadHandle;
|
|
|
|
//
|
|
// This event is signalled by the timer thread right before its going to
|
|
// terminate itself.
|
|
//
|
|
extern KEVENT TimerThreadEvent;
|
|
|
|
//
|
|
// If QueueLockRefreshWorkItem is TRUE, the TimerThread (which cancels all the
|
|
// AsyncEngineContexts that haven't completed in a specified time) queues a
|
|
// WorkItem to refresh the locks. After the WorkItem has been queued the value
|
|
// of QueueLockRefreshWorkItem is set to FALSE. Once the worker thread is
|
|
// done refreshing all the locks, it resets this value to TRUE. We have a
|
|
// corresponding lock QueueLockRefreshWorkItemLock to synchronize access to
|
|
// QueueLockRefreshWorkItem.
|
|
//
|
|
extern BOOL QueueLockRefreshWorkItem;
|
|
extern ERESOURCE QueueLockRefreshWorkItemLock;
|
|
|
|
//
|
|
// The WorkQueueItem used in the MRxDAVContextTimerThread function to refresh
|
|
// the LOCKs taken by this client.
|
|
//
|
|
extern RX_WORK_QUEUE_ITEM LockRefreshWorkQueueItem;
|
|
|
|
#define DAV_MJ_READ 0
|
|
#define DAV_MJ_WRITE 1
|
|
|
|
//
|
|
// Pool tags used by the reflector library. All the DAV MiniRedir pool tags
|
|
// have "DV" as the first two characters.
|
|
//
|
|
#define DAV_SRVCALL_POOLTAG ('cSVD')
|
|
#define DAV_NETROOT_POOLTAG ('tNVD')
|
|
#define DAV_FILEINFO_POOLTAG ('iFVD')
|
|
#define DAV_FILENAME_POOLTAG ('nFVD')
|
|
#define DAV_EXCHANGE_POOLTAG ('xEVD')
|
|
#define DAV_READWRITE_POOLTAG ('wRVD')
|
|
#define DAV_QUERYDIR_POOLTAG ('dQVD')
|
|
#define DAV_SRVOPEN_POOLTAG ('oSVD')
|
|
#define DAV_LOCKTOKENENTRY_POOLTAG ('tLVD')
|
|
#define DAV_LOCKCONFLICTENTRY_POOLTAG ('cLVD')
|
|
|
|
//
|
|
// Use the DavDbgTrace macro for logging Mini-Redir stuff in the kernel
|
|
// debugger.
|
|
//
|
|
#if DBG
|
|
extern ULONG MRxDavDebugVector;
|
|
#define DAV_TRACE_ERROR 0x00000001
|
|
#define DAV_TRACE_DEBUG 0x00000002
|
|
#define DAV_TRACE_CONTEXT 0x00000004
|
|
#define DAV_TRACE_DETAIL 0x00000008
|
|
#define DAV_TRACE_ENTRYEXIT 0x00000010
|
|
#define DAV_TRACE_QUERYDIR 0x00000020
|
|
#define DAV_TRACE_OPENCLOSE 0x00000040
|
|
#define DAV_TRACE_READ 0x00000080
|
|
#define DAV_TRACE_WRITE 0x00000100
|
|
#define DAV_TRACE_SRVCALL 0x00000200
|
|
#define DAV_TRACE_FCBFOBX 0x00000400
|
|
#define DAV_TRACE_DAVNETROOT 0x00000800
|
|
#define DAV_TRACE_INFOCACHE 0x00001000
|
|
#define DAV_TRACE_ALL 0xffffffff
|
|
#define DavDbgTrace(_x_, _y_) { \
|
|
if (_x_ & MRxDavDebugVector) { \
|
|
DbgPrint _y_; \
|
|
} \
|
|
}
|
|
#else
|
|
#define DavDbgTrace(_x_, _y_)
|
|
#endif
|
|
|
|
//
|
|
// The initialization states of the miniredir.
|
|
//
|
|
typedef enum _WEBDAV_INIT_STATES {
|
|
MRxDAVINIT_START,
|
|
MRxDAVINIT_MINIRDR_REGISTERED
|
|
} WEBDAV_INIT_STATES;
|
|
|
|
//
|
|
// These are used by the entry point routines to specify what entrypoint was
|
|
// called. This facilitates common continuation routines.
|
|
//
|
|
typedef enum _WEBDAV_MINIRDR_ENTRYPOINTS {
|
|
DAV_MINIRDR_ENTRY_FROM_CREATE = 0,
|
|
DAV_MINIRDR_ENTRY_FROM_CLEANUPFOBX,
|
|
DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL,
|
|
DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT,
|
|
DAV_MINIRDR_ENTRY_FROM_FINALIZESRVCALL,
|
|
DAV_MINIRDR_ENTRY_FROM_FINALIZEVNETROOT,
|
|
DAV_MINIRDR_ENTRY_FROM_CLOSESRVOPEN,
|
|
DAV_MINIRDR_ENTRY_FROM_RENAME,
|
|
DAV_MINIRDR_ENTRY_FROM_READ,
|
|
DAV_MINIRDR_ENTRY_FROM_WRITE,
|
|
DAV_MINIRDR_ENTRY_FROM_QUERYDIR,
|
|
DAV_MINIRDR_ENTRY_FROM_SETFILEINFORMATION,
|
|
DAV_MINIRDR_ENTRY_FROM_QUERYFILEINFORMATION,
|
|
DAV_MINIRDR_ENTRY_FROM_QUERYVOLUMEINFORMATION,
|
|
DAV_MINIRDR_ENTRY_FROM_REFRESHTHELOCK,
|
|
DAV_MINIRDR_ENTRY_FROM_MAXIMUM
|
|
} WEBDAV_MINIRDR_ENTRYPOINTS;
|
|
|
|
//
|
|
// The states of the I/O operation(s).
|
|
//
|
|
typedef enum _WEBDAV_INNERIO_STATE {
|
|
MRxDAVInnerIoStates_Initial = 0,
|
|
MRxDAVInnerIoStates_ReadyToSend,
|
|
MRxDAVInnerIoStates_OperationOutstanding
|
|
} WEBDAV_INNERIO_STATE;
|
|
|
|
//
|
|
// The WebDav context structure that encapsulates the AsyncEngineCtx structure
|
|
// and has the miniredir specific fields.
|
|
//
|
|
typedef struct _WEBDAV_CONTEXT {
|
|
|
|
//
|
|
// The AsyncEngineCtx Structure used by the Reflector library.
|
|
//
|
|
union {
|
|
UMRX_ASYNCENGINE_CONTEXT;
|
|
UMRX_ASYNCENGINE_CONTEXT AsyncEngineContext;
|
|
};
|
|
|
|
//
|
|
// This is used by the entry point routines to specify what entrypoint was
|
|
// called. This facilitates common continuation routines.
|
|
//
|
|
WEBDAV_MINIRDR_ENTRYPOINTS EntryPoint;
|
|
|
|
//
|
|
// These describe the inner state of the I/O operation. These states are
|
|
// described in the MRxDAV_INNERIO_STATE data structure.
|
|
//
|
|
UCHAR OpSpecificState;
|
|
|
|
//
|
|
// Pointer to the information strucutre for the Create request.
|
|
//
|
|
PDAV_USERMODE_CREATE_RETURNED_FILEINFO CreateReturnedFileInfo;
|
|
|
|
//
|
|
// This is used in the Continuation functions for the read, write and
|
|
// querydir calls. It keeps track of the number of times the Continuation
|
|
// routine has been called.
|
|
//
|
|
ULONG ContinueEntryCount;
|
|
|
|
} WEBDAV_CONTEXT, *PWEBDAV_CONTEXT;
|
|
|
|
//
|
|
// While creating the AsyncEngineContext, the extra space needed for the
|
|
// miniredir specific fields is also allocated. Thus, one doesn't need to
|
|
// allocate twice.
|
|
//
|
|
#define SIZEOF_DAV_SPECIFIC_CONTEXT \
|
|
sizeof(WEBDAV_CONTEXT) - sizeof(UMRX_ASYNCENGINE_CONTEXT)
|
|
|
|
//
|
|
// The WebDav device object structure that encapsulates the UMRX_DEVICE_OBJECT
|
|
// structure and has the miniredir specific fields.
|
|
//
|
|
typedef struct _WEBDAV_DEVICE_OBJECT {
|
|
|
|
//
|
|
// The UMRX_DEVICE_OBJECT structure.
|
|
//
|
|
union {
|
|
UMRX_DEVICE_OBJECT;
|
|
UMRX_DEVICE_OBJECT UMRefDeviceObject;
|
|
};
|
|
|
|
//
|
|
// TRUE => miniredir has been started.
|
|
//
|
|
BOOLEAN IsStarted;
|
|
|
|
//
|
|
// The FCB of the device object.
|
|
//
|
|
PVOID CachedRxDeviceFcb;
|
|
|
|
//
|
|
// The process registering this device object.
|
|
//
|
|
PEPROCESS RegisteringProcess;
|
|
|
|
} WEBDAV_DEVICE_OBJECT, *PWEBDAV_DEVICE_OBJECT;
|
|
|
|
//
|
|
// The Dav device object.
|
|
//
|
|
extern PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject;
|
|
|
|
//
|
|
// The extra number of bytes needed for the device object. This info is used
|
|
// when the device object gets created.
|
|
//
|
|
#define WEBDAV_DEVICE_OBJECT_EXTENSION_SIZE \
|
|
(sizeof(WEBDAV_DEVICE_OBJECT) - sizeof(RDBSS_DEVICE_OBJECT))
|
|
|
|
|
|
//
|
|
// For every LOCK that is taken for a file, the following entry is created and
|
|
// added to the global LockTokenEntryList.
|
|
//
|
|
typedef struct _WEBDAV_LOCK_TOKEN_ENTRY {
|
|
|
|
LIST_ENTRY listEntry;
|
|
|
|
//
|
|
// The LockToken that was returned by the server on a successful LOCK
|
|
// request.
|
|
//
|
|
PWCHAR OpaqueLockToken;
|
|
|
|
//
|
|
// The server on which the file is shared.
|
|
//
|
|
PWCHAR ServerName;
|
|
|
|
//
|
|
// The path of the file on the server.
|
|
//
|
|
PWCHAR PathName;
|
|
|
|
//
|
|
// The ServerHashTable ServerId of this server.
|
|
//
|
|
ULONG ServerID;
|
|
|
|
//
|
|
// The LogonId of this user.
|
|
//
|
|
LUID LogonID;
|
|
|
|
//
|
|
// If this is set to FALSE, this LockEntry is not refreshed.
|
|
//
|
|
BOOL ShouldThisEntryBeRefreshed;
|
|
|
|
//
|
|
// The SecurityClientContext of the client in whose context the LOCK was
|
|
// taken. This is needed to impersonate the client when refreshing the
|
|
// LOCK.
|
|
//
|
|
PSECURITY_CLIENT_CONTEXT SecurityClientContext;
|
|
|
|
//
|
|
// The timeout value of the LOCK taken on the server. If the client wants
|
|
// to hold the LOCK beyond this timeout then it needs to refresh the LOCK
|
|
// before the timeout expires.
|
|
//
|
|
ULONG LockTimeOutValueInSec;
|
|
|
|
//
|
|
// The system tick count when this LOCK entry was created. This value is
|
|
// used in sending out LOCK refresh requests.
|
|
//
|
|
LARGE_INTEGER CreationTimeInTickCount;
|
|
|
|
} WEBDAV_LOCK_TOKEN_ENTRY, *PWEBDAV_LOCK_TOKEN_ENTRY;
|
|
|
|
//
|
|
// The global list of all the active LOCK tokens (one for every LOCK taken) and
|
|
// the resource that is used to synchronize access to it.
|
|
//
|
|
extern LIST_ENTRY LockTokenEntryList;
|
|
extern ERESOURCE LockTokenEntryListLock;
|
|
|
|
#define WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC 10
|
|
|
|
//
|
|
// For every LOCK request that fails, we create an entry below and add it to
|
|
// the global LockConflictEntryList.
|
|
//
|
|
typedef struct _WEBDAV_LOCK_CONFLICT_ENTRY {
|
|
|
|
LIST_ENTRY listEntry;
|
|
|
|
//
|
|
// The complete path name of the file that has already been locked on the
|
|
// server.
|
|
//
|
|
PWCHAR CompletePathName;
|
|
|
|
//
|
|
// The owner of the LOCK on the file as returned by the server.
|
|
//
|
|
PWCHAR LockOwner;
|
|
|
|
//
|
|
// The system tick count when this entry was created. This entry is kept
|
|
// alive for WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC seconds.
|
|
//
|
|
LARGE_INTEGER CreationTimeInTickCount;
|
|
|
|
} WEBDAV_LOCK_CONFLICT_ENTRY, *PWEBDAV_LOCK_CONFLICT_ENTRY;
|
|
|
|
//
|
|
// The global list of all the LOCK conflict entries and the resource that is
|
|
// used to synchronize access to it.
|
|
//
|
|
extern LIST_ENTRY LockConflictEntryList;
|
|
extern ERESOURCE LockConflictEntryListLock;
|
|
|
|
//
|
|
// The WEBDAV specific FOBX structure.
|
|
//
|
|
typedef struct _WEBDAV_FOBX {
|
|
|
|
//
|
|
// The pointer to the DavFileAttribute list for this directory. This list
|
|
// is created on the first call to Enumerate files in the directory.
|
|
//
|
|
PDAV_FILE_ATTRIBUTES DavFileAttributes;
|
|
|
|
//
|
|
// Number of DavFileAttribute entries.
|
|
//
|
|
ULONG NumOfFileEntries;
|
|
|
|
//
|
|
// The index of the next file to be returned to the user. The file index
|
|
// starts from zero, hence file index = 0 => the first file entry etc.
|
|
//
|
|
ULONG CurrentFileIndex;
|
|
|
|
//
|
|
// Pointer to the next entry.
|
|
//
|
|
PLIST_ENTRY listEntry;
|
|
|
|
} WEBDAV_FOBX, *PWEBDAV_FOBX;
|
|
|
|
//
|
|
// A pointer to an instance of WEBDAV_SRV_OPEN is stored in the context field
|
|
// of MRX_SRV_OPEN strucutre.
|
|
//
|
|
#define MRxDAVGetFobxExtension(pFobx) \
|
|
(((pFobx) == NULL) ? NULL : (PWEBDAV_FOBX)((pFobx)->Context))
|
|
|
|
//
|
|
// The WEBDAV specific SRV_OPEN structure.
|
|
//
|
|
typedef struct _WEBDAV_SRV_OPEN {
|
|
|
|
//
|
|
// The file handle associated with this SrvOpen.
|
|
//
|
|
HANDLE UnderlyingHandle;
|
|
|
|
//
|
|
// This also is the handle got from the usermode. Its used for debugging
|
|
// purposes.
|
|
//
|
|
PVOID UserModeKey;
|
|
|
|
//
|
|
// Pointer to the file object associated with the handle. This is set
|
|
// after the handle is successfully created in the usermode.
|
|
//
|
|
PFILE_OBJECT UnderlyingFileObject;
|
|
|
|
//
|
|
// Pointer to the device object represented by the file object mentioned
|
|
// above.
|
|
//
|
|
PDEVICE_OBJECT UnderlyingDeviceObject;
|
|
|
|
//
|
|
// This indicates whether we need to call IoRaiseInformationalHardError
|
|
// when the close fails. We need to do this if the PUT or DELETE failed and
|
|
// the operation which the user expects has succeeded actually failed.
|
|
//
|
|
BOOL RaiseHardErrorIfCloseFails;
|
|
|
|
//
|
|
// Created In Kernel.
|
|
//
|
|
BOOL createdInKernel;
|
|
|
|
//
|
|
// The OpaqueLockToken returned by the server if the file was LOCKed on
|
|
// Create. This token has to be sent with every request that modifies the
|
|
// data or the properties of this file.
|
|
//
|
|
PWCHAR OpaqueLockToken;
|
|
|
|
//
|
|
// The LockTokenEntry created for the OpaqueLockToken above.
|
|
//
|
|
PWEBDAV_LOCK_TOKEN_ENTRY LockTokenEntry;
|
|
|
|
} WEBDAV_SRV_OPEN, *PWEBDAV_SRV_OPEN;
|
|
|
|
//
|
|
// A pointer to an instance of WEBDAV_SRV_OPEN is stored in the context field
|
|
// of MRX_SRV_OPEN strucutre.
|
|
//
|
|
#define MRxDAVGetSrvOpenExtension(pSrvOpen) \
|
|
(((pSrvOpen) == NULL) ? NULL : (PWEBDAV_SRV_OPEN)((pSrvOpen)->Context))
|
|
|
|
//
|
|
// The WEBDAV specific FCB structure.
|
|
//
|
|
typedef struct _WEBDAV_FCB {
|
|
|
|
//
|
|
// Is this FCB for a directory ?
|
|
//
|
|
BOOL isDirectory;
|
|
|
|
//
|
|
// Does the File exist in the WinInet cache ??
|
|
//
|
|
BOOL isFileCached;
|
|
|
|
//
|
|
// Should this file be deleted on Close ?
|
|
//
|
|
BOOL DeleteOnClose;
|
|
|
|
//
|
|
// Was this file written to ?
|
|
//
|
|
ULONG FileWasModified;
|
|
|
|
//
|
|
// Did we reset the FileWasModified in the DavFcb to FALSE? If we did and
|
|
// the PUT failed, we need to reset the FileWasModified field in the FCB to
|
|
// TRUE.
|
|
//
|
|
BOOL FileModifiedBitReset;
|
|
|
|
//
|
|
// If we happen to LOCK the file on the server on Create we set this to
|
|
// TRUE. On CloseSrvOpen we check if this value is TRUE. If it is and the
|
|
// file has been modified, we only go to the usermode to do the PUT, DELETE,
|
|
// PROPPATCH etc, if the SrvOpen contains the OpaqueLockToken. If it does
|
|
// not then any request that modifies the file is going to fail with a
|
|
// 423.
|
|
//
|
|
BOOL FileIsLockedOnTheServer;
|
|
|
|
//
|
|
// On Close, if the file has been modified, we PROPPATCH the time values
|
|
// as well. We take the current time as the value of the "Last Modified Time"
|
|
// (LMT). If the SetFileInformation of the LMT happens after the file has
|
|
// been modifed, then we should use what ever LMT is already in the FCB as
|
|
// the LMT. For example,
|
|
// Create, Write, Close - Use the CurrentTime in close as the LMT.
|
|
// Create, Write, SetFileInfo(LMT), Close - Use the LMT in the FCB.
|
|
//
|
|
BOOL DoNotTakeTheCurrentTimeAsLMT;
|
|
|
|
//
|
|
// This resource is used to synchronize the "Read-Modify-Write" routine
|
|
// in the Write path of the DAV Redir. This is because when we get non-cached
|
|
// writes to the MiniRedir which do not extend the VaildDataLength, RDBSS,
|
|
// acquires the FCB resource shared. This means that multiple threads could
|
|
// be writing data to the local file (in the DAV Redir case) in which case
|
|
// they can overwrite each others changes since we do Read-Modify-Write.
|
|
// Hence we need to protect this code using a resource which we acqiure
|
|
// in an exclusive fashion when we do these writes. We allocate memory for
|
|
// this resource and initialize it the first time we need to acquire the
|
|
// lock. If allocated and initialized, it will be uninitialized and
|
|
// deallocated when the FCB is being deallocated.
|
|
//
|
|
PERESOURCE DavReadModifyWriteLock;
|
|
|
|
//
|
|
// We store the file name information on create. This is used if the delayed
|
|
// write failed to pop up the dialogue box and write an eventlog entry.
|
|
//
|
|
UNICODE_STRING FileNameInfo;
|
|
BOOL FileNameInfoAllocated;
|
|
|
|
//
|
|
// Changes in directory entry.
|
|
//
|
|
BOOLEAN fCreationTimeChanged;
|
|
|
|
BOOLEAN fLastAccessTimeChanged;
|
|
|
|
BOOLEAN fLastModifiedTimeChanged;
|
|
|
|
BOOLEAN fFileAttributesChanged;
|
|
|
|
//
|
|
// Was this file renamed ?
|
|
//
|
|
BOOL FileWasRenamed;
|
|
|
|
BOOL LocalFileIsEncrypted;
|
|
|
|
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
|
|
|
//
|
|
// If the file gets renamed, the new name is copied into this buffer.
|
|
//
|
|
WCHAR NewFileName[MAX_PATH];
|
|
|
|
//
|
|
// Length of the new file name.
|
|
//
|
|
ULONG NewFileNameLength;
|
|
|
|
//
|
|
// The file name of the local file that represents the file on the DAV
|
|
// server which has been created.
|
|
//
|
|
WCHAR FileName[MAX_PATH];
|
|
WCHAR Url[MAX_PATH * 2];
|
|
|
|
} WEBDAV_FCB, *PWEBDAV_FCB;
|
|
|
|
//
|
|
// A pointer to an instance of WEBDAV_FCB is stored in the context field
|
|
// of MRX_FCB strucutre.
|
|
//
|
|
#define MRxDAVGetFcbExtension(pFcb) \
|
|
(((pFcb) == NULL) ? NULL : (PWEBDAV_FCB)((pFcb)->Context))
|
|
|
|
//
|
|
// The WEBDAV specific V_NET_ROOT structure.
|
|
//
|
|
typedef struct _WEBDAV_V_NET_ROOT {
|
|
|
|
//
|
|
// The client's security context. This is set during the create call.
|
|
//
|
|
SECURITY_CLIENT_CONTEXT SecurityClientContext;
|
|
|
|
//
|
|
// Is set to true after the above context is set. This is used to avoid
|
|
// initialization of the SecurityContext.
|
|
//
|
|
BOOLEAN SCAlreadyInitialized;
|
|
|
|
//
|
|
// Has the LogonID of this V_NET_ROOT been set ?
|
|
//
|
|
BOOL LogonIDSet;
|
|
|
|
//
|
|
// The LogonID for this session.
|
|
//
|
|
LUID LogonID;
|
|
|
|
//
|
|
// Is this an Office Web Server share?
|
|
//
|
|
BOOL isOfficeShare;
|
|
|
|
//
|
|
// Is this a TAHOE share?
|
|
//
|
|
BOOL isTahoeShare;
|
|
|
|
//
|
|
// Is PROPATCH method allowed?
|
|
//
|
|
BOOL fAllowsProppatch;
|
|
|
|
//
|
|
// Was this VNetRoot "NOT" created successfully in the usermode? We keep this
|
|
// info because when a finalize VNetRoot request comes, we need to know
|
|
// whether need to go upto the usermode to finalize the PerUserEntry. If the
|
|
// create failed then this BOOL is set to TRUE. If this is TRUE, then we
|
|
// don't go to the usermode to finalize the PerUserEntry.
|
|
//
|
|
BOOL createVNetRootUnSuccessful;
|
|
|
|
|
|
// does he report available space?
|
|
|
|
BOOL fReportsAvailableSpace;
|
|
|
|
} WEBDAV_V_NET_ROOT, *PWEBDAV_V_NET_ROOT;
|
|
|
|
//
|
|
// The WEBDAV specific V_NET_ROOT structure.
|
|
//
|
|
typedef struct _WEBDAV_NET_ROOT {
|
|
ULONG RefCount;
|
|
PMRX_NET_ROOT pRdbssNetRoot; // The Rdbss NetRoot it belongs to
|
|
NAME_CACHE_CONTROL NameCacheCtlGFABasic; // The basic file information name cache control.
|
|
NAME_CACHE_CONTROL NameCacheCtlGFAStandard; // The standard file information name cache control.
|
|
NAME_CACHE_CONTROL NameCacheCtlFNF; // The File not found name cache control.
|
|
} WEBDAV_NET_ROOT, *PWEBDAV_NET_ROOT;
|
|
|
|
//
|
|
// A pointer to an instance of WEBDAV_V_NET_ROOT is stored in the context field
|
|
// of MRX_V_NET_ROOT strucutre.
|
|
//
|
|
#define MRxDAVGetVNetRootExtension(pVNetRoot) \
|
|
(((pVNetRoot) == NULL) ? NULL : (PWEBDAV_V_NET_ROOT)((pVNetRoot)->Context))
|
|
|
|
//
|
|
// The WEBDAV specific V_NET_ROOT structure.
|
|
//
|
|
typedef struct _WEBDAV_SRV_CALL {
|
|
|
|
//
|
|
// The Unique ServerID.
|
|
//
|
|
ULONG ServerID;
|
|
|
|
//
|
|
// Is set to true after the above context is set. Used to check whether we
|
|
// need to delete the SecurityClientContext when we are completing the
|
|
// request.
|
|
//
|
|
BOOLEAN SCAlreadyInitialized;
|
|
|
|
} WEBDAV_SRV_CALL, *PWEBDAV_SRV_CALL;
|
|
|
|
//
|
|
// A pointer to an instance of WEBDAV_SRV_CALL is stored in the context field
|
|
// of MRX_SRV_CALL strucutre.
|
|
//
|
|
#define MRxDAVGetSrvCallExtension(pSrvCall) \
|
|
(((pSrvCall) == NULL) ? NULL : (PWEBDAV_SRV_CALL)((pSrvCall)->Context))
|
|
|
|
//
|
|
// Get the Security client context associated with this request.
|
|
//
|
|
#define MRxDAVGetSecurityClientContext() { \
|
|
if (RxContext != NULL && RxContext->pRelevantSrvOpen != NULL) { \
|
|
if (RxContext->pRelevantSrvOpen->pVNetRoot != NULL) { \
|
|
if (RxContext->pRelevantSrvOpen->pVNetRoot->Context != NULL) { \
|
|
DavVNetRoot = (PWEBDAV_V_NET_ROOT) \
|
|
RxContext->pRelevantSrvOpen->pVNetRoot->Context; \
|
|
SecurityClientContext = &(DavVNetRoot->SecurityClientContext); \
|
|
} \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// We turn away async operations that are not wait by posting. If we can wait
|
|
// then we turn off the sync flag so that things will just act synchronous.
|
|
//
|
|
#define TURN_BACK_ASYNCHRONOUS_OPERATIONS() { \
|
|
if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) { \
|
|
if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT)) { \
|
|
ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION) \
|
|
} else { \
|
|
RxContext->PostRequest = TRUE; \
|
|
return STATUS_PENDING; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// Global locking variables and macros.
|
|
//
|
|
extern RX_SPIN_LOCK MRxDAVGlobalSpinLock;
|
|
extern KIRQL MRxDAVGlobalSpinLockSavedIrql;
|
|
extern BOOLEAN MRxDAVGlobalSpinLockAcquired;
|
|
|
|
#define MRxDAVAcquireGlobalSpinLock() \
|
|
KeAcquireSpinLock(&MRxDAVGlobalSpinLock,&MRxDAVGlobalSpinLockSavedIrql); \
|
|
MRxDAVGlobalSpinLockAcquired = TRUE
|
|
|
|
#define MRxDAVReleaseGlobalSpinLock() \
|
|
MRxDAVGlobalSpinLockAcquired = FALSE; \
|
|
KeReleaseSpinLock(&MRxDAVGlobalSpinLock,MRxDAVGlobalSpinLockSavedIrql)
|
|
|
|
#define MRxDAVGlobalSpinLockAcquired() \
|
|
(MRxDAVGlobalSpinLockAcquired == TRUE)
|
|
|
|
//
|
|
// The IrpCompletionContext structure that is used in the read/write operations.
|
|
// All we need is an event on which we will wait till the underlying file system
|
|
// completes the request. This event gets signalled in the Completion routine
|
|
// that we specify.
|
|
//
|
|
typedef struct _WEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT {
|
|
|
|
//
|
|
// The event which is signalled in the Completion routine that is passed
|
|
// to IoCallDriver in the read and write requests.
|
|
//
|
|
KEVENT DavReadWriteEvent;
|
|
|
|
} WEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT, *PWEBDAV_READ_WRITE_IRP_COMPLETION_CONTEXT;
|
|
|
|
//
|
|
// The prototypes of functions defined for various I/O requests by the DAV
|
|
// miniredir are mentioned below.
|
|
//
|
|
|
|
//
|
|
// Create/Open/Cleanup/Close Request function prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVCreate(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCleanupFobx (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCloseSrvOpen (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCollapseOpen (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVComputeNewBufferingState(
|
|
IN OUT PMRX_SRV_OPEN pSrvOpen,
|
|
IN PVOID pMRxContext,
|
|
OUT ULONG *pNewBufferingState
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVForcedClose (
|
|
IN OUT PMRX_SRV_OPEN SrvOpen
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVShouldTryToCollapseThisOpen (
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVTruncate (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
VOID
|
|
MRxDAVSetLoud(
|
|
IN PBYTE Msg,
|
|
IN PRX_CONTEXT RxContext,
|
|
IN PUNICODE_STRING s
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFlush (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
//
|
|
// Read prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVRead (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
//
|
|
// Write prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVWrite(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
ULONG
|
|
MRxDAVExtendForCache(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN OUT PLARGE_INTEGER NewFileSize,
|
|
OUT PLARGE_INTEGER NewAllocationSize
|
|
);
|
|
|
|
ULONG
|
|
MRxDAVExtendForNonCache(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN OUT PLARGE_INTEGER NewFileSize,
|
|
OUT PLARGE_INTEGER NewAllocationSize
|
|
);
|
|
|
|
|
|
//
|
|
// SrvCall function prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVCreateSrvCall(
|
|
PMRX_SRV_CALL pSrvCall,
|
|
PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFinalizeSrvCall(
|
|
PMRX_SRV_CALL pSrvCall,
|
|
BOOLEAN Force
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVSrvCallWinnerNotify(
|
|
IN PMRX_SRV_CALL pSrvCall,
|
|
IN BOOLEAN ThisMinirdrIsTheWinner,
|
|
IN OUT PVOID pSrvCallContext
|
|
);
|
|
|
|
//
|
|
// NetRoot/VNetRoot function prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVUpdateNetRootState(
|
|
IN OUT PMRX_NET_ROOT pNetRoot
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCreateVNetRoot(
|
|
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFinalizeVNetRoot(
|
|
IN PMRX_V_NET_ROOT pVNetRoot,
|
|
IN PBOOLEAN ForceDisconnect
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFinalizeNetRoot(
|
|
IN PMRX_NET_ROOT pNetRoot,
|
|
IN PBOOLEAN ForceDisconnect
|
|
);
|
|
|
|
VOID
|
|
MRxDAVExtractNetRootName(
|
|
IN PUNICODE_STRING FilePathName,
|
|
IN PMRX_SRV_CALL SrvCall,
|
|
OUT PUNICODE_STRING NetRootName,
|
|
OUT PUNICODE_STRING RestOfName OPTIONAL
|
|
);
|
|
|
|
//
|
|
// Query Directory prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVQueryDirectory(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
//
|
|
// Query volume.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVQueryVolumeInformation(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
//
|
|
// File Information.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVQueryFileInformation(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVSetFileInformation(
|
|
IN PRX_CONTEXT RxContext
|
|
);
|
|
|
|
//
|
|
// DevFcb prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVDevFcbXXXControlFile (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVStart (
|
|
IN OUT struct _RX_CONTEXT * RxContext,
|
|
IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVStop (
|
|
IN OUT struct _RX_CONTEXT * RxContext,
|
|
IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
MRxDAVFastIoDeviceControl (
|
|
IN struct _FILE_OBJECT *FileObject,
|
|
IN BOOLEAN Wait,
|
|
IN PVOID InputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG IoControlCode,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN struct _DEVICE_OBJECT *DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
MRxDAVFastIoRead(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Wait,
|
|
IN ULONG LockKey,
|
|
OUT PVOID Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
BOOLEAN
|
|
MRxDAVFastIoWrite(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN Wait,
|
|
IN ULONG LockKey,
|
|
OUT PVOID Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
//
|
|
// Other Misc prototypes.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVSyncXxxInformation(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN UCHAR MajorFunction,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG InformationClass,
|
|
IN ULONG Length,
|
|
OUT PVOID Information,
|
|
OUT PULONG_PTR ReturnedLength OPTIONAL
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVDeallocateForFcb (
|
|
IN OUT PMRX_FCB pFcb
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVDeallocateForFobx (
|
|
IN OUT PMRX_FOBX pFobx
|
|
);
|
|
|
|
//
|
|
// The prototype of the routine that formats the DAV specific portion of the
|
|
// context.
|
|
//
|
|
NTSTATUS
|
|
MRxDAVFormatTheDAVContext(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
USHORT EntryPoint
|
|
);
|
|
|
|
NTSTATUS
|
|
DavXxxInformation(
|
|
IN const int xMajorFunction,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG InformationClass,
|
|
IN ULONG Length,
|
|
OUT PVOID Information,
|
|
OUT PULONG ReturnedLength
|
|
);
|
|
|
|
ULONG
|
|
DavReadWriteFileEx(
|
|
IN USHORT Operation,
|
|
IN BOOL NonPagedBuffer,
|
|
IN BOOL UseOriginalIrpsMDL,
|
|
IN PMDL OriginalIrpsMdl,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONGLONG FileOffset,
|
|
IN OUT PVOID DataBuffer,
|
|
IN ULONG SizeInBytes,
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock
|
|
);
|
|
|
|
NTSTATUS
|
|
DavReadWriteIrpCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP CalldownIrp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVProbeForReadWrite(
|
|
IN PBYTE BufferToBeValidated,
|
|
IN DWORD BufferSize,
|
|
IN BOOL doProbeForRead,
|
|
IN BOOL doProbeForWrite
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFsCtl(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVIsValidDirectory(
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN PUNICODE_STRING DirectoryName
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCancelRoutine(
|
|
PRX_CONTEXT RxContext
|
|
);
|
|
|
|
VOID
|
|
MRxDAVTimeOutTheContexts(
|
|
BOOL WindDownAllContexts
|
|
);
|
|
|
|
VOID
|
|
MRxDAVContextTimerThread(
|
|
PVOID DummyContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVQueryEaInformation (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVSetEaInformation (
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVGetFullParentDirectoryPath(
|
|
PRX_CONTEXT RxContext,
|
|
PUNICODE_STRING ParentDirName
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVGetFullDirectoryPath(
|
|
PRX_CONTEXT RxContext,
|
|
PUNICODE_STRING FileName,
|
|
PUNICODE_STRING DirName
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCreateEncryptedDirectoryKey(
|
|
PUNICODE_STRING DirName
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVRemoveEncryptedDirectoryKey(
|
|
PUNICODE_STRING DirName
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVQueryEncryptedDirectoryKey(
|
|
PUNICODE_STRING DirName
|
|
);
|
|
|
|
VOID
|
|
MRxDAVCleanUpTheLockConflictList(
|
|
BOOL CleanUpAllEntries
|
|
);
|
|
|
|
#endif //_WEBDAV_H
|
|
|