LINUX: afs_create infinite fetchStatus loop
[pkg-k5-afs_openafs.git] / src / WINNT / afsclass / c_cell.cpp
blob2b1f7ed97b4965c9066d1a1e586ebdc0e4629586
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
13 extern "C" {
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <roken.h>
19 #include <WINNT/afsclass.h>
20 #include "internal.h"
24 * DEFINITIONS ________________________________________________________________
28 // Each CELL object maintains a list of servers; that list has
29 // hashtables placed across the (shortened) server name for
30 // faster lookup; it also maintains a hashtable across the
31 // servers' primary IP address (the first in the list; most
32 // servers will only have one anyway). The default table size
33 // in a HASHLIST is 1000 elements--that's too large for a list
34 // of servers-in-a-cell, as it's enough to handle up to 30,000
35 // servers before the table would need to resize iteself (see
36 // the documentation in hashlist.cpp for info). Instead, we
37 // choose a more reasonable default table size.
39 #define cKEYSERVERNAME_TABLESIZE 50
41 #define cKEYSERVERADDR_TABLESIZE 50
43 // Enable the definition below to do a better job of finding
44 // user entries in PTS which have no KAS entries (for instance,
45 // machine IP accounts).
47 #define FIND_PTS_DEBRIS
51 * VARIABLES __________________________________________________________________
55 LPHASHLIST CELL::x_lCells = NULL;
59 * CONSTRUCTION _______________________________________________________________
63 void CELL::InitClass (void)
65 if (x_lCells == NULL)
67 x_lCells = New (HASHLIST);
68 x_lCells->SetCriticalSection (AfsClass_GetCriticalSection());
73 CELL::CELL (LPTSTR pszCellName, PVOID hCreds)
75 AfsClass_Enter();
76 InitClass();
78 m_hCell = 0;
79 m_hKas = 0;
80 lstrcpy (m_szName, pszCellName);
81 m_nReqs = 0;
82 m_hCreds = hCreds;
83 m_apszServers = 0;
85 m_fStatusOutOfDate = TRUE;
86 m_fVLDBOutOfDate = TRUE;
87 m_lpiThis = NULL;
89 m_fServersOutOfDate = TRUE;
90 m_nServersUnmonitored = 0;
92 m_lServers = New (HASHLIST);
93 m_lServers->SetCriticalSection (AfsClass_GetCriticalSection());
94 m_lkServerName = m_lServers->CreateKey ("Server Name", CELL::KeyServerName_Compare, CELL::KeyServerName_HashObject, CELL::KeyServerName_HashData, cKEYSERVERNAME_TABLESIZE);
95 m_lkServerAddr = m_lServers->CreateKey ("Server Primary Address", CELL::KeyServerAddr_Compare, CELL::KeyServerAddr_HashObject, CELL::KeyServerAddr_HashData, cKEYSERVERADDR_TABLESIZE);
97 m_fUsersOutOfDate = TRUE;
98 m_lUsers = New (HASHLIST);
99 m_lUsers->SetCriticalSection (AfsClass_GetCriticalSection());
100 m_lkUserName = m_lUsers->CreateKey ("User Name", CELL::KeyUserName_Compare, CELL::KeyUserName_HashObject, CELL::KeyUserName_HashData);
101 m_lGroups = New (HASHLIST);
102 m_lGroups->SetCriticalSection (AfsClass_GetCriticalSection());
103 m_lkGroupName = m_lGroups->CreateKey ("Group Name", CELL::KeyGroupName_Compare, CELL::KeyGroupName_HashObject, CELL::KeyGroupName_HashData);
105 AfsClass_Leave();
109 CELL::~CELL (void)
111 FreeUsers (FALSE);
112 FreeServers (FALSE);
114 if (m_lpiThis)
115 m_lpiThis->m_cRef --;
116 Delete (m_lServers);
120 void CELL::FreeServers (BOOL fNotify)
122 for (LPENUM pEnum = m_lServers->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
124 LPSERVER lpServer = (LPSERVER)(pEnum->GetObject());
125 if (fNotify)
126 lpServer->SendDeleteNotifications();
127 m_lServers->Remove (lpServer);
128 Delete (lpServer);
130 if (m_apszServers)
132 for (size_t ii = 0; m_apszServers[ii]; ++ii)
133 FreeString (m_apszServers[ii]);
134 Free (m_apszServers);
135 m_apszServers = NULL;
140 void CELL::FreeUsers (BOOL fNotify)
142 LPENUM pEnum;
143 for (pEnum = m_lGroups->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
145 LPPTSGROUP lpGroup = (LPPTSGROUP)(pEnum->GetObject());
146 if (fNotify)
147 lpGroup->SendDeleteNotifications();
148 m_lGroups->Remove (lpGroup);
149 Delete (lpGroup);
152 for (pEnum = m_lUsers->FindLast(); pEnum; pEnum = pEnum->FindPrevious())
154 LPUSER lpUser = (LPUSER)(pEnum->GetObject());
155 if (fNotify)
156 lpUser->SendDeleteNotifications();
157 m_lUsers->Remove (lpUser);
158 Delete (lpUser);
164 * CELL-LIST MANAGEMENT _______________________________________________________
168 void CELL::Close (void)
170 AfsClass_Leave();
174 BOOL CELL::GetDefaultCell (LPTSTR pszName, ULONG *pStatus)
176 WORKERPACKET wp;
177 wp.wpClientLocalCellGet.pszCell = pszName;
178 return Worker_DoTask (wtaskClientLocalCellGet, &wp, pStatus);
182 LPIDENT CELL::OpenCell (LPTSTR pszCell, PVOID hCreds, ULONG *pStatus)
184 LPIDENT lpiCell = NULL;
185 AfsClass_Enter();
186 InitClass();
188 LPCELL lpCell;
189 if ((lpCell = ReopenCell (pszCell, pStatus)) != NULL)
191 lpiCell = lpCell->GetIdentifier();
192 lpCell->m_nReqs++;
193 lpCell->Close();
195 else // cell hasn't been opened before? see if we can reach the cell.
197 lpCell = New2 (CELL,(pszCell, hCreds));
198 if ((lpCell->m_hCell = lpCell->GetCellObject (pStatus)) == NULL)
199 Delete (lpCell);
200 else
202 lpiCell = lpCell->GetIdentifier();
203 lpCell->m_nReqs = 1;
204 x_lCells->Add (lpCell);
205 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpiCell);
209 AfsClass_Leave();
210 return lpiCell;
214 void CELL::CloseCell (LPIDENT lpiCell)
216 LPCELL lpCell;
217 if ((lpCell = lpiCell->OpenCell()) != NULL)
219 if (lpCell->m_nReqs > 1)
221 lpCell->m_nReqs--;
222 lpCell->Close();
224 else
226 NOTIFYCALLBACK::SendNotificationToAll (evtDestroy, lpiCell);
227 lpCell->CloseKasObject();
228 lpCell->CloseCellObject();
229 lpCell->Close();
230 x_lCells->Remove (lpCell);
231 Delete (lpCell);
237 LPCELL CELL::ReopenCell (LPTSTR pszCell, ULONG *pStatus)
239 LPCELL lpCell = NULL;
240 AfsClass_Enter();
241 InitClass();
243 // Ordinarily we'd place a key on the cell name within the list of
244 // cells--however, the most likely case only has one cell anyway.
245 // So why expend the memory?
247 for (LPENUM pEnum = x_lCells->FindFirst(); pEnum; pEnum = pEnum->FindNext())
249 LPCELL lpCellFound = (LPCELL)( pEnum->GetObject() );
251 if (!lstrcmpi (lpCellFound->m_szName, pszCell))
253 lpCell = lpCellFound;
254 Delete (pEnum);
255 break;
259 if (lpCell == NULL)
261 AfsClass_Leave();
262 if (pStatus)
263 *pStatus = ERROR_FILE_NOT_FOUND;
266 // AfsClass_Leave() has been called only if no cell was opened in the search.
267 return lpCell;
271 PVOID CELL::GetCurrentCredentials (void)
273 return m_hCreds;
277 void CELL::SetCurrentCredentials (PVOID hCreds)
279 CloseCellObject();
281 m_hCreds = hCreds;
283 GetCellObject();
288 * SERVER-LIST MANAGEMENT _____________________________________________________
292 LPSERVER CELL::OpenServer (LPTSTR pszName, ULONG *pStatus)
294 if (!RefreshServers (TRUE, pStatus))
295 return NULL;
297 LPSERVER lpServer;
298 if ((lpServer = (LPSERVER)(m_lkServerName->GetFirstObject (pszName))) != NULL)
299 AfsClass_Enter();
301 return lpServer;
305 LPSERVER CELL::OpenServer (LPSOCKADDR_IN pAddr, ULONG *pStatus)
307 if (!RefreshServers (TRUE, pStatus))
308 return NULL;
310 // We'll try to use our lookup key first--since most machines only
311 // have one IP address anyway, our hashtable should make this lookup
312 // super fast. If it misses (i.e., if the server is multi-homed and
313 // for some reason VLDB refers to it by the second address), we'll
314 // have to do a brute-force search across each server in the cell.
315 // Again, we could have a better-designed lookup table here--but
316 // since multi-homing is the exception (by a vast majority), it's not
317 // worth the extra effort and memory. This technique is fast enough.
319 LPSERVER lpServer;
320 if ((lpServer = (LPSERVER)(m_lkServerAddr->GetFirstObject (pAddr))) != NULL)
322 AfsClass_Enter(); // Aren't HashLists great? We found the server.
324 else // Try brute-force search
326 HENUM hEnum;
327 for (lpServer = ServerFindFirst (&hEnum, TRUE, pStatus); lpServer; lpServer = ServerFindNext (&hEnum))
329 SERVERSTATUS ss;
330 if (lpServer->GetStatus (&ss, TRUE, pStatus))
332 for (size_t iAddr = 0; iAddr < ss.nAddresses; ++iAddr)
334 if (!memcmp (&ss.aAddresses[ iAddr ], pAddr, sizeof(SOCKADDR_IN)))
336 // don't close server! we're going to return this pointer.
337 break;
341 lpServer->Close();
343 ServerFindClose (&hEnum);
345 return lpServer;
349 LPSERVER CELL::ServerFindFirst (HENUM *phEnum, BOOL fNotify, ULONG *pStatus)
351 return ServerFindFirst (phEnum, NULL, fNotify, pStatus);
355 LPSERVER CELL::ServerFindFirst (HENUM *phEnum, LPIDENT lpiFind, BOOL fNotify, ULONG *pStatus)
357 LPSERVER lpServer = NULL;
359 if (!RefreshServers (fNotify, pStatus))
360 return NULL;
362 if (lpiFind != NULL)
364 lpServer = lpiFind->OpenServer();
365 *phEnum = NULL;
367 else if ((*phEnum = m_lServers->FindFirst()) != NULL)
369 lpServer = (LPSERVER)( (*phEnum)->GetObject() );
370 AfsClass_Enter();
373 if (!lpServer && pStatus)
374 *pStatus = ERROR_FILE_NOT_FOUND;
375 return lpServer;
379 LPSERVER CELL::ServerFindNext (HENUM *phEnum)
381 LPSERVER lpServer = NULL;
383 if (*phEnum)
385 if ((*phEnum = (*phEnum)->FindNext()) != NULL)
387 lpServer = (LPSERVER)( (*phEnum)->GetObject() );
388 AfsClass_Enter();
392 return lpServer;
396 void CELL::ServerFindClose (HENUM *phEnum)
398 if (*phEnum)
400 Delete (*phEnum);
401 *phEnum = NULL;
406 BOOL CELL::RefreshServers (BOOL fNotify, ULONG *pStatus)
408 if (!m_fServersOutOfDate)
409 return TRUE;
411 return RefreshServerList (fNotify, pStatus);
415 BOOL CELL::RefreshServerList (BOOL fNotify, ULONG *pStatus)
417 BOOL rc = TRUE;
418 ULONG status = 0;
419 BOOL fNotified = FALSE;
421 if (fNotify && m_fServersOutOfDate)
423 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServersBegin, GetIdentifier());
424 fNotified = TRUE;
427 BOOL fReplaceList = m_fServersOutOfDate;
428 m_fServersOutOfDate = FALSE;
430 // Ordinarily we'd just clear the list of servers and
431 // requery it from scratch; however, servers are an exception
432 // to that technique: occasionally we may get a request to
433 // just look for servers that have appeared or disappeared,
434 // without refreshing data for other servers. Thus the revised
435 // technique:
437 // 1- if fReplaceList, empty the list of servers.
438 // otherwise, set each server's fDelete flag.
440 // 2- enumerate the servers in the cell: for each server,
441 // if fReplaceList, add the server to the list
442 // otherwise, if the server is in the list, clear its fDelete
444 // 3- if !fReplaceList, enumerate the list of servers: for each server,
445 // if the server's fDelete flag is set, remove the server
447 for (LPENUM pEnum = m_lServers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
449 LPSERVER lpServer = (LPSERVER)(pEnum->GetObject());
451 if (fReplaceList)
453 lpServer->SendDeleteNotifications();
454 m_lServers->Remove (lpServer);
455 Delete (lpServer);
457 else // the list of servers isn't invalidated, so just mark fDelete
459 lpServer->m_fDelete = TRUE;
463 // Enumerate the servers in the cell.
465 PVOID hCell;
466 if ((hCell = GetCellObject (&status)) == NULL)
468 rc = FALSE;
469 FreeUsers (TRUE);
470 FreeServers (TRUE);
472 else
474 WORKERPACKET wpBegin;
475 wpBegin.wpClientAFSServerGetBegin.hCell = hCell;
477 if (!Worker_DoTask (wtaskClientAFSServerGetBegin, &wpBegin, &status))
479 rc = FALSE;
481 else
483 for (;;)
485 WORKERPACKET wpNext;
486 wpNext.wpClientAFSServerGetNext.hEnum = wpBegin.wpClientAFSServerGetBegin.hEnum;
487 if (!Worker_DoTask (wtaskClientAFSServerGetNext, &wpNext, &status))
489 if (status == ADMITERATORDONE)
490 status = 0;
491 else
492 rc = FALSE;
493 break;
496 afs_serverEntry_p pEntry = &wpNext.wpClientAFSServerGetNext.Entry;
498 TCHAR szServer[ cchNAME ];
499 CopyAnsiToString (szServer, pEntry->serverName);
500 if (!szServer[0])
502 int addrNetwork = htonl (pEntry->serverAddress[0]);
503 lstrcpy (szServer, inet_ntoa (*(struct in_addr *)&addrNetwork));
506 // The server identified by {pEntry} is in the cell. Now if we're
507 // building a list of SERVER objects from scratch, we can just
508 // add it--but if we're only touching up an existing list,
509 // first make sure there isn't such an animal in there now.
511 BOOL fNotifyAboutThisServer = FALSE;
513 LPSERVER lpServer = NULL;
514 if (!fReplaceList)
516 if ((lpServer = (LPSERVER)(m_lkServerName->GetFirstObject (szServer))) != NULL)
517 lpServer->m_fDelete = FALSE;
520 if (lpServer == NULL)
522 // Okay, it's a new server. Create a SERVER object for it and
523 // add it to the list.
525 lpServer = New2 (SERVER,(this, szServer));
526 lpServer->m_wGhost |= GHOST_HAS_SERVER_ENTRY;
527 m_lServers->Add (lpServer);
528 fNotifyAboutThisServer = TRUE;
531 // Update the server's IP addresses
533 lpServer->m_ss.nAddresses = 0;
535 for (size_t iAddr = 0; iAddr < AFS_MAX_SERVER_ADDRESS; ++iAddr)
537 if (pEntry->serverAddress[ iAddr ] == 0)
538 continue;
539 AfsClass_IntToAddress (&lpServer->m_ss.aAddresses[ lpServer->m_ss.nAddresses++ ], pEntry->serverAddress[ iAddr ]);
542 m_lServers->Update (lpServer); // That update affected a hashlistkey
544 // Tell our clients that we've found a server
546 if (fNotify && fNotifyAboutThisServer)
548 if (!fNotified)
550 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServersBegin, GetIdentifier());
551 fNotified = TRUE;
553 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpServer->GetIdentifier());
557 WORKERPACKET wpDone;
558 wpDone.wpClientAFSServerGetDone.hEnum = wpBegin.wpClientAFSServerGetBegin.hEnum;
559 Worker_DoTask (wtaskClientAFSServerGetDone, &wpDone);
563 // Finally, look through our list of servers: if any have fDelete set,
564 // then we didn't find them in the cell any longer. Remove those servers.
566 if (rc)
568 for (LPENUM pEnum = m_lServers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
570 LPSERVER lpServer = (LPSERVER)(pEnum->GetObject());
571 if (lpServer->m_fDelete)
573 if (fNotify && !fNotified)
575 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServersBegin, GetIdentifier());
576 fNotified = TRUE;
578 lpServer->SendDeleteNotifications();
579 m_lServers->Remove (lpServer);
580 Delete (lpServer);
585 // Fix m_apszServers if we did anything to the list of servers
587 if (fNotified)
589 if (m_apszServers)
591 for (size_t ii = 0; m_apszServers[ii]; ++ii)
592 FreeString (m_apszServers[ii]);
593 Free (m_apszServers);
594 m_apszServers = NULL;
597 size_t cServers = 0;
598 LPENUM pEnum;
599 for (pEnum = m_lServers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
600 ++cServers;
602 if (cServers)
604 m_apszServers = (char**)Allocate (sizeof(char*) * (1+cServers));
605 memset (m_apszServers, 0x00, sizeof(char*) * (1+cServers));
607 size_t iServer = 0;
608 for (pEnum = m_lServers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
610 LPSERVER lpServer = (LPSERVER)(pEnum->GetObject());
611 m_apszServers[ iServer ] = AllocateAnsi (cchNAME+1);
612 CopyStringToAnsi (m_apszServers[ iServer ], lpServer->m_szName);
613 ++iServer;
618 if (fNotified)
619 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshServersEnd, GetIdentifier(), ((rc) ? 0 : status));
621 if (pStatus && !rc)
622 *pStatus = status;
623 return rc;
628 * SERVER-LIST KEYS ___________________________________________________________
632 BOOL CALLBACK CELL::KeyServerName_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
634 if (!lstrcmp (((LPSERVER)pObject)->m_szName, (LPTSTR)pData))
635 return TRUE;
637 TCHAR szShortName[ cchNAME ];
638 SERVER::ShortenName (szShortName, ((LPSERVER)pObject)->m_szName);
639 if (!lstrcmp (szShortName, (LPTSTR)pData))
640 return TRUE;
642 return FALSE;
645 HASHVALUE CALLBACK CELL::KeyServerName_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
647 return CELL::KeyServerName_HashData (pKey, ((LPSERVER)pObject)->m_szName);
650 HASHVALUE CALLBACK CELL::KeyServerName_HashData (LPHASHLISTKEY pKey, PVOID pData)
652 TCHAR szShortName[ cchNAME ];
653 SERVER::ShortenName (szShortName, (LPTSTR)pData);
654 return HashString (szShortName);
658 BOOL CALLBACK CELL::KeyServerAddr_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
660 return !memcmp (&((LPSERVER)pObject)->m_ss.aAddresses[0], (LPSOCKADDR)pData, sizeof(SOCKADDR_IN));
663 HASHVALUE CALLBACK CELL::KeyServerAddr_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
665 return CELL::KeyServerAddr_HashData (pKey, &((LPSERVER)pObject)->m_ss.aAddresses[0]);
668 HASHVALUE CALLBACK CELL::KeyServerAddr_HashData (LPHASHLISTKEY pKey, PVOID pData)
670 return *(DWORD*)pData;
674 BOOL CALLBACK CELL::KeyUserName_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
676 return !lstrcmpi (((LPUSER)pObject)->m_szPrincipal, (LPTSTR)pData);
679 HASHVALUE CALLBACK CELL::KeyUserName_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
681 return CELL::KeyUserName_HashData (pKey, ((LPUSER)pObject)->m_szPrincipal);
684 HASHVALUE CALLBACK CELL::KeyUserName_HashData (LPHASHLISTKEY pKey, PVOID pData)
686 return HashString ((LPTSTR)pData);
690 BOOL CALLBACK CELL::KeyGroupName_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
692 return !lstrcmpi (((LPPTSGROUP)pObject)->m_szName, (LPTSTR)pData);
695 HASHVALUE CALLBACK CELL::KeyGroupName_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
697 return CELL::KeyGroupName_HashData (pKey, ((LPPTSGROUP)pObject)->m_szName);
700 HASHVALUE CALLBACK CELL::KeyGroupName_HashData (LPHASHLISTKEY pKey, PVOID pData)
702 return HashString ((LPTSTR)pData);
707 * CELL OBJECT ________________________________________________________________
711 PVOID CELL::GetCellObject (ULONG *pStatus)
713 if (!m_hCell)
715 ULONG status;
716 NOTIFYCALLBACK::SendNotificationToAll (evtOpenCellBegin, m_szName);
718 WORKERPACKET wpOpen;
719 wpOpen.wpClientCellOpen.pszCell = m_szName;
720 wpOpen.wpClientCellOpen.hCreds = m_hCreds;
722 if (Worker_DoTask (wtaskClientCellOpen, &wpOpen, &status))
723 m_hCell = wpOpen.wpClientCellOpen.hCell;
725 if (pStatus)
726 *pStatus = status;
727 NOTIFYCALLBACK::SendNotificationToAll (evtOpenCellEnd, m_szName, status);
730 return m_hCell;
734 BOOL CELL::CloseCellObject (ULONG *pStatus)
736 BOOL rc = TRUE;
738 if (m_hCell != NULL)
740 WORKERPACKET wp;
741 wp.wpClientCellClose.hCell = m_hCell;
742 rc = Worker_DoTask (wtaskClientCellClose, &wp, pStatus);
743 m_hCell = NULL;
746 return rc;
750 PVOID CELL::GetKasObject (ULONG *pStatus)
752 // m_hKas is actually never set non-NULL;
753 // leaving it NULL indicates we will work happily with *any* server.
755 return m_hKas;
759 BOOL CELL::CloseKasObject (ULONG *pStatus)
761 BOOL rc = TRUE;
763 if (m_hKas != NULL)
765 WORKERPACKET wp;
766 wp.wpKasServerClose.hServer = m_hKas;
767 rc = Worker_DoTask (wtaskKasServerClose, &wp, pStatus);
768 m_hKas = NULL;
771 return rc;
776 * CELL GENERAL _______________________________________________________________
780 LPIDENT CELL::GetIdentifier (void)
782 if (m_lpiThis == NULL)
784 if ((m_lpiThis = IDENT::FindIdent (this)) == NULL)
785 m_lpiThis = New2 (IDENT,(this));
786 m_lpiThis->m_cRef ++;
789 return m_lpiThis;
793 void CELL::GetName (LPTSTR pszName)
795 lstrcpy (pszName, m_szName);
799 PVOID CELL::GetUserParam (void)
801 return GetIdentifier()->GetUserParam();
805 void CELL::SetUserParam (PVOID pUserNew)
807 GetIdentifier()->SetUserParam (pUserNew);
811 BOOL CELL::fAnyServersUnmonitored (void)
813 return (m_nServersUnmonitored > 0) ? TRUE : FALSE;
818 * CELL STATUS ________________________________________________________________
822 void CELL::Invalidate (void)
824 if (!m_fServersOutOfDate || !m_fStatusOutOfDate || !m_fVLDBOutOfDate || !m_fUsersOutOfDate)
826 CloseKasObject();
827 CloseCellObject();
828 m_fServersOutOfDate = TRUE;
829 m_fStatusOutOfDate = TRUE;
830 m_fVLDBOutOfDate = TRUE;
831 m_fUsersOutOfDate = TRUE;
832 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
837 void CELL::InvalidateServers (void)
839 if (!m_fServersOutOfDate || !m_fVLDBOutOfDate)
841 CloseKasObject();
842 CloseCellObject();
843 m_fServersOutOfDate = TRUE;
844 m_fVLDBOutOfDate = TRUE;
845 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
850 void CELL::InvalidateUsers (void)
852 if (!m_fUsersOutOfDate)
854 m_fUsersOutOfDate = TRUE;
855 NOTIFYCALLBACK::SendNotificationToAll (evtInvalidate, GetIdentifier());
860 BOOL CELL::RefreshStatus (BOOL fNotify, ULONG *pStatus)
862 BOOL rc = TRUE;
863 ULONG status = 0;
865 if (m_fStatusOutOfDate)
867 if (fNotify)
868 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier());
870 // Hmmm...well, actually, there's nothing for us to do here. I'm
871 // leaving this around, because the refreshed-cell-status notification
872 // may be useful as an appropriate hooking point.
873 rc = TRUE;
874 status = 0;
876 if (fNotify)
877 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status));
880 if (pStatus && !rc)
881 *pStatus = status;
882 return rc;
886 BOOL CELL::RefreshVLDB (BOOL fNotify, ULONG *pStatus)
888 BOOL rc = TRUE;
890 if (m_fVLDBOutOfDate)
892 if ((rc = RefreshVLDB (GetIdentifier(), fNotify, pStatus)) == TRUE)
894 m_fVLDBOutOfDate = FALSE;
898 return rc;
902 BOOL CELL::RefreshVLDB (LPIDENT lpiRef, BOOL fNotify, ULONG *pStatus, BOOL fAnythingRelatedToThisRWFileset)
904 BOOL rc = TRUE;
905 DWORD status = 0;
907 // What is the scope of this refresh operation? The entire cell,
908 // or the filesets on a particular server or aggregate?
910 LPIDENT lpiRefCell = (lpiRef == NULL) ? GetIdentifier() : lpiRef->GetCell();
911 LPIDENT lpiRefServer = NULL;
912 LPIDENT lpiRefAggregate = NULL;
913 LPIDENT lpiRefFileset = NULL;
914 VOLUMEID *pvidRefFileset = NULL;
915 VOLUMEID vidRefFileset;
917 if (fAnythingRelatedToThisRWFileset)
919 pvidRefFileset = &vidRefFileset;
920 lpiRef->GetFilesetID (pvidRefFileset);
922 else
924 if (lpiRef && !lpiRef->fIsCell())
926 lpiRefServer = lpiRef->GetServer();
928 if (lpiRef && (lpiRef->fIsAggregate() || lpiRef->fIsFileset()))
930 lpiRefAggregate = lpiRef->GetAggregate();
932 if (lpiRef && lpiRef->fIsFileset())
934 lpiRefFileset = lpiRef;
938 // If we've been told to update only one server, aggregate or
939 // fileset, find out which IP addresses correspond with that
940 // server. We'll need this for comparisons later.
942 SERVERSTATUS ssRefServer;
943 if (rc && lpiRefServer)
945 LPSERVER lpServer;
946 if ((lpServer = lpiRefServer->OpenServer (&status)) == NULL)
947 rc = FALSE;
948 else
950 rc = lpServer->GetStatus (&ssRefServer, fNotify, &status);
951 lpServer->Close();
955 // Likewise, if we've been told to update only one aggregate,
956 // find that aggregate's ID. We'll need it for comparisons later.
958 AGGREGATESTATUS asRefAggregate;
959 int idPartition = NO_PARTITION;
960 if (rc && lpiRefAggregate)
962 LPAGGREGATE lpAggregate;
963 if ((lpAggregate = lpiRefAggregate->OpenAggregate (&status)) == NULL)
964 rc = FALSE;
965 else
967 idPartition = lpAggregate->GetID();
968 rc = lpAggregate->GetStatus (&asRefAggregate, fNotify, &status);
969 lpAggregate->Close();
973 // Zip through the current list of objects that we're about to refresh.
974 // On each such object, remove the GHOST_HAS_VLDB_ENTRY flag,
975 // and delete objects entirely if that's the only ghost flag they have.
976 // (e.g., If we went through this routine earlier and created a ghost
977 // aggregate because VLDB referenced it and we couldn't find mention
978 // of it on the server, delete that aggregate. We'll recreate it here
979 // if necessary; otherwise, it needs to be gone.)
981 if (rc)
983 RefreshVLDB_RemoveReferences (lpiRefServer, lpiRefAggregate, lpiRefFileset, pvidRefFileset);
986 // We'll get a new list of filesets from VLDB, and to do that, we'll
987 // need the cell's object. If we're enumerating a specific server, we'll
988 // also need that server's object. Finally, if we're enumerating a
989 // specific aggregate, we'll also need that aggregate's name.
991 PVOID hCell = NULL;
992 PVOID hServer = NULL;
994 if (rc)
996 if (!lpiRefServer)
998 if ((hCell = GetCellObject (&status)) == NULL)
999 rc = FALSE;
1001 else // get cell and server handles
1003 LPSERVER lpServer;
1004 if ((lpServer = lpiRefServer->OpenServer()) == NULL)
1005 rc = FALSE;
1006 else
1008 if ((hServer = lpServer->OpenVosObject (&hCell, &status)) == NULL)
1009 rc = FALSE;
1010 lpServer->Close();
1015 // Go get that list of filesets, and use it to update our knowledge
1016 // of the cell. Remember that, if {pvidRefFileset}, we only want
1017 // one VLDB entry.
1019 if (rc)
1021 if (pvidRefFileset)
1023 WORKERPACKET wpGet;
1024 wpGet.wpVosVLDBGet.hCell = hCell;
1025 wpGet.wpVosVLDBGet.idVolume = *pvidRefFileset;
1027 if (!Worker_DoTask (wtaskVosVLDBGet, &wpGet, &status))
1028 rc = FALSE;
1029 else
1030 RefreshVLDB_OneEntry (&wpGet.wpVosVLDBGet.Data, lpiRefServer, &ssRefServer, lpiRefAggregate, &asRefAggregate, lpiRefFileset, pvidRefFileset, fNotify);
1032 else
1034 WORKERPACKET wpBegin;
1035 wpBegin.wpVosVLDBGetBegin.hCell = hCell;
1036 wpBegin.wpVosVLDBGetBegin.hServer = hServer;
1037 wpBegin.wpVosVLDBGetBegin.idPartition = idPartition;
1039 if (!Worker_DoTask (wtaskVosVLDBGetBegin, &wpBegin, &status))
1040 rc = FALSE;
1041 else
1043 for (;;)
1045 WORKERPACKET wpNext;
1046 wpNext.wpVosVLDBGetNext.hEnum = wpBegin.wpVosVLDBGetBegin.hEnum;
1047 if (!Worker_DoTask (wtaskVosVLDBGetNext, &wpNext, &status))
1049 if (status == ADMITERATORDONE)
1050 status = 0;
1051 else
1052 rc = FALSE;
1053 break;
1056 RefreshVLDB_OneEntry (&wpNext.wpVosVLDBGetNext.Data, lpiRefServer, &ssRefServer, lpiRefAggregate, &asRefAggregate, lpiRefFileset, pvidRefFileset, fNotify);
1059 WORKERPACKET wpDone;
1060 wpDone.wpVosVLDBGetDone.hEnum = wpBegin.wpVosVLDBGetBegin.hEnum;
1061 Worker_DoTask (wtaskVosVLDBGetDone, &wpDone);
1066 // We've finished the update. If we were asked to send notifications
1067 // about our progress, do so.
1069 if (fNotify)
1071 LPIDENT lpiNotify = (lpiRef) ? lpiRef : GetIdentifier();
1073 if (!lpiNotify->fIsFileset())
1075 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshFilesetsBegin, lpiNotify);
1076 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshFilesetsEnd, lpiNotify, status);
1079 if (lpiNotify->fIsCell() || lpiNotify->fIsServer())
1081 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAggregatesBegin, lpiNotify);
1082 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAggregatesEnd, lpiNotify, status);
1086 if (hServer)
1088 LPSERVER lpServer;
1089 if ((lpServer = lpiRefServer->OpenServer()) != NULL)
1091 lpServer->CloseVosObject();
1092 lpServer->Close();
1096 if (pStatus && !rc)
1097 *pStatus = status;
1098 return rc;
1102 void CELL::RefreshVLDB_RemoveReferences (LPIDENT lpiRefServer, LPIDENT lpiRefAggregate, LPIDENT lpiRefFileset, LPVOLUMEID pvidRefFileset)
1104 // Zip through the current list of objects that we're about to refresh.
1105 // On each such object, remove the GHOST_HAS_VLDB_ENTRY flag,
1106 // and delete objects entirely if that's the only ghost flag they have.
1107 // (e.g., If we went through this routine earlier and created a ghost
1108 // aggregate because VLDB referenced it and we couldn't find mention
1109 // of it on the server, delete that aggregate. We'll recreate it here
1110 // if necessary; otherwise, it needs to be gone.)
1112 // Note that by specifying {lpiRefServer} to start the enumeration,
1113 // we'll either enumerate only lpiRefServer, or all servers if it's NULL.
1115 HENUM heServer;
1116 for (LPSERVER lpServer = ServerFindFirst (&heServer, lpiRefServer); lpServer; lpServer = ServerFindNext (&heServer))
1119 if (!pvidRefFileset)
1121 // Since we're about to check VLDB for references to this server,
1122 // remove the GHOST_HAS_VLDB_ENTRY flag from its SERVER object.
1123 // If that's the only thing keeping the object around, remove the
1124 // object entirely.
1126 if ((lpServer->m_wGhost &= (~GHOST_HAS_VLDB_ENTRY)) == 0)
1128 lpServer->Close();
1129 lpServer->SendDeleteNotifications();
1130 m_lServers->Remove (lpServer);
1131 Delete (lpServer);
1132 continue;
1136 // Check each of the server's aggregates, and deal with them the same
1137 // way.
1139 HENUM heAggregate;
1140 for (LPAGGREGATE lpAggregate = lpServer->AggregateFindFirst (&heAggregate, lpiRefAggregate); lpAggregate; lpAggregate = lpServer->AggregateFindNext (&heAggregate))
1143 if (!pvidRefFileset)
1145 // Since we're about to check VLDB for references to this aggregate,
1146 // remove the GHOST_HAS_VLDB_ENTRY flag from its AGGREGATE object.
1147 // If that's the only thing keeping the object around, remove the
1148 // object entirely.
1150 if ((lpAggregate->m_wGhost &= (~GHOST_HAS_VLDB_ENTRY)) == 0)
1152 lpAggregate->Close();
1153 lpAggregate->SendDeleteNotifications();
1154 lpServer->m_lAggregates->Remove (lpAggregate);
1155 Delete (lpAggregate);
1156 continue;
1160 // Check each of the aggregate's filesets, and deal with them the same
1161 // way.
1163 HENUM heFileset;
1164 for (LPFILESET lpFileset = lpAggregate->FilesetFindFirst (&heFileset, lpiRefFileset); lpFileset; lpFileset = lpAggregate->FilesetFindNext (&heFileset))
1166 if ((!pvidRefFileset) || (*pvidRefFileset == lpFileset->m_fs.idReadWrite))
1168 // Since we're about to check VLDB for references to this fileset,
1169 // remove the GHOST_HAS_VLDB_ENTRY flag from its FILESET object.
1170 // If that's the only thing keeping the object around, remove the
1171 // object entirely.
1173 if ((lpFileset->m_wGhost &= (~GHOST_HAS_VLDB_ENTRY)) == 0)
1175 lpFileset->Close();
1176 lpFileset->SendDeleteNotifications();
1177 lpAggregate->m_lFilesets->Remove (lpFileset);
1178 Delete (lpFileset);
1179 continue;
1183 lpFileset->Close();
1186 lpAggregate->Close();
1189 lpServer->Close();
1194 void CELL::RefreshVLDB_OneEntry (PVOID pp, LPIDENT lpiRefServer, LPSERVERSTATUS pssRefServer, LPIDENT lpiRefAggregate, LPAGGREGATESTATUS pasRefAggregate, LPIDENT lpiRefFileset, LPVOLUMEID pvidRefFileset, BOOL fNotify)
1196 vos_vldbEntry_p pEntry = (vos_vldbEntry_p)pp;
1198 // If we were asked to update all the replicas of a particular
1199 // fileset, then we set {pvidRefFileset} above to that fileset's
1200 // ID. Check this VLDB entry to see if it refers to that fileset;
1201 // if not, we're not interested in it.
1203 if (pvidRefFileset)
1205 if (memcmp (&pEntry->volumeId[ VOS_READ_WRITE_VOLUME ], pvidRefFileset, sizeof(VOLUMEID)))
1206 return;
1209 for (int iRepSite = 0; iRepSite < pEntry->numServers; ++iRepSite)
1211 SOCKADDR_IN RepSiteAddr;
1212 AfsClass_IntToAddress (&RepSiteAddr, pEntry->volumeSites[ iRepSite ].serverAddress);
1214 // Every fileset replication site which VLDB knows about
1215 // passes through this point, within {pEntry->volumeSites[ iRepSite ]}.
1217 // Are we going to be refreshing the server/aggregate on which
1218 // this repsite lives? If not, there's no need to process this
1219 // entry any further.
1221 if (lpiRefServer)
1223 BOOL fFilesetLivesOnThisServer = FALSE;
1225 for (size_t iAddress = 0; !fFilesetLivesOnThisServer && (iAddress < pssRefServer->nAddresses); ++iAddress)
1227 if (!memcmp (&pssRefServer->aAddresses[ iAddress ], &RepSiteAddr, sizeof(SOCKADDR_IN)))
1229 if (lpiRefAggregate)
1231 if (pasRefAggregate->dwID != (DWORD)(pEntry->volumeSites[ iRepSite ].serverPartition))
1232 continue;
1234 fFilesetLivesOnThisServer = TRUE;
1238 if (!fFilesetLivesOnThisServer)
1239 continue;
1242 // Do we know about the server mentioned by this replication
1243 // site?
1245 LPSERVER lpServer;
1246 if (lpiRefServer != NULL)
1247 lpServer = lpiRefServer->OpenServer();
1248 else
1249 lpServer = OpenServer (&RepSiteAddr);
1251 // If we found the server but aren't monitoring it,
1252 // forget about this fileset.
1254 if (lpServer && !lpServer->fIsMonitored())
1256 lpServer->Close();
1257 lpServer = NULL;
1258 continue;
1261 // If we have no record of the server mentioned by this
1262 // replication site, we have to create a SERVER entry for
1263 // it before we can proceed. The server will appear as
1264 // a "ghost".
1266 if (!lpServer)
1268 if (lpiRefAggregate || pvidRefFileset)
1269 continue;
1271 LPTSTR pszServer = FormatString (TEXT("%1"), TEXT("%a"), &pEntry->volumeSites[ iRepSite ].serverAddress);
1272 lpServer = New2 (SERVER,(this, pszServer));
1273 AfsClass_Enter();
1274 FreeString (pszServer);
1276 lpServer->m_fStatusOutOfDate = FALSE;
1277 lpServer->m_ss.nAddresses = 1;
1278 memcpy (&lpServer->m_ss.aAddresses[0], &RepSiteAddr, sizeof(SOCKADDR_IN));
1280 m_lServers->Add (lpServer);
1282 if (fNotify)
1283 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpServer->GetIdentifier());
1286 lpServer->m_wGhost |= GHOST_HAS_VLDB_ENTRY;
1288 // Great--we now have a replication site for a particular
1289 // fileset known to VLDB, and a pointer to the server
1290 // on which it resides. Does that server contain the
1291 // aggregate which VLDB expects to find?
1293 LPAGGREGATE lpAggregate;
1294 if (lpiRefAggregate != NULL)
1295 lpAggregate = lpiRefAggregate->OpenAggregate();
1296 else
1297 lpAggregate = lpServer->OpenAggregate (pEntry->volumeSites[ iRepSite ].serverPartition);
1299 // If the server has no record of the aggregate mentioned
1300 // by this replication site, we have to create an
1301 // AGGREGATE entry for it before we can proceed. The
1302 // aggregate will appear as a "ghost". Note that we
1303 // can't update the list of aggregates on a server if
1304 // we've been asked to update a particular fileset,
1305 // because someone clearly has a pointer to the list.
1307 if (!lpAggregate)
1309 if (lpiRefFileset || pvidRefFileset)
1311 lpServer->Close();
1312 lpServer = NULL;
1313 continue;
1316 // Even if the partition doesn't exist, we can still figger out
1317 // its name given its ID--'cause there's a 1:1 mapping between
1318 // allowed IDs and allowed partition names. I guess there's
1319 // something to be said for forcing partitions to be named "vicep*"
1321 TCHAR szPartition[ cchNAME ];
1322 WORKERPACKET wp;
1323 wp.wpVosPartitionIdToName.idPartition = pEntry->volumeSites[ iRepSite ].serverPartition;
1324 wp.wpVosPartitionIdToName.pszPartition = szPartition;
1325 if (!Worker_DoTask (wtaskVosPartitionIdToName, &wp))
1326 wsprintf (szPartition, TEXT("#%lu"), pEntry->volumeSites[ iRepSite ].serverPartition);
1328 lpAggregate = New2 (AGGREGATE,(lpServer, szPartition, TEXT("")));
1329 AfsClass_Enter();
1331 lpAggregate->m_fStatusOutOfDate = FALSE;
1332 lpAggregate->m_as.dwID = pEntry->volumeSites[ iRepSite ].serverPartition;
1333 lpAggregate->m_as.ckStorageTotal = 0;
1334 lpAggregate->m_as.ckStorageFree = 0;
1336 lpServer->m_lAggregates->Add (lpAggregate);
1338 if (fNotify)
1339 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpAggregate->GetIdentifier());
1342 lpAggregate->m_wGhost |= GHOST_HAS_VLDB_ENTRY;
1344 // Great--we now have a replication site for a particular
1345 // fileset known to VLDB, and a pointer to the server
1346 // and aggregate on which it resides. Does that aggregate
1347 // contain the fileset which VLDB expects to find?
1349 // Remember that each iRepSite can represent up to three
1350 // filesets on that aggregate--a RW, a RO, and a BAK.
1352 for (size_t iType = 0; iType < 3; ++iType)
1355 // Does this repsite entry mention having this type
1356 // of fileset on this aggregate?
1358 if ((vos_volumeType_t)iType == VOS_READ_WRITE_VOLUME)
1360 if (!((DWORD)pEntry->volumeSites[ iRepSite ].serverFlags & (DWORD)VOS_VLDB_READ_WRITE))
1361 continue;
1363 else if ((vos_volumeType_t)iType == VOS_READ_ONLY_VOLUME)
1365 if (!((DWORD)pEntry->volumeSites[ iRepSite ].serverFlags & (DWORD)VOS_VLDB_READ_ONLY))
1366 continue;
1368 else if ((vos_volumeType_t)iType == VOS_BACKUP_VOLUME)
1370 if (!((DWORD)pEntry->status & (DWORD)VOS_VLDB_ENTRY_BACKEXISTS))
1371 continue;
1373 // Only look for the backup where the R/W exists
1374 if (!((DWORD)pEntry->volumeSites[ iRepSite ].serverFlags & (DWORD)VOS_VLDB_READ_WRITE))
1375 continue;
1378 LPFILESET lpFileset = lpAggregate->OpenFileset ((LPVOLUMEID)&pEntry->volumeId[ iType ]);
1380 // If the aggregate has no record of the fileset mentioned
1381 // by this VLDB entry, we have to create a FILESET entry
1382 // for it. The fileset will appear as a "ghost".
1384 if (!lpFileset)
1386 TCHAR szFilesetName[ cchNAME ];
1387 CopyAnsiToString (szFilesetName, pEntry->name);
1388 if ((vos_volumeType_t)iType == VOS_READ_ONLY_VOLUME)
1389 lstrcat (szFilesetName, TEXT(".readonly"));
1390 else if ((vos_volumeType_t)iType == VOS_BACKUP_VOLUME)
1391 lstrcat (szFilesetName, TEXT(".backup"));
1393 lpFileset = New2 (FILESET,(lpAggregate, &pEntry->volumeId[ iType ], szFilesetName));
1394 AfsClass_Enter();
1396 lpFileset->m_fs.id = pEntry->volumeId[ iType ];
1397 lpFileset->m_fs.idReadWrite = pEntry->volumeId[ VOS_READ_WRITE_VOLUME ];
1398 lpFileset->m_fs.idReplica = pEntry->volumeId[ VOS_READ_ONLY_VOLUME ];
1399 AfsClass_UnixTimeToSystemTime (&lpFileset->m_fs.timeCreation, 0);
1400 AfsClass_UnixTimeToSystemTime (&lpFileset->m_fs.timeLastUpdate, 0);
1401 AfsClass_UnixTimeToSystemTime (&lpFileset->m_fs.timeLastAccess, 0);
1402 AfsClass_UnixTimeToSystemTime (&lpFileset->m_fs.timeLastBackup, 0);
1403 AfsClass_UnixTimeToSystemTime (&lpFileset->m_fs.timeCopyCreation, 0);
1404 lpFileset->m_fs.nFiles = 0;
1405 lpFileset->m_fs.ckQuota = 0;
1406 lpFileset->m_fs.ckUsed = 0;
1407 lpFileset->m_fs.Type = (iType == 0) ? ftREADWRITE : (iType == 1) ? ftREPLICA : ftCLONE;
1408 lpFileset->m_fs.State = fsNORMAL;
1410 lpAggregate->m_lFilesets->Add (lpFileset);
1412 if (fNotify)
1413 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpFileset->GetIdentifier());
1416 if (fNotify)
1417 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, lpFileset->GetIdentifier());
1419 lpFileset->m_wGhost |= GHOST_HAS_VLDB_ENTRY;
1420 lpFileset->m_fStatusOutOfDate = FALSE;
1421 lpFileset->m_fs.idClone = pEntry->cloneId;
1422 lpFileset->m_fs.State &= ~fsMASK_VLDB;
1424 if (pEntry->status & VOS_VLDB_ENTRY_LOCKED)
1425 lpFileset->m_fs.State |= fsLOCKED;
1427 lpFileset->Close();
1429 if (fNotify)
1430 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, lpFileset->GetIdentifier(), 0);
1433 if (lpServer && lpAggregate)
1435 lpAggregate->InvalidateAllocation();
1436 lpAggregate->Close();
1437 lpAggregate = NULL;
1439 if (lpServer)
1441 lpServer->Close();
1442 lpServer = NULL;
1448 BOOL CELL::RefreshAll (ULONG *pStatus)
1450 BOOL rc = TRUE;
1451 ULONG status = 0;
1453 BOOL fNotified = FALSE;
1455 if (m_fServersOutOfDate && (dwWant & AFSCLASS_WANT_VOLUMES))
1457 if (!fNotified)
1459 fNotified = TRUE;
1460 if ((++cRefreshAllReq) == 1)
1462 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllBegin, GetIdentifier());
1466 ULONG nServersToRefresh = 0;
1468 HENUM hEnum;
1469 for (LPSERVER lpServer = ServerFindFirst (&hEnum); lpServer; lpServer = ServerFindNext (&hEnum))
1471 if (lpServer->fIsMonitored())
1472 ++nServersToRefresh;
1473 lpServer->Close();
1476 if (nServersToRefresh)
1478 size_t iServer = 0;
1479 for (LPSERVER lpServer = ServerFindFirst (&hEnum); lpServer; lpServer = ServerFindNext (&hEnum))
1481 if (lpServer->fIsMonitored())
1483 ULONG perComplete = (ULONG)iServer * 100L / nServersToRefresh;
1484 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllUpdate, lpServer->GetIdentifier(), NULL, NULL, NULL, perComplete, 0);
1486 // intentionally ignore errors in refreshing individual
1487 // servers--we only want to return an error code if
1488 // we couldn't refresh the *cell*.
1490 (void)lpServer->RefreshAll (NULL, ((double)iServer / (double)nServersToRefresh), (1.0 / (double)nServersToRefresh));
1491 ++iServer;
1493 lpServer->Close();
1496 rc = RefreshVLDB (NULL, TRUE, &status);
1500 if (rc && m_fUsersOutOfDate && (dwWant & AFSCLASS_WANT_USERS))
1502 if (!fNotified)
1504 fNotified = TRUE;
1505 if ((++cRefreshAllReq) == 1)
1507 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllBegin, GetIdentifier(), NULL, NULL, NULL, 0, 0);
1511 rc = RefreshUsers (TRUE, &status);
1514 if (fNotified)
1516 if ((--cRefreshAllReq) == 0)
1518 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllEnd, GetIdentifier(), NULL, NULL, NULL, 100, status);
1522 if (!rc && pStatus)
1523 *pStatus = status;
1524 return rc;
1529 * USER/GROUP-LIST MANAGEMENT _________________________________________________
1533 LPUSER CELL::OpenUser (LPTSTR pszName, LPTSTR pszInstance, ULONG *pStatus)
1535 ULONG status = 0;
1537 // First off, do we have a USER object for this guy already?
1539 LPUSER lpUser = NULL;
1540 for (LPENUM pEnum = m_lkUserName->FindFirst (pszName); pEnum; pEnum = pEnum->FindNext())
1542 LPUSER lpTest = (LPUSER)( pEnum->GetObject() );
1543 if (!pszInstance || !lstrcmpi (lpTest->m_szInstance, pszInstance))
1545 lpUser = lpTest;
1546 AfsClass_Enter();
1547 Delete (pEnum);
1548 break;
1552 // If not, see if we can create one...
1554 if (!lpUser)
1556 // See if there's a KAS or PTS entry for this user.
1558 BOOL fHasKAS = FALSE;
1559 BOOL fHasPTS = FALSE;
1561 WORKERPACKET wp;
1562 wp.wpKasPrincipalGet.hCell = GetCellObject (&status);
1563 wp.wpKasPrincipalGet.hServer = GetKasObject (&status);
1564 wp.wpKasPrincipalGet.pszPrincipal = pszName;
1565 wp.wpKasPrincipalGet.pszInstance = pszInstance;
1566 if (Worker_DoTask (wtaskKasPrincipalGet, &wp, &status))
1567 fHasKAS = TRUE;
1569 if (!fHasKAS)
1571 TCHAR szFullName[ cchNAME ];
1572 AfsClass_GenFullUserName (szFullName, pszName, pszInstance);
1574 WORKERPACKET wp;
1575 wp.wpPtsUserGet.hCell = GetCellObject();
1576 wp.wpPtsUserGet.pszUser = szFullName;
1577 if (Worker_DoTask (wtaskPtsUserGet, &wp, &status))
1578 fHasPTS = TRUE;
1580 if (fHasKAS || fHasPTS)
1582 lpUser = New2 (USER,(this, pszName, pszInstance));
1583 m_lUsers->Add (lpUser);
1584 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpUser->GetIdentifier());
1585 AfsClass_Enter();
1589 if (!lpUser && pStatus)
1590 *pStatus = status;
1591 return lpUser;
1595 LPUSER CELL::UserFindFirst (HENUM *phEnum, BOOL fNotify, ULONG *pStatus)
1597 return UserFindFirst (phEnum, NULL, fNotify, pStatus);
1601 LPUSER CELL::UserFindFirst (HENUM *phEnum, LPIDENT lpiFind, BOOL fNotify, ULONG *pStatus)
1603 LPUSER lpUser = NULL;
1605 if (!RefreshUsers (fNotify, pStatus))
1606 return NULL;
1608 if (lpiFind != NULL)
1610 lpUser = lpiFind->OpenUser();
1611 *phEnum = NULL;
1613 else if ((*phEnum = m_lUsers->FindFirst()) != NULL)
1615 lpUser = (LPUSER)( (*phEnum)->GetObject() );
1616 AfsClass_Enter();
1619 if (!lpUser && pStatus)
1620 *pStatus = ERROR_FILE_NOT_FOUND;
1621 return lpUser;
1625 LPUSER CELL::UserFindNext (HENUM *phEnum)
1627 LPUSER lpUser = NULL;
1629 if (*phEnum)
1631 if ((*phEnum = (*phEnum)->FindNext()) != NULL)
1633 lpUser = (LPUSER)( (*phEnum)->GetObject() );
1634 AfsClass_Enter();
1638 return lpUser;
1642 void CELL::UserFindClose (HENUM *phEnum)
1644 if (*phEnum)
1646 Delete (*phEnum);
1647 *phEnum = NULL;
1653 LPPTSGROUP CELL::OpenGroup (LPTSTR pszName, ULONG *pStatus)
1655 ULONG status;
1657 // First off, do we have a USER object for this guy already?
1659 LPPTSGROUP lpGroup;
1660 if ((lpGroup = (LPPTSGROUP)(m_lkGroupName->GetFirstObject (pszName))) != NULL)
1661 AfsClass_Enter();
1663 // If not, see if we can create one...
1665 if (!lpGroup)
1667 // See if there's a PTS entry for this group.
1669 WORKERPACKET wp;
1670 wp.wpPtsGroupGet.hCell = GetCellObject();
1671 wp.wpPtsGroupGet.pszGroup = pszName;
1672 if (Worker_DoTask (wtaskPtsGroupGet, &wp, &status))
1674 lpGroup = New2 (PTSGROUP,(this, pszName));
1675 m_lGroups->Add (lpGroup);
1676 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpGroup->GetIdentifier());
1677 AfsClass_Enter();
1681 if (!lpGroup && pStatus)
1682 *pStatus = status;
1683 return lpGroup;
1687 LPPTSGROUP CELL::GroupFindFirst (HENUM *phEnum, BOOL fNotify, ULONG *pStatus)
1689 return GroupFindFirst (phEnum, NULL, fNotify, pStatus);
1693 LPPTSGROUP CELL::GroupFindFirst (HENUM *phEnum, LPIDENT lpiFind, BOOL fNotify, ULONG *pStatus)
1695 LPPTSGROUP lpGroup = NULL;
1697 if (!RefreshUsers (fNotify, pStatus))
1698 return NULL;
1700 if (lpiFind != NULL)
1702 lpGroup = lpiFind->OpenGroup();
1703 *phEnum = NULL;
1705 else if ((*phEnum = m_lGroups->FindFirst()) != NULL)
1707 lpGroup = (LPPTSGROUP)( (*phEnum)->GetObject() );
1708 AfsClass_Enter();
1711 if (!lpGroup && pStatus)
1712 *pStatus = ERROR_FILE_NOT_FOUND;
1713 return lpGroup;
1717 LPPTSGROUP CELL::GroupFindNext (HENUM *phEnum)
1719 LPPTSGROUP lpGroup = NULL;
1721 if (*phEnum)
1723 if ((*phEnum = (*phEnum)->FindNext()) != NULL)
1725 lpGroup = (LPPTSGROUP)( (*phEnum)->GetObject() );
1726 AfsClass_Enter();
1730 return lpGroup;
1734 void CELL::GroupFindClose (HENUM *phEnum)
1736 if (*phEnum)
1738 Delete (*phEnum);
1739 *phEnum = NULL;
1744 BOOL CELL::RefreshUsers (BOOL fNotify, ULONG *pStatus)
1746 BOOL rc = TRUE;
1747 ULONG status = 0;
1749 if (m_fUsersOutOfDate)
1751 m_fUsersOutOfDate = FALSE;
1753 if (fNotify)
1754 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshUsersBegin, GetIdentifier());
1756 // First, forget everything we think we know about all users and groups;
1757 // we wouldn't be here if someone didn't think it was all out of date.
1759 FreeUsers (TRUE);
1761 // Then zip through KAS to build a list of all user entries;
1762 // we'll need hCell and hKAS for that.
1764 WORKERPACKET wpBegin;
1765 wpBegin.wpKasPrincipalGetBegin.hCell = GetCellObject();
1766 wpBegin.wpKasPrincipalGetBegin.hServer = GetKasObject (&status);
1768 if (!Worker_DoTask (wtaskKasPrincipalGetBegin, &wpBegin, &status))
1769 rc = FALSE;
1770 else
1772 for (;;)
1774 TCHAR szPrincipal[ cchNAME ];
1775 TCHAR szInstance[ cchNAME ];
1777 WORKERPACKET wpNext;
1778 wpNext.wpKasPrincipalGetNext.hEnum = wpBegin.wpKasPrincipalGetBegin.hEnum;
1779 wpNext.wpKasPrincipalGetNext.pszPrincipal = szPrincipal;
1780 wpNext.wpKasPrincipalGetNext.pszInstance = szInstance;
1781 if (!Worker_DoTask (wtaskKasPrincipalGetNext, &wpNext, &status))
1783 if (status == ADMITERATORDONE)
1784 status = 0;
1785 else
1786 rc = FALSE;
1787 break;
1790 // Okay, we got a user from kas. Create a USER object for it.
1792 LPUSER lpUser = New2 (USER,(this, szPrincipal, szInstance));
1793 m_lUsers->Add (lpUser);
1795 // That was easy, wasn't it? Now check this user's groups,
1796 // both the ones it owns and the ones to which it belongs,
1797 // so we can build a full list-o-groups.
1799 LPTSTR mszGroups;
1800 if (lpUser->GetMemberOf (&mszGroups))
1802 BuildGroups (mszGroups);
1803 FreeString (mszGroups);
1806 if (lpUser->GetOwnerOf (&mszGroups))
1808 BuildGroups (mszGroups);
1809 FreeString (mszGroups);
1813 WORKERPACKET wpDone;
1814 wpDone.wpKasPrincipalGetDone.hEnum = wpBegin.wpKasPrincipalGetBegin.hEnum;
1815 Worker_DoTask (wtaskKasPrincipalGetDone, &wpDone);
1818 #ifdef FIND_PTS_DEBRIS
1819 // Icky horrible painful part: to catch entries which exist on PTS
1820 // but not in KAS, we need to zip back through our list of groups
1821 // and check thier memberships.
1823 for (LPENUM pe = m_lGroups->FindFirst(); pe; pe = pe->FindNext())
1825 LPPTSGROUP lpGroup = (LPPTSGROUP)(pe->GetObject());
1827 LPTSTR mszMembers;
1828 if (lpGroup->GetMembers (&mszMembers))
1830 for (LPTSTR pszMember = mszMembers; pszMember && *pszMember; pszMember += 1+lstrlen(pszMember))
1832 // Make sure we have a user or group account for this guy.
1833 // Remember that the member name may have both a name and
1834 // an instance.
1836 if (m_lkGroupName->GetFirstObject (pszMember))
1837 continue;
1839 TCHAR szNameMatch[ cchNAME ];
1840 TCHAR szInstanceMatch[ cchNAME ];
1841 USER::SplitUserName (pszMember, szNameMatch, szInstanceMatch);
1843 LPUSER lpFound = NULL;
1844 for (LPENUM pEnum = m_lkUserName->FindFirst (szNameMatch); pEnum; pEnum = pEnum->FindNext())
1846 LPUSER lpTest = (LPUSER)( pEnum->GetObject() );
1847 if (!lstrcmpi (lpTest->m_szInstance, szInstanceMatch))
1849 lpFound = lpTest;
1850 Delete (pEnum);
1851 break;
1854 if (lpFound)
1855 continue;
1857 // Uh oh. Is this thing a user or a group? We're really only
1858 // interested in finding user-account debris here...
1860 WORKERPACKET wpGet;
1861 wpGet.wpPtsUserGet.hCell = GetCellObject();
1862 wpGet.wpPtsUserGet.pszUser = pszMember;
1863 if (Worker_DoTask (wtaskPtsUserGet, &wpGet))
1865 if (wpGet.wpPtsUserGet.Entry.nameUid > 0)
1867 LPUSER lpUser = New2 (USER,(this, pszMember, TEXT("")));
1868 m_lUsers->Add (lpUser);
1874 #endif
1876 // We've finally generated a complete list of the users and groups in
1877 // this cell. If we've been asked to, send out notifications for all
1878 // the things we found.
1880 if (fNotify)
1882 LPENUM pEnum;
1883 for (pEnum = m_lGroups->FindFirst(); pEnum; pEnum = pEnum->FindNext())
1885 LPPTSGROUP lpGroup = (LPPTSGROUP)(pEnum->GetObject());
1886 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpGroup->GetIdentifier());
1889 for (pEnum = m_lUsers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
1891 LPUSER lpUser = (LPUSER)(pEnum->GetObject());
1892 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpUser->GetIdentifier());
1895 NOTIFYCALLBACK::SendNotificationToAll (evtRefreshUsersEnd, GetIdentifier(), ((rc) ? 0 : status));
1899 if (!rc && pStatus)
1900 *pStatus = status;
1901 return rc;
1905 void CELL::BuildGroups (LPTSTR mszGroups)
1907 for (LPTSTR pszGroup = mszGroups; pszGroup && *pszGroup; pszGroup += 1+lstrlen(pszGroup))
1909 // Make sure we have this group in our list-of-groups
1911 LPPTSGROUP lpGroup;
1912 if ((lpGroup = (LPPTSGROUP)m_lkGroupName->GetFirstObject (pszGroup)) == NULL)
1914 lpGroup = New2 (PTSGROUP,(this, pszGroup));
1915 m_lGroups->Add (lpGroup);
1921 BOOL CELL::RefreshAccount (LPTSTR pszAccount, LPTSTR pszInstance, OP_CELL_REFRESH_ACCOUNT Op, LPIDENT *plpi)
1923 BOOL rc = TRUE;
1925 // See if we can find this thing
1927 LPIDENT lpi;
1928 if ((lpi = IDENT::FindUser (m_lpiThis, pszAccount, pszInstance)) != NULL)
1930 if (lpi->m_cRef == 0)
1931 lpi = NULL;
1933 if (!lpi)
1935 if ((lpi = IDENT::FindGroup (m_lpiThis, pszAccount)) != NULL)
1936 if (lpi->m_cRef == 0)
1937 lpi = NULL;
1940 // If we couldn't find it, and Op is _CREATED_*, then make a new account
1942 if ((!lpi) && (Op == CELL_REFRESH_ACCOUNT_CREATED_USER))
1944 LPUSER lpUser = New2 (USER,(this, pszAccount, pszInstance));
1945 m_lUsers->Add (lpUser);
1946 lpi = lpUser->GetIdentifier();
1947 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpi);
1949 else if ((!lpi) && (Op == CELL_REFRESH_ACCOUNT_CREATED_GROUP))
1951 LPPTSGROUP lpGroup = New2 (PTSGROUP,(this, pszAccount));
1952 m_lGroups->Add (lpGroup);
1953 lpi = lpGroup->GetIdentifier();
1954 NOTIFYCALLBACK::SendNotificationToAll (evtCreate, lpi);
1957 // If we did find it, and Op is _DELETED, then remove the account
1959 if (lpi && (Op == CELL_REFRESH_ACCOUNT_DELETED))
1961 if (lpi && (lpi->GetType() == itUSER))
1963 LPUSER lpUser;
1964 if ((lpUser = lpi->OpenUser()) == NULL)
1965 rc = FALSE;
1966 else
1968 lpUser->SendDeleteNotifications();
1969 lpUser->Close();
1970 m_lUsers->Remove (lpUser);
1971 Delete (lpUser);
1972 lpi = NULL;
1975 else if (lpi && (lpi->GetType() == itGROUP))
1977 LPPTSGROUP lpGroup;
1978 if ((lpGroup = lpi->OpenGroup()) == NULL)
1979 rc = FALSE;
1980 else
1982 lpGroup->SendDeleteNotifications();
1983 lpGroup->Close();
1984 m_lGroups->Remove (lpGroup);
1985 Delete (lpGroup);
1986 lpi = NULL;
1989 else
1991 rc = FALSE;
1995 // If we still have an ident, refresh the account's properties
1997 if (lpi && (lpi->GetType() == itUSER))
1999 LPUSER lpUser;
2000 if ((lpUser = lpi->OpenUser()) == NULL)
2001 rc = FALSE;
2002 else
2004 lpUser->Invalidate();
2005 lpUser->RefreshStatus();
2006 lpUser->Close();
2009 else if (lpi && (lpi->GetType() == itGROUP))
2011 LPPTSGROUP lpGroup;
2012 if ((lpGroup = lpi->OpenGroup()) == NULL)
2013 rc = FALSE;
2014 else
2016 lpGroup->Invalidate();
2017 lpGroup->RefreshStatus();
2018 lpGroup->Close();
2022 if (plpi)
2023 *plpi = lpi;
2024 return rc;
2028 BOOL CELL::RefreshAccounts (LPTSTR mszAccounts, OP_CELL_REFRESH_ACCOUNT Op)
2030 BOOL rc = TRUE;
2031 for (LPTSTR psz = mszAccounts; psz && *psz; psz += 1+lstrlen(psz))
2033 if (!RefreshAccount (psz, NULL, Op))
2034 rc = FALSE;
2036 return rc;