WSL/test/linux/unit_tests/wslpath.c
WSL Team 697572d664 Initial open source commit for WSL.
Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016.

The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021:

Number of commits on the main branch: 2930
Number of contributors: 31

Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
2025-05-15 12:09:45 -07:00

403 lines
10 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
wslpath.c
Abstract:
This file contains tests for the wslpath binary.
--*/
#include "lxtcommon.h"
#include "unittests.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>
#define LXT_NAME "wslpath"
#define WSLPATH_ESCAPE_NAME "wslpath_foo\\:bar"
#define WSLPATH_ESCAPE_NAME_ESCAPED "wslpath_foo\uf05c\uf03abar"
#define WSLPATH_ESCAPE_DIR "/mnt/c/" WSLPATH_ESCAPE_NAME
#define WSLPATH_ESCAPE_DIR_ESCAPED "/mnt/c/" WSLPATH_ESCAPE_NAME_ESCAPED
#define WSLPATH_ESCAPE_DIR_WIN "C:\\" WSLPATH_ESCAPE_NAME_ESCAPED
#define WSLPATH_SYMLINK_TEST_DIR "/mnt/c/symlink_test_dir"
#define WSLPATH_SYMLINK_TEST_TARGET WSLPATH_SYMLINK_TEST_DIR "/target"
#define WSLPATH_SYMLINK_TEST_LINK WSLPATH_SYMLINK_TEST_DIR "/link"
#define WSLPATH_SYMLINK_TEST_DIR_WIN "C:\\symlink_test_dir"
#define WSLPATH_SYMLINK_TEST_TARGET_WIN WSLPATH_SYMLINK_TEST_DIR_WIN "\\target"
#define WSLPATH_SYMLINK_TEST_LINK_WIN WSLPATH_SYMLINK_TEST_DIR_WIN "\\link"
#define WSLPATH_DISTRO_PREFIX "\\\\wsl.localhost\\" LXSS_DISTRO_NAME_TEST
#define WSLPATH_DISTRO_COMPAT_PREFIX "\\\\wsl$\\" LXSS_DISTRO_NAME_TEST
#define WSLPATH_ESCAPE_LX_DIR "/data/" WSLPATH_ESCAPE_NAME
#define WSLPATH_ESCAPE_LX_DIR_WIN WSLPATH_DISTRO_PREFIX "\\data\\" WSLPATH_ESCAPE_NAME_ESCAPED
#define WSLPATH_MOUNT_POINT "/data/wslpath_mount"
LXT_VARIATION_HANDLER WslPathTestDrvFsEscaped;
LXT_VARIATION_HANDLER WslPathTestDrvFsToWinPath;
LXT_VARIATION_HANDLER WslPathTestDrvFsSymlink;
LXT_VARIATION_HANDLER WslPathTestDrvFsFromWinPath;
LXT_VARIATION_HANDLER WslPathTestInvalidMountInfo;
LXT_VARIATION_HANDLER WslPathTestLxEscaped;
LXT_VARIATION_HANDLER WslPathTestLxFromWinPath;
LXT_VARIATION_HANDLER WslPathTestLxToWinPath;
static const LXT_VARIATION g_LxtVariations[] = {
{"WslPath - Windows to DrvFs", WslPathTestDrvFsFromWinPath},
{"WslPath - DrvFs to Windows", WslPathTestDrvFsToWinPath},
{"WslPath - DrvFs escaped characters", WslPathTestDrvFsEscaped},
{"WslPath - DrvFs symlinks", WslPathTestDrvFsSymlink},
{"WslPath - \\\\wsl.localhost to Linux", WslPathTestLxFromWinPath},
{"WslPath - Linux to \\\\wsl.localhost", WslPathTestLxToWinPath},
{"WslPath - \\\\wsl.localhost escaped characters", WslPathTestLxEscaped},
{"WslPath - Invalid mountinfo line", WslPathTestInvalidMountInfo},
};
int WslPathTestEntry(int Argc, char* Argv[])
/*++
Routine Description:
This routine main entry point for the wslpath tests.
Arguments:
Argc - Supplies the number of command line arguments.
Argv - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
LXT_ARGS Args;
int Result;
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
ErrorExit:
LxtUninitialize();
return !LXT_SUCCESS(Result);
}
int WslPathTestDrvFsEscaped(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on DrvFs paths with escaped characters.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckErrno(mkdir(WSLPATH_ESCAPE_DIR, 0777));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_ESCAPE_DIR, WSLPATH_ESCAPE_DIR_WIN, false));
//
// Translating win to drvfs does not unescape, since the escaped characters
// work on drvfs.
//
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_ESCAPE_DIR_WIN, WSLPATH_ESCAPE_DIR_ESCAPED, true));
ErrorExit:
rmdir(WSLPATH_ESCAPE_DIR);
return Result;
}
int WslPathTestDrvFsFromWinPath(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on Windows paths.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckResult(LxtCheckWslPathTranslation("C:\\", "/mnt/c/", true));
LxtCheckResult(LxtCheckWslPathTranslation("C:\\Foo", "/mnt/c/Foo", true));
LxtCheckResult(LxtCheckWslPathTranslation("C:\\Foo\\", "/mnt/c/Foo/", true));
LxtCheckResult(LxtCheckWslPathTranslation("C:\\Foo\\bar", "/mnt/c/Foo/bar", true));
LxtCheckResult(LxtCheckWslPathTranslation("C:/Foo/bar", "/mnt/c/Foo/bar", true));
LxtCheckResult(LxtCheckWslPathTranslation("foo", "foo", true));
LxtCheckResult(LxtCheckWslPathTranslation("foo\\", "foo/", true));
ErrorExit:
return Result;
}
int WslPathTestDrvFsSymlink(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on DrvFs paths with symlinks.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckErrnoZeroSuccess(mkdir(WSLPATH_SYMLINK_TEST_DIR, 0777));
LxtCheckErrnoZeroSuccess(mkdir(WSLPATH_SYMLINK_TEST_TARGET, 0777));
LxtCheckErrnoZeroSuccess(symlink(WSLPATH_SYMLINK_TEST_TARGET, WSLPATH_SYMLINK_TEST_LINK));
//
// Drvfs to Windows follows links.
//
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_SYMLINK_TEST_LINK, WSLPATH_SYMLINK_TEST_TARGET_WIN, false));
//
// Windows to DrvFs is text based so does not.
//
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_SYMLINK_TEST_LINK_WIN, WSLPATH_SYMLINK_TEST_LINK, true));
ErrorExit:
unlink(WSLPATH_SYMLINK_TEST_LINK);
rmdir(WSLPATH_SYMLINK_TEST_TARGET);
rmdir(WSLPATH_SYMLINK_TEST_DIR);
return Result;
}
int WslPathTestDrvFsToWinPath(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on DrvFs paths.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c", "C:\\", false));
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c/", "C:\\", false));
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c/Users", "C:\\Users", false));
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c/Users/", "C:\\Users\\", false));
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c/DOESNOTEXIST/", "C:\\DOESNOTEXIST\\", false));
ErrorExit:
return Result;
}
int WslPathTestInvalidMountInfo(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath's handling of ill-formed mountinfo lines.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
//
// WSL1 does not allow using an empty string as the mount source. This is
// technically a minor bug in WSL1, but it also means this test is not
// relevant, so skip it.
//
if (LxtWslVersion() == 1)
{
LxtLogInfo("Test skipped on WSL1.");
Result = 0;
goto ErrorExit;
}
LxtCheckErrnoZeroSuccess(mkdir(WSLPATH_MOUNT_POINT, 0777));
//
// Using an empty string as the mount source will cause the mountinfo file
// to have a blank field, which neither libmount nor mountutil can parse.
// This should however not break wslpath.
//
LxtCheckErrnoZeroSuccess(mount("", WSLPATH_MOUNT_POINT, "tmpfs", 0, NULL));
LxtCheckResult(LxtCheckWslPathTranslation("/mnt/c", "C:\\", false));
ErrorExit:
umount(WSLPATH_MOUNT_POINT);
rmdir(WSLPATH_MOUNT_POINT);
return Result;
}
int WslPathTestLxEscaped(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on internal Linux paths with escaped characters.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckErrno(mkdir(WSLPATH_ESCAPE_LX_DIR, 0777));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_ESCAPE_LX_DIR, WSLPATH_ESCAPE_LX_DIR_WIN, false));
//
// Translating \\wsl.localhost to Linux does unescape (unlike drvfs).
//
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_ESCAPE_LX_DIR_WIN, WSLPATH_ESCAPE_LX_DIR, true));
ErrorExit:
rmdir(WSLPATH_ESCAPE_LX_DIR);
return Result;
}
int WslPathTestLxFromWinPath(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on \\wsl.localhost paths.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_PREFIX, "/", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_PREFIX "\\", "/", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_PREFIX "\\root", "/root", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_PREFIX "\\proc\\stat", "/proc/stat", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_PREFIX "/proc/stat", "/proc/stat", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_COMPAT_PREFIX "\\proc\\stat", "/proc/stat", true));
LxtCheckResult(LxtCheckWslPathTranslation(WSLPATH_DISTRO_COMPAT_PREFIX, "/", true));
LxtCheckResult(LxtCheckWslPathTranslation("\\\\?\\C:\\Users", "/mnt/c/Users", true));
LxtCheckResult(LxtCheckWslPathTranslation("\\\\?\\C:\\Users\\", "/mnt/c/Users/", true));
LxtCheckResult(LxtCheckWslPathTranslation(".", ".", true));
ErrorExit:
return Result;
}
int WslPathTestLxToWinPath(PLXT_ARGS Args)
/*++
Description:
This routine tests wslpath on internal Linux paths.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckResult(LxtCheckWslPathTranslation("/", WSLPATH_DISTRO_PREFIX "\\", false));
LxtCheckResult(LxtCheckWslPathTranslation("/root", WSLPATH_DISTRO_PREFIX "\\root", false));
LxtCheckResult(LxtCheckWslPathTranslation("/proc/stat", WSLPATH_DISTRO_PREFIX "\\proc\\stat", false));
LxtCheckResult(LxtCheckWslPathTranslation("/proc/1/", WSLPATH_DISTRO_PREFIX "\\proc\\1\\", false));
ErrorExit:
return Result;
}