/*****************************************************************************/ /* DAVmove.c Also see comments on MOVE in DAVWEB.C. Implement the MOVE method for single resources (files) and collections (directory trees). Moves behave the same for for single resources (files) and collections (directories). Both are renamed (if possible), with the directory file itself being renamed in the case of a collection. Should the rename fail due to the target being on another volume the move is done via a copy and delete using the respective DAV code modules. VERSION HISTORY --------------- 17-OCT-2018 MGD bugfix; ensure meta directory exists 07-JUL-2018 MGD bugfix; DavMoveMeta() OdsParseRelease() as final action 05-JUL-2018 MGD bugfix; flawed use of lib$rename_file() using DEFAULT_ZONE memory without free (context not exhausted) - use DavMoveRename() instead (which should be more efficient) bugfix; remove context from lib$rename_file() 28-APR-2015 MGD bugfix; DavMoveMeta() do not report RMS$_DNF 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 "wasd.h" #include "davweb.h" #define WASD_MODULE "DAVMOVE" #define TEST_DEADLOCK_DETECT 0 #define TEST_BETWEEN_DEVICES 0 /* use RMS $RENAME by default but allow older LIB$RENAME_FILE as option */ #define DAV_MOVE_USING_ODS 1 /******************/ /* global storage */ /******************/ /********************/ /* external storage */ /********************/ extern int ToLowerCase[], ToUpperCase[]; extern unsigned long SysPrvMask[]; extern char ErrorSanityCheck[]; extern ACCOUNTING_STRUCT *AccountingPtr; extern CONFIG_STRUCT Config; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* */ DavMoveBegin (REQUEST_STRUCT *rqptr) { int status; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveBegin()"); tkptr = rqptr->WebDavTaskPtr; tkptr->TestLockState = 0; status = DavWebDestination (rqptr); if (VMSnok (status)) { DavWebResponse (rqptr, 0, status, NULL, FI_LI); DavWebEnd (rqptr); return; } if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "MOVE !AZ to !AZ overwrite:!&B depth:!UL path:!AZ", rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, tkptr->CopyData.MoveOverwrite, tkptr->ToDepth, DavWebPathAccess(rqptr)); if (!strcmp (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName)) { /* case-sensitive because the client might just be changing case! */ DavWebResponse (rqptr, 403, 0, "identical", FI_LI); DavWebEnd (rqptr); return; } if (rqptr->ParseOds.NamNameLength || rqptr->ParseOds.NamTypeLength) { /********/ /* file */ /********/ if (tkptr->DestOds.NamNameLength || tkptr->DestOds.NamTypeLength) { /* to a file */ DavMoveFile (rqptr); return; } DavWebResponse (rqptr, 400, 0, "file to directory", FI_LI); } else { /*************/ /* directory */ /*************/ if (!tkptr->DestOds.NamNameLength && !tkptr->DestOds.NamTypeLength) { /* to a directory */ DavMoveDirectory (rqptr); return; } DavWebResponse (rqptr, 400, 0, "directory to file", FI_LI); } DavWebEnd (rqptr); } /*****************************************************************************/ /* */ DavMoveEnd (REQUEST_STRUCT *rqptr) { int status; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveEnd()"); tkptr = rqptr->WebDavTaskPtr; if (tkptr->MoveUsingCopy) { /* delete directories left over from move using copy */ tkptr->MoveUsingCopy = false; status = DavDeleteParse (rqptr, true, "...]*.DIR;*"); if (VMSnok (status)) { DavWebResponse (rqptr, 0, status, NULL, FI_LI); DavWebEnd (rqptr); return; } tkptr->DeleteData.DelPhase = WEBDAV_DELETE_TREE_FILES; DavDeleteSearch (rqptr); return; } if (!rqptr->rqResponse.HttpStatus) { /* in the absence of any other (207 perhaps) status */ if (tkptr->OverwriteOccurred) DavWebResponse (rqptr, 204, 0, "success, overwrite", FI_LI); else { DavWebHref (rqptr, tkptr->DestOds.ExpFileName, 0); DavWebResponse201 (rqptr); } } DavWebEnd (rqptr); } /*****************************************************************************/ /* Move a single (non-.DIR) file. This function will be called multiple times as asynchronous testing of the DLM and meta locking occurs. */ DavMoveFile (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (DstNameDsc, ""); static $DESCRIPTOR (SrcNameDsc, ""); BOOL CanDoIt; int status; unsigned long RenameFlags; ODS_STRUCT DeleteOds; WEBDAV_DLM *dlmptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveFile() !UL", tkptr->TestLockState); /***********/ /* locking */ /***********/ switch (tkptr->TestLockState) { case 0 : /* establish a request (overall) VMS DLM lock on source */ tkptr->TestLockState++; DavWebDlmEnqueue (rqptr, &tkptr->DlmSource, rqptr->ParseOds.ExpFileName, NULL, true, false, DavMoveFile, rqptr); return; case 1 : if (VMSnok (status = tkptr->DlmSource.LockSb.lksb$w_status)) { /* ordinarily shouldn't return any errors */ DavWebResponse (rqptr, 500, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* establish a request (overall) VMS DLM lock on destination */ tkptr->TestLockState++; /* we can rename the case of the same underlying name! */ if (strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { /* do NOT take up a DLM lock on the same target - deadlock!! */ tkptr->DlmDestin.LockSb.lksb$w_status = SS$_NORMAL; DavMoveFile (rqptr); } else { DavWebDlmEnqueue (rqptr, &tkptr->DlmDestin, #if TEST_DEADLOCK_DETECT rqptr->ParseOds.ExpFileName, NULL, #else tkptr->DestOds.ExpFileName, NULL, #endif true, false, DavMoveFile, rqptr); } return; case 2 : if (VMSnok (status = tkptr->DlmDestin.LockSb.lksb$w_status)) { /* ordinarily shouldn't return any errors */ DavWebResponse (rqptr, 500, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* check for meta-lock on existing source */ tkptr->TestLockState++; DavLockTest (rqptr, rqptr->ParseOds.ExpFileName, false, DavMoveFile, rqptr); return; case 3 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "source locked", FI_LI); DavMoveEnd (rqptr); return; } /* check for meta-lock on existing destination */ tkptr->TestLockState++; DavLockTest (rqptr, tkptr->DestOds.ExpFileName, false, DavMoveFile, rqptr); return; case 4 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "destination locked", FI_LI); DavMoveEnd (rqptr); return; } } /*****************/ /* ready to move */ /*****************/ if (DavMetaFile (&tkptr->DestOds) || DavMetaDir (rqptr, &tkptr->DestOds)) { /* this is a metadata file or contains a metadata (sub)directory */ DavWebResponse (rqptr, 404, 0, "directory not found", FI_LI); DavMoveEnd (rqptr); return; } if (!tkptr->CopyData.MoveOverwrite) { sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (tkptr->DestOds.ExpFileName, NULL); sys$setprv (0, &SysPrvMask, 0, 0); if (VMSok(status)) { /* if really different and not just a case change (for instance) */ if (!strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { DavWebResponse (rqptr, 412, 0, "target file exists, no overwrite", FI_LI); DavMoveEnd (rqptr); return; } } } if (!rqptr->ParseOds.ExpFileNameLength || !tkptr->DestOds.ExpFileNameLength) { ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI); DavWebResponse (rqptr, 0, SS$_BUGCHECK, NULL, FI_LI); DavMoveEnd (rqptr); return; } #if TEST_BETWEEN_DEVICES status = RMS$_DEV; #else if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!AZ to !AZ", rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); SrcNameDsc.dsc$a_pointer = rqptr->ParseOds.ExpFileName; SrcNameDsc.dsc$w_length = rqptr->ParseOds.ExpFileNameLength; DstNameDsc.dsc$a_pointer = tkptr->DestOds.ExpFileName; DstNameDsc.dsc$w_length = tkptr->DestOds.ExpFileNameLength; CanDoIt = AuthAccessEnable (rqptr, tkptr->DestOds.ExpFileName, AUTH_ACCESS_WRITE); #if DAV_MOVE_USING_ODS status = DavMoveRename (rqptr, &SrcNameDsc, &DstNameDsc); #else /* DAV_MOVE_USING_ODS */ RenameFlags = 0x1; #ifdef ODS_EXTENDED if (rqptr->PathOdsExtended) RenameFlags += 0x4; #endif /* ODS_EXTENDED */ status = lib$rename_file (&SrcNameDsc, &DstNameDsc, 0, 0, &RenameFlags, 0, 0, 0, 0, 0, 0, 0); #endif /* DAV_MOVE_USING_ODS */ #endif /* TEST_BETWEEN_DEVICES */ AuthAccessEnable (rqptr, 0, 0); if (WATCHING (rqptr, WATCH_WEBDAV)) { if (VMSok(status)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAMED !AZ to !AZ", rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); else if (status != RMS$_DEV) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAME !&S !AZ to !AZ", status, rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); } if (VMSnok(status)) { if (status == RMS$_DEV) { /*********************/ /* to another device */ /*********************/ if (!CanDoIt) { DavWebResponse (rqptr, 403, 0, "uncertain permission to delete source file", FI_LI); DavMoveEnd (rqptr); return; } if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "MOVE to another device - using COPY with DELETE"); tkptr->MoveUsingCopy = true; DavCopyFile (rqptr); return; } if (status == RMS$_RMV) DavWebResponse (rqptr, 403, status, "protection", FI_LI); else if (status == RMS$_DNF) DavWebResponse (rqptr, 409, status, "parent", FI_LI); else DavWebResponse (rqptr, 0, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* if not just a change of case */ if (!strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { /**********************************/ /* delete any previous version(s) */ /**********************************/ OdsStructInit (&DeleteOds, true); OdsParse (&DeleteOds, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength, NULL, 0, NAM$M_SYNCHK, NULL, rqptr); if (VMSnok (status = DeleteOds.Fab.fab$l_sts)) ErrorNoticed (rqptr, status, NULL, FI_LI); else { AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); while (VMSok (status = sys$erase (&DeleteOds.Fab, 0, 0))); AuthAccessEnable (rqptr, 0, 0); if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$erase() !&S !AZ", status, DeleteOds.ExpFileName); if (VMSnok (status) && DeleteOds.Fab.fab$l_stv) status = DeleteOds.Fab.fab$l_stv; if (VMSok (status)) tkptr->OverwriteOccurred = true; if (status == SS$_NOSUCHFILE) status = SS$_NORMAL; if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } OdsParseRelease (&DeleteOds); /*****************/ /* move any meta */ /*****************/ DavMoveMeta (rqptr, rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); } DavMoveEnd (rqptr); } /*****************************************************************************/ /* Move a directory (tree). This function will be called multiple times as asynchronous testing of the DLM and meta locking occurs. */ DavMoveDirectory (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (DstNameDsc, ""); static $DESCRIPTOR (SrcNameDsc, ""); BOOL CanDoIt; int status, DstNameLength, SrcNameLength; unsigned long RenameFlags; char *cptr, *sptr, *zptr; char DstName [ODS_MAX_FILE_NAME_LENGTH+1], SrcName [ODS_MAX_FILE_NAME_LENGTH+1]; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveDirectory() !UL", tkptr->TestLockState); if (VMSnok (DavWebParentExists (NULL, tkptr->DestOds.ExpFileName))) { DavWebResponse (rqptr, 412, 0, "parent does not exist", FI_LI); DavMoveEnd (rqptr); return; } /***********/ /* locking */ /***********/ switch (tkptr->TestLockState) { case 0 : /* establish a request (overall) VMS DLM lock on source */ tkptr->TestLockState++; DavWebDlmEnqueue (rqptr, &tkptr->DlmSource, rqptr->ParseOds.ExpFileName, NULL, true, false, DavMoveDirectory, rqptr); return; case 1 : if (VMSnok (status = tkptr->DlmSource.LockSb.lksb$w_status)) { /* ordinarily shouldn't return any errors */ DavWebResponse (rqptr, 500, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* establish a request (overall) VMS DLM lock on destination */ tkptr->TestLockState++; /* we can rename the case of the same underlying name! */ if (strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { /* do NOT take up a DLM lock on the same target - deadlock!! */ tkptr->DlmDestin.LockSb.lksb$w_status = SS$_NORMAL; DavMoveDirectory (rqptr); } else { DavWebDlmEnqueue (rqptr, &tkptr->DlmDestin, #if TEST_DEADLOCK_DETECT rqptr->ParseOds.ExpFileName, NULL, #else tkptr->DestOds.ExpFileName, NULL, #endif true, false, DavMoveDirectory, rqptr); } return; case 2 : if (VMSnok (status = tkptr->DlmDestin.LockSb.lksb$w_status)) { /* ordinarily shouldn't return any errors */ DavWebResponse (rqptr, 500, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* check for meta-lock on existing source */ tkptr->TestLockState++; DavLockTest (rqptr, rqptr->ParseOds.ExpFileName, false, DavMoveDirectory, rqptr); return; case 3 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "source locked", FI_LI); DavMoveEnd (rqptr); return; } /* check for meta-lock on existing destination */ tkptr->TestLockState++; DavLockTest (rqptr, tkptr->DestOds.ExpFileName, false, DavMoveDirectory, rqptr); return; case 4 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "destination locked", FI_LI); DavMoveEnd (rqptr); return; } } /*****************/ /* ready to move */ /*****************/ if (DavMetaFile (&tkptr->DestOds) || DavMetaDir (rqptr, &tkptr->DestOds)) { /* this is a metadata file or contains a metadata (sub)directory */ DavWebResponse (rqptr, 404, 0, "directory not found", FI_LI); DavMoveEnd (rqptr); return; } /* all collection moves must act as if the depth is infinity */ tkptr->ToDepth = WEBDAV_DEPTH_INFINITY; OdsNameOfDirectoryFile (tkptr->DestOds.ExpFileName, tkptr->DestOds.ExpFileNameLength, DstName, &DstNameLength); sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (DstName, NULL); sys$setprv (0, &SysPrvMask, 0, 0); if (tkptr->CopyData.MoveOverwrite) { /* collection COPY does not (yet) support overwrite */ if (status != RMS$_FNF && status != RMS$_DNF) { /* not completely accurate but will do in the interim */ DavWebResponse (rqptr, 409, 0, "directory MOVE does not support overwrite", FI_LI); DavMoveEnd (rqptr); return; } } else { if (VMSok(status)) { /* if really different and not just a case change (for instance) */ if (!strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { DavWebResponse (rqptr, 412, 0, "target directory exists, overwrite not requested", FI_LI); DavMoveEnd (rqptr); return; } } } OdsNameOfDirectoryFile (rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength, SrcName, &SrcNameLength); if (!rqptr->ParseOds.ExpFileNameLength || !tkptr->DestOds.ExpFileNameLength) { ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI); DavWebResponse (rqptr, 0, SS$_BUGCHECK, NULL, FI_LI); DavMoveEnd (rqptr); return; } if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!AZ to !AZ", SrcName, DstName); SrcNameDsc.dsc$a_pointer = SrcName; SrcNameDsc.dsc$w_length = SrcNameLength; DstNameDsc.dsc$a_pointer = DstName; DstNameDsc.dsc$w_length = DstNameLength; CanDoIt = AuthAccessEnable (rqptr, tkptr->DestOds.ExpFileName, AUTH_ACCESS_WRITE); #if TEST_BETWEEN_DEVICES status = RMS$_DEV; #else #if DAV_MOVE_USING_ODS status = DavMoveRename (rqptr, &SrcNameDsc, &DstNameDsc); #else /* DAV_MOVE_USING_ODS */ RenameFlags = 0x1; #ifdef ODS_EXTENDED if (rqptr->PathOdsExtended) RenameFlags += 0x4; #endif /* ODS_EXTENDED */ status = lib$rename_file (&SrcNameDsc, &DstNameDsc, 0, 0, &RenameFlags, 0, 0, 0, 0, 0, 0, 0); #endif /* DAV_MOVE_USING_ODS */ #endif /* TEST_BETWEEN_DEVICES */ AuthAccessEnable (rqptr, 0, 0); if (WATCHING (rqptr, WATCH_WEBDAV)) { if (VMSok(status)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAMED !AZ to !AZ", SrcName, DstName); else if (status != RMS$_DEV) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAME !&S !AZ to !AZ", status, SrcName, DstName); } if (VMSnok (status)) { if (status == RMS$_DEV) { /*********************/ /* to another device */ /*********************/ if (!CanDoIt) { DavWebResponse (rqptr, 403, 0, "uncertain permission to delete source directory", FI_LI); DavMoveEnd (rqptr); return; } if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "MOVE to another device - using COPY with DELETE"); tkptr->MoveUsingCopy = true; DavCopyDirectory (rqptr); return; } if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "MOVE rename !AZ to !AZ !&S", SrcNameDsc.dsc$a_pointer, DstNameDsc.dsc$a_pointer, status); if (status == RMS$_RMV) DavWebResponse (rqptr, 403, status, "protection", FI_LI); else if (status == RMS$_IDR) DavWebResponse (rqptr, 403, status, "dependency", FI_LI); else if (status == RMS$_DNF) DavWebResponse (rqptr, 409, status, "parent", FI_LI); else DavWebResponse (rqptr, 0, status, NULL, FI_LI); DavMoveEnd (rqptr); return; } /* if not just a change of case */ if (!strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { /*****************/ /* move any meta */ /*****************/ DavMoveMeta (rqptr, rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); } DavMoveEnd (rqptr); } /*****************************************************************************/ /* Move any meta file associated with the source to the destination. If there were multiple versions of the that meta file (because of gerfingerpokin) then delete remaining version. Assumes everything's locked by the calling routine. */ int DavMoveMeta ( REQUEST_STRUCT *rqptr, char *SrcFileName, char *DstFileName ) { static $DESCRIPTOR (DstNameDsc, ""); static $DESCRIPTOR (SrcNameDsc, ""); int status; unsigned long RenameFlags; char *cptr, *sptr, *zptr; ODS_STRUCT DeleteOds; WEBDAV_META *mtaptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveMeta() !AZ !AZ", SrcFileName, DstFileName); mtaptr = &tkptr->MetaData; mtaptr->TaskPtr = rqptr->WebDavTaskPtr; DavMetaName (mtaptr, SrcFileName, 'r'); DavMetaName (mtaptr, DstFileName, 'w'); if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!AZ to !AZ", SrcFileName, DstFileName); SrcNameDsc.dsc$a_pointer = mtaptr->ReadMetaName; SrcNameDsc.dsc$w_length = mtaptr->ReadMetaNameLength; DstNameDsc.dsc$a_pointer = mtaptr->WriteMetaName; DstNameDsc.dsc$w_length = mtaptr->WriteMetaNameLength; DavMetaCreateDir (mtaptr); sys$setprv (1, &SysPrvMask, 0, 0); #if DAV_MOVE_USING_ODS status = DavMoveRename (rqptr, &SrcNameDsc, &DstNameDsc); #else /* DAV_MOVE_USING_ODS */ RenameFlags = 0x1; #ifdef ODS_EXTENDED if (rqptr->PathOdsExtended) RenameFlags += 0x4; #endif /* ODS_EXTENDED */ status = lib$rename_file (&SrcNameDsc, &DstNameDsc, 0, 0, &RenameFlags, 0, 0, 0, 0, 0, 0, 0); #endif /* DAV_MOVE_USING_ODS */ sys$setprv (0, &SysPrvMask, 0, 0); if (WATCHING (rqptr, WATCH_WEBDAV)) { if (VMSok(status)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAMED !AZ to !AZ", mtaptr->ReadMetaName, mtaptr->WriteMetaName); else if (status != RMS$_FNF && status != RMS$_DNF) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "RENAME !&S !AZ to !AZ", status, mtaptr->ReadMetaName, mtaptr->WriteMetaName); } if (VMSnok (status) && status != RMS$_DNF && status != RMS$_FNF) { ErrorNoticed (rqptr, status, NULL, FI_LI); return (status); } /* purge all (remaining) previous meta version(s) */ OdsStructInit (&DeleteOds, true); OdsParse (&DeleteOds, mtaptr->ReadMetaName, mtaptr->ReadMetaNameLength, NULL, 0, NAM$M_SYNCHK, NULL, rqptr); if (VMSnok (status = DeleteOds.Fab.fab$l_sts)) { ErrorNoticed (rqptr, status, NULL, FI_LI); return (status); } sys$setprv (1, &SysPrvMask, 0, 0); while (VMSok (status = sys$erase (&DeleteOds.Fab, 0, 0))); sys$setprv (0, &SysPrvMask, 0, 0); if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$erase() !&S !AZ", status, DeleteOds.ExpFileName); if (VMSnok (status) && DeleteOds.Fab.fab$l_stv) status = DeleteOds.Fab.fab$l_stv; if (status == SS$_NOSUCHFILE) status = SS$_NORMAL; if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); OdsParseRelease (&DeleteOds); return (status); } /*****************************************************************************/ /* Rename a single version of a single file. */ #if DAV_MOVE_USING_ODS int DavMoveRename ( REQUEST_STRUCT *rqptr, struct dsc$descriptor *SrcDscPtr, struct dsc$descriptor *DstDscPtr ) { int status; ODS_STRUCT DstOds, SrcOds; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavMoveRename() !AZ !AZ", SrcDscPtr->dsc$a_pointer, DstDscPtr->dsc$a_pointer); OdsStructInit (&SrcOds, true); status = OdsParse (&SrcOds, SrcDscPtr->dsc$a_pointer, SrcDscPtr->dsc$w_length, NULL, 0, NAM$M_NOCONCEAL, NULL, rqptr); if (VMSok (status)) { OdsStructInit (&DstOds, true); status = OdsParse (&DstOds, DstDscPtr->dsc$a_pointer, DstDscPtr->dsc$w_length, NULL, 0, NAM$M_NOCONCEAL, NULL, rqptr); } if (VMSok (status)) { status = sys$rename (&SrcOds.Fab, 0, 0, &DstOds.Fab); if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "$rename() !&S", status); } return (status); } #endif /* !DAV_MOVE_USING_ODS */ /*****************************************************************************/