ReactOS  0.4.15-dev-2703-g05fb0f1
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 
23 static 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 
35 typedef enum WRET // return code of WHERE command
36 {
40 } WRET;
41 
42 static VOID WhereError(UINT nID)
43 {
44  if (!(s_dwFlags & FLAG_Q)) // not quiet mode?
45  ConResPuts(StdErr, nID);
46 }
47 
49 
50 static 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
93  if (!strlist_add(&s_results, path))
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 
150 static 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 
275 static BOOL WhereGetPathExt(strlist_t *ext_list)
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 {
351  LPWSTR value;
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  {
368  DWORD attrs = GetFileAttributesW(name);
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  }
397  ret = WhereFindByVar(pch, pattern + 1);
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;
442  WRET ret = WRET_ERROR;
443  PVOID dummy;
444 
445  ConInitStdStreams(); // Initialize the Console Standard Streams
446 
448  goto quit;
449 
450  if ((s_dwFlags & FLAG_HELP) || !s_patterns.count)
451  {
453  goto quit;
454  }
455 
456  if (DisableWOW)
457  DisableWOW(&dummy);
458 
459  if (!WhereGetPathExt(&s_pathext))
460  {
462  goto quit;
463  }
464 
465  ret = WRET_SUCCESS;
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 
481 quit:
485  return ret;
486 }
#define FLAG_F
Definition: where.c:20
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
static int argc
Definition: ServiceArgs.c:12
Definition: pdh_main.c:93
BOOL(CALLBACK * WHERE_CALLBACK)(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:48
static BOOL CALLBACK WhereSearchRecursiveCallback(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:151
#define FLAG_HELP
Definition: where.c:17
static int strlist_add(strlist_t *plist, LPCWSTR psz)
Definition: strlist.h:30
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
TCHAR szTime[64]
Definition: solitaire.cpp:19
WRET
Definition: where.c:35
#define TRUE
Definition: types.h:120
GLsizei const GLchar ** path
Definition: glext.h:7234
#define LOCALE_USER_DEFAULT
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
#define FLAG_T
Definition: where.c:21
#define free
Definition: debug_ros.c:5
void quit(int argc, const char *argv[])
Definition: cmds.c:1606
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:615
#define CALLBACK
Definition: compat.h:35
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
static BOOL WhereGetVariable(LPCWSTR name, LPWSTR *value)
Definition: where.c:181
static BOOL CALLBACK WherePrintPath(LPCWSTR pattern, LPCWSTR path, PWIN32_FIND_DATAW data)
Definition: where.c:84
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
static strlist_t s_patterns
Definition: where.c:25
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
#define IDS_USAGE
Definition: resource.h:3
#define argv
Definition: mplay32.c:18
static BOOL WhereGetPathExt(strlist_t *ext_list)
Definition: where.c:275
BOOL WINAPI FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, OUT LPFILETIME lpLocalFileTime)
Definition: time.c:221
#define BOOL
Definition: nt_native.h:43
#define IDS_BAD_PATHPAT
Definition: resource.h:9
int32_t INT
Definition: typedefs.h:58
#define IS_DOTS(pch)
Definition: where.c:30
#define pch(ap)
Definition: match.c:418
HANDLE hKernel32
Definition: locale.c:13
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
#define IDS_PATHPAT_WITH_R
Definition: resource.h:8
#define IDS_BAD_NAME
Definition: resource.h:14
static VOID WhereError(UINT nID)
Definition: where.c:42
static DWORD s_dwFlags
Definition: where.c:23
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
#define IDS_OUTOFMEMORY
Definition: resource.h:10
char ext[3]
Definition: mkdosfs.c:358
Definition: getopt.h:108
#define FLAG_R
Definition: where.c:18
static strlist_t s_pathext
Definition: where.c:27
#define strlist_default
Definition: strlist.h:17
#define IDS_BAD_ENVVAR
Definition: resource.h:11
unsigned int dir
Definition: maze.c:112
#define IDS_TYPE_HELP
Definition: resource.h:6
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
INT wmain(INT argc, WCHAR **argv)
Definition: where.c:435
MmuTrapHandler callback[0x30]
Definition: mmuobject.c:44
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
#define IDS_BAD_ARG
Definition: resource.h:2
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:188
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define IDS_CANT_FOUND
Definition: resource.h:12
#define _countof(array)
Definition: sndvol32.h:68
static BOOL WhereDoOption(DWORD flag, LPCWSTR option)
Definition: where.c:202
static int strlist_find_i(strlist_t *plist, LPCWSTR psz)
Definition: strlist.h:57
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define IDS_FILE_INFO
Definition: resource.h:4
static strlist_t s_results
Definition: where.c:26
#define IDS_WANT_VALUE
Definition: resource.h:5
int ret
#define str_clone
Definition: strlist.h:10
static void strlist_destroy(strlist_t *plist)
Definition: strlist.h:47
static const WCHAR L[]
Definition: oid.c:1250
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
#define IDS_BAD_DIR
Definition: resource.h:13
static LPWSTR s_pszRecursiveDir
Definition: where.c:24
ULONG LowPart
Definition: typedefs.h:106
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
GLsizei const GLfloat * value
Definition: glext.h:6069
#define wcsrchr
Definition: compat.h:16
static BOOL WhereIsRecursiveDirOK(LPCWSTR name)
Definition: where.c:359
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
Definition: lcformat.c:979
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
#define IDS_ENVPAT_WITH_R
Definition: resource.h:7
unsigned int count
Definition: strlist.h:15
#define FILE_ATTRIBUTE_VIRTUAL
Definition: IDataObject.cpp:11
static DWORD path_len
Definition: batch.c:31
LPCWSTR szPath
Definition: env.c:37
unsigned char dummy
Definition: maze.c:118
#define IDS_NOT_FOUND
Definition: resource.h:3
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
static BOOL WhereSearchGeneric(LPCWSTR pattern, LPWSTR path, size_t path_len, BOOL bDir, WHERE_CALLBACK callback)
Definition: where.c:51
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
static BOOL WhereSearch(LPCWSTR pattern, strlist_t *dirlist)
Definition: where.c:170
static BOOL WhereParseCommandLine(INT argc, WCHAR **argv)
Definition: where.c:214
#define StdOut
Definition: fc.c:14
Definition: name.c:38
static BOOL WhereDoPattern(LPWSTR pattern)
Definition: where.c:383
static BOOL WhereSearchRecursive(LPCWSTR pattern, LPCWSTR dir)
Definition: where.c:157
#define DEFAULT_PATHEXT
Definition: where.c:33
#define ConInitStdStreams()
Definition: fc.c:13
#define GetProcAddress(x, y)
Definition: compat.h:612
#define malloc
Definition: debug_ros.c:4
static BOOL WhereSearchFiles(LPCWSTR pattern, LPCWSTR dir)
Definition: where.c:126
static BOOL WhereFindByVar(LPCWSTR pattern, LPCWSTR name)
Definition: where.c:349
#define towupper(c)
Definition: wctype.h:99
WCHAR * LPWSTR
Definition: xmlstorage.h:184
IN PCTCH IN DWORD cch
Definition: pager.h:34
static LPWSTR strlist_get_at(strlist_t *plist, unsigned int i)
Definition: strlist.h:25
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:614
INT WINAPI GetTimeFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, INT cchOut)
Definition: lcformat.c:1079
#define IDS_TOO_MANY
Definition: resource.h:15
#define FLAG_Q
Definition: where.c:19
LONGLONG QuadPart
Definition: typedefs.h:114
GLubyte * pattern
Definition: glext.h:7787
static BOOL WhereFindByDirs(LPCWSTR pattern, LPWSTR dirs)
Definition: where.c:309
#define StdErr
Definition: fc.c:15
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502