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