Windows: RDR SymbolicLink create support
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSFSControl.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011, 2012, 2013 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, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16  *   nor the names of their contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission from Kernel Drivers, LLC and Your File System, Inc.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 //
34 // File: AFSFSControl.cpp
35 //
36
37 #include "AFSCommon.h"
38
39 NTSTATUS
40 AFSFSControl( IN PDEVICE_OBJECT LibDeviceObject,
41               IN PIRP Irp)
42 {
43
44     UNREFERENCED_PARAMETER(LibDeviceObject);
45     NTSTATUS ntStatus = STATUS_SUCCESS;
46     IO_STACK_LOCATION *pIrpSp;
47
48     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
49
50     __try
51     {
52
53         switch( pIrpSp->MinorFunction)
54         {
55
56             case IRP_MN_USER_FS_REQUEST:
57
58                 ntStatus = AFSProcessUserFsRequest( Irp);
59
60                 break;
61
62             case IRP_MN_MOUNT_VOLUME:
63
64                 break;
65
66             case IRP_MN_VERIFY_VOLUME:
67
68                 break;
69
70             default:
71
72                 break;
73         }
74
75         AFSCompleteRequest( Irp,
76                               ntStatus);
77
78     }
79     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
80     {
81
82         AFSDbgLogMsg( 0,
83                       0,
84                       "EXCEPTION - AFSFSControl\n");
85
86         AFSDumpTraceFilesFnc();
87     }
88
89     return ntStatus;
90 }
91
92 static BOOLEAN
93 AFSParseMountPointTarget( IN  UNICODE_STRING *Target,
94                           OUT USHORT         *Type,
95                           OUT UNICODE_STRING *Volume,
96                           OUT UNICODE_STRING *Cell)
97 {
98     // Targets are of the form <type>[<cell>:]<volume>
99
100     *Type = Target->Buffer[ 0];
101
102     // Extract the cell name (if any)
103
104     Cell->Buffer = &Target->Buffer[ 1];
105
106     // Search for colon separator or end of counted string
107
108     for ( Cell->Length = 0; Cell->Length < Target->Length - sizeof( WCHAR); Cell->Length += sizeof( WCHAR))
109     {
110
111         if ( Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':')
112         {
113             break;
114         }
115     }
116
117     // If a colon is not found, it means there is no cell
118
119     if ( Cell->Length < Target->Length - sizeof( WCHAR) &&
120          Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':')
121     {
122
123         Cell->MaximumLength = Cell->Length;
124
125         if ( Cell->Length > Target->Length - 2 * sizeof( WCHAR))
126         {
127             // Invalid target string if there is no room for
128             // the volume name.
129
130             return FALSE;
131         }
132
133         Volume->Length = Volume->MaximumLength = (Target->Length - Cell->Length - 2 * sizeof( WCHAR));
134
135         Volume->Buffer = &Target->Buffer[ Cell->Length / sizeof( WCHAR) + 2];
136     }
137     else
138     {
139         // There is no cell
140
141         Volume->Length = Volume->MaximumLength = Cell->Length;
142
143         Volume->Buffer = Cell->Buffer;
144
145         Cell->Length = Cell->MaximumLength = 0;
146
147         Cell->Buffer = NULL;
148     }
149
150     return TRUE;
151 }
152
153 NTSTATUS
154 AFSProcessUserFsRequest( IN PIRP Irp)
155 {
156
157     NTSTATUS ntStatus = STATUS_SUCCESS;
158     ULONG ulFsControlCode;
159     AFSFcb *pFcb = NULL;
160     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp );
161     AFSCcb *pCcb = NULL;
162     ULONG ulOutputBufferLen, ulInputBufferLen;
163
164     __Enter
165     {
166
167         ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
168
169         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
170
171         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
172
173         if( pFcb == NULL ||
174             pCcb == NULL ||
175             pCcb->DirectoryCB == NULL)
176         {
177
178             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
179                           AFS_TRACE_LEVEL_VERBOSE_2,
180                           "AFSProcessUserFsRequest Invalid Fcb\n");
181
182             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
183         }
184
185         if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
186         {
187
188             ntStatus = AFSProcessShareFsCtrl( Irp,
189                                               pFcb,
190                                               pCcb);
191
192             try_return( ntStatus);
193         }
194
195         ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
196         ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
197
198         //
199         // Process the request
200         //
201
202         switch( ulFsControlCode )
203         {
204
205             case FSCTL_REQUEST_OPLOCK_LEVEL_1:
206             case FSCTL_REQUEST_OPLOCK_LEVEL_2:
207             case FSCTL_REQUEST_BATCH_OPLOCK:
208             case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
209             case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
210             case FSCTL_OPLOCK_BREAK_NOTIFY:
211             case FSCTL_OPLOCK_BREAK_ACK_NO_2:
212             case FSCTL_REQUEST_FILTER_OPLOCK :
213             {
214                 //
215                 // Note that implementing this call will probably need us
216                 // to call the server as well as adding code in read and
217                 // write and caching.  Also that it is unlikely that
218                 // anyone will ever call us at this point - RDR doesn't
219                 // allow it
220                 //
221
222                 ntStatus = STATUS_NOT_IMPLEMENTED;
223
224                 break;
225             }
226
227             case FSCTL_LOCK_VOLUME:
228             {
229                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
230                               AFS_TRACE_LEVEL_VERBOSE_2,
231                               "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n");
232
233                 ntStatus = STATUS_NOT_IMPLEMENTED;
234
235                 break;
236             }
237
238             case FSCTL_UNLOCK_VOLUME:
239             {
240                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
241                               AFS_TRACE_LEVEL_VERBOSE_2,
242                               "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n");
243
244                 ntStatus = STATUS_NOT_IMPLEMENTED;
245
246                 break;
247             }
248
249             case FSCTL_DISMOUNT_VOLUME:
250             {
251                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
252                               AFS_TRACE_LEVEL_VERBOSE_2,
253                               "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n");
254
255                 ntStatus = STATUS_NOT_IMPLEMENTED;
256
257                 break;
258             }
259
260             case FSCTL_MARK_VOLUME_DIRTY:
261             {
262                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
263                               AFS_TRACE_LEVEL_VERBOSE_2,
264                               "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n");
265
266                 ntStatus = STATUS_NOT_IMPLEMENTED;
267
268                 break;
269             }
270
271             case FSCTL_IS_VOLUME_DIRTY:
272             {
273                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
274                               AFS_TRACE_LEVEL_VERBOSE_2,
275                               "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n");
276
277                 ntStatus = STATUS_NOT_IMPLEMENTED;
278
279                 break;
280             }
281
282             case FSCTL_IS_VOLUME_MOUNTED:
283             {
284                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
285                               AFS_TRACE_LEVEL_VERBOSE_2,
286                               "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n");
287
288                 ntStatus = STATUS_NOT_IMPLEMENTED;
289
290                 break;
291             }
292
293             case FSCTL_IS_PATHNAME_VALID:
294             {
295                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
296                               AFS_TRACE_LEVEL_VERBOSE_2,
297                               "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n");
298
299                 ntStatus = STATUS_SUCCESS;
300
301                 break;
302             }
303
304 #ifndef FSCTL_CSC_INTERNAL
305 #define FSCTL_CSC_INTERNAL                  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS)
306 #endif
307             case FSCTL_CSC_INTERNAL:
308             {
309                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
310                               AFS_TRACE_LEVEL_VERBOSE_2,
311                               "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n");
312
313                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
314
315                 break;
316             }
317
318             case FSCTL_GET_REPARSE_POINT:
319             {
320
321                 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
322                 ULONG ulRemainingLen = ulOutputBufferLen;
323                 AFSReparseTagInfo *pReparseInfo = NULL;
324
325                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
326                               AFS_TRACE_LEVEL_VERBOSE_2,
327                               "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
328                               &pCcb->DirectoryCB->NameInformation.FileName,
329                               pCcb->DirectoryCB->ObjectInformation->FileType,
330                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
331
332                 //
333                 // Check if we have the reparse entry set on the entry
334                 //
335
336                 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
337                 {
338
339                     ntStatus = STATUS_NOT_A_REPARSE_POINT;
340
341                     break;
342                 }
343
344                 if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
345                 {
346
347                     ntStatus = STATUS_BUFFER_TOO_SMALL;
348
349                     Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
350
351                     break;
352                 }
353
354                 ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
355
356                 //
357                 // Populate the data in the reparse buffer
358                 //
359
360                 pReparseBuffer->ReparseDataLength  = 0;
361
362                 AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock,
363                                 TRUE);
364
365                 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
366                 {
367
368                     //
369                     // We'll reset the DV to ensure we validate the metadata content
370                     //
371
372                     pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
373
374                     SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
375
376                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
377                                   AFS_TRACE_LEVEL_VERBOSE,
378                                   "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
379                                   &pCcb->DirectoryCB->NameInformation.FileName,
380                                   pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
381                                   pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
382                                   pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
383                                   pCcb->DirectoryCB->ObjectInformation->FileId.Unique);
384
385                     ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
386                                                pCcb->DirectoryCB);
387
388                     if( !NT_SUCCESS( ntStatus))
389                     {
390
391                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
392                                       AFS_TRACE_LEVEL_ERROR,
393                                       "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
394                                       &pCcb->DirectoryCB->NameInformation.FileName,
395                                       pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
396                                       pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
397                                       pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
398                                       pCcb->DirectoryCB->ObjectInformation->FileId.Unique,
399                                       ntStatus);
400
401                         AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
402
403                         break;
404                     }
405                 }
406
407                 pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];
408
409                 switch( pCcb->DirectoryCB->ObjectInformation->FileType)
410                 {
411
412                     case AFS_FILE_TYPE_SYMLINK:
413                     {
414
415                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
416                         {
417
418                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
419
420                             break;
421                         }
422
423                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
424                         {
425
426                             ntStatus = STATUS_BUFFER_TOO_SMALL;
427
428                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
429                                                         FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
430                                                         pCcb->DirectoryCB->NameInformation.TargetName.Length;
431
432                             break;
433                         }
434
435                         pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK;
436
437                         pReparseInfo->AFSSymLink.RelativeLink = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
438
439                         pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
440
441                         RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer,
442                                        pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
443                                        pCcb->DirectoryCB->NameInformation.TargetName.Length);
444
445                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
446
447                         break;
448                     }
449
450                     case AFS_FILE_TYPE_MOUNTPOINT:
451                     {
452                         UNICODE_STRING Cell, Volume;
453                         USHORT Type;
454
455                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
456                         {
457                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
458
459                             break;
460                         }
461
462                         if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName,
463                                                         &Type,
464                                                         &Volume,
465                                                         &Cell))
466                         {
467                             ntStatus = STATUS_INVALID_PARAMETER;
468
469                             break;
470                         }
471
472                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length)
473                         {
474
475                             ntStatus = STATUS_BUFFER_TOO_SMALL;
476
477                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
478                                                         FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) +
479                                                         Volume.Length + Cell.Length;
480
481                             break;
482                         }
483
484                         pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT;
485
486                         pReparseInfo->AFSMountPoint.Type = Type;
487
488                         pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length;
489
490                         pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length;
491
492                         RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer,
493                                        Cell.Buffer,
494                                        Cell.Length);
495
496                         RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)],
497                                        Volume.Buffer,
498                                        Volume.Length);
499
500                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length);
501
502                         break;
503                     }
504
505                     case AFS_FILE_TYPE_DFSLINK:
506                     {
507
508                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
509                         {
510
511                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
512
513                             break;
514                         }
515
516                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
517                         {
518
519                             ntStatus = STATUS_BUFFER_TOO_SMALL;
520
521                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
522                                                         FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
523                                                         pCcb->DirectoryCB->NameInformation.TargetName.Length;
524
525                             break;
526                         }
527
528                         pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC;
529
530                         pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
531
532                         RtlCopyMemory( pReparseInfo->UNCReferral.Buffer,
533                                        pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
534                                        pCcb->DirectoryCB->NameInformation.TargetName.Length);
535
536                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
537
538                         break;
539                     }
540
541                     default:
542
543                         ntStatus = STATUS_NOT_A_REPARSE_POINT;
544
545                         break;
546                 }
547
548                 if ( ntStatus == STATUS_SUCCESS)
549                 {
550
551                     ulRemainingLen -= pReparseBuffer->ReparseDataLength;
552
553                     pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SURROGATE|IO_REPARSE_TAG_OPENAFS_DFS;
554
555                     RtlCopyMemory( &pReparseBuffer->ReparseGuid,
556                                    &GUID_AFS_REPARSE_GUID,
557                                    sizeof( GUID));
558
559                     Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
560                                                               pReparseBuffer->ReparseDataLength;
561                 }
562
563                 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
564
565                 break;
566             }
567
568             case FSCTL_SET_REPARSE_POINT:
569             {
570
571                 REPARSE_GUID_DATA_BUFFER *pReparseGUIDBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
572                 REPARSE_DATA_BUFFER *pReparseBuffer = NULL;
573                 AFSReparseTagInfo *pReparseInfo = NULL;
574                 AFSObjectInfoCB *pParentObjectInfo = NULL;
575                 UNICODE_STRING uniTargetName;
576                 ULONGLONG ullIndex = 0;
577                 LONG lCount;
578
579                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
580                               AFS_TRACE_LEVEL_VERBOSE,
581                               "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
582                               &pCcb->DirectoryCB->NameInformation.FileName,
583                               pCcb->DirectoryCB->ObjectInformation->FileType,
584                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
585
586                 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
587                 {
588
589                     ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
590
591                     break;
592                 }
593
594                 if( (pReparseGUIDBuffer->ReparseTag & 0x0000FFFF) == IO_REPARSE_TAG_OPENAFS_DFS)
595                 {
596
597                     if( RtlCompareMemory( &pReparseGUIDBuffer->ReparseGuid,
598                                           &GUID_AFS_REPARSE_GUID,
599                                           sizeof( GUID)) != sizeof( GUID))
600                     {
601
602                         ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
603
604                         break;
605                     }
606
607                     if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
608                                                                         sizeof( AFSReparseTagInfo))
609                     {
610
611                         ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
612
613                         break;
614                     }
615
616                     pReparseInfo = (AFSReparseTagInfo *)pReparseGUIDBuffer->GenericReparseBuffer.DataBuffer;
617
618                     switch( pReparseInfo->SubTag)
619                     {
620
621                         case OPENAFS_SUBTAG_SYMLINK:
622                         {
623
624                             if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
625                                                            FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
626                                                            pReparseInfo->AFSSymLink.SymLinkTargetLength))
627                             {
628
629                                 ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
630
631                                 break;
632                             }
633
634                             uniTargetName.Length = pReparseInfo->AFSSymLink.SymLinkTargetLength;
635                             uniTargetName.MaximumLength = uniTargetName.Length;
636
637                             uniTargetName.Buffer = (WCHAR *)pReparseInfo->AFSSymLink.Buffer;
638
639                             break;
640                         }
641
642                         case OPENAFS_SUBTAG_UNC:
643                         {
644
645                             if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
646                                                            FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
647                                                            pReparseInfo->UNCReferral.UNCTargetLength))
648                             {
649
650                                 ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
651
652                                 break;
653                             }
654
655                             uniTargetName.Length = pReparseInfo->UNCReferral.UNCTargetLength;
656                             uniTargetName.MaximumLength = uniTargetName.Length;
657
658                             uniTargetName.Buffer = (WCHAR *)pReparseInfo->UNCReferral.Buffer;
659
660                             break;
661                         }
662
663                         case OPENAFS_SUBTAG_MOUNTPOINT:
664                             //
665                             // Not yet handled
666                             //
667                         default:
668                         {
669
670                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
671
672                             break;
673                         }
674                     }
675                 }
676                 else
677                 {
678                     //
679                     // Handle Microsoft Reparse Tags
680                     //
681
682                     switch( pReparseGUIDBuffer->ReparseTag)
683                     {
684
685                         case IO_REPARSE_TAG_MOUNT_POINT:
686                         {
687
688                             pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
689
690                             uniTargetName.Length = pReparseBuffer->MountPointReparseBuffer.PrintNameLength;
691                             uniTargetName.MaximumLength = uniTargetName.Length;
692
693                             uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->MountPointReparseBuffer.PathBuffer +
694                                                               pReparseBuffer->MountPointReparseBuffer.PrintNameOffset);
695
696                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
697                                           AFS_TRACE_LEVEL_VERBOSE_2,
698                                           "AFSProcessUserFsRequest IO_REPARSE_TAG_MOUNT_POINT request %wZ\n",
699                                           &uniTargetName);
700
701                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
702
703                             break;
704                         }
705
706                         case IO_REPARSE_TAG_SYMLINK:
707                         {
708
709                             pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
710
711                             uniTargetName.Length = pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
712                             uniTargetName.MaximumLength = uniTargetName.Length;
713
714                             uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer +
715                                                               pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset);
716
717                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
718                                           AFS_TRACE_LEVEL_VERBOSE_2,
719                                           "AFSProcessUserFsRequest IO_REPARSE_TAG_SYMLINK request %wZ\n",
720                                           &uniTargetName);
721                             break;
722                         }
723
724                         default:
725                         {
726
727                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
728
729                             break;
730                         }
731                     }
732                 }
733
734                 if( !NT_SUCCESS( ntStatus))
735                 {
736
737                     break;
738                 }
739
740                 //
741                 // First thing is to locate/create our object information block
742                 // for this entry
743                 //
744
745                 AFSAcquireExcl( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock,
746                                 TRUE);
747
748                 ullIndex = AFSCreateLowIndex( &pCcb->DirectoryCB->ObjectInformation->ParentFileId);
749
750                 ntStatus = AFSLocateHashEntry( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead,
751                                                ullIndex,
752                                                (AFSBTreeEntry **)&pParentObjectInfo);
753
754                 if ( NT_SUCCESS( ntStatus) &&
755                      pParentObjectInfo)
756                 {
757
758                     lCount = AFSObjectInfoIncrement( pParentObjectInfo,
759                                                      AFS_OBJECT_REFERENCE_DIRENTRY);
760
761                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
762                                   AFS_TRACE_LEVEL_VERBOSE,
763                                   "AFSProcessUserFsRequest Increment count on object %p Cnt %d\n",
764                                   pParentObjectInfo,
765                                   lCount);
766                 }
767
768                 AFSReleaseResource( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock);
769
770                 //
771                 // Extract out the information to the call to the service
772                 //
773
774                 ntStatus = AFSCreateSymlink( &pCcb->AuthGroup,
775                                              pParentObjectInfo,
776                                              &pCcb->DirectoryCB->NameInformation.FileName,
777                                              pCcb->DirectoryCB->ObjectInformation,
778                                              &uniTargetName);
779
780                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
781                               AFS_TRACE_LEVEL_VERBOSE_2,
782                               "AFSProcessUserFsRequest Processed FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x Status %08lX\n",
783                               &pCcb->DirectoryCB->NameInformation.FileName,
784                               pCcb->DirectoryCB->ObjectInformation->FileType,
785                               pCcb->DirectoryCB->ObjectInformation->FileAttributes,
786                               ntStatus);
787
788                 lCount = AFSObjectInfoDecrement( pParentObjectInfo,
789                                                  AFS_OBJECT_REFERENCE_DIRENTRY);
790
791                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
792                               AFS_TRACE_LEVEL_VERBOSE,
793                               "AFSProcessUserFsRequest Decrement count on object %p Cnt %d\n",
794                               pParentObjectInfo,
795                               lCount);
796
797                 break;
798             }
799
800             case FSCTL_DELETE_REPARSE_POINT:
801             {
802
803                 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
804
805                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
806                               AFS_TRACE_LEVEL_VERBOSE_2,
807                               "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
808                               &pCcb->DirectoryCB->NameInformation.FileName,
809                               pCcb->DirectoryCB->ObjectInformation->FileType,
810                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
811
812                 //
813                 // Check if we have the reparse entry set on the entry
814                 //
815
816                 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
817                 {
818
819                     ntStatus = STATUS_NOT_A_REPARSE_POINT;
820
821                     break;
822                 }
823
824                 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
825                 {
826
827                     ntStatus = STATUS_INVALID_PARAMETER;
828
829                     break;
830                 }
831
832                 if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != IO_REPARSE_TAG_OPENAFS_DFS)
833                 {
834
835                     ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
836
837                     break;
838                 }
839
840                 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
841                                       &GUID_AFS_REPARSE_GUID,
842                                       sizeof( GUID)) != sizeof( GUID))
843                 {
844
845                     ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
846
847                     break;
848                 }
849
850                 //
851                 // For now deny access on this call
852                 //
853
854                 ntStatus = STATUS_ACCESS_DENIED;
855
856                 break;
857             }
858
859 #ifndef FSCTL_SET_PURGE_FAILURE_MODE
860 #define FSCTL_SET_PURGE_FAILURE_MODE        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 156, METHOD_BUFFERED, FILE_ANY_ACCESS)
861 #endif
862
863             case FSCTL_SET_PURGE_FAILURE_MODE:
864             {
865
866                 //
867                 // For the time being just succeed this call
868                 //
869
870                 ntStatus = STATUS_SUCCESS;
871
872                 break;
873             }
874
875             default :
876             {
877
878                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
879                               AFS_TRACE_LEVEL_VERBOSE_2,
880                               "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode);
881
882                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
883
884                 break;
885             }
886         }
887
888 try_exit:
889
890         NOTHING;
891     }
892
893     return ntStatus;
894 }
895
896 NTSTATUS
897 AFSProcessShareFsCtrl( IN IRP *Irp,
898                        IN AFSFcb *Fcb,
899                        IN AFSCcb *Ccb)
900 {
901
902     UNREFERENCED_PARAMETER(Fcb);
903     NTSTATUS ntStatus = STATUS_SUCCESS;
904     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
905     ULONG ulOutputBufferLen = 0, ulInputBufferLen;
906     ULONG ulFsControlCode;
907
908     __Enter
909     {
910
911         ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
912
913         ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
914         ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
915
916         switch( ulFsControlCode)
917         {
918
919             case FSCTL_PIPE_TRANSCEIVE:
920             {
921
922                 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
923                               AFS_TRACE_LEVEL_VERBOSE,
924                               "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n",
925                               &Ccb->DirectoryCB->NameInformation.FileName);
926
927                 ntStatus = AFSNotifyPipeTransceive( Ccb,
928                                                     ulInputBufferLen,
929                                                     ulOutputBufferLen,
930                                                     pIrpSp->Parameters.FileSystemControl.Type3InputBuffer,
931                                                     Irp->UserBuffer,
932                                                     (ULONG *)&Irp->IoStatus.Information);
933
934                 if( !NT_SUCCESS( ntStatus))
935                 {
936
937                     AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
938                                   AFS_TRACE_LEVEL_VERBOSE,
939                                   "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n",
940                                   &Ccb->DirectoryCB->NameInformation.FileName,
941                                   ntStatus);
942                 }
943
944                 break;
945             }
946
947             default:
948             {
949
950                 AFSPrint( "AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n",
951                           ulFsControlCode,
952                           ulInputBufferLen,
953                           ulOutputBufferLen);
954
955                 break;
956             }
957         }
958     }
959
960     return ntStatus;
961 }