Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / afsclass / afsclassfn.cpp
1 extern "C" {
2 #include <afs/param.h>
3 #include <afs/stds.h>
4 }
5
6 #include <WINNT/afsclass.h>
7 #include "internal.h"
8
9
10 /*
11  * DEFINITIONS ________________________________________________________________
12  *
13  */
14
15 #define cREALLOC_ADMINLISTENTRIES   32
16
17 #define cREALLOC_HOSTLISTENTRIES    16
18
19 #define cREALLOC_SERVERKEYS         16
20
21 #define ACCOUNTACCESS_TO_USERACCESS(_aa) ( ((_aa) == aaOWNER_ONLY) ? PTS_USER_OWNER_ACCESS : PTS_USER_ANYUSER_ACCESS )
22
23 #define ACCOUNTACCESS_TO_GROUPACCESS(_aa) ( ((_aa) == aaOWNER_ONLY) ? PTS_GROUP_OWNER_ACCESS : ((_aa) == aaGROUP_ONLY) ? PTS_GROUP_ACCESS : PTS_GROUP_ANYUSER_ACCESS )
24
25
26 /*
27  * PROTOTYPES _________________________________________________________________
28  *
29  */
30
31
32 /*
33  * ROUTINES ___________________________________________________________________
34  *
35  */
36
37 BOOL AfsClass_GetServerLogFile (LPIDENT lpiServer, LPTSTR pszLocal, LPTSTR pszRemote, ULONG *pStatus)
38 {
39    BOOL rc = TRUE;
40    ULONG status;
41
42    AfsClass_Enter();
43    NOTIFYCALLBACK::SendNotificationToAll (evtGetServerLogFileBegin, lpiServer, pszRemote, 0);
44
45    PVOID hCell;
46    PVOID hBOS;
47    LPSERVER lpServer;
48    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
49       rc = FALSE;
50    else
51       {
52       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
53          rc = FALSE;
54       lpServer->Close();
55       }
56
57    if (rc)
58       {
59       WORKERPACKET wp;
60       wp.wpBosLogGet.hServer = hBOS;
61       wp.wpBosLogGet.pszLogName = pszRemote;
62       wp.wpBosLogGet.pszLogData = NULL;
63
64       AfsClass_Leave();
65       if ((rc = Worker_DoTask (wtaskBosLogGet, &wp, &status)) == TRUE)
66          {
67          HANDLE fh;
68          if ((fh = CreateFile (pszLocal, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL)) != INVALID_HANDLE_VALUE)
69             {
70             // Write the file a line at a time in order to make
71             // sure that each line ends with "\r\n".  If we encounter
72             // a line which ends in \r\n already, well, leave it alone.
73             //
74             for (LPTSTR psz = wp.wpBosLogGet.pszLogData; psz && *psz; )
75                {
76                for (LPTSTR pszNext = psz; *pszNext && (*pszNext != TEXT('\r')) && (*pszNext != TEXT('\n')); ++pszNext)
77                   ;
78                DWORD cbWrite;
79                DWORD cbWrote;
80                if ((cbWrite = pszNext - psz) != 0)
81                   WriteFile (fh, psz, cbWrite, &cbWrote, NULL);
82                WriteFile (fh, TEXT("\r\n"), 2, &cbWrote, NULL);
83                psz = (*pszNext == TEXT('\r')) ? (2+pszNext) : (*pszNext == TEXT('\n')) ? (1+pszNext) : NULL;
84                }
85             CloseHandle (fh);
86             }
87
88          Free (wp.wpBosLogGet.pszLogData);
89          }
90
91       AfsClass_Enter();
92       }
93
94    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
95       {
96       lpServer->CloseBosObject();
97       lpServer->Close();
98       }
99
100    NOTIFYCALLBACK::SendNotificationToAll (evtGetServerLogFileEnd, lpiServer, pszRemote, status);
101    AfsClass_Leave();
102
103    if (pStatus && !rc)
104       *pStatus = status;
105    return rc;
106 }
107
108
109 BOOL AfsClass_SetServerAuth (LPIDENT lpiServer, BOOL fEnabled, ULONG *pStatus)
110 {
111    BOOL rc = TRUE;
112    ULONG status;
113
114    AfsClass_Enter();
115    NOTIFYCALLBACK::SendNotificationToAll (evtSetServerAuthBegin, lpiServer);
116
117    PVOID hCell;
118    PVOID hBOS;
119    LPSERVER lpServer;
120    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
121       rc = FALSE;
122    else
123       {
124       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
125          rc = FALSE;
126       lpServer->Close();
127       }
128
129    if (rc)
130       {
131       WORKERPACKET wp;
132       wp.wpBosAuthSet.hServer = hBOS;
133       wp.wpBosAuthSet.fEnableAuth = fEnabled;
134
135       AfsClass_Leave();
136       rc = Worker_DoTask (wtaskBosAuthSet, &wp, &status);
137       AfsClass_Enter();
138       }
139
140    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
141       {
142       lpServer->CloseBosObject();
143       lpServer->Close();
144       }
145
146    NOTIFYCALLBACK::SendNotificationToAll (evtSetServerAuthEnd, lpiServer, status);
147    AfsClass_Leave();
148
149    if (pStatus && !rc)
150       *pStatus = status;
151    return rc;
152 }
153
154
155 BOOL AfsClass_StartService (LPIDENT lpiStart, BOOL fTemporary, ULONG *pStatus)
156 {
157    BOOL rc = TRUE;
158    ULONG status;
159
160    AfsClass_Enter();
161    NOTIFYCALLBACK::SendNotificationToAll (evtStartServiceBegin, lpiStart);
162
163    PVOID hCell;
164    PVOID hBOS;
165    LPSERVER lpServer;
166    if ((lpServer = lpiStart->OpenServer (&status)) == NULL)
167       rc = FALSE;
168    else
169       {
170       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
171          rc = FALSE;
172       lpServer->Close();
173       }
174
175    if (rc)
176       {
177       if (lpiStart->fIsService())
178          {
179          TCHAR szName[ cchNAME ];
180          lpiStart->GetServiceName (szName);
181
182          if (fTemporary)
183             {
184             WORKERPACKET wp;
185             wp.wpBosProcessExecutionStateSetTemporary.hServer = hBOS;
186             wp.wpBosProcessExecutionStateSetTemporary.pszService = szName;
187             wp.wpBosProcessExecutionStateSetTemporary.state = SERVICESTATE_RUNNING;
188
189             AfsClass_Leave();
190             rc = Worker_DoTask (wtaskBosProcessExecutionStateSetTemporary, &wp, &status);
191             AfsClass_Enter();
192             }
193          else
194             {
195             WORKERPACKET wp;
196             wp.wpBosProcessExecutionStateSet.hServer = hBOS;
197             wp.wpBosProcessExecutionStateSet.pszService = szName;
198             wp.wpBosProcessExecutionStateSet.state = SERVICESTATE_RUNNING;
199
200             AfsClass_Leave();
201             rc = Worker_DoTask (wtaskBosProcessExecutionStateSet, &wp, &status);
202             AfsClass_Enter();
203             }
204          }
205       else
206          {
207          WORKERPACKET wp;
208          wp.wpBosProcessAllStart.hServer = hBOS;
209          AfsClass_Leave();
210          rc = Worker_DoTask (wtaskBosProcessAllStart, &wp, &status);
211          AfsClass_Enter();
212          }
213       }
214
215    if (rc)
216       {
217       if (lpiStart->fIsService())
218          {
219          LPSERVICE lpService;
220          if ((lpService = lpiStart->OpenService (&status)) == NULL)
221             rc = FALSE;
222          else
223             {
224             lpService->Invalidate();
225             lpService->RefreshStatus();
226             lpService->Close();
227             }
228          }
229       else
230          {
231          if ((lpServer = lpiStart->OpenServer (&status)) == NULL)
232             rc = FALSE;
233          else
234             {
235             lpServer->Invalidate();
236             lpServer->RefreshAll();
237             lpServer->Close();
238             }
239          }
240       }
241
242    if ((lpServer = lpiStart->OpenServer (&status)) != NULL)
243       {
244       lpServer->CloseBosObject();
245       lpServer->Close();
246       }
247
248    NOTIFYCALLBACK::SendNotificationToAll (evtStartServiceEnd, lpiStart, status);
249    AfsClass_Leave();
250
251    if (pStatus && !rc)
252       *pStatus = status;
253    return rc;
254 }
255
256
257 BOOL AfsClass_StopService (LPIDENT lpiStop, BOOL fTemporary, BOOL fWait, ULONG *pStatus)
258 {
259    BOOL rc = TRUE;
260    ULONG status;
261
262    AfsClass_Enter();
263    NOTIFYCALLBACK::SendNotificationToAll (evtStopServiceBegin, lpiStop);
264
265    PVOID hCell;
266    PVOID hBOS;
267    LPSERVER lpServer;
268    if ((lpServer = lpiStop->OpenServer (&status)) == NULL)
269       rc = FALSE;
270    else
271       {
272       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
273          rc = FALSE;
274       lpServer->Close();
275       }
276
277    if (rc)
278       {
279       if (lpiStop->fIsService())
280          {
281          TCHAR szName[ cchNAME ];
282          lpiStop->GetServiceName (szName);
283
284          if (fTemporary)
285             {
286             WORKERPACKET wp;
287             wp.wpBosProcessExecutionStateSetTemporary.hServer = hBOS;
288             wp.wpBosProcessExecutionStateSetTemporary.pszService = szName;
289             wp.wpBosProcessExecutionStateSetTemporary.state = SERVICESTATE_STOPPED;
290             // TODO: wp.wpStopBosProcessTemporary.fWait = TRUE;
291
292             AfsClass_Leave();
293             rc = Worker_DoTask (wtaskBosProcessExecutionStateSetTemporary, &wp, &status);
294             AfsClass_Enter();
295             }
296          else
297             {
298             WORKERPACKET wp;
299             wp.wpBosProcessExecutionStateSet.hServer = hBOS;
300             wp.wpBosProcessExecutionStateSet.pszService = szName;
301             wp.wpBosProcessExecutionStateSet.state = SERVICESTATE_STOPPED;
302             // TODO: wp.wpStopBosProcess.fWait = TRUE;
303
304             AfsClass_Leave();
305             rc = Worker_DoTask (wtaskBosProcessExecutionStateSet, &wp, &status);
306             AfsClass_Enter();
307             }
308          }
309       else if (fWait)
310          {
311          WORKERPACKET wp;
312          wp.wpBosProcessAllWaitStop.hServer = hBOS;
313
314          AfsClass_Leave();
315          rc = Worker_DoTask (wtaskBosProcessAllWaitStop, &wp, &status);
316          AfsClass_Enter();
317          }
318       else // (!fWait)
319          {
320          WORKERPACKET wp;
321          wp.wpBosProcessAllStop.hServer = hBOS;
322
323          AfsClass_Leave();
324          rc = Worker_DoTask (wtaskBosProcessAllStop, &wp, &status);
325          AfsClass_Enter();
326          }
327       }
328
329    if (rc)
330       {
331       if (lpiStop->fIsService())
332          {
333          LPSERVICE lpService;
334          if ((lpService = lpiStop->OpenService (&status)) == NULL)
335             rc = FALSE;
336          else
337             {
338             lpService->Invalidate();
339             lpService->RefreshStatus();
340             lpService->Close();
341             }
342          }
343       else
344          {
345          LPSERVER lpServer;
346          if ((lpServer = lpiStop->OpenServer (&status)) == NULL)
347             rc = FALSE;
348          else
349             {
350             lpServer->Invalidate();
351             lpServer->RefreshAll();
352             lpServer->Close();
353             }
354          }
355       }
356
357    if ((lpServer = lpiStop->OpenServer (&status)) != NULL)
358       {
359       lpServer->CloseBosObject();
360       lpServer->Close();
361       }
362
363    NOTIFYCALLBACK::SendNotificationToAll (evtStopServiceEnd, lpiStop, status);
364    AfsClass_Leave();
365
366    if (pStatus && !rc)
367       *pStatus = status;
368    return rc;
369 }
370
371
372 BOOL AfsClass_RestartService (LPIDENT lpiRestart, ULONG *pStatus)
373 {
374    BOOL rc = TRUE;
375    ULONG status;
376
377    AfsClass_Enter();
378    NOTIFYCALLBACK::SendNotificationToAll (evtRestartServiceBegin, lpiRestart);
379
380    PVOID hCell;
381    PVOID hBOS;
382    LPSERVER lpServer;
383    if ((lpServer = lpiRestart->OpenServer (&status)) == NULL)
384       rc = FALSE;
385    else
386       {
387       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
388          rc = FALSE;
389       lpServer->Close();
390       }
391
392    BOOL fRestartAll;
393    if (!lpiRestart->fIsService())
394       fRestartAll = TRUE;
395
396    TCHAR szServiceRestart[ cchNAME ];
397    if (lpiRestart->fIsService())
398       {
399       lpiRestart->GetServiceName (szServiceRestart);
400       if (!lstrcmpi (szServiceRestart, TEXT("BOS")))
401          fRestartAll = TRUE;
402       }
403
404    if (rc)
405       {
406       if (!fRestartAll)
407          {
408          WORKERPACKET wp;
409          wp.wpBosProcessRestart.hServer = hBOS;
410          wp.wpBosProcessRestart.pszService = szServiceRestart;
411
412          AfsClass_Leave();
413          rc = Worker_DoTask (wtaskBosProcessRestart, &wp, &status);
414          AfsClass_Enter();
415          }
416       else // (fRestartAll)
417          {
418          WORKERPACKET wp;
419          wp.wpBosProcessAllStopAndRestart.hServer = hBOS;
420          wp.wpBosProcessAllStopAndRestart.fRestartBOS = TRUE;
421
422          AfsClass_Leave();
423          rc = Worker_DoTask (wtaskBosProcessAllStopAndRestart, &wp, &status);
424          AfsClass_Enter();
425          }
426       }
427
428    if (rc)
429       {
430       if (!fRestartAll)
431          {
432          LPSERVICE lpService;
433          if ((lpService = lpiRestart->OpenService (&status)) == NULL)
434             rc = FALSE;
435          else
436             {
437             lpService->Invalidate();
438             lpService->RefreshStatus();
439             lpService->Close();
440             }
441          }
442       else // (fRestartAll)
443          {
444          LPSERVER lpServer;
445          if ((lpServer = lpiRestart->OpenServer (&status)) == NULL)
446             rc = FALSE;
447          else
448             {
449             lpServer->Invalidate();
450             lpServer->RefreshAll();
451             lpServer->Close();
452             }
453          }
454       }
455
456    if ((lpServer = lpiRestart->OpenServer (&status)) != NULL)
457       {
458       lpServer->CloseBosObject();
459       lpServer->Close();
460       }
461
462    NOTIFYCALLBACK::SendNotificationToAll (evtRestartServiceEnd, lpiRestart, status);
463    AfsClass_Leave();
464
465    if (pStatus && !rc)
466       *pStatus = status;
467    return rc;
468 }
469
470
471 LPIDENT AfsClass_CreateFileset (LPIDENT lpiAggregate, LPTSTR pszFileset, ULONG ckQuota, ULONG *pStatus)
472 {
473    LPIDENT lpiFileset = NULL;
474    ULONG status;
475    BOOL rc = TRUE;
476
477    AfsClass_Enter();
478    NOTIFYCALLBACK::SendNotificationToAll (evtCreateFilesetBegin, lpiAggregate, pszFileset, 0);
479
480    // Obtain hCell and hVOS
481    //
482    PVOID hCell;
483    PVOID hVOS = NULL;
484    LPSERVER lpServer;
485    if ((lpServer = lpiAggregate->OpenServer (&status)) == NULL)
486       rc = FALSE;
487    else
488       {
489       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
490          rc = FALSE;
491       lpServer->Close();
492       }
493
494    // Obtain idPartition
495    //
496    int idPartition;
497    LPAGGREGATE lpAggregate;
498    if ((lpAggregate = lpiAggregate->OpenAggregate (&status)) == NULL)
499       rc = FALSE;
500    else
501       {
502       idPartition = lpAggregate->GetID();
503       lpAggregate->Close();
504       }
505
506    // Perform the actual operation
507    //
508    if (rc)
509       {
510       WORKERPACKET wp;
511       wp.wpVosVolumeCreate.hCell = hCell;
512       wp.wpVosVolumeCreate.hServer = hVOS;
513       wp.wpVosVolumeCreate.idPartition = idPartition;
514       wp.wpVosVolumeCreate.pszVolume = pszFileset;
515       wp.wpVosVolumeCreate.ckQuota = ckQuota;
516
517       AfsClass_Leave();
518       rc = Worker_DoTask (wtaskVosVolumeCreate, &wp, &status);
519       AfsClass_Enter();
520       }
521
522    // Clean up
523    //
524    if (rc)
525       {
526       LPAGGREGATE lpAggregate;
527       if ((lpAggregate = lpiAggregate->OpenAggregate (&status)) == NULL)
528          rc = FALSE;
529       else
530          {
531          lpAggregate->Invalidate();
532          lpAggregate->RefreshFilesets (TRUE, &status);
533          lpAggregate->Close();
534          }
535       }
536
537    if (rc)
538       {
539       LPCELL lpCell;
540       if ((lpCell = lpiAggregate->OpenCell()) == NULL)
541          rc = FALSE;
542       else
543          {
544          lpCell->RefreshVLDB (lpiAggregate);
545          lpCell->Close();
546          }
547       }
548
549    if (rc)
550       {
551       LPAGGREGATE lpAggregate;
552       if ((lpAggregate = lpiAggregate->OpenAggregate (&status)) == NULL)
553          rc = FALSE;
554       else
555          {
556          LPFILESET lpFileset;
557          if ((lpFileset = lpAggregate->OpenFileset (pszFileset, &status)) == NULL)
558             rc = FALSE;
559          else
560             {
561             lpiFileset = lpFileset->GetIdentifier();
562             lpFileset->Close();
563             }
564          lpAggregate->Close();
565          }
566       }
567
568    if (hVOS)
569       {
570       if ((lpServer = lpiAggregate->OpenServer (&status)) != NULL)
571          {
572          lpServer->CloseVosObject();
573          lpServer->Close();
574          }
575       }
576
577    NOTIFYCALLBACK::SendNotificationToAll (evtCreateFilesetEnd, lpiAggregate, pszFileset, status);
578    AfsClass_Leave();
579
580    if (pStatus && !rc)
581       *pStatus = status;
582    return (rc) ? lpiFileset : NULL;
583 }
584
585
586 BOOL AfsClass_DeleteFileset (LPIDENT lpiFileset, BOOL fVLDB, BOOL fServer, ULONG *pStatus)
587 {
588    BOOL rc = TRUE;
589    ULONG status;
590
591    AfsClass_Enter();
592    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteFilesetBegin, lpiFileset);
593
594    // Obtain hCell and hVOS
595    //
596    PVOID hCell;
597    PVOID hVOS = NULL;
598    LPSERVER lpServer;
599    if ((lpServer = lpiFileset->OpenServer (&status)) == NULL)
600       rc = FALSE;
601    else
602       {
603       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
604          rc = FALSE;
605       lpServer->Close();
606       }
607
608    // Does the fileset have a VLDB entry? Does it actually exist on the server?
609    // What's its volume ID?  Its R/W ID?  Its partition ID?
610    //
611    VOLUMEID vidFileset;
612    VOLUMEID vidReadWrite;
613    int wFilesetGhost;
614
615    // Obtain the ID of the fileset's parent aggregate.
616    //
617    int idPartition;
618    LPAGGREGATE lpAggregate;
619    if ((lpAggregate = lpiFileset->OpenAggregate (&status)) == NULL)
620       rc = FALSE;
621    else
622       {
623       if ((idPartition = lpAggregate->GetID()) == NO_PARTITION)
624          rc = FALSE;
625       lpAggregate->Close();
626       }
627
628    if (rc)
629       {
630       LPFILESET lpFileset;
631       if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
632          rc = FALSE;
633       else
634          {
635          wFilesetGhost = lpFileset->GetGhostStatus();
636          lpiFileset->GetFilesetID (&vidFileset);
637
638          FILESETSTATUS fs;
639          if (!lpFileset->GetStatus (&fs))
640             vidReadWrite = vidFileset;
641          else
642             vidReadWrite = fs.idReadWrite;
643
644          lpFileset->Close();
645          }
646       }
647
648    if (!(wFilesetGhost & GHOST_HAS_VLDB_ENTRY))
649       fVLDB = FALSE;
650    if (!(wFilesetGhost & GHOST_HAS_SERVER_ENTRY))
651       fServer = FALSE;
652
653    if (rc && fVLDB && fServer)
654       {
655       WORKERPACKET wp;
656       wp.wpVosVolumeDelete.hCell = hCell;
657       wp.wpVosVolumeDelete.hServer = hVOS;
658       wp.wpVosVolumeDelete.idPartition = idPartition;
659       wp.wpVosVolumeDelete.idVolume = vidFileset;
660
661       AfsClass_Leave();
662       rc = Worker_DoTask (wtaskVosVolumeDelete, &wp, &status);
663       AfsClass_Enter();
664       }
665    else if (rc && fVLDB)
666       {
667       WORKERPACKET wp;
668       wp.wpVosVLDBEntryRemove.hCell = hCell;
669       wp.wpVosVLDBEntryRemove.hServer = hVOS;
670       wp.wpVosVLDBEntryRemove.idPartition = idPartition;
671       wp.wpVosVLDBEntryRemove.idVolume = vidReadWrite;
672
673       AfsClass_Leave();
674       rc = Worker_DoTask (wtaskVosVLDBEntryRemove, &wp, &status);
675       AfsClass_Enter();
676       }
677    else if (rc && fServer)
678       {
679       WORKERPACKET wp;
680       wp.wpVosVolumeZap.hCell = hCell;
681       wp.wpVosVolumeZap.hServer = hVOS;
682       wp.wpVosVolumeZap.idPartition = idPartition;
683       wp.wpVosVolumeZap.idVolume = vidFileset;
684       wp.wpVosVolumeZap.fForce = TRUE;
685
686       AfsClass_Leave();
687       rc = Worker_DoTask (wtaskVosVolumeZap, &wp, &status);
688       AfsClass_Enter();
689       }
690
691    if (rc)
692       {
693       LPAGGREGATE lpAggregate;
694       if ((lpAggregate = lpiFileset->OpenAggregate (&status)) == NULL)
695          rc = FALSE;
696       else
697          {
698          lpAggregate->Invalidate();
699          lpAggregate->RefreshFilesets (TRUE);
700          lpAggregate->Close();
701          }
702       }
703
704    if (rc)
705       {
706       LPCELL lpCell;
707       if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
708          rc = FALSE;
709       else
710          {
711          lpCell->RefreshVLDB (lpiFileset->GetAggregate(), TRUE);
712          lpCell->Close();
713          }
714       }
715
716    if (hVOS)
717       {
718       if ((lpServer = lpiFileset->OpenServer()) != NULL)
719          {
720          lpServer->CloseVosObject();
721          lpServer->Close();
722          }
723       }
724
725    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteFilesetEnd, lpiFileset, status);
726    AfsClass_Leave();
727
728    if (pStatus && !rc)
729       *pStatus = status;
730    return rc;
731 }
732
733
734 BOOL AfsClass_MoveFileset (LPIDENT lpiFileset, LPIDENT lpiAggregateTarget, ULONG *pStatus)
735 {
736    BOOL rc = TRUE;
737    ULONG status;
738
739    AfsClass_Enter();
740    NOTIFYCALLBACK::SendNotificationToAll (evtMoveFilesetBegin, lpiFileset, lpiAggregateTarget, NULL, NULL, 0, 0);
741
742    LPIDENT lpiAggregateSource = lpiFileset->GetAggregate();
743
744    // Obtain hCell, hVOS and the aggregate name for the source
745    //
746    PVOID hCell;
747    PVOID hVOSSource = NULL;
748    LPSERVER lpServer;
749    if ((lpServer = lpiFileset->OpenServer (&status)) == NULL)
750       rc = FALSE;
751    else
752       {
753       if ((hVOSSource = lpServer->OpenVosObject (&hCell, &status)) == NULL)
754          rc = FALSE;
755       lpServer->Close();
756       }
757
758    // Obtain the ID of the source aggregate
759    //
760    int idPartitionSource;
761    LPAGGREGATE lpAggregate;
762    if ((lpAggregate = lpiFileset->OpenAggregate (&status)) == NULL)
763       rc = FALSE;
764    else
765       {
766       if ((idPartitionSource = lpAggregate->GetID()) == NO_PARTITION)
767          rc = FALSE;
768       lpAggregate->Close();
769       }
770
771    // Obtain hCell, hVOS and the aggregate name for the target
772    //
773    PVOID hVOSTarget = NULL;
774    if ((lpServer = lpiAggregateTarget->OpenServer (&status)) == NULL)
775       rc = FALSE;
776    else
777       {
778       if ((hVOSTarget = lpServer->OpenVosObject (NULL, &status)) == NULL)
779          rc = FALSE;
780       lpServer->Close();
781       }
782
783    // Obtain the ID of the target aggregate
784    //
785    int idPartitionTarget;
786    if ((lpAggregate = lpiAggregateTarget->OpenAggregate (&status)) == NULL)
787       rc = FALSE;
788    else
789       {
790       if ((idPartitionTarget = lpAggregate->GetID()) == NO_PARTITION)
791          rc = FALSE;
792       lpAggregate->Close();
793       }
794
795    if (rc)
796       {
797       WORKERPACKET wp;
798       wp.wpVosVolumeMove.hCell = hCell;
799       wp.wpVosVolumeMove.hServerFrom = hVOSSource;
800       wp.wpVosVolumeMove.idPartitionFrom = idPartitionSource;
801       wp.wpVosVolumeMove.hServerTo = hVOSTarget;
802       wp.wpVosVolumeMove.idPartitionTo = idPartitionTarget;
803       lpiFileset->GetFilesetID (&wp.wpVosVolumeMove.idVolume);
804
805       AfsClass_Leave();
806       rc = Worker_DoTask (wtaskVosVolumeMove, &wp, &status);
807       AfsClass_Enter();
808       }
809
810    if (rc)
811       {
812       LPAGGREGATE lpAggregate;
813       if ((lpAggregate = lpiAggregateSource->OpenAggregate (&status)) == NULL)
814          rc = FALSE;
815       else
816          {
817          lpAggregate->Invalidate();
818          lpAggregate->RefreshFilesets();
819          lpAggregate->Close();
820          }
821       }
822
823    if (rc)
824       {
825       LPAGGREGATE lpAggregate;
826       if ((lpAggregate = lpiAggregateTarget->OpenAggregate (&status)) == NULL)
827          rc = FALSE;
828       else
829          {
830          lpAggregate->Invalidate();
831          lpAggregate->RefreshFilesets();
832          lpAggregate->Close();
833          }
834       }
835
836    if (rc)
837       {
838       LPFILESET lpFileset;
839       if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
840          rc = FALSE;
841       else
842          {
843          lpFileset->Invalidate();
844          lpFileset->RefreshStatus();
845          lpFileset->Close();
846          }
847       }
848
849    if (rc)
850       {
851       LPCELL lpCell;
852       if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
853          rc = FALSE;
854       else
855          {
856          lpCell->RefreshVLDB (lpiAggregateSource, TRUE);
857          lpCell->RefreshVLDB (lpiAggregateTarget, TRUE);
858          lpCell->Close();
859          }
860       }
861
862    if (hVOSSource)
863       {
864       if ((lpServer = lpiAggregateSource->OpenServer()) != NULL)
865          {
866          lpServer->CloseVosObject();
867          lpServer->Close();
868          }
869       }
870    if (hVOSTarget)
871       {
872       if ((lpServer = lpiAggregateTarget->OpenServer()) != NULL)
873          {
874          lpServer->CloseVosObject();
875          lpServer->Close();
876          }
877       }
878
879    NOTIFYCALLBACK::SendNotificationToAll (evtMoveFilesetEnd, lpiFileset, lpiAggregateTarget, NULL, NULL, 0, status);
880    AfsClass_Leave();
881
882    if (pStatus && !rc)
883       *pStatus = status;
884    return rc;
885 }
886
887
888 BOOL AfsClass_SetFilesetQuota (LPIDENT lpiFileset, size_t ckQuotaNew, ULONG *pStatus)
889 {
890    BOOL rc = TRUE;
891    ULONG status;
892
893    AfsClass_Enter();
894    NOTIFYCALLBACK::SendNotificationToAll (evtSetFilesetQuotaBegin, lpiFileset);
895
896    // Obtain hCell and hVOS for the server where this fileset lives
897    //
898    PVOID hCell;
899    PVOID hVOS = NULL;
900    LPSERVER lpServer;
901    if ((lpServer = lpiFileset->OpenServer (&status)) == NULL)
902       rc = FALSE;
903    else
904       {
905       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
906          rc = FALSE;
907       lpServer->Close();
908       }
909
910    // Obtain the ID of the fileset's parent aggregate.
911    //
912    int idPartition;
913    if (rc)
914       {
915       LPAGGREGATE lpAggregate;
916       if ((lpAggregate = lpiFileset->OpenAggregate (&status)) == NULL)
917          rc = FALSE;
918       else
919          {
920          if ((idPartition = lpAggregate->GetID()) == NO_PARTITION)
921             rc = FALSE;
922          lpAggregate->Close();
923          }
924       }
925
926    // Change the fileset's quota.
927    //
928    if (rc)
929       {
930       WORKERPACKET wp;
931       wp.wpVosVolumeQuotaChange.hCell = hCell;
932       wp.wpVosVolumeQuotaChange.hServer = hVOS;
933       wp.wpVosVolumeQuotaChange.idPartition = idPartition;
934       lpiFileset->GetFilesetID (&wp.wpVosVolumeQuotaChange.idVolume);
935       wp.wpVosVolumeQuotaChange.ckQuota = ckQuotaNew;
936
937       AfsClass_Leave();
938       rc = Worker_DoTask (wtaskVosVolumeQuotaChange, &wp, &status);
939       AfsClass_Enter();
940       }
941
942    if (rc)
943       {
944       LPFILESET lpFileset;
945       if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
946          rc = FALSE;
947       else
948          {
949          lpFileset->Invalidate();
950          lpFileset->RefreshStatus();
951          lpFileset->Close();
952          }
953       }
954
955    if (rc)
956       {
957       LPAGGREGATE lpAggregate;
958       if ((lpAggregate = lpiFileset->OpenAggregate (&status)) == NULL)
959          rc = FALSE;
960       else
961          {
962          lpAggregate->RefreshStatus();
963          lpAggregate->Close();
964          }
965       }
966
967    if (hVOS != NULL)
968       {
969       if ((lpServer = lpiFileset->OpenServer()) != NULL)
970          {
971          lpServer->CloseVosObject();
972          lpServer->Close();
973          }
974       }
975
976    NOTIFYCALLBACK::SendNotificationToAll (evtSetFilesetQuotaEnd, lpiFileset, status);
977    AfsClass_Leave();
978
979    if (pStatus && !rc)
980       *pStatus = status;
981    return rc;
982 }
983
984
985 BOOL AfsClass_SyncVLDB (LPIDENT lpiSync, BOOL fForce, ULONG *pStatus)
986 {
987    BOOL rc = TRUE;
988    ULONG status;
989
990    AfsClass_Enter();
991    NOTIFYCALLBACK::SendNotificationToAll (evtSyncVLDBBegin, lpiSync);
992
993    // Obtain hCell and hVOS
994    //
995    PVOID hCell;
996    PVOID hVOS = NULL;
997    LPSERVER lpServer;
998    if ((lpServer = lpiSync->OpenServer (&status)) == NULL)
999       rc = FALSE;
1000    else
1001       {
1002       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
1003          rc = FALSE;
1004       lpServer->Close();
1005       }
1006
1007    // Obtain the ID of the target aggregate.
1008    //
1009    int idPartition = NO_PARTITION;
1010    if (rc && (lpiSync->fIsAggregate() || lpiSync->fIsFileset()))
1011       {
1012       LPAGGREGATE lpAggregate;
1013       if ((lpAggregate = lpiSync->OpenAggregate (&status)) == NULL)
1014          rc = FALSE;
1015       else
1016          {
1017          if ((idPartition = lpAggregate->GetID()) == NO_PARTITION)
1018             rc = FALSE;
1019          lpAggregate->Close();
1020          }
1021       }
1022
1023    if (rc)
1024       {
1025       WORKERPACKET wp;
1026       wp.wpVosVLDBSync.hCell = hCell;
1027       wp.wpVosVLDBSync.hServer = hVOS;
1028       wp.wpVosVLDBSync.idPartition = idPartition;
1029       wp.wpVosVLDBSync.fForce = fForce;
1030
1031       AfsClass_Leave();
1032       rc = Worker_DoTask (wtaskVosVLDBSync, &wp, &status);
1033       AfsClass_Enter();
1034       }
1035
1036    if (rc)
1037       {
1038       if (lpiSync->fIsServer())
1039          {
1040          LPSERVER lpServer;
1041          if ((lpServer = lpiSync->OpenServer (&status)) == NULL)
1042             rc = FALSE;
1043          else
1044             {
1045             lpServer->Invalidate();
1046             rc = lpServer->RefreshAll (&status);
1047             lpServer->Close();
1048             }
1049          }
1050       else // (lpiSync->fIsAggregate())
1051          {
1052          LPAGGREGATE lpAggregate;
1053          if ((lpAggregate = lpiSync->OpenAggregate (&status)) == NULL)
1054             rc = FALSE;
1055          else
1056             {
1057             lpAggregate->Invalidate();
1058             lpAggregate->RefreshStatus();
1059             lpAggregate->RefreshFilesets();
1060             lpAggregate->Close();
1061
1062             LPCELL lpCell;
1063             if ((lpCell = lpiSync->OpenCell()) == NULL)
1064                rc = FALSE;
1065             else
1066                {
1067                lpCell->RefreshVLDB (lpiSync);
1068                lpCell->Close();
1069                }
1070             }
1071          }
1072       }
1073
1074    if (hVOS)
1075       {
1076       if ((lpServer = lpiSync->OpenServer()) != NULL)
1077          {
1078          lpServer->CloseVosObject();
1079          lpServer->Close();
1080          }
1081       }
1082
1083    NOTIFYCALLBACK::SendNotificationToAll (evtSyncVLDBEnd, lpiSync, status);
1084    AfsClass_Leave();
1085
1086    if (pStatus && !rc)
1087       *pStatus = status;
1088    return rc;
1089 }
1090
1091
1092 BOOL AfsClass_ChangeAddress (LPIDENT lpiServer, LPSOCKADDR_IN pAddrOld, LPSOCKADDR_IN pAddrNew, ULONG *pStatus)
1093 {
1094    BOOL rc = TRUE;
1095    ULONG status;
1096
1097    AfsClass_Enter();
1098    NOTIFYCALLBACK::SendNotificationToAll (evtChangeAddressBegin, lpiServer);
1099
1100    // Obtain hCell
1101    //
1102    PVOID hCell;
1103    LPCELL lpCell;
1104    if ((lpCell = lpiServer->OpenCell (&status)) == NULL)
1105       rc = FALSE;
1106    else
1107       {
1108       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1109          rc = FALSE;
1110       lpCell->Close();
1111       }
1112
1113    if (rc && pAddrNew)
1114       {
1115       WORKERPACKET wp;
1116       wp.wpVosFileServerAddressChange.hCell = hCell;
1117       wp.wpVosFileServerAddressChange.addrOld = *pAddrOld;
1118       wp.wpVosFileServerAddressChange.addrNew = *pAddrNew;
1119
1120       AfsClass_Leave();
1121       rc = Worker_DoTask (wtaskVosFileServerAddressChange, &wp, &status);
1122       AfsClass_Enter();
1123       }
1124    else if (rc && !pAddrNew)
1125       {
1126       WORKERPACKET wp;
1127       wp.wpVosFileServerAddressRemove.hCell = hCell;
1128       wp.wpVosFileServerAddressRemove.addr = *pAddrOld;
1129
1130       AfsClass_Leave();
1131       rc = Worker_DoTask (wtaskVosFileServerAddressRemove, &wp, &status);
1132       AfsClass_Enter();
1133       }
1134
1135    if (rc)
1136       {
1137       LPSERVER lpServer;
1138       if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
1139          {
1140          lpServer->InvalidateStatus();
1141          lpServer->Close();
1142          }
1143
1144       LPCELL lpCell;
1145       if ((lpCell = lpiServer->OpenCell (&status)) == NULL)
1146          rc = FALSE;
1147       else
1148          {
1149          lpCell->InvalidateServers ();
1150          rc = lpCell->RefreshServers (TRUE, &status);
1151          lpCell->Close();
1152          }
1153       }
1154
1155    NOTIFYCALLBACK::SendNotificationToAll (evtChangeAddressEnd, lpiServer, status);
1156    AfsClass_Leave();
1157
1158    if (pStatus && !rc)
1159       *pStatus = status;
1160    return rc;
1161 }
1162
1163
1164 BOOL AfsClass_ChangeAddress (LPIDENT lpiServer, LPSERVERSTATUS pStatusOld, LPSERVERSTATUS pStatusNew, ULONG *pStatus)
1165 {
1166    BOOL rc = TRUE;
1167    ULONG status;
1168
1169    AfsClass_Enter();
1170    NOTIFYCALLBACK::SendNotificationToAll (evtChangeAddressBegin, lpiServer);
1171
1172    // Obtain hCell
1173    //
1174    PVOID hCell;
1175    LPCELL lpCell;
1176    if ((lpCell = lpiServer->OpenCell (&status)) == NULL)
1177       rc = FALSE;
1178    else
1179       {
1180       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1181          rc = FALSE;
1182       lpCell->Close();
1183       }
1184
1185    if (rc)
1186       {
1187       AfsClass_Leave();
1188
1189       for (size_t iAddr = 0; rc && (iAddr < AFSCLASS_MAX_ADDRESSES_PER_SITE); ++iAddr)
1190          {
1191          int oldAddress;
1192          int newAddress;
1193          AfsClass_AddressToInt (&oldAddress, &pStatusOld->aAddresses[ iAddr ]);
1194          AfsClass_AddressToInt (&newAddress, &pStatusNew->aAddresses[ iAddr ]);
1195
1196          if (oldAddress && newAddress && (oldAddress != newAddress))
1197             {
1198             WORKERPACKET wp;
1199             wp.wpVosFileServerAddressChange.hCell = hCell;
1200             wp.wpVosFileServerAddressChange.addrOld = pStatusOld->aAddresses[ iAddr ];
1201             wp.wpVosFileServerAddressChange.addrNew = pStatusNew->aAddresses[ iAddr ];
1202
1203             rc = Worker_DoTask (wtaskVosFileServerAddressChange, &wp, &status);
1204             }
1205          else if (oldAddress && !newAddress)
1206             {
1207             WORKERPACKET wp;
1208             wp.wpVosFileServerAddressRemove.hCell = hCell;
1209             wp.wpVosFileServerAddressRemove.addr = pStatusOld->aAddresses[ iAddr ];
1210
1211             rc = Worker_DoTask (wtaskVosFileServerAddressRemove, &wp, &status);
1212             }
1213          }
1214
1215       AfsClass_Enter();
1216       }
1217
1218    if (rc)
1219       {
1220       LPSERVER lpServer;
1221       if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
1222          {
1223          lpServer->InvalidateStatus();
1224          lpServer->Close();
1225          }
1226
1227       LPCELL lpCell;
1228       if ((lpCell = lpiServer->OpenCell (&status)) == NULL)
1229          rc = FALSE;
1230       else
1231          {
1232          lpCell->InvalidateServers ();
1233          rc = lpCell->RefreshServers (TRUE, &status);
1234          lpCell->Close();
1235          }
1236       }
1237
1238    NOTIFYCALLBACK::SendNotificationToAll (evtChangeAddressEnd, lpiServer, status);
1239    AfsClass_Leave();
1240
1241    if (pStatus && !rc)
1242       *pStatus = status;
1243    return rc;
1244 }
1245
1246
1247 BOOL AfsClass_LockFileset (LPIDENT lpiFileset, ULONG *pStatus)
1248 {
1249    BOOL rc = TRUE;
1250    ULONG status;
1251
1252    AfsClass_Enter();
1253    NOTIFYCALLBACK::SendNotificationToAll (evtLockFilesetBegin, lpiFileset);
1254
1255    // Obtain hCell
1256    //
1257    PVOID hCell;
1258    LPCELL lpCell;
1259    if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1260       rc = FALSE;
1261    else
1262       {
1263       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1264          rc = FALSE;
1265       lpCell->Close();
1266       }
1267
1268    // Obtain the fileset's read-write identifier
1269    //
1270    LPIDENT lpiRW = NULL;
1271    LPFILESET lpFileset;
1272    if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
1273       rc = FALSE;
1274    else
1275       {
1276       if ((lpiRW = lpFileset->GetReadWriteIdentifier()) == NULL)
1277          rc = FALSE;
1278       lpFileset->Close();
1279       }
1280
1281    // Perform the lock operation
1282    //
1283    if (rc)
1284       {
1285       WORKERPACKET wp;
1286       wp.wpVosVLDBEntryLock.hCell = hCell;
1287       lpiRW->GetFilesetID (&wp.wpVosVLDBEntryLock.idVolume);
1288
1289       AfsClass_Leave();
1290       rc = Worker_DoTask (wtaskVosVLDBEntryLock, &wp, &status);
1291       AfsClass_Enter();
1292       }
1293
1294    if (rc)
1295       {
1296       LPCELL lpCell;
1297       if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1298          rc = FALSE;
1299       else
1300          {
1301          if (lpiRW)
1302             lpCell->RefreshVLDB (lpiRW, TRUE, NULL, TRUE);
1303          else
1304             lpCell->RefreshVLDB (lpiFileset->GetCell());
1305          lpCell->Close();
1306          }
1307       }
1308
1309    NOTIFYCALLBACK::SendNotificationToAll (evtLockFilesetEnd, lpiFileset, status);
1310    AfsClass_Leave();
1311
1312    if (pStatus && !rc)
1313       *pStatus = status;
1314    return rc;
1315 }
1316
1317
1318 BOOL AfsClass_UnlockFileset (LPIDENT lpiFileset, ULONG *pStatus)
1319 {
1320    BOOL rc = TRUE;
1321    ULONG status;
1322
1323    AfsClass_Enter();
1324    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockFilesetBegin, lpiFileset);
1325
1326    // Obtain hCell
1327    //
1328    PVOID hCell;
1329    LPCELL lpCell;
1330    if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1331       rc = FALSE;
1332    else
1333       {
1334       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1335          rc = FALSE;
1336       lpCell->Close();
1337       }
1338
1339    // Obtain the fileset's read-write identifier
1340    //
1341    LPIDENT lpiRW = NULL;
1342    LPFILESET lpFileset;
1343    if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
1344       rc = FALSE;
1345    else
1346       {
1347       if ((lpiRW = lpFileset->GetReadWriteIdentifier()) == NULL)
1348          rc = FALSE;
1349       lpFileset->Close();
1350       }
1351
1352    // Perform the unlock operation
1353    //
1354    if (rc)
1355       {
1356       WORKERPACKET wp;
1357       wp.wpVosVLDBEntryUnlock.hCell = hCell;
1358       wp.wpVosVLDBEntryUnlock.hServer = NULL;
1359       wp.wpVosVLDBEntryUnlock.idPartition = NO_PARTITION;
1360       lpiRW->GetFilesetID (&wp.wpVosVLDBEntryUnlock.idVolume);
1361
1362       AfsClass_Leave();
1363       rc = Worker_DoTask (wtaskVosVLDBEntryUnlock, &wp, &status);
1364       AfsClass_Enter();
1365       }
1366
1367    if (rc)
1368       {
1369       LPCELL lpCell;
1370       if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1371          rc = FALSE;
1372       else
1373          {
1374          if (lpiRW)
1375             lpCell->RefreshVLDB (lpiRW, TRUE, NULL, TRUE);
1376          else
1377             lpCell->RefreshVLDB (lpiFileset->GetCell());
1378          lpCell->Close();
1379          }
1380       }
1381
1382    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockFilesetEnd, lpiFileset, status);
1383    AfsClass_Leave();
1384
1385    if (pStatus && !rc)
1386       *pStatus = status;
1387    return rc;
1388 }
1389
1390
1391 BOOL AfsClass_UnlockAllFilesets (LPIDENT lpi, ULONG *pStatus)
1392 {
1393    BOOL rc = TRUE;
1394    ULONG status;
1395
1396    AfsClass_Enter();
1397    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockAllFilesetsBegin, lpi);
1398
1399    // Obtain hCell
1400    //
1401    PVOID hCell;
1402    LPCELL lpCell;
1403    if ((lpCell = lpi->OpenCell (&status)) == NULL)
1404       rc = FALSE;
1405    else
1406       {
1407       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1408          rc = FALSE;
1409       lpCell->Close();
1410       }
1411
1412    // Obtain hServer if appropriate
1413    //
1414    PVOID hVOS = NULL;
1415    if (lpi && (!lpi->fIsCell()))
1416       {
1417       LPSERVER lpServer;
1418       if ((lpServer = lpi->OpenServer (&status)) == NULL)
1419          rc = FALSE;
1420       else
1421          {
1422          if ((hVOS = lpServer->OpenVosObject (NULL, &status)) == NULL)
1423             rc = FALSE;
1424          lpServer->Close();
1425          }
1426       }
1427
1428    // Obtain the ID of the scope aggregate.
1429    //
1430    int idPartition = NO_PARTITION;
1431    if (rc && (lpi->fIsFileset() || (lpi->fIsAggregate())))
1432       {
1433       LPAGGREGATE lpAggregate;
1434       if ((lpAggregate = lpi->OpenAggregate (&status)) == NULL)
1435          rc = FALSE;
1436       else
1437          {
1438          if ((idPartition = lpAggregate->GetID()) == NO_PARTITION)
1439             rc = FALSE;
1440          lpAggregate->Close();
1441          }
1442       }
1443
1444    // Perform the unlock operation
1445    //
1446    if (rc)
1447       {
1448       WORKERPACKET wp;
1449       wp.wpVosVLDBEntryUnlock.hCell = hCell;
1450       wp.wpVosVLDBEntryUnlock.hServer = hVOS;
1451       wp.wpVosVLDBEntryUnlock.idPartition = idPartition;
1452       wp.wpVosVLDBEntryUnlock.idVolume = NO_VOLUME;
1453
1454       AfsClass_Leave();
1455       rc = Worker_DoTask (wtaskVosVLDBEntryUnlock, &wp, &status);
1456       AfsClass_Enter();
1457       }
1458
1459    if (rc)
1460       {
1461       LPCELL lpCell;
1462       if ((lpCell = lpi->OpenCell (&status)) == NULL)
1463          rc = FALSE;
1464       else
1465          {
1466          lpCell->RefreshVLDB (lpi);
1467          lpCell->Close();
1468          }
1469       }
1470
1471    if (hVOS)
1472       {
1473       LPSERVER lpServer;
1474       if ((lpServer = lpi->OpenServer (&status)) != NULL)
1475          {
1476          lpServer->CloseVosObject();
1477          lpServer->Close();
1478          }
1479       }
1480
1481    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockAllFilesetsEnd, lpi);
1482    AfsClass_Leave();
1483
1484    if (pStatus && !rc)
1485       *pStatus = status;
1486    return rc;
1487 }
1488
1489
1490 LPIDENT AfsClass_CreateReplica (LPIDENT lpiFileset, LPIDENT lpiAggregate, ULONG *pStatus)
1491 {
1492    BOOL rc = TRUE;
1493    ULONG status;
1494    LPIDENT lpiReplica = NULL;
1495
1496    AfsClass_Enter();
1497    NOTIFYCALLBACK::SendNotificationToAll (evtCreateReplicaBegin, lpiFileset, lpiAggregate, NULL, NULL, 0, 0);
1498
1499    // Obtain hCell and hVOS for the target server
1500    //
1501    PVOID hCell;
1502    PVOID hVOS = NULL;
1503    LPSERVER lpServer;
1504    if ((lpServer = lpiAggregate->OpenServer (&status)) == NULL)
1505       rc = FALSE;
1506    else
1507       {
1508       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
1509          rc = FALSE;
1510       lpServer->Close();
1511       }
1512
1513    // Obtain idPartition
1514    //
1515    int idPartition;
1516    LPAGGREGATE lpAggregate;
1517    if ((lpAggregate = lpiAggregate->OpenAggregate (&status)) == NULL)
1518       rc = FALSE;
1519    else
1520       {
1521       idPartition = lpAggregate->GetID();
1522       lpAggregate->Close();
1523       }
1524
1525    // Modify VLDB to create mention of a new replica
1526    //
1527    if (rc)
1528       {
1529       WORKERPACKET wp;
1530       wp.wpVosVLDBReadOnlySiteCreate.hCell = hCell;
1531       wp.wpVosVLDBReadOnlySiteCreate.hServer = hVOS;
1532       wp.wpVosVLDBReadOnlySiteCreate.idPartition = idPartition;
1533       lpiFileset->GetFilesetID (&wp.wpVosVLDBReadOnlySiteCreate.idVolume);
1534
1535       AfsClass_Leave();
1536       rc = Worker_DoTask (wtaskVosVLDBReadOnlySiteCreate, &wp, &status);
1537       AfsClass_Enter();
1538       }
1539
1540    // Clean up
1541    //
1542    if (rc)
1543       {
1544       LPAGGREGATE lpAggregate;
1545       if ((lpAggregate = lpiAggregate->OpenAggregate (&status)) == NULL)
1546          rc = FALSE;
1547       else
1548          {
1549          lpAggregate->Invalidate();
1550          lpAggregate->RefreshFilesets (TRUE, &status);
1551          lpAggregate->Close();
1552          }
1553       }
1554
1555    if (rc)
1556       {
1557       LPCELL lpCell;
1558       if ((lpCell = lpiAggregate->OpenCell()) == NULL)
1559          rc = FALSE;
1560       else
1561          {
1562          lpCell->RefreshVLDB (lpiAggregate);
1563          lpCell->Close();
1564          }
1565       }
1566
1567    if (rc)
1568       {
1569       LPFILESET lpFileset;
1570       if ((lpFileset = lpiFileset->OpenFileset (&status)) == NULL)
1571          rc = FALSE;
1572       else
1573          {
1574          if ((lpiReplica = lpFileset->GetReadOnlyIdentifier (lpiAggregate, &status)) == NULL)
1575             rc = FALSE;
1576          lpFileset->Close();
1577          }
1578       }
1579
1580    if (hVOS)
1581       {
1582       if ((lpServer = lpiAggregate->OpenServer (&status)) != NULL)
1583          {
1584          lpServer->CloseVosObject();
1585          lpServer->Close();
1586          }
1587       }
1588
1589    NOTIFYCALLBACK::SendNotificationToAll (evtCreateReplicaEnd, lpiFileset, lpiAggregate, NULL, NULL, 0, status);
1590    AfsClass_Leave();
1591
1592    if (pStatus && !rc)
1593       *pStatus = status;
1594    return (rc) ? lpiReplica : FALSE;
1595 }
1596
1597
1598 BOOL AfsClass_DeleteReplica (LPIDENT lpiReplica, ULONG *pStatus)
1599 {
1600    BOOL rc = TRUE;
1601    ULONG status;
1602
1603    AfsClass_Enter();
1604    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteFilesetBegin, lpiReplica);
1605
1606    // Obtain hCell and hVOS for the server
1607    //
1608    PVOID hCell;
1609    PVOID hVOS = NULL;
1610    LPSERVER lpServer;
1611    if ((lpServer = lpiReplica->OpenServer (&status)) == NULL)
1612       rc = FALSE;
1613    else
1614       {
1615       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
1616          rc = FALSE;
1617       lpServer->Close();
1618       }
1619
1620    // Get the read/write fileset identifier and Ghost status
1621    //
1622    LPIDENT lpiRW = NULL;
1623    int wFilesetGhost = 0;
1624    LPFILESET lpFileset;
1625    if ((lpFileset = lpiReplica->OpenFileset (&status)) == NULL)
1626       rc = FALSE;
1627    else
1628       {
1629       wFilesetGhost = lpFileset->GetGhostStatus();
1630       if ((lpiRW = lpFileset->GetReadWriteIdentifier()) == NULL)
1631          rc = FALSE;
1632       lpFileset->Close();
1633       }
1634
1635    TCHAR szAggregateName[ cchNAME ];
1636    lpiReplica->GetAggregateName (szAggregateName);
1637
1638    // Obtain the ID of the replica's partition
1639    //
1640    int idPartition;
1641    LPAGGREGATE lpAggregate;
1642    if ((lpAggregate = lpiReplica->OpenAggregate (&status)) == NULL)
1643       rc = FALSE;
1644    else
1645       {
1646       idPartition = lpAggregate->GetID();
1647       lpAggregate->Close();
1648       }
1649
1650    // If the volume exists in both VLDB and on the server, just delete it
1651    //
1652    if (rc && (wFilesetGhost & GHOST_HAS_VLDB_ENTRY) && (wFilesetGhost & GHOST_HAS_SERVER_ENTRY))
1653       {
1654       WORKERPACKET wp;
1655       wp.wpVosVolumeDelete.hCell = hCell;
1656       wp.wpVosVolumeDelete.hServer = hVOS;
1657       wp.wpVosVolumeDelete.idPartition = idPartition;
1658       lpiReplica->GetFilesetID (&wp.wpVosVolumeDelete.idVolume);
1659
1660       AfsClass_Leave();
1661       rc = Worker_DoTask (wtaskVosVolumeDelete, &wp, &status);
1662       AfsClass_Enter();
1663       }
1664    else
1665       {
1666       // If necessary, modify VLDB to remove mention of this replica
1667       //
1668       if (rc && (wFilesetGhost & GHOST_HAS_VLDB_ENTRY))
1669          {
1670          WORKERPACKET wp;
1671          wp.wpVosVLDBReadOnlySiteDelete.hCell = hCell;
1672          wp.wpVosVLDBReadOnlySiteDelete.hServer = hVOS;
1673          wp.wpVosVLDBReadOnlySiteDelete.idPartition = idPartition;
1674          lpiRW->GetFilesetID (&wp.wpVosVLDBReadOnlySiteDelete.idVolume);
1675
1676          AfsClass_Leave();
1677          rc = Worker_DoTask (wtaskVosVLDBReadOnlySiteDelete, &wp, &status);
1678          AfsClass_Enter();
1679          }
1680
1681       // If necessary, zap the volume
1682       //
1683       if (rc && (wFilesetGhost & GHOST_HAS_SERVER_ENTRY))
1684          {
1685          WORKERPACKET wp;
1686          wp.wpVosVolumeZap.hCell = hCell;
1687          wp.wpVosVolumeZap.hServer = hVOS;
1688          wp.wpVosVolumeZap.idPartition = idPartition;
1689          lpiReplica->GetFilesetID (&wp.wpVosVolumeZap.idVolume);
1690          wp.wpVosVolumeZap.fForce = TRUE;
1691
1692          AfsClass_Leave();
1693          rc = Worker_DoTask (wtaskVosVolumeZap, &wp, &status);
1694          AfsClass_Enter();
1695          }
1696       }
1697
1698    // Clean up
1699    //
1700    if (rc)
1701       {
1702       LPAGGREGATE lpAggregate;
1703       if ((lpAggregate = lpiReplica->OpenAggregate (&status)) == NULL)
1704          rc = FALSE;
1705       else
1706          {
1707          lpAggregate->Invalidate();
1708          lpAggregate->RefreshFilesets (TRUE, &status);
1709          lpAggregate->Close();
1710          }
1711       }
1712
1713    if (rc)
1714       {
1715       LPCELL lpCell;
1716       if ((lpCell = lpiReplica->OpenCell()) == NULL)
1717          rc = FALSE;
1718       else
1719          {
1720          lpCell->RefreshVLDB (lpiReplica->GetAggregate());
1721          lpCell->Close();
1722          }
1723       }
1724
1725    if (hVOS)
1726       {
1727       if ((lpServer = lpiReplica->OpenServer (&status)) != NULL)
1728          {
1729          lpServer->CloseVosObject();
1730          lpServer->Close();
1731          }
1732       }
1733
1734    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteFilesetEnd, lpiReplica, status);
1735    AfsClass_Leave();
1736
1737    if (pStatus && !rc)
1738       *pStatus = status;
1739    return rc;
1740 }
1741
1742
1743 BOOL AfsClass_DeleteClone (LPIDENT lpiClone, ULONG *pStatus)
1744 {
1745    return AfsClass_DeleteFileset (lpiClone, TRUE, TRUE, pStatus);
1746 }
1747
1748
1749 BOOL AfsClass_InstallFile (LPIDENT lpiServer, LPTSTR pszTarget, LPTSTR pszSource, ULONG *pStatus)
1750 {
1751    BOOL rc = TRUE;
1752    ULONG status;
1753
1754    AfsClass_Enter();
1755    NOTIFYCALLBACK::SendNotificationToAll (evtInstallFileBegin, lpiServer, pszSource, 0);
1756
1757    PVOID hCell;
1758    PVOID hBOS;
1759    LPSERVER lpServer;
1760    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
1761       rc = FALSE;
1762    else
1763       {
1764       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
1765          rc = FALSE;
1766       lpServer->Close();
1767       }
1768
1769    if (rc)
1770       {
1771       WORKERPACKET wp;
1772       wp.wpBosExecutableCreate.hServer = hBOS;
1773       wp.wpBosExecutableCreate.pszLocal = pszSource;
1774       wp.wpBosExecutableCreate.pszRemoteDir = pszTarget;
1775
1776       AfsClass_Leave();
1777       rc = Worker_DoTask (wtaskBosExecutableCreate, &wp, &status);
1778       AfsClass_Enter();
1779       }
1780
1781    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
1782       {
1783       lpServer->CloseBosObject();
1784       lpServer->Close();
1785       }
1786
1787    NOTIFYCALLBACK::SendNotificationToAll (evtInstallFileEnd, lpiServer, pszSource, status);
1788    AfsClass_Leave();
1789
1790    if (pStatus && !rc)
1791       *pStatus = status;
1792    return rc;
1793 }
1794
1795
1796 BOOL AfsClass_UninstallFile (LPIDENT lpiServer, LPTSTR pszUninstall, ULONG *pStatus)
1797 {
1798    BOOL rc = TRUE;
1799    ULONG status;
1800
1801    AfsClass_Enter();
1802    NOTIFYCALLBACK::SendNotificationToAll (evtUninstallFileBegin, lpiServer, pszUninstall, 0);
1803
1804    PVOID hCell;
1805    PVOID hBOS;
1806    LPSERVER lpServer;
1807    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
1808       rc = FALSE;
1809    else
1810       {
1811       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
1812          rc = FALSE;
1813       lpServer->Close();
1814       }
1815
1816    if (rc)
1817       {
1818       WORKERPACKET wp;
1819       wp.wpBosExecutableRevert.hServer = hBOS;
1820       wp.wpBosExecutableRevert.pszFilename = pszUninstall;
1821
1822       AfsClass_Leave();
1823       rc = Worker_DoTask (wtaskBosExecutableRevert, &wp, &status);
1824       AfsClass_Enter();
1825       }
1826
1827    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
1828       {
1829       lpServer->CloseBosObject();
1830       lpServer->Close();
1831       }
1832
1833    NOTIFYCALLBACK::SendNotificationToAll (evtUninstallFileEnd, lpiServer, pszUninstall, status);
1834    AfsClass_Leave();
1835
1836    if (pStatus && !rc)
1837       *pStatus = status;
1838    return rc;
1839 }
1840
1841
1842 BOOL AfsClass_PruneOldFiles (LPIDENT lpiServer, BOOL fBAK, BOOL fOLD, BOOL fCore, ULONG *pStatus)
1843 {
1844    BOOL rc = TRUE;
1845    ULONG status;
1846
1847    AfsClass_Enter();
1848    NOTIFYCALLBACK::SendNotificationToAll (evtPruneFilesBegin, lpiServer);
1849
1850    PVOID hCell;
1851    PVOID hBOS;
1852    LPSERVER lpServer;
1853    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
1854       rc = FALSE;
1855    else
1856       {
1857       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
1858          rc = FALSE;
1859       lpServer->Close();
1860       }
1861
1862    if (rc)
1863       {
1864       WORKERPACKET wp;
1865       wp.wpBosExecutablePrune.hServer = hBOS;
1866       wp.wpBosExecutablePrune.fPruneBak = fBAK;
1867       wp.wpBosExecutablePrune.fPruneOld = fOLD;
1868       wp.wpBosExecutablePrune.fPruneCore = fCore;
1869
1870       AfsClass_Leave();
1871       rc = Worker_DoTask (wtaskBosExecutablePrune, &wp, &status);
1872       AfsClass_Enter();
1873       }
1874
1875    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
1876       {
1877       lpServer->CloseBosObject();
1878       lpServer->Close();
1879       }
1880
1881    NOTIFYCALLBACK::SendNotificationToAll (evtPruneFilesEnd, lpiServer, status);
1882    AfsClass_Leave();
1883
1884    if (pStatus && !rc)
1885       *pStatus = status;
1886    return rc;
1887 }
1888
1889
1890 BOOL AfsClass_RenameFileset (LPIDENT lpiFileset, LPTSTR pszNewName, ULONG *pStatus)
1891 {
1892    BOOL rc = TRUE;
1893    ULONG status;
1894
1895    AfsClass_Enter();
1896    NOTIFYCALLBACK::SendNotificationToAll (evtRenameFilesetBegin, lpiFileset, pszNewName, 0);
1897
1898    PVOID hCell;
1899    LPCELL lpCell;
1900    if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1901       rc = FALSE;
1902    else
1903       {
1904       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
1905          rc = FALSE;
1906       lpCell->Close();
1907       }
1908
1909    if (rc)
1910       {
1911       WORKERPACKET wp;
1912       wp.wpVosVolumeRename.hCell = hCell;
1913       lpiFileset->GetFilesetID (&wp.wpVosVolumeRename.idVolume);
1914       wp.wpVosVolumeRename.pszVolume = pszNewName;
1915
1916       AfsClass_Leave();
1917       rc = Worker_DoTask (wtaskVosVolumeRename, &wp, &status);
1918       AfsClass_Enter();
1919       }
1920
1921    if (rc)
1922       {
1923       LPCELL lpCell;
1924       if ((lpCell = lpiFileset->OpenCell (&status)) == NULL)
1925          rc = FALSE;
1926       else
1927          {
1928          lpCell->Invalidate();
1929          rc = lpCell->RefreshAll (&status);
1930          lpCell->Close();
1931          }
1932       }
1933
1934
1935    NOTIFYCALLBACK::SendNotificationToAll (evtRenameFilesetEnd, lpiFileset, pszNewName, status);
1936    AfsClass_Leave();
1937
1938    if (pStatus && !rc)
1939       *pStatus = status;
1940    return rc;
1941 }
1942
1943
1944 #define iswhite(_ch) ((_ch)==TEXT(' ') || (_ch)==TEXT('\t'))
1945
1946 LPIDENT AfsClass_CreateService (LPIDENT lpiServer, LPTSTR pszService, LPTSTR pszCommand, LPTSTR pszParams, LPTSTR pszNotifier, SERVICETYPE type, SYSTEMTIME *pstIfCron, ULONG *pStatus)
1947 {
1948    BOOL rc = TRUE;
1949    ULONG status;
1950    LPIDENT lpiService = NULL;
1951
1952    AfsClass_Enter();
1953    NOTIFYCALLBACK::SendNotificationToAll (evtCreateServiceBegin, lpiServer, pszService, 0);
1954
1955    PVOID hCell;
1956    PVOID hBOS;
1957    LPSERVER lpServer;
1958    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
1959       rc = FALSE;
1960    else
1961       {
1962       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
1963          rc = FALSE;
1964       lpServer->Close();
1965       }
1966
1967    if (rc)
1968       {
1969       WORKERPACKET wp;
1970       wp.wpBosProcessCreate.hServer = hBOS;
1971       wp.wpBosProcessCreate.pszService = pszService;
1972       wp.wpBosProcessCreate.type = type;
1973       wp.wpBosProcessCreate.pszNotifier = pszNotifier;
1974
1975       TCHAR szFullCommand[ MAX_PATH + MAX_PATH ];
1976       wsprintf (szFullCommand, TEXT("%s %s"), pszCommand, pszParams);
1977       wp.wpBosProcessCreate.pszCommand = szFullCommand;
1978
1979       TCHAR szCronTime[ 256 ] = TEXT("");
1980       wp.wpBosProcessCreate.pszTimeCron = szCronTime;
1981
1982       if (type == SERVICETYPE_CRON)
1983          AfsClass_FormatRecurringTime (szCronTime, pstIfCron);
1984       else
1985          wp.wpBosProcessCreate.pszTimeCron = NULL;
1986
1987       AfsClass_Leave();
1988       rc = Worker_DoTask (wtaskBosProcessCreate, &wp, &status);
1989       AfsClass_Enter();
1990       }
1991
1992    if (rc)
1993       {
1994       if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
1995          rc = FALSE;
1996       else
1997          {
1998          lpServer->InvalidateServices();
1999          if (!lpServer->RefreshServices (TRUE, &status))
2000             rc = FALSE;
2001          else
2002             {
2003             LPSERVICE lpService;
2004             if ((lpService = lpServer->OpenService (pszService, &status)) == NULL)
2005                rc = FALSE;
2006             else
2007                {
2008                lpiService = lpService->GetIdentifier();
2009                lpService->Close();
2010                }
2011             }
2012          lpServer->Close();
2013          }
2014       }
2015
2016    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2017       {
2018       lpServer->CloseBosObject();
2019       lpServer->Close();
2020       }
2021
2022    NOTIFYCALLBACK::SendNotificationToAll (evtCreateServiceEnd, lpiServer, pszService, status);
2023    AfsClass_Leave();
2024
2025    if (pStatus && !rc)
2026       *pStatus = status;
2027    return (rc) ? lpiService : NULL;
2028 }
2029
2030
2031 BOOL AfsClass_DeleteService (LPIDENT lpiService, ULONG *pStatus)
2032 {
2033    BOOL rc = TRUE;
2034    ULONG status;
2035
2036    AfsClass_Enter();
2037    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteServiceBegin, lpiService);
2038
2039    PVOID hCell;
2040    PVOID hBOS;
2041    LPSERVER lpServer;
2042    if ((lpServer = lpiService->OpenServer (&status)) == NULL)
2043       rc = FALSE;
2044    else
2045       {
2046       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2047          rc = FALSE;
2048       lpServer->Close();
2049       }
2050
2051    // Before a service can be deleted, it must be stopped (otherwise, on NT,
2052    // the Delete operation won't block for the required Stop to complete--
2053    // so our wtaskDeleteBosProcess would return before the service really
2054    // was deleted).
2055    //
2056    if (rc)
2057       {
2058       TCHAR szService[ cchNAME ];
2059       lpiService->GetServiceName (szService);
2060
2061       WORKERPACKET wp;
2062       wp.wpBosProcessExecutionStateSet.hServer = hBOS;
2063       wp.wpBosProcessExecutionStateSet.pszService = szService;
2064       wp.wpBosProcessExecutionStateSet.state = SERVICESTATE_STOPPED;
2065       // TODO: wp.wpStopBosProcess.fWait = TRUE;
2066
2067       AfsClass_Leave();
2068       rc = Worker_DoTask (wtaskBosProcessExecutionStateSet, &wp, &status);
2069       AfsClass_Enter();
2070       }
2071
2072    // Delete the service
2073    //
2074    if (rc)
2075       {
2076       TCHAR szService[ cchNAME ];
2077       lpiService->GetServiceName (szService);
2078
2079       WORKERPACKET wp;
2080       wp.wpBosProcessDelete.hServer = hBOS;
2081       wp.wpBosProcessDelete.pszService = szService;
2082
2083       AfsClass_Leave();
2084       rc = Worker_DoTask (wtaskBosProcessDelete, &wp, &status);
2085       AfsClass_Enter();
2086       }
2087
2088    if (rc)
2089       {
2090       if ((lpServer = lpiService->OpenServer (&status)) == NULL)
2091          rc = FALSE;
2092       else
2093          {
2094          lpServer->InvalidateServices();
2095          if (!lpServer->RefreshServices (TRUE, &status))
2096             rc = FALSE;
2097          lpServer->Close();
2098          }
2099       }
2100
2101    if ((lpServer = lpiService->OpenServer (&status)) != NULL)
2102       {
2103       lpServer->CloseBosObject();
2104       lpServer->Close();
2105       }
2106
2107    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteServiceEnd, lpiService, status);
2108    AfsClass_Leave();
2109
2110    if (pStatus && !rc)
2111       *pStatus = status;
2112    return rc;
2113 }
2114
2115
2116 BOOL AfsClass_ReleaseFileset (LPIDENT lpiFilesetRW, BOOL fForce, ULONG *pStatus)
2117 {
2118    BOOL rc = TRUE;
2119    ULONG status;
2120
2121    AfsClass_Enter();
2122    NOTIFYCALLBACK::SendNotificationToAll (evtReleaseFilesetBegin, lpiFilesetRW);
2123
2124    // Obtain hCell and hVOS
2125    //
2126    PVOID hCell;
2127    PVOID hVOS = NULL;
2128    LPSERVER lpServer;
2129    if ((lpServer = lpiFilesetRW->OpenServer (&status)) == NULL)
2130       rc = FALSE;
2131    else
2132       {
2133       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
2134          rc = FALSE;
2135       lpServer->Close();
2136       }
2137
2138    // Perform the actual operation
2139    //
2140    if (rc)
2141       {
2142       WORKERPACKET wp;
2143       wp.wpVosVolumeRelease.hCell = hCell;
2144       wp.wpVosVolumeRelease.fForce = fForce;
2145       lpiFilesetRW->GetFilesetID (&wp.wpVosVolumeRelease.idVolume);
2146
2147       AfsClass_Leave();
2148       rc = Worker_DoTask (wtaskVosVolumeRelease, &wp, &status);
2149       AfsClass_Enter();
2150       }
2151
2152    // Clean up
2153    //
2154    if (rc)
2155       {
2156       LPCELL lpCell;
2157       if ((lpCell = lpiFilesetRW->OpenCell (&status)) == NULL)
2158          rc = FALSE;
2159       else
2160          {
2161          lpCell->Invalidate();
2162          rc = lpCell->RefreshAll (&status);
2163          lpCell->Close();
2164          }
2165       }
2166
2167    if (hVOS)
2168       {
2169       if ((lpServer = lpiFilesetRW->OpenServer (&status)) != NULL)
2170          {
2171          lpServer->CloseVosObject();
2172          lpServer->Close();
2173          }
2174       }
2175
2176    NOTIFYCALLBACK::SendNotificationToAll (evtReleaseFilesetEnd, lpiFilesetRW, status);
2177    AfsClass_Leave();
2178
2179    if (pStatus && !rc)
2180       *pStatus = status;
2181    return rc;
2182 }
2183
2184
2185 BOOL AfsClass_GetFileDates (LPIDENT lpiServer, LPTSTR pszFilename, SYSTEMTIME *pstFile, SYSTEMTIME *pstBAK, SYSTEMTIME *pstOLD, ULONG *pStatus)
2186 {
2187    BOOL rc = TRUE;
2188    ULONG status;
2189
2190    AfsClass_Enter();
2191    NOTIFYCALLBACK::SendNotificationToAll (evtGetFileDatesBegin, lpiServer, pszFilename, 0);
2192
2193    PVOID hCell;
2194    PVOID hBOS;
2195    LPSERVER lpServer;
2196    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2197       rc = FALSE;
2198    else
2199       {
2200       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2201          rc = FALSE;
2202       lpServer->Close();
2203       }
2204
2205    if (rc)
2206       {
2207       WORKERPACKET wp;
2208       wp.wpBosExecutableTimestampGet.hServer = hBOS;
2209       wp.wpBosExecutableTimestampGet.pszFilename = pszFilename;
2210
2211       AfsClass_Leave();
2212       if ((rc = Worker_DoTask (wtaskBosExecutableTimestampGet, &wp, &status)) == TRUE)
2213          {
2214          *pstFile = wp.wpBosExecutableTimestampGet.timeNew;
2215          *pstBAK = wp.wpBosExecutableTimestampGet.timeBak;
2216          *pstOLD = wp.wpBosExecutableTimestampGet.timeOld;
2217          }
2218
2219       AfsClass_Enter();
2220       }
2221
2222    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2223       {
2224       lpServer->CloseBosObject();
2225       lpServer->Close();
2226       }
2227
2228    NOTIFYCALLBACK::SendNotificationToAll (evtGetFileDatesEnd, lpiServer, pszFilename, status);
2229    AfsClass_Leave();
2230
2231    if (pStatus && !rc)
2232       *pStatus = status;
2233    return rc;
2234 }
2235
2236
2237 BOOL AfsClass_ExecuteCommand (LPIDENT lpiServer, LPTSTR pszCommand, ULONG *pStatus)
2238 {
2239    BOOL rc = TRUE;
2240    ULONG status;
2241
2242    AfsClass_Enter();
2243    NOTIFYCALLBACK::SendNotificationToAll (evtExecuteCommandBegin, lpiServer, pszCommand, 0);
2244
2245    PVOID hCell;
2246    PVOID hBOS;
2247    LPSERVER lpServer;
2248    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2249       rc = FALSE;
2250    else
2251       {
2252       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2253          rc = FALSE;
2254       lpServer->Close();
2255       }
2256
2257    if (rc)
2258       {
2259       WORKERPACKET wp;
2260       wp.wpBosCommandExecute.hServer = hBOS;
2261       wp.wpBosCommandExecute.pszCommand = pszCommand;
2262
2263       AfsClass_Leave();
2264       rc = Worker_DoTask (wtaskBosCommandExecute, &wp, &status);
2265       AfsClass_Enter();
2266       }
2267
2268    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2269       {
2270       lpServer->CloseBosObject();
2271       lpServer->Close();
2272       }
2273
2274    NOTIFYCALLBACK::SendNotificationToAll (evtExecuteCommandEnd, lpiServer, pszCommand, status);
2275    AfsClass_Leave();
2276
2277    if (pStatus && !rc)
2278       *pStatus = status;
2279    return rc;
2280 }
2281
2282
2283 LPADMINLIST AfsClass_AdminList_Load (LPIDENT lpiServer, ULONG *pStatus)
2284 {
2285    BOOL rc = TRUE;
2286    ULONG status;
2287    LPADMINLIST lpList = NULL;
2288
2289    AfsClass_Enter();
2290    NOTIFYCALLBACK::SendNotificationToAll (evtAdminListLoadBegin, lpiServer);
2291
2292    PVOID hCell;
2293    PVOID hBOS;
2294    LPSERVER lpServer;
2295    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2296       rc = FALSE;
2297    else
2298       {
2299       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2300          rc = FALSE;
2301       lpServer->Close();
2302       }
2303
2304    if (rc)
2305       {
2306       lpList = New(ADMINLIST);
2307       memset (lpList, 0x00, sizeof(ADMINLIST));
2308       lpList->cRef = 1;
2309       lpList->lpiServer = lpiServer;
2310
2311       WORKERPACKET wpBegin;
2312       wpBegin.wpBosAdminGetBegin.hServer = hBOS;
2313       if (!Worker_DoTask (wtaskBosAdminGetBegin, &wpBegin, &status))
2314          rc = FALSE;
2315       else
2316          {
2317          for (;;)
2318             {
2319             TCHAR szAdmin[ cchNAME ];
2320
2321             WORKERPACKET wpNext;
2322             wpNext.wpBosAdminGetNext.hEnum = wpBegin.wpBosAdminGetBegin.hEnum;
2323             wpNext.wpBosAdminGetNext.pszAdmin = szAdmin;
2324
2325             if (!Worker_DoTask (wtaskBosAdminGetNext, &wpNext, &status))
2326                {
2327                if (status == ADMITERATORDONE)
2328                   status = 0;
2329                else
2330                   rc = FALSE;
2331                break;
2332                }
2333
2334             size_t iAdded;
2335             if ((iAdded = AfsClass_AdminList_AddEntry (lpList, szAdmin)) != (size_t)-1)
2336                {
2337                lpList->aEntries[ iAdded ].fAdded = FALSE;
2338                }
2339             }
2340
2341          WORKERPACKET wpDone;
2342          wpDone.wpBosAdminGetDone.hEnum = wpBegin.wpBosAdminGetBegin.hEnum;
2343          Worker_DoTask (wtaskBosAdminGetDone, &wpDone);
2344          }
2345       }
2346
2347    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2348       {
2349       lpServer->CloseBosObject();
2350       lpServer->Close();
2351       }
2352
2353    NOTIFYCALLBACK::SendNotificationToAll (evtAdminListLoadEnd, lpiServer, status);
2354    AfsClass_Leave();
2355
2356    if (pStatus && !rc)
2357       *pStatus = status;
2358    return (rc) ? lpList : NULL;
2359 }
2360
2361
2362 LPADMINLIST AfsClass_AdminList_Copy (LPADMINLIST lpOld)
2363 {
2364    LPADMINLIST lpNew = NULL;
2365
2366    if (lpOld)
2367       {
2368       lpNew = New(ADMINLIST);
2369       memcpy (lpNew, lpOld, sizeof(ADMINLIST));
2370
2371       lpNew->cRef = 1;
2372       lpNew->aEntries = 0;
2373       lpNew->cEntries = 0;
2374
2375       if (REALLOC (lpNew->aEntries, lpNew->cEntries, lpOld->cEntries, cREALLOC_ADMINLISTENTRIES))
2376          {
2377          size_t cb = lpOld->cEntries * sizeof(ADMINLISTENTRY);
2378          memcpy (lpNew->aEntries, lpOld->aEntries, cb);
2379          }
2380       }
2381
2382    return lpNew;
2383 }
2384
2385
2386 BOOL AfsClass_AdminList_Save (LPADMINLIST lpList, ULONG *pStatus)
2387 {
2388    BOOL rc = TRUE;
2389    ULONG status;
2390
2391    AfsClass_Enter();
2392    NOTIFYCALLBACK::SendNotificationToAll (evtAdminListSaveBegin, lpList->lpiServer);
2393
2394    PVOID hCell;
2395    PVOID hBOS;
2396    LPSERVER lpServer;
2397    if ((lpServer = lpList->lpiServer->OpenServer (&status)) == NULL)
2398       rc = FALSE;
2399    else
2400       {
2401       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2402          rc = FALSE;
2403       lpServer->Close();
2404       }
2405
2406    if (rc)
2407       {
2408       for (size_t iEntry = 0; iEntry < lpList->cEntries; ++iEntry)
2409          {
2410          if (!lpList->aEntries[ iEntry ].szAdmin[0])
2411             continue;
2412
2413          // are we supposed to add this entry?
2414          //
2415          if (lpList->aEntries[ iEntry ].fAdded && !lpList->aEntries[ iEntry ].fDeleted)
2416             {
2417             WORKERPACKET wp;
2418             wp.wpBosAdminCreate.hServer = hBOS;
2419             wp.wpBosAdminCreate.pszAdmin = lpList->aEntries[ iEntry ].szAdmin;
2420
2421             ULONG thisstatus;
2422             if (!Worker_DoTask (wtaskBosAdminCreate, &wp, &thisstatus))
2423                {
2424                rc = FALSE;
2425                status = thisstatus;
2426                }
2427             else
2428                {
2429                lpList->aEntries[ iEntry ].fAdded = FALSE;
2430                }
2431             }
2432
2433          // are we supposed to delete this entry?
2434          //
2435          if (!lpList->aEntries[ iEntry ].fAdded && lpList->aEntries[ iEntry ].fDeleted)
2436             {
2437             WORKERPACKET wp;
2438             wp.wpBosAdminDelete.hServer = hBOS;
2439             wp.wpBosAdminDelete.pszAdmin = lpList->aEntries[ iEntry ].szAdmin;
2440
2441             ULONG thisstatus;
2442             if (!Worker_DoTask (wtaskBosAdminDelete, &wp, &thisstatus))
2443                {
2444                rc = FALSE;
2445                status = thisstatus;
2446                }
2447             else
2448                {
2449                lpList->aEntries[ iEntry ].szAdmin[0] = TEXT('\0');
2450                lpList->aEntries[ iEntry ].fDeleted = FALSE;
2451                }
2452             }
2453          }
2454       }
2455
2456    if ((lpServer = lpList->lpiServer->OpenServer (&status)) != NULL)
2457       {
2458       lpServer->CloseBosObject();
2459       lpServer->Close();
2460       }
2461
2462    NOTIFYCALLBACK::SendNotificationToAll (evtAdminListSaveEnd, lpList->lpiServer, status);
2463    AfsClass_Leave();
2464
2465    if (pStatus && !rc)
2466       *pStatus = status;
2467    return rc;
2468 }
2469
2470
2471 void AfsClass_AdminList_Free (LPADMINLIST lpList)
2472 {
2473    if (lpList && !InterlockedDecrement (&lpList->cRef))
2474       {
2475       if (lpList->aEntries)
2476          Free (lpList->aEntries);
2477       memset (lpList, 0x00, sizeof(ADMINLIST));
2478       Delete (lpList);
2479       }
2480 }
2481
2482
2483 size_t AfsClass_AdminList_AddEntry (LPADMINLIST lpList, LPTSTR pszAdmin)
2484 {
2485    size_t iAdded = (size_t)-1;
2486
2487    if (lpList)
2488       {
2489       for (size_t iEntry = 0; iEntry < lpList->cEntries; ++iEntry)
2490          {
2491          if (!lpList->aEntries[ iEntry ].szAdmin[0])
2492             break;
2493          }
2494       if (iEntry >= lpList->cEntries)
2495          {
2496          (void)REALLOC (lpList->aEntries, lpList->cEntries, 1+iEntry, cREALLOC_ADMINLISTENTRIES);
2497          }
2498       if (iEntry < lpList->cEntries)
2499          {
2500          iAdded = iEntry;
2501          lstrcpy (lpList->aEntries[ iAdded ].szAdmin, pszAdmin);
2502          lpList->aEntries[ iAdded ].fAdded = TRUE;
2503          lpList->aEntries[ iAdded ].fDeleted = FALSE;
2504          }
2505       }
2506
2507    return iAdded;
2508 }
2509
2510
2511 BOOL AfsClass_AdminList_DelEntry (LPADMINLIST lpList, size_t iIndex)
2512 {
2513    BOOL rc = FALSE;
2514
2515    if ( lpList &&
2516         (iIndex < lpList->cEntries) &&
2517         (lpList->aEntries[ iIndex ].szAdmin[0]) &&
2518         (!lpList->aEntries[ iIndex ].fDeleted) )
2519       {
2520       if (lpList->aEntries[ iIndex ].fAdded)
2521          lpList->aEntries[ iIndex ].szAdmin[0] = TEXT('\0');
2522       else
2523          lpList->aEntries[ iIndex ].fDeleted = TRUE;
2524
2525       rc = TRUE;
2526       }
2527
2528    return rc;
2529 }
2530
2531
2532 LPKEYLIST AfsClass_KeyList_Load (LPIDENT lpiServer, ULONG *pStatus)
2533 {
2534    BOOL rc = TRUE;
2535    ULONG status;
2536    LPKEYLIST lpList = NULL;
2537
2538    AfsClass_Enter();
2539    NOTIFYCALLBACK::SendNotificationToAll (evtKeyListLoadBegin, lpiServer);
2540
2541    PVOID hCell;
2542    PVOID hBOS;
2543    LPSERVER lpServer;
2544    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2545       rc = FALSE;
2546    else
2547       {
2548       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2549          rc = FALSE;
2550       lpServer->Close();
2551       }
2552
2553    if (rc)
2554       {
2555       lpList = New(KEYLIST);
2556       memset (lpList, 0x00, sizeof(KEYLIST));
2557       lpList->lpiServer = lpiServer;
2558
2559       WORKERPACKET wpBegin;
2560       wpBegin.wpBosKeyGetBegin.hServer = hBOS;
2561       if (!Worker_DoTask (wtaskBosKeyGetBegin, &wpBegin, &status))
2562          rc = FALSE;
2563       else
2564          {
2565          for (size_t iEnum = 0; ; ++iEnum)
2566             {
2567             WORKERPACKET wpNext;
2568             wpNext.wpBosKeyGetNext.hEnum = wpBegin.wpBosKeyGetBegin.hEnum;
2569
2570             if (!Worker_DoTask (wtaskBosKeyGetNext, &wpNext, &status))
2571                {
2572                if (status == ADMITERATORDONE)
2573                   status = 0;
2574                else
2575                   rc = FALSE;
2576                break;
2577                }
2578
2579             if (REALLOC (lpList->aKeys, lpList->cKeys, 1+iEnum, cREALLOC_SERVERKEYS))
2580                {
2581                lpList->aKeys[ iEnum ].keyVersion = wpNext.wpBosKeyGetNext.keyVersion;
2582                memcpy (&lpList->aKeys[ iEnum ].keyData, &wpNext.wpBosKeyGetNext.keyData, sizeof(ENCRYPTIONKEY));
2583                memcpy (&lpList->aKeys[ iEnum ].keyInfo, &wpNext.wpBosKeyGetNext.keyInfo, sizeof(ENCRYPTIONKEYINFO));
2584                }
2585             }
2586
2587          WORKERPACKET wpDone;
2588          wpDone.wpBosKeyGetDone.hEnum = wpBegin.wpBosKeyGetBegin.hEnum;
2589          Worker_DoTask (wtaskBosKeyGetDone, &wpDone);
2590          }
2591       }
2592
2593    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2594       {
2595       lpServer->CloseBosObject();
2596       lpServer->Close();
2597       }
2598
2599    NOTIFYCALLBACK::SendNotificationToAll (evtKeyListLoadEnd, lpiServer, status);
2600    AfsClass_Leave();
2601
2602    if (pStatus && !rc)
2603       *pStatus = status;
2604    return (rc) ? lpList : NULL;
2605 }
2606
2607
2608 void AfsClass_KeyList_Free (LPKEYLIST lpList)
2609 {
2610    if (lpList)
2611       {
2612       if (lpList->aKeys)
2613          Free (lpList->aKeys);
2614       memset (lpList, 0x00, sizeof(KEYLIST));
2615       Delete (lpList);
2616       }
2617 }
2618
2619
2620 BOOL AfsClass_AddKey (LPIDENT lpiServer, int keyVersion, LPTSTR pszString, ULONG *pStatus)
2621 {
2622    BOOL rc = TRUE;
2623    ULONG status = 0;
2624
2625    TCHAR szCell[ cchNAME ];
2626    lpiServer->GetCellName (szCell);
2627
2628    WORKERPACKET wp;
2629    wp.wpKasStringToKey.pszCell = szCell;
2630    wp.wpKasStringToKey.pszString = pszString;
2631    if (!Worker_DoTask (wtaskKasStringToKey, &wp, &status))
2632       {
2633       rc = FALSE;
2634       }
2635    else if (!AfsClass_AddKey (lpiServer, keyVersion, &wp.wpKasStringToKey.key, &status))
2636       {
2637       rc = FALSE;
2638       }
2639
2640    if (pStatus && !rc)
2641       *pStatus = status;
2642    return rc;
2643 }
2644
2645
2646 BOOL AfsClass_AddKey (LPIDENT lpiServer, int keyVersion, LPENCRYPTIONKEY pKey, ULONG *pStatus)
2647 {
2648    BOOL rc = TRUE;
2649    ULONG status = 0;
2650
2651    PVOID hCell;
2652    PVOID hBOS;
2653    LPSERVER lpServer;
2654    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2655       rc = FALSE;
2656    else
2657       {
2658       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2659          rc = FALSE;
2660       lpServer->Close();
2661       }
2662
2663    if (rc)
2664       {
2665       WORKERPACKET wp;
2666       wp.wpBosKeyCreate.hServer = hBOS;
2667       wp.wpBosKeyCreate.keyVersion = keyVersion;
2668       memcpy (&wp.wpBosKeyCreate.key, pKey, sizeof(ENCRYPTIONKEY));
2669       rc = Worker_DoTask (wtaskBosKeyCreate, &wp, &status);
2670       }
2671
2672    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2673       {
2674       lpServer->CloseBosObject();
2675       lpServer->Close();
2676       }
2677
2678    if (pStatus && !rc)
2679       *pStatus = status;
2680    return rc;
2681 }
2682
2683
2684 BOOL AfsClass_DeleteKey (LPIDENT lpiServer, int keyVersion, ULONG *pStatus)
2685 {
2686    BOOL rc = TRUE;
2687    ULONG status = 0;
2688
2689    PVOID hCell;
2690    PVOID hBOS;
2691    LPSERVER lpServer;
2692    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
2693       rc = FALSE;
2694    else
2695       {
2696       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
2697          rc = FALSE;
2698       lpServer->Close();
2699       }
2700
2701    if (rc)
2702       {
2703       WORKERPACKET wp;
2704       wp.wpBosKeyDelete.hServer = hBOS;
2705       wp.wpBosKeyDelete.keyVersion = keyVersion;
2706       rc = Worker_DoTask (wtaskBosKeyDelete, &wp, &status);
2707       }
2708
2709    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
2710       {
2711       lpServer->CloseBosObject();
2712       lpServer->Close();
2713       }
2714
2715    if (pStatus && !rc)
2716       *pStatus = status;
2717    return rc;
2718 }
2719
2720
2721 BOOL AfsClass_GetRandomKey (LPIDENT lpi, LPENCRYPTIONKEY pKey, ULONG *pStatus)
2722 {
2723    BOOL rc = TRUE;
2724    ULONG status = 0;
2725
2726    PVOID hCell;
2727    PVOID hKAS;
2728    LPCELL lpCell;
2729    if ((lpCell = lpi->OpenCell (&status)) == NULL)
2730       rc = FALSE;
2731    else
2732       {
2733       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
2734          rc = FALSE;
2735       else
2736          hKAS = lpCell->GetKasObject (&status);
2737       lpCell->Close();
2738       }
2739
2740    if (rc)
2741       {
2742       WORKERPACKET wp;
2743       wp.wpKasServerRandomKeyGet.hCell = hCell;
2744       wp.wpKasServerRandomKeyGet.hServer = hKAS;
2745       rc = Worker_DoTask (wtaskKasServerRandomKeyGet, &wp, &status);
2746
2747       if (rc)
2748          memcpy (pKey, &wp.wpKasServerRandomKeyGet.key, sizeof(ENCRYPTIONKEY));
2749       }
2750
2751    if (pStatus && !rc)
2752       *pStatus = status;
2753    return rc;
2754 }
2755
2756
2757 BOOL AfsClass_Clone (LPIDENT lpiRW, ULONG *pStatus)
2758 {
2759    BOOL rc = TRUE;
2760    ULONG status;
2761
2762    AfsClass_Enter();
2763    NOTIFYCALLBACK::SendNotificationToAll (evtCloneBegin, lpiRW, 0);
2764
2765    // Obtain hCell
2766    //
2767    PVOID hCell;
2768    LPCELL lpCell;
2769    if ((lpCell = lpiRW->OpenCell (&status)) == NULL)
2770       rc = FALSE;
2771    else
2772       {
2773       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
2774          rc = FALSE;
2775       lpCell->Close();
2776       }
2777
2778    // Perform the actual operation
2779    //
2780    if (rc)
2781       {
2782       WORKERPACKET wp;
2783       wp.wpVosBackupVolumeCreate.hCell = hCell;
2784       lpiRW->GetFilesetID (&wp.wpVosBackupVolumeCreate.idVolume);
2785
2786       AfsClass_Leave();
2787       rc = Worker_DoTask (wtaskVosBackupVolumeCreate, &wp, &status);
2788       AfsClass_Enter();
2789       }
2790
2791    // Clean up
2792    //
2793    if (rc)
2794       {
2795       LPSERVER lpServer;
2796       if ((lpServer = lpiRW->OpenServer (&status)) == NULL)
2797          rc = FALSE;
2798       else
2799          {
2800          lpServer->Invalidate();
2801          rc = lpServer->RefreshAll (&status);
2802          lpServer->Close();
2803          }
2804       }
2805
2806    NOTIFYCALLBACK::SendNotificationToAll (evtCloneEnd, lpiRW, status);
2807    AfsClass_Leave();
2808
2809    if (pStatus && !rc)
2810       *pStatus = status;
2811    return rc;
2812 }
2813
2814
2815 BOOL AfsClass_CloneMultiple (LPIDENT lpi, LPTSTR pszPrefix, BOOL fExclude, ULONG *pStatus)
2816 {
2817    BOOL rc = TRUE;
2818    ULONG status;
2819
2820    AfsClass_Enter();
2821    NOTIFYCALLBACK::SendNotificationToAll (evtCloneMultipleBegin, lpi);
2822
2823    // Obtain hCell
2824    //
2825    PVOID hCell;
2826    LPCELL lpCell;
2827    if ((lpCell = lpi->OpenCell (&status)) == NULL)
2828       rc = FALSE;
2829    else
2830       {
2831       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
2832          rc = FALSE;
2833       lpCell->Close();
2834       }
2835
2836    // Obtain hServer if appropriate
2837    //
2838    PVOID hVOS = NULL;
2839    if (!lpi->fIsCell())
2840       {
2841       LPSERVER lpServer;
2842       if ((lpServer = lpi->OpenServer (&status)) == NULL)
2843          rc = FALSE;
2844       else
2845          {
2846          if ((hVOS = lpServer->OpenVosObject (NULL, &status)) == NULL)
2847             rc = FALSE;
2848          lpServer->Close();
2849          }
2850       }
2851
2852    // If requested, obtain the appropriate aggregate ID
2853    //
2854    int idPartition = NO_PARTITION;
2855    if (rc && (lpi->fIsFileset() || lpi->fIsAggregate()))
2856       {
2857       LPAGGREGATE lpAggregate;
2858       if ((lpAggregate = lpi->OpenAggregate (&status)) == NULL)
2859          rc = FALSE;
2860       else
2861          {
2862          if ((idPartition = lpAggregate->GetID()) == NO_PARTITION)
2863             rc = FALSE;
2864          lpAggregate->Close();
2865          }
2866       }
2867
2868    // Perform the actual operation
2869    //
2870    if (rc)
2871       {
2872       WORKERPACKET wp;
2873       wp.wpVosBackupVolumeCreateMultiple.hCell = hCell;
2874       wp.wpVosBackupVolumeCreateMultiple.hServer = hVOS;
2875       wp.wpVosBackupVolumeCreateMultiple.idPartition = idPartition;
2876       wp.wpVosBackupVolumeCreateMultiple.pszPrefix = pszPrefix;
2877       wp.wpVosBackupVolumeCreateMultiple.fExclude = fExclude;
2878
2879       AfsClass_Leave();
2880       rc = Worker_DoTask (wtaskVosBackupVolumeCreateMultiple, &wp, &status);
2881       AfsClass_Enter();
2882       }
2883
2884    // Clean up
2885    //
2886    if (rc)
2887       {
2888       if (lpi->fIsCell())
2889          {
2890          LPCELL lpCell;
2891          if ((lpCell = lpi->OpenCell (&status)) == NULL)
2892             rc = FALSE;
2893          else
2894             {
2895             lpCell->Invalidate();
2896             rc = lpCell->RefreshAll (&status);
2897             lpCell->Close();
2898             }
2899          }
2900       else
2901          {
2902          LPSERVER lpServer;
2903          if ((lpServer = lpi->OpenServer (&status)) == NULL)
2904             rc = FALSE;
2905          else
2906             {
2907             lpServer->Invalidate();
2908             rc = lpServer->RefreshAll (&status);
2909             lpServer->Close();
2910             }
2911          }
2912       }
2913
2914    if (hVOS)
2915       {
2916       LPSERVER lpServer;
2917       if ((lpServer = lpi->OpenServer (&status)) != NULL)
2918          {
2919          lpServer->CloseVosObject();
2920          lpServer->Close();
2921          }
2922       }
2923
2924    NOTIFYCALLBACK::SendNotificationToAll (evtCloneMultipleEnd, lpi, status);
2925    AfsClass_Leave();
2926
2927    if (pStatus && !rc)
2928       *pStatus = status;
2929    return rc;
2930 }
2931
2932
2933 BOOL AfsClass_DumpFileset (LPIDENT lpi, LPTSTR pszFilename, LPSYSTEMTIME pstDate, ULONG *pStatus)
2934 {
2935    BOOL rc = TRUE;
2936    ULONG status;
2937
2938    AfsClass_Enter();
2939    NOTIFYCALLBACK::SendNotificationToAll (evtDumpFilesetBegin, lpi, pszFilename, 0);
2940
2941    // Obtain hCell and hVOS
2942    //
2943    PVOID hCell;
2944    PVOID hVOS = NULL;
2945    LPSERVER lpServer;
2946    if ((lpServer = lpi->OpenServer (&status)) == NULL)
2947       rc = FALSE;
2948    else
2949       {
2950       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
2951          rc = FALSE;
2952       lpServer->Close();
2953       }
2954
2955    // Obtain idPartition
2956    //
2957    int idPartition;
2958    LPAGGREGATE lpAggregate;
2959    if ((lpAggregate = lpi->OpenAggregate (&status)) == NULL)
2960       rc = FALSE;
2961    else
2962       {
2963       idPartition = lpAggregate->GetID();
2964       lpAggregate->Close();
2965       }
2966
2967    // Perform the actual operation
2968    //
2969    if (rc)
2970       {
2971       WORKERPACKET wp;
2972       wp.wpVosVolumeDump.hCell = hCell;
2973       wp.wpVosVolumeDump.hServer = hVOS;
2974       wp.wpVosVolumeDump.pszFilename = pszFilename;
2975       wp.wpVosVolumeDump.idPartition = idPartition;
2976       lpi->GetFilesetID (&wp.wpVosVolumeDump.idVolume);
2977
2978       if (pstDate)
2979          memcpy (&wp.wpVosVolumeDump.stStart, pstDate, sizeof(SYSTEMTIME));
2980       else
2981          memset (&wp.wpVosVolumeDump.stStart, 0x00, sizeof(SYSTEMTIME));
2982
2983       AfsClass_Leave();
2984       rc = Worker_DoTask (wtaskVosVolumeDump, &wp, &status);
2985       AfsClass_Enter();
2986       }
2987
2988    NOTIFYCALLBACK::SendNotificationToAll (evtDumpFilesetEnd, lpi, pszFilename, status);
2989    AfsClass_Leave();
2990
2991    if (hVOS)
2992       {
2993       LPSERVER lpServer;
2994       if ((lpServer = lpi->OpenServer (&status)) != NULL)
2995          {
2996          lpServer->CloseVosObject();
2997          lpServer->Close();
2998          }
2999       }
3000
3001    if (pStatus && !rc)
3002       *pStatus = status;
3003    return rc;
3004 }
3005
3006
3007 BOOL AfsClass_RestoreFileset (LPIDENT lpi, LPTSTR pszFileset, LPTSTR pszFilename, BOOL fIncremental, ULONG *pStatus)
3008 {
3009    BOOL rc = TRUE;
3010    ULONG status;
3011
3012    AfsClass_Enter();
3013    NOTIFYCALLBACK::SendNotificationToAll (evtRestoreFilesetBegin, lpi, NULL, pszFileset, pszFilename, 0, 0);
3014
3015    // Obtain hCell and hVOS
3016    //
3017    PVOID hCell;
3018    PVOID hVOS = NULL;
3019    LPSERVER lpServer;
3020    if ((lpServer = lpi->OpenServer (&status)) == NULL)
3021       rc = FALSE;
3022    else
3023       {
3024       if ((hVOS = lpServer->OpenVosObject (&hCell, &status)) == NULL)
3025          rc = FALSE;
3026       lpServer->Close();
3027       }
3028
3029    // Obtain idPartition
3030    //
3031    int idPartition;
3032    LPAGGREGATE lpAggregate;
3033    if ((lpAggregate = lpi->OpenAggregate (&status)) == NULL)
3034       rc = FALSE;
3035    else
3036       {
3037       idPartition = lpAggregate->GetID();
3038       lpAggregate->Close();
3039       }
3040
3041    // Perform the actual operation
3042    //
3043    if (rc)
3044       {
3045       WORKERPACKET wp;
3046       wp.wpVosVolumeRestore.hCell = hCell;
3047       wp.wpVosVolumeRestore.hServer = hVOS;
3048       wp.wpVosVolumeRestore.idPartition = idPartition;
3049       wp.wpVosVolumeRestore.pszVolume = pszFileset;
3050       wp.wpVosVolumeRestore.pszFilename = pszFilename;
3051       wp.wpVosVolumeRestore.fIncremental = fIncremental;
3052
3053       if (lpi->fIsFileset())
3054          lpi->GetFilesetID (&wp.wpVosVolumeRestore.idVolume);
3055       else
3056          wp.wpVosVolumeRestore.idVolume = NO_VOLUME;
3057
3058       AfsClass_Leave();
3059       rc = Worker_DoTask (wtaskVosVolumeRestore, &wp, &status);
3060       AfsClass_Enter();
3061       }
3062
3063    // Clean up
3064    //
3065    if (rc)
3066       {
3067       if ((lpServer = lpi->OpenServer (&status)) == NULL)
3068          rc = FALSE;
3069       else
3070          {
3071          lpServer->Invalidate();
3072          rc = lpServer->RefreshAll (&status);
3073          lpServer->Close();
3074          }
3075       }
3076
3077    if (hVOS)
3078       {
3079       if ((lpServer = lpi->OpenServer (&status)) != NULL)
3080          {
3081          lpServer->CloseVosObject();
3082          lpServer->Close();
3083          }
3084       }
3085
3086    NOTIFYCALLBACK::SendNotificationToAll (evtRestoreFilesetEnd, lpi, NULL, pszFileset, pszFilename, 0, status);
3087    AfsClass_Leave();
3088
3089    if (pStatus && !rc)
3090       *pStatus = status;
3091    return rc;
3092 }
3093
3094
3095 BOOL AfsClass_GetRestartTimes (LPIDENT lpiServer, BOOL *pfWeekly, LPSYSTEMTIME pstWeekly, BOOL *pfDaily, LPSYSTEMTIME pstDaily, ULONG *pStatus)
3096 {
3097    BOOL rc = TRUE;
3098    ULONG status;
3099
3100    AfsClass_Enter();
3101    NOTIFYCALLBACK::SendNotificationToAll (evtGetRestartTimesBegin, lpiServer);
3102
3103    PVOID hCell;
3104    PVOID hBOS;
3105    LPSERVER lpServer;
3106    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
3107       rc = FALSE;
3108    else
3109       {
3110       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
3111          rc = FALSE;
3112       lpServer->Close();
3113       }
3114
3115    if (rc)
3116       {
3117       WORKERPACKET wp;
3118       wp.wpBosExecutableRestartTimeGet.hServer = hBOS;
3119
3120       AfsClass_Leave();
3121       rc = Worker_DoTask (wtaskBosExecutableRestartTimeGet, &wp, &status);
3122       AfsClass_Enter();
3123
3124       if (rc)
3125          {
3126          *pfWeekly = wp.wpBosExecutableRestartTimeGet.fWeeklyRestart;
3127          *pstWeekly = wp.wpBosExecutableRestartTimeGet.timeWeekly;
3128          *pfDaily = wp.wpBosExecutableRestartTimeGet.fDailyRestart;
3129          *pstDaily = wp.wpBosExecutableRestartTimeGet.timeDaily;
3130          }
3131       }
3132
3133    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
3134       {
3135       lpServer->CloseBosObject();
3136       lpServer->Close();
3137       }
3138
3139    NOTIFYCALLBACK::SendNotificationToAll (evtGetRestartTimesEnd, lpiServer, status);
3140    AfsClass_Leave();
3141
3142    if (pStatus && !rc)
3143       *pStatus = status;
3144    return rc;
3145 }
3146
3147
3148 BOOL AfsClass_SetRestartTimes (LPIDENT lpiServer, LPSYSTEMTIME pstWeekly, LPSYSTEMTIME pstDaily, ULONG *pStatus)
3149 {
3150    BOOL rc = TRUE;
3151    ULONG status;
3152
3153    AfsClass_Enter();
3154    NOTIFYCALLBACK::SendNotificationToAll (evtSetRestartTimesBegin, lpiServer);
3155
3156    PVOID hCell;
3157    PVOID hBOS;
3158    LPSERVER lpServer;
3159    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
3160       rc = FALSE;
3161    else
3162       {
3163       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
3164          rc = FALSE;
3165       lpServer->Close();
3166       }
3167
3168    if (rc)
3169       {
3170       SYSTEMTIME timeNever;
3171       memset (&timeNever, 0x00, sizeof(SYSTEMTIME));
3172
3173       WORKERPACKET wp;
3174       wp.wpBosExecutableRestartTimeSet.hServer = hBOS;
3175       wp.wpBosExecutableRestartTimeSet.fWeeklyRestart = (pstWeekly != NULL) ? TRUE : FALSE;
3176       wp.wpBosExecutableRestartTimeSet.timeWeekly = (pstWeekly != NULL) ? *pstWeekly : timeNever;
3177       wp.wpBosExecutableRestartTimeSet.fDailyRestart = (pstDaily != NULL) ? TRUE : FALSE;
3178       wp.wpBosExecutableRestartTimeSet.timeDaily = (pstDaily != NULL) ? *pstDaily : timeNever;
3179
3180       AfsClass_Leave();
3181       rc = Worker_DoTask (wtaskBosExecutableRestartTimeSet, &wp, &status);
3182       AfsClass_Enter();
3183       }
3184
3185    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
3186       {
3187       lpServer->CloseBosObject();
3188       lpServer->Close();
3189       }
3190
3191    NOTIFYCALLBACK::SendNotificationToAll (evtSetRestartTimesEnd, lpiServer, status);
3192    AfsClass_Leave();
3193
3194    if (pStatus && !rc)
3195       *pStatus = status;
3196    return rc;
3197 }
3198
3199
3200 BOOL AfsClass_MoveReplica (LPIDENT lpiReplica, LPIDENT lpiAggregateTarget, ULONG *pStatus)
3201 {
3202    BOOL rc = TRUE;
3203
3204    // Find the identifier for this replica's read/write fileset.
3205    //
3206    LPIDENT lpiFilesetRW = NULL;
3207    LPFILESET lpFileset;
3208    if ((lpFileset = lpiReplica->OpenFileset (pStatus)) == NULL)
3209       rc = FALSE;
3210    else
3211       {
3212       if ((lpiFilesetRW = lpFileset->GetReadWriteIdentifier (pStatus)) == NULL)
3213          rc = FALSE;
3214       lpFileset->Close();
3215       }
3216
3217    // If the fileset replica currently resides on the same server
3218    // as the target aggregate, we'll follow the following steps:
3219    //
3220    // 1. Delete the old fileset replica -> on error, quit
3221    // 2. Create the new fileset replica -> on error, recreate old replica, quit
3222    //
3223    // If the fileset replica instead currently resides on a different
3224    // server, we can follow the preferred steps:
3225    //
3226    // 1. Create the new fileset replica -> on error, quit
3227    // 2. Delete the old fileset replica -> on error, delete the new replica, quit
3228    //
3229    if (rc)
3230       {
3231       LPIDENT lpiReplicaNew;
3232
3233       if (lpiReplica->GetServer() == lpiAggregateTarget->GetServer())
3234          {
3235          LPIDENT lpiAggregateOriginal = lpiReplica->GetAggregate();
3236
3237          if (!AfsClass_DeleteReplica (lpiReplica, pStatus))
3238             {
3239             rc = FALSE;
3240             }
3241          else if ((lpiReplicaNew = AfsClass_CreateReplica (lpiFilesetRW, lpiAggregateTarget, pStatus)) == NULL)
3242             {
3243             (void)AfsClass_CreateReplica (lpiFilesetRW, lpiAggregateOriginal);
3244             rc = FALSE;
3245             }
3246          }
3247       else // different server?
3248          {
3249          if ((lpiReplicaNew = AfsClass_CreateReplica (lpiFilesetRW, lpiAggregateTarget, pStatus)) == NULL)
3250             {
3251             rc = FALSE;
3252             }
3253          else if (!AfsClass_DeleteReplica (lpiReplica, pStatus))
3254             {
3255             (void)AfsClass_DeleteReplica (lpiReplicaNew, pStatus);
3256             rc = FALSE;
3257             }
3258          }
3259       }
3260
3261    return rc;
3262 }
3263
3264
3265 BOOL AfsClass_Salvage (LPIDENT lpiSalvage, LPTSTR *ppszLogData, int nProcesses, LPTSTR pszTempDir, LPTSTR pszLogFile, BOOL fForce, BOOL fReadonly, BOOL fLogInodes, BOOL fLogRootInodes, BOOL fRebuildDirs, BOOL fReadBlocks, ULONG *pStatus)
3266 {
3267    BOOL rc = TRUE;
3268    ULONG status;
3269
3270    AfsClass_Enter();
3271    NOTIFYCALLBACK::SendNotificationToAll (evtSalvageBegin, lpiSalvage);
3272
3273    PVOID hCell;
3274    PVOID hBOS;
3275    LPSERVER lpServer;
3276    if ((lpServer = lpiSalvage->OpenServer (&status)) == NULL)
3277       rc = FALSE;
3278    else
3279       {
3280       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
3281          rc = FALSE;
3282       lpServer->Close();
3283       }
3284
3285    if (ppszLogData)
3286       *ppszLogData = NULL;
3287
3288    // Step one: perform the actual salvage. This will dump a log file onto
3289    // the target computer.
3290    //
3291    if (rc)
3292       {
3293       LPTSTR pszAggregate = NULL;
3294       TCHAR szAggregate[ cchNAME ];
3295       if (lpiSalvage->fIsAggregate() || lpiSalvage->fIsFileset())
3296          {
3297          lpiSalvage->GetAggregateName (szAggregate);
3298          pszAggregate = szAggregate;
3299          }
3300
3301       LPTSTR pszFileset = NULL;
3302       TCHAR szFileset[ cchNAME ];
3303       if (lpiSalvage->fIsFileset())
3304          {
3305          VOLUMEID vid;
3306          lpiSalvage->GetFilesetID (&vid);
3307          wsprintf (szFileset, TEXT("%lu"), vid);
3308          pszFileset = szFileset;
3309          }
3310
3311       if (pszLogFile == NULL)
3312          pszLogFile = TEXT("SalvageLog");
3313
3314       WORKERPACKET wp;
3315       wp.wpBosSalvage.hCell = hCell;
3316       wp.wpBosSalvage.hServer = hBOS;
3317       wp.wpBosSalvage.pszAggregate = pszAggregate;
3318       wp.wpBosSalvage.pszFileset = pszFileset;
3319       wp.wpBosSalvage.nProcesses = nProcesses;
3320       wp.wpBosSalvage.pszTempDir = pszTempDir;
3321       wp.wpBosSalvage.pszLogFile = pszLogFile;
3322       wp.wpBosSalvage.fForce = fForce;
3323       wp.wpBosSalvage.fReadonly = fReadonly;
3324       wp.wpBosSalvage.fLogInodes = fLogInodes;
3325       wp.wpBosSalvage.fLogRootInodes = fLogRootInodes;
3326       wp.wpBosSalvage.fRebuildDirs = fRebuildDirs;
3327       wp.wpBosSalvage.fReadBlocks = fReadBlocks;
3328
3329       AfsClass_Leave();
3330       rc = Worker_DoTask (wtaskBosSalvage, &wp, &status);
3331       AfsClass_Enter();
3332       }
3333
3334    // Step two: retrieve the log file from that salvage operation.
3335    // If we can't get the log file back, that's not fatal--just return
3336    // a NULL pointer for the log data.
3337    //
3338    if (rc && ppszLogData)
3339       {
3340       WORKERPACKET wp;
3341       wp.wpBosLogGet.hServer = hBOS;
3342       wp.wpBosLogGet.pszLogName = pszLogFile;
3343       wp.wpBosLogGet.pszLogData = NULL;
3344
3345       AfsClass_Leave();
3346       if ((rc = Worker_DoTask (wtaskBosLogGet, &wp, &status)) == TRUE)
3347          {
3348          // Okay, well, we have the log in memory now. Problem is,
3349          // it has UNIX-style CR's... and so is missing the LF which
3350          // PCs expect before each CR.  Wow--look at all the
3351          // acronyms!  Count the CRs, alloc a larger buffer, and stuff
3352          // in the LFs before each CR.
3353          //
3354          size_t cchRequired = 1;
3355          for (LPTSTR pchIn = wp.wpBosLogGet.pszLogData; *pchIn; ++pchIn)
3356             {
3357             cchRequired += (*pchIn == TEXT('\r')) ? 0 : (*pchIn == TEXT('\n')) ? 2 : 1;
3358             }
3359
3360          if ((*ppszLogData = AllocateString (cchRequired)) != NULL)
3361             {
3362             LPTSTR pszOut = *ppszLogData;
3363             for (LPTSTR pchIn = wp.wpBosLogGet.pszLogData; *pchIn; ++pchIn)
3364                {
3365                if (*pchIn == TEXT('\n'))
3366                   *pszOut++ = TEXT('\r');
3367                if (*pchIn != TEXT('\r'))
3368                   *pszOut++ = *pchIn;
3369                }
3370             *pszOut++ = TEXT('\0');
3371             }
3372          }
3373       AfsClass_Enter();
3374       }
3375
3376    if ((lpServer = lpiSalvage->OpenServer (&status)) != NULL)
3377       {
3378       lpServer->CloseBosObject();
3379       lpServer->Close();
3380       }
3381
3382    NOTIFYCALLBACK::SendNotificationToAll (evtSalvageEnd, lpiSalvage, status);
3383    AfsClass_Leave();
3384
3385    if (pStatus && !rc)
3386       *pStatus = status;
3387    return rc;
3388 }
3389
3390
3391 void AfsClass_FreeSalvageLog (LPTSTR pszLogData)
3392 {
3393    if (pszLogData)
3394       Free (pszLogData);
3395 }
3396
3397
3398 LPHOSTLIST AfsClass_HostList_Load (LPIDENT lpiServer, ULONG *pStatus)
3399 {
3400    BOOL rc = TRUE;
3401    ULONG status;
3402    LPHOSTLIST lpList = NULL;
3403
3404    AfsClass_Enter();
3405    NOTIFYCALLBACK::SendNotificationToAll (evtHostListLoadBegin, lpiServer);
3406
3407    PVOID hCell;
3408    PVOID hBOS;
3409    LPSERVER lpServer;
3410    if ((lpServer = lpiServer->OpenServer (&status)) == NULL)
3411       rc = FALSE;
3412    else
3413       {
3414       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
3415          rc = FALSE;
3416       lpServer->Close();
3417       }
3418
3419    if (rc)
3420       {
3421       lpList = New(HOSTLIST);
3422       memset (lpList, 0x00, sizeof(HOSTLIST));
3423       lpList->cRef = 1;
3424       lpList->lpiServer = lpiServer;
3425
3426       WORKERPACKET wpBegin;
3427       wpBegin.wpBosHostGetBegin.hServer = hBOS;
3428       if (!Worker_DoTask (wtaskBosHostGetBegin, &wpBegin, &status))
3429          rc = FALSE;
3430       else
3431          {
3432          for (;;)
3433             {
3434             TCHAR szHost[ cchNAME ];
3435
3436             WORKERPACKET wpNext;
3437             wpNext.wpBosHostGetNext.hEnum = wpBegin.wpBosHostGetBegin.hEnum;
3438             wpNext.wpBosHostGetNext.pszServer = szHost;
3439
3440             if (!Worker_DoTask (wtaskBosHostGetNext, &wpNext, &status))
3441                {
3442                if (status == ADMITERATORDONE)
3443                   status = 0;
3444                else
3445                   rc = FALSE;
3446                break;
3447                }
3448
3449             size_t iAdded;
3450             if ((iAdded = AfsClass_HostList_AddEntry (lpList, szHost)) != (size_t)-1)
3451                {
3452                lpList->aEntries[ iAdded ].fAdded = FALSE;
3453                }
3454             }
3455
3456          WORKERPACKET wpDone;
3457          wpDone.wpBosHostGetDone.hEnum = wpBegin.wpBosHostGetBegin.hEnum;
3458          Worker_DoTask (wtaskBosHostGetDone, &wpDone);
3459          }
3460       }
3461
3462    if ((lpServer = lpiServer->OpenServer (&status)) != NULL)
3463       {
3464       lpServer->CloseBosObject();
3465       lpServer->Close();
3466       }
3467
3468    NOTIFYCALLBACK::SendNotificationToAll (evtHostListLoadEnd, lpiServer, status);
3469    AfsClass_Leave();
3470
3471    if (pStatus && !rc)
3472       *pStatus = status;
3473    return (rc) ? lpList : NULL;
3474 }
3475
3476
3477 LPHOSTLIST AfsClass_HostList_Copy (LPHOSTLIST lpOld)
3478 {
3479    LPHOSTLIST lpNew = NULL;
3480
3481    if (lpOld)
3482       {
3483       lpNew = New(HOSTLIST);
3484       memcpy (lpNew, lpOld, sizeof(HOSTLIST));
3485
3486       lpNew->cRef = 1;
3487       lpNew->aEntries = 0;
3488       lpNew->cEntries = 0;
3489
3490       if (REALLOC (lpNew->aEntries, lpNew->cEntries, lpOld->cEntries, cREALLOC_HOSTLISTENTRIES))
3491          {
3492          size_t cb = lpOld->cEntries * sizeof(HOSTLISTENTRY);
3493          memcpy (lpNew->aEntries, lpOld->aEntries, cb);
3494          }
3495       }
3496
3497    return lpNew;
3498 }
3499
3500
3501 BOOL AfsClass_HostList_Save (LPHOSTLIST lpList, ULONG *pStatus)
3502 {
3503    BOOL rc = TRUE;
3504    ULONG status;
3505
3506    AfsClass_Enter();
3507    NOTIFYCALLBACK::SendNotificationToAll (evtHostListSaveBegin, lpList->lpiServer);
3508
3509    PVOID hCell;
3510    PVOID hBOS;
3511    LPSERVER lpServer;
3512    if ((lpServer = lpList->lpiServer->OpenServer (&status)) == NULL)
3513       rc = FALSE;
3514    else
3515       {
3516       if ((hBOS = lpServer->OpenBosObject (&hCell, &status)) == NULL)
3517          rc = FALSE;
3518       lpServer->Close();
3519       }
3520
3521    if (rc)
3522       {
3523       for (size_t iEntry = 0; iEntry < lpList->cEntries; ++iEntry)
3524          {
3525          if (!lpList->aEntries[ iEntry ].szHost[0])
3526             continue;
3527
3528          // are we supposed to add this entry?
3529          //
3530          if (lpList->aEntries[ iEntry ].fAdded && !lpList->aEntries[ iEntry ].fDeleted)
3531             {
3532             WORKERPACKET wp;
3533             wp.wpBosHostCreate.hServer = hBOS;
3534             wp.wpBosHostCreate.pszServer = lpList->aEntries[ iEntry ].szHost;
3535
3536             ULONG thisstatus;
3537             if (!Worker_DoTask (wtaskBosHostCreate, &wp, &thisstatus))
3538                {
3539                rc = FALSE;
3540                status = thisstatus;
3541                }
3542             else
3543                {
3544                lpList->aEntries[ iEntry ].fAdded = FALSE;
3545                }
3546             }
3547
3548          // are we supposed to delete this entry?
3549          //
3550          if (!lpList->aEntries[ iEntry ].fAdded && lpList->aEntries[ iEntry ].fDeleted)
3551             {
3552             WORKERPACKET wp;
3553             wp.wpBosHostDelete.hServer = hBOS;
3554             wp.wpBosHostDelete.pszServer = lpList->aEntries[ iEntry ].szHost;
3555
3556             ULONG thisstatus;
3557             if (!Worker_DoTask (wtaskBosHostDelete, &wp, &thisstatus))
3558                {
3559                rc = FALSE;
3560                status = thisstatus;
3561                }
3562             else
3563                {
3564                lpList->aEntries[ iEntry ].szHost[0] = TEXT('\0');
3565                lpList->aEntries[ iEntry ].fDeleted = FALSE;
3566                }
3567             }
3568          }
3569       }
3570
3571    if ((lpServer = lpList->lpiServer->OpenServer (&status)) != NULL)
3572       {
3573       lpServer->CloseBosObject();
3574       lpServer->Close();
3575       }
3576
3577    NOTIFYCALLBACK::SendNotificationToAll (evtHostListSaveEnd, lpList->lpiServer, status);
3578    AfsClass_Leave();
3579
3580    if (pStatus && !rc)
3581       *pStatus = status;
3582    return rc;
3583 }
3584
3585
3586 void AfsClass_HostList_Free (LPHOSTLIST lpList)
3587 {
3588    if (lpList && !InterlockedDecrement (&lpList->cRef))
3589       {
3590       if (lpList->aEntries)
3591          Free (lpList->aEntries);
3592       memset (lpList, 0x00, sizeof(HOSTLIST));
3593       Delete (lpList);
3594       }
3595 }
3596
3597
3598 size_t AfsClass_HostList_AddEntry (LPHOSTLIST lpList, LPTSTR pszHost)
3599 {
3600    size_t iAdded = (size_t)-1;
3601
3602    if (lpList)
3603       {
3604       for (size_t iEntry = 0; iEntry < lpList->cEntries; ++iEntry)
3605          {
3606          if (!lpList->aEntries[ iEntry ].szHost[0])
3607             break;
3608          }
3609       if (iEntry >= lpList->cEntries)
3610          {
3611          (void)REALLOC (lpList->aEntries, lpList->cEntries, 1+iEntry, cREALLOC_HOSTLISTENTRIES);
3612          }
3613       if (iEntry < lpList->cEntries)
3614          {
3615          iAdded = iEntry;
3616          lstrcpy (lpList->aEntries[ iAdded ].szHost, pszHost);
3617          lpList->aEntries[ iAdded ].fAdded = TRUE;
3618          lpList->aEntries[ iAdded ].fDeleted = FALSE;
3619          }
3620       }
3621
3622    return iAdded;
3623 }
3624
3625
3626 BOOL AfsClass_HostList_DelEntry (LPHOSTLIST lpList, size_t iIndex)
3627 {
3628    BOOL rc = FALSE;
3629
3630    if ( lpList &&
3631         (iIndex < lpList->cEntries) &&
3632         (lpList->aEntries[ iIndex ].szHost[0]) &&
3633         (!lpList->aEntries[ iIndex ].fDeleted) )
3634       {
3635       if (lpList->aEntries[ iIndex ].fAdded)
3636          lpList->aEntries[ iIndex ].szHost[0] = TEXT('\0');
3637       else
3638          lpList->aEntries[ iIndex ].fDeleted = TRUE;
3639
3640       rc = TRUE;
3641       }
3642
3643    return rc;
3644 }
3645
3646
3647 BOOL AfsClass_GetPtsProperties (LPIDENT lpiCell, LPPTSPROPERTIES pProperties, ULONG *pStatus)
3648 {
3649    BOOL rc = TRUE;
3650    ULONG status;
3651
3652    memset (pProperties, 0x00, sizeof(PTSPROPERTIES));
3653
3654    // Obtain hCell
3655    //
3656    PVOID hCell;
3657    LPCELL lpCell;
3658    if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
3659       rc = FALSE;
3660    else
3661       {
3662       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
3663          rc = FALSE;
3664       lpCell->Close();
3665       }
3666
3667    // Go get the necessary properties
3668    //
3669    if (rc)
3670       {
3671       WORKERPACKET wp;
3672       wp.wpPtsUserMaxGet.hCell = hCell;
3673
3674       if ((rc = Worker_DoTask (wtaskPtsUserMaxGet, &wp, &status)) == TRUE)
3675          pProperties->idUserMax = wp.wpPtsUserMaxGet.idUserMax;
3676       }
3677
3678    if (rc)
3679       {
3680       WORKERPACKET wp;
3681       wp.wpPtsGroupMaxGet.hCell = hCell;
3682
3683       if ((rc = Worker_DoTask (wtaskPtsGroupMaxGet, &wp, &status)) == TRUE)
3684          pProperties->idGroupMax = wp.wpPtsGroupMaxGet.idGroupMax;
3685       }
3686
3687    if (pStatus && !rc)
3688       *pStatus = status;
3689    return rc;
3690 }
3691
3692
3693 BOOL AfsClass_SetPtsProperties (LPIDENT lpiCell, LPPTSPROPERTIES pProperties, ULONG *pStatus)
3694 {
3695    BOOL rc = TRUE;
3696    ULONG status;
3697
3698    // Obtain hCell
3699    //
3700    PVOID hCell;
3701    LPCELL lpCell;
3702    if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
3703       rc = FALSE;
3704    else
3705       {
3706       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
3707          rc = FALSE;
3708       lpCell->Close();
3709       }
3710
3711    // Modify the specified properties
3712    //
3713    if (rc)
3714       {
3715       WORKERPACKET wp;
3716       wp.wpPtsUserMaxSet.hCell = hCell;
3717       wp.wpPtsUserMaxSet.idUserMax = pProperties->idUserMax;
3718       rc = Worker_DoTask (wtaskPtsUserMaxSet, &wp, &status);
3719       }
3720
3721    if (rc)
3722       {
3723       WORKERPACKET wp;
3724       wp.wpPtsGroupMaxSet.hCell = hCell;
3725       wp.wpPtsGroupMaxSet.idGroupMax = pProperties->idGroupMax;
3726       Worker_DoTask (wtaskPtsGroupMaxSet, &wp, &status);
3727       }
3728
3729    if (pStatus && !rc)
3730       *pStatus = status;
3731    return rc;
3732 }
3733
3734
3735 LPIDENT AfsClass_CreateUser (LPIDENT lpiCell, LPTSTR pszUserName, LPTSTR pszInstance, LPTSTR pszPassword, int idUser, BOOL fCreateKAS, BOOL fCreatePTS, ULONG *pStatus)
3736 {
3737    BOOL rc = TRUE;
3738    ULONG status;
3739
3740    if (pszInstance && !*pszInstance)
3741       pszInstance = NULL;
3742
3743    AfsClass_Enter();
3744    NOTIFYCALLBACK::SendNotificationToAll (evtCreateUserBegin, lpiCell, pszUserName, 0);
3745
3746    // We'll need both hCell and hKAS.
3747    //
3748    PVOID hCell;
3749    PVOID hKAS;
3750    LPCELL lpCell;
3751    if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
3752       rc = FALSE;
3753    else
3754       {
3755       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
3756          rc = FALSE;
3757       else
3758          hKAS = lpCell->GetKasObject (&status);
3759       lpCell->Close();
3760       }
3761
3762    // First try to create a KAS entry.
3763    //
3764    if (rc && fCreateKAS)
3765       {
3766       WORKERPACKET wp;
3767       wp.wpKasPrincipalCreate.hCell = hCell;
3768       wp.wpKasPrincipalCreate.hServer = hKAS;
3769       wp.wpKasPrincipalCreate.pszPrincipal = pszUserName;
3770       wp.wpKasPrincipalCreate.pszInstance = pszInstance;
3771       wp.wpKasPrincipalCreate.pszPassword = pszPassword;
3772
3773       AfsClass_Leave();
3774       rc = Worker_DoTask (wtaskKasPrincipalCreate, &wp, &status);
3775       AfsClass_Enter();
3776       }
3777
3778    // If that succeeded, try to create a PTS entry as well.
3779    //
3780    if (rc && fCreatePTS)
3781       {
3782       TCHAR szUserName[ cchNAME ];
3783       lstrcpy (szUserName, pszUserName);
3784       if (pszInstance)
3785          wsprintf (&szUserName[ lstrlen(szUserName) ], TEXT(".%s"), pszInstance);
3786
3787       WORKERPACKET wp;
3788       wp.wpPtsUserCreate.hCell = hCell;
3789       wp.wpPtsUserCreate.pszUser = szUserName;
3790       wp.wpPtsUserCreate.idUser = idUser;
3791
3792       AfsClass_Leave();
3793
3794       if ((rc = Worker_DoTask (wtaskPtsUserCreate, &wp, &status)) == FALSE)
3795          {
3796          if (status == PREXIST)
3797             rc = TRUE;
3798          }
3799
3800       if (!rc)
3801          {
3802          // If we couldn't make a KAS entry as well, remove the KAS entry.
3803          //
3804          if (fCreateKAS)
3805             {
3806             WORKERPACKET wpDel;
3807             wpDel.wpKasPrincipalDelete.hCell = hCell;
3808             wpDel.wpKasPrincipalDelete.hServer = hKAS;
3809             wpDel.wpKasPrincipalDelete.pszPrincipal = pszUserName;
3810             wpDel.wpKasPrincipalDelete.pszInstance = pszInstance;
3811             Worker_DoTask (wtaskKasPrincipalDelete, &wpDel);
3812             }
3813          }
3814
3815       AfsClass_Enter();
3816       }
3817
3818    // If we were able to create the user's accounts successfully, refresh
3819    // the cell status and return the new user's ident.
3820    //
3821    LPIDENT lpiUser;
3822
3823    if (rc)
3824       {
3825       if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
3826          rc = FALSE;
3827       else
3828          {
3829          if (!lpCell->RefreshAccount (pszUserName, pszInstance, CELL_REFRESH_ACCOUNT_CREATED_USER, &lpiUser))
3830             rc = FALSE;
3831          else if (!lpiUser)
3832             rc = FALSE;
3833          lpCell->Close();
3834          }
3835       }
3836
3837    NOTIFYCALLBACK::SendNotificationToAll (evtCreateUserEnd, lpiCell, pszUserName, status);
3838    AfsClass_Leave();
3839
3840    if (pStatus && !rc)
3841       *pStatus = status;
3842    return (rc) ? lpiUser : NULL;
3843 }
3844
3845
3846 BOOL AfsClass_SetUserProperties (LPIDENT lpiUser, LPUSERPROPERTIES pProperties, ULONG *pStatus)
3847 {
3848    BOOL rc = TRUE;
3849    ULONG status;
3850
3851    AfsClass_Enter();
3852    NOTIFYCALLBACK::SendNotificationToAll (evtChangeUserBegin, lpiUser);
3853
3854    // We'll need both hCell and hKAS.
3855    //
3856    PVOID hCell;
3857    PVOID hKAS;
3858    LPCELL lpCell;
3859    if ((lpCell = lpiUser->OpenCell (&status)) == NULL)
3860       rc = FALSE;
3861    else
3862       {
3863       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
3864          rc = FALSE;
3865       else
3866          hKAS = lpCell->GetKasObject (&status);
3867       lpCell->Close();
3868       }
3869
3870    // We'll also need this user's current status
3871    //
3872    LPUSER lpUser;
3873    USERSTATUS us;
3874    if ((lpUser = lpiUser->OpenUser (&status)) == NULL)
3875       rc = FALSE;
3876    else
3877       {
3878       if (!lpUser->GetStatus (&us, TRUE, &status))
3879          rc = FALSE;
3880       lpUser->Close();
3881       }
3882
3883    // Modify the user's KAS entry (if necessary)
3884    //
3885    DWORD dwKasMask = ( MASK_USERPROP_fAdmin |
3886                        MASK_USERPROP_fGrantTickets |
3887                        MASK_USERPROP_fCanEncrypt |
3888                        MASK_USERPROP_fCanChangePassword |
3889                        MASK_USERPROP_fCanReusePasswords |
3890                        MASK_USERPROP_timeAccountExpires |
3891                        MASK_USERPROP_cdayPwExpires |
3892                        MASK_USERPROP_csecTicketLifetime |
3893                        MASK_USERPROP_nFailureAttempts |
3894                        MASK_USERPROP_csecFailedLoginLockTime );
3895
3896    if (rc && (pProperties->dwMask & dwKasMask))
3897       {
3898       TCHAR szPrincipal[ cchNAME ];
3899       TCHAR szInstance[ cchNAME ];
3900       lpiUser->GetUserName (szPrincipal, szInstance);
3901
3902       WORKERPACKET wp;
3903       wp.wpKasPrincipalFieldsSet.hCell = hCell;
3904       wp.wpKasPrincipalFieldsSet.hServer = hKAS;
3905       wp.wpKasPrincipalFieldsSet.pszPrincipal = szPrincipal;
3906       wp.wpKasPrincipalFieldsSet.pszInstance = szInstance;
3907       wp.wpKasPrincipalFieldsSet.fIsAdmin = (pProperties->dwMask & MASK_USERPROP_fAdmin) ? pProperties->fAdmin : us.KASINFO.fIsAdmin;
3908       wp.wpKasPrincipalFieldsSet.fGrantTickets = (pProperties->dwMask & MASK_USERPROP_fGrantTickets) ? pProperties->fGrantTickets : us.KASINFO.fCanGetTickets;
3909       wp.wpKasPrincipalFieldsSet.fCanEncrypt = (pProperties->dwMask & MASK_USERPROP_fCanEncrypt) ? pProperties->fCanEncrypt : us.KASINFO.fEncrypt;
3910       wp.wpKasPrincipalFieldsSet.fCanChangePassword = (pProperties->dwMask & MASK_USERPROP_fCanChangePassword) ? pProperties->fCanChangePassword : us.KASINFO.fCanChangePassword;
3911       wp.wpKasPrincipalFieldsSet.fCanReusePasswords = (pProperties->dwMask & MASK_USERPROP_fCanReusePasswords) ? pProperties->fCanReusePasswords : us.KASINFO.fCanReusePasswords;
3912       memcpy (&wp.wpKasPrincipalFieldsSet.timeExpires, (pProperties->dwMask & MASK_USERPROP_timeAccountExpires) ? &pProperties->timeAccountExpires : &us.KASINFO.timeExpires, sizeof(SYSTEMTIME));
3913       wp.wpKasPrincipalFieldsSet.cdayPwExpires = (pProperties->dwMask & MASK_USERPROP_cdayPwExpires) ? pProperties->cdayPwExpires : us.KASINFO.cdayPwExpire;
3914       wp.wpKasPrincipalFieldsSet.csecTicketLifetime = (pProperties->dwMask & MASK_USERPROP_csecTicketLifetime) ? pProperties->csecTicketLifetime : us.KASINFO.csecTicketLifetime;
3915       wp.wpKasPrincipalFieldsSet.nFailureAttempts = (pProperties->dwMask & MASK_USERPROP_nFailureAttempts) ? pProperties->nFailureAttempts : us.KASINFO.cFailLogin;
3916       wp.wpKasPrincipalFieldsSet.csecFailedLoginLockTime = (pProperties->dwMask & MASK_USERPROP_csecFailedLoginLockTime) ? pProperties->csecFailedLoginLockTime : us.KASINFO.csecFailLoginLock;
3917
3918       AfsClass_Leave();
3919       rc = Worker_DoTask (wtaskKasPrincipalFieldsSet, &wp, &status);
3920       AfsClass_Enter();
3921       }
3922
3923
3924    // Modify the user's PTS entry (if necessary)
3925    //
3926    DWORD dwPtsMask = ( MASK_USERPROP_cGroupCreationQuota |
3927                        MASK_USERPROP_aaListStatus |
3928                        MASK_USERPROP_aaGroupsOwned |
3929                        MASK_USERPROP_aaMembership );
3930
3931    if (rc && (pProperties->dwMask & dwPtsMask))
3932       {
3933       TCHAR szFullName[ cchNAME ];
3934       lpiUser->GetFullUserName (szFullName);
3935
3936       WORKERPACKET wp;
3937       wp.wpPtsUserModify.hCell = hCell;
3938       wp.wpPtsUserModify.pszUser = szFullName;
3939       memset (&wp.wpPtsUserModify.Delta, 0x00, sizeof(wp.wpPtsUserModify.Delta));
3940
3941       if (pProperties->dwMask & MASK_USERPROP_cGroupCreationQuota)
3942          {
3943          wp.wpPtsUserModify.Delta.flag = (pts_UserUpdateFlag_t)( (LONG)wp.wpPtsUserModify.Delta.flag | (LONG)PTS_USER_UPDATE_GROUP_CREATE_QUOTA );
3944          wp.wpPtsUserModify.Delta.groupCreationQuota = pProperties->cGroupCreationQuota;
3945          }
3946
3947       if (pProperties->dwMask & (MASK_USERPROP_aaListStatus | MASK_USERPROP_aaGroupsOwned | MASK_USERPROP_aaMembership))
3948          {
3949          wp.wpPtsUserModify.Delta.flag = (pts_UserUpdateFlag_t)( (LONG)wp.wpPtsUserModify.Delta.flag | (LONG)PTS_USER_UPDATE_PERMISSIONS );
3950          wp.wpPtsUserModify.Delta.listStatus = ACCOUNTACCESS_TO_USERACCESS( (pProperties->dwMask & MASK_USERPROP_aaListStatus) ? pProperties->aaListStatus : us.PTSINFO.aaListStatus );
3951          wp.wpPtsUserModify.Delta.listGroupsOwned = ACCOUNTACCESS_TO_USERACCESS( (pProperties->dwMask & MASK_USERPROP_aaGroupsOwned) ? pProperties->aaGroupsOwned : us.PTSINFO.aaGroupsOwned );
3952          wp.wpPtsUserModify.Delta.listMembership = ACCOUNTACCESS_TO_USERACCESS( (pProperties->dwMask & MASK_USERPROP_aaMembership) ? pProperties->aaMembership : us.PTSINFO.aaMembership );
3953          }
3954
3955       AfsClass_Leave();
3956       rc = Worker_DoTask (wtaskPtsUserModify, &wp, &status);
3957       AfsClass_Enter();
3958       }
3959
3960    // If we were able to modify the user's properties successfully, refresh
3961    // that user's status.
3962    //
3963    if ((lpUser = lpiUser->OpenUser (&status)) != NULL)
3964       {
3965       lpUser->Invalidate();
3966       lpUser->RefreshStatus();
3967       lpUser->Close();
3968       }
3969
3970    NOTIFYCALLBACK::SendNotificationToAll (evtChangeUserBegin, lpiUser, status);
3971    AfsClass_Leave();
3972
3973    if (pStatus && !rc)
3974       *pStatus = status;
3975    return rc;
3976 }
3977
3978
3979 BOOL AfsClass_SetUserPassword (LPIDENT lpiUser, int keyVersion, LPTSTR pszPassword, ULONG *pStatus)
3980 {
3981    BOOL rc = TRUE;
3982    ULONG status = 0;
3983
3984    TCHAR szCell[ cchNAME ];
3985    lpiUser->GetCellName (szCell);
3986
3987    WORKERPACKET wp;
3988    wp.wpKasStringToKey.pszCell = szCell;
3989    wp.wpKasStringToKey.pszString = pszPassword;
3990    if (!Worker_DoTask (wtaskKasStringToKey, &wp, &status))
3991       {
3992       rc = FALSE;
3993       }
3994    else if (!AfsClass_SetUserPassword (lpiUser, keyVersion, &wp.wpKasStringToKey.key, &status))
3995       {
3996       rc = FALSE;
3997       }
3998
3999    if (pStatus && !rc)
4000       *pStatus = status;
4001    return rc;
4002 }
4003
4004
4005 BOOL AfsClass_SetUserPassword (LPIDENT lpiUser, int keyVersion, LPENCRYPTIONKEY pKey, ULONG *pStatus)
4006 {
4007    BOOL rc = TRUE;
4008    ULONG status;
4009
4010    AfsClass_Enter();
4011    NOTIFYCALLBACK::SendNotificationToAll (evtChangeUserPasswordBegin, lpiUser);
4012
4013    // We'll need both hCell and hKAS.
4014    //
4015    PVOID hCell;
4016    PVOID hKAS;
4017    LPCELL lpCell;
4018    if ((lpCell = lpiUser->OpenCell (&status)) == NULL)
4019       rc = FALSE;
4020    else
4021       {
4022       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
4023          rc = FALSE;
4024       else
4025          hKAS = lpCell->GetKasObject (&status);
4026       lpCell->Close();
4027       }
4028
4029    // Change the user's password
4030    //
4031    if (rc)
4032       {
4033       TCHAR szPrincipal[ cchNAME ];
4034       TCHAR szInstance[ cchNAME ];
4035       lpiUser->GetUserName (szPrincipal, szInstance);
4036
4037       WORKERPACKET wp;
4038       wp.wpKasPrincipalKeySet.hCell = hCell;
4039       wp.wpKasPrincipalKeySet.hServer = hKAS;
4040       wp.wpKasPrincipalKeySet.pszPrincipal = szPrincipal;
4041       wp.wpKasPrincipalKeySet.pszInstance = szInstance;
4042       wp.wpKasPrincipalKeySet.keyVersion = keyVersion;
4043       memcpy (&wp.wpKasPrincipalKeySet.key.key, &pKey->key, ENCRYPTIONKEY_LEN);
4044
4045       AfsClass_Leave();
4046       rc = Worker_DoTask (wtaskKasPrincipalKeySet, &wp, &status);
4047       AfsClass_Enter();
4048       }
4049
4050    // If we were able to modify the user's password successfully, refresh
4051    // that user's status.
4052    //
4053    LPUSER lpUser;
4054    if ((lpUser = lpiUser->OpenUser (&status)) != NULL)
4055       {
4056       lpUser->Invalidate();
4057       lpUser->RefreshStatus();
4058       lpUser->Close();
4059       }
4060
4061    NOTIFYCALLBACK::SendNotificationToAll (evtChangeUserPasswordEnd, lpiUser, status);
4062    AfsClass_Leave();
4063
4064    if (pStatus && !rc)
4065       *pStatus = status;
4066    return rc;
4067 }
4068
4069
4070 BOOL AfsClass_DeleteUser (LPIDENT lpiUser, BOOL fDeleteKAS, BOOL fDeletePTS, ULONG *pStatus)
4071 {
4072    BOOL rc = TRUE;
4073    ULONG status;
4074
4075    AfsClass_Enter();
4076    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteUserBegin, lpiUser);
4077
4078    // We'll need both hCell and hKAS.
4079    //
4080    PVOID hCell;
4081    PVOID hKAS;
4082    LPCELL lpCell;
4083    if ((lpCell = lpiUser->OpenCell (&status)) == NULL)
4084       rc = FALSE;
4085    else
4086       {
4087       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
4088          rc = FALSE;
4089       else
4090          hKAS = lpCell->GetKasObject (&status);
4091       lpCell->Close();
4092       }
4093
4094    // Find out whether this user has KAS and/or PTS entries. Also
4095    // get the various lists of groups for this user...
4096    //
4097    LPUSER lpUser;
4098    LPTSTR mszOwnerOf = NULL;
4099    LPTSTR mszMemberOf = NULL;
4100    if ((lpUser = lpiUser->OpenUser (&status)) == NULL)
4101       rc = FALSE;
4102    else
4103       {
4104       lpUser->GetOwnerOf (&mszOwnerOf);
4105       lpUser->GetMemberOf (&mszMemberOf);
4106       lpUser->Close();
4107       }
4108
4109    // Delete the user's PTS entry
4110    //
4111    if (rc && fDeletePTS)
4112       {
4113       TCHAR szFullName[ cchNAME ];
4114       lpiUser->GetFullUserName (szFullName);
4115
4116       WORKERPACKET wp;
4117       wp.wpPtsUserDelete.hCell = hCell;
4118       wp.wpPtsUserDelete.pszUser = szFullName;
4119
4120       AfsClass_Leave();
4121       if ((rc = Worker_DoTask (wtaskPtsUserDelete, &wp, &status)) == FALSE)
4122          {
4123          if (status == ADMPTSFAILEDNAMETRANSLATE) // User had no PTS entry?
4124             rc = TRUE;
4125          }
4126       AfsClass_Enter();
4127       }
4128
4129    // Delete the user's KAS entry
4130    //
4131    if (rc && fDeleteKAS)
4132       {
4133       TCHAR szPrincipal[ cchNAME ];
4134       TCHAR szInstance[ cchNAME ];
4135       lpiUser->GetUserName (szPrincipal, szInstance);
4136
4137       WORKERPACKET wp;
4138       wp.wpKasPrincipalDelete.hCell = hCell;
4139       wp.wpKasPrincipalDelete.hServer = hKAS;
4140       wp.wpKasPrincipalDelete.pszPrincipal = szPrincipal;
4141       wp.wpKasPrincipalDelete.pszInstance = szInstance;
4142
4143       AfsClass_Leave();
4144       if ((rc = Worker_DoTask (wtaskKasPrincipalDelete, &wp, &status)) == FALSE)
4145          {
4146          if (status == KANOENT)
4147             rc = TRUE;
4148          }
4149       AfsClass_Enter();
4150       }
4151
4152    // If we were able to delete the user's accounts successfully, refresh
4153    // the cell status.
4154    //
4155    if (rc)
4156       {
4157       if ((lpCell = lpiUser->OpenCell (&status)) != NULL)
4158          {
4159          TCHAR szPrincipal[ cchNAME ];
4160          TCHAR szInstance[ cchNAME ];
4161          lpiUser->GetUserName (szPrincipal, szInstance);
4162
4163          lpCell->RefreshAccount (szPrincipal, szInstance, CELL_REFRESH_ACCOUNT_DELETED);
4164          lpCell->RefreshAccounts (mszOwnerOf, CELL_REFRESH_ACCOUNT_CHANGED);
4165          lpCell->RefreshAccounts (mszMemberOf, CELL_REFRESH_ACCOUNT_CHANGED);
4166          lpCell->Close();
4167          }
4168       }
4169
4170    NOTIFYCALLBACK::SendNotificationToAll (evtDeleteUserEnd, lpiUser, status);
4171    AfsClass_Leave();
4172
4173    if (mszOwnerOf)
4174       FreeString (mszOwnerOf);
4175    if (mszMemberOf)
4176       FreeString (mszMemberOf);
4177    if (pStatus && !rc)
4178       *pStatus = status;
4179    return rc;
4180 }
4181
4182
4183 BOOL AfsClass_UnlockUser (LPIDENT lpiUser, ULONG *pStatus)
4184 {
4185    BOOL rc = TRUE;
4186    ULONG status;
4187
4188    AfsClass_Enter();
4189    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockUserBegin, lpiUser);
4190
4191    // We'll need both hCell and hKAS.
4192    //
4193    PVOID hCell;
4194    PVOID hKAS;
4195    LPCELL lpCell;
4196    if ((lpCell = lpiUser->OpenCell (&status)) == NULL)
4197       rc = FALSE;
4198    else
4199       {
4200       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
4201          rc = FALSE;
4202       else
4203          hKAS = lpCell->GetKasObject (&status);
4204       lpCell->Close();
4205       }
4206
4207    // Unlock the user's KAS entry
4208    //
4209    if (rc)
4210       {
4211       TCHAR szPrincipal[ cchNAME ];
4212       TCHAR szInstance[ cchNAME ];
4213       lpiUser->GetUserName (szPrincipal, szInstance);
4214
4215       WORKERPACKET wp;
4216       wp.wpKasPrincipalUnlock.hCell = hCell;
4217       wp.wpKasPrincipalUnlock.hServer = hKAS;
4218       wp.wpKasPrincipalUnlock.pszPrincipal = szPrincipal;
4219       wp.wpKasPrincipalUnlock.pszInstance = szInstance;
4220
4221       AfsClass_Leave();
4222       rc = Worker_DoTask (wtaskKasPrincipalUnlock, &wp, &status);
4223       AfsClass_Enter();
4224       }
4225
4226    // If we were able to unlock the user's accounts successfully, refresh
4227    // the user's properties.
4228    //
4229    if (rc)
4230       {
4231       LPUSER lpUser;
4232       if ((lpUser = lpiUser->OpenUser (&status)) != NULL)
4233          {
4234          lpUser->Invalidate();
4235          lpUser->RefreshStatus();
4236          lpUser->Close();
4237          }
4238       }
4239
4240    NOTIFYCALLBACK::SendNotificationToAll (evtUnlockUserEnd, lpiUser, status);
4241    AfsClass_Leave();
4242
4243    if (pStatus && !rc)
4244       *pStatus = status;
4245    return rc;
4246 }
4247
4248
4249 LPIDENT AfsClass_CreateGroup (LPIDENT lpiCell, LPTSTR pszGroupName, LPIDENT lpiOwner, int idGroup, ULONG *pStatus)
4250 {
4251    BOOL rc = TRUE;
4252    ULONG status;
4253
4254    AfsClass_Enter();
4255    NOTIFYCALLBACK::SendNotificationToAll (evtCreateGroupBegin, lpiCell, pszGroupName, 0);
4256
4257    // Obtain hCell
4258    //
4259    PVOID hCell;
4260    LPCELL lpCell;
4261    if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
4262       rc = FALSE;
4263    else
4264       {
4265       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
4266          rc = FALSE;
4267       lpCell->Close();
4268       }
4269
4270    // Create a PTS entry for the new group
4271    //
4272    if (rc)
4273       {
4274       TCHAR szOwner[ cchNAME ] = TEXT("");
4275       if (lpiOwner && lpiOwner->fIsUser())
4276          lpiOwner->GetFullUserName (szOwner);
4277       else if (lpiOwner && lpiOwner->fIsGroup())
4278          lpiOwner->GetGroupName (szOwner);
4279
4280       WORKERPACKET wp;
4281       wp.wpPtsGroupCreate.hCell = hCell;
4282       wp.wpPtsGroupCreate.pszGroup = pszGroupName;
4283       wp.wpPtsGroupCreate.pszOwner = (szOwner[0]) ? szOwner : NULL;
4284       wp.wpPtsGroupCreate.idGroup = idGroup;
4285
4286       AfsClass_Leave();
4287       rc = Worker_DoTask (wtaskPtsGroupCreate, &wp, &status);
4288       AfsClass_Enter();
4289       }
4290
4291    // If we were able to create the group successfully, refresh
4292    // the cell status and return the new group's ident.
4293    //
4294    LPIDENT lpiGroup;
4295
4296    if (rc)
4297       {
4298       if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
4299          rc = FALSE;
4300       else
4301          {
4302          if (!lpCell->RefreshAccount (pszGroupName, NULL, CELL_REFRESH_ACCOUNT_CREATED_GROUP, &lpiGroup))
4303             rc = FALSE;
4304          else if (!lpiGroup)
4305             rc = FALSE;
4306          lpCell->Close();
4307          }
4308       }
4309
4310    NOTIFYCALLBACK::SendNotificationToAll (evtCreateGroupEnd, lpiCell, pszGroupName, status);
4311    AfsClass_Leave();
4312
4313    if (pStatus && !rc)
4314       *pStatus = status;
4315    return (rc) ? lpiGroup : NULL;
4316 }
4317
4318
4319 BOOL AfsClass_SetGroupProperties (LPIDENT lpiGroup, LPGROUPPROPERTIES pProperties, ULONG *pStatus)
4320 {
4321    BOOL rc = TRUE;
4322    ULONG status;
4323
4324    AfsClass_Enter();
4325    NOTIFYCALLBACK::SendNotificationToAll (evtChangeGroupBegin, lpiGroup);
4326
4327    // Obtain hCell
4328    //
4329    PVOID hCell;
4330    LPCELL lpCell;
4331    if ((lpCell = lpiGroup->OpenCell (&status)) == NULL)
4332       rc = FALSE;
4333    else
4334       {
4335       if ((hCell = lpCell->GetCellObject (&status)) == NULL)
4336          rc = FALSE;
4337       lpCell->Close();
4338       }
4339
4340    // We'll also need this group's current status
4341    //
4342    LPPTSGROUP lpGroup;
4343    PTSGROUPSTATUS gs;
4344    if ((lpGroup = lpiGroup->OpenGroup (&status)) == NULL)
4345       rc = FALSE;
4346    else
4347       {
4348       if (!lpGroup->GetStatus (&gs, TRUE, &status))
4349          rc = FALSE;
4350       lpGroup->Close();
4351       }
4352
4353    // Modify the group's PTS entry (if requested)
4354    //
4355    DWORD dwPtsMask = ( MASK_GROUPPROP_aaListStatus |
4356                        MASK_GROUPPROP_aaListGroupsOwned |
4357                        MASK_GROUPPROP_aaListMembers |
4358                        MASK_GROUPPROP_aaAddMember |
4359                        MASK_GROUPPROP_aaDeleteMember );
4360
4361    if (rc && (pProperties->dwMask & dwPtsMask))
4362       {
4363       TCHAR szGroup[ cchNAME ];
4364       lpiGroup->GetGroupName (szGroup);
4365
4366       WORKERPACKET wp;
4367       wp.wpPtsGroupModify.hCell = hCell;
4368       wp.wpPtsGroupModify.pszGroup = szGroup;
4369       memset (&wp.wpPtsGroupModify.Delta, 0x00, sizeof(wp.wpPtsGroupModify.Delta));
4370       wp.wpPtsGroupModify.Delta.listStatus = ACCOUNTACCESS_TO_GROUPACCESS( (pProperties->dwMask & MASK_GROUPPROP_aaListStatus) ? pProperties->aaListStatus : gs.aaListStatus );
4371       wp.wpPtsGroupModify.Delta.listGroupsOwned = ACCOUNTACCESS_TO_GROUPACCESS( (pProperties->dwMask & MASK_GROUPPROP_aaListGroupsOwned) ? pProperties->aaListGroupsOwned : gs.aaListGroupsOwned );
4372       wp.wpPtsGroupModify.Delta.listMembership = ACCOUNTACCESS_TO_GROUPACCESS( (pProperties->dwMask & MASK_GROUPPROP_aaListMembers) ? pProperties->aaListMembers : gs.aaListMembers );
4373       wp.wpPtsGroupModify.Delta.listAdd = ACCOUNTACCESS_TO_GROUPACCESS( (pProperties->dwMask & MASK_GROUPPROP_aaAddMember) ? pProperties->aaAddMember : gs.aaAddMember );
4374       wp.wpPtsGroupModify.Delta.listDelete = ACCOUNTACCESS_TO_GROUPACCESS( (pProperties->dwMask & MASK_GROUPPROP_aaDeleteMember) ? pProperties->aaDeleteMember : gs.aaDeleteMember );
4375
4376       AfsClass_Leave();
4377       rc = Worker_DoTask (wtaskPtsGroupModify, &wp, &status);
4378       AfsClass_Enter();
4379       }
4380
4381    // Change the group's owner (if requested)
4382    //
4383    if (rc && (pProperties->dwMask & MASK_GROUPPROP_szOwner))
4384       {
4385       TCHAR szGroup[ cchNAME ];
4386       lpiGroup->GetGroupName (szGroup);
4387
4388       WORKERPACKET wp;
4389       wp.wpPtsGroupOwnerChange.hCell = hCell;
4390       wp.wpPtsGroupOwnerChange.pszGroup = szGroup;
4391       wp.wpPtsGroupOwnerChange.pszOwner = pProperties->szOwner;
4392
4393       AfsClass_Leave();
4394       rc = Worker_DoTask (wtaskPtsGroupOwnerChange, &wp, &status);
4395       AfsClass_Enter();
4396       }
4397
4398    // If we were able to modify the group's properties successfully, refresh
4399    // either the group's status. If the group's owner changed, also refresh
4400    // the group's old and new owners.
4401    //
4402    if (rc)
4403       {
4404       if ((lpCell = lpiGroup->OpenCell (&status)) != NULL)