/*****************************************************************************/
/*
DAVmeta.c
The WASD WebDAV meta-data is used to store lock and 'dead' property data
potentially for each file-system object (file and directory) accessable from
the server using WebDAV. Meta-data files are stored in the same directory as
the resource, using the same name as the resource, with "__wasdav" concatenated
to the file type (note the two underscores). Collection (directory) meta-data
is associated with the directory file (e.g. A_Directory.DIR__wasdav).
Hence a directory listing containing two resources with associated meta-data
looks something like:
admin.c;1 125KB 3-JAN-2009 06:06:55.46
admin.c__wasdav;1 0.50KB 11-JUN-2009 18:26:27.82
admin.h;1 8KB 17-FEB-2008 15:02:53.32
auth.c;1 142KB 27-APR-2008 08:28:59.21
auth.c__wasdav;1 0.50KB 11-JUN-2009 18:27:17.02
auth.h;1 18KB 29-APR-2009 21:16:31.33
authaccess.c;1 16KB 6-AUG-2007 17:43:51.68
authacme.c;1 24KB 30-APR-2009 06:23:51.94
After some experimentation with autonomous and centeralised databasing it was
decided to place the meta-data with the resource. This was done for reasons of
programmatic simplicity, file-system efficiency, reducing WebDAV latency and
for the convenience of any command-line owner of the resources. No specialised
tools are required. All non-WebDAV WASD functionality ignores *.*__wasdav;
files (e.g. directory listing, file GET). Of course other applications (e.g.
$ DIRECTORY) do not.
META-DATA XML
-------------
Meta-data files contain XML. WASD name-space contains zero or more WASD lock
elements and/or zero or more property elements. If there is zero of both (as
might occur after an UNLOCK or PROPPATCH remove, the meta-data file is deleted.
The WASD element also contains the (file-system) resource the meta-data
represents (file or directory specification) and the date/time of the last
update to that meta-data.
The following is an example of this XML structure:
...
...
LOCK META-DATA
--------------
All lock characteristics except the potentially XML-containing owner element
are contained in attributes to the WASD lock element. One or more lock
elements may be present representing compatible locks against the resource.
Example lock meta-data:
blah blah
PROPERTY META-DATA
------------------
The property elements are stored as-supplied by client. It is presumed that
their XML well-formedness is guaranteed by the original request XML parsing.
For ease of processing (by WASD DAV) each element in a property contains an
'xmlns=""' attribute.
An example of such meta-data generated by a Microsoft Windows (not Internet)
Explorer client (example is intentionally not wrapped):
Tue, 26 Jun 2007 02:00:48 GMT
Mon, 23 Jul 2007 01:52:32 GMT
Mon, 23 Jul 2007 01:52:32 GMT
00000020
VERSION HISTORY
---------------
07-SEP-2013 MGD bugfix; DavMetaUpdate() abort if SetTimeout() fails
08-JUN-2010 MGD bugfix; DavMetaReadName() and DavMetaWriteName()
allow for typeless file names (e.g. ]AFILE.;)
10-MAY-2010 JPP bugfix; do not set new token when refreshing
02-SEP-2009 MGD bugfix; scanning backwards through extended file spec
31-DEC-2006 MGD initial
*/
/*****************************************************************************/
#ifdef WASD_VMS_V7
#undef _VMS__V6__SOURCE
#define _VMS__V6__SOURCE
#undef __VMS_VER
#define __VMS_VER 70000000
#undef __CRTL_VER
#define __CRTL_VER 70000000
#endif
#include
#include
#include
#include
#include
#include "wasd.h"
#include "davweb.h"
#define WASD_MODULE "DAVMETA"
#ifndef WASD_WEBDAV
#define WASD_WEBDAV 1
#endif
#define DAVMETA_READ_CHUNK (512 * 32)
/* just reduce the amount of XML parse noise when WATCHing */
#define WATCH_XML 1
/******************/
/* global storage */
/******************/
/********************/
/* external storage */
/********************/
extern BOOL WebDavEnabled,
WebDavLockingEnabled;
extern int EfnWait,
EfnNoWait;
extern int ToLowerCase[],
ToUpperCase[];
extern unsigned long HttpdBinTime[],
SysLckMask[],
SysPrvMask[];
extern char ErrorSanityCheck[],
HttpdSoftwareIdName[],
HttpdVersion[];
extern ACCOUNTING_STRUCT *AccountingPtr;
extern CONFIG_STRUCT Config;
extern LIST_HEAD RequestList;
extern WATCH_STRUCT Watch;
/*****************************************************************************/
/*
Build the data buffer containing the XML formated WASD lock and properties
associated with the resource (file). This can then be written to disk.
The two descriptor collections, 'MetaLockDsc' containing any existing lock
elements, and 'MetaPropDsc', containing any existing property elements are
merged with the lock elements from the request contained in 'XmlLockSetDsc',
and the property elements in 'XmlPropSetDsc'.
The merging is performed by emptying any element of 'MetaLockDsc' or
'MetaPropDsc' that is to be removed, by overwriting any existing element that
is to be set, or appended to the collection any new element, both to
'MetaLockDsc' or 'MetaPropDsc' as required.
*/
int DavMetaBuild (WEBDAV_META *mtaptr)
{
int status,
ItemCount;
char *sptr;
char DateTime [32];
STR_DSC *sdptr, *wdptr;
WEBDAV_LOCK *lckptr;
REQUEST_STRUCT *rqptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaBuild()");
tkptr = rqptr->WebDavTaskPtr;
/*************************/
/* remove/set properties */
/*************************/
StrDscColIfNotBegin (rqptr, &mtaptr->PropDsc, 256);
if (STR_DSC_LEN(&mtaptr->PropDsc))
{
/* remove properties specified in the request XML */
STR_DSC_ITERATE (sdptr, &tkptr->XmlData.PropRemoveDsc)
DavMetaRemove (rqptr, &mtaptr->PropDsc, sdptr);
}
if (STR_DSC_LEN(&tkptr->XmlData.PropSetDsc))
{
/* set properties specified in the request XML */
STR_DSC_ITERATE (sdptr, &tkptr->XmlData.PropSetDsc)
DavMetaSet (rqptr, &mtaptr->PropDsc, sdptr);
}
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
{
if (STR_DSC_LEN(&mtaptr->LockDsc))
{
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "LOCK built");
STR_DSC_ITERATE (sdptr, &mtaptr->LockDsc)
if (STR_DSC_LEN(sdptr))
WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));
}
if (STR_DSC_LEN(&mtaptr->PropDsc))
{
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "PROP built");
STR_DSC_ITERATE (sdptr, &mtaptr->PropDsc)
if (STR_DSC_LEN(sdptr))
WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));
}
}
/******************/
/* build meta XML */
/******************/
/* write will be by block and so must be evenly divisible by 512! */
wdptr = StrDscBegin (rqptr, &mtaptr->WriteDsc, 4096);
ItemCount = 0;
DavWebDateTimeTo3339 (DateTime, &HttpdBinTime);
FaoToBuffer (wdptr, -1, NULL,
"\n\
\n",
DateTime, &HttpdBinTime);
/* step through each lock in the list generating an XML text equivalent */
LIST_ITERATE (lckptr, &mtaptr->LockList)
{
DavLockXml (rqptr, lckptr, wdptr);
ItemCount++;
}
/* step through each property in the list adding the XML */
STR_DSC_ITERATE (sdptr, &mtaptr->PropDsc)
{
if (!STR_DSC_LEN(sdptr)) continue;
StrDscBuild (wdptr, NULL, "\n");
StrDscBuild (wdptr, sdptr, NULL);
StrDscNewLine (wdptr);
StrDscBuild (wdptr, NULL, "\n");
ItemCount++;
}
StrDscBuild (wdptr, NULL, "\n");
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "!&Z", STR_DSC_PTR(wdptr));
if (ItemCount) return (SS$_NORMAL);
/* return this code to indicate the file is empty and should be deleted */
return (SS$_ALRDYCLOSED);
}
/*****************************************************************************/
/*
Add the XML element specified in 'adptr' to the descriptor collection specified
by 'cdptr'. Over-write an existing identical element in the collection.
Returns a pointer to the new (or over-written) element.
*/
STR_DSC* DavMetaSet
(
REQUEST_STRUCT *rqptr,
STR_DSC *cdptr,
STR_DSC *adptr
)
{
STR_DSC *sdptr;
/*********/
/* begin */
/*********/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaSet()");
if (sdptr = DavMetaSearch (rqptr, cdptr, adptr))
{
/* overwite existing element */
STR_DSC_LEN(sdptr) = 0;
sdptr = StrDscBuild (sdptr, adptr, NULL);
}
else
sdptr = StrDscBuild (cdptr, adptr, NULL);
STR_DSC_SET_FROZEN(sdptr)
return (sdptr);
}
/*****************************************************************************/
/*
Remove the XML element specified in 'rdptr' from the descriptor collection
specified by 'cdptr'. Returns true if removed, false if not found.
*/
BOOL DavMetaRemove
(
REQUEST_STRUCT *rqptr,
STR_DSC *cdptr,
STR_DSC *rdptr
)
{
STR_DSC *sdptr;
/*********/
/* begin */
/*********/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaRemove()");
if (sdptr = DavMetaSearch (rqptr, cdptr, rdptr))
{
STR_DSC_LEN(sdptr) = 0;
return (true);
}
return (false);
}
/*****************************************************************************/
/*
Search the collection specified by 'cdptr' for the element specified by
'edptr'. Return a pointer to the descriptor if found, otherwise return NULL.
*/
STR_DSC* DavMetaSearch
(
REQUEST_STRUCT *rqptr,
STR_DSC *cdptr,
STR_DSC *edptr
)
{
char *cptr, *sptr;
STR_DSC *sdptr;
/*********/
/* begin */
/*********/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaSearch()");
if (!cdptr || !edptr) return (NULL);
for (sdptr = cdptr; sdptr; sdptr = STR_DSC_NEXT(sdptr))
{
if (!(cptr = STR_DSC_PTR(edptr))) continue;
if (!(sptr = STR_DSC_PTR(sdptr))) continue;
while (*cptr && *sptr && *cptr != '>' && *sptr != '>' && *cptr == *sptr)
{
cptr++;
sptr++;
}
/* if the two elements matched then it's a hit */
if (*cptr == '>' && *sptr == '>') return (sdptr);
}
return (NULL);
}
/*****************************************************************************/
/*
(EXPAT) XML parse the text read from the database file. This will parse the
lock elements into 'MetaLockDsc' and the property elements into 'MetaPropDsc'.
*/
int DavMetaParseXml (WEBDAV_META *mtaptr)
{
int status, xmlsts;
STR_DSC *sdptr;
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaParseXml()");
sdptr = &mtaptr->ReadDsc;
/* shouldn't be calling this without content to parse! */
if (!(STR_DSC_SANITY(sdptr) && STR_DSC_LEN(sdptr))) return (SS$_BUGCHECK);
tkptr = rqptr->WebDavTaskPtr;
/* successful unless an error is encountered :-) */
status = SS$_NORMAL;
StrDscColIfNotBegin (rqptr, &mtaptr->PropDsc, 256);
mtaptr->ParseData = mtaptr->ParseLock =
mtaptr->ParseLockExpires = mtaptr->ParseLockOwner =
mtaptr->ParseProp = WEBDAV_STATE_NOT_PARSING;
tkptr->XmlData.ParserPtr = XML_ParserCreateNS ("UTF-8", ' ');
if (!tkptr->XmlData.ParserPtr) return (vaxc$errno);
mtaptr->ElementDepth = 0;
XML_SetUserData (tkptr->XmlData.ParserPtr, mtaptr);
XML_SetElementHandler (tkptr->XmlData.ParserPtr, DavMetaStartElement,
DavMetaEndElement);
XML_SetCharacterDataHandler (tkptr->XmlData.ParserPtr, DavMetaCharData);
xmlsts = XML_Parse (tkptr->XmlData.ParserPtr,
STR_DSC_PTR(sdptr), STR_DSC_LEN(sdptr), 1);
if (xmlsts == XML_STATUS_ERROR)
DavXmlParseError (rqptr, tkptr->XmlData.ParserPtr,
sdptr, &mtaptr->ParseErrorDsc);
XML_ParserFree (tkptr->XmlData.ParserPtr);
if (xmlsts == XML_STATUS_ERROR)
{
/* shouldn't be getting parse errors from our own data */
ErrorNoticed (rqptr, status = SS$_BUGCHECK,
STR_DSC_PTR(&mtaptr->ParseErrorDsc), FI_LI);
}
else
{
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
{
if (STR_DSC_LEN(&mtaptr->LockDsc))
{
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "LOCKS current");
STR_DSC_ITERATE (sdptr, &mtaptr->LockDsc)
if (STR_DSC_LEN(sdptr))
WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));
}
if (STR_DSC_LEN(&mtaptr->PropDsc))
{
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "META current");
STR_DSC_ITERATE (sdptr, &mtaptr->PropDsc)
if (STR_DSC_LEN(sdptr))
WatchDataFormatted ("!AZ\n", STR_DSC_PTR(sdptr));
}
}
}
return (status);
}
/*****************************************************************************/
/*
(EXPAT) This function and DavMetaEndElement() set various flags to indicate the
state of the current XML element. From those various flags indicating
properties to be manipulated are set.
This pretty-much assumes that the parsing library is ensuring document
well-formedness, so the checks on element nesting are very elementary.
*/
void XMLCALL DavMetaStartElement
(
WEBDAV_META *mtaptr,
char *ElementPtr,
char **AttrPtr
)
{
int idx, len, status;
char *cptr, *sptr, *zptr;
char ResourceBuffer [ODS_MAX_FILE_NAME_LENGTH+1];
STR_DSC *sdptr;
STR_DSC_AUTO (ScratchDsc);
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCH_XML && WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaStartElement() !UL !&Z",
mtaptr->ElementDepth+1, ElementPtr);
mtaptr->ElementDepth++;
if (WATCH_XML && WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
{
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "ELEMENT !AZ", ElementPtr);
for (idx = 0; AttrPtr[idx]; idx += 2)
WatchDataFormatted ("!AZ=\"!AZ\"\n", AttrPtr[idx], AttrPtr[idx+1]);
}
sdptr = NULL;
if (WEBDAV_IS_PARSING(mtaptr->ParseLock))
{
/* the most recently added lock will be at the head of the list */
lckptr = LIST_GET_HEAD(&mtaptr->LockList);
if (WEBDAV_IS_PARSING(mtaptr->ParseLockOwner))
sdptr = &lckptr->OwnerDsc;
else
sdptr = &lckptr->LockDsc;
}
else
if (WEBDAV_IS_PARSING(mtaptr->ParseProp))
sdptr = &mtaptr->PropDsc;
if (WEBDAV_IS_WASDAVEL (ElementPtr, "data"))
{
/* should only be the one data element per meta-data file! */
if (WEBDAV_IS_PARSED(mtaptr->ParseData))
{
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV,
"META multiple (ignoring subsequent)");
return;
}
WEBDAV_PARSING(mtaptr->ParseData);
}
else
if (WEBDAV_IS_WASDAVEL (ElementPtr, "lock"))
{
lckptr = (WEBDAV_LOCK*)VmGetHeap (rqptr, sizeof(WEBDAV_LOCK));
ListAddHead (&mtaptr->LockList, lckptr);
StrDscColIfNotBegin (rqptr, &lckptr->LockDsc, 256);
StrDscBegin (rqptr, &lckptr->OwnerDsc, 256);
WEBDAV_PARSING(mtaptr->ParseLock);
sdptr = &lckptr->LockDsc;
sdptr = StrDscBuild (sdptr, NULL, "ParseLock) &&
!WEBDAV_IS_PARSING(mtaptr->ParseLockOwner))
{
if (!strcmp (AttrPtr[idx], "depth"))
{
if (!strcmp (AttrPtr[idx+1], "0"))
lckptr->Depth = WEBDAV_DEPTH_ZERO;
else
if (!strcmp (AttrPtr[idx+1], "1"))
lckptr->Depth = WEBDAV_DEPTH_ONE;
else
if (!strcmp (AttrPtr[idx+1], "infinity"))
lckptr->Depth = WEBDAV_DEPTH_INFINITY;
else
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
else
if (!strcmp (AttrPtr[idx], "expires"))
{
zptr = (sptr = lckptr->ExpiresString) +
sizeof(lckptr->ExpiresString)-1;
for (cptr = AttrPtr[idx+1];
*cptr && sptr < zptr;
*sptr++ = *cptr++);
if (sptr < zptr)
{
*sptr = '\0';
status = DavWebDateTimeFrom3339 (lckptr->ExpiresString,
&lckptr->ExpiresBinTime);
if (VMSnok (status))
ErrorNoticed (rqptr, status, AttrPtr[idx+1], FI_LI);
}
else
{
lckptr->ExpiresString[0] = '\0';
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
}
else
if (!strcmp (AttrPtr[idx], "token"))
{
zptr = (sptr = lckptr->TokenString) +
sizeof(lckptr->TokenString);
for (cptr = AttrPtr[idx+1];
*cptr && sptr < zptr;
*sptr++ = *cptr++);
if (sptr < zptr)
*sptr = '\0';
else
{
lckptr->TokenString[0] = '\0';
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
}
else
if (!strcmp (AttrPtr[idx], "type"))
{
if (!strcmp (AttrPtr[idx+1], "write"))
lckptr->Type = WEBDAV_LOCK_TYPE_WRITE;
else
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
else
if (!strcmp (AttrPtr[idx], "scope"))
{
if (!strcmp (AttrPtr[idx+1], "exclusive"))
lckptr->Scope = WEBDAV_LOCK_SCOPE_EXCLUSIVE;
else
if (!strcmp (AttrPtr[idx+1], "shared"))
lckptr->Scope = WEBDAV_LOCK_SCOPE_SHARED;
else
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
else
if (!strcmp (AttrPtr[idx], "timeout"))
{
if (!strcmp (AttrPtr[idx+1], "infinite"))
{
lckptr->Timeout = WEBDAV_TIMEOUT_INFINITE;
strcpy (lckptr->TimeoutString, "infinite");
}
else
if (!strncmp (AttrPtr[idx+1], "Second-", 7) &&
isdigit(AttrPtr[idx+1][7]))
{
lckptr->Timeout = atoi(AttrPtr[idx+1]+7);
sprintf (lckptr->TimeoutString, "Second-%d", lckptr->Timeout);
}
else
ErrorNoticed (rqptr, SS$_BUGCHECK, AttrPtr[idx+1], FI_LI);
}
}
}
StrDscBuild (sdptr, NULL, ">\n");
sdptr = NULL;
}
else
if (WEBDAV_IS_WASDAVEL (ElementPtr, "owner"))
{
if (WEBDAV_IS_PARSING(mtaptr->ParseLock))
WEBDAV_PARSING(mtaptr->ParseLockOwner);
else
ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI);
}
else
if (WEBDAV_IS_WASDAVEL (ElementPtr, "prop"))
WEBDAV_PARSING(mtaptr->ParseProp);
if (sdptr)
{
for (cptr = ElementPtr; *cptr && *cptr != ' '; cptr++);
sdptr = StrDscBuild (sdptr, NULL, "");
WEBDAV_PARSING(mtaptr->ParseCharData);
}
else
WEBDAV_NOT_PARSING(mtaptr->ParseCharData);
}
/*****************************************************************************/
/*
(EXPAT) This function and DavMetaStartElement() set various flags to indicate
the state of the current XML element.
*/
void XMLCALL DavMetaEndElement
(
WEBDAV_META *mtaptr,
char *ElementPtr
)
{
char *cptr, *sptr;
STR_DSC *sdptr;
STR_DSC_AUTO (ScratchDsc);
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCH_XML && WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (mtaptr->RequestPtr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaEndElement() !UL !&Z",
mtaptr->ElementDepth, ElementPtr);
if (!WEBDAV_IS_PARSING(mtaptr->ParseData)) return;
if (WEBDAV_IS_PARSING(mtaptr->ParseLock))
{
if (WEBDAV_IS_WASDAVEL (ElementPtr, "lock"))
{
/* no longer parsing the lock, freeze current content */
WEBDAV_PARSED(mtaptr->ParseLock);
/* the most recently added lock will be at the head of the list */
lckptr = LIST_GET_HEAD(&mtaptr->LockList);
sdptr = &lckptr->LockDsc;
sdptr = StrDscBuild (sdptr, NULL, "");
StrDscTailFrozen (&lckptr->LockDsc);
}
else
if (WEBDAV_IS_WASDAVEL (ElementPtr, "owner"))
WEBDAV_PARSED(mtaptr->ParseLockOwner);
}
else
if (WEBDAV_IS_PARSING(mtaptr->ParseProp))
{
if (WEBDAV_IS_WASDAVEL (ElementPtr, "prop"))
{
/* no longer parsing this property, freeze current content */
WEBDAV_PARSED(mtaptr->ParseProp);
StrDscTailFrozen (&mtaptr->PropDsc);
}
}
else
/* as this is the level 0 element it MUST be the last checked! */
if (WEBDAV_IS_PARSING(mtaptr->ParseData))
{
if (WEBDAV_IS_WASDAVEL (ElementPtr, "data"))
WEBDAV_PARSED(mtaptr->ParseData);
}
sdptr = NULL;
if (WEBDAV_IS_PARSING(mtaptr->ParseLock))
{
/* the most recently added lock will be at the head of the list */
lckptr = LIST_GET_HEAD(&mtaptr->LockList);
if (WEBDAV_IS_PARSING(mtaptr->ParseLockOwner))
sdptr = &lckptr->OwnerDsc;
else
sdptr = &lckptr->LockDsc;
}
else
if (WEBDAV_IS_PARSING(mtaptr->ParseProp))
sdptr = &mtaptr->PropDsc;
if (sdptr)
{
for (cptr = ElementPtr; *cptr && *cptr != ' '; cptr++);
sdptr = StrDscBuild (sdptr, NULL, "");
if (mtaptr->ElementDepth == 3)
{
if (WEBDAV_IS_PARSING(mtaptr->ParseProp))
{
/* end of this property, freeze current content */
STR_DSC_SET_FROZEN (sdptr)
}
WEBDAV_NOT_PARSING(mtaptr->ParseCharData);
}
else
WEBDAV_PARSING(mtaptr->ParseCharData);
}
else
WEBDAV_NOT_PARSING(mtaptr->ParseCharData);
if (mtaptr->ElementDepth) mtaptr->ElementDepth--;
}
/*****************************************************************************/
/*
(EXPAT) XML character data.
*/
void XMLCALL DavMetaCharData
(
WEBDAV_META *mtaptr,
XML_Char *DataPtr,
int DataLength
)
{
STR_DSC *sdptr;
STR_DSC_AUTO (CharDataDsc);
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCH_XML && WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (mtaptr->RequestPtr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaCharData() !&B !UL |!#AZ",
mtaptr->ParseCharData, DataLength, DataLength, DataPtr);
if (!WEBDAV_IS_PARSING(mtaptr->ParseCharData)) return;
sdptr = NULL;
if (WEBDAV_IS_PARSING(mtaptr->ParseLock))
{
/* the most recently added lock will be at the head of the list */
lckptr = LIST_GET_HEAD(&mtaptr->LockList);
if (WEBDAV_IS_PARSING(mtaptr->ParseLockOwner))
sdptr = &lckptr->OwnerDsc;
else
sdptr = &lckptr->LockDsc;
}
else
if (WEBDAV_IS_PARSING(mtaptr->ParseProp))
sdptr = &mtaptr->PropDsc;
if (!sdptr) return;
StrDscThis (NULL, &CharDataDsc, DataPtr, DataLength);
StrDscBuild (sdptr, &CharDataDsc, NULL);
}
/*****************************************************************************/
/*
Generate the name of the meta-data file to be read.
*/
DavMetaReadName
(
WEBDAV_META *mtaptr,
char *FileSpec
)
{
int status;
char *cptr, *sptr, *zptr;
REQUEST_STRUCT *rqptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaReadName() !&Z", FileSpec);
zptr = (sptr = mtaptr->ReadMetaName) + sizeof(mtaptr->ReadMetaName)-1;
for (cptr = FileSpec; *cptr && sptr < zptr; *sptr++ = TOLO(*cptr++));
*sptr = '\0';
/* check that it's not already a meta-data specification */
for (cptr = sptr - 1;
cptr > FileSpec &&
(*cptr != '.' || SAME2(cptr-1,'^.')) &&
(*cptr != ']' || SAME2(cptr-1,'^]')) &&
!WEBDAV_WASDAV(cptr);
cptr--);
/* if not already a meta-data name */
if (!WEBDAV_WASDAV(cptr))
{
while (sptr > mtaptr->ReadMetaName &&
(*sptr != ';' || SAME2(sptr-1,'^;')) &&
(*sptr != '.' || SAME2(sptr-1,'^.')) &&
(*sptr != ']' || SAME2(sptr-1,'^]'))) sptr--;
if (*sptr == ']')
{
while (*sptr) sptr++;
if (*(sptr-1) != ']' && !SAME2(sptr-2,'^]') && sptr < zptr)
*sptr++ = '.';
}
else
if (*sptr != ';')
while (*sptr) sptr++;
*sptr = '\0';
if (*(sptr-1) == ']')
{
OdsNameOfDirectoryFile (mtaptr->ReadMetaName,
sptr - mtaptr->ReadMetaName,
mtaptr->ReadMetaName,
&mtaptr->ReadMetaNameLength);
for (sptr = mtaptr->ReadMetaName; *sptr; sptr++) *sptr = TOLO(*sptr);
}
for (cptr = "__wasdav"; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
mtaptr->ReadMetaNameLength = sptr - mtaptr->ReadMetaName;
if (sptr >= zptr)
{
/* disable the use of this meta-data file name */
SET4(mtaptr->ReadMetaName,'****');
ErrorNoticed (rqptr, SS$_BUFFEROVF, FileSpec, FI_LI);
}
Md5Digest (mtaptr->ReadMetaName, mtaptr->ReadMetaNameLength,
&mtaptr->ReadHash);
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "!&Z !8XL!8XL!8XL!8XL",
mtaptr->ReadMetaName,
mtaptr->ReadHash[0], mtaptr->ReadHash[1],
mtaptr->ReadHash[2], mtaptr->ReadHash[3]);
}
/*****************************************************************************/
/*
Generate the name of the meta-data file to be written.
*/
DavMetaWriteName
(
WEBDAV_META *mtaptr,
char *FileSpec
)
{
int status;
char *cptr, *sptr, *zptr;
REQUEST_STRUCT *rqptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaWriteName() !&Z", FileSpec);
zptr = (sptr = mtaptr->WriteMetaName) + sizeof(mtaptr->WriteMetaName)-1;
for (cptr = FileSpec; *cptr && sptr < zptr; *sptr++ = TOLO(*cptr++));
*sptr = '\0';
/* check that it's not already a meta-data specification */
for (cptr = sptr - 1;
cptr > FileSpec &&
(*cptr != '.' || SAME2(cptr-1,'^.')) &&
(*cptr != ']' || SAME2(cptr-1,'^]')) &&
!WEBDAV_WASDAV(cptr);
cptr--);
/* if not already a meta-data name */
if (!WEBDAV_WASDAV(cptr))
{
while (sptr > mtaptr->WriteMetaName &&
(*sptr != ';' || SAME2(sptr-1,'^;')) &&
(*sptr != '.' || SAME2(sptr-1,'^.')) &&
(*sptr != ']' || SAME2(sptr-1,'^]'))) sptr--;
if (*sptr == ']')
{
while (*sptr) sptr++;
if (*(sptr-1) != ']' && !SAME2(sptr-2,'^]') && sptr < zptr)
*sptr++ = '.';
}
else
if (*sptr != ';')
while (*sptr) sptr++;
*sptr = '\0';
if (*(sptr-1) == ']')
{
OdsNameOfDirectoryFile (mtaptr->WriteMetaName,
sptr - mtaptr->WriteMetaName,
mtaptr->WriteMetaName,
&mtaptr->WriteMetaNameLength);
for (sptr = mtaptr->WriteMetaName; *sptr; sptr++) *sptr = TOLO(*sptr);
}
for (cptr = "__wasdav"; *cptr && sptr < zptr; *sptr++ = *cptr++);
*sptr = '\0';
}
mtaptr->WriteMetaNameLength = sptr - mtaptr->WriteMetaName;
if (sptr >= zptr)
{
/* disable the use of this meta-data file name */
SET4(mtaptr->WriteMetaName,'****');
ErrorNoticed (rqptr, SS$_BUFFEROVF, FileSpec, FI_LI);
}
Md5Digest (mtaptr->WriteMetaName, mtaptr->WriteMetaNameLength,
&mtaptr->WriteHash);
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "!&Z !8XL!8XL!8XL!8XL",
mtaptr->WriteMetaName,
mtaptr->WriteHash[0], mtaptr->WriteHash[1],
mtaptr->WriteHash[2], mtaptr->WriteHash[3]);
}
/*****************************************************************************/
/*
Attempt to read a meta-data file corresponding to the file name provided in the
parameter. We're not sure whether such a meta-data file exists at this stage
so it might just end up a file-not-found at the AST.
*/
DavMetaRead
(
REQUEST_STRUCT *rqptr,
WEBDAV_META *mtaptr,
char *FileSpec,
REQUEST_AST AstFunction,
unsigned long AstParam
)
{
/*********/
/* begin */
/*********/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaRead() !&Z", FileSpec);
InstanceGblSecIncrLong (&AccountingPtr->WebDavMetaReadAttemptCount);
/* dispose of dynamic buffers from any previous call */
StrDscEnd (&mtaptr->ReadDsc, FI_LI);
memset (mtaptr, 0, sizeof(WEBDAV_META));
DavMetaReadName (mtaptr, FileSpec);
mtaptr->RequestPtr = rqptr;
mtaptr->TaskPtr = rqptr->WebDavTaskPtr;
mtaptr->UpdateLocked = false;
mtaptr->ReadAstFunction = AstFunction;
mtaptr->ReadAstParam = AstParam;
DavWebDlmEnqueue (rqptr, &mtaptr->DlmData, mtaptr->ReadMetaName,
&mtaptr->ReadHash, false, false, DavMetaReadOpen, mtaptr);
}
/*****************************************************************************/
/*
AST from VMS lock enqueue attempt.
*/
DavMetaReadOpen (WEBDAV_META *mtaptr)
{
REQUEST_STRUCT *rqptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaReadOpen() !UL !&Z",
mtaptr->ReadMetaNameLength, mtaptr->ReadMetaName);
mtaptr->VmsStatus = mtaptr->DlmData.LockSb.lksb$w_status;
if (VMSnok (mtaptr->VmsStatus))
{
/* VMS DLM enqueue failed, explicitly call any AST */
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "META read !AZ !&S",
mtaptr->ReadMetaName, mtaptr->VmsStatus);
SysDclAst (mtaptr->ReadAstFunction, mtaptr->ReadAstParam);
return;
}
/* turn on SYSPRV to allow access to the file */
sys$setprv (1, &SysPrvMask, 0, 0);
OdsOpen (&mtaptr->ReadOds,
mtaptr->ReadMetaName, mtaptr->ReadMetaNameLength, NULL, 0,
FAB$M_GET + FAB$M_BIO, 0, FAB$M_SHRGET,
&DavMetaOpenAst, mtaptr);
sys$setprv (0, &SysPrvMask, 0, 0);
}
/*****************************************************************************/
/*
Set up the meta-data creation attributes then queue an exclusive VMS LDM lock
on the meta-data hash. When granted this VMS DLM lock *queues* and blocks all
subsequent requests to modify the meta-data (and hence represented resource)
for the duration of the VMS DLM lock.
*/
DavMetaLock
(
REQUEST_STRUCT *rqptr,
WEBDAV_META *mtaptr,
char *FileSpec,
REQUEST_AST AstFunction,
unsigned long AstParam
)
{
/*********/
/* begin */
/*********/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaLock() !&Z", FileSpec);
InstanceGblSecIncrLong (&AccountingPtr->WebDavMetaReadAttemptCount);
/* dispose of dynamic buffers from any previous call */
StrDscEnd (&mtaptr->ReadDsc, FI_LI);
memset (mtaptr, 0, sizeof(WEBDAV_META));
DavMetaReadName (mtaptr, FileSpec);
mtaptr->RequestPtr = rqptr;
mtaptr->TaskPtr = rqptr->WebDavTaskPtr;
mtaptr->UpdateLocked = true;
mtaptr->ReadAstFunction = AstFunction;
mtaptr->ReadAstParam = AstParam;
DavWebDlmEnqueue (rqptr, &mtaptr->DlmData, mtaptr->ReadMetaName,
&mtaptr->ReadHash, false, false, DavMetaLockAst, mtaptr);
}
/*****************************************************************************/
/*
Check the VMS DLM status value for success or failure. If failed then just
queue the AST with the status code set. For success, open a file for exclusive
access. Create it if it does not already exist. We're not sure whether such a
meta-data file exists at this stage so it might just end up a file-not-found at
the AST.
*/
DavMetaLockAst (WEBDAV_META *mtaptr)
{
REQUEST_STRUCT *rqptr;
WEBDAV_DLM *dlmptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "DavMetaLockAst()");
dlmptr = &mtaptr->DlmData;
mtaptr->VmsStatus = dlmptr->LockSb.lksb$w_status;
if (VMSnok (mtaptr->VmsStatus))
{
/* VMS DLM enqueue failed, explicitly call any AST */
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "META read !AZ !&S",
mtaptr->ReadMetaName, mtaptr->VmsStatus);
SysDclAst (mtaptr->ReadAstFunction, mtaptr->ReadAstParam);
return;
}
/* turn on SYSPRV to allow access to the file */
sys$setprv (1, &SysPrvMask, 0, 0);
OdsCreate (&mtaptr->ReadOds,
mtaptr->ReadMetaName, mtaptr->ReadMetaNameLength, NULL, 0,
FAB$M_PUT + FAB$M_GET + FAB$M_BIO + FAB$M_TRN,
FAB$M_CIF + FAB$M_TEF,
FAB$M_NIL, FAB$C_STMLF, FAB$M_CR, NULL,
&DavMetaOpenAst, mtaptr);
sys$setprv (0, &SysPrvMask, 0, 0);
}
/*****************************************************************************/
/*
If the open fails (for any reason, including file-not-found) explicitly call
the AST function. If the open succeeds allocate a dynamic buffer the same
size of the file and $READ that as blocks (if larger than a possible single
$READ) from the file call DavMetaReadAst() when complete.
*/
DavMetaOpenAst (WEBDAV_META *mtaptr)
{
int status;
REQUEST_STRUCT *rqptr;
WEBDAV_DLM *dlmptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaOpenAst() !&S", mtaptr->ReadOds.Fab.fab$l_sts);
tkptr = rqptr->WebDavTaskPtr;
dlmptr = &mtaptr->DlmData;
if (VMSok (mtaptr->VmsStatus = mtaptr->ReadOds.Fab.fab$l_sts) &&
(mtaptr->ReadOds.Fab.fab$b_rfm == FAB$C_VAR ||
mtaptr->ReadOds.Fab.fab$b_rfm == FAB$C_VFC))
{
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV,
"META ***** MUST BE STREAM-LF FORMAT!! *****");
mtaptr->VmsStatus = SS$_ABORT;
}
if (VMSnok(mtaptr->VmsStatus))
{
/* open failed, explicitly call any AST */
if (mtaptr->VmsStatus != RMS$_FNF)
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV,
"META read open !AZ !&S",
mtaptr->ReadOds.ExpFileName,
mtaptr->VmsStatus);
mtaptr->UpdateLocked = false;
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->ReadAstFunction, mtaptr->ReadAstParam);
return;
}
mtaptr->ReadOds.Rab = cc$rms_rab;
mtaptr->ReadOds.Rab.rab$l_fab = &mtaptr->ReadOds.Fab;
status = sys$connect (&mtaptr->ReadOds.Rab, 0, 0);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadOds.ExpFileName, FI_LI);
mtaptr->ReadOds.Rab.rab$l_ctx = mtaptr;
mtaptr->ReadOds.Rab.rab$l_sts = mtaptr->ReadOds.Rab.rab$l_stv = 0;
if (mtaptr->VmsStatus == RMS$_CREATED)
{
/* if newly created, obviously nothing to read */
mtaptr->MetaCreated = true;
SysDclAst (mtaptr->ReadAstFunction, mtaptr->ReadAstParam);
return;
}
/* access to the meta data was successful */
InstanceGblSecIncrLong (&AccountingPtr->WebDavMetaReadCount);
DavMetaReadAst (&mtaptr->ReadOds.Rab);
}
/*****************************************************************************/
/*
The asynchronous $READ has completed. Check the status and the proportion of
the file read. If another $READ is required then queue that. Once the file
has been completely read, or at an error status, call the AST function.
*/
DavMetaReadAst (struct RAB *RabPtr)
{
int status,
BucketNumber,
SizeInBytes;
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
WEBDAV_META *mtaptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
mtaptr = RabPtr->rab$l_ctx;
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaReadAst() sts:!&X stv:!&X rsz:!UL",
RabPtr->rab$l_sts, RabPtr->rab$l_stv, RabPtr->rab$w_rsz);
tkptr = rqptr->WebDavTaskPtr;
if (mtaptr->ReadOds.Rab.rab$l_sts)
{
/*******************/
/* subsequent read */
/*******************/
mtaptr->VmsStatus = mtaptr->ReadOds.Rab.rab$l_sts;
if (VMSok (mtaptr->VmsStatus))
{
STR_DSC_LEN(&mtaptr->ReadDsc) += RabPtr->rab$w_rsz;
/* artifically generate an EOF as we've got all there is to get */
if (STR_DSC_LEN(&mtaptr->ReadDsc) >= STR_DSC_SIZE(&mtaptr->ReadDsc))
mtaptr->VmsStatus = RMS$_EOF;
}
}
else
{
/****************/
/* initial read */
/****************/
if (mtaptr->ReadOds.XabFhc.xab$l_ebk <= 1)
SizeInBytes = mtaptr->ReadOds.XabFhc.xab$w_ffb;
else
SizeInBytes = ((mtaptr->ReadOds.XabFhc.xab$l_ebk-1) << 9) +
mtaptr->ReadOds.XabFhc.xab$w_ffb;
/* unlikely to be legitimate meta-data if less than this */
if (SizeInBytes < 128)
{
/* can happen if the server exits without closing RMS$M_DLT files */
mtaptr->VmsStatus = SS$_ENDOFFILE;
}
else
{
StrDscBegin (rqptr, &mtaptr->ReadDsc, SizeInBytes);
/* asynchronous block $READs */
mtaptr->ReadOds.Rab.rab$l_rop = RAB$M_BIO | RAB$M_ASY;
mtaptr->VmsStatus = SS$_NORMAL;
}
}
if (VMSok (mtaptr->VmsStatus))
{
/*************/
/* read more */
/*************/
SizeInBytes = STR_DSC_SIZE(&mtaptr->ReadDsc) -
STR_DSC_LEN(&mtaptr->ReadDsc);
if (SizeInBytes > DAVMETA_READ_CHUNK) SizeInBytes = DAVMETA_READ_CHUNK;
BucketNumber = (STR_DSC_LEN(&mtaptr->ReadDsc) / 512) + 1;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV, "!UL-!UL=!UL !UL !UL",
STR_DSC_SIZE(&mtaptr->ReadDsc),
STR_DSC_LEN(&mtaptr->ReadDsc),
STR_DSC_SIZE(&mtaptr->ReadDsc) -
STR_DSC_LEN(&mtaptr->ReadDsc),
BucketNumber, SizeInBytes);
mtaptr->ReadOds.Rab.rab$l_ubf = STR_DSC_PTR(&mtaptr->ReadDsc) +
STR_DSC_LEN(&mtaptr->ReadDsc);
mtaptr->ReadOds.Rab.rab$w_usz = SizeInBytes;
mtaptr->ReadOds.Rab.rab$l_bkt = BucketNumber;
sys$read (&mtaptr->ReadOds.Rab, &DavMetaReadAst, &DavMetaReadAst);
return;
}
/*****************/
/* read finished */
/*****************/
/* if we retrieved the entire file then that's a good thing! */
if (mtaptr->VmsStatus == RMS$_EOF) mtaptr->VmsStatus = SS$_NORMAL;
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
{
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "META read !AZ !&S",
mtaptr->ReadOds.ExpFileName, mtaptr->VmsStatus);
if (VMSok(mtaptr->VmsStatus))
if (STR_DSC_LEN(&mtaptr->ReadDsc))
WatchDataFormatted ("!#AZ", STR_DSC_LEN(&mtaptr->ReadDsc),
STR_DSC_PTR(&mtaptr->ReadDsc));
}
if (VMSnok (mtaptr->VmsStatus))
{
/*******/
/* nbg */
/*******/
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
}
else
{
/*********/
/* parse */
/*********/
if (!mtaptr->UpdateLocked)
{
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
}
mtaptr->VmsStatus = DavMetaParseXml (mtaptr);
}
if (!mtaptr->UpdateLocked && !mtaptr->CopyLocked)
DavWebDequeue (&mtaptr->DlmData);
/* ensure any exclusive lock is at the head of the list */
LIST_ITERATE (lckptr, &mtaptr->LockList)
if (lckptr->Type == WEBDAV_LOCK_TYPE_WRITE &&
lckptr->Scope == WEBDAV_LOCK_SCOPE_EXCLUSIVE) break;
if (lckptr && lckptr != LIST_GET_HEAD(&mtaptr->LockList))
{
/* move it to the head of the list */
ListRemove (&mtaptr->LockList, lckptr);
ListAddHead (&mtaptr->LockList, lckptr);
}
SysDclAst (mtaptr->ReadAstFunction, mtaptr->ReadAstParam);
}
/*****************************************************************************/
/*
The file has been opened for write exclusively locked by DavMetaRead(). If it
was an existing meta-data file the content can be updated or if it was created
the content can be 'updated' for the first time. If there are no properties
data to be written to the file then flag it for delete-on-close and close the
file, otherwise build a buffer of the properties data and queue an asynchronous
$WRITE.
*/
DavMetaUpdate
(
WEBDAV_META *mtaptr,
REQUEST_AST AstFunction,
unsigned long AstParam
)
{
int status,
MaxKbytes,
PropCount,
SizeInBytes;
STR_DSC *sdptr;
REQUEST_STRUCT *rqptr;
WEBDAV_LOCK *lckptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaUpdate() !&S", mtaptr->VmsStatus);
tkptr = rqptr->WebDavTaskPtr;
mtaptr->UpdateAstFunction = AstFunction;
mtaptr->UpdateAstParam = AstParam;
if (mtaptr->VmsStatus != RMS$_CREATED)
{
/*******************/
/* update allowed? */
/*******************/
if (VMSnok (mtaptr->VmsStatus = DavLockTestMeta (rqptr)))
goto DavMetaUpdateAbort;
}
if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_LOCK)
{
/********/
/* lock */
/********/
if (rqptr->rqHeader.WebDavIfPtr)
{
/* should be refreshing an existing lock */
if (!(lckptr = DavLockFindToken (rqptr))) goto DavMetaUpdateAbort;
}
else
{
/* if the request didn't supply complete lock data */
if (!(tkptr->LockData.Type &&
tkptr->LockData.Scope)) goto DavMetaUpdateAbort;
/* add it to the list */
ListAddHead (&mtaptr->LockList, lckptr = &tkptr->LockData);
DavLockSetToken (rqptr, lckptr);
}
if (DavLockSetTimeout (rqptr, lckptr))
goto DavMetaUpdateAbort;
}
else
if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_UNLOCK)
{
/**********/
/* unlock */
/**********/
/* should be an existing lock */
if (!(lckptr = DavLockFindToken (rqptr))) goto DavMetaUpdateAbort;
/* simply remove the lock from the list */
ListRemove (&mtaptr->LockList, lckptr);
}
/*******************/
/* build meta-data */
/*******************/
/* ensure the file disappears unless successfully completed */
mtaptr->ReadOds.DeleteOnClose = true;
status = DavMetaBuild (mtaptr);
if (VMSnok(status) || status == SS$_ALRDYCLOSED)
{
/********************/
/* delete meta-data */
/********************/
tkptr->MetaData.VmsStatus = status;
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
return;
}
/*******************/
/* limit meta size */
/*******************/
/* to something reasonable (say 1/32 of the maximum PUTable) */
SizeInBytes = 0;
for (sdptr = &mtaptr->WriteDsc; sdptr; sdptr = STR_DSC_NEXT(sdptr))
SizeInBytes += STR_DSC_LEN(sdptr);
if (!(MaxKbytes = rqptr->rqPathSet.PutMaxKbytes))
MaxKbytes = Config.cfMisc.PutMaxKbytes;
if ((SizeInBytes >> 10) > (MaxKbytes >> 5))
{
DavWebResponse (rqptr, 413, 0, "META too large", FI_LI);
/* keep the existing meta file */
mtaptr->ReadOds.DeleteOnClose = false;
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
return;
}
/********************/
/* set up the write */
/********************/
mtaptr->ReadOds.Rab.rab$l_ctx = mtaptr;
mtaptr->ReadOds.Rab.rab$l_sts = mtaptr->ReadOds.Rab.rab$l_stv = 0;
DavMetaUpdateWrite (&mtaptr->ReadOds.Rab);
return;
DavMetaUpdateAbort:
{
/********************/
/* abort the update */
/********************/
mtaptr->VmsStatus = SS$_ABORT;
/* allow existing to remain in the meta-data store */
mtaptr->ReadOds.DeleteOnClose = true;
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
}
}
/*****************************************************************************/
/*
This function queues $WRITEs of the meta-data and acts as it's own AST,
assessing the status of the previous write and queuing then next, if required.
When the write has completed (successfully or unsuccessfully) the
'MetaUpdateAstFunction' is called which should (as always) check 'MetaStatus'.
*/
DavMetaUpdateWrite (struct RAB *RabPtr)
{
int status;
REQUEST_STRUCT *rqptr;
STR_DSC *sdptr;
WEBDAV_META *mtaptr;
WEBDAV_TASK *tkptr;
/*********/
/* begin */
/*********/
mtaptr = RabPtr->rab$l_ctx;
rqptr = mtaptr->RequestPtr;
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"DavMetaUpdateWrite() sts:!&S stv:!&S",
RabPtr->rab$l_sts, RabPtr->rab$l_stv);
tkptr = rqptr->WebDavTaskPtr;
if (mtaptr->ReadOds.Rab.rab$l_sts)
{
/********************/
/* subsequent write */
/********************/
status = mtaptr->VmsStatus = mtaptr->ReadOds.Rab.rab$l_sts;
if (VMSnok (status))
{
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "META update !AZ !&S",
mtaptr->ReadMetaName, status);
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
return;
}
}
else
{
/*****************/
/* initial write */
/*****************/
InstanceGblSecIncrLong (&AccountingPtr->WebDavMetaWriteAttemptCount);
/* check the data is acceptable for $WRITE */
for (sdptr = &mtaptr->WriteDsc; sdptr; sdptr = STR_DSC_NEXT(sdptr))
{
/* all but the last descriptor must be a full block */
if (STR_DSC_LEN(sdptr) > 0xffff ||
(STR_DSC_NEXT(sdptr) && STR_DSC_LEN(sdptr) % 512))
{
mtaptr->VmsStatus = SS$_BUGCHECK;
ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI);
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSnok (status))
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
return;
}
}
mtaptr->RabBucket = 1;
mtaptr->ReadOds.Rab.rab$l_rop = RAB$M_BIO | RAB$M_ASY | RAB$M_TPT;
}
/* find the next descriptor to be written */
for (sdptr = &mtaptr->WriteDsc; sdptr; sdptr = STR_DSC_NEXT(sdptr))
if (!STR_DSC_IS_NOTED(sdptr)) break;
if (!sdptr)
{
/***************/
/* end of data */
/***************/
if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_WEBDAV))
{
WatchThis (rqptr, FI_LI, WATCH_WEBDAV, "META update !AZ !&S",
mtaptr->ReadOds.ExpFileName, SS$_NORMAL);
if (STR_DSC_LEN(&mtaptr->WriteDsc))
WatchDataFormatted ("!#AZ", STR_DSC_LEN(&mtaptr->WriteDsc),
STR_DSC_PTR(&mtaptr->WriteDsc));
}
mtaptr->VmsStatus = SS$_NORMAL;
/* allow it to remain in the meta-data store */
mtaptr->ReadOds.DeleteOnClose = false;
status = OdsClose (&mtaptr->ReadOds, NULL, NULL);
if (VMSok (status))
InstanceGblSecIncrLong (&AccountingPtr->WebDavMetaWriteCount);
else
ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI);
DavWebDequeue (&mtaptr->DlmData);
SysDclAst (mtaptr->UpdateAstFunction, mtaptr->UpdateAstParam);
return;
}
/**************/
/* write data */
/**************/
if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD_WEBDAV))
WatchThis (rqptr, FI_LI, WATCH_MOD_WEBDAV,
"rsz: !UL", STR_DSC_LEN(sdptr));
mtaptr->ReadOds.Rab.rab$l_rbf = STR_DSC_PTR(sdptr);
mtaptr->ReadOds.Rab.rab$w_rsz = STR_DSC_LEN(sdptr);
mtaptr->ReadOds.Rab.rab$l_bkt = mtaptr->RabBucket;
mtaptr->RabBucket += STR_DSC_LEN(sdptr) / 512;
STR_DSC_SET_NOTED(sdptr)
sys$write (&mtaptr->ReadOds.Rab, &DavMetaUpdateWrite,
&DavMetaUpdateWrite);
}
/*****************************************************************************/