e90183aecaf2a2234ddb9b93312fc159f92b6369
[openafs.git] / src / WINNT / afsd / cm_volstat.c
1 /* 
2  * Copyright (c) 2007 Secure Endpoints Inc.
3  *
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  * 
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.
15  * 
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.
27  */
28
29 /* This source file provides the declarations 
30  * which specify the AFS Cache Manager Volume Status Event
31  * Notification API
32  */
33
34 #include <afs/param.h>
35 #include <afs/stds.h>
36
37 #include <windows.h>
38 #include <winsock2.h>
39 #include <nb30.h>
40 #include <string.h>
41 #include <malloc.h>
42 #include "afsd.h"
43 #include <WINNT/afsreg.h>
44
45 HMODULE hVolStatus = NULL;
46 dll_VolStatus_Funcs_t dll_funcs;
47 cm_VolStatus_Funcs_t cm_funcs;
48
49 static char volstat_NetbiosName[64] = "";
50
51 afs_uint32
52 cm_VolStatus_Active(void)
53 {
54     return (hVolStatus != NULL);
55 }
56
57 /* This function is used to load any Volume Status Handlers 
58  * and their associated function pointers.  
59  */
60 long 
61 cm_VolStatus_Initialization(void)
62 {
63     long (__fastcall * dll_VolStatus_Initialization)(dll_VolStatus_Funcs_t * dll_funcs, cm_VolStatus_Funcs_t *cm_funcs) = NULL;
64     long code = 0;
65     HKEY parmKey;
66     DWORD dummyLen;
67     char wd[MAX_PATH+1] = "";
68
69     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
70                          0, KEY_QUERY_VALUE, &parmKey);
71     if (code == ERROR_SUCCESS) {
72         dummyLen = sizeof(wd);
73         code = RegQueryValueEx(parmKey, "VolStatusHandler", NULL, NULL,
74                                 (BYTE *) &wd, &dummyLen);
75
76         if (code == 0) {
77             dummyLen = sizeof(volstat_NetbiosName);
78             code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL, 
79                                    (BYTE *)volstat_NetbiosName, &dummyLen);
80         }
81         RegCloseKey (parmKey);
82     }
83
84     if (code == ERROR_SUCCESS && wd[0])
85         hVolStatus = LoadLibrary(wd);
86     if (hVolStatus) {
87         (FARPROC) dll_VolStatus_Initialization = GetProcAddress(hVolStatus, "@VolStatus_Initialization@8");
88         if (dll_VolStatus_Initialization) {
89             cm_funcs.version = CM_VOLSTATUS_FUNCS_VERSION;
90             cm_funcs.cm_VolStatus_Path_To_ID = cm_VolStatus_Path_To_ID;
91             cm_funcs.cm_VolStatus_Path_To_DFSlink = cm_VolStatus_Path_To_DFSlink;
92
93             dll_funcs.version = DLL_VOLSTATUS_FUNCS_VERSION;
94             code = dll_VolStatus_Initialization(&dll_funcs, &cm_funcs);
95         } 
96
97         if (dll_VolStatus_Initialization == NULL || code != 0 || 
98             dll_funcs.version != DLL_VOLSTATUS_FUNCS_VERSION) {
99             FreeLibrary(hVolStatus);
100             hVolStatus = NULL;
101             code = -1;
102         }
103     }
104
105     osi_Log1(afsd_logp,"cm_VolStatus_Initialization 0x%x", code);
106
107     return code;
108 }
109
110 /* This function is used to unload any Volume Status Handlers
111  * that were loaded during initialization.
112  */
113 long 
114 cm_VolStatus_Finalize(void)
115 {
116     osi_Log1(afsd_logp,"cm_VolStatus_Finalize handle 0x%x", hVolStatus);
117
118     if (hVolStatus == NULL)
119         return 0;
120
121     FreeLibrary(hVolStatus);
122     hVolStatus = NULL;
123     return 0;
124 }
125
126 /* This function notifies the Volume Status Handlers that the
127  * AFS client service has started.  If the network is started
128  * at this point we call cm_VolStatus_Network_Started().
129  */
130 long 
131 cm_VolStatus_Service_Started(void)
132 {
133     long code = 0;
134
135     osi_Log1(afsd_logp,"cm_VolStatus_Service_Started handle 0x%x", hVolStatus);
136
137     if (hVolStatus == NULL)
138         return 0;
139    
140     code = dll_funcs.dll_VolStatus_Service_Started();
141     if (code == 0 && smb_IsNetworkStarted())
142         code = dll_funcs.dll_VolStatus_Network_Started(cm_NetbiosName, cm_NetbiosName);
143
144     return code;
145 }
146
147 /* This function notifies the Volume Status Handlers that the
148  * AFS client service is stopping.
149  */
150 long 
151 cm_VolStatus_Service_Stopped(void)
152 {
153     long code = 0;
154
155     osi_Log1(afsd_logp,"cm_VolStatus_Service_Stopped handle 0x%x", hVolStatus);
156
157     if (hVolStatus == NULL)
158         return 0;
159    
160     code = dll_funcs.dll_VolStatus_Service_Stopped();
161
162     return code;
163 }
164
165
166 /* This function notifies the Volume Status Handlers that the
167  * AFS client service is accepting network requests using the 
168  * specified netbios names.
169  */
170 long
171 #ifdef _WIN64
172 cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64)
173 #else /* _WIN64 */
174 cm_VolStatus_Network_Started(const char * netbios)
175 #endif /* _WIN64 */
176 {
177     long code = 0;
178
179     if (hVolStatus == NULL)
180         return 0;
181
182 #ifdef _WIN64
183     code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64);
184 #else
185     code = dll_funcs.dll_VolStatus_Network_Started(netbios, netbios);
186 #endif
187
188     return code;
189 }
190
191 /* This function notifies the Volume Status Handlers that the
192  * AFS client service is no longer accepting network requests 
193  * using the specified netbios names 
194  */
195 long
196 #ifdef _WIN64
197 cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64)
198 #else /* _WIN64 */
199 cm_VolStatus_Network_Stopped(const char * netbios)
200 #endif /* _WIN64 */
201 {
202     long code = 0;
203
204     if (hVolStatus == NULL)
205         return 0;
206
207 #ifdef _WIN64
208     code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64);
209 #else
210     code = dll_funcs.dll_VolStatus_Network_Stopped(netbios, netbios);
211 #endif
212
213     return code;
214 }
215
216 /* This function is called when the IP address list changes.
217  * Volume Status Handlers can use this notification as a hint 
218  * that it might be possible to determine volume IDs for paths 
219  * that previously were not accessible.  
220  */
221 long 
222 cm_VolStatus_Network_Addr_Change(void)
223 {
224     long code = 0;
225
226     if (hVolStatus == NULL)
227         return 0;
228
229     code = dll_funcs.dll_VolStatus_Network_Addr_Change();
230
231     return code;
232 }
233
234 /* This function notifies the Volume Status Handlers that the 
235  * state of the specified cell.volume has changed.
236  */
237 long 
238 cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status)
239 {
240     long code = 0;
241
242     if (hVolStatus == NULL)
243         return 0;
244
245     code = dll_funcs.dll_VolStatus_Change_Notification(cellID, volID, status);
246
247     return code;
248 }
249
250
251
252 long
253 cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp)
254 {
255     long code = 0;
256     char src[1024], *p;
257     size_t len;
258
259     if (hVolStatus == NULL || dll_funcs.version < 2)
260         return 0;
261
262     snprintf(src,sizeof(src), "\\\\%s%s", volstat_NetbiosName, tidPathp);
263     len = strlen(src);
264     if ((src[len-1] == '\\' || src[len-1] == '/') &&
265         (pathp[0] == '\\' || pathp[0] == '/'))
266         strncat(src, &pathp[1], sizeof(src));
267     else
268         strncat(src, pathp, sizeof(src));
269
270     for ( p=src; *p; p++ ) {
271         if (*p == '/')
272             *p = '\\';
273     }
274
275     code = dll_funcs.dll_VolStatus_Notify_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
276                                                       src, scp->mountPointStringp);
277
278     return code;
279 }
280
281 long
282 cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp)
283 {
284     long code = 0;
285
286     if (hVolStatus == NULL || dll_funcs.version < 2)
287         return 0;
288
289     code = dll_funcs.dll_VolStatus_Invalidate_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
290
291     return code;
292 }
293
294
295 long __fastcall
296 cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID, enum volstatus *pstatus)
297 {
298     afs_uint32  code = 0;
299     cm_req_t    req;
300     cm_scache_t *scp;
301     cm_volume_t *volp;
302
303     if (cellID == NULL || volID == NULL)
304         return CM_ERROR_INVAL;
305
306     osi_Log2(afsd_logp,"cm_VolStatus_Path_To_ID share %s path %s", 
307               osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
308
309     cm_InitReq(&req);
310
311     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp);
312     if (code)
313         goto done;
314
315     lock_ObtainWrite(&scp->rw);
316     code = cm_SyncOp(scp, NULL,cm_rootUserp, &req, 0,
317                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
318     if (code) {
319         lock_ReleaseWrite(&scp->rw);
320         cm_ReleaseSCache(scp);
321         goto done;
322     }
323         
324     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
325
326     *cellID = scp->fid.cell;
327     *volID  = scp->fid.volume;
328     volp = cm_GetVolumeByFID(&scp->fid);
329     if (volp) {
330         *pstatus = cm_GetVolumeStatus(volp, scp->fid.volume);
331         cm_PutVolume(volp);
332     } else
333         *pstatus = vl_unknown;
334
335     lock_ReleaseWrite(&scp->rw);
336     cm_ReleaseSCache(scp);
337
338   done:
339     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_ID code 0x%x",code); 
340     return code;
341 }
342
343 long __fastcall
344 cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer)
345 {
346     afs_uint32  code = 0;
347     cm_req_t    req;
348     cm_scache_t *scp;
349     size_t      len;
350
351     if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0))
352         return CM_ERROR_INVAL;
353
354     osi_Log2(afsd_logp,"cm_VolStatus_Path_To_DFSlink share %s path %s", 
355               osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
356
357     cm_InitReq(&req);
358
359     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
360                     cm_rootUserp, (char *)share, &req, &scp);
361     if (code)
362         goto done;
363
364     lock_ObtainWrite(&scp->rw);
365     code = cm_SyncOp(scp, NULL, cm_rootUserp, &req, 0,
366                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
367     if (code) {
368         lock_ReleaseWrite(&scp->rw);
369         cm_ReleaseSCache(scp);
370         goto done;
371     }
372         
373     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
374
375     if (scp->fileType != CM_SCACHETYPE_DFSLINK) {
376         code = CM_ERROR_NOT_A_DFSLINK;
377         goto done;
378     }
379
380     len = strlen(scp->mountPointStringp) + 1;
381     if (pBuffer == NULL)
382         *pBufSize = len;
383     else if (*pBufSize >= len) {
384         strcpy(pBuffer, scp->mountPointStringp);
385         *pBufSize = len;
386     } else {
387         code = CM_ERROR_TOOBIG;
388         goto done;
389     }
390
391     lock_ReleaseWrite(&scp->rw);
392     cm_ReleaseSCache(scp);
393
394   done:
395     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code); 
396     return code;
397 }