2611259b5e5d5409b88423229ce365effbcebc23
[openafs.git] / src / WINNT / afsrdr / kernel / fs / AFSNetworkProviderSupport.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
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 notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSNetworkProviderSupport.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 NTSTATUS
42 AFSAddConnectionEx( IN UNICODE_STRING *RemoteName,
43                     IN ULONG DisplayType,
44                     IN ULONG Flags)
45 {
46
47     NTSTATUS ntStatus = STATUS_SUCCESS;
48     AFSProviderConnectionCB *pConnection = NULL, *pLastConnection = NULL, *pServerConnection = NULL;
49     UNICODE_STRING uniRemoteName;
50     AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
51
52     __Enter
53     {
54
55         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
56                       AFS_TRACE_LEVEL_VERBOSE,
57                       "AFSAddConnectionEx Acquiring AFSProviderListLock lock %08lX EXCL %08lX\n",
58                       &pRDRDevExt->Specific.RDR.ProviderListLock,
59                       PsGetCurrentThread());
60
61         AFSAcquireExcl( &pRDRDevExt->Specific.RDR.ProviderListLock,
62                         TRUE);
63
64
65         AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER,
66                       AFS_TRACE_LEVEL_VERBOSE,
67                       "AFSAddConnectionEx remote name %wZ display type %08lX flags %08lX\n",
68                       RemoteName,
69                       DisplayType,
70                       Flags);
71
72         //
73         // If this is a server, start in the enum list, otherwise
74         // locate the server node
75         //
76
77         if( DisplayType == RESOURCEDISPLAYTYPE_SERVER)
78         {
79
80             pConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList;
81         }
82         else
83         {
84
85             pServerConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList; // For now we have only one server ...
86
87             if( pServerConnection == NULL)
88             {
89
90                 try_return( ntStatus);
91             }
92
93             pConnection = pServerConnection->EnumerationList;
94         }
95
96         //
97         // Look for the connection
98         //
99
100         uniRemoteName.Length = RemoteName->Length;
101         uniRemoteName.MaximumLength = RemoteName->Length;
102
103         uniRemoteName.Buffer = RemoteName->Buffer;
104
105         while( pConnection != NULL)
106         {
107
108             if( RtlCompareUnicodeString( &uniRemoteName,
109                                          &pConnection->RemoteName,
110                                          TRUE) == 0)
111             {
112
113                 break;
114             }
115
116             pConnection = pConnection->fLink;
117         }
118
119         if( pConnection != NULL)
120         {
121
122             try_return( ntStatus);
123         }
124
125         //
126         // Strip off any trailing slashes
127         //
128
129         if( uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] == L'\\')
130         {
131
132             uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] = L'\0';
133
134             uniRemoteName.Length -= sizeof( WCHAR);
135         }
136
137         AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER,
138                       AFS_TRACE_LEVEL_VERBOSE,
139                       "AFSAddConnectionEx Inserting remote name %wZ\n", &uniRemoteName);
140
141         //
142         // Allocate a new node and add it to our list
143         //
144
145         pConnection = (AFSProviderConnectionCB *)AFSExAllocatePoolWithTag( PagedPool,
146                                                                            sizeof( AFSProviderConnectionCB) +
147                                                                            uniRemoteName.Length,
148                                                                            AFS_PROVIDER_CB);
149
150         if( pConnection == NULL)
151         {
152
153             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
154         }
155
156         RtlZeroMemory( pConnection,
157                        sizeof( AFSProviderConnectionCB) + uniRemoteName.Length);
158
159         pConnection->LocalName = L'\0';
160
161         pConnection->RemoteName.Length = uniRemoteName.Length;
162         pConnection->RemoteName.MaximumLength = pConnection->RemoteName.Length;
163
164         pConnection->RemoteName.Buffer = (WCHAR *)((char *)pConnection + sizeof( AFSProviderConnectionCB));
165
166         RtlCopyMemory( pConnection->RemoteName.Buffer,
167                        uniRemoteName.Buffer,
168                        pConnection->RemoteName.Length);
169
170         //
171         // Point to the component portion of the name
172         //
173
174         pConnection->ComponentName.Length = 0;
175         pConnection->ComponentName.MaximumLength = 0;
176
177         pConnection->ComponentName.Buffer = &pConnection->RemoteName.Buffer[ (pConnection->RemoteName.Length/sizeof( WCHAR)) - 1];
178
179         while( pConnection->ComponentName.Length <= pConnection->RemoteName.Length)
180         {
181
182             if( pConnection->ComponentName.Buffer[ 0] == L'\\')
183             {
184
185                 pConnection->ComponentName.Buffer++;
186
187                 break;
188             }
189
190             pConnection->ComponentName.Length += sizeof( WCHAR);
191             pConnection->ComponentName.MaximumLength += sizeof( WCHAR);
192
193             pConnection->ComponentName.Buffer--;
194         }
195
196         //
197         // Go initialize the information about the connection
198         //
199
200         AFSInitializeConnectionInfo( pConnection,
201                                      DisplayType);
202
203         //
204         // Store away the flags for the connection
205         //
206
207         pConnection->Flags = Flags;
208
209         //
210         // Insert the entry into our list. If this is a server
211         // connection then add it to the enumeration list, otherwise
212         // find the server name for this connection
213         //
214
215         if( DisplayType == RESOURCEDISPLAYTYPE_SERVER)
216         {
217
218             if( pRDRDevExt->Specific.RDR.ProviderEnumerationList == NULL)
219             {
220
221                 pRDRDevExt->Specific.RDR.ProviderEnumerationList = pConnection;
222             }
223             else
224             {
225
226                 //
227                 // Get the end of the list
228                 //
229
230                 pLastConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList;
231
232                 while( pLastConnection->fLink != NULL)
233                 {
234
235                     pLastConnection = pLastConnection->fLink;
236                 }
237
238                 pLastConnection->fLink = pConnection;
239             }
240         }
241         else if( pServerConnection != NULL)
242         {
243
244             if( pServerConnection->EnumerationList == NULL)
245             {
246
247                 pServerConnection->EnumerationList = pConnection;
248             }
249             else
250             {
251
252                 //
253                 // Get the end of the list
254                 //
255
256                 pLastConnection = pServerConnection->EnumerationList;
257
258                 while( pLastConnection->fLink != NULL)
259                 {
260
261                     pLastConnection = pLastConnection->fLink;
262                 }
263
264                 pLastConnection->fLink = pConnection;
265             }
266         }
267
268 try_exit:
269
270         AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock);
271     }
272
273     return ntStatus;
274 }
275
276 void
277 AFSInitializeConnectionInfo( IN AFSProviderConnectionCB *Connection,
278                              IN ULONG DisplayType)
279 {
280
281     NTSTATUS ntStatus = STATUS_SUCCESS;
282     UNICODE_STRING uniName, uniComponentName, uniRemainingName;
283
284     __Enter
285     {
286
287         uniName = Connection->RemoteName;
288
289         //
290         // Strip of the double leading slash if there is one
291         //
292
293         if( uniName.Buffer[ 0] == L'\\' &&
294             uniName.Buffer[ 1] == L'\\')
295         {
296
297             uniName.Buffer = &uniName.Buffer[ 1];
298
299             uniName.Length -= sizeof( WCHAR);
300         }
301
302
303         FsRtlDissectName( uniName,
304                           &uniComponentName,
305                           &uniRemainingName);
306
307         //
308         // Initialize the information for the connection
309         // First, if this is the server only then mark it accordingly
310         //
311
312         if( uniRemainingName.Length == 0 ||
313             DisplayType == RESOURCEDISPLAYTYPE_SERVER)
314         {
315
316             Connection->Type = RESOURCETYPE_DISK;
317
318             Connection->Scope = RESOURCE_GLOBALNET;
319
320             Connection->DisplayType = RESOURCEDISPLAYTYPE_SERVER;
321
322             Connection->Usage = RESOURCEUSAGE_CONTAINER;
323
324             Connection->Comment.Length = 20;
325             Connection->Comment.MaximumLength = 22;
326
327             Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
328                                                                             Connection->Comment.MaximumLength,
329                                                                             AFS_NETWORK_PROVIDER_7_TAG);
330
331             if( Connection->Comment.Buffer != NULL)
332             {
333
334                 RtlZeroMemory( Connection->Comment.Buffer,
335                                Connection->Comment.MaximumLength);
336
337                 RtlCopyMemory( Connection->Comment.Buffer,
338                                L"AFS Root",
339                                16);
340             }
341             else
342             {
343
344                 Connection->Comment.Length = 0;
345                 Connection->Comment.MaximumLength = 0;
346             }
347
348             try_return( ntStatus);
349         }
350
351         uniName = uniRemainingName;
352
353         FsRtlDissectName( uniName,
354                           &uniComponentName,
355                           &uniRemainingName);
356
357         if( uniRemainingName.Length == 0 ||
358             uniRemainingName.Buffer == NULL ||
359             DisplayType == RESOURCEDISPLAYTYPE_SHARE)
360         {
361
362             Connection->Type = RESOURCETYPE_DISK;
363
364             Connection->DisplayType = RESOURCEDISPLAYTYPE_SHARE;
365
366             Connection->Usage = RESOURCEUSAGE_CONNECTABLE;
367
368             if( Connection->LocalName != L'\0')
369             {
370
371                 Connection->Usage |= RESOURCEUSAGE_ATTACHED;
372
373                 Connection->Scope = RESOURCE_CONNECTED;
374             }
375             else
376             {
377
378                 Connection->Scope = RESOURCE_GLOBALNET;
379             }
380
381             Connection->Comment.Length = 18;
382             Connection->Comment.MaximumLength = 20;
383
384             Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
385                                                                             Connection->Comment.MaximumLength,
386                                                                             AFS_NETWORK_PROVIDER_8_TAG);
387
388             if( Connection->Comment.Buffer != NULL)
389             {
390
391                 RtlZeroMemory( Connection->Comment.Buffer,
392                                Connection->Comment.MaximumLength);
393
394                 RtlCopyMemory( Connection->Comment.Buffer,
395                                L"AFS Share",
396                                18);
397             }
398             else
399             {
400
401                 Connection->Comment.Length = 0;
402                 Connection->Comment.MaximumLength = 0;
403             }
404
405             try_return( ntStatus);
406         }
407
408         //
409         // This is a sub directory within a share
410         //
411
412         Connection->Type = RESOURCETYPE_DISK;
413
414         Connection->DisplayType = RESOURCEDISPLAYTYPE_DIRECTORY;
415
416         Connection->Usage = RESOURCEUSAGE_CONNECTABLE;
417
418         if( Connection->LocalName != L'\0')
419         {
420
421             Connection->Usage |= RESOURCEUSAGE_ATTACHED;
422         }
423
424         Connection->Scope = RESOURCE_CONNECTED;
425
426         Connection->Comment.Length = 26;
427         Connection->Comment.MaximumLength = 28;
428
429         Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
430                                                                         Connection->Comment.MaximumLength,
431                                                                         AFS_NETWORK_PROVIDER_9_TAG);
432
433         if( Connection->Comment.Buffer != NULL)
434         {
435
436             RtlZeroMemory( Connection->Comment.Buffer,
437                            Connection->Comment.MaximumLength);
438
439             RtlCopyMemory( Connection->Comment.Buffer,
440                            L"AFS Directory",
441                            26);
442         }
443         else
444         {
445
446             Connection->Comment.Length = 0;
447             Connection->Comment.MaximumLength = 0;
448         }
449
450 try_exit:
451
452         NOTHING;
453     }
454
455     return;
456 }