/*++

Copyright (c) 2000-2001  Microsoft Corporation

Module Name:

    create.c

Abstract:

    This module implements routines related to handling IRP_MJ_CREATE.

--*/

#include "rawx.h"

NTSTATUS
RawxFsdCreate(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
/*++

Routine Description:

    This routine is called by the I/O manager to handle IRP_MJ_CREATE requests.

Arguments:

    DeviceObject - Specifies the device object that the I/O request is for.

    Irp - Specifies the packet that describes the I/O request.

Return Value:

    Status of operation.

--*/
{
    NTSTATUS status;
    PRAW_VOLUME_EXTENSION VolumeExtension;
    PIO_STACK_LOCATION IrpSp;
    ACCESS_MASK DesiredAccess;
    USHORT ShareAccess;
    ULONG CreateOptions;
    PFILE_OBJECT FileObject;
    ULONG CreateDisposition;

    VolumeExtension = (PRAW_VOLUME_EXTENSION)DeviceObject->DeviceExtension;
    IrpSp = IoGetCurrentIrpStackLocation(Irp);
    DesiredAccess = IrpSp->Parameters.Create.DesiredAccess;
    ShareAccess = IrpSp->Parameters.Create.ShareAccess;
    CreateOptions = IrpSp->Parameters.Create.Options;
    FileObject = IrpSp->FileObject;

    RawxAcquireVolumeMutexExclusive(VolumeExtension);

    //
    // Check if the volume has been dismounted.
    //

    if (VolumeExtension->Dismounted) {
        status = STATUS_VOLUME_DISMOUNTED;
        goto CleanupAndExit;
    }

    //
    // Don't allow a relative path to be opened.
    //

    if (IrpSp->FileObject->RelatedFileObject != NULL) {
        status = STATUS_INVALID_PARAMETER;
        goto CleanupAndExit;
    } else if (IrpSp->Parameters.Create.RemainingName->Length != 0) {
        status = STATUS_OBJECT_PATH_NOT_FOUND;
        goto CleanupAndExit;
    }

    //
    // Verify that the create disposition is for open access only.
    //

    CreateDisposition = (CreateOptions >> 24) & 0xFF;

    if ((CreateDisposition != FILE_OPEN) && (CreateDisposition != FILE_OPEN_IF)) {
        status = STATUS_ACCESS_DENIED;
        goto CleanupAndExit;
    }

    //
    // The caller shouldn't be expecting to see a directory file.
    //

    if (RawxIsFlagSet(CreateOptions, FILE_DIRECTORY_FILE)) {
        status = STATUS_NOT_A_DIRECTORY;
        goto CleanupAndExit;
    }

    //
    // If this is the first open handle to the file, then initialize the sharing
    // mode.  Otherwise, verify that the requested sharing mode is compatible
    // with the current sharing mode.
    //

    if (VolumeExtension->ShareAccess.OpenCount == 0) {
        IoSetShareAccess(DesiredAccess, ShareAccess, FileObject,
            &VolumeExtension->ShareAccess);
        status = STATUS_SUCCESS;
    } else {
        status = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject,
            &VolumeExtension->ShareAccess, TRUE);
    }

    if (NT_SUCCESS(status)) {

        //
        // Physical volume access is always non-cached.  Mark the file object as
        // non-cached so that the I/O manager enforces alignment requirements.
        //

        FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;

        //
        // Indicate to the caller that we opened the file as opposed to creating
        // or overwriting the file.
        //

        Irp->IoStatus.Information = FILE_OPENED;

        status = STATUS_SUCCESS;
    }

CleanupAndExit:
    RawxReleaseVolumeMutex(VolumeExtension);

    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}
