2 * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
14 * this list of conditions and the following disclaimer in the
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.
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.
36 // File: AFSFSControl.cpp
39 #include "AFSCommon.h"
42 AFSFSControl( IN PDEVICE_OBJECT LibDeviceObject,
46 NTSTATUS ntStatus = STATUS_SUCCESS;
47 IO_STACK_LOCATION *pIrpSp;
49 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
54 switch( pIrpSp->MinorFunction)
57 case IRP_MN_USER_FS_REQUEST:
59 ntStatus = AFSProcessUserFsRequest( Irp);
63 case IRP_MN_MOUNT_VOLUME:
67 case IRP_MN_VERIFY_VOLUME:
76 AFSCompleteRequest( Irp,
80 __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
85 "EXCEPTION - AFSFSControl\n");
92 AFSParseMountPointTarget( IN UNICODE_STRING *Target,
94 OUT UNICODE_STRING *Volume,
95 OUT UNICODE_STRING *Cell)
97 // Targets are of the form <type>[<cell>:]<volume>
99 *Type = Target->Buffer[ 0];
101 // Extract the cell name (if any)
103 Cell->Buffer = &Target->Buffer[ 1];
105 // Search for colon separator or end of counted string
107 for ( Cell->Length = 0; Cell->Length < Target->Length - sizeof( WCHAR); Cell->Length += sizeof( WCHAR))
110 if ( Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':')
116 // If a colon is not found, it means there is no cell
118 if ( Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':')
121 Cell->MaximumLength = Cell->Length;
123 if ( Cell->Length > Target->Length - 2 * sizeof( WCHAR))
125 // Invalid target string if there is no room for
131 Volume->Length = Volume->MaximumLength = (Target->Length - Cell->Length - 2 * sizeof( WCHAR));
133 Volume->Buffer = &Target->Buffer[ Cell->Length / sizeof( WCHAR) + 2];
139 Volume->Length = Volume->MaximumLength = Cell->Length;
141 Volume->Buffer = Cell->Buffer;
143 Cell->Length = Cell->MaximumLength = 0;
152 AFSProcessUserFsRequest( IN PIRP Irp)
155 NTSTATUS ntStatus = STATUS_SUCCESS;
156 ULONG ulFsControlCode;
158 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp );
160 ULONG ulOutputBufferLen, ulInputBufferLen;
165 ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
167 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
169 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
172 pCcb->DirectoryCB == NULL)
175 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
176 AFS_TRACE_LEVEL_VERBOSE_2,
177 "AFSProcessUserFsRequest Invalid Fcb\n");
179 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
182 if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
185 ntStatus = AFSProcessShareFsCtrl( Irp,
189 try_return( ntStatus);
192 ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
193 ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
196 // Process the request
199 switch( ulFsControlCode )
202 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
203 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
204 case FSCTL_REQUEST_BATCH_OPLOCK:
205 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
206 case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
207 case FSCTL_OPLOCK_BREAK_NOTIFY:
208 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
209 case FSCTL_REQUEST_FILTER_OPLOCK :
212 // Note that implementing this call will probably need us
213 // to call the server as well as adding code in read and
214 // write and caching. Also that it is unlikely that
215 // anyone will ever call us at this point - RDR doesn't
219 ntStatus = STATUS_NOT_IMPLEMENTED;
223 case FSCTL_LOCK_VOLUME:
225 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
226 AFS_TRACE_LEVEL_VERBOSE_2,
227 "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n");
231 case FSCTL_UNLOCK_VOLUME:
233 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
234 AFS_TRACE_LEVEL_VERBOSE_2,
235 "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n");
239 case FSCTL_DISMOUNT_VOLUME:
241 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
242 AFS_TRACE_LEVEL_VERBOSE_2,
243 "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n");
247 case FSCTL_MARK_VOLUME_DIRTY:
249 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
250 AFS_TRACE_LEVEL_VERBOSE_2,
251 "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n");
255 case FSCTL_IS_VOLUME_DIRTY:
257 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
258 AFS_TRACE_LEVEL_VERBOSE_2,
259 "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n");
263 case FSCTL_IS_VOLUME_MOUNTED:
265 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
266 AFS_TRACE_LEVEL_VERBOSE_2,
267 "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n");
271 case FSCTL_IS_PATHNAME_VALID:
273 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
274 AFS_TRACE_LEVEL_VERBOSE_2,
275 "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n");
279 case FSCTL_GET_REPARSE_POINT:
282 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
283 ULONG ulRemainingLen = ulOutputBufferLen;
284 AFSReparseTagInfo *pReparseInfo = NULL;
286 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
287 AFS_TRACE_LEVEL_VERBOSE_2,
288 "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request\n");
290 if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
293 ntStatus = STATUS_BUFFER_TOO_SMALL;
295 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
300 ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
303 // Check if we have the reparse entry set on the entry
306 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
309 ntStatus = STATUS_NOT_A_REPARSE_POINT;
315 // Populate the data in the reparse buffer
318 pReparseBuffer->ReparseDataLength = 0;
320 AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock,
323 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
327 // We'll reset the DV to ensure we validate the metadata content
330 pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
332 SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
334 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
335 AFS_TRACE_LEVEL_VERBOSE,
336 "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
337 &pCcb->DirectoryCB->NameInformation.FileName,
338 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
339 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
340 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
341 pCcb->DirectoryCB->ObjectInformation->FileId.Unique);
343 ntStatus = AFSVerifyEntry( &pFcb->AuthGroup,
346 if( !NT_SUCCESS( ntStatus))
349 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
350 AFS_TRACE_LEVEL_ERROR,
351 "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
352 &pCcb->DirectoryCB->NameInformation.FileName,
353 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
354 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
355 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
356 pCcb->DirectoryCB->ObjectInformation->FileId.Unique,
359 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
365 pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];
367 switch( pCcb->DirectoryCB->ObjectInformation->FileType)
370 case AFS_FILE_TYPE_SYMLINK:
373 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
376 ntStatus = STATUS_ACCESS_DENIED;
381 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
384 ntStatus = STATUS_BUFFER_TOO_SMALL;
386 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
387 FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
388 pCcb->DirectoryCB->NameInformation.TargetName.Length;
393 pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK;
395 pReparseInfo->AFSSymLink.RelativeLink = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
397 pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
399 RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer,
400 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
401 pCcb->DirectoryCB->NameInformation.TargetName.Length);
403 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
408 case AFS_FILE_TYPE_MOUNTPOINT:
410 UNICODE_STRING Cell, Volume;
413 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
415 ntStatus = STATUS_ACCESS_DENIED;
420 if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName,
425 ntStatus = STATUS_INVALID_PARAMETER;
430 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length)
433 ntStatus = STATUS_BUFFER_TOO_SMALL;
435 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
436 FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) +
437 Volume.Length + Cell.Length;
442 pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT;
444 pReparseInfo->AFSMountPoint.Type = Type;
446 pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length;
448 pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length;
450 RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer,
454 RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)],
458 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length);
463 case AFS_FILE_TYPE_DFSLINK:
466 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
469 ntStatus = STATUS_ACCESS_DENIED;
474 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
477 ntStatus = STATUS_BUFFER_TOO_SMALL;
479 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
480 FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
481 pCcb->DirectoryCB->NameInformation.TargetName.Length;
486 pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC;
488 pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
490 RtlCopyMemory( pReparseInfo->UNCReferral.Buffer,
491 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
492 pCcb->DirectoryCB->NameInformation.TargetName.Length);
494 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
501 ntStatus = STATUS_NOT_A_REPARSE_POINT;
506 if ( ntStatus == STATUS_SUCCESS)
509 ulRemainingLen -= pReparseBuffer->ReparseDataLength;
511 pReparseBuffer->ReparseTag = IO_REPARSE_TAG_OPENAFS_DFS;
513 RtlCopyMemory( &pReparseBuffer->ReparseGuid,
514 &GUID_AFS_REPARSE_GUID,
517 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
518 pReparseBuffer->ReparseDataLength;
521 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
526 case FSCTL_SET_REPARSE_POINT:
529 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
531 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
532 AFS_TRACE_LEVEL_VERBOSE_2,
533 "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request\n");
535 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
538 ntStatus = STATUS_INVALID_PARAMETER;
544 // Check if we have the reparse entry set on the entry
547 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
550 ntStatus = STATUS_NOT_A_REPARSE_POINT;
555 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
558 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
563 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
564 &GUID_AFS_REPARSE_GUID,
565 sizeof( GUID)) != sizeof( GUID))
568 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
574 // For now deny access on this call
580 case FSCTL_DELETE_REPARSE_POINT:
583 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
585 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
586 AFS_TRACE_LEVEL_VERBOSE_2,
587 "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request\n");
589 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
592 ntStatus = STATUS_INVALID_PARAMETER;
598 // Check if we have the reparse entry set on the entry
601 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
604 ntStatus = STATUS_NOT_A_REPARSE_POINT;
609 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
612 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
617 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
618 &GUID_AFS_REPARSE_GUID,
619 sizeof( GUID)) != sizeof( GUID))
622 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
628 // For now deny access on this call
631 ntStatus = STATUS_ACCESS_DENIED;
638 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
639 AFS_TRACE_LEVEL_VERBOSE_2,
640 "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode);
642 ntStatus = STATUS_INVALID_PARAMETER;
656 AFSProcessShareFsCtrl( IN IRP *Irp,
661 NTSTATUS ntStatus = STATUS_SUCCESS;
662 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
663 ULONG ulOutputBufferLen = 0, ulInputBufferLen;
664 ULONG ulFsControlCode;
669 ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
671 ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
672 ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
674 switch( ulFsControlCode)
677 case FSCTL_PIPE_TRANSCEIVE:
680 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
681 AFS_TRACE_LEVEL_VERBOSE,
682 "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n",
683 &Ccb->DirectoryCB->NameInformation.FileName);
685 ntStatus = AFSNotifyPipeTransceive( Ccb,
688 pIrpSp->Parameters.FileSystemControl.Type3InputBuffer,
690 (ULONG *)&Irp->IoStatus.Information);
692 if( !NT_SUCCESS( ntStatus))
695 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
696 AFS_TRACE_LEVEL_VERBOSE,
697 "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n",
698 &Ccb->DirectoryCB->NameInformation.FileName,
708 if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_SERVER_SERVICE))
711 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For srvsvc input %08lX output %08lX\n",
714 // ulOutputBufferLen);
716 else if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_WORKSTATION_SERVICE))
719 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For wkssvc input %08lX output %08lX\n",
722 // ulOutputBufferLen);
727 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n",
730 // ulOutputBufferLen);