mirror of
https://github.com/reactos/reactos.git
synced 2025-02-20 15:35:04 +00:00
[CMDUTILS][WHERE] Implement WHERE command (#3642)
WHERE is a Windows command that finds the file location from a executable file name. This PR implements it in ReactOS. CORE-17443
This commit is contained in:
parent
04e9251612
commit
55060911e4
7 changed files with 639 additions and 0 deletions
|
@ -25,6 +25,7 @@ add_subdirectory(taskkill)
|
|||
add_subdirectory(tasklist)
|
||||
add_subdirectory(timeout)
|
||||
add_subdirectory(tree)
|
||||
add_subdirectory(where)
|
||||
add_subdirectory(whoami)
|
||||
add_subdirectory(wmic)
|
||||
add_subdirectory(wscript)
|
||||
|
|
7
base/applications/cmdutils/where/CMakeLists.txt
Normal file
7
base/applications/cmdutils/where/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||
|
||||
add_executable(where where.c where.rc)
|
||||
set_module_type(where win32cui UNICODE)
|
||||
target_link_libraries(where conutils ${PSEH_LIB})
|
||||
add_importlibs(where msvcrt kernel32)
|
||||
add_cd_file(TARGET where DESTINATION reactos/system32 FOR all)
|
52
base/applications/cmdutils/where/lang/en-US.rc
Normal file
52
base/applications/cmdutils/where/lang/en-US.rc
Normal file
|
@ -0,0 +1,52 @@
|
|||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_USAGE "Usage: WHERE [options] pattern...\n\
|
||||
\n\
|
||||
Description:\n\
|
||||
Shows the location of the file(s) specified by the pattern(s).\n\
|
||||
By default, this tool searches by using the pattern(s) and the paths\n\
|
||||
of the PATH environment variable.\n\
|
||||
\n\
|
||||
Options:\n\
|
||||
/F Displays all matched file(s) in double quotes.\n\
|
||||
/Q Quiet mode. Doesn't show any files and messages.\n\
|
||||
/R dir Starts searching from the specified directory and recursively\n\
|
||||
performs the search.\n\
|
||||
/T Shows the file size and last modified date of all matched\n\
|
||||
files.\n\
|
||||
pattern Specifies the pattern to search files. Wildcards * and ? can\n\
|
||||
be used. ""$env:pattern"" and ""path:pattern"" formats can also\n\
|
||||
be used, where ""env"" is an environment variable and\n\
|
||||
the search is done in the paths of the ""env"" environment\n\
|
||||
variable. Don't use these formats with /R. The search is also\n\
|
||||
performed by adding the extension of the PATHEXT variable to\n\
|
||||
the pattern.\n\
|
||||
/? Displays this message.\n\
|
||||
\n\
|
||||
NOTE: This tool returns an error level of 0 if the search was successful,\n\
|
||||
1 if the file was not found, and 2 if there was an error.\n\
|
||||
\n\
|
||||
Example:\n\
|
||||
WHERE myfile*.exe\n\
|
||||
WHERE /F /T mspaint\n\
|
||||
WHERE $WINDIR:notepad myfile???\n\
|
||||
WHERE C:\\ReactOS;C:\\ReactOS\\system32:exp*.exe\n\
|
||||
WHERE /R ""C:\\Program Files"" *.dll\n"
|
||||
|
||||
IDS_BAD_ARG "ERROR: Invalid argument - '%ls'.\n"
|
||||
IDS_NOT_FOUND "INFO: Could not find files for the given pattern(s).\n"
|
||||
IDS_FILE_INFO "%10I64u %-12ls %-12ls %ls\n"
|
||||
IDS_WANT_VALUE "ERROR: Value is needed for '%ls'.\n"
|
||||
IDS_TYPE_HELP "Type ""WHERE /?"" for usage help.\n"
|
||||
IDS_ENVPAT_WITH_R "ERROR: ""$env:pattern"" cannot be used with /R.\n"
|
||||
IDS_PATHPAT_WITH_R "ERROR: ""path:pattern"" format cannot be used with /R.\n"
|
||||
IDS_BAD_PATHPAT "ERROR: Invalid pattern is specified in ""path:pattern"".\n"
|
||||
IDS_OUTOFMEMORY "ERROR: Out of memory.\n"
|
||||
IDS_BAD_ENVVAR "ERROR: Environment variable ""%ls"" is not found.\n"
|
||||
IDS_CANT_FOUND "ERROR: The system could not find the file specified.\n"
|
||||
IDS_BAD_DIR "ERROR: Invalid directory is specified.\n"
|
||||
IDS_BAD_NAME "ERROR: The filename, directory name or volume label syntax is wrong.\n"
|
||||
IDS_TOO_MANY "ERROR: '%ls' option is not allowed more than '%u' time(s).\n"
|
||||
END
|
15
base/applications/cmdutils/where/resource.h
Normal file
15
base/applications/cmdutils/where/resource.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#define IDS_USAGE 100
|
||||
#define IDS_BAD_ARG 101
|
||||
#define IDS_NOT_FOUND 103
|
||||
#define IDS_FILE_INFO 104
|
||||
#define IDS_WANT_VALUE 106
|
||||
#define IDS_TYPE_HELP 107
|
||||
#define IDS_ENVPAT_WITH_R 108
|
||||
#define IDS_PATHPAT_WITH_R 109
|
||||
#define IDS_BAD_PATHPAT 110
|
||||
#define IDS_OUTOFMEMORY 111
|
||||
#define IDS_BAD_ENVVAR 112
|
||||
#define IDS_CANT_FOUND 113
|
||||
#define IDS_BAD_DIR 114
|
||||
#define IDS_BAD_NAME 115
|
||||
#define IDS_TOO_MANY 116
|
66
base/applications/cmdutils/where/strlist.h
Normal file
66
base/applications/cmdutils/where/strlist.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* PROJECT: ReactOS WHERE command
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Providing string list
|
||||
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define str_clone _wcsdup
|
||||
|
||||
typedef struct strlist_t
|
||||
{
|
||||
LPWSTR *ppsz;
|
||||
unsigned int count;
|
||||
} strlist_t;
|
||||
#define strlist_default { NULL, 0 }
|
||||
|
||||
static inline void strlist_init(strlist_t *plist)
|
||||
{
|
||||
plist->ppsz = NULL;
|
||||
plist->count = 0;
|
||||
}
|
||||
|
||||
static inline LPWSTR strlist_get_at(strlist_t *plist, unsigned int i)
|
||||
{
|
||||
return plist->ppsz[i];
|
||||
}
|
||||
|
||||
static int strlist_add(strlist_t *plist, LPCWSTR psz)
|
||||
{
|
||||
LPWSTR *ppsz, clone = str_clone(psz);
|
||||
if (!clone)
|
||||
return 0;
|
||||
ppsz = (LPWSTR *)realloc(plist->ppsz, (plist->count + 1) * sizeof(LPWSTR));
|
||||
if (!ppsz)
|
||||
{
|
||||
free(clone);
|
||||
return 0;
|
||||
}
|
||||
plist->ppsz = ppsz;
|
||||
plist->ppsz[plist->count] = clone;
|
||||
++(plist->count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void strlist_destroy(strlist_t *plist)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < plist->count; ++i)
|
||||
free(plist->ppsz[i]);
|
||||
plist->count = 0;
|
||||
free(plist->ppsz);
|
||||
plist->ppsz = NULL;
|
||||
}
|
||||
|
||||
static inline int strlist_find_i(strlist_t *plist, LPCWSTR psz)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < plist->count; ++i)
|
||||
{
|
||||
if (_wcsicmp(plist->ppsz[i], psz) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
486
base/applications/cmdutils/where/where.c
Normal file
486
base/applications/cmdutils/where/where.c
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* PROJECT: ReactOS WHERE command
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Search executable files
|
||||
* COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <strsafe.h>
|
||||
#include <conutils.h>
|
||||
#include "strlist.h" // strlist_...
|
||||
#include "resource.h"
|
||||
|
||||
#define FLAG_HELP (1 << 0) // "/?"
|
||||
#define FLAG_R (1 << 1) // recursive directory
|
||||
#define FLAG_Q (1 << 2) // quiet mode
|
||||
#define FLAG_F (1 << 3) // double quote
|
||||
#define FLAG_T (1 << 4) // detailed info
|
||||
|
||||
static DWORD s_dwFlags = 0;
|
||||
static LPWSTR s_pszRecursiveDir = NULL;
|
||||
static strlist_t s_patterns = strlist_default;
|
||||
static strlist_t s_results = strlist_default;
|
||||
static strlist_t s_pathext = strlist_default;
|
||||
|
||||
// is it either "." or ".."?
|
||||
#define IS_DOTS(pch) \
|
||||
(*(pch) == L'.' && ((pch)[1] == 0 || ((pch)[1] == L'.' && (pch)[2] == 0)))
|
||||
|
||||
#define DEFAULT_PATHEXT L".com;.exe;.bat;.cmd"
|
||||
|
||||
typedef enum WRET // return code of WHERE command
|
||||
{
|
||||
WRET_SUCCESS = 0,
|
||||
WRET_NOT_FOUND = 1,
|
||||
WRET_ERROR = 2
|
||||
} WRET;
|
||||
|
||||
static VOID WhereError(UINT nID)
|
||||
{
|
||||
if (!(s_dwFlags & FLAG_Q)) // not quiet mode?
|
||||
ConResPuts(StdErr, nID);
|
||||
}
|
||||
|
||||
typedef BOOL (CALLBACK *WHERE_CALLBACK)(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data);
|
||||
|
||||
static BOOL
|
||||
WhereSearchGeneric(LPCWSTR pattern, LPWSTR path, size_t path_len, BOOL bDir,
|
||||
WHERE_CALLBACK callback)
|
||||
{
|
||||
LPWSTR pch;
|
||||
size_t cch;
|
||||
BOOL ret;
|
||||
WIN32_FIND_DATAW data;
|
||||
HANDLE hFind = FindFirstFileExW(path, FindExInfoStandard, &data, FindExSearchNameMatch,
|
||||
NULL, 0);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return TRUE; // not found
|
||||
|
||||
pch = wcsrchr(path, L'\\') + 1;
|
||||
cch = path_len - (pch - path);
|
||||
do
|
||||
{
|
||||
if (bDir != !!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
continue;
|
||||
if (bDir && IS_DOTS(data.cFileName))
|
||||
continue; // ignore "." and ".."
|
||||
if (data.dwFileAttributes & FILE_ATTRIBUTE_VIRTUAL)
|
||||
continue; // ignore virtual
|
||||
|
||||
StringCchCopyW(pch, cch, data.cFileName); // build full path
|
||||
|
||||
ret = callback(pattern, path, &data);
|
||||
if (!ret) // out of memory
|
||||
break;
|
||||
} while (FindNextFileW(hFind, &data));
|
||||
FindClose(hFind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK WherePrintPath(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
|
||||
{
|
||||
WCHAR szPath[MAX_PATH + 2], szDate[32], szTime[32];
|
||||
LARGE_INTEGER FileSize;
|
||||
FILETIME ftLocal;
|
||||
SYSTEMTIME st;
|
||||
|
||||
if (strlist_find_i(&s_results, path) >= 0)
|
||||
return TRUE; // already exists
|
||||
if (!strlist_add(&s_results, path))
|
||||
return FALSE; // out of memory
|
||||
if (s_dwFlags & FLAG_Q) // quiet mode?
|
||||
return TRUE;
|
||||
|
||||
if (s_dwFlags & FLAG_T) // print detailed info
|
||||
{
|
||||
// convert date/time
|
||||
FileTimeToLocalFileTime(&data->ftLastWriteTime, &ftLocal);
|
||||
FileTimeToSystemTime(&ftLocal, &st);
|
||||
// get date/time strings
|
||||
GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, _countof(szDate));
|
||||
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szTime, _countof(szTime));
|
||||
// set size
|
||||
FileSize.LowPart = data->nFileSizeLow;
|
||||
FileSize.HighPart = data->nFileSizeHigh;
|
||||
// print
|
||||
if (s_dwFlags & FLAG_F) // double quote
|
||||
StringCchPrintfW(szPath, _countof(szPath), L"\"%s\"", path);
|
||||
else
|
||||
StringCchCopyW(szPath, _countof(szPath), path);
|
||||
ConResPrintf(StdOut, IDS_FILE_INFO, FileSize.QuadPart, szDate, szTime, szPath);
|
||||
}
|
||||
else // print path only
|
||||
{
|
||||
if (s_dwFlags & FLAG_F) // double quote
|
||||
ConPrintf(StdOut, L"\"%ls\"\n", path);
|
||||
else
|
||||
ConPrintf(StdOut, L"%ls\n", path);
|
||||
}
|
||||
return TRUE; // success
|
||||
}
|
||||
|
||||
static BOOL WhereSearchFiles(LPCWSTR pattern, LPCWSTR dir)
|
||||
{
|
||||
INT iExt;
|
||||
size_t cch;
|
||||
WCHAR szPath[MAX_PATH];
|
||||
StringCchCopyW(szPath, _countof(szPath), dir);
|
||||
StringCchCatW(szPath, _countof(szPath), L"\\");
|
||||
StringCchCatW(szPath, _countof(szPath), pattern);
|
||||
cch = wcslen(szPath);
|
||||
|
||||
for (iExt = 0; iExt < s_pathext.count; ++iExt)
|
||||
{
|
||||
szPath[cch] = 0; // cut off extension
|
||||
// append extension
|
||||
StringCchCatW(szPath, _countof(szPath), strlist_get_at(&s_pathext, iExt));
|
||||
|
||||
if (!WhereSearchGeneric(pattern, szPath, _countof(szPath), FALSE, WherePrintPath))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WhereSearchRecursive(LPCWSTR pattern, LPCWSTR dir);
|
||||
|
||||
static BOOL CALLBACK
|
||||
WhereSearchRecursiveCallback(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
|
||||
{
|
||||
return WhereSearchRecursive(pattern, path);
|
||||
}
|
||||
|
||||
// FIXME: Too slow. Optimize for speed.
|
||||
static BOOL WhereSearchRecursive(LPCWSTR pattern, LPCWSTR dir)
|
||||
{
|
||||
WCHAR szPath[MAX_PATH];
|
||||
if (!WhereSearchFiles(pattern, dir))
|
||||
return FALSE; // out of memory
|
||||
|
||||
// build path with wildcard
|
||||
StringCchCopyW(szPath, _countof(szPath), dir);
|
||||
StringCchCatW(szPath, _countof(szPath), L"\\*");
|
||||
return WhereSearchGeneric(pattern, szPath, _countof(szPath), TRUE,
|
||||
WhereSearchRecursiveCallback);
|
||||
}
|
||||
|
||||
static BOOL WhereSearch(LPCWSTR pattern, strlist_t *dirlist)
|
||||
{
|
||||
UINT iDir;
|
||||
for (iDir = 0; iDir < dirlist->count; ++iDir)
|
||||
{
|
||||
if (!WhereSearchFiles(pattern, strlist_get_at(dirlist, iDir)))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WhereGetVariable(LPCWSTR name, LPWSTR *value)
|
||||
{
|
||||
DWORD cch = GetEnvironmentVariableW(name, NULL, 0);
|
||||
if (cch == 0) // variable not found
|
||||
{
|
||||
*value = NULL;
|
||||
if (!(s_dwFlags & FLAG_Q)) // not quiet mode?
|
||||
ConResPrintf(StdErr, IDS_BAD_ENVVAR, name);
|
||||
return TRUE; // it is error, but continue the task
|
||||
}
|
||||
|
||||
*value = malloc(cch * sizeof(WCHAR));
|
||||
if (!*value || !GetEnvironmentVariableW(name, *value, cch))
|
||||
{
|
||||
free(*value);
|
||||
*value = NULL;
|
||||
return FALSE; // error
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WhereDoOption(DWORD flag, LPCWSTR option)
|
||||
{
|
||||
if (s_dwFlags & flag)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_TOO_MANY, option, 1);
|
||||
ConResPuts(StdErr, IDS_TYPE_HELP);
|
||||
return FALSE;
|
||||
}
|
||||
s_dwFlags |= flag;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WhereParseCommandLine(INT argc, WCHAR** argv)
|
||||
{
|
||||
INT iArg;
|
||||
for (iArg = 1; iArg < argc; ++iArg)
|
||||
{
|
||||
LPWSTR arg = argv[iArg];
|
||||
if (arg[0] == L'/' || arg[0] == L'-')
|
||||
{
|
||||
if (arg[2] == 0)
|
||||
{
|
||||
switch (towupper(arg[1]))
|
||||
{
|
||||
case L'?':
|
||||
if (!WhereDoOption(FLAG_HELP, L"/?"))
|
||||
return FALSE;
|
||||
continue;
|
||||
case L'F':
|
||||
if (!WhereDoOption(FLAG_F, L"/F"))
|
||||
return FALSE;
|
||||
continue;
|
||||
case L'Q':
|
||||
if (!WhereDoOption(FLAG_Q, L"/Q"))
|
||||
return FALSE;
|
||||
continue;
|
||||
case L'T':
|
||||
if (!WhereDoOption(FLAG_T, L"/T"))
|
||||
return FALSE;
|
||||
continue;
|
||||
case L'R':
|
||||
{
|
||||
if (!WhereDoOption(FLAG_R, L"/R"))
|
||||
return FALSE;
|
||||
if (iArg + 1 < argc)
|
||||
{
|
||||
++iArg;
|
||||
s_pszRecursiveDir = argv[iArg];
|
||||
continue;
|
||||
}
|
||||
ConResPrintf(StdErr, IDS_WANT_VALUE, L"/R");
|
||||
ConResPuts(StdErr, IDS_TYPE_HELP);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
ConResPrintf(StdErr, IDS_BAD_ARG, argv[iArg]);
|
||||
ConResPuts(StdErr, IDS_TYPE_HELP);
|
||||
return FALSE;
|
||||
}
|
||||
else // pattern?
|
||||
{
|
||||
if (!strlist_add(&s_patterns, argv[iArg])) // append pattern
|
||||
{
|
||||
ConResPuts(StdErr, IDS_OUTOFMEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE; // success
|
||||
}
|
||||
|
||||
static BOOL WhereGetPathExt(strlist_t *ext_list)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
LPWSTR pszPathExt, ext;
|
||||
DWORD cchPathExt = GetEnvironmentVariableW(L"PATHEXT", NULL, 0);
|
||||
|
||||
pszPathExt = (cchPathExt ? malloc(cchPathExt * sizeof(WCHAR)) : str_clone(DEFAULT_PATHEXT));
|
||||
if (!pszPathExt)
|
||||
return FALSE; // out of memory
|
||||
|
||||
if (cchPathExt)
|
||||
GetEnvironmentVariableW(L"PATHEXT", pszPathExt, cchPathExt);
|
||||
|
||||
if (!strlist_add(ext_list, L"")) // add empty extension for normal search
|
||||
{
|
||||
strlist_destroy(ext_list);
|
||||
free(pszPathExt);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (ext = wcstok(pszPathExt, L";"); ext; ext = wcstok(NULL, L";")) // for all extensions
|
||||
{
|
||||
if (!strlist_add(ext_list, ext)) // add extension to ext_list
|
||||
{
|
||||
strlist_destroy(ext_list);
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(pszPathExt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WhereFindByDirs(LPCWSTR pattern, LPWSTR dirs)
|
||||
{
|
||||
BOOL ret;
|
||||
size_t cch;
|
||||
WCHAR szPath[MAX_PATH];
|
||||
LPWSTR dir, pch;
|
||||
strlist_t dirlist = strlist_default;
|
||||
|
||||
GetCurrentDirectoryW(_countof(szPath), szPath);
|
||||
if (!strlist_add(&dirlist, szPath))
|
||||
return FALSE; // out of memory
|
||||
|
||||
for (dir = wcstok(dirs, L";"); dir; dir = wcstok(NULL, L";"))
|
||||
{
|
||||
if (*dir == L'"') // began from '"'
|
||||
{
|
||||
pch = wcschr(++dir, L'"'); // find '"'
|
||||
if (*pch)
|
||||
*pch = 0; // cut off
|
||||
}
|
||||
|
||||
if (*dir != '\\' && dir[1] != L':')
|
||||
continue; // relative path
|
||||
|
||||
cch = wcslen(dir);
|
||||
if (cch > 0 && dir[cch - 1] == L'\\')
|
||||
dir[cch - 1] = 0; // remove trailing backslash
|
||||
|
||||
if (!strlist_add(&dirlist, dir))
|
||||
{
|
||||
strlist_destroy(&dirlist);
|
||||
return FALSE; // out of memory
|
||||
}
|
||||
}
|
||||
|
||||
ret = WhereSearch(pattern, &dirlist);
|
||||
strlist_destroy(&dirlist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WhereFindByVar(LPCWSTR pattern, LPCWSTR name)
|
||||
{
|
||||
LPWSTR value;
|
||||
BOOL ret = WhereGetVariable(name, &value);
|
||||
if (ret && value)
|
||||
ret = WhereFindByDirs(pattern, value);
|
||||
free(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WhereIsRecursiveDirOK(LPCWSTR name)
|
||||
{
|
||||
if (wcschr(name, L';') != NULL)
|
||||
{
|
||||
WhereError(IDS_BAD_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD attrs = GetFileAttributesW(name);
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES) // file not found
|
||||
{
|
||||
WhereError(IDS_CANT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
if (!(attrs & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
WhereError(IDS_BAD_DIR);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL WhereDoPattern(LPWSTR pattern)
|
||||
{
|
||||
BOOL ret;
|
||||
LPWSTR pch = wcsrchr(pattern, L':');
|
||||
if (pch)
|
||||
{
|
||||
*pch++ = 0;
|
||||
if (pattern[0] == L'$') // $env:pattern
|
||||
{
|
||||
if (s_dwFlags & FLAG_R) // recursive?
|
||||
{
|
||||
WhereError(IDS_ENVPAT_WITH_R);
|
||||
return FALSE;
|
||||
}
|
||||
ret = WhereFindByVar(pch, pattern + 1);
|
||||
}
|
||||
else // path:pattern
|
||||
{
|
||||
if (s_dwFlags & FLAG_R) // recursive?
|
||||
{
|
||||
WhereError(IDS_PATHPAT_WITH_R);
|
||||
return FALSE;
|
||||
}
|
||||
if (wcschr(pch, L'\\') != NULL) // found '\\'?
|
||||
{
|
||||
WhereError(IDS_BAD_PATHPAT);
|
||||
return FALSE;
|
||||
}
|
||||
ret = WhereFindByDirs(pch, pattern);
|
||||
}
|
||||
}
|
||||
else if (s_pszRecursiveDir) // recursive
|
||||
{
|
||||
WCHAR szPath[MAX_PATH];
|
||||
|
||||
if (!WhereIsRecursiveDirOK(s_pszRecursiveDir))
|
||||
return FALSE;
|
||||
|
||||
GetFullPathNameW(s_pszRecursiveDir, _countof(szPath), szPath, NULL);
|
||||
|
||||
ret = WhereSearchRecursive(pattern, szPath);
|
||||
}
|
||||
else // otherwise
|
||||
{
|
||||
ret = WhereFindByVar(pattern, L"PATH");
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
WhereError(IDS_OUTOFMEMORY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INT wmain(INT argc, WCHAR **argv)
|
||||
{
|
||||
typedef BOOL (WINAPI *FN_DISABLE_WOW)(PVOID *);
|
||||
HANDLE hKernel32 = GetModuleHandleA("kernel32");
|
||||
FN_DISABLE_WOW DisableWOW =
|
||||
(FN_DISABLE_WOW)GetProcAddress(hKernel32, "Wow64DisableWow64FsRedirection");
|
||||
DWORD iPattern;
|
||||
WRET ret = WRET_ERROR;
|
||||
PVOID dummy;
|
||||
|
||||
ConInitStdStreams(); // Initialize the Console Standard Streams
|
||||
|
||||
if (!WhereParseCommandLine(argc, argv))
|
||||
goto quit;
|
||||
|
||||
if ((s_dwFlags & FLAG_HELP) || !s_patterns.count)
|
||||
{
|
||||
ConResPuts(StdOut, IDS_USAGE);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (DisableWOW)
|
||||
DisableWOW(&dummy);
|
||||
|
||||
if (!WhereGetPathExt(&s_pathext))
|
||||
{
|
||||
WhereError(IDS_OUTOFMEMORY);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
ret = WRET_SUCCESS;
|
||||
for (iPattern = 0; iPattern < s_patterns.count; ++iPattern)
|
||||
{
|
||||
if (!WhereDoPattern(strlist_get_at(&s_patterns, iPattern)))
|
||||
{
|
||||
ret = WRET_ERROR;
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_results.count)
|
||||
{
|
||||
WhereError(IDS_NOT_FOUND);
|
||||
ret = WRET_NOT_FOUND;
|
||||
}
|
||||
|
||||
quit:
|
||||
strlist_destroy(&s_results);
|
||||
strlist_destroy(&s_patterns);
|
||||
strlist_destroy(&s_pathext);
|
||||
return ret;
|
||||
}
|
12
base/applications/cmdutils/where/where.rc
Normal file
12
base/applications/cmdutils/where/where.rc
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <windef.h>
|
||||
#include "resource.h"
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS WHERE Command"
|
||||
#define REACTOS_STR_INTERNAL_NAME "where"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "where.exe"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
#pragma code_page(65001) /* UTF-8 */
|
||||
#ifdef LANGUAGE_EN_US
|
||||
#include "lang/en-US.rc"
|
||||
#endif
|
Loading…
Reference in a new issue