Leaked source code of windows server 2003
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.
 
 
 
 
 
 

459 lines
13 KiB

/*
* S T A T E T O K. H
*
* Sources implementation of DAV-Lock common definitions.
*
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
*/
/*
* This file contains the definitions used for parsing state token
* relared headers.
*
*/
#ifndef __STATETOK_H__
#define __STATETOK_H__
// Current max seconds = 1 day.
//
DEC_CONST INT gc_cSecondsMaxLock = 60 * 60 * 24;
// Current default lock time out is 3 minutes
//
DEC_CONST INT gc_cSecondsDefaultLock = 60 * 3;
//$REVIEW These flags are duplicated in lockmgr.h and statetok.h. before
//$REVIEW this is addressed, to be safe, we make sure they match
//$REVIEW Also inherit the excellent comments from the lockmgr.h regarding
//$REVIEW how the flags should be defined when we merge.
#define DAV_LOCKTYPE_ROLLBACK 0x08000000
#define DAV_LOCKTYPE_CHECKOUT 0x04000000
#define DAV_LOCKTYPE_TRANSACTION_GOP 0x00100000
#define DAV_LOCKTYPE_READWRITE (GENERIC_READ | GENERIC_WRITE)
#define DAV_LOCKTYPE_FLAGS (GENERIC_READ | GENERIC_WRITE | DAV_LOCKTYPE_ROLLBACK | DAV_LOCKTYPE_CHECKOUT | DAV_LOCKTYPE_TRANSACTION_GOP)
#define DAV_EXCLUSIVE_LOCK 0x01000000
#define DAV_SHARED_LOCK 0x02000000
#define DAV_LOCKSCOPE_LOCAL 0x04000000
#define DAV_LOCKSCOPE_FLAGS (DAV_EXCLUSIVE_LOCK | DAV_SHARED_LOCK | DAV_LOCKSCOPE_LOCAL)
#define DAV_RECURSIVE_LOCK 0x00800000
#define DAV_LOCK_FLAGS (DAV_LOCKTYPE_FLAGS | DAV_RECURSIVE_LOCK | DAV_LOCKSCOPE_FLAGS)
/*
- IFITER
-
*
* This is the parser copied from the original IF header processor
* used in lockutil.cpp. Eventually lockutil.cpp shall use this
* file since this file shall have only the common stuff sharable
* between davex and davfs lock code.
*
* Comment format change to the style used in this file otherwise.
*
*
*/
// ========================================================================
//
// class IFITER
//
// Built to parse the new If header.
//
// Format of the If header
// If = "If" ":" ( 1*No-tag-list | 1*Tagged-list)
// No-tag-list = List
// Tagged-list = Resource 1*List
// Resource = Coded-url
// List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")"
// State-token = Coded-url
// Coded-url = "<" URI ">"
//
//
// NOTE: We are going to be lax about tagged/untagged lists.
// If the first list is not tagged, but we find tagged lists later,
// that's cool by me.
// (Realize that there no problem switching from tagged to untagged --
// because that case cannot be detected & distinguished from another
// list for the same URI! The only problem is if the first list is
// untagged, and later there are tagged lists. That is a case that
// *should*, by a perfectly tight reading of the spec, be a bad request.
// I am treating it as perfectly valid until someone tells me that I have
// to do the extra 1 bit of bookkeeping.)
//
// State machine for this class
// It's a really simple state machine.
// (NOTE that I'm calling statetokens and etags "tokens", and the
// contents of a single set of parentheses a "list", just like above.)
//
// Three possible states: NONE, NAME, and LIST.
// Starts in state NONE -- can accept a tag (URI) or a start of a list.
// Moves to NAME if a tag (URI) is encountered.
// Only a list can follow a tag (URI).
// Moves to LIST when a list start (left paren) is encountered.
// Moves back to NONE when a list end (right paren) is encountered.
//
// ------------------------------------------------------------------------
// enum FETCH_TOKEN_TYPE
// These are the flags used in IFITER::PszNextToken.
// There are two basic types of fetching:
// o advance to next item of this type (xxx_NEW_xxx)
// o fetch the next item & fail if the type does not match.
//
enum FETCH_TOKEN_TYPE
{
TOKEN_URI, // Fetch a URI, don't skip anything.
TOKEN_NEW_URI, // Advance to the next URI, skipping stuff in between.
TOKEN_START_LIST, // Fetch the next list item. Must be the starting list item.
TOKEN_SAME_LIST, // Fetch the next internal item in this list.
TOKEN_NEW_LIST, // Advance to the next start of a list, skipping past the
// end of the current list if necessary. Don't skip uris.
TOKEN_ANY_LIST, // NTRaid#244243 -- special for looking up locktokens
// Fetch the next item for this same uri -- can cross lists,
// but not uris.
TOKEN_NONE, // Empty marker.
};
class IFITER
{
private:
enum STATE_TYPE
{
STATE_NONE,
STATE_NAME,
STATE_LIST,
};
const LPCWSTR m_pwszHdr;
LPCWSTR m_pwch;
StringBuffer<WCHAR> m_buf;
// State bits
STATE_TYPE m_state;
BOOL m_fCurrentNot;
// NOT IMPLEMENTED
//
IFITER& operator=( const IFITER& );
IFITER( const IFITER& );
public:
IFITER (LPCWSTR pwsz=0) :
m_pwszHdr(pwsz),
m_pwch(pwsz),
m_state(STATE_NONE),
m_fCurrentNot(FALSE)
{
}
~IFITER() {}
LPCWSTR PszNextToken (FETCH_TOKEN_TYPE type);
BOOL FCurrentNot() const
{
return m_fCurrentNot;
}
void Restart()
{
m_pwch = m_pwszHdr; m_state = STATE_NONE;
}
};
/*
- PwszSkipCodes
-
* Remove <> or [] tags around stuff. Useful for if: header
* tags. also eliminates the LWS near to the delimiters.
*
* *pdwLen may be zero or the length of the string. If zero
* the routine calculate the length using strlen. Wasteful,
* if you already know the length.
*
* Returns the pointer to the first non-lws, non-delimiter.
* dwLen shall be set to the actual number of chars, from the
* first to the last char which is non-lws, non-delimiter when
* we start looking from the end. Does not stick the null char
* at the end. Do it yourself, if you need to, using dwLen.
*
*/
LPCWSTR PwszSkipCodes(IN LPCWSTR pwszTagged, IN OUT DWORD *pdwLen);
/*
- CStateToken
-
* The state token is the lean string that we use to communicate
* with the client. It is the external representation of a DAV lock
* or any other kind of state information.
*
* State token is a quoted uri which is <uri> for the external world.
* So we provide facilities to deal with this in this class. The < and
* > are not useful for internal processing - so we hide this to our
* customers - this will avoid copying to prepend the <.
*
* E-TAGs are special beasts and are just plain quoted strings surrounded
* by [ and ].
*
*/
class CStateToken
{
public:
// Common defintions which are public, also used privately!
//
typedef enum StateTokenType
{
TOKEN_NONE = 0,
TOKEN_LOCK,
TOKEN_TRANS,
TOKEN_ETAG,
TOKEN_RESTAG,
} STATE_TOKEN_TYPE;
// normally state tokens are about of this size
// ie lock tokens.
//
enum { NORMAL_STATE_TOKEN_SIZE = 128 };
private:
// Token buffer
//
LPWSTR m_pwszToken;
// Allocated size of the current buffer.
//
DWORD m_cchBuf;
// type of the token
//
STATE_TOKEN_TYPE m_tType;
// Never implemented
//
CStateToken( const CStateToken& );
CStateToken& operator=( const CStateToken& );
public:
CStateToken() : m_pwszToken(NULL), m_cchBuf(0), m_tType(TOKEN_NONE)
{
};
~CStateToken()
{
if (NULL != m_pwszToken)
ExFree(m_pwszToken);
}
// Plain token accepted here.
// If the dwLen is zero, NULL terminated pszToken
// is the token. If non zero, it gives actual
// number of chars in the token.
// Useful when we parse the if: header.
//
BOOL FSetToken(LPCWSTR pwszToken, BOOL fEtag, DWORD dwLen = 0);
// Accessors to the token info
//
inline STATE_TOKEN_TYPE GetTokenType() const { return m_tType; }
// TRUE if the lock tokens are equal.
//
BOOL FIsEqual(CStateToken *pstokRhs);
// get a pointer to the token string
//
inline LPCWSTR WszGetToken() const { return m_pwszToken; }
// Parses the state token as a lock token and
// get the lock token information.. Note that our lock
// tokens consist of a GUIID and a long long(int64).
// The guid string must be long enough to hold a GUID
// string (37 chars).
//
BOOL FGetLockTokenInfo(unsigned __int64 *pi64SeqNum, LPWSTR pwszGuid);
};
/*
- CStateMatchOp
-
* This class is used as the base class for doing
* state match operations including e-tag
* checks. Each implementation shall derive its own
* ways to check the state of the resource. This way
* the core parse code is shared between subsystems.
*
* Not multi-thread safe - create,use and delete in a
* single thread.
*
*/
class CStateMatchOp
{
private:
// NOT IMPLEMENTED
//
CStateMatchOp( const CStateMatchOp& );
CStateMatchOp& operator=( const CStateMatchOp& );
protected:
// Current token under investigation.
// All derived classes can access it.
// We do not pass this as the parameter.
//
CStateToken m_tokCurrent;
friend class CIfHeadParser;
// ---------------------------------------------------------
// support API for the ifheader parser
// set the current token
//
inline BOOL FSetToken(LPCWSTR pwszToken, BOOL fEtag)
{
return m_tokCurrent.FSetToken(pwszToken, fEtag);
}
// get the current token type
//
inline CStateToken::STATE_TOKEN_TYPE GetTokenType() const
{
return m_tokCurrent.GetTokenType();
}
// return the storage path of the uri. Note that davex and davfs
// has different implementations of this.
//
virtual SCODE ScGetResourcePath(LPCWSTR pwszUri, LPCWSTR * ppwszStoragePath) = 0;
// check if the resource is locked by the lock specified
// by the current lock token above. fRecusrive says if the
// condition is to be applied to all the resources under the
// given path. Believe me, lpwszPath can be NULL. And it is
// NULL when the match condition is to be applied on the
// first path given to HrApplyIf!. Why we do this: normally
// we do lotsa processing on the method's resource before
// we call the if-header parser. This processing generates
// info like e-tags which can be used to do the state match
// check here. So the parser needs to tell the match checker
// that this is for the original uri and NULL is the indication
// of that.
//
virtual SCODE ScMatchLockToken(LPCWSTR pwszPath, BOOL fRecursive) = 0;
virtual SCODE ScMatchResTag(LPCWSTR pwszPath) = 0;
virtual SCODE ScMatchTransactionToken(LPCWSTR pwszPath) = 0;
// Checks if the resource is in the state specified by the
// (e-tag) state token above. Parameters have same meaning as above.
//
virtual SCODE ScMatchETag(LPCWSTR pwszPath, BOOL fRecursive) = 0;
// -----------------------------------------------------------
public:
// Usual suspects of CTOR and DTOR
//
CStateMatchOp() { };
~CStateMatchOp() { };
// Using this object as the match operator parse an if header.
// This is used by all method impls.
//
SCODE ScParseIf(LPCWSTR pwszIfHeader, LPCWSTR rgpwszPaths[], DWORD cPaths, BOOL fRecur, SCODE * pSC);
};
/*
- FCompareSids
-
* compare two sids
*
*/
inline BOOL FCompareSids(PSID pSidLeft, PSID pSidRight)
{
if ((NULL == pSidLeft) || (NULL == pSidRight))
return FALSE;
// Assert the SID validity.
//
Assert(IsValidSid(pSidLeft));
Assert(IsValidSid(pSidRight));
return EqualSid(pSidLeft, pSidRight);
}
/*
- FSeparator
-
* returns true if input is a path separator - used below
*
*/
inline BOOL FSeparator(WCHAR wch)
{
return ((wch == L'\\') || (wch == L'/'));
}
/*
- FIsChildPath
-
* compare two paths to check if the child is within the scope
* of the parent.
*
* For non recursive match, the two paths must match exactly for
* TRUE return. This is useful when tagged URIs within the IF header
* is processed and we have a deep operation going on. The other place
* this function is used is when we have a recursive lock and need to
* find out if a path is locked by this lock.
*
*/
inline BOOL FIsChildPath(LPCWSTR pwszPathParent, LPCWSTR pwszPathChild, BOOL fRecursive)
{
UINT cchParentLen;
if ((NULL == pwszPathParent) || (NULL == pwszPathChild))
return FALSE;
cchParentLen = static_cast<UINT>(wcslen(pwszPathParent));
// If the parent path is not an initial substring
// of child return fail immediately.
//
if ( 0 != _wcsnicmp(pwszPathChild, pwszPathParent, cchParentLen) )
{
return FALSE;
}
// Parent indeed is the initial substring.
// Check the next char of child (for NULL) to see
// if they match exactly. This is an instand good condition.
//
if (L'\0' == pwszPathChild[cchParentLen])
{
return TRUE;
}
// We still have hope for a match ONLY for recursive checks.
//
if (! fRecursive)
{
return FALSE;
}
else
{
// either parent or child need to have a separator
//
if ( FSeparator(pwszPathParent[cchParentLen-1]) ||
FSeparator(pwszPathChild[cchParentLen]) )
return TRUE;
else
return FALSE;
}
}
#endif