static
NTSTATUS
PvfsSetEndOfFileWithContext(
    PVOID pContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PPVFS_PENDING_SET_END_OF_FILE pSetEoFCtx = (PPVFS_PENDING_SET_END_OF_FILE)pContext;
    PIRP pIrp = pSetEoFCtx->pIrpContext->pIrp;
    PPVFS_CCB pCcb = pSetEoFCtx->pCcb;
    IRP_ARGS_QUERY_SET_INFORMATION Args = {0};
    PFILE_END_OF_FILE_INFORMATION pFileInfo = NULL;

    Args = pSetEoFCtx->pIrpContext->pIrp->Args.QuerySetInformation;
    pFileInfo = (PFILE_END_OF_FILE_INFORMATION)Args.FileInformation;

    ntError = PvfsSysFtruncate(pCcb->fd, (off_t)pFileInfo->EndOfFile);
    BAIL_ON_NT_STATUS(ntError);

    pIrp->IoStatusBlock.BytesTransferred = sizeof(*pFileInfo);
    ntError = STATUS_SUCCESS;

    PvfsNotifyScheduleFullReport(
        pCcb->pScb->pOwnerFcb,
        FILE_NOTIFY_CHANGE_SIZE,
        FILE_ACTION_MODIFIED,
        pCcb->pScb->pOwnerFcb->pszFilename);


cleanup:
    return ntError;

error:
    goto cleanup;
}
Beispiel #2
0
NTSTATUS
PvfsSetFileAttributes(
    IN PPVFS_CCB pCcb,
    IN FILE_ATTRIBUTES Attributes
    )
{
    NTSTATUS ntError = STATUS_ACCESS_DENIED;
    FILE_ATTRIBUTES AttribNotSettable = FILE_ATTRIBUTE_ENCRYPTED |
                                        FILE_ATTRIBUTE_DEVICE |
                                        FILE_ATTRIBUTE_COMPRESSED |
                                        FILE_ATTRIBUTE_REPARSE_POINT |
                                        FILE_ATTRIBUTE_SPARSE_FILE;

    /* Use PvfsSetFileAttributesEx() for IoControl */

    if (Attributes & AttribNotSettable) {
        ntError = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntError);
    }

    /* Clear some bits that should not be stored */

    Attributes &= ~(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL);

    if (Attributes & FILE_ATTRIBUTE_SYSTEM)
    {
        Attributes |= FILE_ATTRIBUTE_ARCHIVE;
    }

#ifdef HAVE_EA_SUPPORT
    ntError = PvfsSetFileAttributesXattr(pCcb, Attributes);
#else
    ntError = STATUS_SUCCESS;
#endif

    BAIL_ON_NT_STATUS(ntError);

    PvfsNotifyScheduleFullReport(
        pCcb->pFcb,
        FILE_NOTIFY_CHANGE_ATTRIBUTES,
        FILE_ACTION_MODIFIED,
        pCcb->pszFilename);

cleanup:
    return ntError;

