2 * Copyright (c) 2007-2010 Secure Endpoints Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Neither the name of the Secure Endpoints Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /* This source file provides the declarations
30 * which specify the AFS Cache Manager Volume Status Event
34 #include <afsconfig.h>
35 #include <afs/param.h>
47 #include <WINNT/afsreg.h>
49 extern DWORD RDR_NetworkAddrChange(void);
50 extern DWORD RDR_VolumeStatus(ULONG cellID, ULONG volID, BOOLEAN online);
51 extern DWORD RDR_NetworkStatus(BOOLEAN status);
53 HMODULE hVolStatus = NULL;
54 dll_VolStatus_Funcs_t dll_funcs;
55 cm_VolStatus_Funcs_t cm_funcs;
57 static char volstat_NetbiosName[64] = "";
59 static DWORD RDR_Notifications = 0;
61 rdr_volstat_evt_t *rdr_evtH = NULL;
62 rdr_volstat_evt_t *rdr_evtT = NULL;
64 static EVENT_HANDLE rdr_q_event = NULL;
66 static osi_mutex_t rdr_evt_lock;
69 cm_VolStatus_SetRDRNotifications(DWORD onoff)
71 RDR_Notifications = onoff;
75 cm_VolStatus_Active(void)
77 return (hVolStatus != NULL);
80 /* This function is used to load any Volume Status Handlers
81 * and their associated function pointers.
84 cm_VolStatus_Initialization(void)
86 long (__fastcall * dll_VolStatus_Initialization)(dll_VolStatus_Funcs_t * dll_funcs, cm_VolStatus_Funcs_t *cm_funcs) = NULL;
90 char wd[MAX_PATH+1] = "";
92 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
93 0, KEY_QUERY_VALUE, &parmKey);
94 if (code == ERROR_SUCCESS) {
95 dummyLen = sizeof(wd);
96 code = RegQueryValueEx(parmKey, "VolStatusHandler", NULL, NULL,
97 (BYTE *) &wd, &dummyLen);
99 if (code == ERROR_SUCCESS) {
100 dummyLen = sizeof(volstat_NetbiosName);
101 code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
102 (BYTE *)volstat_NetbiosName, &dummyLen);
104 if (code == ERROR_SUCCESS && wd[0])
105 hVolStatus = LoadLibrary(wd);
107 dummyLen = sizeof(wd);
108 code = RegQueryValueEx(parmKey, "RDRVolStatNotify", NULL, NULL,
109 (BYTE *) &RDR_Notifications, &dummyLen);
111 RegCloseKey (parmKey);
115 (FARPROC) dll_VolStatus_Initialization = GetProcAddress(hVolStatus, "@VolStatus_Initialization@8");
116 if (dll_VolStatus_Initialization) {
117 cm_funcs.version = CM_VOLSTATUS_FUNCS_VERSION;
118 cm_funcs.cm_VolStatus_Path_To_ID = cm_VolStatus_Path_To_ID;
119 cm_funcs.cm_VolStatus_Path_To_DFSlink = cm_VolStatus_Path_To_DFSlink;
121 dll_funcs.version = DLL_VOLSTATUS_FUNCS_VERSION;
122 code = dll_VolStatus_Initialization(&dll_funcs, &cm_funcs);
125 if (dll_VolStatus_Initialization == NULL || code != 0 ||
126 dll_funcs.version != DLL_VOLSTATUS_FUNCS_VERSION) {
127 FreeLibrary(hVolStatus);
133 if (RDR_Initialized && RDR_Notifications) {
137 lock_InitializeMutex(&rdr_evt_lock, "rdr_evt_lock", LOCK_HIERARCHY_IGNORE);
139 phandle = thrd_Create((SecurityAttrib) NULL, 0,
140 (ThreadFunc) cm_VolStatus_DeliverNotifications,
141 0, 0, &pid, "cm_VolStatus_DeliverNotifications");
142 osi_assertx(phandle != NULL, "cm_VolStatus_DeliverNotifications thread creation failure");
143 thrd_CloseHandle(phandle);
145 rdr_q_event = thrd_CreateEvent(NULL, TRUE, TRUE, "rdr_q_event");
146 if ( GetLastError() == ERROR_ALREADY_EXISTS )
147 afsi_log("Event Object Already Exists: rdr_q_event");
150 osi_Log1(afsd_logp,"cm_VolStatus_Initialization 0x%x", code);
155 /* This function is used to unload any Volume Status Handlers
156 * that were loaded during initialization.
159 cm_VolStatus_Finalize(void)
161 osi_Log1(afsd_logp,"cm_VolStatus_Finalize handle 0x%x", hVolStatus);
163 if ( RDR_Initialized && RDR_Notifications ) {
164 CloseHandle(rdr_q_event);
167 if (hVolStatus == NULL)
170 FreeLibrary(hVolStatus);
175 /* This function notifies the Volume Status Handlers that the
176 * AFS client service has started. If the network is started
177 * at this point we call cm_VolStatus_Network_Started().
180 cm_VolStatus_Service_Started(void)
184 osi_Log1(afsd_logp,"cm_VolStatus_Service_Started handle 0x%x", hVolStatus);
186 if (hVolStatus == NULL)
189 code = dll_funcs.dll_VolStatus_Service_Started();
190 if (code == 0 && smb_IsNetworkStarted())
191 code = dll_funcs.dll_VolStatus_Network_Started(cm_NetbiosName, cm_NetbiosName);
196 /* This function notifies the Volume Status Handlers that the
197 * AFS client service is stopping.
200 cm_VolStatus_Service_Stopped(void)
204 osi_Log1(afsd_logp,"cm_VolStatus_Service_Stopped handle 0x%x", hVolStatus);
206 if (hVolStatus == NULL)
209 code = dll_funcs.dll_VolStatus_Service_Stopped();
215 /* This function notifies the Volume Status Handlers that the
216 * AFS client service is accepting network requests using the
217 * specified netbios names.
221 cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64)
223 cm_VolStatus_Network_Started(const char * netbios32)
228 if (RDR_Initialized && RDR_Notifications) {
229 rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
230 evp->type = netstatus;
231 evp->netstatus_data.status = TRUE;
233 lock_ObtainMutex(&rdr_evt_lock);
234 osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
235 lock_ReleaseMutex(&rdr_evt_lock);
237 thrd_SetEvent(rdr_q_event);
240 if (hVolStatus == NULL)
244 code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64);
246 code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios32);
252 /* This function notifies the Volume Status Handlers that the
253 * AFS client service is no longer accepting network requests
254 * using the specified netbios names
258 cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64)
260 cm_VolStatus_Network_Stopped(const char * netbios32)
265 if (RDR_Initialized && RDR_Notifications) {
266 rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
267 evp->type = netstatus;
268 evp->netstatus_data.status = FALSE;
270 lock_ObtainMutex(&rdr_evt_lock);
271 osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
272 lock_ReleaseMutex(&rdr_evt_lock);
274 thrd_SetEvent(rdr_q_event);
277 if (hVolStatus == NULL)
281 code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64);
283 code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios32);
289 /* This function is called when the IP address list changes.
290 * Volume Status Handlers can use this notification as a hint
291 * that it might be possible to determine volume IDs for paths
292 * that previously were not accessible.
295 cm_VolStatus_Network_Addr_Change(void)
299 if (RDR_Initialized && RDR_Notifications) {
300 rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
303 lock_ObtainMutex(&rdr_evt_lock);
304 osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
305 lock_ReleaseMutex(&rdr_evt_lock);
307 thrd_SetEvent(rdr_q_event);
310 if (hVolStatus == NULL)
313 code = dll_funcs.dll_VolStatus_Network_Addr_Change();
318 /* This function notifies the Volume Status Handlers that the
319 * state of the specified cell.volume has changed.
322 cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status)
326 if (RDR_Initialized && RDR_Notifications) {
327 rdr_volstat_evt_t *evp = (rdr_volstat_evt_t *)malloc(sizeof(rdr_volstat_evt_t));
331 evp->type = volstatus;
332 evp->volstatus_data.cellID = cellID;
333 evp->volstatus_data.volID = volID;
334 evp->volstatus_data.online = FALSE;
336 lock_ObtainMutex(&rdr_evt_lock);
337 osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
338 lock_ReleaseMutex(&rdr_evt_lock);
341 evp->type = volstatus;
342 evp->volstatus_data.cellID = cellID;
343 evp->volstatus_data.volID = volID;
344 evp->volstatus_data.online = TRUE;
346 lock_ObtainMutex(&rdr_evt_lock);
347 osi_QAddH((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
348 lock_ReleaseMutex(&rdr_evt_lock);
351 thrd_SetEvent(rdr_q_event);
354 if (hVolStatus == NULL)
357 code = dll_funcs.dll_VolStatus_Change_Notification(cellID, volID, status);
365 cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, const clientchar_t *ctidPathp,
366 const clientchar_t *cpathp)
371 char * tidPathp = NULL;
374 if (hVolStatus == NULL || dll_funcs.version < 2)
377 tidPathp = cm_ClientStringToUtf8Alloc(ctidPathp, -1, NULL);
378 pathp = cm_ClientStringToUtf8Alloc(cpathp, -1, NULL);
380 snprintf(src,sizeof(src), "\\\\%s%s", volstat_NetbiosName, tidPathp);
382 if ((src[len-1] == '\\' || src[len-1] == '/') &&
383 (pathp[0] == '\\' || pathp[0] == '/'))
384 strncat(src, &pathp[1], sizeof(src));
386 strncat(src, pathp, sizeof(src));
388 for ( p=src; *p; p++ ) {
393 code = dll_funcs.dll_VolStatus_Notify_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
394 src, scp->mountPointStringp);
405 cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp)
409 if (hVolStatus == NULL || dll_funcs.version < 2)
412 code = dll_funcs.dll_VolStatus_Invalidate_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
419 cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID, enum volstatus *pstatus)
425 clientchar_t * cpath = NULL;
426 clientchar_t * cshare = NULL;
428 if (cellID == NULL || volID == NULL)
429 return CM_ERROR_INVAL;
431 osi_Log2(afsd_logp,"cm_VolStatus_Path_To_ID share %s path %s",
432 osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
436 cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
437 cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
439 if (cpath == NULL || cshare == NULL) {
440 osi_Log1(afsd_logp, "Can't convert %s string. Aborting",
441 (cpath == NULL)? "path" : "share");
442 code = CM_ERROR_NOSUCHPATH;
446 code = cm_NameI(cm_RootSCachep(cm_rootUserp, &req), cpath,
447 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
448 cm_rootUserp, cshare, &req, &scp);
452 lock_ObtainWrite(&scp->rw);
453 code = cm_SyncOp(scp, NULL,cm_rootUserp, &req, 0,
454 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
456 lock_ReleaseWrite(&scp->rw);
457 cm_ReleaseSCache(scp);
461 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
463 *cellID = scp->fid.cell;
464 *volID = scp->fid.volume;
465 volp = cm_GetVolumeByFID(&scp->fid);
467 *pstatus = cm_GetVolumeStatus(volp, scp->fid.volume);
470 *pstatus = vl_unknown;
472 lock_ReleaseWrite(&scp->rw);
473 cm_ReleaseSCache(scp);
481 osi_Log1(afsd_logp,"cm_VolStatus_Path_To_ID code 0x%x",code);
486 cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer)
492 clientchar_t *cpath = NULL;
493 clientchar_t *cshare = NULL;
495 if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0))
496 return CM_ERROR_INVAL;
498 osi_Log2(afsd_logp,"cm_VolStatus_Path_To_DFSlink share %s path %s",
499 osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
503 cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
504 cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
506 if (cpath == NULL || cshare == NULL) {
507 osi_Log1(afsd_logp, "Can't convert %s string. Aborting",
508 (cpath == NULL)? "path" : "share");
509 code = CM_ERROR_NOSUCHPATH;
513 code = cm_NameI(cm_RootSCachep(cm_rootUserp, &req), cpath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
514 cm_rootUserp, cshare, &req, &scp);
518 lock_ObtainWrite(&scp->rw);
519 code = cm_SyncOp(scp, NULL, cm_rootUserp, &req, 0,
520 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
522 lock_ReleaseWrite(&scp->rw);
523 cm_ReleaseSCache(scp);
527 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
529 if (scp->fileType != CM_SCACHETYPE_DFSLINK) {
530 code = CM_ERROR_NOT_A_DFSLINK;
534 len = strlen(scp->mountPointStringp) + 1;
537 else if (*pBufSize >= len) {
538 strcpy(pBuffer, scp->mountPointStringp);
541 code = CM_ERROR_TOOBIG;
545 lock_ReleaseWrite(&scp->rw);
546 cm_ReleaseSCache(scp);
554 osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code);
559 cm_VolStatus_DeliverNotifications(void * dummy)
561 rdr_volstat_evt_t *evp, *evprev;
565 code = thrd_WaitForSingleObject_Event( rdr_q_event, INFINITE );
567 lock_ObtainMutex(&rdr_evt_lock);
568 for (evp = rdr_evtT; evp; evp = evprev)
570 evprev = (rdr_volstat_evt_t *) osi_QPrev(&evp->q);
571 osi_QRemoveHT((osi_queue_t **) &rdr_evtH, (osi_queue_t **) &rdr_evtT, &evp->q);
572 lock_ReleaseMutex(&rdr_evt_lock);
574 switch ( evp->type ) {
576 RDR_NetworkAddrChange();
579 RDR_VolumeStatus(evp->volstatus_data.cellID, evp->volstatus_data.volID, evp->volstatus_data.online);
582 RDR_NetworkStatus(evp->netstatus_data.status);
587 lock_ObtainMutex(&rdr_evt_lock);
589 lock_ReleaseMutex(&rdr_evt_lock);