mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-31 12:08:41 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			198 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * @file wsl-test.c
 | |
|  *
 | |
|  * @copyright 2015-2025 Bill Zissimopoulos
 | |
|  */
 | |
| /*
 | |
|  * This file is part of WinFsp.
 | |
|  *
 | |
|  * You can redistribute it and/or modify it under the terms of the GNU
 | |
|  * General Public License version 3 as published by the Free Software
 | |
|  * Foundation.
 | |
|  *
 | |
|  * Licensees holding a valid commercial license may use this software
 | |
|  * in accordance with the commercial license agreement provided in
 | |
|  * conjunction with the software.  The terms and conditions of any such
 | |
|  * commercial license agreement shall govern, supersede, and render
 | |
|  * ineffective any application of the GPLv3 license to this software,
 | |
|  * notwithstanding of any reference thereto in the software or
 | |
|  * associated repository.
 | |
|  */
 | |
| 
 | |
| #include <winfsp/winfsp.h>
 | |
| #include <tlib/testsuite.h>
 | |
| #include <strsafe.h>
 | |
| #include "memfs.h"
 | |
| 
 | |
| #include "winfsp-tests.h"
 | |
| 
 | |
| /*
 | |
|  * The following symbols were missing from earlier SDKs, but are defined
 | |
|  * in latest SDKs. Use the macro LX_FILE_METADATA_HAS_UID to determine if
 | |
|  * they are missing and if so define them.
 | |
|  */
 | |
| #if !defined(LX_FILE_METADATA_HAS_UID)
 | |
| typedef struct _FILE_STAT_INFORMATION
 | |
| {
 | |
|     LARGE_INTEGER FileId;
 | |
|     LARGE_INTEGER CreationTime;
 | |
|     LARGE_INTEGER LastAccessTime;
 | |
|     LARGE_INTEGER LastWriteTime;
 | |
|     LARGE_INTEGER ChangeTime;
 | |
|     LARGE_INTEGER AllocationSize;
 | |
|     LARGE_INTEGER EndOfFile;
 | |
|     ULONG FileAttributes;
 | |
|     ULONG ReparseTag;
 | |
|     ULONG NumberOfLinks;
 | |
|     ACCESS_MASK EffectiveAccess;
 | |
| } FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION;
 | |
| typedef struct _FILE_STAT_LX_INFORMATION
 | |
| {
 | |
|     LARGE_INTEGER FileId;
 | |
|     LARGE_INTEGER CreationTime;
 | |
|     LARGE_INTEGER LastAccessTime;
 | |
|     LARGE_INTEGER LastWriteTime;
 | |
|     LARGE_INTEGER ChangeTime;
 | |
|     LARGE_INTEGER AllocationSize;
 | |
|     LARGE_INTEGER EndOfFile;
 | |
|     ULONG FileAttributes;
 | |
|     ULONG ReparseTag;
 | |
|     ULONG NumberOfLinks;
 | |
|     ACCESS_MASK EffectiveAccess;
 | |
|     ULONG LxFlags;
 | |
|     ULONG LxUid;
 | |
|     ULONG LxGid;
 | |
|     ULONG LxMode;
 | |
|     ULONG LxDeviceIdMajor;
 | |
|     ULONG LxDeviceIdMinor;
 | |
| } FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION;
 | |
| #endif
 | |
| 
 | |
| NTSTATUS NTAPI NtQueryInformationFile(
 | |
|     HANDLE FileHandle,
 | |
|     PIO_STATUS_BLOCK IoStatusBlock,
 | |
|     PVOID FileInformation,
 | |
|     ULONG Length,
 | |
|     FILE_INFORMATION_CLASS FileInformationClass);
 | |
| 
 | |
| static void wsl_stat_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
 | |
