ec0acf541827c48579cbebcb5b90a6438dae2d40
[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     BOOLEAN bRelative = FALSE;
164
165     __Enter
166     {
167
168         ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
169
170         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
171
172         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
173
174         if( pFcb == NULL ||
175             pCcb == NULL ||
176             pCcb->DirectoryCB == NULL)
177         {
178
179             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
180                           AFS_TRACE_LEVEL_VERBOSE_2,
181                           "AFSProcessUserFsRequest Invalid Fcb\n");
182
183             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
184         }
185
186         if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
187         {
188
189             ntStatus = AFSProcessShareFsCtrl( Irp,
190                                               pFcb,
191                                               pCcb);
192
193             try_return( ntStatus);
194         }
195
196         ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
197         ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
198
199         //
200         // Process the request
201         //
202
203         switch( ulFsControlCode )
204         {
205
206             case FSCTL_REQUEST_OPLOCK_LEVEL_1:
207             case FSCTL_REQUEST_OPLOCK_LEVEL_2:
208             case FSCTL_REQUEST_BATCH_OPLOCK:
209             case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
210             case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
211             case FSCTL_OPLOCK_BREAK_NOTIFY:
212             case FSCTL_OPLOCK_BREAK_ACK_NO_2:
213             case FSCTL_REQUEST_FILTER_OPLOCK :
214             {
215                 //
216                 // Note that implementing this call will probably need us
217                 // to call the server as well as adding code in read and
218                 // write and caching.  Also that it is unlikely that
219                 // anyone will ever call us at this point - RDR doesn't
220                 // allow it
221                 //
222
223                 ntStatus = STATUS_NOT_IMPLEMENTED;
224
225                 break;
226             }
227
228             case FSCTL_LOCK_VOLUME:
229             {
230                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
231                               AFS_TRACE_LEVEL_VERBOSE_2,
232                               "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n");
233
234                 ntStatus = STATUS_NOT_IMPLEMENTED;
235
236                 break;
237             }
238
239             case FSCTL_UNLOCK_VOLUME:
240             {
241                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
242                               AFS_TRACE_LEVEL_VERBOSE_2,
243                               "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n");
244
245                 ntStatus = STATUS_NOT_IMPLEMENTED;
246
247                 break;
248             }
249
250             case FSCTL_DISMOUNT_VOLUME:
251             {
252                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
253                               AFS_TRACE_LEVEL_VERBOSE_2,
254                               "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n");
255
256                 ntStatus = STATUS_NOT_IMPLEMENTED;
257
258                 break;
259             }
260
261             case FSCTL_MARK_VOLUME_DIRTY:
262             {
263                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
264                               AFS_TRACE_LEVEL_VERBOSE_2,
265                               "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n");
266
267                 ntStatus = STATUS_NOT_IMPLEMENTED;
268
269                 break;
270             }
271
272             case FSCTL_IS_VOLUME_DIRTY:
273             {
274                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
275                               AFS_TRACE_LEVEL_VERBOSE_2,
276                               "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n");
277
278                 ntStatus = STATUS_NOT_IMPLEMENTED;
279
280                 break;
281             }
282
283             case FSCTL_IS_VOLUME_MOUNTED:
284             {
285                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
286                               AFS_TRACE_LEVEL_VERBOSE_2,
287                               "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n");
288
289                 ntStatus = STATUS_NOT_IMPLEMENTED;
290
291                 break;
292             }
293
294             case FSCTL_IS_PATHNAME_VALID:
295             {
296                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
297                               AFS_TRACE_LEVEL_VERBOSE_2,
298                               "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n");
299
300                 ntStatus = STATUS_SUCCESS;
301
302                 break;
303             }
304
305 #ifndef FSCTL_CSC_INTERNAL
306 #define FSCTL_CSC_INTERNAL                  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS)
307 #endif
308             case FSCTL_CSC_INTERNAL:
309             {
310                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
311                               AFS_TRACE_LEVEL_VERBOSE_2,
312                               "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n");
313
314                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
315
316                 break;
317             }
318
319             case FSCTL_GET_REPARSE_POINT:
320             {
321
322                 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
323                 ULONG ulRemainingLen = ulOutputBufferLen;
324                 AFSReparseTagInfo *pReparseInfo = NULL;
325
326                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
327                               AFS_TRACE_LEVEL_VERBOSE_2,
328                               "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
329                               &pCcb->DirectoryCB->NameInformation.FileName,
330                               pCcb->DirectoryCB->ObjectInformation->FileType,
331                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
332
333                 //
334                 // Check if we have the reparse entry set on the entry
335                 //
336
337                 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
338                 {
339
340                     ntStatus = STATUS_NOT_A_REPARSE_POINT;
341
342                     break;
343                 }
344
345                 if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
346                 {
347
348                     ntStatus = STATUS_BUFFER_TOO_SMALL;
349
350                     Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
351
352                     break;
353                 }
354
355                 ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
356
357                 //
358                 // Populate the data in the reparse buffer
359                 //
360
361                 pReparseBuffer->ReparseDataLength  = 0;
362
363                 AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock,
364                                 TRUE);
365
366                 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
367                 {
368
369                     //
370                     // We'll reset the DV to ensure we validate the metadata content
371                     //
372
373                     pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
374
375                     SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
376
377                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
378                                   AFS_TRACE_LEVEL_VERBOSE,
379                                   "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
380                                   &pCcb->DirectoryCB->NameInformation.FileName,
381                                   pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
382                                   pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
383                                   pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
384                                   pCcb->DirectoryCB->ObjectInformation->FileId.Unique);
385
386                     ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
387                                                pCcb->DirectoryCB);
388
389                     if( !NT_SUCCESS( ntStatus))
390                     {
391
392                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
393                                       AFS_TRACE_LEVEL_ERROR,
394                                       "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
395                                       &pCcb->DirectoryCB->NameInformation.FileName,
396                                       pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
397                                       pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
398                                       pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
399                                       pCcb->DirectoryCB->ObjectInformation->FileId.Unique,
400                                       ntStatus);
401
402                         AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
403
404                         break;
405                     }
406                 }
407
408                 pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];
409
410                 switch( pCcb->DirectoryCB->ObjectInformation->FileType)
411                 {
412
413                     case AFS_FILE_TYPE_SYMLINK:
414                     {
415
416                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
417                         {
418
419                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
420
421                             break;
422                         }
423
424                         bRelative = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
425
426                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
427                             pCcb->DirectoryCB->NameInformation.TargetName.Length + (bRelative ? 0 : sizeof( WCHAR)))
428                         {
429
430                             ntStatus = STATUS_BUFFER_TOO_SMALL;
431
432                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
433                                                         FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
434                                                         pCcb->DirectoryCB->NameInformation.TargetName.Length +
435                                                         (bRelative ? 0 : sizeof( WCHAR));
436
437                             break;
438                         }
439
440                         pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK;
441
442                         pReparseInfo->AFSSymLink.RelativeLink = bRelative;
443
444                         pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
445
446                         if ( pReparseInfo->AFSSymLink.RelativeLink == FALSE)
447                         {
448
449                             pReparseInfo->AFSSymLink.Buffer[0] = L'\\';
450
451                             RtlCopyMemory( &pReparseInfo->AFSSymLink.Buffer[ 1],
452                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
453                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
454
455                             pReparseInfo->AFSSymLink.SymLinkTargetLength += sizeof( WCHAR);
456                         }
457                         else
458                         {
459
460                             RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer,
461                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
462                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
463                         }
464
465                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer)
466                                                               + pReparseInfo->AFSSymLink.SymLinkTargetLength);
467
468                         break;
469                     }
470
471                     case AFS_FILE_TYPE_MOUNTPOINT:
472                     {
473                         UNICODE_STRING Cell, Volume;
474                         USHORT Type;
475
476                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
477                         {
478                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
479
480                             break;
481                         }
482
483                         if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName,
484                                                         &Type,
485                                                         &Volume,
486                                                         &Cell))
487                         {
488                             ntStatus = STATUS_INVALID_PARAMETER;
489
490                             break;
491                         }
492
493                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length)
494                         {
495
496                             ntStatus = STATUS_BUFFER_TOO_SMALL;
497
498                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
499                                                         FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) +
500                                                         Volume.Length + Cell.Length;
501
502                             break;
503                         }
504
505                         pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT;
506
507                         pReparseInfo->AFSMountPoint.Type = Type;
508
509                         pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length;
510
511                         pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length;
512
513                         RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer,
514                                        Cell.Buffer,
515                                        Cell.Length);
516
517                         RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)],
518                                        Volume.Buffer,
519                                        Volume.Length);
520
521                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length);
522
523                         break;
524                     }
525
526                     case AFS_FILE_TYPE_DFSLINK:
527                     {
528
529                         if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
530                         {
531
532                             ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
533
534                             break;
535                         }
536
537                         if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
538                             pCcb->DirectoryCB->NameInformation.TargetName.Length +
539                             (pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\' ? sizeof( WCHAR) : 0))
540                         {
541
542                             ntStatus = STATUS_BUFFER_TOO_SMALL;
543
544                             Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
545                                                         FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
546                                                         pCcb->DirectoryCB->NameInformation.TargetName.Length +
547                                                         (pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\' ? sizeof( WCHAR) : 0);
548
549                             break;
550                         }
551
552                         pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC;
553
554                         pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
555
556                         if ( pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\')
557                         {
558
559                             pReparseInfo->UNCReferral.Buffer[0] = L'\\';
560
561                             RtlCopyMemory( &pReparseInfo->UNCReferral.Buffer[ 1],
562                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
563                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
564
565                             pReparseInfo->UNCReferral.UNCTargetLength += sizeof( WCHAR);
566                         }
567                         else
568                         {
569
570                             RtlCopyMemory( pReparseInfo->UNCReferral.Buffer,
571                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
572                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
573                         }
574
575                         pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer)
576                                                               + pReparseInfo->UNCReferral.UNCTargetLength);
577
578                         break;
579                     }
580
581                     default:
582
583                         ntStatus = STATUS_NOT_A_REPARSE_POINT;
584
585                         break;
586                 }
587
588                 if ( ntStatus == STATUS_SUCCESS)
589                 {
590
591                     ulRemainingLen -= pReparseBuffer->ReparseDataLength;
592
593                     pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SURROGATE|IO_REPARSE_TAG_OPENAFS_DFS;
594
595                     RtlCopyMemory( &pReparseBuffer->ReparseGuid,
596                                    &GUID_AFS_REPARSE_GUID,
597                                    sizeof( GUID));
598
599                     Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
600                                                               pReparseBuffer->ReparseDataLength;
601                 }
602
603                 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
604
605                 break;
606             }
607
608             case FSCTL_SET_REPARSE_POINT:
609             {
610
611                 REPARSE_GUID_DATA_BUFFER *pReparseGUIDBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
612                 REPARSE_DATA_BUFFER *pReparseBuffer = NULL;
613                 AFSReparseTagInfo *pReparseInfo = NULL;
614                 AFSObjectInfoCB *pParentObjectInfo = NULL;
615                 UNICODE_STRING uniTargetName;
616                 ULONGLONG ullIndex = 0;
617                 LONG lCount;
618
619                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
620                               AFS_TRACE_LEVEL_VERBOSE,
621                               "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
622                               &pCcb->DirectoryCB->NameInformation.FileName,
623                               pCcb->DirectoryCB->ObjectInformation->FileType,
624                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
625
626                 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
627                 {
628
629                     ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
630
631                     break;
632                 }
633
634                 if( (pReparseGUIDBuffer->ReparseTag & 0x0000FFFF) == IO_REPARSE_TAG_OPENAFS_DFS)
635                 {
636
637                     if( RtlCompareMemory( &pReparseGUIDBuffer->ReparseGuid,
638                                           &GUID_AFS_REPARSE_GUID,
639                                           sizeof( GUID)) != sizeof( GUID))
640                     {
641
642                         ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
643
644                         break;
645                     }
646
647                     if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
648                                                                         sizeof( AFSReparseTagInfo))
649                     {
650
651                         ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
652
653                         break;
654                     }
655
656                     pReparseInfo = (AFSReparseTagInfo *)pReparseGUIDBuffer->GenericReparseBuffer.DataBuffer;
657
658                     switch( pReparseInfo->SubTag)
659                     {
660
661                         case OPENAFS_SUBTAG_SYMLINK:
662                         {
663
664                             if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
665                                                            FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
666                                                            pReparseInfo->AFSSymLink.SymLinkTargetLength))
667                             {
668
669                                 ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
670
671                                 break;
672                             }
673
674                             uniTargetName.Length = pReparseInfo->AFSSymLink.SymLinkTargetLength;
675                             uniTargetName.MaximumLength = uniTargetName.Length;
676
677                             uniTargetName.Buffer = (WCHAR *)pReparseInfo->AFSSymLink.Buffer;
678
679                             break;
680                         }
681
682                         case OPENAFS_SUBTAG_UNC:
683                         {
684
685                             if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
686                                                            FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
687                                                            pReparseInfo->UNCReferral.UNCTargetLength))
688                             {
689
690                                 ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
691
692                                 break;
693                             }
694
695                             uniTargetName.Length = pReparseInfo->UNCReferral.UNCTargetLength;
696                             uniTargetName.MaximumLength = uniTargetName.Length;
697
698                             uniTargetName.Buffer = (WCHAR *)pReparseInfo->UNCReferral.Buffer;
699
700                             break;
701                         }
702
703                         case OPENAFS_SUBTAG_MOUNTPOINT:
704                             //
705                             // Not yet handled
706                             //
707                         default:
708                         {
709
710                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
711
712                             break;
713                         }
714                     }
715                 }
716                 else
717                 {
718                     //
719                     // Handle Microsoft Reparse Tags
720                     //
721
722                     switch( pReparseGUIDBuffer->ReparseTag)
723                     {
724
725                         case IO_REPARSE_TAG_MOUNT_POINT:
726                         {
727
728                             pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
729
730                             uniTargetName.Length = pReparseBuffer->MountPointReparseBuffer.PrintNameLength;
731                             uniTargetName.MaximumLength = uniTargetName.Length;
732
733                             uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->MountPointReparseBuffer.PathBuffer +
734                                                               pReparseBuffer->MountPointReparseBuffer.PrintNameOffset);
735
736                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
737                                           AFS_TRACE_LEVEL_VERBOSE_2,
738                                           "AFSProcessUserFsRequest IO_REPARSE_TAG_MOUNT_POINT request %wZ\n",
739                                           &uniTargetName);
740
741                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
742
743                             break;
744                         }
745
746                         case IO_REPARSE_TAG_SYMLINK:
747                         {
748
749                             pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
750
751                             uniTargetName.Length = pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
752                             uniTargetName.MaximumLength = uniTargetName.Length;
753
754                             uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer +
755                                                               pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset);
756
757                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
758                                           AFS_TRACE_LEVEL_VERBOSE_2,
759                                           "AFSProcessUserFsRequest IO_REPARSE_TAG_SYMLINK request %wZ\n",
760                                           &uniTargetName);
761                             break;
762                         }
763
764                         default:
765                         {
766
767                             ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
768
769                             break;
770                         }
771                     }
772                 }
773
774                 if( !NT_SUCCESS( ntStatus))
775                 {
776
777                     break;
778                 }
779
780                 //
781                 // First thing is to locate/create our object information block
782                 // for this entry
783                 //
784
785                 AFSAcquireExcl( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock,
786                                 TRUE);
787
788                 ullIndex = AFSCreateLowIndex( &pCcb->DirectoryCB->ObjectInformation->ParentFileId);
789
790                 ntStatus = AFSLocateHashEntry( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead,
791                                                ullIndex,
792                                                (AFSBTreeEntry **)&pParentObjectInfo);
793
794                 if ( NT_SUCCESS( ntStatus) &&
795                      pParentObjectInfo)
796                 {
797
798                     lCount = AFSObjectInfoIncrement( pParentObjectInfo,
799                                                      AFS_OBJECT_REFERENCE_DIRENTRY);
800
801                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
802                                   AFS_TRACE_LEVEL_VERBOSE,
803                                   "AFSProcessUserFsRequest Increment count on object %p Cnt %d\n",
804                                   pParentObjectInfo,
805                                   lCount);
806                 }
807
808                 AFSReleaseResource( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock);
809
810                 //
811                 // Extract out the information to the call to the service
812                 //
813
814                 ntStatus = AFSCreateSymlink( &pCcb->AuthGroup,
815                                              pParentObjectInfo,
816                                              &pCcb->DirectoryCB->NameInformation.FileName,
817                                              pCcb->DirectoryCB->ObjectInformation,
818                                              &uniTargetName);
819
820                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
821                               AFS_TRACE_LEVEL_VERBOSE_2,
822                               "AFSProcessUserFsRequest Processed FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x Status %08lX\n",
823                               &pCcb->DirectoryCB->NameInformation.FileName,
824                               pCcb->DirectoryCB->ObjectInformation->FileType,
825                               pCcb->DirectoryCB->ObjectInformation->FileAttributes,
826                               ntStatus);
827
828                 lCount = AFSObjectInfoDecrement( pParentObjectInfo,
829                                                  AFS_OBJECT_REFERENCE_DIRENTRY);
830
831                 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
832                               AFS_TRACE_LEVEL_VERBOSE,
833                               "AFSProcessUserFsRequest Decrement count on object %p Cnt %d\n",
834                               pParentObjectInfo,
835                               lCount);
836
837                 break;
838             }
839
840             case FSCTL_DELETE_REPARSE_POINT:
841             {
842
843                 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
844
845                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
846                               AFS_TRACE_LEVEL_VERBOSE_2,
847                               "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
848                               &pCcb->DirectoryCB->NameInformation.FileName,
849                               pCcb->DirectoryCB->ObjectInformation->FileType,
850                               pCcb->DirectoryCB->ObjectInformation->FileAttributes);
851
852                 //
853                 // Check if we have the reparse entry set on the entry
854                 //
855
856                 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
857                 {
858
859                     ntStatus = STATUS_NOT_A_REPARSE_POINT;
860
861                     break;
862                 }
863
864                 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
865                 {
866
867                     ntStatus = STATUS_INVALID_PARAMETER;
868
869                     break;
870                 }
871
872                 if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != IO_REPARSE_TAG_OPENAFS_DFS)
873                 {
874
875                     ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
876
877                     break;
878                 }
879
880                 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
881                                       &GUID_AFS_REPARSE_GUID,
882                                       sizeof( GUID)) != sizeof( GUID))
883                 {
884
885                     ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
886
887                     break;
888                 }
889
890                 //
891                 // Claim success.  The typical usage is setting delete on close
892                 // as the next operation on the reparse point before closing
893                 // the handle.
894                 //
895
896                 ntStatus = STATUS_SUCCESS;
897
898                 break;
899             }
900
901 #ifndef FSCTL_SET_PURGE_FAILURE_MODE
902 #define FSCTL_SET_PURGE_FAILURE_MODE        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 156, METHOD_BUFFERED, FILE_ANY_ACCESS)
903 #endif
904
905             case FSCTL_SET_PURGE_FAILURE_MODE:
906             {
907
908                 //
909                 // For the time being just succeed this call
910                 //
911
912                 ntStatus = STATUS_SUCCESS;
913
914                 break;
915             }
916
917             default :
918             {
919
920                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
921                               AFS_TRACE_LEVEL_VERBOSE_2,
922                               "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode);
923
924                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
925
926                 break;
927             }
928         }
929
930 try_exit:
931
932         NOTHING;
933     }
934
935     return ntStatus;
936 }
937
938 NTSTATUS
939 AFSProcessShareFsCtrl( IN IRP *Irp,
940                        IN AFSFcb *Fcb,
941                        IN AFSCcb *Ccb)
942 {
943
944     UNREFERENCED_PARAMETER(Fcb);
945     NTSTATUS ntStatus = STATUS_SUCCESS;
946     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
947     ULONG ulOutputBufferLen = 0, ulInputBufferLen;
948     ULONG ulFsControlCode;
949
950     __Enter
951     {
952
953         ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
954
955         ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
956         ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
957
958         switch( ulFsControlCode)
959         {
960
961             case FSCTL_PIPE_TRANSCEIVE:
962             {
963
964                 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
965                               AFS_TRACE_LEVEL_VERBOSE,
966                               "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n",
967                               &Ccb->DirectoryCB->NameInformation.FileName);
968
969                 ntStatus = AFSNotifyPipeTransceive( Ccb,
970                                                     ulInputBufferLen,
971                                                     ulOutputBufferLen,
972                                                     pIrpSp->Parameters.FileSystemControl.Type3InputBuffer,
973                                                     Irp->UserBuffer,
974                                                     (ULONG *)&Irp->IoStatus.Information);
975
976                 if( !NT_SUCCESS( ntStatus))
977                 {
978
979                     AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
980                                   AFS_TRACE_LEVEL_VERBOSE,
981                                   "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n",
982                                   &Ccb->DirectoryCB->NameInformation.FileName,
983                                   ntStatus);
984                 }
985
986                 break;
987             }
988
989             default:
990             {
991
992                 AFSPrint( "AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n",
993                           ulFsControlCode,
994                           ulInputBufferLen,
995                           ulOutputBufferLen);
996
997                 break;
998             }
999         }
1000     }
1001
1002     return ntStatus;
1003 }