error:
    goto cleanup;
}
Beispiel #3
0
NTSTATUS
PvfsCreateDirDoSysOpen(
    IN PVOID pContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PPVFS_PENDING_CREATE pCreateContext = (PPVFS_PENDING_CREATE)pContext;
    PIRP pIrp = pCreateContext->pIrpContext->pIrp;
    IRP_ARGS_CREATE Args = pIrp->Args.Create;
    int fd = -1;
    int unixFlags = 0;
    PIO_CREATE_SECURITY_CONTEXT pSecCtx = Args.SecurityContext;
    FILE_CREATE_RESULT CreateResult = 0;
    IO_MATCH_FILE_SPEC FileSpec = {0};
    WCHAR wszPattern[2] = {L'*', 0x0 };
    PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcess = NULL;
    PBOOLEAN pbEnableAbe = NULL;
    ULONG ulEcpSize = 0;

    pProcess = IoSecurityGetProcessInfo(pSecCtx);

    /* Fail any create that requires setting the security but doesn't
       have the Unix uid/gid information */

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) &&
        (pProcess == NULL))
    {
        ntError = STATUS_ACCESS_DENIED;
        BAIL_ON_NT_STATUS(ntError);
    }

    /* Do the open() */

    ntError = MapPosixOpenFlags(
                  &unixFlags,
                  pCreateContext->GrantedAccess,
                  Args);
    BAIL_ON_NT_STATUS(ntError);

    if (!pCreateContext->bFileExisted)
    {
        ntError = PvfsSysMkDir(
                      pCreateContext->pszDiskFilename,
                      (mode_t)gPvfsDriverConfig.CreateDirectoryMode);
        BAIL_ON_NT_STATUS(ntError);
    }

    /* Open the DIR* and then open a fd based on that */

    ntError = PvfsAllocateMemory(
                  (PVOID)&pCreateContext->pCcb->pDirContext,
                  sizeof(PVFS_DIRECTORY_CONTEXT));
    BAIL_ON_NT_STATUS(ntError);

    pCreateContext->pCcb->pszFilename = pCreateContext->pszDiskFilename;
    pCreateContext->pszDiskFilename = NULL;

    ntError = IoRtlEcpListFind(
                  pIrp->Args.Create.EcpList,
                  SRV_ECP_TYPE_ABE,
                  OUT_PPVOID(&pbEnableAbe),
                  &ulEcpSize);
    if (ntError != STATUS_NOT_FOUND)
    {
        BAIL_ON_NT_STATUS(ntError);

        if (ulEcpSize != sizeof(BOOLEAN))
        {
            ntError = STATUS_INVALID_PARAMETER;
            BAIL_ON_NT_STATUS(ntError);
        }

        if (*pbEnableAbe)
        {
            pCreateContext->pCcb->EcpFlags |= PVFS_ECP_ENABLE_ABE;
        }
    }

    do
    {
        ntError = PvfsSysOpen(
                      &fd,
                      pCreateContext->pCcb->pszFilename,
                      0,
                      0);

    } while (ntError == STATUS_MORE_PROCESSING_REQUIRED);
    BAIL_ON_NT_STATUS(ntError);

    /* Save our state */

    pCreateContext->pCcb->fd = fd;
    pCreateContext->pCcb->ShareFlags = Args.ShareAccess;
    pCreateContext->pCcb->AccessGranted = pCreateContext->GrantedAccess;
    pCreateContext->pCcb->CreateOptions = Args.CreateOptions;

    ntError = PvfsAddCCBToFCB(pCreateContext->pFcb, pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsSaveFileDeviceInfo(pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && pSecCtx)
    {
        /* Unix Security */

        ntError = PvfsSysChown(
                      pCreateContext->pCcb,
                      pProcess->Uid,
                      pProcess->Gid);
        BAIL_ON_NT_STATUS(ntError);

        /* Security Descriptor */

        ntError = PvfsCreateFileSecurity(
                      pCreateContext->pCcb->pUserToken,
                      pCreateContext->pCcb,
                      Args.SecurityDescriptor,
                      TRUE);
        BAIL_ON_NT_STATUS(ntError);
    }

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_ATTRIB) &&
        (Args.FileAttributes != 0))
    {
        ntError = PvfsSetFileAttributes(
                      pCreateContext->pCcb,
                      Args.FileAttributes);
        BAIL_ON_NT_STATUS(ntError);
    }

    /* Save the delete-on-close flag to the FCB */

    if (Args.CreateOptions & FILE_DELETE_ON_CLOSE)
    {
        LwRtlUnicodeStringInit(&FileSpec.Pattern, wszPattern);

        ntError = PvfsEnumerateDirectory(pCreateContext->pCcb, &FileSpec, 1, FALSE);
        if (ntError == STATUS_SUCCESS)
        {
            ntError = STATUS_DIRECTORY_NOT_EMPTY;
            BAIL_ON_NT_STATUS(ntError);
        }

        pCreateContext->pCcb->bPendingDeleteHandle = TRUE;
    }

    ntError = PvfsStoreCCB(pIrp->FileHandle, pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    PvfsInitializeZctSupport(pCreateContext->pCcb, pIrp->FileHandle);

    CreateResult = PvfsSetCreateResult(
                       Args.CreateDisposition,
                       pCreateContext->bFileExisted,
                       STATUS_SUCCESS);

    if (CreateResult == FILE_CREATED)
    {
        PvfsNotifyScheduleFullReport(
            pCreateContext->pCcb->pFcb,
            FILE_NOTIFY_CHANGE_FILE_NAME,
            FILE_ACTION_ADDED,
            pCreateContext->pCcb->pszFilename);
    }

    /* The CCB has been handled off to the FileHandle so make sure
       we don't think we still own it */

    pCreateContext->pCcb = NULL;

cleanup:
    pIrp->IoStatusBlock.CreateResult = CreateResult;

    return ntError;

error:
    CreateResult = PvfsSetCreateResult(
                       Args.CreateDisposition,
                       pCreateContext->bFileExisted,
                       ntError);

    if (fd != -1)
    {
        PSTR pszRemovePath = NULL;

        /* Pick up where we started the pathname */

        pszRemovePath = pCreateContext->pszDiskFilename ?
                        pCreateContext->pszDiskFilename :
                        pCreateContext->pCcb->pszFilename;

        PvfsCleanupFailedCreate(
            fd,
            pszRemovePath,
            !pCreateContext->bFileExisted);
    }

    goto cleanup;
}
Beispiel #4
0
NTSTATUS
PvfsCreateFileDoSysOpen(
    IN PVOID pContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PPVFS_PENDING_CREATE pCreateContext = (PPVFS_PENDING_CREATE)pContext;
    PIRP pIrp = pCreateContext->pIrpContext->pIrp;
    IRP_ARGS_CREATE Args = pIrp->Args.Create;
    int fd = -1;
    int unixFlags = 0;
    PIO_CREATE_SECURITY_CONTEXT pSecCtx = Args.SecurityContext;
    FILE_CREATE_RESULT CreateResult = 0;
    PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcess = NULL;

    pProcess = IoSecurityGetProcessInfo(pSecCtx);

    /* Fail any create that requires setting the security but doesn't
       have the Unix uid/gid information */

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) &&
        (pProcess == NULL))
    {
        ntError = STATUS_ACCESS_DENIED;
        BAIL_ON_NT_STATUS(ntError);
    }

    ntError = PvfsEnforceShareMode(
                   pCreateContext->pFcb,
                   Args.ShareAccess,
                   pCreateContext->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    /* Do the open() */

    ntError = MapPosixOpenFlags(&unixFlags, pCreateContext->GrantedAccess, Args);
    BAIL_ON_NT_STATUS(ntError);

    do
    {
        ntError = PvfsSysOpen(
                      &fd,
                      pCreateContext->pszDiskFilename,
                      unixFlags,
                      (mode_t)gPvfsDriverConfig.CreateFileMode);

    } while (ntError == STATUS_MORE_PROCESSING_REQUIRED);
    BAIL_ON_NT_STATUS(ntError);

    /* Perform preallocation is requested */

    if (Args.AllocationSize > 0)
    {
        BOOLEAN bAllocate = FALSE;

        switch (Args.CreateDisposition)
        {
        case FILE_SUPERSEDE:
        case FILE_CREATE:
        case FILE_OVERWRITE:
        case FILE_OVERWRITE_IF:
            bAllocate = TRUE;
            break;

        case FILE_OPEN_IF:
            if (!pCreateContext->bFileExisted)
            {
                bAllocate = TRUE;
            }
            break;
        }

        if (bAllocate)
        {
            ntError = PvfsSysFtruncate(fd, (off_t)Args.AllocationSize);
            BAIL_ON_NT_STATUS(ntError);
        }
    }

    /* Save our state */

    pCreateContext->pCcb->fd = fd;
    pCreateContext->pCcb->ShareFlags = Args.ShareAccess;
    pCreateContext->pCcb->AccessGranted = pCreateContext->GrantedAccess;
    pCreateContext->pCcb->CreateOptions = Args.CreateOptions;

    pCreateContext->pCcb->pszFilename = pCreateContext->pszDiskFilename;
    pCreateContext->pszDiskFilename = NULL;

    ntError = PvfsAddCCBToFCB(pCreateContext->pFcb, pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsSaveFileDeviceInfo(pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    /* CCB is now complete */

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && pSecCtx)
    {
        /* Unix Security */

        ntError = PvfsSysChown(
                      pCreateContext->pCcb,
                      pProcess->Uid,
                      pProcess->Gid);
        BAIL_ON_NT_STATUS(ntError);

        /* Security Descriptor */

        ntError = PvfsCreateFileSecurity(
                      pCreateContext->pCcb->pUserToken,
                      pCreateContext->pCcb,
                      Args.SecurityDescriptor,
                      FALSE);
        BAIL_ON_NT_STATUS(ntError);
    }

    if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_ATTRIB) &&
        (Args.FileAttributes != 0))
    {
        ntError = PvfsSetFileAttributes(
                      pCreateContext->pCcb,
                      Args.FileAttributes);
        BAIL_ON_NT_STATUS(ntError);
    }

    /* Save the delete-on-close flag to the FCB */

    if (Args.CreateOptions & FILE_DELETE_ON_CLOSE)
    {
        pCreateContext->pCcb->bPendingDeleteHandle = TRUE;
    }

    ntError = PvfsStoreCCB(pIrp->FileHandle, pCreateContext->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    PvfsInitializeZctSupport(pCreateContext->pCcb, pIrp->FileHandle);

    CreateResult = PvfsSetCreateResult(
                       Args.CreateDisposition,
                       pCreateContext->bFileExisted,
                       STATUS_SUCCESS);

    if (CreateResult == FILE_CREATED)
    {
        PvfsNotifyScheduleFullReport(
            pCreateContext->pCcb->pFcb,
            FILE_NOTIFY_CHANGE_FILE_NAME,
            FILE_ACTION_ADDED,
            pCreateContext->pCcb->pszFilename);
    }

    /* The CCB has been handled off to the FileHandle so make sure
       we don't think we still own it */

    pCreateContext->pCcb = NULL;

cleanup:
    pIrp->IoStatusBlock.CreateResult = CreateResult;

    return ntError;

error:
    CreateResult = PvfsSetCreateResult(
                       Args.CreateDisposition,
                       pCreateContext->bFileExisted,
                       ntError);

    if (fd != -1)
    {
        PSTR pszRemovePath = NULL;

        /* Pick up where we started the pathname */

        pszRemovePath = pCreateContext->pszDiskFilename ?
                        pCreateContext->pszDiskFilename :
                        pCreateContext->pCcb->pszFilename;

        PvfsCleanupFailedCreate(
            fd,
            pszRemovePath,
            !pCreateContext->bFileExisted);
    }

    goto cleanup;
}
Beispiel #5
0
NTSTATUS
PvfsCcbSetFileBasicInformation(
    PPVFS_CCB pCcb,
    PFILE_BASIC_INFORMATION pFileInfo
    )
{
    NTSTATUS ntError = STATUS_SUCCESS;
    LONG64 WriteTime = 0;
    LONG64 AccessTime = 0;
    FILE_NOTIFY_CHANGE NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE |
                                      FILE_NOTIFY_CHANGE_LAST_ACCESS;
    PVFS_STAT Stat = {0};
    BOOLEAN fcbControlLocked = FALSE;
    PPVFS_FCB pFcb = PvfsReferenceFCB(pCcb->pScb->pOwnerFcb);

    if (PvfsIsDefaultStream(pCcb->pScb))
    {
        ntError = PvfsValidatePathSCB(pCcb->pScb, &pCcb->FileId);
    }
    else
    {
        // Have to grab the base file object
        LWIO_LOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex);

        ntError = PvfsValidatePathFCB(pFcb, &pFcb->FileId);
        BAIL_ON_NT_STATUS(ntError);

        LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex);
    }

    /* We cant's set the Change Time so ignore it */

    WriteTime  = pFileInfo->LastWriteTime;
    AccessTime = pFileInfo->LastAccessTime;

    /* Ignore 0xffffffff */

    if (WriteTime == (LONG64)-1) {
        WriteTime = 0;
    }

    if (AccessTime == (LONG64)-1) {
        AccessTime = 0;
    }

    /* Save for "sticky" WriteTime sematics */

    if (WriteTime != 0)
    {
        PvfsSetLastWriteTimeFCB(pFcb, WriteTime);
    }

    /* Check if we need to preserve any original timestamps */

    if (WriteTime == 0 || AccessTime == 0)
    {
        if (PvfsIsDefaultStream(pCcb->pScb))
        {
            ntError = PvfsSysFstat(pCcb->fd, &Stat);
        }
        else
        {
            // Have to grab the stat() on the base file object
            ntError = PvfsSysStatByFcb(pFcb, &Stat);
        }
        BAIL_ON_NT_STATUS(ntError);

        if (WriteTime == 0)
        {
            NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;

            ntError = PvfsUnixToWinTime(&WriteTime, Stat.s_mtime);
            BAIL_ON_NT_STATUS(ntError);
        }

        if (AccessTime == 0)
        {
            NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;

            ntError = PvfsUnixToWinTime(&AccessTime, Stat.s_atime);
            BAIL_ON_NT_STATUS(ntError);
        }
    }

    ntError = PvfsSysUtimeByFcb(pFcb, WriteTime, AccessTime);
    BAIL_ON_NT_STATUS(ntError);

    if (pFileInfo->FileAttributes != 0)
    {
        ntError = PvfsSetFileAttributes(pCcb, pFileInfo->FileAttributes);
        BAIL_ON_NT_STATUS(ntError);
    }

    if (NotifyFilter != 0)
    {
        PvfsNotifyScheduleFullReport(
            pFcb,
            NotifyFilter,
            FILE_ACTION_MODIFIED,
            pFcb->pszFilename);
    }