| {
 | |
|     void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
 | |
| 
 | |
|     HANDLE Handle;
 | |
|     WCHAR FilePath[MAX_PATH];
 | |
|     FILE_STAT_INFORMATION StatInfo;
 | |
|     FILE_STAT_LX_INFORMATION StatLxInfo;
 | |
|     FILETIME FileTime;
 | |
|     LONGLONG TimeLo, TimeHi;
 | |
|     IO_STATUS_BLOCK IoStatus;
 | |
|     NTSTATUS Result;
 | |
| 
 | |
|     GetSystemTimeAsFileTime(&FileTime);
 | |
|     TimeLo = ((PLARGE_INTEGER)&FileTime)->QuadPart;
 | |
|     TimeHi = TimeLo + 10000 * 10000/* 10 seconds */;
 | |
| 
 | |
|     StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0",
 | |
|         Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
 | |
| 
 | |
|     Handle = CreateFileW(FilePath,
 | |
|         GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
 | |
|         CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
 | |
|     ASSERT(INVALID_HANDLE_VALUE != Handle);
 | |
| 
 | |
|     for (int repeat = 0; 2 > repeat; repeat++)
 | |
|     {
 | |
|         /* repeat this test to ensure that any caches are tested */
 | |
| 
 | |
|         Result = NtQueryInformationFile(Handle, &IoStatus, &StatInfo, sizeof StatInfo,
 | |
|             68/*FileStatInformation*/);
 | |
|         if (STATUS_SUCCESS == Result)
 | |
|         {
 | |
|             ASSERT(STATUS_SUCCESS == Result);
 | |
|             if (-1 != Flags)
 | |
|                 ASSERT(
 | |
|                     TimeLo <= StatInfo.CreationTime.QuadPart &&
 | |
|                     TimeHi >  StatInfo.CreationTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatInfo.LastAccessTime.QuadPart &&
 | |
|                 TimeHi >  StatInfo.LastAccessTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatInfo.LastWriteTime.QuadPart &&
 | |
|                 TimeHi >  StatInfo.LastWriteTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatInfo.ChangeTime.QuadPart &&
 | |
|                 TimeHi >  StatInfo.ChangeTime.QuadPart);
 | |
|             ASSERT(0 == StatInfo.AllocationSize.QuadPart);
 | |
|             ASSERT(0 == StatInfo.EndOfFile.QuadPart);
 | |
|             //ASSERT(FILE_ATTRIBUTE_ARCHIVE == StatInfo.FileAttributes);
 | |
|             ASSERT(0 == StatInfo.ReparseTag);
 | |
|             ASSERT(1 == StatInfo.NumberOfLinks);
 | |
|             //tlib_printf("%lx %lx", FILE_GENERIC_READ | FILE_GENERIC_WRITE, StatInfo.EffectiveAccess);
 | |
|             //ASSERT((FILE_GENERIC_READ | FILE_GENERIC_WRITE) == StatInfo.EffectiveAccess);
 | |
| 
 | |
|             Result = NtQueryInformationFile(Handle, &IoStatus, &StatLxInfo, sizeof StatLxInfo,
 | |
|                 70/*FileStatLxInformation*/);
 | |
|             ASSERT(STATUS_SUCCESS == Result);
 | |
|             if (-1 != Flags)
 | |
|                 ASSERT(
 | |
|                     TimeLo <= StatLxInfo.CreationTime.QuadPart &&
 | |
|                     TimeHi >  StatLxInfo.CreationTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatLxInfo.LastAccessTime.QuadPart &&
 | |
|                 TimeHi >  StatLxInfo.LastAccessTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatLxInfo.LastWriteTime.QuadPart &&
 | |
|                 TimeHi >  StatLxInfo.LastWriteTime.QuadPart);
 | |
|             ASSERT(
 | |
|                 TimeLo <= StatLxInfo.ChangeTime.QuadPart &&
 | |
|                 TimeHi >  StatLxInfo.ChangeTime.QuadPart);
 | |
|             ASSERT(0 == StatLxInfo.AllocationSize.QuadPart);
 | |
|             ASSERT(0 == StatLxInfo.EndOfFile.QuadPart);
 | |
|             //ASSERT(FILE_ATTRIBUTE_ARCHIVE == StatLxInfo.FileAttributes);
 | |
|             ASSERT(0 == StatLxInfo.ReparseTag);
 | |
|             ASSERT(1 == StatLxInfo.NumberOfLinks);
 | |
|             //tlib_printf("%lx %lx", FILE_GENERIC_READ | FILE_GENERIC_WRITE, StatLxInfo.EffectiveAccess);
 | |
|             //ASSERT((FILE_GENERIC_READ | FILE_GENERIC_WRITE) == StatLxInfo.EffectiveAccess);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ASSERT(
 | |
|                 STATUS_INVALID_INFO_CLASS == Result ||
 | |
|                 STATUS_NOT_IMPLEMENTED == Result/* value returned under WOW64 */);
 | |
|             FspDebugLog(__FUNCTION__ ": only works in Win10 with WSLinux\n");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     CloseHandle(Handle);
 | |
| 
 | |
|     memfs_stop(memfs);
 | |
| }
 | |
| 
 | |
| static void wsl_stat_test(void)
 | |
| {
 | |
|     if (NtfsTests)
 | |
|     {
 | |
|         WCHAR DirBuf[MAX_PATH];
 | |
|         GetTestDirectory(DirBuf);
 | |
|         wsl_stat_dotest(-1, DirBuf, 0);
 | |
|     }
 | |
|     if (WinFspDiskTests)
 | |
|     {
 | |
|         wsl_stat_dotest(MemfsDisk, 0, 0);
 | |
|         wsl_stat_dotest(MemfsDisk, 0, 1000);
 | |
|     }
 | |
|     if (WinFspNetTests)
 | |
|     {
 | |
|         wsl_stat_dotest(MemfsNet, L"\\\\memfs\\share", 0);
 | |
|         wsl_stat_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void wsl_tests(void)
 | |
| {
 | |
|     if (OptFuseExternal)
 | |
|         return;
 | |
| 
 | |
|     TEST_OPT(wsl_stat_test);
 | |
| }
 |