Skip to content

Commit

Permalink
dll,fuse: allow dir buffer entry invalidation
Browse files Browse the repository at this point in the history
The FUSE implementation of ReadDirectory issues readdir followed
by a slew of getattr. In the current implementation if a getattr fails
the whole readdir operation fails.

This commit adds the ability to invalidate individual entries in the
directory buffer. Entries for which getattr fails are now marked invalid
rather than fail the overall ReadDirectory operation.

See #292
  • Loading branch information
billziss-gh committed Apr 13, 2020
1 parent 42fd579 commit b4c39f6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 7 deletions.
12 changes: 12 additions & 0 deletions src/dll/dirbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,18 @@ FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)

FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;

/* eliminate invalidated entries from the index */
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
ULONG I, J;
for (I = Count - 1, J = Count; I < Count; I--)
{
if (FspFileSystemDirectoryBufferEntryInvalid == Index[I])
continue;
Index[--J] = Index[I];
}
DirBuffer->HiMark = (ULONG)((PUINT8)&Index[J] - DirBuffer->Buffer);

FspFileSystemSortDirectoryBuffer(DirBuffer);

ReleaseSRWLockExclusive(&DirBuffer->Lock);
Expand Down
3 changes: 2 additions & 1 deletion src/dll/fuse/fuse_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1866,7 +1866,8 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
/* mark the directory buffer entry as invalid */
*Index = FspFileSystemDirectoryBufferEntryInvalid;

if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
Expand Down
1 change: 1 addition & 0 deletions src/dll/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);

PWSTR FspDiagIdent(VOID);

#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1)
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);

Expand Down
70 changes: 64 additions & 6 deletions tst/winfsp-tests/dirbuf-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ static void dirbuf_dots_test(void)
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
}

static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
{
PVOID DirBuffer = 0;
NTSTATUS Result;
Expand Down Expand Up @@ -202,6 +202,51 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
ASSERT(STATUS_SUCCESS == Result);
}

#if 1
{
ASSERT(Count > InvalidCount);

#if !defined(FspFileSystemDirectoryBufferEntryInvalid)
const ULONG FspFileSystemDirectoryBufferEntryInvalid = ((ULONG)-1);
#endif
typedef struct
{
SRWLOCK Lock;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *PeekDirBuffer = DirBuffer;
PUINT8 PeekBuffer = PeekDirBuffer->Buffer;
PULONG PeekIndex = (PULONG)(PeekDirBuffer->Buffer + PeekDirBuffer->HiMark);
ULONG PeekCount = (PeekDirBuffer->Capacity - PeekDirBuffer->HiMark) / sizeof(ULONG);

ASSERT(Count == PeekCount);

for (ULONG I = 0; InvalidCount > I; I++)
{
for (;;)
{
N = rand() % PeekCount;
if (FspFileSystemDirectoryBufferEntryInvalid == PeekIndex[N])
continue;

DirInfo = (PVOID)(PeekBuffer + PeekIndex[N]);
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';

/* do not invalidate dot entries as they are used in testing below */
if (0 == wcscmp(CurrFileName, L".") || 0 == wcscmp(CurrFileName, L".."))
continue;

PeekIndex[N] = FspFileSystemDirectoryBufferEntryInvalid;
break;
}
}

Count -= InvalidCount;
}
#endif

FspFileSystemReleaseDirectoryBuffer(&DirBuffer);

MarkerIndex = rand() % Count;
Expand Down Expand Up @@ -303,19 +348,32 @@ static void dirbuf_fill_test(void)
{
unsigned seed = (unsigned)time(0);

dirbuf_fill_dotest(1485473509, 10);
dirbuf_fill_dotest(1485473509, 10, 0);
dirbuf_fill_dotest(1485473509, 10, 3);

for (ULONG I = 0; 10000 > I; I++)
dirbuf_fill_dotest(seed + I, 10);
{
dirbuf_fill_dotest(seed + I, 10, 0);
dirbuf_fill_dotest(seed + I, 10, 3);
}

for (ULONG I = 0; 1000 > I; I++)
dirbuf_fill_dotest(seed + I, 100);
{
dirbuf_fill_dotest(seed + I, 100, 0);
dirbuf_fill_dotest(seed + I, 100, 30);
}

for (ULONG I = 0; 100 > I; I++)
dirbuf_fill_dotest(seed + I, 1000);
{
dirbuf_fill_dotest(seed + I, 1000, 0);
dirbuf_fill_dotest(seed + I, 1000, 300);
}

for (ULONG I = 0; 10 > I; I++)
dirbuf_fill_dotest(seed + I, 10000);
{
dirbuf_fill_dotest(seed + I, 10000, 0);
dirbuf_fill_dotest(seed + I, 10000, 3000);
}
}

void dirbuf_tests(void)
Expand Down

0 comments on commit b4c39f6

Please sign in to comment.