/*****************************************************************************/ /* DAVcopy.c Also see comments on MOVE in DAVWEB.C. Implement the COPY method for single resources (files) and collections (directory trees). This module is also used by a MOVE of resources between different volumes. For files a DLM is taken out on the source file specification and any associated meta-data tested for. If not locked the file is copied. For directories (collections) a DLM lock is taken out on the source directory and target directory specifications, and then any associated META locking tested. Locking permitting the source tree is then walked with corresponding target directories being created and files copied from tree-to-tree. Source files are deleted when closed (so the source tree shrinks as the target tree grows). When concluded source directory files (.DIRs) remain in the source tree and are explicitly removed using DELETE functionality. VERSION HISTORY --------------- 17-OCT-2018 MGD bugfix; ensure meta directory exists 16-OCT-2018 MGD bugfix; DavCopyNext() copy meta for single file 13-APR-2018 MGD SS$_ABORT on ->RequestRundown 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 "DAVCOPY" #define TEST_DEADLOCK_DETECT 0 /******************/ /* global storage */ /******************/ /********************/ /* external storage */ /********************/ extern char ErrorSanityCheck[]; extern unsigned long SysPrvMask[]; extern ACCOUNTING_STRUCT *AccountingPtr; extern CONFIG_STRUCT Config; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* */ DavCopyBegin (REQUEST_STRUCT *rqptr) { int status; WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyBegin()"); tkptr = rqptr->WebDavTaskPtr; cpyptr = &tkptr->CopyData; 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, "COPY !AZ to !AZ overwrite:!&B depth:!UL path:!AZ", rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, tkptr->CopyData.MoveOverwrite, tkptr->ToDepth, DavWebPathAccess(rqptr)); if (strsame (rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName, -1)) { /* caseless compare because can't copy to the same underlying name! */ DavWebResponse (rqptr, 403, 0, "same underlying file name", FI_LI); DavWebEnd (rqptr); return; } if (rqptr->ParseOds.NamNameLength || rqptr->ParseOds.NamTypeLength) { /* copying a file */ if (tkptr->DestOds.NamNameLength || tkptr->DestOds.NamTypeLength) { /* to a file */ DavCopyFile (rqptr); return; } DavWebResponse (rqptr, 400, 0, "file to directory", FI_LI); } else { /* copying a directory */ if (!tkptr->DestOds.NamNameLength && !tkptr->DestOds.NamTypeLength) { /* to a directory */ DavCopyDirectory (rqptr); return; } DavWebResponse (rqptr, 400, 0, "directory to file", FI_LI); } /* file to a directory or directory to a file specification! */ DavWebEnd (rqptr); } /*****************************************************************************/ /* */ DavCopyEnd (WEBDAV_COPY *cpyptr) { int status; REQUEST_STRUCT *rqptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyEnd()"); tkptr = rqptr->WebDavTaskPtr; if (cpyptr->CopyingDir) if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPIED dirs:!UL fail:!UL files:!UL fail:!UL meta:!UL fail:!UL", cpyptr->DirCount, cpyptr->DirFailCount, cpyptr->FileCount, cpyptr->FileFailCount, cpyptr->MetaCount, cpyptr->MetaFailCount); if (rqptr->rqResponse.HttpStatus == 207) FaoToNet (rqptr, "\n"); if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_MOVE) { /* move using copy */ DavMoveEnd (rqptr); return; } if (!rqptr->rqResponse.HttpStatus) { /* in the absence of any other status */ if (tkptr->OverwriteOccurred) DavWebResponse (rqptr, 204, 0, "success, overwrite", FI_LI); else { DavWebHref (rqptr, tkptr->DestOds.ExpFileName, 0); DavWebResponse201 (rqptr); } } DavWebEnd (rqptr); } /*****************************************************************************/ /* Copy a single file (depth:0). */ DavCopyFile (REQUEST_STRUCT *rqptr) { int status; WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyFile()"); tkptr = rqptr->WebDavTaskPtr; cpyptr = &tkptr->CopyData; cpyptr->RequestPtr = rqptr; if (!cpyptr->MoveOverwrite) { sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (tkptr->DestOds.ExpFileName, NULL); sys$setprv (0, &SysPrvMask, 0, 0); if (VMSok(status)) { DavWebResponse (rqptr, 412, 0, "target file exists, no overwrite", FI_LI); DavCopyEnd (cpyptr); return; } } DavCopyFile2 (cpyptr); } /*****************************************************************************/ /* Test if the source or destination are locked and continue copy if not. This function will be called multiple times as asynchronous testing of the DLM and meta locking occurs. */ DavCopyFile2 (WEBDAV_COPY *cpyptr) { int status; REQUEST_STRUCT *rqptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyFile2() !UL", tkptr->TestLockState); /***********/ /* locking */ /***********/ /* if it's a move then locking has already been processed */ if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_MOVE) tkptr->TestLockState = 999; 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, DavCopyFile2, cpyptr); 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); DavCopyEnd (cpyptr); return; } /* establish a request (overall) VMS DLM lock on destination */ tkptr->TestLockState++; DavWebDlmEnqueue (rqptr, &tkptr->DlmDestin, #if TEST_DEADLOCK_DETECT rqptr->ParseOds.ExpFileName, NULL, #else tkptr->DestOds.ExpFileName, NULL, #endif true, false, DavCopyFile2, cpyptr); 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); DavCopyEnd (cpyptr); return; } /* check for meta-lock on existing source */ tkptr->TestLockState++; DavLockTest (rqptr, rqptr->ParseOds.ExpFileName, false, DavCopyFile2, cpyptr); return; case 3 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "source locked", FI_LI); DavCopyEnd (cpyptr); return; } /* check for meta-lock on existing destination */ tkptr->TestLockState++; DavLockTest (rqptr, tkptr->DestOds.ExpFileName, false, DavCopyFile2, cpyptr); return; case 4 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "destination locked", FI_LI); DavCopyEnd (cpyptr); return; } } /**************/ /* not locked */ /**************/ StrDscText (rqptr, &cpyptr->ReadNameDsc, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength); StrDscText (rqptr, &cpyptr->WriteNameDsc, tkptr->DestOds.ExpFileName, tkptr->DestOds.ExpFileNameLength); cpyptr->ReadOdsPtr = (ODS_STRUCT*)VmGetHeap (rqptr, sizeof(ODS_STRUCT)); OdsStructInit (cpyptr->ReadOdsPtr, false); cpyptr->WriteOdsPtr = (ODS_STRUCT*)VmGetHeap (rqptr, sizeof(ODS_STRUCT)); OdsStructInit (cpyptr->WriteOdsPtr, false); DavCopyReadOpen (cpyptr); } /*****************************************************************************/ /* Copy a directory tree (depth:infinity). */ DavCopyDirectory (REQUEST_STRUCT *rqptr) { int status; WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyDirectory()"); tkptr = rqptr->WebDavTaskPtr; cpyptr = &tkptr->CopyData; cpyptr->RequestPtr = rqptr; if (tkptr->ToDepth != WEBDAV_DEPTH_ZERO && tkptr->ToDepth != WEBDAV_DEPTH_INFINITY) { DavWebResponse (rqptr, 400, 0, "inappropriate depth", FI_LI); DavCopyEnd (cpyptr); return; } if (cpyptr->MoveOverwrite) { sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (tkptr->DestOds.ExpFileName, "*.*"); sys$setprv (0, &SysPrvMask, 0, 0); if (status != RMS$_FNF && status != RMS$_DNF) { /* not completely accurate but will do in the interim */ DavWebResponse (rqptr, 409, 0, "directory COPY does not support overwrite", FI_LI); DavCopyEnd (cpyptr); return; } } else { sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (tkptr->DestOds.ExpFileName, NULL); sys$setprv (0, &SysPrvMask, 0, 0); if (VMSok(status)) { DavWebResponse (rqptr, 412, 0, "target directory exists, overwrite not requested", FI_LI); DavCopyEnd (cpyptr); return; } } if (VMSnok (DavWebParentExists (NULL, tkptr->DestOds.ExpFileName))) { DavWebResponse (rqptr, 412, 0, "parent does not exist", FI_LI); DavCopyEnd (rqptr); return; } DavCopyDirectory2 (rqptr); } /*****************************************************************************/ /* Test if the source or destination are locked and continue copy if not. This function will be called multiple times as asynchronous testing of the DLM and meta locking occurs. */ DavCopyDirectory2 (REQUEST_STRUCT *rqptr) { int status, ParentNameLength; char *cptr, *sptr, *zptr; char ParentName [ODS_MAX_FILE_NAME_LENGTH+1]; WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyDirectory2() !UL", tkptr->TestLockState); cpyptr = &tkptr->CopyData; /***********/ /* locking */ /***********/ /* if it's a move then locking has already been processed */ if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_MOVE) tkptr->TestLockState = 999; 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, DavCopyDirectory2, 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); DavCopyEnd (cpyptr); return; } /* establish a request (overall) VMS DLM lock on destination */ tkptr->TestLockState++; DavWebDlmEnqueue (rqptr, &tkptr->DlmDestin, #if TEST_DEADLOCK_DETECT rqptr->ParseOds.ExpFileName, NULL, #else tkptr->DestOds.ExpFileName, NULL, #endif true, false, DavCopyDirectory2, 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); DavCopyEnd (cpyptr); return; } /* check for meta-lock on existing source */ tkptr->TestLockState++; DavLockTest (rqptr, rqptr->ParseOds.ExpFileName, false, DavCopyDirectory2, rqptr); return; case 3 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "source locked", FI_LI); DavCopyEnd (cpyptr); return; } /* check for meta-lock on existing destination */ tkptr->TestLockState++; DavLockTest (rqptr, tkptr->DestOds.ExpFileName, false, DavCopyDirectory2, rqptr); return; case 4 : if (VMSnok (tkptr->TestLockStatus)) { DavWebResponse (rqptr, 423, 0, "destination locked", FI_LI); DavCopyEnd (cpyptr); return; } /* now ready to copy */ } /**************/ /* not locked */ /**************/ OdsNameOfDirectoryFile (tkptr->DestOds.ExpFileName, tkptr->DestOds.ExpFileNameLength, ParentName, &ParentNameLength); sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (ParentName, NULL); sys$setprv (0, &SysPrvMask, 0, 0); if (status == RMS$_DNF) { /* parent or other ascendent directory does not exist */ DavWebResponse (rqptr, 409, status, "parent", FI_LI); DavCopyEnd (cpyptr); return; } /******************************/ /* create top-level directory */ /******************************/ status = DavWebCreateDir (rqptr, tkptr->DestOds.ExpFileName, tkptr->DestOds.ExpFileNameLength); if (VMSok(status)) cpyptr->DirCount++; else { cpyptr->DirFailCount++; DavWebResponse (rqptr, 0, status, NULL, FI_LI); DavCopyEnd (cpyptr); return; } if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) { /* depth of zero essentially only creates the directory */ DavWebHref (rqptr, tkptr->DestOds.ExpFileName, 0); DavWebResponse201 (rqptr); DavCopyEnd (cpyptr); return; } /***********************/ /* directory tree spec */ /***********************/ cpyptr->CopyingDir = true; zptr = (sptr = tkptr->SearchSpec) + sizeof(tkptr->SearchSpec)-1; for (cptr = rqptr->ParseOds.NamDevicePtr; cptr < rqptr->ParseOds.NamNamePtr-1 && sptr < zptr; *sptr++ = *cptr++); for (cptr = "...]*.*;"; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr >= zptr) { ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI); DavWebResponse (rqptr, 0, SS$_BUGCHECK, NULL, FI_LI); return; } tkptr->SearchSpecLength = sptr - tkptr->SearchSpec; *sptr = '\0'; /* suitable to search against (i.e. no NAM$_SYNCHK) */ OdsStructInit (&tkptr->SearchOds, false); OdsParse (&tkptr->SearchOds, tkptr->SearchSpec, tkptr->SearchSpecLength, NULL, 0, 0, NULL, 0); if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { ErrorNoticed (rqptr, status, NULL, FI_LI); DavWebResponse (rqptr, 500, status, NULL, FI_LI); return; } /****************/ /* some storage */ /****************/ StrDscText (rqptr, &cpyptr->ReadNameDsc, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength); StrDscText (rqptr, &cpyptr->WriteNameDsc, tkptr->DestOds.ExpFileName, tkptr->DestOds.ExpFileNameLength); cpyptr->ReadOdsPtr = (ODS_STRUCT*)VmGetHeap (rqptr, sizeof(ODS_STRUCT)); OdsStructInit (cpyptr->ReadOdsPtr, false); cpyptr->WriteOdsPtr = (ODS_STRUCT*)VmGetHeap (rqptr, sizeof(ODS_STRUCT)); OdsStructInit (cpyptr->WriteOdsPtr, false); DavCopyNext (cpyptr); } /*****************************************************************************/ /* This function is a common target from the file copy functions when the copy fails or completes. If a single file copy it just calls DavCopyEnd() and that's that! For a directory (tree) copy, a search for the next file is performed which ASTs to DavCopyNextAst(). */ DavCopyNext (WEBDAV_COPY *cpyptr) { REQUEST_STRUCT *rqptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyNext()"); tkptr = rqptr->WebDavTaskPtr; if (!cpyptr->CopyingDir) { /* no next if we're copying the one file (depth:0) */ if (cpyptr->CopyingMeta) DavCopyEnd (cpyptr); else DavCopyMeta (rqptr, rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); return; } AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsSearch (&tkptr->SearchOds, &DavCopyNextAst, cpyptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* Directry (tree) copy search has completed. If no more files are found then it's the end of the tree copy. Otherwise initiate the copy of this file. */ DavCopyNextAst (WEBDAV_COPY *cpyptr) { BOOL IsDirectory; int status, FileNameLength; char *cptr, *sptr, *zptr; char DirName [ODS_MAX_FILE_NAME_LENGTH+1], FileName [ODS_MAX_FILE_NAME_LENGTH+1], FromDirName [ODS_MAX_FILE_NAME_LENGTH+1]; STR_DSC_AUTO (FromDsc); STR_DSC_AUTO (ToDsc); REQUEST_STRUCT *rqptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyNextAst() sts:!&S stv:!&S", tkptr->SearchOds.Fab.fab$l_sts, tkptr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DavCopyEnd (cpyptr); return; } if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { if (status == RMS$_NMF || status == RMS$_FNF) { cpyptr->VmsStatus = SS$_NORMAL; if (!cpyptr->CopyingMeta) { DavCopyMeta (rqptr, rqptr->ParseOds.ExpFileName, tkptr->DestOds.ExpFileName); return; } } else cpyptr->VmsStatus = status; DavCopyEnd (cpyptr); return; } IsDirectory = false; if (tkptr->SearchOds.NamTypeLength == 4 && (MATCH5 (tkptr->SearchOds.NamTypePtr, ".DIR;") || MATCH5 (tkptr->SearchOds.NamTypePtr, ".dir;"))) { status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSok(status)) IsDirectory = true; } if (IsDirectory) { /*************/ /* directory */ /*************/ /* derived from the original plus the descendent tree */ zptr = (sptr = DirName) + sizeof(DirName)-1; for (cptr = tkptr->DestOds.ExpFileName; *cptr && sptr < zptr; *sptr++ = *cptr++); /* eliminate the trailing ']' */ sptr--; if (sptr < zptr) *sptr++ = '.'; /* append (any) descendent tree from the search results */ cptr = tkptr->SearchOds.ResFileName + rqptr->ParseOds.ExpFileNameLength - 1; while (cptr < tkptr->SearchOds.NamTypePtr && sptr < zptr) { if (*cptr == ']') *sptr++ = '.'; else *sptr++ = *cptr; cptr++; } if (sptr < zptr) *sptr++ = ']'; if (sptr >= zptr) { ErrorNoticed (rqptr, SS$_RESULTOVF, NULL, FI_LI); DavCopyEnd (cpyptr); return; } *sptr = '\0'; status = DavWebCreateDir (rqptr, DirName, sptr-DirName); if (VMSok(status)) cpyptr->DirCount++; else { cpyptr->DirFailCount++; DavWebMultiStatus (rqptr, status, DirName); } DavCopyNext (cpyptr); return; } /***************************/ /* source and target names */ /***************************/ /* the source file name comes directly from the search results */ StrDscText (rqptr, &cpyptr->ReadNameDsc, tkptr->SearchOds.ResFileName, tkptr->SearchOds.ResFileNameLength); /* the target name is derived from the original plus the descendent tree */ zptr = (sptr = FileName) + ODS_MAX_FILE_NAME_LENGTH; for (cptr = tkptr->DestOds.ExpFileName; *cptr && sptr < zptr; *sptr++ = *cptr++); /* eliminate the trailing ']' */ sptr--; /* append (any) descendent tree from the search results */ for (cptr = tkptr->SearchOds.ResFileName + rqptr->ParseOds.ExpFileNameLength - 2; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr >= zptr) { ErrorNoticed (rqptr, SS$_RESULTOVF, NULL, FI_LI); DavCopyEnd (cpyptr); return; } *sptr = '\0'; FileNameLength = sptr - FileName; StrDscText (rqptr, &cpyptr->WriteNameDsc, FileName, FileNameLength); DavCopyReadOpen (cpyptr); } /*****************************************************************************/ /* Open the source file. */ DavCopyReadOpen (WEBDAV_COPY *cpyptr) { int status; REQUEST_STRUCT *rqptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyReadOpen()"); AuthAccessEnable (rqptr, STR_DSC_PTR(&cpyptr->ReadNameDsc), AUTH_ACCESS_READ); OdsOpen (cpyptr->ReadOdsPtr, &cpyptr->ReadNameDsc, -1, NULL, 0, FAB$M_GET + FAB$M_BIO, 0, FAB$M_SHRGET, DavCopyReadOpenAst, cpyptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST from source file open. Check status and abandon copy if it failed. If successful connect a RAB and attempt to create the target file. */ DavCopyReadOpenAst (WEBDAV_COPY *cpyptr) { int status; REQUEST_STRUCT *rqptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyReadOpenAst() !&S", cpyptr->ReadOdsPtr->Fab.fab$l_sts); cpyptr->VmsStatus = status = cpyptr->ReadOdsPtr->Fab.fab$l_sts; if (VMSnok (status)) { if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPY read open !AZ !&S", STR_DSC_PTR(&cpyptr->ReadNameDsc), status); if (!cpyptr->CopyingMeta) { cpyptr->FileFailCount++; if (VMSnok (status)) DavWebMultiStatus (rqptr, status, STR_DSC_PTR(&cpyptr->ReadNameDsc)); } DavCopyNext (cpyptr); return; } cpyptr->ReadOdsPtr->Rab = cc$rms_rab; cpyptr->ReadOdsPtr->Rab.rab$l_ctx = cpyptr; cpyptr->ReadOdsPtr->Rab.rab$l_fab = &cpyptr->ReadOdsPtr->Fab; status = sys$connect (&cpyptr->ReadOdsPtr->Rab, 0, 0); if (VMSnok (status)) { cpyptr->VmsStatus = status; OdsClose (cpyptr->ReadOdsPtr, NULL, NULL); DavCopyNext (cpyptr); return; } if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!&Z", STR_DSC_PTR(&cpyptr->WriteNameDsc)); AuthAccessEnable (rqptr, STR_DSC_PTR(&cpyptr->WriteNameDsc), AUTH_ACCESS_WRITE); OdsCreate (cpyptr->WriteOdsPtr, &cpyptr->WriteNameDsc, -1, NULL, 0, FAB$M_PUT + FAB$M_GET + FAB$M_BIO, FAB$M_CIF, FAB$M_NIL, 0, 0, &cpyptr->ReadOdsPtr->Fab, DavCopyWriteOpenAst, cpyptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST from target file create. Check status and abandon copy if it failed. If successful connect a RAB and populate the RABs ready for an asynchronous set of reads and writes. */ DavCopyWriteOpenAst (WEBDAV_COPY *cpyptr) { int status; ODS_STRUCT *rodsptr, *wodsptr; REQUEST_STRUCT *rqptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyWriteOpenAst() !&S", cpyptr->WriteOdsPtr->Fab.fab$l_sts); tkptr = rqptr->WebDavTaskPtr; rodsptr = cpyptr->ReadOdsPtr; wodsptr = cpyptr->WriteOdsPtr; cpyptr->VmsStatus = status = wodsptr->Fab.fab$l_sts; if (VMSnok (status)) { if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPY write open !AZ !&S", STR_DSC_PTR(&cpyptr->WriteNameDsc), status); cpyptr->FileFailCount++; if (VMSnok (status)) DavWebMultiStatus (rqptr, status, STR_DSC_PTR(&cpyptr->WriteNameDsc)); OdsClose (rodsptr, NULL, NULL); DavCopyNext (cpyptr); return; } if (cpyptr->VmsStatus != RMS$_CREATED) tkptr->OverwriteOccurred = true; /* unless the copy completes successfully */ wodsptr->DeleteOnClose = true; wodsptr->Rab = cc$rms_rab; wodsptr->Rab.rab$l_ctx = cpyptr; wodsptr->Rab.rab$l_fab = &wodsptr->Fab; status = sys$connect (&wodsptr->Rab, 0, 0); if (VMSnok (status)) { cpyptr->VmsStatus = status; /* ensure delete-on-close (if required) */ AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsClose (rodsptr, NULL, NULL); OdsClose (wodsptr, NULL, NULL); AuthAccessEnable (rqptr, 0, 0); DavCopyNext (cpyptr); return; } /* maximise block buffer size against file size */ if (rodsptr->XabFhc.xab$l_ebk < 127) cpyptr->BucketSize = rodsptr->XabFhc.xab$l_ebk; else cpyptr->BucketSize = 127; cpyptr->DataSize = cpyptr->BucketSize * 512; cpyptr->DataPtr = VmGetHeap (rqptr, cpyptr->DataSize); /* set up read RAB */ rodsptr->Rab.rab$l_ctx = cpyptr; rodsptr->Rab.rab$l_rop = RAB$M_BIO | RAB$M_ASY; rodsptr->Rab.rab$l_ubf = cpyptr->DataPtr; rodsptr->Rab.rab$w_usz = cpyptr->DataSize; rodsptr->Rab.rab$l_bkt = 1; /* set up write RAB */ wodsptr->Rab.rab$l_ctx = cpyptr; wodsptr->Rab.rab$l_rop = RAB$M_BIO | RAB$M_ASY; sys$read (&rodsptr->Rab, &DavCopyReadAst, &DavCopyReadAst); } /*****************************************************************************/ /* AST from source read. Check status and abandon copy if it failed. If successful write the just-read buffer. */ DavCopyReadAst (struct RAB *RabPtr) { BOOL IsMetaFile; int status; char *cptr; ODS_STRUCT *rodsptr, *wodsptr; REQUEST_STRUCT *rqptr; STR_DSC_AUTO (FromDsc); STR_DSC_AUTO (ToDsc); WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ cpyptr = RabPtr->rab$l_ctx; rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyReadAst() read: !&S !UL write: !&S !UL", cpyptr->ReadOdsPtr->Rab.rab$l_sts, cpyptr->ReadOdsPtr->Rab.rab$w_rsz, cpyptr->WriteOdsPtr->Rab.rab$l_sts, cpyptr->WriteOdsPtr->Rab.rab$w_rsz); tkptr = rqptr->WebDavTaskPtr; rodsptr = cpyptr->ReadOdsPtr; wodsptr = cpyptr->WriteOdsPtr; status = rodsptr->Rab.rab$l_sts; if (VMSnok (status)) { if (status == RMS$_EOF) { /* successful copy */ if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPIED !AZ", STR_DSC_PTR(&cpyptr->ReadNameDsc)); /* delete original if moving using copy */ if (rqptr->rqHeader.Method == HTTP_METHOD_WEBDAV_MOVE) rodsptr->DeleteOnClose = true; /* undo delete unless successful */ wodsptr->DeleteOnClose = false; cpyptr->VmsStatus = status = SS$_NORMAL; } else cpyptr->VmsStatus = status; /* only need this expense when WATCHing */ if (WATCHING (rqptr, WATCH_WEBDAV)) { IsMetaFile = DavMetaFile (cpyptr->ReadOdsPtr); if (VMSok(status)) if (IsMetaFile) cpyptr->MetaCount++; else cpyptr->FileCount++; else if (IsMetaFile) cpyptr->MetaFailCount++; else cpyptr->FileFailCount++; } if (VMSnok (status)) { if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPY read !AZ !&S", STR_DSC_PTR(&cpyptr->ReadNameDsc), status); DavWebMultiStatus (rqptr, status, STR_DSC_PTR(&cpyptr->ReadNameDsc)); } /* ensure delete-on-close (if required) */ AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsClose (rodsptr, NULL, NULL); OdsClose (wodsptr, NULL, NULL); AuthAccessEnable (rqptr, 0, 0); DavCopyNext (cpyptr); return; } wodsptr->Rab.rab$l_rbf = rodsptr->Rab.rab$l_ubf; wodsptr->Rab.rab$w_rsz = rodsptr->Rab.rab$w_rsz; wodsptr->Rab.rab$l_bkt = rodsptr->Rab.rab$l_bkt; sys$write (&wodsptr->Rab, &DavCopyWriteAst, &DavCopyWriteAst); } /*****************************************************************************/ /* AST from target write. Check status and abandon copy if it failed. If successful queue another source read. */ DavCopyWriteAst (struct RAB *RabPtr) { int status; ODS_STRUCT *rodsptr, *wodsptr; REQUEST_STRUCT *rqptr; WEBDAV_COPY *cpyptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ cpyptr = RabPtr->rab$l_ctx; rqptr = cpyptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyWriteAst() !&S !UL", cpyptr->WriteOdsPtr->Rab.rab$l_sts, cpyptr->WriteOdsPtr->Rab.rab$w_rsz); tkptr = rqptr->WebDavTaskPtr; rodsptr = cpyptr->ReadOdsPtr; wodsptr = cpyptr->WriteOdsPtr; status = wodsptr->Rab.rab$l_sts; if (VMSnok (status)) { cpyptr->VmsStatus = status; cpyptr->FileFailCount++; if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "COPY write !AZ !&S", STR_DSC_PTR(&cpyptr->WriteNameDsc), status); DavWebMultiStatus (rqptr, cpyptr->VmsStatus, STR_DSC_PTR(&cpyptr->WriteNameDsc)); /* ensure delete-on-close (if required) */ AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsClose (rodsptr, NULL, NULL); OdsClose (wodsptr, NULL, NULL); AuthAccessEnable (rqptr, 0, 0); DavCopyNext (cpyptr); return; } rodsptr->Rab.rab$l_bkt += cpyptr->BucketSize; sys$read (&rodsptr->Rab, &DavCopyReadAst, &DavCopyReadAst); } /*****************************************************************************/ /* Copy any meta file associated with the source to the destination. Assumes everything's locked by the calling routine. */ DavCopyMeta ( REQUEST_STRUCT *rqptr, char *SrcFileName, char *DstFileName ) { int status; WEBDAV_COPY *cpyptr; WEBDAV_META *mtaptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavCopyMeta() !AZ !AZ", SrcFileName, DstFileName); cpyptr = &tkptr->CopyData; cpyptr->CopyingMeta = true; mtaptr = &tkptr->MetaData; mtaptr->TaskPtr = rqptr->WebDavTaskPtr; DavMetaName (mtaptr, SrcFileName, 'r'); DavMetaName (mtaptr, DstFileName, 'w'); StrDscText (rqptr, &cpyptr->ReadNameDsc, mtaptr->ReadMetaName, mtaptr->ReadMetaNameLength); StrDscText (rqptr, &cpyptr->WriteNameDsc, mtaptr->WriteMetaName, mtaptr->WriteMetaNameLength); DavMetaCreateDir (mtaptr); DavCopyReadOpen (cpyptr); } /*****************************************************************************/