mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 08:53:01 -05:00
dll: fuse_intf: ReadDirectory reimplementation
This commit is contained in:
parent
c6bab18947
commit
1124e24a61
@ -1193,108 +1193,29 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
|||||||
const struct fuse_stat *stbuf, fuse_off_t off)
|
const struct fuse_stat *stbuf, fuse_off_t off)
|
||||||
{
|
{
|
||||||
struct fuse_dirhandle *dh = buf;
|
struct fuse_dirhandle *dh = buf;
|
||||||
UINT32 Uid, Gid, Mode;
|
struct fsp_fuse_dirinfo *di;
|
||||||
union
|
ULONG len, xfersize;
|
||||||
{
|
|
||||||
FSP_FSCTL_DIR_INFO V;
|
|
||||||
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
|
|
||||||
} DirInfoBuf;
|
|
||||||
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
|
|
||||||
char *PosixPathEnd = 0, SavedPathChar;
|
|
||||||
PWSTR FileName = 0;
|
|
||||||
ULONG Size;
|
|
||||||
NTSTATUS Result;
|
|
||||||
|
|
||||||
if ('.' == name[0] && '\0' == name[1])
|
len = lstrlenA(name);
|
||||||
|
if (len > 255)
|
||||||
|
len = 255;
|
||||||
|
|
||||||
|
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
|
||||||
|
xfersize = FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(struct fsp_fuse_dirinfo) + len + 1);
|
||||||
|
|
||||||
|
if ((PUINT8)di + xfersize > (PUINT8)dh->Buffer + dh->Length)
|
||||||
{
|
{
|
||||||
PosixPathEnd = 1 < dh->PosixName - dh->PosixPath ? dh->PosixName - 1 : dh->PosixName;
|
PVOID Buffer;
|
||||||
SavedPathChar = *PosixPathEnd;
|
ULONG Length = dh->Length;
|
||||||
*PosixPathEnd = '\0';
|
|
||||||
}
|
if (0 == Length)
|
||||||
|
Length = 16 * 1024;
|
||||||
|
else if (Length < 16 * 1024 * 1024)
|
||||||
|
Length *= 2;
|
||||||
else
|
else
|
||||||
if ('.' == name[0] && '.' == name[1] && '\0' == name[2])
|
|
||||||
{
|
|
||||||
PosixPathEnd = 1 < dh->PosixName - dh->PosixPath ? dh->PosixName - 2 : dh->PosixName;
|
|
||||||
while (dh->PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
|
|
||||||
PosixPathEnd--;
|
|
||||||
if (dh->PosixPath == PosixPathEnd)
|
|
||||||
PosixPathEnd++;
|
|
||||||
SavedPathChar = *PosixPathEnd;
|
|
||||||
*PosixPathEnd = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Size = lstrlenA(name);
|
|
||||||
if (Size > 255)
|
|
||||||
Size = 255;
|
|
||||||
memcpy(dh->PosixName, name, Size);
|
|
||||||
dh->PosixName[Size] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
Result = fsp_fuse_intf_GetFileInfoEx(dh->FileSystem, dh->PosixPath, 0,
|
|
||||||
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (0 != PosixPathEnd)
|
Buffer = MemAlloc(Length);
|
||||||
*PosixPathEnd = SavedPathChar;
|
|
||||||
|
|
||||||
Result = FspPosixMapPosixToWindowsPath(name, &FileName);
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
Size = lstrlenW(FileName);
|
|
||||||
if (Size > 255)
|
|
||||||
Size = 255;
|
|
||||||
Size *= sizeof(WCHAR);
|
|
||||||
memcpy(DirInfo->FileNameBuf, FileName, Size);
|
|
||||||
|
|
||||||
FspPosixDeletePath(FileName);
|
|
||||||
|
|
||||||
memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
|
|
||||||
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size);
|
|
||||||
DirInfo->NextOffset = off;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FUSE readdir documentation quote:
|
|
||||||
*
|
|
||||||
* The filesystem may choose between two modes of operation:
|
|
||||||
*
|
|
||||||
* 1) The readdir implementation ignores the offset parameter, and
|
|
||||||
* passes zero to the filler function's offset. The filler
|
|
||||||
* function will not return '1' (unless an error happens), so the
|
|
||||||
* whole directory is read in a single readdir operation. This
|
|
||||||
* works just like the old getdir() method.
|
|
||||||
*
|
|
||||||
* 2) The readdir implementation keeps track of the offsets of the
|
|
||||||
* directory entries. It uses the offset parameter and always
|
|
||||||
* passes non-zero offset to the filler function. When the buffer
|
|
||||||
* is full (or an error happens) the filler function will return
|
|
||||||
* '1'.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (0 != off)
|
|
||||||
{
|
|
||||||
if (0 == dh->Buffer)
|
|
||||||
{
|
|
||||||
dh->Buffer = dh->OriginalBuffer;
|
|
||||||
dh->Length = dh->OriginalLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dh->OriginalBuffer != dh->Buffer)
|
|
||||||
{
|
|
||||||
DirInfo->NextOffset = dh->BytesTransferred + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size);
|
|
||||||
|
|
||||||
if (0 != dh->Buffer &&
|
|
||||||
FspFileSystemAddDirInfo(DirInfo, dh->Buffer, dh->Length, &dh->BytesTransferred))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (0 == dh->Length)
|
|
||||||
dh->Length = 8 * 1024; /* initial alloc: 16 == 8 * 2; see below */
|
|
||||||
else if (dh->Length >= 2 * 1024 * 1024)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
PVOID Buffer = MemAlloc(dh->Length * 2);
|
|
||||||
if (0 == Buffer)
|
if (0 == Buffer)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -1302,10 +1223,21 @@ int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
|
|||||||
MemFree(dh->Buffer);
|
MemFree(dh->Buffer);
|
||||||
|
|
||||||
dh->Buffer = Buffer;
|
dh->Buffer = Buffer;
|
||||||
dh->Length *= 2;
|
dh->Length = Length;
|
||||||
|
|
||||||
|
di = (PVOID)((PUINT8)dh->Buffer + dh->BytesTransferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ! FspFileSystemAddDirInfo(DirInfo, dh->Buffer, dh->Length, &dh->BytesTransferred);
|
dh->BytesTransferred += xfersize;
|
||||||
|
dh->NonZeroOffset = dh->NonZeroOffset || 0 != off;
|
||||||
|
|
||||||
|
di->Size = (UINT16)(sizeof(struct fsp_fuse_dirinfo) + len + 1);
|
||||||
|
di->FileInfoValid = FALSE;
|
||||||
|
di->NextOffset = 0 != off ? off : dh->BytesTransferred;
|
||||||
|
memcpy(di->PosixNameBuf, name, len);
|
||||||
|
di->PosixNameBuf[len] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
|
int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name,
|
||||||
@ -1325,35 +1257,25 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
(PVOID)(UINT_PTR)Request->Req.QueryDirectory.UserContext2;
|
(PVOID)(UINT_PTR)Request->Req.QueryDirectory.UserContext2;
|
||||||
struct fuse_file_info fi;
|
struct fuse_file_info fi;
|
||||||
struct fuse_dirhandle dh;
|
struct fuse_dirhandle dh;
|
||||||
FSP_FSCTL_DIR_INFO *DirInfo;
|
struct fsp_fuse_dirinfo *di;
|
||||||
PUINT8 DirInfoEnd;
|
PUINT8 diend;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
FSP_FSCTL_DIR_INFO V;
|
||||||
|
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + 255 * sizeof(WCHAR)];
|
||||||
|
} DirInfoBuf;
|
||||||
|
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.V;
|
||||||
|
UINT32 Uid, Gid, Mode;
|
||||||
|
char *PosixPath = 0, *PosixName, *PosixPathEnd, SavedPathChar;
|
||||||
|
PWSTR FileName = 0;
|
||||||
ULONG Size;
|
ULONG Size;
|
||||||
int err;
|
int err;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
memset(&dh, 0, sizeof dh);
|
||||||
|
|
||||||
if (0 == filedesc->DirBuffer)
|
if (0 == filedesc->DirBuffer)
|
||||||
{
|
{
|
||||||
memset(&dh, 0, sizeof dh);
|
|
||||||
dh.FileSystem = FileSystem;
|
|
||||||
|
|
||||||
Size = lstrlenA(filedesc->PosixPath);
|
|
||||||
dh.PosixPath = MemAlloc(Size + 1 + 255 + 1);
|
|
||||||
if (0 == dh.PosixPath)
|
|
||||||
{
|
|
||||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(dh.PosixPath, filedesc->PosixPath, Size);
|
|
||||||
if (1 < Size)
|
|
||||||
/* if not root */
|
|
||||||
dh.PosixPath[Size++] = '/';
|
|
||||||
dh.PosixPath[Size] = '\0';
|
|
||||||
dh.PosixName = dh.PosixPath + Size;
|
|
||||||
|
|
||||||
dh.OriginalBuffer = Buffer;
|
|
||||||
dh.OriginalLength = Length;
|
|
||||||
|
|
||||||
if (0 != f->ops.readdir)
|
if (0 != f->ops.readdir)
|
||||||
{
|
{
|
||||||
memset(&fi, 0, sizeof fi);
|
memset(&fi, 0, sizeof fi);
|
||||||
@ -1371,55 +1293,133 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
else
|
else
|
||||||
Result = STATUS_INVALID_DEVICE_REQUEST;
|
Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
|
||||||
exit:
|
if (!NT_SUCCESS(Result))
|
||||||
MemFree(dh.PosixPath);
|
goto exit;
|
||||||
|
|
||||||
if (NT_SUCCESS(Result))
|
if (0 == dh.BytesTransferred)
|
||||||
{
|
{
|
||||||
if (dh.OriginalBuffer == dh.Buffer)
|
|
||||||
{
|
|
||||||
*PBytesTransferred = dh.BytesTransferred;
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == dh.Buffer)
|
|
||||||
{
|
|
||||||
*PBytesTransferred = dh.BytesTransferred;
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
*PBytesTransferred = 0;
|
||||||
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||||
|
goto success;
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
else if (dh.NonZeroOffset)
|
||||||
filedesc->DirBuffer = dh.Buffer;
|
{
|
||||||
filedesc->DirBufferSize = dh.BytesTransferred;
|
di = (PVOID)((PUINT8)dh.Buffer + 0);
|
||||||
/* fall through! */
|
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemFree(dh.Buffer);
|
di = (PVOID)((PUINT8)dh.Buffer + Offset);
|
||||||
return Result;
|
diend = (PUINT8)dh.Buffer + dh.BytesTransferred;
|
||||||
|
filedesc->DirBuffer = dh.Buffer;
|
||||||
|
filedesc->DirBufferSize = dh.BytesTransferred;
|
||||||
|
dh.Buffer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
di = (PVOID)((PUINT8)filedesc->DirBuffer + Offset);
|
||||||
|
diend = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
DirInfo = (PVOID)((PUINT8)filedesc->DirBuffer + Offset);
|
|
||||||
DirInfoEnd = (PUINT8)filedesc->DirBuffer + filedesc->DirBufferSize;
|
|
||||||
for (;
|
for (;
|
||||||
(PUINT8)DirInfo + sizeof(DirInfo->Size) <= DirInfoEnd;
|
(PUINT8)di + sizeof(di->Size) <= diend;
|
||||||
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)))
|
di = (PVOID)((PUINT8)di + FSP_FSCTL_DEFAULT_ALIGN_UP(di->Size)))
|
||||||
{
|
{
|
||||||
if (sizeof(FSP_FSCTL_DIR_INFO) > DirInfo->Size)
|
if (sizeof(struct fsp_fuse_dirinfo) > di->Size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (!di->FileInfoValid)
|
||||||
|
{
|
||||||
|
if (0 == PosixPath)
|
||||||
|
{
|
||||||
|
Size = lstrlenA(filedesc->PosixPath);
|
||||||
|
PosixPath = MemAlloc(Size + 1 + 255 + 1);
|
||||||
|
if (0 == PosixPath)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(PosixPath, filedesc->PosixPath, Size);
|
||||||
|
if (1 < Size)
|
||||||
|
/* if not root */
|
||||||
|
PosixPath[Size++] = '/';
|
||||||
|
PosixPath[Size] = '\0';
|
||||||
|
PosixName = PosixPath + Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('.' == di->PosixNameBuf[0] && '\0' == di->PosixNameBuf[1])
|
||||||
|
{
|
||||||
|
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
|
||||||
|
SavedPathChar = *PosixPathEnd;
|
||||||
|
*PosixPathEnd = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ('.' == di->PosixNameBuf[0] && '.' == di->PosixNameBuf[1] && '\0' == di->PosixNameBuf[2])
|
||||||
|
{
|
||||||
|
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
|
||||||
|
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
|
||||||
|
PosixPathEnd--;
|
||||||
|
if (PosixPath == PosixPathEnd)
|
||||||
|
PosixPathEnd++;
|
||||||
|
SavedPathChar = *PosixPathEnd;
|
||||||
|
*PosixPathEnd = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PosixPathEnd = 0;
|
||||||
|
Size = lstrlenA(di->PosixNameBuf);
|
||||||
|
if (Size > 255)
|
||||||
|
Size = 255;
|
||||||
|
memcpy(PosixName, di->PosixNameBuf, Size);
|
||||||
|
PosixName[Size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
|
||||||
|
&Uid, &Gid, &Mode, &di->FileInfo);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (0 != PosixPathEnd)
|
||||||
|
*PosixPathEnd = SavedPathChar;
|
||||||
|
|
||||||
|
di->FileInfoValid = TRUE;
|
||||||
|
}
|
||||||
|
memcpy(&DirInfo->FileInfo, &di->FileInfo, sizeof di->FileInfo);
|
||||||
|
|
||||||
|
Result = FspPosixMapPosixToWindowsPath(di->PosixNameBuf, &FileName);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
Size = lstrlenW(FileName);
|
||||||
|
if (Size > 255)
|
||||||
|
Size = 255;
|
||||||
|
Size *= sizeof(WCHAR);
|
||||||
|
memcpy(DirInfo->FileNameBuf, FileName, Size);
|
||||||
|
|
||||||
|
FspPosixDeletePath(FileName);
|
||||||
|
|
||||||
|
memset(DirInfo->Padding, 0, sizeof DirInfo->Padding);
|
||||||
|
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + Size);
|
||||||
|
DirInfo->NextOffset = di->NextOffset;
|
||||||
|
|
||||||
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
|
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((PUINT8)DirInfo + sizeof(DirInfo->Size) > DirInfoEnd)
|
if ((PUINT8)di + sizeof(di->Size) > diend)
|
||||||
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
success:
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
MemFree(PosixPath);
|
||||||
|
MemFree(dh.Buffer);
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||||
|
@ -58,16 +58,22 @@ struct fsp_fuse_file_desc
|
|||||||
|
|
||||||
struct fuse_dirhandle
|
struct fuse_dirhandle
|
||||||
{
|
{
|
||||||
FSP_FILE_SYSTEM *FileSystem;
|
|
||||||
char *PosixPath, *PosixName;
|
|
||||||
PVOID OriginalBuffer;
|
|
||||||
ULONG OriginalLength;
|
|
||||||
PVOID Buffer;
|
PVOID Buffer;
|
||||||
ULONG Length;
|
ULONG Length;
|
||||||
ULONG BytesTransferred;
|
ULONG BytesTransferred;
|
||||||
|
BOOLEAN NonZeroOffset;
|
||||||
BOOLEAN DotFiles, HasChild;
|
BOOLEAN DotFiles, HasChild;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fsp_fuse_dirinfo
|
||||||
|
{
|
||||||
|
UINT16 Size;
|
||||||
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
|
BOOLEAN FileInfoValid;
|
||||||
|
UINT64 NextOffset;
|
||||||
|
char PosixNameBuf[]; /* includes term-0 (unlike FSP_FSCTL_DIR_INFO) */
|
||||||
|
};
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
struct fsp_fuse_context_header *fsp_fuse_context_header(VOID)
|
struct fsp_fuse_context_header *fsp_fuse_context_header(VOID)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user