Windows: fix deadlock in symlink Attrib retrieval
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSFileInfo.cpp
index c08a020..390ad80 100644 (file)
@@ -745,6 +745,13 @@ AFSQueryBasicInfo( IN PIRP Irp,
 {
     NTSTATUS ntStatus = STATUS_SUCCESS;
     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    ULONG ulFileAttribs = 0;
+    AFSFcb *pFcb = NULL;
+    AFSCcb *pCcb = NULL;
+    IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
+    AFSFileInfoCB stFileInfo;
+    AFSDirectoryCB *pParentDirectoryCB = NULL;
+    UNICODE_STRING uniParentPath;
 
     if( *Length >= sizeof( FILE_BASIC_INFORMATION))
     {
@@ -752,24 +759,59 @@ AFSQueryBasicInfo( IN PIRP Irp,
         RtlZeroMemory( Buffer,
                        *Length);
 
+        ulFileAttribs = DirectoryCB->ObjectInformation->FileAttributes;
+
+        pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
+        pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
+
+        if( DirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_SYMLINK)
+        {
+
+            pParentDirectoryCB = AFSGetParentEntry( pCcb->NameArray);
+
+            AFSRetrieveParentPath( &pCcb->FullFileName,
+                                   &uniParentPath);
+
+            RtlZeroMemory( &stFileInfo,
+                           sizeof( AFSFileInfoCB));
+
+            //
+            // Can't hold the Fcb while evaluating the path, leads to lock inversion
+            //
+
+            AFSReleaseResource( &pFcb->NPFcb->Resource);
+
+            if( NT_SUCCESS( AFSRetrieveFileAttributes( pParentDirectoryCB,
+                                                       DirectoryCB,
+                                                       &uniParentPath,
+                                                       NULL,
+                                                       &stFileInfo)))
+            {
+                ulFileAttribs = stFileInfo.FileAttributes;
+
+                ulFileAttribs |= FILE_ATTRIBUTE_REPARSE_POINT;
+            }
+
+            AFSAcquireShared( &pFcb->NPFcb->Resource,
+                              TRUE);
+        }
+
         Buffer->CreationTime = DirectoryCB->ObjectInformation->CreationTime;
         Buffer->LastAccessTime = DirectoryCB->ObjectInformation->LastAccessTime;
         Buffer->LastWriteTime = DirectoryCB->ObjectInformation->LastWriteTime;
         Buffer->ChangeTime = DirectoryCB->ObjectInformation->ChangeTime;
-        Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes;
+        Buffer->FileAttributes = ulFileAttribs;
 
         if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' &&
-                 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
+            BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
         {
 
             if ( Buffer->FileAttributes != FILE_ATTRIBUTE_NORMAL)
             {
-
                 Buffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
             }
             else
             {
-
                 Buffer->FileAttributes = FILE_ATTRIBUTE_HIDDEN;
             }
         }
@@ -793,13 +835,18 @@ AFSQueryStandardInfo( IN PIRP Irp,
 {
 
     NTSTATUS ntStatus = STATUS_SUCCESS;
-    AFSFileInfoCB stFileInformation;
+    AFSFcb *pFcb = NULL;
     AFSCcb *pCcb = NULL;
     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
+    AFSFileInfoCB stFileInfo;
+    AFSDirectoryCB *pParentDirectoryCB = NULL;
+    UNICODE_STRING uniParentPath;
+    ULONG ulFileAttribs = 0;
 
     if( *Length >= sizeof( FILE_STANDARD_INFORMATION))
     {
 
+        pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
 
         RtlZeroMemory( Buffer,
@@ -808,14 +855,43 @@ AFSQueryStandardInfo( IN PIRP Irp,
         Buffer->NumberOfLinks = 1;
         Buffer->DeletePending = BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
 
-        RtlZeroMemory( &stFileInformation,
-                       sizeof( AFSFileInfoCB));
-
         Buffer->AllocationSize.QuadPart = (ULONGLONG)((DirectoryCB->ObjectInformation->AllocationSize.QuadPart/PAGE_SIZE) + 1) * PAGE_SIZE;
 
         Buffer->EndOfFile = DirectoryCB->ObjectInformation->EndOfFile;
 
-        Buffer->Directory = BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
+        ulFileAttribs = DirectoryCB->ObjectInformation->FileAttributes;
+
+        if( DirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_SYMLINK)
+        {
+
+            pParentDirectoryCB = AFSGetParentEntry( pCcb->NameArray);
+
+            AFSRetrieveParentPath( &pCcb->FullFileName,
+                                   &uniParentPath);
+
+            RtlZeroMemory( &stFileInfo,
+                           sizeof( AFSFileInfoCB));
+
+            //
+            // Can't hold the Fcb while evaluating the path, leads to lock inversion
+            //
+
+            AFSReleaseResource( &pFcb->NPFcb->Resource);
+
+            if( NT_SUCCESS( AFSRetrieveFileAttributes( pParentDirectoryCB,
+                                                       DirectoryCB,
+                                                       &uniParentPath,
+                                                       NULL,
+                                                       &stFileInfo)))
+            {
+                ulFileAttribs = stFileInfo.FileAttributes;
+            }
+
+            AFSAcquireShared( &pFcb->NPFcb->Resource,
+                              TRUE);
+        }
+
+        Buffer->Directory = BooleanFlagOn( ulFileAttribs, FILE_ATTRIBUTE_DIRECTORY);
 
         *Length -= sizeof( FILE_STANDARD_INFORMATION);
     }
@@ -1240,6 +1316,13 @@ AFSQueryNetworkInfo( IN PIRP Irp,
 
     NTSTATUS ntStatus = STATUS_SUCCESS;
     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    AFSFcb *pFcb = NULL;
+    AFSCcb *pCcb = NULL;
+    PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
+    AFSFileInfoCB stFileInfo;
+    AFSDirectoryCB *pParentDirectoryCB = NULL;
+    UNICODE_STRING uniParentPath;
+    ULONG ulFileAttribs = 0;
 
     RtlZeroMemory( Buffer,
                    *Length);
@@ -1247,6 +1330,43 @@ AFSQueryNetworkInfo( IN PIRP Irp,
     if( *Length >= sizeof( FILE_NETWORK_OPEN_INFORMATION))
     {
 
+        ulFileAttribs = DirectoryCB->ObjectInformation->FileAttributes;
+
+        pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
+        pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
+
+        if( DirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_SYMLINK)
+        {
+
+            pParentDirectoryCB = AFSGetParentEntry( pCcb->NameArray);
+
+            AFSRetrieveParentPath( &pCcb->FullFileName,
+                                   &uniParentPath);
+
+            RtlZeroMemory( &stFileInfo,
+                           sizeof( AFSFileInfoCB));
+
+            //
+            // Can't hold the Fcb while evaluating the path, leads to lock inversion
+            //
+
+            AFSReleaseResource( &pFcb->NPFcb->Resource);
+
+            if( NT_SUCCESS( AFSRetrieveFileAttributes( pParentDirectoryCB,
+                                                       DirectoryCB,
+                                                       &uniParentPath,
+                                                       NULL,
+                                                       &stFileInfo)))
+            {
+                ulFileAttribs = stFileInfo.FileAttributes;
+
+                ulFileAttribs |= FILE_ATTRIBUTE_REPARSE_POINT;
+            }
+
+            AFSAcquireShared( &pFcb->NPFcb->Resource,
+                              TRUE);
+        }
+
         Buffer->CreationTime.QuadPart = DirectoryCB->ObjectInformation->CreationTime.QuadPart;
         Buffer->LastAccessTime.QuadPart = DirectoryCB->ObjectInformation->LastAccessTime.QuadPart;
         Buffer->LastWriteTime.QuadPart = DirectoryCB->ObjectInformation->LastWriteTime.QuadPart;
@@ -1255,7 +1375,7 @@ AFSQueryNetworkInfo( IN PIRP Irp,
         Buffer->AllocationSize.QuadPart = DirectoryCB->ObjectInformation->AllocationSize.QuadPart;
         Buffer->EndOfFile.QuadPart = DirectoryCB->ObjectInformation->EndOfFile.QuadPart;
 
-        Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes;
+        Buffer->FileAttributes = ulFileAttribs;
 
         if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' &&
             BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
@@ -1364,6 +1484,13 @@ AFSQueryAttribTagInfo( IN PIRP Irp,
     NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL;
     ULONG ulCopyLength = 0;
     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
+    AFSFcb *pFcb = NULL;
+    AFSCcb *pCcb = NULL;
+    PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
+    AFSFileInfoCB stFileInfo;
+    AFSDirectoryCB *pParentDirectoryCB = NULL;
+    UNICODE_STRING uniParentPath;
+    ULONG ulFileAttribs = 0;
 
     if( *Length >= sizeof( FILE_ATTRIBUTE_TAG_INFORMATION))
     {
@@ -1371,7 +1498,44 @@ AFSQueryAttribTagInfo( IN PIRP Irp,
         RtlZeroMemory( Buffer,
                        *Length);
 
-        Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes;
+        ulFileAttribs = DirectoryCB->ObjectInformation->FileAttributes;
+
+        pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
+        pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
+
+        if( DirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_SYMLINK)
+        {
+
+            pParentDirectoryCB = AFSGetParentEntry( pCcb->NameArray);
+
+            AFSRetrieveParentPath( &pCcb->FullFileName,
+                                   &uniParentPath);
+
+            RtlZeroMemory( &stFileInfo,
+                           sizeof( AFSFileInfoCB));
+
+            //
+            // Can't hold the Fcb while evaluating the path, leads to lock inversion
+            //
+
+            AFSReleaseResource( &pFcb->NPFcb->Resource);
+
+            if( NT_SUCCESS( AFSRetrieveFileAttributes( pParentDirectoryCB,
+                                                       DirectoryCB,
+                                                       &uniParentPath,
+                                                       NULL,
+                                                       &stFileInfo)))
+            {
+                ulFileAttribs = stFileInfo.FileAttributes;
+
+                ulFileAttribs |= FILE_ATTRIBUTE_REPARSE_POINT;
+            }
+
+            AFSAcquireShared( &pFcb->NPFcb->Resource,
+                              TRUE);
+        }
+
+        Buffer->FileAttributes = ulFileAttribs;
 
         if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' &&
             BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))