Windows: Robocopy Symlinks
authorJeffrey Altman <jaltman@your-file-system.com>
Fri, 22 Mar 2013 20:10:54 +0000 (16:10 -0400)
committerJeffrey Altman <jaltman@your-file-system.com>
Sat, 23 Mar 2013 04:38:55 +0000 (21:38 -0700)
This patchset enables AFS Symlinks and DFSlinks to be copied to
a local NTFS disk using robocopy's /SL option.

Separate print names and substitute names are now provided permitting
the reparse data copied from AFS to be applied to a local disk object
for recreation.

Change-Id: I7bab4e8352a069a14b9ac4b3b2e22819f3de7a23
Reviewed-on: http://gerrit.openafs.org/9655
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>
Tested-by: Jeffrey Altman <jaltman@your-file-system.com>

src/WINNT/afsrdr/kernel/lib/AFSFSControl.cpp

index cd8a953..322b94b 100644 (file)
@@ -323,6 +323,7 @@ AFSProcessUserFsRequest( IN PIRP Irp)
                 ULONG ulRemainingLen = ulOutputBufferLen;
                 AFSReparseTagInfo *pReparseInfo = NULL;
                 BOOLEAN bRelative = FALSE;
+                BOOLEAN bDriveLetter = FALSE;
                 WCHAR * PathBuffer = NULL;
 
                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
@@ -448,56 +449,104 @@ AFSProcessUserFsRequest( IN PIRP Irp)
 
                         bRelative = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);
 
-                        if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length + (bRelative ? 0 : sizeof( WCHAR)))
+                        if ( bRelative)
                         {
 
-                            ntStatus = STATUS_BUFFER_TOO_SMALL;
+                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length)
+                            {
 
-                            Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
-                                pCcb->DirectoryCB->NameInformation.TargetName.Length + (bRelative ? 0 : sizeof( WCHAR));
+                                ntStatus = STATUS_BUFFER_TOO_SMALL;
 
-                            break;
-                        }
+                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length;
+
+                                break;
+                            }
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = (bRelative ? SYMLINK_FLAG_RELATIVE : 0);
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
 
-                        PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+                            RtlCopyMemory( PathBuffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);
 
-                        if ( bRelative == FALSE)
+                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                        }
+                        else
                         {
 
+                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                /* Display Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
+                                /* Substitute Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR))
+                            {
+
+                                ntStatus = STATUS_BUFFER_TOO_SMALL;
+
+                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);
+
+                                break;
+                            }
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR);
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+
+                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+
+                            /* Display Name */
                             *PathBuffer++ = L'\\';
 
                             RtlCopyMemory( PathBuffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
 
-                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength += sizeof( WCHAR);
+                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);
 
-                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength += sizeof( WCHAR);
-                        }
-                        else
-                        {
+                            /* Substitute Name */
+                            *PathBuffer++ = L'\\';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'\\';
+                            *PathBuffer++ = L'U';
+                            *PathBuffer++ = L'N';
+                            *PathBuffer++ = L'C';
 
                             RtlCopyMemory( PathBuffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
-                        }
 
-                        pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer)
-                            - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)
-                            + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                        }
 
                         break;
                     }
@@ -568,58 +617,164 @@ AFSProcessUserFsRequest( IN PIRP Irp)
                             break;
                         }
 
-                        if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length +
-                            (pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\' ? sizeof( WCHAR) : 0))
+                        bRelative = ( pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\');
+
+                        bDriveLetter = (bRelative == FALSE && pCcb->DirectoryCB->NameInformation.TargetName.Buffer[1] == L':');
+
+                        if ( bRelative)
                         {
 
-                            ntStatus = STATUS_BUFFER_TOO_SMALL;
+                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length)
+                            {
 
-                            Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
-                                pCcb->DirectoryCB->NameInformation.TargetName.Length +
-                                (pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\' ? sizeof( WCHAR) : 0);
+                                ntStatus = STATUS_BUFFER_TOO_SMALL;
 
-                            break;
-                        }
+                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;
+                                break;
+                            }
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
-                            pCcb->DirectoryCB->NameInformation.TargetName.Length;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
-                        pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
 
-                        PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+
+                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+
+                            RtlCopyMemory( PathBuffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);
 
-                        if ( pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\')
+                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                        }
+                        else if ( bDriveLetter)
                         {
 
-                            *PathBuffer++ = L'\\';
+                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                /* Display Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length +
+                                /* Substitute Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR))
+                            {
+
+                                ntStatus = STATUS_BUFFER_TOO_SMALL;
+
+                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR);
+
+                                break;
+                            }
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR);
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length;
 
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+
+                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+
+                            /* Display Name */
                             RtlCopyMemory( PathBuffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
 
-                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength += sizeof( WCHAR);
+                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);
+
+                            /* Substitute Name */
+                            *PathBuffer++ = L'\\';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'\\';
+
+                            RtlCopyMemory( PathBuffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);
 
-                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength += sizeof( WCHAR);
+                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                         }
                         else
                         {
 
+                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                /* Display Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
+                                /* Substitute Name */
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR))
+                            {
+
+                                ntStatus = STATUS_BUFFER_TOO_SMALL;
+
+                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
+                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);
+
+                                break;
+                            }
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
+                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR);
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;
+
+                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+
+                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;
+
+                            /* Display Name */
+                            *PathBuffer++ = L'\\';
+
                             RtlCopyMemory( PathBuffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                            pCcb->DirectoryCB->NameInformation.TargetName.Length);
-                        }
 
-                        pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer)
-                            - FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)
-                            + pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);
+
+                            /* Substitute Name */
+                            *PathBuffer++ = L'\\';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'?';
+                            *PathBuffer++ = L'\\';
+                            *PathBuffer++ = L'U';
+                            *PathBuffer++ = L'N';
+                            *PathBuffer++ = L'C';
+
+                            RtlCopyMemory( PathBuffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
+                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);
+
+                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+                        }
 
                         break;
                     }