[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430] [0431] [0432] [0433] [0434] [0435] [0436] [0437] [0438] [0439] [0440] [0441] [0442] [0443] [0444] [0445] [0446] [0447] [0448] [0449] [0450] [0451] [0452] [0453] [0454] [0455] [0456] [0457] [0458] [0459] [0460] [0461] [0462] [0463] [0464] [0465] [0466] [0467] [0468] [0469] [0470] [0471] [0472] [0473] [0474] [0475] [0476] [0477] [0478] [0479] [0480] [0481] [0482] [0483] [0484] [0485] [0486] [0487] [0488] [0489] [0490] [0491] [0492] [0493] [0494] [0495] [0496] [0497] [0498] [0499] [0500] [0501] [0502] [0503] [0504] [0505] [0506] [0507] [0508] [0509] [0510] [0511] [0512] [0513] [0514] [0515] [0516] [0517] [0518] [0519] [0520] [0521] [0522] [0523] [0524] [0525] [0526] [0527] [0528] [0529] [0530] [0531] [0532] [0533] [0534] [0535] [0536] [0537] [0538] [0539] [0540] [0541] [0542] [0543] [0544] [0545] [0546] [0547] [0548] [0549] [0550] [0551] [0552] [0553] [0554] [0555] [0556] [0557] [0558] [0559] [0560] [0561] [0562] [0563] [0564] [0565] [0566] [0567] [0568] [0569] [0570] [0571] [0572] [0573] [0574] [0575] [0576] [0577] [0578] [0579] [0580] [0581] [0582] [0583] [0584] [0585] [0586] [0587] [0588] [0589] [0590] [0591] [0592] [0593] [0594] [0595] [0596] [0597] [0598] [0599] [0600] [0601] [0602] [0603] [0604] [0605] [0606] [0607] [0608] [0609] [0610] [0611] [0612] [0613] [0614] [0615] [0616] [0617] [0618] [0619] [0620] [0621] [0622] [0623] [0624] [0625] [0626] [0627] [0628] [0629] [0630] [0631] [0632] [0633] [0634] [0635] [0636] [0637] [0638] [0639] [0640] [0641] [0642] [0643] [0644] [0645] [0646] [0647] [0648] [0649] [0650] [0651] [0652] [0653] [0654] [0655] [0656] [0657] [0658] [0659] [0660] [0661] [0662] [0663] [0664] [0665] [0666] [0667] [0668] [0669] [0670] [0671] [0672] [0673] [0674] [0675] [0676] [0677] [0678] [0679] [0680] [0681] [0682] [0683] [0684] [0685] [0686] [0687] [0688] [0689] [0690] [0691] [0692] [0693] [0694] [0695] [0696] [0697] [0698] [0699] [0700] [0701] [0702] [0703] [0704] [0705] [0706] [0707] [0708] [0709] [0710] [0711] [0712] [0713] [0714] [0715] [0716] [0717] [0718] [0719] [0720] [0721] [0722] [0723] [0724] [0725] [0726] [0727] [0728] [0729] [0730] [0731] [0732] [0733] [0734] [0735] [0736] [0737] [0738] [0739] [0740] [0741] [0742] [0743] [0744] [0745] [0746] [0747] [0748] [0749] [0750] [0751] [0752] [0753] [0754] [0755] [0756] [0757] [0758] [0759] [0760] [0761] [0762] [0763] [0764] [0765] [0766] [0767] [0768] [0769] [0770] [0771] [0772] [0773] [0774] [0775] [0776] [0777] [0778] [0779] [0780] [0781] [0782] [0783] [0784] [0785] [0786] [0787] [0788] [0789] [0790] [0791] [0792] [0793] [0794] [0795] [0796] [0797] [0798] [0799] [0800] [0801] [0802] [0803] [0804] [0805] [0806] [0807] [0808] [0809] [0810] [0811] [0812] [0813] [0814] [0815] [0816] [0817] [0818] [0819] [0820] [0821] [0822] [0823] [0824] [0825] [0826] [0827] [0828] [0829] [0830] [0831] [0832] [0833] [0834] [0835] [0836] [0837] [0838] [0839] [0840] [0841] [0842] [0843] [0844] [0845] [0846] [0847] [0848] [0849] [0850] [0851] [0852] [0853] [0854] [0855] [0856] [0857] [0858] [0859] [0860] [0861] [0862] [0863] [0864] [0865] [0866] [0867] [0868] [0869] [0870] [0871] [0872] [0873] [0874] [0875] [0876] [0877] [0878] [0879] [0880] [0881] [0882] [0883] [0884] [0885] [0886] [0887] [0888] [0889] [0890] [0891] [0892] [0893] [0894] [0895] [0896] [0897] [0898] [0899] [0900] [0901] [0902] [0903] [0904] [0905] [0906] [0907] [0908] [0909] [0910] [0911] [0912] [0913] [0914] [0915] [0916] [0917] [0918] [0919] [0920] [0921] [0922] [0923] [0924] [0925] [0926] [0927] [0928] [0929] [0930] [0931] [0932] [0933] [0934] [0935] [0936] [0937] [0938] [0939] [0940] [0941] [0942] [0943] [0944] [0945] [0946] [0947] [0948] [0949] [0950] [0951] [0952] [0953] [0954] [0955] [0956] [0957] [0958] [0959] [0960] [0961] [0962] [0963] [0964] [0965] [0966] [0967] [0968] [0969] [0970] [0971] [0972] [0973] [0974] [0975] [0976] [0977] [0978] [0979] [0980] [0981] [0982] [0983] [0984] [0985] [0986] [0987] [0988] [0989] [0990] [0991] [0992] [0993] [0994] [0995] [0996] [0997] [0998] [0999] [1000] [1001] [1002] [1003] [1004] [1005] [1006] [1007] [1008] [1009] [1010] [1011] [1012] [1013] [1014] [1015] [1016] [1017] [1018] [1019] [1020] [1021] [1022] [1023] [1024] [1025] [1026] [1027] [1028] [1029] [1030] [1031] [1032] [1033] [1034] [1035] [1036] [1037] [1038] [1039] [1040] [1041] [1042] [1043] [1044] [1045] [1046] [1047] [1048] [1049] [1050] [1051] [1052] [1053] [1054] [1055] [1056] [1057] [1058] [1059] [1060] [1061] [1062] [1063] [1064] [1065] [1066] [1067] [1068] [1069] [1070] [1071] [1072] [1073] [1074] [1075] [1076] [1077] [1078] [1079] [1080] [1081] [1082] [1083] [1084] [1085] [1086] [1087] [1088] [1089] [1090] [1091] [1092] [1093] [1094] [1095] [1096] [1097] [1098] [1099] [1100] [1101] [1102] [1103] [1104] [1105] [1106] [1107] [1108] [1109] [1110] [1111] [1112] [1113] [1114] [1115] [1116] [1117] [1118] [1119] [1120] [1121] [1122] [1123] [1124] [1125] [1126] [1127] [1128] [1129] [1130] [1131] [1132] [1133] [1134] [1135] [1136] [1137] [1138] [1139] [1140] [1141] [1142] [1143] [1144] [1145] [1146] [1147] [1148] [1149] [1150] [1151] [1152] [1153] [1154] [1155] [1156] [1157] [1158] [1159] [1160] [1161] [1162] [1163] [1164] [1165] [1166] [1167] [1168] [1169] [1170] [1171] [1172] [1173] [1174] [1175] [1176] [1177] [1178] [1179] [1180] [1181] [1182] [1183] [1184] [1185] [1186] [1187] [1188] [1189] [1190] [1191] [1192] [1193] [1194] [1195] [1196] [1197] [1198] [1199] [1200] [1201] [1202] [1203] [1204] [1205] [1206] [1207] [1208] [1209] [1210] [1211] [1212] [1213] [1214] [1215] [1216] [1217] [1218] [1219] [1220] [1221] [1222] [1223] [1224] [1225] [1226] [1227] [1228] [1229] [1230] [1231] [1232] [1233] [1234] [1235] [1236] [1237] [1238] [1239] [1240] [1241] [1242] [1243] [1244] [1245] [1246] [1247] [1248] [1249] [1250] [1251] [1252] [1253] [1254] [1255] [1256] [1257] [1258] [1259] [1260] [1261] [1262] [1263] [1264] [1265] [1266] [1267] [1268] [1269] [1270] [1271] [1272] [1273] [1274] [1275] [1276] [1277] [1278] [1279] [1280] [1281] [1282] [1283] [1284] [1285] [1286] [1287] [1288] [1289] [1290] [1291] [1292] [1293] [1294] [1295] [1296] [1297] [1298] [1299] [1300] [1301] [1302] [1303] [1304] [1305] [1306] [1307] [1308] [1309] [1310] [1311] [1312] [1313] [1314] [1315] [1316] [1317] [1318] [1319] [1320] [1321] [1322] [1323] [1324] [1325] [1326] [1327] [1328] [1329] [1330] [1331] [1332] [1333] [1334] [1335] [1336] [1337] [1338] [1339] [1340] [1341] [1342] [1343] [1344] [1345] [1346] [1347] [1348] [1349] [1350] [1351] [1352] [1353] [1354] [1355] [1356] [1357] [1358] [1359] [1360] [1361] [1362] [1363] [1364] [1365] [1366] [1367] [1368] [1369] [1370] [1371] [1372] [1373] [1374] [1375] [1376] [1377] [1378] [1379] [1380] [1381] [1382] [1383] [1384] [1385] [1386] [1387] [1388] [1389] [1390] [1391] [1392] [1393] [1394] [1395] [1396] [1397] [1398] [1399] [1400] [1401] [1402] [1403] [1404] [1405] [1406] [1407] [1408] [1409] [1410] [1411] [1412] [1413] [1414] [1415] [1416] [1417] [1418] [1419] [1420] [1421] [1422] [1423] [1424] [1425] [1426] [1427] [1428] [1429] [1430] [1431] [1432] [1433] [1434] [1435] [1436] [1437] [1438] [1439] [1440] [1441] [1442] [1443] [1444] [1445] [1446] [1447] [1448] [1449] [1450] [1451] [1452] [1453] [1454] [1455] [1456] [1457] [1458] [1459] [1460] [1461] [1462] [1463] [1464] [1465] [1466] [1467] [1468] [1469] [1470] [1471] [1472] [1473] [1474] [1475] [1476] [1477] [1478] [1479] [1480] [1481] [1482] [1483] [1484] [1485] [1486] [1487] [1488] [1489] [1490] [1491] [1492] [1493] [1494] [1495] [1496] [1497] [1498] [1499] [1500] [1501] [1502] [1503] [1504] [1505] [1506] [1507] [1508] [1509] [1510] [1511] [1512] [1513] [1514] [1515] [1516] [1517] [1518] [1519] [1520] [1521] [1522] [1523] [1524] [1525] [1526] [1527] [1528] [1529] [1530] [1531] [1532] [1533] [1534] [1535] [1536] [1537] [1538] [1539] [1540] [1541] [1542] [1543] [1544] [1545] [1546] [1547] [1548] [1549] [1550] [1551] [1552] [1553] [1554] [1555] [1556] [1557] [1558] [1559] [1560] [1561] [1562] [1563] [1564] [1565] [1566] [1567] [1568] [1569] [1570] [1571] [1572] [1573] [1574] [1575] [1576] [1577] [1578] [1579] [1580] [1581] [1582] [1583] [1584] [1585] [1586] [1587] [1588] [1589] [1590] [1591] [1592] [1593] [1594] [1595] [1596] [1597] [1598] [1599] [1600] [1601] [1602] [1603] [1604] [1605] [1606] [1607] [1608] [1609] [1610] [1611] [1612] [1613] [1614] [1615] [1616] [1617] [1618] [1619] [1620] [1621] [1622] [1623] [1624] [1625] [1626] [1627] [1628] [1629] [1630] [1631] [1632] [1633] [1634] [1635] [1636] [1637] [1638] [1639] [1640] [1641] [1642] [1643] [1644] [1645] [1646] [1647] [1648] [1649] [1650] [1651] [1652] [1653] [1654] [1655] [1656] [1657] [1658] [1659] [1660] [1661] [1662] [1663] [1664] [1665] [1666] [1667] [1668] [1669] [1670] [1671] [1672] [1673] [1674] [1675] [1676] [1677] [1678] [1679] [1680] [1681] [1682] [1683] [1684] [1685] [1686] [1687] [1688] [1689] [1690] [1691] [1692] [1693] [1694] [1695] [1696] [1697] [1698] [1699] [1700] [1701] [1702] [1703]
/*****************************************************************************/ /* DAVprop.c Provide DAV properties of collections (directories) and resources (files). These include 'live' properties (those stored as part of the file-system, e.g. CDT, RDT) and 'dead' properties (those provided by clients and stored as XML in the meta-data). Apparently <allprop/> is deprecated by RFC 4981. VERSION HISTORY --------------- 25-SEP-2020 MGD bugfix; DavPropBegin() WATCH report no reverse mapping 12-SEP-2018 MGD bugfix; significant refactor of locking 06-SEP-2018 MGD bugfix; DavPropLive() metadata file also needs to be read for ->LockDiscovery as well as ->AllProp and ->FindProp 15-APR-2018 MGD SS$_ABORT on ->RequestRundown bugfix; DavPropDead() flush the network buffer periodically (for rediculously but legally sized file it might not quickly enough to prevent no-progress timeout) bugfix; DavPropSearchAst() resultant name already terminated 22-JUN-2016 MGD DavPropSearchAst() ignore ambiguous file names containing an escaped ("^.") period but no type 27-SEP-2014 MGD improve "no reverse mapping" detection and reporting bugfix; DavPropEnd() ensure unused meta-data file deleted 16-JUN-2014 MGD DavPropSearchAst() meta file subdirectory detect and suppress 06-JUN-2013 MGD bugfix; DavPropSearchAst() on non-ODS_EXTENDED platforms (i.e. VAX) reset .nam$b_rsl to changed resultant length or it can generate RMS$_RSL errors - check it out! 05-SEP-2009 MGD refinements 24-JUN-2009 MGD DavPropQuota() RFC 4331 quota properties bugfix; DavPropName() XML 19-APR-2007 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 /* standard C header files */ #include <ctype.h> #include <errno.h> #include <stdio.h> #include <string.h> /* VMS related header files */ #include <atrdef.h> #include <descrip.h> #include <dvidef.h> #include <fibdef.h> #include <iodef.h> #include <libdtdef.h> #include <libdef.h> #include <rmsdef.h> #include <rms.h> #include <ssdef.h> #include <stsdef.h> #include <uaidef.h> /* application related header file */ #include "wasd.h" #include "davweb.h" #define WASD_MODULE "DAVPROP" #define FCH$M_DIRECTORY 0x2000 #define TEST_PROP_QUOTA 0 #define _TEST_PROP_QUOTA_USERNAME "DANIEL" /********************/ /* external storage */ /********************/ extern BOOL WebDavQuotaEnabled; extern char ErrorSanityCheck[]; extern int SysPrvMask[], ToLowerCase[], ToUpperCase[]; extern int EfnWait, EfnNoWait, HttpdTickSecond; extern ACCOUNTING_STRUCT *AccountingPtr; extern CONFIG_STRUCT Config; extern HTTPD_PROCESS HttpdProcess; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* This function should check for a mapping-generated error message to determine is there were any problems. */ DavPropBegin (REQUEST_STRUCT *rqptr) { int status, Length; char *sptr; char Scratch [ODS_MAX_FILE_NAME_LENGTH+1]; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropBegin() depth:!UL !&Z", rqptr->WebDavTaskPtr->ToDepth, rqptr->ParseOds.ExpFileName); tkptr = rqptr->WebDavTaskPtr; if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "PROPFIND!AZ !AZ depth:!UL path:!AZ", rqptr->rqPathSet.WebDavNoProp ? " (path set NOprop)" : "", rqptr->ParseOds.ExpFileName, tkptr->ToDepth, DavWebPathAccess(rqptr)); /* always flush before no-progress timeout (at 75%) */ tkptr->PropFindFlushAfter = Config.cfTimeout.NoProgress * 75 / 100; tkptr->PropFindFlushSecond = HttpdTickSecond + tkptr->PropFindFlushAfter; /* ensure a reverse mapping exists for the file specification */ Scratch[0] = '\0'; sptr = MapUrl_Map (Scratch, sizeof(Scratch), rqptr->ParseOds.NamDevicePtr, 0, NULL, 0, NULL, 0, NULL, 0, NULL, rqptr, NULL); if (!sptr[0] && sptr[1] || (MATCH8(sptr,MAPURL_NO_REVERSE_PATH) && strsame(sptr,MAPURL_NO_REVERSE_PATH,-1))) { if (WATCHING (rqptr, WATCH_WEBDAV)) { if (!sptr[0] && sptr[1]) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "REVERSE MAPPING !AZ error !AZ", rqptr->ParseOds.NamDevicePtr, sptr+1); else if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "NO REVERSE MAPPING from !AZ to URI", rqptr->ParseOds.NamDevicePtr); } rqptr->rqResponse.HttpStatus = 500; ErrorVmsStatus (rqptr, SS$_ABORT, FI_LI); DavPropEnd (rqptr); return; } /* default to reporting all properties */ if (!rqptr->rqHeader.ContentLength64) tkptr->PropData.AllProp = true; /* take out a concurrent read lock on the resource */ DavWebDlmEnqueue (rqptr, &tkptr->DlmSource, rqptr->ParseOds.ExpFileName, NULL, false, false, DavPropBegin2, rqptr); } /*****************************************************************************/ /* Entry point for AST from VMS DLM lock. */ DavPropBegin2 (REQUEST_STRUCT *rqptr) { int status; WEBDAV_DLM *dlmptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; dlmptr = &tkptr->DlmSource; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropBegin2() !&S", dlmptr->LockSb.lksb$w_status); if (VMSnok (dlmptr->LockSb.lksb$w_status)) { DavPropEnd (rqptr); return; } /* network writes are checked for success, fudge the first one! */ rqptr->NetIoPtr->WriteStatus = SS$_NORMAL; if (rqptr->ParseOds.NamNameLength > 0 || rqptr->ParseOds.NamTypeLength > 1) { /*******************/ /* single resource */ /*******************/ /* any other depth is meaningless */ tkptr->ToDepth = WEBDAV_DEPTH_ZERO; status = DavPropParse (rqptr); if (VMSnok(status)) { /* HTTP status will be set from VMS status */ ErrorVmsStatus (rqptr, status, FI_LI); DavPropEnd (rqptr); return; } if (tkptr->PropData.PropName) DavPropName (rqptr); else DavPropLiveAcp (rqptr); return; } /**************/ /* collection */ /**************/ if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) { /* collection itself */ DavPropParent (rqptr); return; } if (tkptr->ToDepth == WEBDAV_DEPTH_ONE) { /* collection and children, provide the parent */ DavPropParent (rqptr); return; } if (tkptr->ToDepth == WEBDAV_DEPTH_INFINITY) { /* potentially too expensive! */ DavWebResponse (rqptr, 501, 0, "Infinite depth too expensive", FI_LI); DavPropEnd (rqptr); return; } ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); } /*****************************************************************************/ /* As necessary, close the multistatus XML. */ DavPropEnd (REQUEST_STRUCT *rqptr) { int status; WEBDAV_META *mtaptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropEnd() !&F", &DavPropEnd); tkptr = rqptr->WebDavTaskPtr; mtaptr = &tkptr->MetaData; if (mtaptr->ReadOds.Fab.fab$l_sts == RMS$_CREATED && mtaptr->ReadOds.DeleteOnClose) { /* meta-data file created and never updated */ status = OdsClose (&mtaptr->ReadOds, NULL, NULL); if (VMSnok (status)) ErrorNoticed (rqptr, status, mtaptr->ReadMetaName, FI_LI); } /* if an 'empty' multistatus response was generated */ if (!rqptr->rqResponse.HttpStatus) { rqptr->rqResponse.NoGzip = true; DavWebResponse207 (rqptr); } if (rqptr->rqResponse.HttpStatus == 207) FaoToNet (rqptr, "</D:multistatus>\n"); DavWebEnd (rqptr); } /*****************************************************************************/ /* Get the file name of the directory containing this collection and begin to process to get it's WebDAV properties. */ DavPropParent (REQUEST_STRUCT *rqptr) { int status, DirectoryFileLength; char DirectoryFile [ODS_MAX_FILE_NAME_LENGTH+1]; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropParent() !AZ", rqptr->ParseOds.NamDevicePtr); tkptr = rqptr->WebDavTaskPtr; /* get name of directory in parent */ OdsNameOfDirectoryFile (rqptr->ParseOds.NamDevicePtr, rqptr->ParseOds.NamNamePtr - rqptr->ParseOds.NamDevicePtr, DirectoryFile, &DirectoryFileLength); AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); if (VMSok (status = OdsFileExists (NULL, DirectoryFile))) OdsParse (&tkptr->SearchOds, DirectoryFile, DirectoryFileLength, NULL, 0, NULL, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status)) { DavWebResponse (rqptr, 404, status, "collection does not exist", FI_LI); DavPropEnd (rqptr); return; } if (VMSok (status = tkptr->SearchOds.Fab.fab$l_sts)) status = OdsParseTerminate (&tkptr->SearchOds); if (VMSnok(status)) { /* HTTP status will be set from VMS status */ ErrorNoticed (rqptr, status, NULL, FI_LI); ErrorVmsStatus (rqptr, status, FI_LI); DavPropEnd (rqptr); return; } tkptr->PropParent = true; AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsSearch (&tkptr->SearchOds, &DavPropSearchAst, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* Parse the search structure. */ int DavPropParse (REQUEST_STRUCT *rqptr) { int status; char *cptr, *sptr, *zptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropParse()"); tkptr = rqptr->WebDavTaskPtr; cptr = rqptr->ParseOds.ExpFileName; zptr = (sptr = tkptr->SearchSpec) + sizeof(tkptr->SearchSpec); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (!(rqptr->ParseOds.NamNameLength > 0 || rqptr->ParseOds.NamTypeLength > 1)) { /* no name or type was supplied with the request, wildcard it */ for (cptr = "*.*;0"; *cptr && sptr < zptr; *sptr++ = *cptr++); } if (sptr >= zptr) { ErrorNoticed (rqptr, SS$_RESULTOVF, NULL, FI_LI); return (SS$_RESULTOVF); } *sptr = '\0'; tkptr->SearchSpecLength = sptr - tkptr->SearchSpec; AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tkptr->SearchOds, tkptr->SearchSpec, tkptr->SearchSpecLength, NULL, 0, NULL, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSok (status = tkptr->SearchOds.Fab.fab$l_sts)) status = OdsParseTerminate (&rqptr->ParseOds); return (status); } /*****************************************************************************/ /* AST function to invoke another $SEARCH call. */ DavPropSearch (REQUEST_STRUCT *rqptr) { int status; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropSearch() !&F !&S", &DavPropSearch, rqptr->NetIoPtr->WriteStatus); if (VMSnok (rqptr->NetIoPtr->WriteStatus)) { /* network write has failed (as AST), bail out now */ DavPropEnd (rqptr); return; } tkptr = rqptr->WebDavTaskPtr; if (tkptr->PropParent) { /*******************/ /* finished parent */ /*******************/ tkptr->PropParent = false; OdsParseRelease (&tkptr->SearchOds); if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) { DavPropEnd (rqptr); return; } /******************/ /* begin children */ /******************/ status = DavPropParse (rqptr); if (VMSnok(status)) { /* HTTP status will be set from VMS status */ ErrorVmsStatus (rqptr, status, FI_LI); DavPropEnd (rqptr); return; } } AuthAccessEnable (rqptr, 0, AUTH_ACCESS_SYSPRV); OdsSearch (&tkptr->SearchOds, &DavPropSearchAst, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another file name found or have "no more files found" status (or an error!). */ DavPropSearchAst (REQUEST_STRUCT *rqptr) { int status; char *cptr, *sptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropSearchAst() !&F sts:!&S stv:!&S", &DavPropSearchAst, rqptr->WebDavTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->WebDavTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { DavPropEnd (rqptr); return; } tkptr = rqptr->WebDavTaskPtr; if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { /* if its a search list treat directory not found as if file not found */ if ((tkptr->SearchOds.Nam_fnb & NAM$M_SEARCH_LIST) && status == RMS$_DNF) status = RMS$_FNF; if (status == RMS$_FNF || status == RMS$_NMF) { /***************************/ /* end of directory search */ /***************************/ tkptr->SearchOds.ParseInUse = false; DavPropEnd (rqptr); return; } /*************************/ /* protection violation? */ /*************************/ if (status == SS$_NOPRIV || status == RMS$_PRV) { /* continue the search */ DavPropSearch (rqptr); return; } /**********************/ /* sys$search() error */ /**********************/ /* assume this can only happen on the first call */ ErrorVmsStatus (rqptr, status, FI_LI); DavPropEnd (rqptr); return; } /*****************/ /* search result */ /*****************/ #ifndef ODS_EXTENDED /* 06-JUN-2013 MGD VAX VMS V7.3 seems to require this adjusted or it generates RMS$_RSL errors (!?) */ if (tkptr->SearchOds.NamTypeLength > 1) tkptr->SearchOds.Nam.nam$b_rsl = tkptr->SearchOds.NamVersionPtr - tkptr->SearchOds.NamDevicePtr; else tkptr->SearchOds.Nam.nam$b_rsl = tkptr->SearchOds.NamTypePtr - tkptr->SearchOds.NamDevicePtr; #endif if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!&Z", tkptr->SearchOds.NamDevicePtr); if (MATCH7(tkptr->SearchOds.NamNamePtr,"000000.") && strsame (tkptr->SearchOds.NamNamePtr, "000000.DIR;", 11)) { status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSok (status)) { /* no need to report the MFD */ DavPropSearch (rqptr); return; } } /* if a meta file directory it is not accessible */ if (DavMetaDir (rqptr, &tkptr->SearchOds)) { DavPropSearch (rqptr); return; } if (DavMetaFile (&tkptr->SearchOds)) { DavPropSearch (rqptr); return; } /* in true Unix-style "hidden" files do not appear (those beginning ".") */ if (SAME1(tkptr->SearchOds.NamNamePtr,'.') || SAME2(tkptr->SearchOds.NamNamePtr,'^.')) { /* except in demo mode or to VMS authenticated and profiled requests */ if (rqptr->rqPathSet.WebDavNoHidden) { if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, ".FILE (hidden)"); DavPropSearch (rqptr); return; } } if (tkptr->SearchOds.NamTypeLength <= 1) { /* no explicit type - look to see if name contains escaped period */ for (cptr = tkptr->SearchOds.NamNamePtr; cptr < tkptr->SearchOds.NamTypePtr; cptr++) if (*(USHORTPTR)cptr == '^.') break; if (cptr < tkptr->SearchOds.NamTypePtr) { /* escaped period - do not list these ambiguous file names */ if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "^.NAME.; !AZ", tkptr->SearchOds.NamNamePtr); DavPropSearch (rqptr); return; } } /**************/ /* properties */ /**************/ if (tkptr->PropData.PropName) DavPropName (rqptr); else DavPropLiveAcp (rqptr); } /*****************************************************************************/ /* Provide the <propname/> property (all property names without values). */ DavPropName (REQUEST_STRUCT *rqptr) { WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropName()"); tkptr = rqptr->WebDavTaskPtr; DavWebHref (rqptr, tkptr->SearchOds.NamDevicePtr, 0); if (!rqptr->rqResponse.HttpStatus) DavWebResponse207 (rqptr); FaoToNet (rqptr, " <D:response>\n\ <D:href>!AZ!&%AZ</D:href>\n\ <D:propstat>\n\ <D:status>HTTP/1.1 200 OK</D:status>\n\ <D:prop>\n\ <creationdate/>\n\ <displayname/>\n\ <getlastmodified/>\n\ <getcontentlanguage/>\n\ <getcontentlength/>\n\ <getcontenttype/>\n\ <getetag/>\n\ <resourcetype/>\n\ <source/>\n", tkptr->HrefHost, tkptr->PropParent ? rqptr->rqHeader.PathInfoPtr : tkptr->HrefPath); if (tkptr->LockingEnabled) FaoToNet (rqptr, " <lockdiscovery/>\n\ <supportedlock/>\n"); if (tkptr->QuotaEnabled) FaoToNet (rqptr, " <quota-available-bytes/>\n\ <quota-used-bytes/>\n"); FaoToNet (rqptr, " </D:prop>\n\ </D:propstat>\n\ </D:response>\n"); DavPropEnd (rqptr); } /*****************************************************************************/ /* Using the ACP-QIO interface obtain the live file properties (size, created date/time, last modified, etc.) */ DavPropLiveAcp (REQUEST_STRUCT *rqptr) { int status; char *cptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropLiveAcp() !AZ", rqptr->WebDavTaskPtr->SearchOds.NamDevicePtr); tkptr = rqptr->WebDavTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.NamDevicePtr, AUTH_ACCESS_READ); OdsFileAcpInfo (&tkptr->SearchOds, &DavPropLive, rqptr); AuthAccessEnable (rqptr, 0, 0); } /****************************************************************************/ /* AST called from OdsFileAcpInfo() (invoked by DavPropLiveAcp()) when ACP QIO completes. This function supplies the 'live' properties associated with a file (or directory file). */ DavPropLive (REQUEST_STRUCT *rqptr) { int status, Bytes, NameLength; unsigned long AllocatedVbn, EndOfFileVbn; char *cptr, *sptr, *zptr; char DateTime [32], EntityTag [32], FileSpec [ODS_MAX_FILE_NAME_LENGTH+1]; WEBDAV_PROP *proptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropLive() !&F !&S", &DavPropLive, rqptr->WebDavTaskPtr->SearchOds.FileQio.IOsb.Status); tkptr = rqptr->WebDavTaskPtr; proptr = &tkptr->PropData; /* first deassign the channel allocated by OdsFileAcpInfo() */ sys$dassgn (tkptr->SearchOds.FileQio.AcpChannel); if ((status = tkptr->SearchOds.FileQio.IOsb.Status) == SS$_NOSUCHFILE) status = RMS$_FNF; if (VMSnok (status)) { /****************/ /* error status */ /****************/ if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) { /* just the single resource */ ErrorVmsStatus (rqptr, status, FI_LI); DavPropEnd (rqptr); return; } /*************************/ /* protection violation? */ /*************************/ if (status == SS$_NOPRIV || status == RMS$_PRV) { DavPropSearch (rqptr); return; } /*******************/ /* something else! */ /*******************/ DavWebMultiStatus (rqptr, status, tkptr->SearchOds.ExpFileName); DavPropEnd (rqptr); return; } if (!rqptr->rqResponse.HttpStatus) DavWebResponse207 (rqptr); /**********/ /* report */ /**********/ /* same status as OdsReallyADir() */ if (tkptr->SearchOds.FileQio.AtrUchar & FCH$M_DIRECTORY) { tkptr->SearchIsDirectory = true; status = SS$_NORMAL; } else { tkptr->SearchIsDirectory = false; status = SS$_ABORT; } DavWebHref (rqptr, tkptr->SearchOds.NamDevicePtr, status); FaoToNet (rqptr, " <D:response>\n\ <D:href>!AZ!&%AZ</D:href>\n\ <D:propstat>\n\ <D:status>HTTP/1.1 200 OK</D:status>\n\ <D:prop>\n", tkptr->HrefHost, tkptr->PropParent ? rqptr->rqHeader.PathInfoPtr : tkptr->HrefPath); if (proptr->AllProp || proptr->DisplayName) { /********/ /* name */ /********/ if (tkptr->PropParent) zptr = cptr = ""; else { /* resolve the name from the href path */ for (cptr = sptr = tkptr->HrefPath; *cptr; cptr++); zptr = cptr; while (cptr > sptr && *cptr != '/') cptr--; if (tkptr->SearchIsDirectory) { if (cptr > sptr && *cptr == '/') { cptr--; zptr--; } while (cptr > sptr && *cptr != '/') cptr--; } if (*cptr == '/') cptr++; } FaoToNet (rqptr, " <D:displayname>!#&;AZ</D:displayname>\n", zptr-cptr, cptr); } if (proptr->AllProp || proptr->ResourceType) { /******************/ /* file/directory */ /******************/ if (tkptr->SearchIsDirectory) FaoToNet (rqptr, " <D:resourcetype><D:collection/></D:resourcetype>\n"); else FaoToNet (rqptr, " <D:resourcetype/>\n"); } if (proptr->AllProp || proptr->CreationDate) { /***********/ /* created */ /***********/ /* this property format is "1995-0825T17:32:40Z" */ DavWebDateTimeTo3339 (DateTime, &tkptr->SearchOds.FileQio.CdtTime64); FaoToNet (rqptr, " <D:creationdate>!AZ</D:creationdate>\n", DateTime); } if (proptr->AllProp || proptr->GetContentLanguage) /* WASD dosn't handle this datum */ FaoToNet (rqptr, " <D:getcontentlanguage/>\n"); if (proptr->AllProp || proptr->GetContentLength) { /******************/ /* content length */ /******************/ if (!tkptr->SearchIsDirectory) { AllocatedVbn = ((tkptr->SearchOds.FileQio.RecAttr.fat$l_hiblk & 0xffff) << 16) | ((tkptr->SearchOds.FileQio.RecAttr.fat$l_hiblk & 0xffff0000) >> 16); EndOfFileVbn = ((tkptr->SearchOds.FileQio.RecAttr.fat$l_efblk & 0xffff) << 16) | ((tkptr->SearchOds.FileQio.RecAttr.fat$l_efblk & 0xffff0000) >> 16); if (EndOfFileVbn <= 1) Bytes = tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte; else Bytes = ((EndOfFileVbn-1) << 9) + tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "AllocatedVbn:!UL EndOfFileVbn:!UL FirstFreeByte:!UL Bytes;!UL", AllocatedVbn, EndOfFileVbn, tkptr->SearchOds.FileQio.RecAttr.fat$w_ffbyte, Bytes); FaoToNet (rqptr, " <D:getcontentlength>!UL</D:getcontentlength>\n", Bytes); } } if (proptr->AllProp || proptr->GetContentType) { /****************/ /* content type */ /****************/ if (tkptr->SearchIsDirectory) cptr = "httpd/unix-directory"; else { if (rqptr->PathOds == MAPURL_PATH_ODS_ADS || rqptr->PathOds == MAPURL_PATH_ODS_SMB) cptr = MapOdsAdsFileType (tkptr->SearchOds.NamTypePtr); else if (rqptr->PathOds == MAPURL_PATH_ODS_SRI) cptr = MapOdsSriFileType (tkptr->SearchOds.NamTypePtr); else cptr = tkptr->SearchOds.NamTypePtr; ConfigContentType (&tkptr->ContentInfo, cptr); cptr = tkptr->ContentInfo.ContentTypePtr; /* transmogrify WASD internal types */ if (SAME2(cptr,'x-') || SAME2(cptr,'X-')) cptr = "application/octet-stream"; } FaoToNet (rqptr, " <D:getcontenttype>!AZ</D:getcontenttype>\n", cptr); } if (proptr->AllProp || proptr->GetEtag) { /********/ /* etag */ /********/ FileGenerateEntityTag (EntityTag, &tkptr->SearchOds.FileQio); FaoToNet (rqptr, " <D:getetag>\"!AZ\"</D:getetag>\n", EntityTag); } if (proptr->AllProp || proptr->GetLastModified) { /*****************/ /* last modified */ /*****************/ /* this property format is "Fri, 25 Aug 1995 17:32:40 GMT" */ HttpGmTimeString (DateTime, &tkptr->SearchOds.FileQio.RdtTime64); FaoToNet (rqptr, " <D:getlastmodified>!AZ</D:getlastmodified>\n", DateTime); } #if TEST_PROP_QUOTA WebDavQuotaEnabled = proptr->QuotaUsedBytes = proptr->QuotaAvailableBytes = true; #endif if (WebDavQuotaEnabled) if (proptr->QuotaUsedBytes || proptr->QuotaAvailableBytes) DavPropQuota (rqptr); if (tkptr->LockingEnabled && (proptr->AllProp || proptr->LockDiscovery)) { /*********************/ /* locking available */ /*********************/ FaoToNet (rqptr, " <D:supportedlock>\n\ <D:lockentry>\n\ <D:lockscope><D:exclusive/></D:lockscope>\n\ <D:locktype><D:write/></D:locktype>\n\ </D:lockentry>\n\ <D:lockentry>\n\ <D:lockscope><D:shared/></D:lockscope>\n\ <D:locktype><D:write/></D:locktype>\n\ </D:lockentry>\n\ </D:supportedlock>\n"); } if (tkptr->MicrosoftAgent && rqptr->rqPathSet.WebDavNoWinProp && (proptr->AllProp || proptr->FindProp)) { /******************************/ /* fudge Microsoft properties */ /******************************/ /* these property formats are "Fri, 25 Aug 1995 17:32:40 GMT" */ HttpGmTimeString (DateTime, &tkptr->SearchOds.FileQio.CdtTime64); FaoToNet (rqptr, " <MS:Win32CreationTime xmlns:MS=\"urn:schemas-microsoft-com:\">\ !AZ</MS:Win32CreationTime>\n", DateTime); HttpGmTimeString (DateTime, &tkptr->SearchOds.FileQio.RdtTime64); FaoToNet (rqptr, " <MS:Win32LastModifiedTime xmlns:MS=\"urn:schemas-microsoft-com:\">\ !AZ</MS:Win32LastModifiedTime>\n", DateTime); /* NOT the last access time but what the hey it's a fudge! */ FaoToNet (rqptr, " <MS:Win32LastAccessTime xmlns:MS=\"urn:schemas-microsoft-com:\">\ !AZ</MS:Win32LastAccessTime>\n", DateTime); /* apparently it is good practice to always set the archive bit */ FaoToNet (rqptr, " <MS:Win32FileAttributes xmlns:MS=\"urn:schemas-microsoft-com:\">\ 00000020</MS:Win32FileAttributes>\n"); } tkptr->MetaData.VmsStatus = 0; if (rqptr->rqPathSet.WebDavNoProp) DavPropDead (rqptr); else if (proptr->AllProp || proptr->FindProp || proptr->LockDiscovery) { /*************/ /* meta-data */ /*************/ if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) { /* The collection itself. Do NOT use DavPropParent() non-concealed specification to access the meta-data. Use the original request specification. */ DavMetaRead (rqptr, &tkptr->MetaData, rqptr->ParseOds.NamDevicePtr, &DavPropDead, rqptr); return; } zptr = (sptr = FileSpec) + sizeof(FileSpec)-1; cptr = tkptr->SearchOds.NamDevicePtr; if (tkptr->SearchOds.FileQio.AtrUchar & FCH$M_DIRECTORY) { /* munge the ]NAME.DIR into a directory specification .NAME] */ while (*cptr && cptr < tkptr->SearchOds.NamNamePtr-1 && sptr < zptr) *sptr++ = *cptr++; if (sptr < zptr) *sptr++ = '.'; if (*cptr) cptr++; while (*cptr && cptr < tkptr->SearchOds.NamTypePtr && sptr < zptr) *sptr++ = *cptr++; if (sptr < zptr) *sptr++ = ']'; } else { /* just a POF */ while (*cptr && cptr < tkptr->SearchOds.NamVersionPtr && sptr < zptr) *sptr++ = *cptr++; } *sptr = '\0'; DavMetaRead (rqptr, &tkptr->MetaData, FileSpec, &DavPropDead, rqptr); } else DavPropDead (rqptr); } /*****************************************************************************/ /* AST called from DavMetaRead() (invoked by DavPropLive()), or called directly from DavPropLive(). This function supplies the 'dead' properties assocated with a file (or directory). These properties are stored in the meta-data and accessed as required. */ DavPropDead (REQUEST_STRUCT *rqptr) { int status; STR_DSC *fdptr, *sdptr; WEBDAV_META *mtaptr; WEBDAV_PROP *proptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropDead() !&S", rqptr->WebDavTaskPtr->MetaData.VmsStatus); tkptr = rqptr->WebDavTaskPtr; mtaptr = &tkptr->MetaData; proptr = &tkptr->PropData; if (VMSok (tkptr->MetaData.VmsStatus)) { if (tkptr->LockingEnabled && (proptr->AllProp || proptr->LockDiscovery)) { /* what locking is available */ DavLockDiscovery (rqptr); } if (proptr->AllProp) { /* list all of the 'dead' properties */ STR_DSC_ITERATE (sdptr, &tkptr->MetaData.PropDsc) if (STR_DSC_LEN(sdptr)) FaoToNet (rqptr, " !AZ\n", STR_DSC_PTR(sdptr)); } else if (proptr->FindProp) { /* search for requested properties and report any found */ STR_DSC_ITERATE (sdptr, &tkptr->XmlData.PropFindDsc) if (fdptr = DavMetaSearch (rqptr, &tkptr->MetaData.PropDsc, sdptr)) if (STR_DSC_LEN(fdptr)) FaoToNet (rqptr, " !AZ\n", STR_DSC_PTR(fdptr)); } } FaoToNet (rqptr, " </D:prop>\n\ </D:propstat>\n\ </D:response>\n"); if (tkptr->ToDepth == WEBDAV_DEPTH_ZERO) DavPropEnd (rqptr); else if (tkptr->PropFindFlushSecond <= HttpdTickSecond) { /* no output for this period so let's force a flush */ tkptr->PropFindFlushSecond = HttpdTickSecond + tkptr->PropFindFlushAfter; NetWriteBuffered (rqptr, DavPropSearch, NULL, 0); } else { /* reset flush timer if the buffer was at the last attempt */ if (STR_DSC_LEN(&rqptr->NetWriteBufferDsc) < tkptr->PropFindFlushLength) tkptr->PropFindFlushSecond = HttpdTickSecond + tkptr->PropFindFlushAfter; /* set the current length of the buffer */ tkptr->PropFindFlushLength = STR_DSC_LEN(&rqptr->NetWriteBufferDsc); /* flush if buffer full(ish) */ NetWriteBuffered (rqptr, DavPropSearch, NULL, -1); } } /*****************************************************************************/ /* Implement the PROPPATCH method. Modfiy the meta-data properties. */ DavPropPatchBegin (REQUEST_STRUCT *rqptr) { STR_DSC *sdptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropPatchBegin() !&Z", rqptr->ParseOds.ExpFileName); if (!rqptr->RemoteUser[0]) { DavWebResponse (rqptr, 403, SS$_BUGCHECK, "RemoteUser?", FI_LI); DavWebEnd (rqptr); return; } tkptr = rqptr->WebDavTaskPtr; if (rqptr->rqPathSet.WebDavNoProp) { if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "PROPPATCH (path set NOprop) !AZ", rqptr->ParseOds.ExpFileName); DavPropPatchEnd (rqptr); return; } if (tkptr->MicrosoftAgent && rqptr->rqPathSet.WebDavNoWinProp) { /* step through each property in the request body */ STR_DSC_ITERATE (sdptr, &tkptr->XmlData.PropSetDsc) { if (!STR_DSC_LEN(sdptr)) continue; if (strstr(STR_DSC_PTR(sdptr),"urn:schemas-microsoft-com:")) continue; /* break on the first non-MS property */ break; } if (!sdptr) { /* no properties (unlikely) or all MS properties (almost certainly) */ if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "PROPPATCH (path set NOWINPROP) !AZ", rqptr->ParseOds.ExpFileName); tkptr->MetaData.VmsStatus = SS$_NORMAL; DavPropPatchEnd (rqptr); return; } /* otherwise drop thru to continue */ } tkptr->TestLockState = 0; DavPropPatchBegin2 (rqptr); } /*****************************************************************************/ /* Asynchronously test for locking then if not begin the patching. */ DavPropPatchBegin2 (REQUEST_STRUCT *rqptr) { int status; char *cptr; WEBDAV_META *mtaptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ tkptr = rqptr->WebDavTaskPtr; mtaptr = &tkptr->MetaData; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropPatchBegin2() !&F !UL", DavPropPatchBegin2, tkptr->TestLockState); if (tkptr->SearchOds.NamDeviceLength) cptr = tkptr->SearchOds.ExpFileName; else if (rqptr->ParseOds.NamDeviceLength) cptr = rqptr->ParseOds.ExpFileName; else ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); /***********/ /* 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, DavPropPatchBegin2, 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); DavPropPatchEnd (rqptr); return; } /* check for meta-lock on existing source */ tkptr->TestLockState++; DavLockTest (rqptr, rqptr->ParseOds.ExpFileName, false, DavPropPatchBegin2, rqptr); return; case 2 : if (VMSnok (tkptr->TestLockStatus)) { mtaptr->VmsStatus = tkptr->TestLockStatus; DavWebResponse (rqptr, 423, 0, "source locked", FI_LI); DavPropPatchEnd (rqptr); return; } } /**************/ /* not locked */ /**************/ if (WATCHING (rqptr, WATCH_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_WEBDAV, "PROPPATCH !AZ", cptr); DavMetaLock (rqptr, &tkptr->MetaData, rqptr->ParseOds.ExpFileName, &DavPropPatchUpdate, &tkptr->MetaData); } /*****************************************************************************/ /* */ DavPropPatchUpdate (WEBDAV_META *mtaptr) { int status; REQUEST_STRUCT *rqptr; /*********/ /* begin */ /*********/ rqptr = mtaptr->RequestPtr; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropPatchUpdate() !&F !&S", DavPropPatchUpdate, mtaptr->VmsStatus); if (VMSok (mtaptr->VmsStatus)) DavMetaUpdate (mtaptr, DavPropPatchEnd, rqptr); else DavPropPatchEnd (rqptr); } /*****************************************************************************/ /* Complete a PROPPATCH request. */ DavPropPatchEnd (REQUEST_STRUCT *rqptr) { int status, xmlsts; char *cptr; WEBDAV_META *mtaptr; WEBDAV_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropPatchEnd()"); tkptr = rqptr->WebDavTaskPtr; mtaptr = &tkptr->MetaData; if (VMSok (mtaptr->VmsStatus)) { rqptr->rqResponse.NoGzip = true; DavWebResponse207 (rqptr); DavWebHref (rqptr, rqptr->ParseOds.ExpFileName, 0); FaoToNet (rqptr, " <D:response>\n\ <D:href>!AZ!&%AZ</D:href>\n\ </D:response>\n\ </D:multistatus>\n", tkptr->HrefHost, tkptr->PropParent ? rqptr->rqHeader.PathInfoPtr : tkptr->HrefPath); } else { if (mtaptr->VmsStatus == SS$_ACCONFLICT) { /* resource is locked */ DavWebResponse (rqptr, 423, 0, NULL, FI_LI); } else { /* other reason for failure */ DavWebResponse (rqptr, 500, mtaptr->VmsStatus, NULL, FI_LI); } } DavWebEnd (rqptr); } /*****************************************************************************/ /* Provide RFC 4331 quota properties (all synchronous). If the path access is SET webdav=server attempt to return any disk quota for the HTTPd server account or if SET webdav=profile the SYSUAF authenticated request's VMS username. Both of these require a $GETUAI to obtain the UIC. If neither of these (or if the $GETUAI fails for some reason) then return the request path's device used and available space. */ DavPropQuota (REQUEST_STRUCT *rqptr) { static unsigned long AddendZero = 0, FiveTwelve = 512, UaiContext = -1; static unsigned long DviFreeBlocks, DviMaxBlock, UaiUic; static char UserName [12+1]; static int UserNameLength; static $DESCRIPTOR (UserNameDsc, UserName); static VMS_ITEM_LIST2 DeviceFibDsc, InQuotaDsc, OutQuotaDsc; static VMS_ITEM_LIST3 UaiItems [] = { { sizeof(UaiUic), UAI$_UIC, &UaiUic, 0 }, { 0,0,0,0 } }, BlocksItemList [] = { { sizeof(DviMaxBlock), DVI$_MAXBLOCK, &DviMaxBlock, 0 }, { sizeof(DviFreeBlocks), DVI$_FREEBLOCKS, &DviFreeBlocks, 0 }, { 0, 0, 0, 0 } }; int status; unsigned short DeviceChannel, OutLength; unsigned long BytesAvailable, BytesUsed; uint64 bytes64; $DESCRIPTOR (DeviceDsc, ""); struct fibdef DeviceFib; WEBDAV_PROP *proptr; WEBDAV_TASK *tkptr; struct { unsigned long flags; unsigned long uic; unsigned long used; unsigned long perm; unsigned long over; unsigned long unused[3]; } InQuota, OutQuota; struct { unsigned short iosb$w_status; unsigned short iosb$w_bcnt; unsigned long iosb$l_reserved; } IOsb; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "DavPropQuota()"); tkptr = rqptr->WebDavTaskPtr; proptr = &tkptr->PropData; DeviceDsc.dsc$a_pointer = rqptr->ParseOds.NamDevicePtr; DeviceDsc.dsc$w_length = rqptr->ParseOds.NamDeviceLength; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "!#AZ", DeviceDsc.dsc$w_length, DeviceDsc.dsc$a_pointer); status = sys$assign (&DeviceDsc, &DeviceChannel, 0, 0); if (VMSnok (status)) { if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$assign() !&S", status); return (status); } UserNameDsc.dsc$a_pointer = NULL; if (rqptr->rqPathSet.WebDavServer) { /* try to check HTTPd server account quota */ UserNameDsc.dsc$a_pointer = HttpdProcess.UserName; UserNameDsc.dsc$w_length = HttpdProcess.UserNameLength; } else if (rqptr->rqPathSet.WebDavProfile) { /* try to check SYSUAF authenticated user account quota */ if (rqptr->rqAuth.SysUafAuthenticated && rqptr->rqAuth.VmsUserProfileLength) { UserNameDsc.dsc$a_pointer = rqptr->RemoteUser; UserNameDsc.dsc$w_length = rqptr-> RemoteUserLength; } } #if TEST_PROP_QUOTA #ifdef TEST_PROP_QUOTA_USERNAME UserNameDsc.dsc$a_pointer = TEST_PROP_QUOTA_USERNAME; UserNameDsc.dsc$w_length = strlen(TEST_PROP_QUOTA_USERNAME); #endif #endif status = 0; if (UserNameDsc.dsc$a_pointer) { /****************/ /* username UIC */ /****************/ if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "{!UL}!#AZ !&Z", UserNameDsc.dsc$w_length, UserNameDsc.dsc$w_length, UserNameDsc.dsc$a_pointer, UserName); if (UserNameLength != UserNameDsc.dsc$w_length || strncmp (UserName, UserNameDsc.dsc$a_pointer, UserNameLength)) { /* buffer the username (and consequently the UIC) */ char *cptr, *sptr, *zptr; zptr = (sptr = UserName) + sizeof(UserName)-1; for (cptr = UserNameDsc.dsc$a_pointer; cptr < UserNameDsc.dsc$a_pointer + UserNameDsc.dsc$w_length; *sptr++ = *cptr++); *sptr = '\0'; UserNameLength = sptr - UserName; UserNameDsc.dsc$a_pointer = UserName; UserNameDsc.dsc$w_length = UserNameLength; sys$setprv (1, &SysPrvMask, 0, 0); status = sys$getuai (0, &UaiContext, &UserNameDsc, &UaiItems, 0, 0, 0); sys$setprv (0, &SysPrvMask, 0, 0); if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$getuai() !&S", status); } else status = SS$_NORMAL; } /* if UIC was successfully retrieved */ if (VMSok (status)) { /********************/ /* check disk quota */ /********************/ memset (&DeviceFib, 0, sizeof(DeviceFib)); DeviceFib.fib$w_exctl = FIB$C_EXA_QUOTA; DeviceFibDsc.buf_len = sizeof(DeviceFib); DeviceFibDsc.buf_addr = &DeviceFib; memset (&InQuota, 0, sizeof(InQuota)); InQuotaDsc.buf_len = sizeof(InQuota); InQuotaDsc.buf_addr = &InQuota; InQuota.uic = UaiUic; memset (&OutQuota, 0, sizeof(OutQuota)); OutQuotaDsc.buf_len = sizeof(OutQuota); OutQuotaDsc.buf_addr = &OutQuota; status = sys$qiow (0, DeviceChannel, IO$_ACPCONTROL, &IOsb, 0, 0, &DeviceFibDsc, &InQuotaDsc, &OutLength, &OutQuotaDsc, 0, 0); if (VMSok (status)) status = IOsb.iosb$w_status; if (VMSok (status)) { BytesAvailable = OutQuota.perm - OutQuota.used; BytesUsed = OutQuota.used; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "QUOTA perm:!UL used:!UL", OutQuota.perm, OutQuota.used); } else if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$qiow() !&S", status); } /* if the quota ACP failed or if quota not checked */ if (VMSnok (status)) { /********************/ /* get device usage */ /********************/ status = sys$getdviw (EfnWait, DeviceChannel, 0, &BlocksItemList, &IOsb, 0, 0, 0); if (VMSok (status)) status = IOsb.iosb$w_status; if (VMSok (status)) { BytesAvailable = DviFreeBlocks; BytesUsed = DviMaxBlock - DviFreeBlocks; if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "BLOCKS max:!UL free:!UL", DviMaxBlock, DviFreeBlocks); } else if (WATCHMOD (rqptr, WATCH_MOD_WEBDAV)) WatchThis (WATCHITM(rqptr), WATCH_MOD_WEBDAV, "sys$qiow() !&S", status); } if (VMSok (status)) { /***************/ /* list quotas */ /***************/ if (proptr->QuotaUsedBytes) { status = lib$emul (&FiveTwelve, &BytesUsed, &AddendZero, &bytes64); if (VMSok (status)) FaoToNet (rqptr, " <D:quota-used-bytes>!@SQ</D:quota-used-bytes>\n", &bytes64); else ErrorNoticed (rqptr, status, NULL, FI_LI); } if (proptr->QuotaAvailableBytes) { status = lib$emul (&FiveTwelve, &BytesAvailable, &AddendZero, &bytes64); if (VMSok (status)) FaoToNet (rqptr, " <D:quota-available-bytes>!@SQ</D:quota-available-bytes>\n", &bytes64); else ErrorNoticed (rqptr, status, NULL, FI_LI); } } sys$dassgn (DeviceChannel); return (status); } /*****************************************************************************/