From: Elizabeth Figura zfigura@codeweavers.com
Based on patches by Erich E. Hoover. --- programs/cmd/Makefile.in | 2 +- programs/cmd/directory.c | 75 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/programs/cmd/Makefile.in b/programs/cmd/Makefile.in index cca40b84011..cc913733c8b 100644 --- a/programs/cmd/Makefile.in +++ b/programs/cmd/Makefile.in @@ -1,5 +1,5 @@ MODULE = cmd.exe -IMPORTS = shell32 user32 advapi32 +IMPORTS = shell32 user32 advapi32 kernelbase
EXTRADLLFLAGS = -mconsole -municode
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c index 985a9899cec..e95d57e9d19 100644 --- a/programs/cmd/directory.c +++ b/programs/cmd/directory.c @@ -22,6 +22,10 @@ #define WIN32_LEAN_AND_MEAN
#include "wcmd.h" +#define WIN32_NO_STATUS +#include <pathcch.h> +#include <winioctl.h> +#include <ddk/ntifs.h> #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(cmd); @@ -232,6 +236,56 @@ static void WCMD_getfileowner(WCHAR *filename, WCHAR *owner, int ownerlen) { return; }
+static void output_reparse_target(const WCHAR *dir, const WCHAR *filename) +{ + REPARSE_DATA_BUFFER *data; + HANDLE file; + WCHAR *path; + DWORD size; + BOOL ret; + + PathAllocCombine(dir, filename, PATHCCH_ALLOW_LONG_PATHS, &path); + file = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); + if (file == INVALID_HANDLE_VALUE) + { + WARN("failed to open %s, error %lu\n", debugstr_w(path), GetLastError()); + LocalFree(path); + return; + } + + data = malloc(1024); + ret = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0, data, 1024, &size, NULL); + if (!ret && GetLastError() == ERROR_MORE_DATA) + { + size = sizeof(REPARSE_DATA_BUFFER) + data->ReparseDataLength; + data = realloc(data, size); + ret = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0, data, size, &size, NULL); + } + + if (ret) + { + if (data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) + { + size_t offset = data->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR); + WCMD_output(L" [%1]", data->MountPointReparseBuffer.PathBuffer + offset); + } + else if (data->ReparseTag == IO_REPARSE_TAG_SYMLINK) + { + size_t offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR); + WCMD_output(L" [%1]", data->SymbolicLinkReparseBuffer.PathBuffer + offset); + } + } + else + { + WARN("failed to get reparse point from %s, error %lu\n", debugstr_w(path), GetLastError()); + } + + free(data); + LocalFree(path); + CloseHandle(file); +} + /***************************************************************************** * WCMD_list_directory * @@ -404,10 +458,19 @@ static RETURN_CODE WCMD_list_directory (DIRECTORY_STACK *inputparms, int level, dir_count++;
if (!bare) { - WCMD_output (L"%1 %2 <DIR> ", datestring, timestring); + if ((fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + && (fd[i].dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) + WCMD_output(L"%1 %2 <JUNCTION> ", datestring, timestring); + else if ((fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + && (fd[i].dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + WCMD_output(L"%1 %2 <SYMLINKD> ", datestring, timestring); + else + WCMD_output(L"%1 %2 <DIR> ", datestring, timestring); if (shortname) WCMD_output(L"%1!-13s!", fd[i].cAlternateFileName); if (usernames) WCMD_output(L"%1!-23s!", username); WCMD_output(L"%1",fd[i].cFileName); + if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + output_reparse_target(inputparms->dirName, fd[i].cFileName); } else { if (!((lstrcmpW(fd[i].cFileName, L".") == 0) || (lstrcmpW(fd[i].cFileName, L"..") == 0))) { @@ -423,11 +486,17 @@ static RETURN_CODE WCMD_list_directory (DIRECTORY_STACK *inputparms, int level, file_size.u.HighPart = fd[i].nFileSizeHigh; byte_count.QuadPart += file_size.QuadPart; if (!bare) { - WCMD_output (L"%1 %2 %3!14s! ", datestring, timestring, - WCMD_filesize64(file_size.QuadPart)); + if ((fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + && (fd[i].dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + WCMD_output(L"%1 %2 <SYMLINK> ", datestring, timestring); + else + WCMD_output(L"%1 %2 %3!14s! ", datestring, timestring, + WCMD_filesize64(file_size.QuadPart)); if (shortname) WCMD_output(L"%1!-13s!", fd[i].cAlternateFileName); if (usernames) WCMD_output(L"%1!-23s!", username); WCMD_output(L"%1",fd[i].cFileName); + if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + output_reparse_target(inputparms->dirName, fd[i].cFileName); } else { WCMD_output(L"%1%2", recurse ? inputparms->dirName : L"", fd[i].cFileName); }