mirror of
https://github.com/winfsp/winfsp.git
synced 2025-06-07 20:42:09 -05:00
dll: fuse: multiple improvements and fixes
- Symlinks: Now supports conventing a directory into a symlink reparse point. - Symlinks: The determination of whether a symlink is a file or directory is now possible for file systems that do not support slashdot (/.) queries. - EA: Now allows the removal of non-existant EA without error (this is allowed on Windows).
This commit is contained in:
parent
ec3386c2b3
commit
0b94e8bc6a
@ -197,7 +197,8 @@ enum
|
||||
/* user-mode flags */\
|
||||
UINT32 UmFileContextIsUserContext2:1; /* user mode: FileContext parameter is UserContext2 */\
|
||||
UINT32 UmFileContextIsFullContext:1; /* user mode: FileContext parameter is FullContext */\
|
||||
UINT32 UmReservedFlags:6;\
|
||||
UINT32 UmNoReparsePointsDirCheck:1; /* user mode: no dir option check for reparse points */\
|
||||
UINT32 UmReservedFlags:5;\
|
||||
/* additional kernel-mode flags */\
|
||||
UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\
|
||||
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
|
||||
|
@ -1143,7 +1143,13 @@ typedef struct _FSP_FILE_SYSTEM
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||
SRWLOCK OpGuardLock;
|
||||
BOOLEAN UmFileContextIsUserContext2, UmFileContextIsFullContext;
|
||||
UINT16 UmNoReparsePointsDirCheck:1;
|
||||
UINT16 UmReservedFlags:15;
|
||||
} FSP_FILE_SYSTEM;
|
||||
FSP_FSCTL_STATIC_ASSERT(
|
||||
(4 == sizeof(PVOID) && 660 == sizeof(FSP_FILE_SYSTEM)) ||
|
||||
(8 == sizeof(PVOID) && 792 == sizeof(FSP_FILE_SYSTEM)),
|
||||
"sizeof(FSP_FILE_SYSTEM) must be exactly 660 in 32-bit and 792 in 64-bit.");
|
||||
typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
|
@ -161,6 +161,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
|
||||
|
||||
FileSystem->UmFileContextIsUserContext2 = !!VolumeParams->UmFileContextIsUserContext2;
|
||||
FileSystem->UmFileContextIsFullContext = !!VolumeParams->UmFileContextIsFullContext;
|
||||
FileSystem->UmNoReparsePointsDirCheck = VolumeParams->UmNoReparsePointsDirCheck;
|
||||
|
||||
*PFileSystem = FileSystem;
|
||||
|
||||
|
@ -642,6 +642,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
opt_data.VolumeParams.RejectIrpPriorToTransact0 = TRUE;
|
||||
#endif
|
||||
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
|
||||
opt_data.VolumeParams.UmNoReparsePointsDirCheck = TRUE;
|
||||
if (L'\0' == opt_data.VolumeParams.FileSystemName[0])
|
||||
memcpy(opt_data.VolumeParams.FileSystemName, L"FUSE", 5 * sizeof(WCHAR));
|
||||
|
||||
|
@ -21,6 +21,13 @@
|
||||
|
||||
#include <dll/fuse/library.h>
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
||||
static NTSTATUS fsp_fuse_intf_SetEaEntry(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PFILE_FULL_EA_INFORMATION SingleEa);
|
||||
|
||||
static inline
|
||||
VOID fsp_fuse_op_enter_lock(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
|
||||
@ -304,33 +311,111 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
const char *PosixPath)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
char *PosixDotPath = 0;
|
||||
size_t Length;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
BOOLEAN Result = FALSE;
|
||||
|
||||
Length = lstrlenA(PosixPath);
|
||||
PosixDotPath = MemAlloc(Length + 3);
|
||||
if (0 != PosixDotPath)
|
||||
if (FSP_FUSE_HAS_SLASHDOT(f))
|
||||
{
|
||||
memcpy(PosixDotPath, PosixPath, Length);
|
||||
PosixDotPath[Length + 0] = '/';
|
||||
PosixDotPath[Length + 1] = '.';
|
||||
PosixDotPath[Length + 2] = '\0';
|
||||
char *PosixDotPath = 0;
|
||||
size_t Length;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
BOOLEAN Result = FALSE;
|
||||
|
||||
Length = lstrlenA(PosixPath);
|
||||
PosixDotPath = MemAlloc(Length + 3);
|
||||
if (0 != PosixDotPath)
|
||||
{
|
||||
memcpy(PosixDotPath, PosixPath, Length);
|
||||
PosixDotPath[Length + 0] = '/';
|
||||
PosixDotPath[Length + 1] = '.';
|
||||
PosixDotPath[Length + 2] = '\0';
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
if (0 != f->ops.getattr)
|
||||
err = f->ops.getattr(PosixDotPath, (void *)&stbuf);
|
||||
else
|
||||
err = -ENOSYS_(f->env);
|
||||
|
||||
MemFree(PosixDotPath);
|
||||
|
||||
Result = 0 == err && 0040000 == (stbuf.st_mode & 0170000);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
PWSTR WindowsPath = 0, P;
|
||||
char *PosixResolvedPath = 0;
|
||||
UINT32 ReparsePointIndex;
|
||||
UINT32 ResolvedFileAttributes = -1;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
union
|
||||
{
|
||||
REPARSE_DATA_BUFFER V;
|
||||
UINT8 B[FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
|
||||
FSP_FSCTL_TRANSACT_PATH_SIZEMAX + sizeof(WCHAR)/* add space for term-0 */];
|
||||
} ReparseDataBuf;
|
||||
SIZE_T ReparseDataSize;
|
||||
struct fuse_stat_ex stbuf;
|
||||
int err;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = FspPosixMapPosixToWindowsPath(PosixPath, &WindowsPath);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
ReparsePointIndex = 0;
|
||||
for (P = WindowsPath; '\0' != *P; P++)
|
||||
if (L'\\' == *P)
|
||||
ReparsePointIndex = (UINT32)(P + 1 - WindowsPath);
|
||||
|
||||
ReparseDataSize = sizeof ReparseDataBuf - sizeof(WCHAR)/* leave space for term-0 */;
|
||||
Result = FspFileSystemResolveReparsePoints(FileSystem,
|
||||
fsp_fuse_intf_GetReparsePointByName, &ResolvedFileAttributes,
|
||||
WindowsPath, ReparsePointIndex, TRUE,
|
||||
&IoStatus, &ReparseDataBuf,
|
||||
&ReparseDataSize);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
if (IO_REPARSE_TAG_SYMLINK != ReparseDataBuf.V.ReparseTag)
|
||||
{
|
||||
Result = STATUS_UNSUCCESSFUL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (-1 != ResolvedFileAttributes)
|
||||
{
|
||||
Result = (FILE_ATTRIBUTE_DIRECTORY & ResolvedFileAttributes) ?
|
||||
STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
P = (PWSTR)(ReparseDataBuf.V.SymbolicLinkReparseBuffer.PathBuffer +
|
||||
ReparseDataBuf.V.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR));
|
||||
P[ReparseDataBuf.V.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)] = L'\0';
|
||||
|
||||
Result = FspPosixMapWindowsToPosixPath(P, &PosixResolvedPath);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
if (0 != f->ops.getattr)
|
||||
err = f->ops.getattr(PosixDotPath, (void *)&stbuf);
|
||||
err = f->ops.getattr(PosixResolvedPath, (void *)&stbuf);
|
||||
else
|
||||
err = -ENOSYS_(f->env);
|
||||
|
||||
MemFree(PosixDotPath);
|
||||
Result = 0 == err && 0040000 == (stbuf.st_mode & 0170000) ?
|
||||
STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
|
||||
Result = 0 == err && 0040000 == (stbuf.st_mode & 0170000);
|
||||
exit:
|
||||
if (0 != PosixResolvedPath)
|
||||
FspPosixDeletePath(PosixResolvedPath);
|
||||
if (0 != WindowsPath)
|
||||
FspPosixDeletePath(WindowsPath);
|
||||
|
||||
return NT_SUCCESS(Result);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static inline uint32_t fsp_fuse_intf_MapFileAttributesToFlags(UINT32 FileAttributes)
|
||||
@ -367,10 +452,11 @@ static inline UINT32 fsp_fuse_intf_MapFlagsToFileAttributes(uint32_t flags)
|
||||
|
||||
#define FUSE_FILE_INFO(IsDirectory, fi) ((IsDirectory) ? 0 : (fi))
|
||||
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
|
||||
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
|
||||
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, TRUE, FileInfo)
|
||||
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
|
||||
const char *PosixPath, struct fuse_file_info *fi, const void *stbufp,
|
||||
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
|
||||
BOOLEAN CheckSymlinkDirectory,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
@ -429,7 +515,7 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
|
||||
{
|
||||
FileInfo->FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
FileInfo->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||
if (fsp_fuse_intf_CheckSymlinkDirectory(FileSystem, PosixPath))
|
||||
if (CheckSymlinkDirectory && fsp_fuse_intf_CheckSymlinkDirectory(FileSystem, PosixPath))
|
||||
FileInfo->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
break;
|
||||
}
|
||||
@ -572,7 +658,7 @@ exit:
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
const char *PosixPath, struct fuse_file_info *fi,
|
||||
PVOID Buffer, PSIZE_T PSize)
|
||||
PVOID Buffer, PSIZE_T PSize, PUINT32 PResolvedFileAttributes)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
UINT32 Uid, Gid, Mode, Dev;
|
||||
@ -583,12 +669,16 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0,
|
||||
&Uid, &Gid, &Mode, &Dev, &FileInfo);
|
||||
&Uid, &Gid, &Mode, &Dev, FALSE, &FileInfo);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (0 == (FILE_ATTRIBUTE_REPARSE_POINT & FileInfo.FileAttributes))
|
||||
{
|
||||
if (0 != PResolvedFileAttributes)
|
||||
*PResolvedFileAttributes = FileInfo.FileAttributes;
|
||||
return STATUS_NOT_A_REPARSE_POINT;
|
||||
}
|
||||
|
||||
if (0 == Buffer)
|
||||
return STATUS_SUCCESS;
|
||||
@ -688,13 +778,6 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
||||
static NTSTATUS fsp_fuse_intf_SetEaEntry(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PFILE_FULL_EA_INFORMATION SingleEa);
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||
{
|
||||
@ -1031,7 +1114,12 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
break;
|
||||
}
|
||||
|
||||
if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
{
|
||||
fi.fh = -1;
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
else if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (0 != f->ops.opendir)
|
||||
{
|
||||
@ -1044,11 +1132,6 @@ static NTSTATUS fsp_fuse_intf_Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else if (FileInfoBuf.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
{
|
||||
fi.fh = -1;
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@ -1192,15 +1275,15 @@ static VOID fsp_fuse_intf_Close(FSP_FILE_SYSTEM *FileSystem,
|
||||
fi.flags = filedesc->OpenFlags;
|
||||
fi.fh = filedesc->FileHandle;
|
||||
|
||||
if (filedesc->IsDirectory)
|
||||
if (filedesc->IsReparsePoint)
|
||||
{
|
||||
/* reparse points are not opened, nothing to do! */
|
||||
}
|
||||
else if (filedesc->IsDirectory)
|
||||
{
|
||||
if (0 != f->ops.releasedir)
|
||||
f->ops.releasedir(filedesc->PosixPath, &fi);
|
||||
}
|
||||
else if (filedesc->IsReparsePoint)
|
||||
{
|
||||
/* reparse points are not opened, nothing to do! */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != f->ops.flush)
|
||||
@ -1332,7 +1415,9 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
|
||||
fi.fh = filedesc->FileHandle;
|
||||
|
||||
Result = STATUS_SUCCESS; /* just say success, if fs does not support fsync */
|
||||
if (filedesc->IsDirectory)
|
||||
if (filedesc->IsReparsePoint)
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
else if (filedesc->IsDirectory)
|
||||
{
|
||||
if (0 != f->ops.fsyncdir)
|
||||
{
|
||||
@ -1340,8 +1425,6 @@ static NTSTATUS fsp_fuse_intf_Flush(FSP_FILE_SYSTEM *FileSystem,
|
||||
Result = fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
}
|
||||
else if (filedesc->IsReparsePoint)
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
else
|
||||
{
|
||||
if (0 != f->ops.fsync)
|
||||
@ -1854,7 +1937,7 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
||||
NTSTATUS Result0;
|
||||
|
||||
Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, name, 0, stbuf,
|
||||
&Uid, &Gid, &Mode, 0, &DirInfo->FileInfo);
|
||||
&Uid, &Gid, &Mode, 0, TRUE, &DirInfo->FileInfo);
|
||||
if (NT_SUCCESS(Result0))
|
||||
DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */
|
||||
}
|
||||
@ -1976,6 +2059,9 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
||||
int err;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (!filedesc->IsDirectory || filedesc->IsReparsePoint)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
if (FspFileSystemAcquireDirectoryBuffer(&filedesc->DirBuffer, 0 == Marker, &Result))
|
||||
{
|
||||
memset(&dh, 0, sizeof dh);
|
||||
@ -2032,6 +2118,9 @@ static NTSTATUS fsp_fuse_intf_GetDirInfoByName(FSP_FILE_SYSTEM *FileSystem,
|
||||
UINT32 Uid, Gid, Mode;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (!filedesc->IsDirectory || filedesc->IsReparsePoint)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
Result = FspPosixMapWindowsToPosixPath(FileName, &PosixName);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
@ -2098,7 +2187,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
Result = fsp_fuse_intf_GetReparsePointEx(FileSystem, PosixPath, 0, Buffer, PSize);
|
||||
Result = fsp_fuse_intf_GetReparsePointEx(FileSystem, PosixPath, 0, Buffer, PSize, Context);
|
||||
|
||||
exit:
|
||||
if (0 != PosixPath)
|
||||
@ -2120,7 +2209,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
return fsp_fuse_intf_GetReparsePointEx(FileSystem, filedesc->PosixPath,
|
||||
FUSE_FILE_INFO(filedesc->IsDirectory, &fi),
|
||||
Buffer, PSize);
|
||||
Buffer, PSize, 0);
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
@ -2159,23 +2248,25 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
* Note that this will also result in a change of the inode number for the reparse point!
|
||||
*/
|
||||
|
||||
if (0 == f->ops.rename || 0 == f->ops.unlink)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
ReparseData = (PREPARSE_DATA_BUFFER)Buffer;
|
||||
|
||||
if (IO_REPARSE_TAG_SYMLINK == ReparseData->ReparseTag || (
|
||||
IO_REPARSE_TAG_NFS == ReparseData->ReparseTag &&
|
||||
NFS_SPECFILE_LNK == *(PUINT64)ReparseData->GenericReparseBuffer.DataBuffer))
|
||||
{
|
||||
if (0 == f->ops.symlink)
|
||||
if (filedesc->IsDirectory && 0 == f->ops.rmdir)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
if (0 == f->ops.symlink || 0 == f->ops.rename || 0 == f->ops.unlink)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
IsSymlink = TRUE;
|
||||
}
|
||||
else if (IO_REPARSE_TAG_NFS == ReparseData->ReparseTag)
|
||||
{
|
||||
if (0 == f->ops.mknod)
|
||||
/* FUSE cannot make a directory into an NFS reparse point */
|
||||
if (filedesc->IsDirectory)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
if (0 == f->ops.mknod || 0 == f->ops.rename || 0 == f->ops.unlink)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
IsSymlink = FALSE;
|
||||
@ -2183,10 +2274,6 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
else
|
||||
return STATUS_IO_REPARSE_TAG_MISMATCH;
|
||||
|
||||
/* FUSE cannot make a directory into a reparse point */
|
||||
if (filedesc->IsDirectory)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
memset(&fi, 0, sizeof fi);
|
||||
fi.flags = filedesc->OpenFlags;
|
||||
fi.fh = filedesc->FileHandle;
|
||||
@ -2297,17 +2384,33 @@ static NTSTATUS fsp_fuse_intf_SetReparsePoint(FSP_FILE_SYSTEM *FileSystem,
|
||||
}
|
||||
}
|
||||
|
||||
err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath);
|
||||
if (filedesc->IsDirectory)
|
||||
{
|
||||
err = f->ops.rmdir(filedesc->PosixPath);
|
||||
if (0 == err)
|
||||
err = f->ops.rename(PosixHiddenPath, filedesc->PosixPath);
|
||||
}
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
if (filedesc->IsDirectory)
|
||||
{
|
||||
if (0 != f->ops.releasedir)
|
||||
f->ops.releasedir(filedesc->PosixPath, &fi);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != f->ops.release)
|
||||
f->ops.release(filedesc->PosixPath, &fi);
|
||||
}
|
||||
filedesc->IsReparsePoint = TRUE;
|
||||
filedesc->FileHandle = -1;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
@ -2433,13 +2536,17 @@ static NTSTATUS fsp_fuse_intf_SetEaEntry(
|
||||
int err;
|
||||
|
||||
if (0 != SingleEa->EaValueLength)
|
||||
err = f->ops.setxattr(PosixPath,
|
||||
SingleEa->EaName, SingleEa->EaName + SingleEa->EaNameLength + 1, SingleEa->EaValueLength, 0);
|
||||
{
|
||||
err = f->ops.setxattr(PosixPath, SingleEa->EaName,
|
||||
SingleEa->EaName + SingleEa->EaNameLength + 1, SingleEa->EaValueLength, 0);
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
else
|
||||
err = f->ops.removexattr(PosixPath,
|
||||
SingleEa->EaName);
|
||||
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
{
|
||||
err = f->ops.removexattr(PosixPath, SingleEa->EaName);
|
||||
/* ignore errors */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
@ -160,6 +160,29 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
/* this should always fail with ENOSYS or EINVAL */
|
||||
err = f->ops.readlink("/", buf, sizeof buf);
|
||||
f->has_symlinks = -ENOSYS_(f->env) != err;
|
||||
|
||||
if (f->has_symlinks)
|
||||
{
|
||||
/*
|
||||
* Determine if the file system supports "/." queries.
|
||||
*
|
||||
* Symlinks on Windows are differentiated as "file" symlinks or "directory" symlinks.
|
||||
* When we need to make the distinction we can follow one of two techniques:
|
||||
*
|
||||
* - Slashdot technique: We issue a getattr(path + "/.") and check the stat result.
|
||||
* In general this is not a getattr() query that FUSE file systems are expected
|
||||
* to handle. For this reason we issue a getattr("/.") below to determine
|
||||
* if the file system handles this kind of query against the root directory.
|
||||
*
|
||||
* - Resolve technique: If the file system cannot handle slashdot queries, we resolve
|
||||
* the path using readlink on each path component, then issue getattr on the resolved
|
||||
* path and check the stat result.
|
||||
*/
|
||||
struct fuse_stat_ex stbuf;
|
||||
memset(&stbuf, 0, sizeof stbuf);
|
||||
err = f->ops.getattr("/.", (void *)&stbuf);
|
||||
f->has_slashdot = 0 == err && 0040000 == (stbuf.st_mode & 0170000);
|
||||
}
|
||||
}
|
||||
if (0 != f->ops.listxattr && 0 != f->ops.getxattr &&
|
||||
0 != f->ops.setxattr && 0 != f->ops.removexattr)
|
||||
|
@ -34,6 +34,7 @@
|
||||
((struct fuse_context *)((PUINT8)(h) + sizeof(struct fsp_fuse_context_header)))
|
||||
|
||||
#define FSP_FUSE_HAS_SYMLINKS(f) ((f)->has_symlinks)
|
||||
#define FSP_FUSE_HAS_SLASHDOT(f) ((f)->has_slashdot)
|
||||
|
||||
#define ENOSYS_(env) ('C' == (env)->environment ? 88 : 40)
|
||||
|
||||
@ -61,7 +62,7 @@ struct fuse
|
||||
void *data;
|
||||
unsigned conn_want;
|
||||
BOOLEAN fsinit;
|
||||
BOOLEAN has_symlinks;
|
||||
BOOLEAN has_symlinks, has_slashdot;
|
||||
UINT32 DebugLog;
|
||||
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
|
||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||
|
@ -325,6 +325,13 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* We allow some file systems (notably FUSE) to open reparse points
|
||||
* regardless of the FILE_DIRECTORY_FILE / FILE_NON_DIRECTORY_FILE options.
|
||||
*/
|
||||
if (0 != (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && FileSystem->UmNoReparsePointsDirCheck)
|
||||
goto skip_reparse_dir_check;
|
||||
|
||||
if ((Request->Req.Create.CreateOptions & FILE_DIRECTORY_FILE) &&
|
||||
0 == (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
@ -337,6 +344,9 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
Result = STATUS_FILE_IS_A_DIRECTORY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
skip_reparse_dir_check:
|
||||
;
|
||||
}
|
||||
|
||||
if (Request->Req.Create.UserMode)
|
||||
|
Loading…
x
Reference in New Issue
Block a user