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