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