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 #ifndef FSCTL_CSC_INTERNAL
288 #define FSCTL_CSC_INTERNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS)
290 case FSCTL_CSC_INTERNAL:
292 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
293 AFS_TRACE_LEVEL_VERBOSE_2,
294 "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n");
296 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
301 case FSCTL_GET_REPARSE_POINT:
304 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
305 ULONG ulRemainingLen = ulOutputBufferLen;
306 AFSReparseTagInfo *pReparseInfo = NULL;
308 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
309 AFS_TRACE_LEVEL_VERBOSE_2,
310 "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request\n");
313 // Check if we have the reparse entry set on the entry
316 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
319 ntStatus = STATUS_NOT_A_REPARSE_POINT;
324 if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
327 ntStatus = STATUS_BUFFER_TOO_SMALL;
329 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
334 ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer);
337 // Populate the data in the reparse buffer
340 pReparseBuffer->ReparseDataLength = 0;
342 AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock,
345 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
349 // We'll reset the DV to ensure we validate the metadata content
352 pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
354 SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
356 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
357 AFS_TRACE_LEVEL_VERBOSE,
358 "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
359 &pCcb->DirectoryCB->NameInformation.FileName,
360 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
361 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
362 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
363 pCcb->DirectoryCB->ObjectInformation->FileId.Unique);
365 ntStatus = AFSVerifyEntry( &pFcb->AuthGroup,
368 if( !NT_SUCCESS( ntStatus))
371 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
372 AFS_TRACE_LEVEL_ERROR,
373 "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
374 &pCcb->DirectoryCB->NameInformation.FileName,
375 pCcb->DirectoryCB->ObjectInformation->FileId.Cell,
376 pCcb->DirectoryCB->ObjectInformation->FileId.Volume,
377 pCcb->DirectoryCB->ObjectInformation->FileId.Vnode,
378 pCcb->DirectoryCB->ObjectInformation->FileId.Unique,
381 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
387 pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];
389 switch( pCcb->DirectoryCB->ObjectInformation->FileType)
392 case AFS_FILE_TYPE_SYMLINK:
395 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
398 ntStatus = STATUS_ACCESS_DENIED;
403 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
406 ntStatus = STATUS_BUFFER_TOO_SMALL;
408 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
409 FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
410 pCcb->DirectoryCB->NameInformation.TargetName.Length;
415 pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK;
417 pReparseInfo->AFSSymLink.RelativeLink = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
419 pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
421 RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer,
422 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
423 pCcb->DirectoryCB->NameInformation.TargetName.Length);
425 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
430 case AFS_FILE_TYPE_MOUNTPOINT:
432 UNICODE_STRING Cell, Volume;
435 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
437 ntStatus = STATUS_ACCESS_DENIED;
442 if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName,
447 ntStatus = STATUS_INVALID_PARAMETER;
452 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length)
455 ntStatus = STATUS_BUFFER_TOO_SMALL;
457 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
458 FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) +
459 Volume.Length + Cell.Length;
464 pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT;
466 pReparseInfo->AFSMountPoint.Type = Type;
468 pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length;
470 pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length;
472 RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer,
476 RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)],
480 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length);
485 case AFS_FILE_TYPE_DFSLINK:
488 if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
491 ntStatus = STATUS_ACCESS_DENIED;
496 if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length)
499 ntStatus = STATUS_BUFFER_TOO_SMALL;
501 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
502 FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
503 pCcb->DirectoryCB->NameInformation.TargetName.Length;
508 pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC;
510 pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length;
512 RtlCopyMemory( pReparseInfo->UNCReferral.Buffer,
513 pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
514 pCcb->DirectoryCB->NameInformation.TargetName.Length);
516 pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length);
523 ntStatus = STATUS_NOT_A_REPARSE_POINT;
528 if ( ntStatus == STATUS_SUCCESS)
531 ulRemainingLen -= pReparseBuffer->ReparseDataLength;
533 pReparseBuffer->ReparseTag = IO_REPARSE_TAG_OPENAFS_DFS;
535 RtlCopyMemory( &pReparseBuffer->ReparseGuid,
536 &GUID_AFS_REPARSE_GUID,
539 Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
540 pReparseBuffer->ReparseDataLength;
543 AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);
548 case FSCTL_SET_REPARSE_POINT:
551 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
553 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
554 AFS_TRACE_LEVEL_VERBOSE_2,
555 "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request\n");
558 // Check if we have the reparse entry set on the entry
561 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
564 ntStatus = STATUS_NOT_A_REPARSE_POINT;
569 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
572 ntStatus = STATUS_INVALID_PARAMETER;
577 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
580 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
585 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
586 &GUID_AFS_REPARSE_GUID,
587 sizeof( GUID)) != sizeof( GUID))
590 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
596 // For now deny access on this call
602 case FSCTL_DELETE_REPARSE_POINT:
605 REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
607 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
608 AFS_TRACE_LEVEL_VERBOSE_2,
609 "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request\n");
612 // Check if we have the reparse entry set on the entry
615 if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
618 ntStatus = STATUS_NOT_A_REPARSE_POINT;
623 if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
626 ntStatus = STATUS_INVALID_PARAMETER;
631 if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS)
634 ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
639 if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
640 &GUID_AFS_REPARSE_GUID,
641 sizeof( GUID)) != sizeof( GUID))
644 ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
650 // For now deny access on this call
653 ntStatus = STATUS_ACCESS_DENIED;
660 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
661 AFS_TRACE_LEVEL_VERBOSE_2,
662 "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode);
664 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
678 AFSProcessShareFsCtrl( IN IRP *Irp,
683 NTSTATUS ntStatus = STATUS_SUCCESS;
684 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
685 ULONG ulOutputBufferLen = 0, ulInputBufferLen;
686 ULONG ulFsControlCode;
691 ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode;
693 ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength;
694 ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
696 switch( ulFsControlCode)
699 case FSCTL_PIPE_TRANSCEIVE:
702 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
703 AFS_TRACE_LEVEL_VERBOSE,
704 "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n",
705 &Ccb->DirectoryCB->NameInformation.FileName);
707 ntStatus = AFSNotifyPipeTransceive( Ccb,
710 pIrpSp->Parameters.FileSystemControl.Type3InputBuffer,
712 (ULONG *)&Irp->IoStatus.Information);
714 if( !NT_SUCCESS( ntStatus))
717 AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING,
718 AFS_TRACE_LEVEL_VERBOSE,
719 "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n",
720 &Ccb->DirectoryCB->NameInformation.FileName,
730 if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_SERVER_SERVICE))
733 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For srvsvc input %08lX output %08lX\n",
736 // ulOutputBufferLen);
738 else if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_WORKSTATION_SERVICE))
741 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For wkssvc input %08lX output %08lX\n",
744 // ulOutputBufferLen);
749 //AFSPrint("AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n",
752 // ulOutputBufferLen);