mirror of
https://github.com/winfsp/winfsp.git
synced 2025-06-08 04:52:10 -05:00
sys,dll: reparse point implementation: WIP
This commit is contained in:
parent
7337f3c6cd
commit
f7e0362350
@ -59,6 +59,8 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
|||||||
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (64 * sizeof(WCHAR))
|
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (64 * sizeof(WCHAR))
|
||||||
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
|
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX (FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
|
||||||
|
|
||||||
|
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX 2048
|
||||||
|
|
||||||
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
|
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */
|
||||||
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
|
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */
|
||||||
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN 16384
|
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN 16384
|
||||||
@ -295,6 +297,7 @@ typedef struct
|
|||||||
UINT64 UserContext2;
|
UINT64 UserContext2;
|
||||||
UINT32 FsControlCode;
|
UINT32 FsControlCode;
|
||||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||||
|
UINT32 TargetOnFileSystem:1;/* the target of the symbolic link is on this file system */
|
||||||
} FileSystemControl;
|
} FileSystemControl;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -910,7 +910,6 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
{
|
{
|
||||||
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer) -
|
Size = FSP_FSCTL_TRANSACT_RSP_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_RSP, Buffer) -
|
||||||
sizeof(*SymlinkReparseData);
|
sizeof(*SymlinkReparseData);
|
||||||
Size /= 2; /* need space for SubstituteName and PrintName */
|
|
||||||
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
Result = FileSystem->Interface->GetReparsePoint(FileSystem, Request,
|
||||||
(PVOID)Request->Req.FileSystemControl.UserContext,
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
@ -921,8 +920,8 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
Offset = 0;
|
Offset = 0;
|
||||||
if (Size > 4 * sizeof(WCHAR) &&
|
if (Size > 4 * sizeof(WCHAR) &&
|
||||||
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[0] &&
|
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[0] &&
|
||||||
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[1] &&
|
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[1] &&
|
||||||
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[2] &&
|
'?' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[2] &&
|
||||||
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[3])
|
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[3])
|
||||||
Offset = 4 * sizeof(WCHAR);
|
Offset = 4 * sizeof(WCHAR);
|
||||||
|
|
||||||
@ -930,23 +929,17 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
SymlinkReparseData->ReparseDataLength = (USHORT)(
|
SymlinkReparseData->ReparseDataLength = (USHORT)(
|
||||||
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
|
||||||
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer) +
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer) +
|
||||||
Size + Size - Offset);
|
Size);
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset =
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset =
|
||||||
0;
|
0;
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength =
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength =
|
||||||
(USHORT)Size;
|
(USHORT)Size;
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameOffset =
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameOffset =
|
||||||
(USHORT)Size;
|
(USHORT)Offset;
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameLength =
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PrintNameLength =
|
||||||
(USHORT)(Size - Offset);
|
(USHORT)(Size - Offset);
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.Flags =
|
SymlinkReparseData->SymbolicLinkReparseBuffer.Flags = 0 == Offset ?
|
||||||
Size > 1 * sizeof(WCHAR) &&
|
0 : SYMLINK_FLAG_RELATIVE;
|
||||||
'\\' == SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer[0] ?
|
|
||||||
0 : SYMLINK_FLAG_RELATIVE;
|
|
||||||
RtlMoveMemory(
|
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer + Size / sizeof(WCHAR),
|
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer + Offset / sizeof(WCHAR),
|
|
||||||
(DWORD)(Size - Offset));
|
|
||||||
|
|
||||||
Response->Rsp.FileSystemControl.Buffer.Size = (UINT16)Size;
|
Response->Rsp.FileSystemControl.Buffer.Size = (UINT16)Size;
|
||||||
}
|
}
|
||||||
@ -974,7 +967,7 @@ FSP_API NTSTATUS FspFileSystemOpFileSystemControl(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
(PVOID)Request->Req.FileSystemControl.UserContext,
|
(PVOID)Request->Req.FileSystemControl.UserContext,
|
||||||
(PWSTR)Request->Buffer,
|
(PWSTR)Request->Buffer,
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
SymlinkReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR),
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
|
||||||
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
SymlinkReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -37,10 +37,12 @@ struct fsp_fuse_core_opt_data
|
|||||||
set_umask, umask,
|
set_umask, umask,
|
||||||
set_uid, uid,
|
set_uid, uid,
|
||||||
set_gid, gid,
|
set_gid, gid,
|
||||||
set_attr_timeout, attr_timeout;
|
set_attr_timeout, attr_timeout,
|
||||||
|
rellinks;
|
||||||
int set_FileInfoTimeout;
|
int set_FileInfoTimeout;
|
||||||
int CaseInsensitiveSearch, ReparsePoints,
|
int CaseInsensitiveSearch,
|
||||||
NamedStreams, ReadOnlyVolume;
|
NamedStreams,
|
||||||
|
ReadOnlyVolume;
|
||||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,6 +80,9 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
|||||||
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("intr_signal=", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("modules=", FUSE_OPT_KEY_DISCARD),
|
||||||
|
|
||||||
|
FSP_FUSE_CORE_OPT("rellinks", rellinks, 1),
|
||||||
|
FSP_FUSE_CORE_OPT("norellinks", rellinks, 0),
|
||||||
|
|
||||||
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
FSP_FUSE_CORE_OPT("SectorSize=%hu", VolumeParams.SectorSize, 4096),
|
||||||
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
FSP_FUSE_CORE_OPT("SectorsPerAllocationUnit=%hu", VolumeParams.SectorsPerAllocationUnit, 1),
|
||||||
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
FSP_FUSE_CORE_OPT("MaxComponentLength=%hu", VolumeParams.MaxComponentLength, 0),
|
||||||
@ -89,11 +94,11 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
|||||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
|
||||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
||||||
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
|
||||||
FSP_FUSE_CORE_OPT("ReparsePoints", ReparsePoints, 1),
|
|
||||||
FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1),
|
FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1),
|
||||||
|
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
||||||
|
FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD),
|
||||||
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD),
|
||||||
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
|
|
||||||
FUSE_OPT_KEY("--UNC=", 'U'),
|
FUSE_OPT_KEY("--UNC=", 'U'),
|
||||||
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
FUSE_OPT_KEY("--VolumePrefix=", 'U'),
|
||||||
|
|
||||||
@ -449,7 +454,6 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
|||||||
" -o VolumeSerialNumber=N 32-bit wide\n"
|
" -o VolumeSerialNumber=N 32-bit wide\n"
|
||||||
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
|
||||||
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
|
||||||
" -o ReparsePoints file system supports reparse points\n"
|
|
||||||
//" -o NamedStreams file system supports named streams\n"
|
//" -o NamedStreams file system supports named streams\n"
|
||||||
//" -o ReadOnlyVolume file system is read only\n"
|
//" -o ReadOnlyVolume file system is read only\n"
|
||||||
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n");
|
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n");
|
||||||
@ -498,7 +502,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
|
||||||
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch;
|
||||||
opt_data.VolumeParams.PersistentAcls = TRUE;
|
opt_data.VolumeParams.PersistentAcls = TRUE;
|
||||||
opt_data.VolumeParams.ReparsePoints = !!opt_data.ReparsePoints;
|
opt_data.VolumeParams.ReparsePoints = FALSE; /* see FSP_FUSE_HAS_SYMLINKS use below */
|
||||||
|
opt_data.VolumeParams.ReparsePointsSymbolicLinks = TRUE;
|
||||||
|
opt_data.VolumeParams.ReparsePointsPrivilegeCheck = FALSE;
|
||||||
opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams;
|
opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams;
|
||||||
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume;
|
||||||
|
|
||||||
@ -510,6 +516,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
|
f->set_umask = opt_data.set_umask; f->umask = opt_data.umask;
|
||||||
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
|
f->set_uid = opt_data.set_uid; f->uid = opt_data.uid;
|
||||||
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
|
f->set_gid = opt_data.set_gid; f->gid = opt_data.gid;
|
||||||
|
f->rellinks = opt_data.rellinks;
|
||||||
memcpy(&f->ops, ops, opsize);
|
memcpy(&f->ops, ops, opsize);
|
||||||
f->data = data;
|
f->data = data;
|
||||||
f->DebugLog = opt_data.debug ? -1 : 0;
|
f->DebugLog = opt_data.debug ? -1 : 0;
|
||||||
@ -550,6 +557,8 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f->VolumeParams.ReparsePoints = FSP_FUSE_HAS_SYMLINKS(f);
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -17,6 +17,14 @@
|
|||||||
|
|
||||||
#include <dll/fuse/library.h>
|
#include <dll/fuse/library.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FSP_FUSE_REPARSE_OPTHACK
|
||||||
|
*
|
||||||
|
* Define this macro to enable the ResolveReparsePoints optimization hack.
|
||||||
|
* See fsp_fuse_intf_GetSecurityByName for details.
|
||||||
|
*/
|
||||||
|
#define FSP_FUSE_REPARSE_OPTHACK
|
||||||
|
|
||||||
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
NTSTATUS fsp_fuse_op_enter(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||||
{
|
{
|
||||||
@ -218,8 +226,25 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoEx(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
|
|
||||||
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
AllocationUnit = (UINT64)f->VolumeParams.SectorSize *
|
||||||
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
(UINT64)f->VolumeParams.SectorsPerAllocationUnit;
|
||||||
FileInfo->FileAttributes = (stbuf.st_mode & 0040000) ? FILE_ATTRIBUTE_DIRECTORY : 0;
|
switch (stbuf.st_mode & 0170000)
|
||||||
FileInfo->ReparseTag = 0;
|
{
|
||||||
|
case 0040000:
|
||||||
|
FileInfo->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
FileInfo->ReparseTag = 0;
|
||||||
|
break;
|
||||||
|
case 0120000:
|
||||||
|
if (FSP_FUSE_HAS_SYMLINKS(f))
|
||||||
|
{
|
||||||
|
FileInfo->FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
FileInfo->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
FileInfo->FileAttributes = 0;
|
||||||
|
FileInfo->ReparseTag = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
FileInfo->FileSize = stbuf.st_size;
|
FileInfo->FileSize = stbuf.st_size;
|
||||||
FileInfo->AllocationSize =
|
FileInfo->AllocationSize =
|
||||||
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
(FileInfo->FileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit;
|
||||||
@ -289,6 +314,44 @@ exit:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *fsp_fuse_intf_GetSymlinkPointer(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
char *PosixPath)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
char *p, *lastp;
|
||||||
|
struct fuse_stat stbuf;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (0 == f->ops.getattr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = PosixPath;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while ('/' == *p)
|
||||||
|
p++;
|
||||||
|
lastp = p;
|
||||||
|
while ('/' != *p)
|
||||||
|
{
|
||||||
|
if ('\0' == *p)
|
||||||
|
return 0;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
memset(&stbuf, 0, sizeof stbuf);
|
||||||
|
err = f->ops.getattr(PosixPath, (void *)&stbuf);
|
||||||
|
*p = '/';
|
||||||
|
|
||||||
|
if (0 != err)
|
||||||
|
return 0;
|
||||||
|
else if (0120000 == (stbuf.st_mode & 0170000))
|
||||||
|
return lastp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request,
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||||
@ -330,7 +393,7 @@ static NTSTATUS fsp_fuse_intf_GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
|
PSECURITY_DESCRIPTOR SecurityDescriptorBuf, SIZE_T *PSecurityDescriptorSize)
|
||||||
{
|
{
|
||||||
struct fuse *f = FileSystem->UserContext;
|
struct fuse *f = FileSystem->UserContext;
|
||||||
char *PosixPath = 0;
|
char *PosixPath = 0, *PosixSymlinkPointer;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
Result = FspPosixMapWindowsToPosixPath(FileName, &PosixPath);
|
Result = FspPosixMapWindowsToPosixPath(FileName, &PosixPath);
|
||||||
@ -342,7 +405,31 @@ static NTSTATUS fsp_fuse_intf_GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
Result = STATUS_SUCCESS;
|
if (FSP_FUSE_HAS_SYMLINKS(f) &&
|
||||||
|
0 != (PosixSymlinkPointer = fsp_fuse_intf_GetSymlinkPointer(FileSystem, PosixPath)))
|
||||||
|
{
|
||||||
|
#if defined(FSP_FUSE_REPARSE_OPTHACK)
|
||||||
|
/* OPTHACK: This is a rather gross hack for optimization purposes only.
|
||||||
|
*
|
||||||
|
* If the FileName in this GetSecurityByName call and the PosixPath we computed
|
||||||
|
* matches the one in the FSD request, then remember where the first symlink is
|
||||||
|
* for use in ResolveReparsePoints later on. This avoids going through every path
|
||||||
|
* component twice (doing both a getattr and readlink).
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct fuse_context *context = fsp_fuse_get_context(f->env);
|
||||||
|
struct fsp_fuse_context_header *contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
||||||
|
|
||||||
|
if (FspFsctlTransactCreateKind == contexthdr->Request->Kind &&
|
||||||
|
(PUINT8)FileName == contexthdr->Request->Buffer &&
|
||||||
|
0 == lstrcmpA(PosixPath, contexthdr->PosixPath))
|
||||||
|
contexthdr->SymlinkIndex = PosixSymlinkPointer - PosixPath;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (0 != PosixPath)
|
if (0 != PosixPath)
|
||||||
@ -1422,6 +1509,337 @@ exit:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
PWSTR FileName, BOOLEAN OpenReparsePoint,
|
||||||
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
struct fuse_context *context = fsp_fuse_get_context(f->env);
|
||||||
|
struct fsp_fuse_context_header *contexthdr = FSP_FUSE_HDR_FROM_CONTEXT(context);
|
||||||
|
char c, *p, *lastp;
|
||||||
|
char PosixTargetPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
|
char PosixTargetLink[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
|
PWSTR TargetPath = 0;
|
||||||
|
ULONG Length, MaxTries = 32;
|
||||||
|
int err;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (0 == f->ops.readlink)
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
Length = lstrlenA(contexthdr->PosixPath);
|
||||||
|
if (Length > sizeof PosixTargetPath - 1)
|
||||||
|
return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
memcpy(PosixTargetPath, contexthdr->PosixPath, Length + 1);
|
||||||
|
|
||||||
|
p = PosixTargetPath +
|
||||||
|
contexthdr->SymlinkIndex; /* NOTE: if FSP_FUSE_REPARSE_OPTHACK is undefined, this will be 0 */
|
||||||
|
c = *p;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while ('/' == *p)
|
||||||
|
p++;
|
||||||
|
lastp = p;
|
||||||
|
while ('/' != *p)
|
||||||
|
{
|
||||||
|
if ('\0' == *p)
|
||||||
|
{
|
||||||
|
if (!OpenReparsePoint)
|
||||||
|
goto end;
|
||||||
|
OpenReparsePoint = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle dot and dotdot! */
|
||||||
|
if ('.' == lastp[0])
|
||||||
|
{
|
||||||
|
if (p == lastp + 1)
|
||||||
|
/* dot */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ('.' == lastp[1] && p == lastp + 1)
|
||||||
|
{
|
||||||
|
/* dotdot */
|
||||||
|
p = lastp;
|
||||||
|
while (PosixTargetPath < p)
|
||||||
|
{
|
||||||
|
p--;
|
||||||
|
if ('/' != *p)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (PosixTargetPath < p)
|
||||||
|
{
|
||||||
|
p--;
|
||||||
|
if ('/' == *p)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c = *p;
|
||||||
|
*p = '\0';
|
||||||
|
err = f->ops.readlink(contexthdr->PosixPath, PosixTargetLink, sizeof PosixTargetLink);
|
||||||
|
*p = c;
|
||||||
|
|
||||||
|
if (EINVAL/* same on MSVC and Cygwin */ == err)
|
||||||
|
/* it was not a symlink; continue */
|
||||||
|
continue;
|
||||||
|
else if (0 != err)
|
||||||
|
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
|
|
||||||
|
/* found a symlink */
|
||||||
|
if (0 == --MaxTries)
|
||||||
|
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||||
|
Length = lstrlenA(PosixTargetLink);
|
||||||
|
if ('/' == PosixTargetLink[0])
|
||||||
|
{
|
||||||
|
/* we do not support absolute paths without the rellinks option */
|
||||||
|
if (!f->rellinks)
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* absolute symlink; replace whole path */
|
||||||
|
memcpy(PosixTargetPath, PosixTargetLink, Length + 1);
|
||||||
|
p = PosixTargetPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* relative symlink; replace last path component seen */
|
||||||
|
if (Length + 1 > (p + sizeof PosixTargetPath) - lastp)
|
||||||
|
return STATUS_OBJECT_NAME_INVALID;
|
||||||
|
memcpy(lastp, PosixTargetLink, Length + 1);
|
||||||
|
p = lastp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
Result = FspPosixMapPosixToWindowsPath(PosixTargetPath, &TargetPath);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
Length = lstrlenW(TargetPath);
|
||||||
|
if (Length > *PSize)
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
*PSize = Length;
|
||||||
|
memcpy(Buffer, TargetPath, Length * sizeof(WCHAR));
|
||||||
|
|
||||||
|
PIoStatus->Status = STATUS_REPARSE;
|
||||||
|
PIoStatus->Information = 0/*IO_REPARSE*/;
|
||||||
|
Result = STATUS_REPARSE;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != TargetPath)
|
||||||
|
FspPosixDeletePath(TargetPath);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, PSIZE_T PSize)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
struct fsp_fuse_file_desc *filedesc =
|
||||||
|
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
|
||||||
|
char PosixTargetPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
|
PWSTR TargetPath = 0;
|
||||||
|
ULONG Length;
|
||||||
|
int err;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (0 == f->ops.readlink)
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
err = f->ops.readlink(filedesc->PosixPath, PosixTargetPath, sizeof PosixTargetPath);
|
||||||
|
if (0 != err)
|
||||||
|
{
|
||||||
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is this an absolute path? */
|
||||||
|
if ('/' == PosixTargetPath[0])
|
||||||
|
{
|
||||||
|
/* we do not support absolute paths without the rellinks option */
|
||||||
|
if (!f->rellinks)
|
||||||
|
{
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transform absolute path to relative.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *p, *t, *pstem, *tstem;
|
||||||
|
unsigned index, count;
|
||||||
|
|
||||||
|
p = pstem = filedesc->PosixPath;
|
||||||
|
t = tstem = PosixTargetPath;
|
||||||
|
|
||||||
|
/* skip common prefix */
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while ('/' == *p)
|
||||||
|
p++;
|
||||||
|
while ('/' == *t)
|
||||||
|
t++;
|
||||||
|
pstem = p, tstem = t;
|
||||||
|
while ('/' != *p)
|
||||||
|
{
|
||||||
|
if (*p != *t)
|
||||||
|
goto common_prefix_end;
|
||||||
|
else if ('\0' == *p)
|
||||||
|
{
|
||||||
|
while ('/' == *t)
|
||||||
|
t++;
|
||||||
|
pstem = p, tstem = t;
|
||||||
|
goto common_prefix_end;
|
||||||
|
}
|
||||||
|
p++, t++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
common_prefix_end:
|
||||||
|
p = pstem;
|
||||||
|
t = tstem;
|
||||||
|
|
||||||
|
/* count path components */
|
||||||
|
for (count = 0; '\0' != *p; count++)
|
||||||
|
{
|
||||||
|
while ('/' == *p)
|
||||||
|
p++;
|
||||||
|
while ('/' != *p && '\0' != *p)
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make relative path */
|
||||||
|
if (0 == count)
|
||||||
|
{
|
||||||
|
/* special case symlink loop: a -> a/stem */
|
||||||
|
while (PosixTargetPath < tstem)
|
||||||
|
{
|
||||||
|
tstem--;
|
||||||
|
if ('/' != *tstem)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (PosixTargetPath < tstem)
|
||||||
|
{
|
||||||
|
tstem--;
|
||||||
|
if ('/' == *tstem)
|
||||||
|
{
|
||||||
|
tstem++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Length = lstrlenA(tstem);
|
||||||
|
Length += !!Length; /* add tstem term-0 */
|
||||||
|
if (3 * count + Length > sizeof PosixTargetPath)
|
||||||
|
{
|
||||||
|
Result = STATUS_IO_REPARSE_DATA_INVALID;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
memmove(PosixTargetPath + 3 * count, tstem, Length);
|
||||||
|
for (index = 0; count > index; index++)
|
||||||
|
{
|
||||||
|
PosixTargetPath[index * 3 + 0] = '.';
|
||||||
|
PosixTargetPath[index * 3 + 1] = '.';
|
||||||
|
PosixTargetPath[index * 3 + 2] = '/';
|
||||||
|
}
|
||||||
|
if (0 == Length)
|
||||||
|
PosixTargetPath[(count - 1) * 3 + 2] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = FspPosixMapPosixToWindowsPath(PosixTargetPath, &TargetPath);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Length = lstrlenW(TargetPath);
|
||||||
|
if (Length > *PSize)
|
||||||
|
{
|
||||||
|
Result = STATUS_BUFFER_TOO_SMALL;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
*PSize = Length;
|
||||||
|
memcpy(Buffer, TargetPath, Length * sizeof(WCHAR));
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != TargetPath)
|
||||||
|
FspPosixDeletePath(TargetPath);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *Request,
|
||||||
|
PVOID FileNode,
|
||||||
|
PWSTR FileName, PVOID Buffer, SIZE_T Size)
|
||||||
|
{
|
||||||
|
struct fuse *f = FileSystem->UserContext;
|
||||||
|
struct fsp_fuse_file_desc *filedesc =
|
||||||
|
(PVOID)(UINT_PTR)Request->Req.FileSystemControl.UserContext2;
|
||||||
|
WCHAR TargetPath[FSP_FSCTL_TRANSACT_PATH_SIZEMAX / sizeof(WCHAR)];
|
||||||
|
char *PosixTargetPath = 0;
|
||||||
|
int err;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
if (0 == f->ops.symlink)
|
||||||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
|
/* is this an absolute path? */
|
||||||
|
if (Size > 4 * sizeof(WCHAR) &&
|
||||||
|
'\\' == ((PWSTR)Buffer)[0] &&
|
||||||
|
'?' == ((PWSTR)Buffer)[1] &&
|
||||||
|
'?' == ((PWSTR)Buffer)[2] &&
|
||||||
|
'\\' == ((PWSTR)Buffer)[3])
|
||||||
|
{
|
||||||
|
/* we do not support absolute paths that point outside this file system */
|
||||||
|
if (!Request->Req.FileSystemControl.TargetOnFileSystem)
|
||||||
|
{
|
||||||
|
Result = STATUS_ACCESS_DENIED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Size > sizeof TargetPath - sizeof(WCHAR))
|
||||||
|
{
|
||||||
|
Result = STATUS_IO_REPARSE_DATA_INVALID;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
memcpy(TargetPath, Buffer, Size);
|
||||||
|
TargetPath[Size / sizeof(WCHAR)] = L'\0';
|
||||||
|
|
||||||
|
Result = FspPosixMapWindowsToPosixPath(TargetPath, &PosixTargetPath);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
err = f->ops.symlink(PosixTargetPath, filedesc->PosixPath);
|
||||||
|
if (0 != err)
|
||||||
|
{
|
||||||
|
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (0 != PosixTargetPath)
|
||||||
|
FspPosixDeletePath(PosixTargetPath);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||||
{
|
{
|
||||||
fsp_fuse_intf_GetVolumeInfo,
|
fsp_fuse_intf_GetVolumeInfo,
|
||||||
@ -1443,4 +1861,7 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
|||||||
fsp_fuse_intf_GetSecurity,
|
fsp_fuse_intf_GetSecurity,
|
||||||
fsp_fuse_intf_SetSecurity,
|
fsp_fuse_intf_SetSecurity,
|
||||||
fsp_fuse_intf_ReadDirectory,
|
fsp_fuse_intf_ReadDirectory,
|
||||||
|
fsp_fuse_intf_ResolveReparsePoints,
|
||||||
|
fsp_fuse_intf_GetReparsePoint,
|
||||||
|
fsp_fuse_intf_SetReparsePoint,
|
||||||
};
|
};
|
||||||
|
@ -29,12 +29,15 @@
|
|||||||
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
|
#define FSP_FUSE_CONTEXT_FROM_HDR(h) \
|
||||||
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
|
(struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header))
|
||||||
|
|
||||||
|
#define FSP_FUSE_HAS_SYMLINKS(f) (0 != (f)->ops.readlink)
|
||||||
|
|
||||||
struct fuse
|
struct fuse
|
||||||
{
|
{
|
||||||
struct fsp_fuse_env *env;
|
struct fsp_fuse_env *env;
|
||||||
int set_umask, umask;
|
int set_umask, umask;
|
||||||
int set_uid, uid;
|
int set_uid, uid;
|
||||||
int set_gid, gid;
|
int set_gid, gid;
|
||||||
|
int rellinks;
|
||||||
struct fuse_operations ops;
|
struct fuse_operations ops;
|
||||||
void *data;
|
void *data;
|
||||||
UINT32 DebugLog;
|
UINT32 DebugLog;
|
||||||
@ -51,6 +54,7 @@ struct fsp_fuse_context_header
|
|||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||||
char *PosixPath;
|
char *PosixPath;
|
||||||
|
ptrdiff_t SymlinkIndex;
|
||||||
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
|
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 ContextBuf[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,8 +50,14 @@
|
|||||||
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
|
NTSYSAPI VOID NTAPI RtlFillMemory(VOID *Destination, DWORD Length, BYTE Fill);
|
||||||
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
|
NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD Length);
|
||||||
|
|
||||||
#pragma function(memcpy)
|
|
||||||
#pragma function(memset)
|
#pragma function(memset)
|
||||||
|
#pragma function(memcpy)
|
||||||
|
static inline
|
||||||
|
void *memset(void *dst, int val, size_t siz)
|
||||||
|
{
|
||||||
|
RtlFillMemory(dst, (DWORD)siz, val);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
static inline
|
static inline
|
||||||
void *memcpy(void *dst, const void *src, size_t siz)
|
void *memcpy(void *dst, const void *src, size_t siz)
|
||||||
{
|
{
|
||||||
@ -59,9 +65,9 @@ void *memcpy(void *dst, const void *src, size_t siz)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
void *memset(void *dst, int val, size_t siz)
|
void *memmove(void *dst, const void *src, size_t siz)
|
||||||
{
|
{
|
||||||
RtlFillMemory(dst, (DWORD)siz, val);
|
RtlMoveMemory(dst, src, (DWORD)siz);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,9 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
|||||||
PVOID OutputBuffer = Irp->UserBuffer;
|
PVOID OutputBuffer = Irp->UserBuffer;
|
||||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||||
ULONG ReparseTag;
|
PREPARSE_DATA_BUFFER ReparseData;
|
||||||
|
PWSTR PathBuffer;
|
||||||
|
BOOLEAN TargetOnFileSystem = FALSE;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||||
|
|
||||||
ASSERT(FileNode == FileDesc->FileNode);
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
@ -123,16 +125,53 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
ReparseTag = ((PREPARSE_DATA_BUFFER)InputBuffer)->ReparseTag;
|
ReparseData = (PREPARSE_DATA_BUFFER)InputBuffer;
|
||||||
|
|
||||||
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
|
if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag)
|
||||||
if (FsvolDeviceExtension->VolumeParams.ReparsePointsPrivilegeCheck)
|
|
||||||
{
|
{
|
||||||
if (IO_REPARSE_TAG_SYMLINK == ReparseTag &&
|
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
|
||||||
KernelMode != Irp->RequestorMode &&
|
if (FsvolDeviceExtension->VolumeParams.ReparsePointsPrivilegeCheck)
|
||||||
SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
|
{
|
||||||
UserMode))
|
if (KernelMode != Irp->RequestorMode &&
|
||||||
return STATUS_ACCESS_DENIED;
|
SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
|
||||||
|
UserMode))
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine if target resides on same device as link (convenience for user mode) */
|
||||||
|
PathBuffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||||
|
if (ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength > 4 * sizeof(WCHAR) &&
|
||||||
|
'\\' == PathBuffer[0] &&
|
||||||
|
'?' == PathBuffer[1] &&
|
||||||
|
'?' == PathBuffer[2] &&
|
||||||
|
'\\' == PathBuffer[3])
|
||||||
|
{
|
||||||
|
UNICODE_STRING TargetDeviceName;
|
||||||
|
PFILE_OBJECT TargetDeviceFile;
|
||||||
|
PDEVICE_OBJECT TargetDeviceObject;
|
||||||
|
|
||||||
|
RtlInitEmptyUnicodeString(&TargetDeviceName,
|
||||||
|
PathBuffer,
|
||||||
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||||
|
|
||||||
|
/* the first path component is assumed to be the device name */
|
||||||
|
TargetDeviceName.Length = 4 * sizeof(WCHAR);
|
||||||
|
while (TargetDeviceName.Length < TargetDeviceName.MaximumLength &&
|
||||||
|
'\\' != TargetDeviceName.Buffer[TargetDeviceName.Length / sizeof(WCHAR)])
|
||||||
|
TargetDeviceName.Length += sizeof(WCHAR);
|
||||||
|
|
||||||
|
Result = IoGetDeviceObjectPointer(&TargetDeviceName,
|
||||||
|
FILE_READ_ATTRIBUTES, &TargetDeviceFile, &TargetDeviceObject);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto target_check_exit;
|
||||||
|
|
||||||
|
TargetOnFileSystem = IoGetRelatedDeviceObject(FileObject) == TargetDeviceObject;
|
||||||
|
ObDereferenceObject(TargetDeviceFile);
|
||||||
|
|
||||||
|
target_check_exit:
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -169,6 +208,8 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
|||||||
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
|
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
|
||||||
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||||
InputBuffer, InputBufferLength);
|
InputBuffer, InputBufferLength);
|
||||||
|
|
||||||
|
Request->Req.FileSystemControl.TargetOnFileSystem = TargetOnFileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user