error:
    LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex);

    if (pFcb)
    {
        PvfsReleaseFCB(&pFcb);
    }

    return ntError;
}
Beispiel #6
0
NTSTATUS
PvfsSetSecurityDescriptorFile(
    IN PPVFS_CCB pCcb,
    IN SECURITY_INFORMATION SecInfo,
    IN PSECURITY_DESCRIPTOR_RELATIVE pSecDesc,
    IN ULONG SecDescLength
    )
{
    NTSTATUS ntError = STATUS_ACCESS_DENIED;
    PSECURITY_DESCRIPTOR_RELATIVE pFinalSecDesc = NULL;
    ULONG ulFinalSecDescLength = 0;
    SECURITY_INFORMATION SecInfoAll = (OWNER_SECURITY_INFORMATION |
                                       GROUP_SECURITY_INFORMATION |
                                       DACL_SECURITY_INFORMATION |
                                       SACL_SECURITY_INFORMATION);
    BYTE pCurrentSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE];
    ULONG ulCurrentSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE;
    BYTE pNewSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE];
    ULONG ulNewSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE;
    PSECURITY_DESCRIPTOR_ABSOLUTE pIncAbsSecDesc = NULL;
    union {
        TOKEN_OWNER TokenOwnerInfo;
        BYTE Buffer[SID_MAX_SIZE];
    } TokenOwnerBuffer;
    PTOKEN_OWNER pTokenOwnerInformation = (PTOKEN_OWNER)&TokenOwnerBuffer;
    ULONG ulTokenOwnerLength = 0;
    union {
        SID Sid;
        BYTE Buffer[SID_MAX_SIZE];
    } LocalSystemSidBuffer;
    PSID pLocalSystemSid = (PSID)&LocalSystemSidBuffer;
    ULONG ulLocalSystemSidLength = sizeof(LocalSystemSidBuffer);

    memset(pCurrentSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE);
    memset(pNewSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE);
    memset(TokenOwnerBuffer.Buffer, 0, SID_MAX_SIZE);

    /* Sanity checks */

    if (SecInfo == 0)
    {
        ntError = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntError);
    }

    /* If the new Security Descriptor contains owner or group SID
       information, berify that the user's ACCESS_TOKEN contains the
       SID as a member */

    if (SecInfo & (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION))
    {
        PSID pOwner = NULL;
        PSID pGroup = NULL;
        BOOLEAN bDefaulted = FALSE;

        ntError = PvfsSecurityAclSelfRelativeToAbsoluteSD(
                      &pIncAbsSecDesc,
                      pSecDesc);
        BAIL_ON_NT_STATUS(ntError);

        ntError = RtlQueryAccessTokenInformation(
                      pCcb->pUserToken,
                      TokenOwner,
                      (PVOID)pTokenOwnerInformation,
                      sizeof(TokenOwnerBuffer),
                      &ulTokenOwnerLength);
        BAIL_ON_NT_STATUS(ntError);

        ntError = RtlCreateWellKnownSid(
                      WinLocalSystemSid,
                      NULL,
                      pLocalSystemSid,
                      &ulLocalSystemSidLength);
        BAIL_ON_NT_STATUS(ntError);

        if (SecInfo & OWNER_SECURITY_INFORMATION)
        {
            ntError = RtlGetOwnerSecurityDescriptor(
                          pIncAbsSecDesc,
                          &pOwner,
                          &bDefaulted);
            BAIL_ON_NT_STATUS(ntError);

            if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pOwner) &&
                !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner))
            {
                ntError = STATUS_ACCESS_DENIED;
                BAIL_ON_NT_STATUS(ntError);
            }
        }

        if (SecInfo & GROUP_SECURITY_INFORMATION)
        {
            ntError = RtlGetGroupSecurityDescriptor(
                          pIncAbsSecDesc,
                          &pGroup,
                          &bDefaulted);
            BAIL_ON_NT_STATUS(ntError);

            if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pGroup) &&
                !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner))
            {
                ntError = STATUS_ACCESS_DENIED;
                BAIL_ON_NT_STATUS(ntError);
            }
        }
    }


    if (SecInfo == SecInfoAll)
    {
        /* We already have a fully formed Security Descriptor */

        pFinalSecDesc = pSecDesc;
        ulFinalSecDescLength = SecDescLength;
    }
    else
    {
        /* Retrieve the existing SD and merge with the incoming one */

        ntError = PvfsGetSecurityDescriptorFile(
                      pCcb,
                      SecInfoAll,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer,
                      &ulCurrentSecDescLength);
        BAIL_ON_NT_STATUS(ntError);

        /* Assume that the new SD is <= the combined size of the current
           SD and the incoming one */

        ntError = RtlSetSecurityDescriptorInfo(
                      SecInfo,
                      pSecDesc,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer,
                      &ulNewSecDescLength,
                      &gPvfsFileGenericMapping);
        BAIL_ON_NT_STATUS(ntError);

        pFinalSecDesc = (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer;
        ulFinalSecDescLength = ulNewSecDescLength;

    }


    /* Save the combined SD */

#ifdef HAVE_EA_SUPPORT
    ntError = PvfsSetSecurityDescriptorFileXattr(
                  pCcb,
                  pFinalSecDesc,
                  ulFinalSecDescLength);
#else
    ntError = PvfsSetSecurityDescriptorPosix(
                  pCcb,
                  pFinalSecDesc,
                  ulFinalSecDescLength);
#endif

    BAIL_ON_NT_STATUS(ntError);

    PvfsNotifyScheduleFullReport(
        pCcb->pFcb,
        FILE_NOTIFY_CHANGE_SECURITY,
        FILE_ACTION_MODIFIED,
        pCcb->pszFilename);


cleanup:
    if (pIncAbsSecDesc)
    {
        PvfsFreeAbsoluteSecurityDescriptor(&pIncAbsSecDesc);
    }

    return ntError;

error:
    goto cleanup;
}