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;
224 case FSCTL_LOCK_VOLUME:
226 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
227 AFS_TRACE_LEVEL_VERBOSE_2,
228 "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n");
233 case FSCTL_UNLOCK_VOLUME:
235 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
236 AFS_TRACE_LEVEL_VERBOSE_2,
237 "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n");
242 case FSCTL_DISMOUNT_VOLUME:
244 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
245 AFS_TRACE_LEVEL_VERBOSE_2,
246 "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n");
251 case FSCTL_MARK_VOLUME_DIRTY:
253 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
254 AFS_TRACE_LEVEL_VERBOSE_2,
255 "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n");
260 case FSCTL_IS_VOLUME_DIRTY:
262 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
263 AFS_TRACE_LEVEL_VERBOSE_2,
264 "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n");
269 case FSCTL_IS_VOLUME_MOUNTED:
271 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
272 AFS_TRACE_LEVEL_VERBOSE_2,
273 "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n");
278 case FSCTL_IS_PATHNAME_VALID:
280 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
281 AFS_TRACE_LEVEL_VERBOSE_2,
282 "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n");
287 case FSCTL_GET_REPARSE_POINT:
290 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
291 ULONG ulRemainingLen = ulOutputBufferLen;
292 AFSReparseTagInfo *pReparseInfo = NULL;
294 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
295 AFS_TRACE_LEVEL_VERBOSE_2,
296 "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request\n");
298 if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
301 ntStatus = STATUS_BUFFER_TOO_SMALL;
303 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
308 ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
311 // Check if we have the reparse entry set on the entry
314 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
317 ntStatus = STATUS_NOT_A_REPARSE_POINT;
323 // Populate the data in the reparse buffer
326 pReparseBuffer->ReparseDataLength = 0;
328 AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock,
331 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
335 // We'll reset the DV to ensure we validate the metadata content
338 pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
340 SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
342 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
343 AFS_TRACE_LEVEL_VERBOSE,
344 "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
345 &pCcb->DirectoryCB->NameInformation.FileName,
346 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
347 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
348 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
349 pCcb->DirectoryCB->ObjectInformation->FileId.Unique);
351 ntStatus = AFSVerifyEntry( &pFcb->AuthGroup,
354 if( !NT_SUCCESS( ntStatus))
357 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
358 AFS_TRACE_LEVEL_ERROR,
359 "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
360 &pCcb->DirectoryCB->NameInformation.FileName,
361 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
362 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
363 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
364 pCcb->DirectoryCB->ObjectInformation->FileId.Unique,
367 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
373 pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];
375 switch( pCcb->DirectoryCB->ObjectInformation->FileType)
378 case AFS_FILE_TYPE_SYMLINK:
381 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
384 ntStatus = STATUS_ACCESS_DENIED;
389 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
392 ntStatus = STATUS_BUFFER_TOO_SMALL;
394 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
395 FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
396 pCcb->DirectoryCB->NameInformation.TargetName.Length;
401 pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK;
403 pReparseInfo->AFSSymLink.RelativeLink = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
405 pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
407 RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer,
408 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
409 pCcb->DirectoryCB->NameInformation.TargetName.Length);
411 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
416 case AFS_FILE_TYPE_MOUNTPOINT:
418 UNICODE_STRING Cell, Volume;
421 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
423 ntStatus = STATUS_ACCESS_DENIED;
428 if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName,
433 ntStatus = STATUS_INVALID_PARAMETER;
438 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length)
441 ntStatus = STATUS_BUFFER_TOO_SMALL;
443 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
444 FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) +
445 Volume.Length + Cell.Length;
450 pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT;
452 pReparseInfo->AFSMountPoint.Type = Type;
454 pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length;
456 pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length;
458 RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer,
462 RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)],
466 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length);
471 case AFS_FILE_TYPE_DFSLINK:
474 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
477 ntStatus = STATUS_ACCESS_DENIED;
482 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
485 ntStatus = STATUS_BUFFER_TOO_SMALL;
487 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
488 FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
489 pCcb->DirectoryCB->NameInformation.TargetName.Length;
494 pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC;
496 pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
498 RtlCopyMemory( pReparseInfo->UNCReferral.Buffer,
499 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
500 pCcb->DirectoryCB->NameInformation.TargetName.Length);
502 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
509 ntStatus = STATUS_NOT_A_REPARSE_POINT;
514 if ( ntStatus == STATUS_SUCCESS)
517 ulRemainingLen -= pReparseBuffer->ReparseDataLength;
519 pReparseBuffer->ReparseTag = IO_REPARSE_TAG_OPENAFS_DFS;
521 RtlCopyMemory( &pReparseBuffer->ReparseGuid,
522 &GUID_AFS_REPARSE_GUID,
525 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
526 pReparseBuffer->ReparseDataLength;
529 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
534 case FSCTL_SET_REPARSE_POINT:
537 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
539 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
540 AFS_TRACE_LEVEL_VERBOSE_2,
541 "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request\n");
543 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
546 ntStatus = STATUS_INVALID_PARAMETER;
552 // Check if we have the reparse entry set on the entry
555 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
558 ntStatus = STATUS_NOT_A_REPARSE_POINT;
563 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
566 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
571 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
572 &GUID_AFS_REPARSE_GUID,
573 sizeof( GUID)) != sizeof( GUID))
576 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
582 // For now deny access on this call
588 case FSCTL_DELETE_REPARSE_POINT:
591 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
593 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
594 AFS_TRACE_LEVEL_VERBOSE_2,
595 "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request\n");
597 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
600 ntStatus = STATUS_INVALID_PARAMETER;
606 // Check if we have the reparse entry set on the entry
609 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
612 ntStatus = STATUS_NOT_A_REPARSE_POINT;
617 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
620 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
625 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
626 &GUID_AFS_REPARSE_GUID,
627 sizeof( GUID)) != sizeof( GUID))
630 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
636 // For now deny access on this call
639 ntStatus = STATUS_ACCESS_DENIED;
646 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
647 AFS_TRACE_LEVEL_VERBOSE_2,
648 "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode);
650 ntStatus = STATUS_INVALID_PARAMETER;
664 AFSProcessShareFsCtrl( IN IRP *Irp,
669 NTSTATUS ntStatus = STATUS_SUCCESS;
670 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
671 ULONG ulOutputBufferLen = 0, ulInputBufferLen;
672 ULONG ulFsControlCode;
677 ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
679 ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
680 ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
682 switch( ulFsControlCode)
685 case FSCTL_PIPE_TRANSCEIVE:
688 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
689 AFS_TRACE_LEVEL_VERBOSE,
690 "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n",
691 &Ccb->DirectoryCB->NameInformation.FileName);
693 ntStatus = AFSNotifyPipeTransceive( Ccb,
696 pIrpSp->Parameters.FileSystemControl.Type3InputBuffer,
698 (ULONG *)&Irp->IoStatus.Information);
700 if( !NT_SUCCESS( ntStatus))
703 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
704 AFS_TRACE_LEVEL_VERBOSE,
705 "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n",
706 &Ccb->DirectoryCB->NameInformation.FileName,
716 if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_SERVER_SERVICE))
719 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For srvsvc input %08lX output %08lX\n",
722 // ulOutputBufferLen);
724 else if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_WORKSTATION_SERVICE))
727 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For wkssvc input %08lX output %08lX\n",
730 // ulOutputBufferLen);
735 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n",
738 // ulOutputBufferLen);