windows-volstat-and-vista-dfs-support-20071222
[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
302     if (cellID == NULL || volID == NULL)
303         return CM_ERROR_INVAL;
304
305     osi_Log2(afsd_logp,"cm_VolStatus_Path_To_ID share %s path %s", 
306               osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
307
308     cm_InitReq(&req);
309
310     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp);
311     if (code)
312         goto done;
313
314     lock_ObtainMutex(&scp->mx);
315     code = cm_SyncOp(scp, NULL,cm_rootUserp, &req, 0,
316                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
317     if (code) {
318         lock_ReleaseMutex(&scp->mx);
319         cm_ReleaseSCache(scp);
320         goto done;
321     }
322         
323     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
324
325     *cellID = scp->fid.cell;
326     *volID  = scp->fid.volume;
327     *pstatus = cm_GetVolumeStatus(scp->volp, scp->fid.volume);
328
329     lock_ReleaseMutex(&scp->mx);
330     cm_ReleaseSCache(scp);
331
332   done:
333     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_ID code 0x%x",code); 
334     return code;
335 }
336
337 long __fastcall
338 cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer)
339 {
340     afs_uint32  code = 0;
341     cm_req_t    req;
342     cm_scache_t *scp;
343     size_t      len;
344
345     if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0))
346         return CM_ERROR_INVAL;
347
348     osi_Log2(afsd_logp,"cm_VolStatus_Path_To_DFSlink share %s path %s", 
349               osi_LogSaveString(afsd_logp, (char *)share), osi_LogSaveString(afsd_logp, (char *)path));
350
351     cm_InitReq(&req);
352
353     code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
354                     cm_rootUserp, (char *)share, &req, &scp);
355     if (code)
356         goto done;
357
358     lock_ObtainMutex(&scp->mx);
359     code = cm_SyncOp(scp, NULL, cm_rootUserp, &req, 0,
360                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
361     if (code) {
362         lock_ReleaseMutex(&scp->mx);
363         cm_ReleaseSCache(scp);
364         goto done;
365     }
366         
367     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
368
369     if (scp->fileType != CM_SCACHETYPE_DFSLINK) {
370         code = CM_ERROR_NOT_A_DFSLINK;
371         goto done;
372     }
373
374     len = strlen(scp->mountPointStringp) + 1;
375     if (pBuffer == NULL)
376         *pBufSize = len;
377     else if (*pBufSize >= len) {
378         strcpy(pBuffer, scp->mountPointStringp);
379         *pBufSize = len;
380     } else {
381         code = CM_ERROR_TOOBIG;
382         goto done;
383     }
384
385     lock_ReleaseMutex(&scp->mx);
386     cm_ReleaseSCache(scp);
387
388   done:
389     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code); 
390     return code;
391 }