diff --git a/src/dll/fsop.c b/src/dll/fsop.c index 92997925..6b136375 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -1141,29 +1141,35 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, return Result; } - /* found a reparse point */ + /* + * Found a reparse point! + */ + /* if not a symlink return the full reparse point */ if (IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag) - /* not a symlink; return the full reparse point! */ goto reparse_data_exit; ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; - if (ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) - /* absolute symlink; return the full reparse point! */ + /* if an absolute (in the NT namespace) symlink return the full reparse point */ + if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) && + ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) goto reparse_data_exit; if (0 == --MaxTries) return STATUS_REPARSE_POINT_NOT_RESOLVED; - /* relative symlink; replace last path component seen */ - if (ReparseTargetPathLength + sizeof(WCHAR) > (TargetPathEnd - lastp) * sizeof(WCHAR)) + /* if device relative symlink replace whole path; else replace last path component */ + p = ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0] ? + TargetPath : lastp; + + if (ReparseTargetPathLength + sizeof(WCHAR) > (TargetPathEnd - p) * sizeof(WCHAR)) return STATUS_REPARSE_POINT_NOT_RESOLVED; - memcpy(lastp, ReparseTargetPath, ReparseTargetPathLength); - lastp[ReparseTargetPathLength / sizeof(WCHAR)] = L'\0'; - p = lastp; + + memcpy(p, ReparseTargetPath, ReparseTargetPathLength); + p[ReparseTargetPathLength / sizeof(WCHAR)] = L'\0'; } exit: @@ -1196,8 +1202,8 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint( else if (*(PULONG)CurrentReparseData != *(PULONG)ReplaceReparseData) return STATUS_IO_REPARSE_TAG_MISMATCH; else if (!IsReparseTagMicrosoft(*(PULONG)CurrentReparseData) && ( - REPARSE_GUID_DATA_BUFFER_HEADER_SIZE > CurrentReparseDataSize || - REPARSE_GUID_DATA_BUFFER_HEADER_SIZE > ReplaceReparseDataSize || + (SIZE_T)REPARSE_GUID_DATA_BUFFER_HEADER_SIZE > CurrentReparseDataSize || + (SIZE_T)REPARSE_GUID_DATA_BUFFER_HEADER_SIZE > ReplaceReparseDataSize || *(PUINT32)&((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data1 != *(PUINT32)&((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data1 || *(PUINT32)&((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data2 != diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index cc865a09..f8e2cffb 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -2005,7 +2005,8 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem, ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; /* is this an absolute path? */ - if (ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) + if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) && + ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) { /* we do not support absolute paths that point outside this file system */ if (0 == Request->Req.FileSystemControl.TargetOnFileSystem) diff --git a/src/sys/create.c b/src/sys/create.c index 269f115f..eec9a04b 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -516,9 +516,8 @@ NTSTATUS FspFsvolCreateComplete( * path. Prefix it with our device name and send it to the IO Manager. * * IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full - * symbolic link reparse buffer. In this case send the target path to the IO Manager - * without prefixing it with our device name as it is expected to be absolute in the - * NT namespace. + * symbolic link reparse buffer. In this case send the target path to the IO Manager, + * and prefix it with our device name depending on SYMLINK_FLAG_RELATIVE. */ if (IO_REPARSE == Response->IoStatus.Information) @@ -550,7 +549,11 @@ NTSTATUS FspFsvolCreateComplete( if (!NT_SUCCESS(Result)) FSP_RETURN(); - RtlZeroMemory(&ReparseTargetPrefix, sizeof ReparseTargetPrefix); + if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE)) + RtlZeroMemory(&ReparseTargetPrefix, sizeof ReparseTargetPrefix); + else + RtlCopyMemory(&ReparseTargetPrefix, &FsvolDeviceExtension->VolumeName, + sizeof ReparseTargetPrefix); ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index a13a30b2..aa35dbfa 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -145,7 +145,8 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint( ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength; /* is this an absolute path? determine if target resides on same device as link */ - if (ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) + if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) && + ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0]) { UNICODE_STRING TargetObjectName; PDEVICE_OBJECT TargetDeviceObject;