ReactOS 0.4.15-dev-7928-g68a8619
where.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS WHERE command
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Search executable files
5 * COPYRIGHT: Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8#include <stdlib.h>
9#include <windef.h>
10#include <winbase.h>
11#include <winnls.h>
12#include <strsafe.h>
13#include <conutils.h>
14#include "strlist.h" // strlist_...
15#include "resource.h"
16
17#define FLAG_HELP (1 << 0) // "/?"
18#define FLAG_R (1 << 1) // recursive directory
19#define FLAG_Q (1 << 2) // quiet mode
20#define FLAG_F (1 << 3) // double quote
21#define FLAG_T (1 << 4) // detailed info
22
23static DWORD s_dwFlags = 0;
28
29// is it either "." or ".."?
30#define IS_DOTS(pch) \
31 (*(pch) == L'.' && ((pch)[1] == 0 || ((pch)[1] == L'.' && (pch)[2] == 0)))
32
33#define DEFAULT_PATHEXT L".com;.exe;.bat;.cmd"
34
35typedef enum WRET // return code of WHERE command
36{
39 WRET_ERROR = 2
41
42static VOID WhereError(UINT nID)
43{
44 if (!(s_dwFlags & FLAG_Q)) // not quiet mode?
45 ConResPuts(StdErr, nID);
46}
47
49
50static BOOL
53{
54 LPWSTR pch;
55 size_t cch;
56 BOOL ret;
59 NULL, 0);
60 if (hFind == INVALID_HANDLE_VALUE)
61 return TRUE; // not found
62
63 pch = wcsrchr(path, L'\\') + 1;
64 cch = path_len - (pch - path);
65 do
66 {
67 if (bDir != !!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
68 continue;
69 if (bDir && IS_DOTS(data.cFileName))
70 continue; // ignore "." and ".."
71 if (data.dwFileAttributes & FILE_ATTRIBUTE_VIRTUAL)
72 continue; // ignore virtual
73
74 StringCchCopyW(pch, cch, data.cFileName); // build full path
75
77 if (!ret) // out of memory
78 break;
79 } while (FindNextFileW(hFind, &data));
80 FindClose(hFind);
81 return ret;
82}
83
85{
86 WCHAR szPath[MAX_PATH + 2], szDate[32], szTime[32];
88 FILETIME ftLocal;
89 SYSTEMTIME st;
90
91 if (strlist_find_i(&s_results, path) >= 0)
92 return TRUE; // already exists
94 return FALSE; // out of memory
95 if (s_dwFlags & FLAG_Q) // quiet mode?
96 return TRUE;
97
98 if (s_dwFlags & FLAG_T) // print detailed info
99 {
100 // convert date/time
101 FileTimeToLocalFileTime(&data->ftLastWriteTime, &ftLocal);
102 FileTimeToSystemTime(&ftLocal, &st);
103 // get date/time strings
104 GetDateFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, _countof(szDate));
106 // set size
107 FileSize.LowPart = data->nFileSizeLow;
108 FileSize.HighPart = data->nFileSizeHigh;
109 // print
110 if (s_dwFlags & FLAG_F) // double quote
112 else
115 }
116 else // print path only
117 {
118 if (s_dwFlags & FLAG_F) // double quote
119 ConPrintf(StdOut, L"\"%ls\"\n", path);
120 else
121 ConPrintf(StdOut, L"%ls\n", path);
122 }
123 return TRUE; // success
124}
125
127{
128 INT iExt;
129 size_t cch;
134 cch = wcslen(szPath);
135
136 for (iExt = 0; iExt < s_pathext.count; ++iExt)
137 {
138 szPath[cch] = 0; // cut off extension
139 // append extension
141
143 return FALSE;
144 }
145 return TRUE;
146}
147
149
150static BOOL CALLBACK
152{
154}
155
156// FIXME: Too slow. Optimize for speed.
158{
161 return FALSE; // out of memory
162
163 // build path with wildcard
168}
169
171{
172 UINT iDir;
173 for (iDir = 0; iDir < dirlist->count; ++iDir)
174 {
175 if (!WhereSearchFiles(pattern, strlist_get_at(dirlist, iDir)))
176 return FALSE;
177 }
178 return TRUE;
179}
180
182{
184 if (cch == 0) // variable not found
185 {
186 *value = NULL;
187 if (!(s_dwFlags & FLAG_Q)) // not quiet mode?
189 return TRUE; // it is error, but continue the task
190 }
191
192 *value = malloc(cch * sizeof(WCHAR));
194 {
195 free(*value);
196 *value = NULL;
197 return FALSE; // error
198 }
199 return TRUE;
200}
201
203{
204 if (s_dwFlags & flag)
205 {
208 return FALSE;
209 }
210 s_dwFlags |= flag;
211 return TRUE;
212}
213
215{
216 INT iArg;
217 for (iArg = 1; iArg < argc; ++iArg)
218 {
219 LPWSTR arg = argv[iArg];
220 if (arg[0] == L'/' || arg[0] == L'-')
221 {
222 if (arg[2] == 0)
223 {
224 switch (towupper(arg[1]))
225 {
226 case L'?':
227 if (!WhereDoOption(FLAG_HELP, L"/?"))
228 return FALSE;
229 continue;
230 case L'F':
231 if (!WhereDoOption(FLAG_F, L"/F"))
232 return FALSE;
233 continue;
234 case L'Q':
235 if (!WhereDoOption(FLAG_Q, L"/Q"))
236 return FALSE;
237 continue;
238 case L'T':
239 if (!WhereDoOption(FLAG_T, L"/T"))
240 return FALSE;
241 continue;
242 case L'R':
243 {
244 if (!WhereDoOption(FLAG_R, L"/R"))
245 return FALSE;
246 if (iArg + 1 < argc)
247 {
248 ++iArg;
249 s_pszRecursiveDir = argv[iArg];
250 continue;
251 }
254 return FALSE;
255 }
256 }
257 }
260 return FALSE;
261 }
262 else // pattern?
263 {
264 if (!strlist_add(&s_patterns, argv[iArg])) // append pattern
265 {
267 return FALSE;
268 }
269 }
270 }
271
272 return TRUE; // success
273}
274
276{
277 BOOL ret = TRUE;
278 LPWSTR pszPathExt, ext;
279 DWORD cchPathExt = GetEnvironmentVariableW(L"PATHEXT", NULL, 0);
280
281 pszPathExt = (cchPathExt ? malloc(cchPathExt * sizeof(WCHAR)) : str_clone(DEFAULT_PATHEXT));
282 if (!pszPathExt)
283 return FALSE; // out of memory
284
285 if (cchPathExt)
286 GetEnvironmentVariableW(L"PATHEXT", pszPathExt, cchPathExt);
287
288 if (!strlist_add(ext_list, L"")) // add empty extension for normal search
289 {
290 strlist_destroy(ext_list);
291 free(pszPathExt);
292 return FALSE;
293 }
294
295 for (ext = wcstok(pszPathExt, L";"); ext; ext = wcstok(NULL, L";")) // for all extensions
296 {
297 if (!strlist_add(ext_list, ext)) // add extension to ext_list
298 {
299 strlist_destroy(ext_list);
300 ret = FALSE;
301 break;
302 }
303 }
304
305 free(pszPathExt);
306 return ret;
307}
308
310{
311 BOOL ret;
312 size_t cch;
314 LPWSTR dir, pch;
315 strlist_t dirlist = strlist_default;
316
318 if (!strlist_add(&dirlist, szPath))
319 return FALSE; // out of memory
320
321 for (dir = wcstok(dirs, L";"); dir; dir = wcstok(NULL, L";"))
322 {
323 if (*dir == L'"') // began from '"'
324 {
325 pch = wcschr(++dir, L'"'); // find '"'
326 if (*pch)
327 *pch = 0; // cut off
328 }
329
330 if (*dir != '\\' && dir[1] != L':')
331 continue; // relative path
332
333 cch = wcslen(dir);
334 if (cch > 0 && dir[cch - 1] == L'\\')
335 dir[cch - 1] = 0; // remove trailing backslash
336
337 if (!strlist_add(&dirlist, dir))
338 {
339 strlist_destroy(&dirlist);
340 return FALSE; // out of memory
341 }
342 }
343
344 ret = WhereSearch(pattern, &dirlist);
345 strlist_destroy(&dirlist);
346 return ret;
347}
348
350{
353 if (ret && value)
355 free(value);
356 return ret;
357}
358
360{
361 if (wcschr(name, L';') != NULL)
362 {
364 return FALSE;
365 }
366 else
367 {
369 if (attrs == INVALID_FILE_ATTRIBUTES) // file not found
370 {
372 return FALSE;
373 }
374 if (!(attrs & FILE_ATTRIBUTE_DIRECTORY))
375 {
377 return FALSE;
378 }
379 return TRUE;
380 }
381}
382
384{
385 BOOL ret;
386 LPWSTR pch = wcsrchr(pattern, L':');
387 if (pch)
388 {
389 *pch++ = 0;
390 if (pattern[0] == L'$') // $env:pattern
391 {
392 if (s_dwFlags & FLAG_R) // recursive?
393 {
395 return FALSE;
396 }
398 }
399 else // path:pattern
400 {
401 if (s_dwFlags & FLAG_R) // recursive?
402 {
404 return FALSE;
405 }
406 if (wcschr(pch, L'\\') != NULL) // found '\\'?
407 {
409 return FALSE;
410 }
412 }
413 }
414 else if (s_pszRecursiveDir) // recursive
415 {
417
419 return FALSE;
420
422
424 }
425 else // otherwise
426 {
427 ret = WhereFindByVar(pattern, L"PATH");
428 }
429
430 if (!ret)
432 return ret;
433}
434
436{
437 typedef BOOL (WINAPI *FN_DISABLE_WOW)(PVOID *);
438 HANDLE hKernel32 = GetModuleHandleA("kernel32");
439 FN_DISABLE_WOW DisableWOW =
440 (FN_DISABLE_WOW)GetProcAddress(hKernel32, "Wow64DisableWow64FsRedirection");
441 DWORD iPattern;
443 PVOID dummy;
444
445 ConInitStdStreams(); // Initialize the Console Standard Streams
446
448 goto quit;
449
451 {
453 goto quit;
454 }
455
456 if (DisableWOW)
457 DisableWOW(&dummy);
458
460 {
462 goto quit;
463 }
464
466 for (iPattern = 0; iPattern < s_patterns.count; ++iPattern)
467 {
468 if (!WhereDoPattern(strlist_get_at(&s_patterns, iPattern)))
469 {
470 ret = WRET_ERROR;
471 goto quit;
472 }
473 }
474
475 if (!s_results.count)
476 {
479 }
480
481quit:
485 return ret;
486}
#define FILE_ATTRIBUTE_VIRTUAL
Definition: IDataObject.cpp:11
static int argc
Definition: ServiceArgs.c:12
unsigned int dir
Definition: maze.c:112
#define IDS_USAGE
Definition: resource.h:3
#define ConInitStdStreams()
Definition: fc.c:13
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
#define StdOut
Definition: fc.c:14
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
#define StdErr
Definition: fc.c:15
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define IDS_CANT_FOUND
Definition: resource.h:12
#define IDS_BAD_ENVVAR
Definition: resource.h:11
#define IDS_BAD_ARG
Definition: resource.h:2
#define IDS_WANT_VALUE
Definition: resource.h:5
#define IDS_PATHPAT_WITH_R
Definition: resource.h:8
#define IDS_TOO_MANY
Definition: resource.h:15
#define IDS_BAD_DIR
Definition: resource.h:13
#define IDS_OUTOFMEMORY
Definition: resource.h:10
#define IDS_FILE_INFO
Definition: resource.h:4
#define IDS_BAD_PATHPAT
Definition: resource.h:9
#define IDS_ENVPAT_WITH_R
Definition: resource.h:7
#define IDS_TYPE_HELP
Definition: resource.h:6
#define IDS_NOT_FOUND
Definition: resource.h:3
#define IDS_BAD_NAME
Definition: resource.h:14
static BOOL WhereDoPattern(LPWSTR pattern)
Definition: where.c:383
static strlist_t s_results
Definition: where.c:26
static BOOL WhereGetVariable(LPCWSTR name, LPWSTR *value)
Definition: where.c:181
static strlist_t s_patterns
Definition: where.c:25
BOOL(CALLBACK * WHERE_CALLBACK)(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:48
#define FLAG_T
Definition: where.c:21
static BOOL WhereSearchGeneric(LPCWSTR pattern, LPWSTR path, size_t path_len, BOOL bDir, WHERE_CALLBACK callback)
Definition: where.c:51
static BOOL WhereSearchFiles(LPCWSTR pattern, LPCWSTR dir)
Definition: where.c:126
static BOOL CALLBACK WherePrintPath(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:84
static BOOL WhereFindByVar(LPCWSTR pattern, LPCWSTR name)
Definition: where.c:349
static BOOL WhereDoOption(DWORD flag, LPCWSTR option)
Definition: where.c:202
#define FLAG_F
Definition: where.c:20
#define IS_DOTS(pch)
Definition: where.c:30
static BOOL CALLBACK WhereSearchRecursiveCallback(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:151
static BOOL WhereIsRecursiveDirOK(LPCWSTR name)
Definition: where.c:359
static BOOL WhereGetPathExt(strlist_t *ext_list)
Definition: where.c:275
static BOOL WhereSearch(LPCWSTR pattern, strlist_t *dirlist)
Definition: where.c:170
static LPWSTR s_pszRecursiveDir
Definition: where.c:24
#define FLAG_R
Definition: where.c:18
#define FLAG_Q
Definition: where.c:19
static BOOL WhereSearchRecursive(LPCWSTR pattern, LPCWSTR dir)
Definition: where.c:157
WRET
Definition: where.c:36
@ WRET_NOT_FOUND
Definition: where.c:38
@ WRET_ERROR
Definition: where.c:39
@ WRET_SUCCESS
Definition: where.c:37
static BOOL WhereFindByDirs(LPCWSTR pattern, LPWSTR dirs)
Definition: where.c:309
static VOID WhereError(UINT nID)
Definition: where.c:42
static strlist_t s_pathext
Definition: where.c:27
static BOOL WhereParseCommandLine(INT argc, WCHAR **argv)
Definition: where.c:214
static DWORD s_dwFlags
Definition: where.c:23
#define FLAG_HELP
Definition: where.c:17
#define DEFAULT_PATHEXT
Definition: where.c:33
void quit(int argc, const char *argv[])
Definition: cmds.c:1606
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define wcschr
Definition: compat.h:17
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:756
#define wcsrchr
Definition: compat.h:16
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:755
#define GetProcAddress(x, y)
Definition: compat.h:753
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
static const WCHAR *const ext[]
Definition: module.c:53
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
HANDLE WINAPI FindFirstFileExW(IN LPCWSTR lpFileName, IN FINDEX_INFO_LEVELS fInfoLevelId, OUT LPVOID lpFindFileData, IN FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, IN DWORD dwAdditionalFlags)
Definition: find.c:649
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:188
BOOL WINAPI FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, OUT LPFILETIME lpLocalFileTime)
Definition: time.c:221
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLubyte * pattern
Definition: glext.h:7787
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
INT WINAPI GetTimeFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, INT cchOut)
Definition: lcformat.c:1093
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
Definition: lcformat.c:993
#define pch(ap)
Definition: match.c:418
LPCWSTR szPath
Definition: env.c:37
HANDLE hKernel32
Definition: locale.c:13
static DWORD path_len
Definition: batch.c:31
static IPrintDialogCallback callback
Definition: printdlg.c:326
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
#define argv
Definition: mplay32.c:18
unsigned int UINT
Definition: ndis.h:50
#define BOOL
Definition: nt_native.h:43
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define LOCALE_USER_DEFAULT
#define L(x)
Definition: ntvdm.h:50
int wmain()
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
#define _countof(array)
Definition: sndvol32.h:68
TCHAR szTime[64]
Definition: solitaire.cpp:20
static LPWSTR strlist_get_at(strlist_t *plist, unsigned int i)
Definition: strlist.h:25
#define strlist_default
Definition: strlist.h:17
static void strlist_destroy(strlist_t *plist)
Definition: strlist.h:47
static int strlist_find_i(strlist_t *plist, LPCWSTR psz)
Definition: strlist.h:57
#define str_clone
Definition: strlist.h:10
static int strlist_add(strlist_t *plist, LPCWSTR psz)
Definition: strlist.h:30
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
Definition: name.c:39
Definition: getopt.h:109
unsigned int count
Definition: strlist.h:15
#define towupper(c)
Definition: wctype.h:99
int32_t INT
Definition: typedefs.h:58
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
Definition: pdh_main.c:94
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
int ret
@ FindExSearchNameMatch
Definition: winbase.h:1134
@ FindExInfoStandard
Definition: winbase.h:1128
#define WINAPI
Definition: msvc.h:6
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185