mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
sys,dll: reparse point implementation: DeleteReparsePoint
This commit is contained in:
parent
b88b2ec51d
commit
80e07cead6
@ -182,7 +182,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@ -207,7 +207,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
@ -235,7 +235,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -263,7 +263,7 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
|
|||||||
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
|
||||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||||
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>..\..\src\dll\library.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);credui.lib;version.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);rpcrt4.lib;credui.lib;version.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -766,12 +766,41 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
PVOID FileNode,
|
PVOID FileNode,
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
|
/**
|
||||||
|
* Delete reparse point.
|
||||||
|
*
|
||||||
|
* The behavior of this function depends on the value of FSP_FSCTL_VOLUME_PARAMS ::
|
||||||
|
* ReparsePointsSymlinkOnly. If the value of ReparsePointsSymlinkOnly
|
||||||
|
* is FALSE the file system supports full reparse points and this function is expected
|
||||||
|
* to delete the reparse point contained in the buffer. If the value of
|
||||||
|
* ReparsePointsSymlinkOnly is TRUE the file system supports symbolic links only
|
||||||
|
* as reparse points and the Buffer and Size arguments will be NULL.
|
||||||
|
*
|
||||||
|
* @param FileSystem
|
||||||
|
* The file system on which this request is posted.
|
||||||
|
* @param Request
|
||||||
|
* The request posted by the kernel mode FSD.
|
||||||
|
* @param FileNode
|
||||||
|
* The file node of the reparse point.
|
||||||
|
* @param FileName
|
||||||
|
* The file name of the reparse point.
|
||||||
|
* @param Buffer
|
||||||
|
* Pointer to a buffer that contains the data for this operation.
|
||||||
|
* @param Size
|
||||||
|
* Size of data to write.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
*/
|
||||||
|
NTSTATUS (*DeleteReparsePoint)(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This ensures that this interface will always contain 64 function pointers.
|
* This ensures that this interface will always contain 64 function pointers.
|
||||||
* Please update when changing the interface as it is important for future compatibility.
|
* Please update when changing the interface as it is important for future compatibility.
|
||||||
*/
|
*/
|
||||||
NTSTATUS (*Reserved[42])();
|
NTSTATUS (*Reserved[41])();
|
||||||
} FSP_FILE_SYSTEM_INTERFACE;
|
} FSP_FILE_SYSTEM_INTERFACE;
|
||||||
#if defined(WINFSP_DLL_INTERNAL)
|
#if defined(WINFSP_DLL_INTERNAL)
|
||||||
/*
|
/*
|
||||||
@ -1126,6 +1155,29 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PVOID Context,
|
PVOID Context,
|
||||||
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN OpenReparsePoint,
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN OpenReparsePoint,
|
||||||
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize);
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize);
|
||||||
|
/**
|
||||||
|
* Test whether reparse data can be replaced.
|
||||||
|
*
|
||||||
|
* This is a helper for implementing the SetReparsePoint/DeleteReparsePoint operation
|
||||||
|
* in file systems that support reparse points.
|
||||||
|
*
|
||||||
|
* @param CurrentReparseData
|
||||||
|
* Pointer to the current reparse data.
|
||||||
|
* @param CurrentReparseDataSize
|
||||||
|
* Pointer to the current reparse data size.
|
||||||
|
* @param ReplaceReparseData
|
||||||
|
* Pointer to the replacement reparse data.
|
||||||
|
* @param ReplaceReparseDataSize
|
||||||
|
* Pointer to the replacement reparse data size.
|
||||||
|
* @return
|
||||||
|
* STATUS_SUCCESS or error code.
|
||||||
|
* @see
|
||||||
|
* SetReparsePoint
|
||||||
|
* DeleteReparsePoint
|
||||||
|
*/
|
||||||
|
FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
||||||
|
PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize,
|
||||||
|
PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Security
|
* Security
|
||||||
|
102
src/dll/fsop.c
102
src/dll/fsop.c
@ -954,12 +954,15 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
if (FileSystem->ReparsePointsSymlinkOnly)
|
if (FileSystem->ReparsePointsSymlinkOnly)
|
||||||
{
|
{
|
||||||
|
if (IO_REPARSE_TAG_SYMLINK == *(PULONG)SetReparseData)
|
||||||
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
||||||
(PVOID)Request->Req.FileSystemControl.UserContext,
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
SetReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
SetReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
SetReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
SetReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||||
SetReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
SetReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||||
|
else
|
||||||
|
Result = STATUS_IO_REPARSE_TAG_MISMATCH;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
||||||
@ -970,58 +973,27 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FSCTL_DELETE_REPARSE_POINT:
|
case FSCTL_DELETE_REPARSE_POINT:
|
||||||
if (0 != FileSystem->Interface->GetReparsePoint &&
|
if (0 != FileSystem->Interface->DeleteReparsePoint)
|
||||||
0 != FileSystem->Interface->SetReparsePoint)
|
|
||||||
{
|
|
||||||
GetReparseData = (PREPARSE_DATA_BUFFER)Response->Buffer;
|
|
||||||
memset(GetReparseData, 0, sizeof *GetReparseData);
|
|
||||||
|
|
||||||
if (FileSystem->ReparsePointsSymlinkOnly)
|
|
||||||
{
|
|
||||||
GetReparseData->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
|
||||||
Result = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer);
|
|
||||||
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
|
||||||
(PVOID)Request->Req.FileSystemControl.UserContext,
|
|
||||||
(PWSTR)Request->Buffer, GetReparseData, &Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
|
||||||
{
|
{
|
||||||
SetReparseData = (PREPARSE_DATA_BUFFER)
|
SetReparseData = (PREPARSE_DATA_BUFFER)
|
||||||
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset);
|
||||||
|
|
||||||
if (GetReparseData->ReparseTag != SetReparseData->ReparseTag)
|
if (FileSystem->ReparsePointsSymlinkOnly)
|
||||||
Result = STATUS_IO_REPARSE_TAG_MISMATCH;
|
{
|
||||||
else if (!IsReparseTagMicrosoft(SetReparseData->ReparseTag) && (
|
if (IO_REPARSE_TAG_SYMLINK == *(PULONG)SetReparseData)
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data1 !=
|
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem, Request,
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data1 ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data2 !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data2 ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data3 !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data3 ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[0] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[0] ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[1] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[1] ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[2] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[2] ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[3] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[3] ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[4] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[4] ||
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)GetReparseData)->ReparseGuid.Data4[5] !=
|
|
||||||
((PREPARSE_GUID_DATA_BUFFER)SetReparseData)->ReparseGuid.Data4[5]))
|
|
||||||
Result = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
|
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
|
||||||
Result = FileSystem->Interface->SetReparsePoint(FileSystem, Request,
|
|
||||||
(PVOID)Request->Req.FileSystemControl.UserContext,
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
(PWSTR)Request->Buffer, 0, 0);
|
(PWSTR)Request->Buffer,
|
||||||
|
0, 0);
|
||||||
|
else
|
||||||
|
Result = STATUS_IO_REPARSE_TAG_MISMATCH;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Result = FileSystem->Interface->DeleteReparsePoint(FileSystem, Request,
|
||||||
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
|
(PWSTR)Request->Buffer,
|
||||||
|
SetReparseData,
|
||||||
|
Request->Req.FileSystemControl.Buffer.Size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1231,8 +1203,7 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
continue;
|
continue;
|
||||||
else if (!NT_SUCCESS(Result))
|
else if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
if ((STATUS_OBJECT_NAME_NOT_FOUND == Result && '\0' != c) ||
|
if (STATUS_OBJECT_NAME_NOT_FOUND != Result || '\0' != c)
|
||||||
STATUS_NOT_A_DIRECTORY == Result)
|
|
||||||
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
Result = STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -1301,3 +1272,38 @@ no_symlink_exit:
|
|||||||
PIoStatus->Information = ReparseData->ReparseTag;
|
PIoStatus->Information = ReparseData->ReparseTag;
|
||||||
return STATUS_REPARSE;
|
return STATUS_REPARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint(
|
||||||
|
PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize,
|
||||||
|
PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize)
|
||||||
|
{
|
||||||
|
if (sizeof(ULONG) > CurrentReparseDataSize ||
|
||||||
|
sizeof(ULONG) > ReplaceReparseDataSize)
|
||||||
|
return STATUS_IO_REPARSE_DATA_INVALID; /* should not happen! */
|
||||||
|
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 ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data1 !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data1 ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data2 !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data2 ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data3 !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data3 ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[0] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[0] ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[1] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[1] ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[2] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[2] ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[3] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[3] ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[4] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[4] ||
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)CurrentReparseData)->ReparseGuid.Data4[5] !=
|
||||||
|
((PREPARSE_GUID_DATA_BUFFER)ReplaceReparseData)->ReparseGuid.Data4[5]))
|
||||||
|
return STATUS_REPARSE_ATTRIBUTE_CONFLICT;
|
||||||
|
else
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
@ -183,6 +183,86 @@ NTSTATUS fsp_fuse_op_leave(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_NewHiddenName(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
char *PosixPath, char **PPosixHiddenPath)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
NTSTATUS Result;
|
||||||
|
char *PosixHiddenPath = 0;
|
||||||
|
char *p, *lastp;
|
||||||
|
size_t Size;
|
||||||
|
RPC_STATUS RpcStatus;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct { UINT32 V[4]; } Values;
|
||||||
|
UUID Uuid;
|
||||||
|
} UuidBuf;
|
||||||
|
struct fuse_stat stbuf;
|
||||||
|
int err, maxtries = 3;
|
||||||
|
|
||||||
|
*PPosixHiddenPath = 0;
|
||||||
|
|
||||||
|
p = PosixPath;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while ('/' == *p)
|
||||||
|
p++;
|
||||||
|
lastp = p;
|
||||||
|
while ('/' != *p)
|
||||||
|
{
|
||||||
|
if ('\0' == *p)
|
||||||
|
goto loopend;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loopend:;
|
||||||
|
|
||||||
|
Size = lastp - PosixPath + sizeof ".fuse_hidden0123456789abcdef";
|
||||||
|
PosixHiddenPath = MemAlloc(Size);
|
||||||
|
if (0 == PosixHiddenPath)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
memcpy(PosixHiddenPath, PosixPath, lastp - PosixPath);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
RpcStatus = UuidCreate(&UuidBuf.Uuid);
|
||||||
|
if (S_OK != RpcStatus && RPC_S_UUID_LOCAL_ONLY != RpcStatus)
|
||||||
|
{
|
||||||
|
Result = STATUS_INTERNAL_ERROR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
wsprintfA(PosixHiddenPath + (lastp - PosixPath),
|
||||||
|
".fuse_hidden%08lx%08lx",
|
||||||
|
UuidBuf.Values.V[0] ^ UuidBuf.Values.V[2],
|
||||||
|
UuidBuf.Values.V[1] ^ UuidBuf.Values.V[3]);
|
||||||
|
|
||||||
|
memset(&stbuf, 0, sizeof stbuf);
|
||||||
|
if (0 != f->ops.getattr)
|
||||||
|
err = f->ops.getattr(PosixPath, (void *)&stbuf);
|
||||||
|
else
|
||||||
|
err = -ENOSYS;
|
||||||
|
} while (0 == err && 0 < --maxtries);
|
||||||
|
|
||||||
|
if (0 == err)
|
||||||
|
{
|
||||||
|
Result = STATUS_DEVICE_BUSY; // current EBUSY mapping
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PPosixHiddenPath = PosixHiddenPath;
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
MemFree(PosixHiddenPath);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetFileInfoEx(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetFileInfoEx(FSP_FILE_SYSTEM *FileSystem,
|
||||||
const char *PosixPath, struct fuse_file_info *fi,
|
const char *PosixPath, struct fuse_file_info *fi,
|
||||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode,
|
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode,
|
||||||
@ -321,7 +401,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(
|
|||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
err = f->ops.readlink(PosixPath, PosixTargetPath, sizeof PosixTargetPath);
|
err = f->ops.readlink(PosixPath, PosixTargetPath, sizeof PosixTargetPath);
|
||||||
if (EINVAL/* same on MSVC and Cygwin */ == err)
|
if (-EINVAL/* same on MSVC and Cygwin */ == err)
|
||||||
{
|
{
|
||||||
Result = STATUS_NOT_A_REPARSE_POINT;
|
Result = STATUS_NOT_A_REPARSE_POINT;
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -1653,16 +1733,19 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
struct fsp_fuse_file_desc *filedesc =
|
struct fsp_fuse_file_desc *filedesc =
|
||||||
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
|
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
|
||||||
WCHAR TargetPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
WCHAR TargetPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
char *PosixTargetPath = 0;
|
char *PosixTargetPath = 0, *PosixHiddenPath = 0;
|
||||||
int err;
|
int err;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
if (0 == f->ops.symlink)
|
if (0 == f->ops.symlink || 0 == f->ops.rename || 0 == f->ops.unlink)
|
||||||
return STATUS_INVALID_DEVICE_REQUEST;
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
/* were we asked to delete the reparse point? no can do! */
|
/* FUSE cannot make a directory into a symlink */
|
||||||
if (0 == Buffer)
|
if (filedesc->IsDirectory)
|
||||||
return STATUS_ACCESS_DENIED;
|
{
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* is this an absolute path? */
|
/* is this an absolute path? */
|
||||||
if (Size > 4 * sizeof(WCHAR) &&
|
if (Size > 4 * sizeof(WCHAR) &&
|
||||||
@ -1691,22 +1774,64 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
err = f->ops.symlink(PosixTargetPath, filedesc->PosixPath);
|
/*
|
||||||
|
* How we implement this is probably one of the worst aspects of this FUSE implementation.
|
||||||
|
*
|
||||||
|
* In Windows a CreateSymbolicLink is the sequence of the following:
|
||||||
|
* Create
|
||||||
|
* DeviceIoControl(FSCTL_SET_REPARSE_POINT)
|
||||||
|
* Cleanup
|
||||||
|
* Close
|
||||||
|
*
|
||||||
|
* The Create call creates the new file and the DeviceIoControl(FSCTL_SET_REPARSE_POINT)
|
||||||
|
* call is supposed to convert it into a reparse point. However FUSE symlink() will fail
|
||||||
|
* with -EEXIST in this case.
|
||||||
|
*
|
||||||
|
* We must therefore find a solution using rename, which is unreliable and error-prone.
|
||||||
|
* Note that this will also result in a change of the inode number for the symlink!
|
||||||
|
*/
|
||||||
|
|
||||||
|
Result = fsp_fuse_intf_NewHiddenName(FileSystem, filedesc->PosixPath, &PosixHiddenPath);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
err = f->ops.symlink(PosixTargetPath, PosixHiddenPath);
|
||||||
if (0 != err)
|
if (0 != err)
|
||||||
{
|
{
|
||||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath);
|
||||||
|
if (0 != err)
|
||||||
|
{
|
||||||
|
/* on failure unlink "hidden" symlink */
|
||||||
|
f->ops.unlink(PosixHiddenPath);
|
||||||
|
|
||||||
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
MemFree(PosixHiddenPath);
|
||||||
|
|
||||||
if (0 != PosixTargetPath)
|
if (0 != PosixTargetPath)
|
||||||
FspPosixDeletePath(PosixTargetPath);
|
FspPosixDeletePath(PosixTargetPath);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
/* we were asked to delete the reparse point? no can do! */
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||||
{
|
{
|
||||||
fsp_fuse_intf_GetVolumeInfo,
|
fsp_fuse_intf_GetVolumeInfo,
|
||||||
@ -1731,4 +1856,5 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
|||||||
fsp_fuse_intf_ResolveReparsePoints,
|
fsp_fuse_intf_ResolveReparsePoints,
|
||||||
fsp_fuse_intf_GetReparsePoint,
|
fsp_fuse_intf_GetReparsePoint,
|
||||||
fsp_fuse_intf_SetReparsePoint,
|
fsp_fuse_intf_SetReparsePoint,
|
||||||
|
fsp_fuse_intf_DeleteReparsePoint,
|
||||||
};
|
};
|
||||||
|
@ -339,8 +339,6 @@ static NTSTATUS FspFsvolCreateNoLock(
|
|||||||
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
|
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
|
||||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
if (CreateOptions & FILE_DIRECTORY_FILE)
|
||||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
||||||
if (CreateOptions & FILE_OPEN_REPARSE_POINT)
|
|
||||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
||||||
|
@ -1007,25 +1007,66 @@ static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PVOID FileNode0,
|
PVOID FileNode0,
|
||||||
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
{
|
{
|
||||||
|
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
PVOID ReparseData;
|
PVOID ReparseData;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
if (0 == (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
if (MemfsFileNodeMapHasChild(Memfs->FileNodeMap, FileNode))
|
||||||
return STATUS_NOT_A_REPARSE_POINT;
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
||||||
|
|
||||||
|
if (0 != FileNode->ReparseData)
|
||||||
|
{
|
||||||
|
Result = FspFileSystemCanReplaceReparsePoint(
|
||||||
|
FileNode->ReparseData, FileNode->ReparseDataSize,
|
||||||
|
Buffer, Size);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
ReparseData = realloc(FileNode->ReparseData, Size);
|
ReparseData = realloc(FileNode->ReparseData, Size);
|
||||||
if (0 == ReparseData)
|
if (0 == ReparseData && 0 != Size)
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
FileNode->FileInfo.ReparseTag = *(PULONG)Buffer;
|
||||||
/* the first field in a reparse buffer is the reparse tag */
|
/* the first field in a reparse buffer is the reparse tag */
|
||||||
FileNode->FileInfo.ReparseTag = 0 != Buffer ? *(PULONG)Buffer : 0;
|
|
||||||
|
|
||||||
FileNode->ReparseDataSize = Size;
|
FileNode->ReparseDataSize = Size;
|
||||||
|
FileNode->ReparseData = ReparseData;
|
||||||
memcpy(FileNode->ReparseData, Buffer, Size);
|
memcpy(FileNode->ReparseData, Buffer, Size);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode0,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (0 != FileNode->ReparseData)
|
||||||
|
{
|
||||||
|
Result = FspFileSystemCanReplaceReparsePoint(
|
||||||
|
FileNode->ReparseData, FileNode->ReparseDataSize,
|
||||||
|
Buffer, Size);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return STATUS_NOT_A_REPARSE_POINT;
|
||||||
|
|
||||||
|
free(FileNode->ReparseData);
|
||||||
|
|
||||||
|
FileNode->FileInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
FileNode->FileInfo.ReparseTag = 0;
|
||||||
|
FileNode->ReparseDataSize = 0;
|
||||||
|
FileNode->ReparseData = 0;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||||
{
|
{
|
||||||
GetVolumeInfo,
|
GetVolumeInfo,
|
||||||
@ -1050,6 +1091,7 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
|||||||
ResolveReparsePoints,
|
ResolveReparsePoints,
|
||||||
GetReparsePoint,
|
GetReparsePoint,
|
||||||
SetReparsePoint,
|
SetReparsePoint,
|
||||||
|
DeleteReparsePoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
NTSTATUS MemfsCreate(
|
NTSTATUS MemfsCreate(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user