ReactOS  0.4.15-dev-499-g1f31905
internal.c
Go to the documentation of this file.
1 /*
2  * INTERNAL.C - command.com internal commands.
3  *
4  *
5  * History:
6  *
7  * 17/08/94 (Tim Norman)
8  * started.
9  *
10  * 08/08/95 (Matt Rains)
11  * i have cleaned up the source code. changes now bring this source into
12  * guidelines for recommended programming practice.
13  *
14  * cd()
15  * started.
16  *
17  * dir()
18  * i have added support for file attributes to the DIR() function. the
19  * routine adds "d" (directory) and "r" (read only) output. files with the
20  * system attribute have the filename converted to lowercase. files with
21  * the hidden attribute are not displayed.
22  *
23  * i have added support for directorys. now if the directory attribute is
24  * detected the file size if replaced with the string "<dir>".
25  *
26  * ver()
27  * started.
28  *
29  * md()
30  * started.
31  *
32  * rd()
33  * started.
34  *
35  * del()
36  * started.
37  *
38  * does not support wildcard selection.
39  *
40  * todo: add delete directory support.
41  * add recursive directory delete support.
42  *
43  * ren()
44  * started.
45  *
46  * does not support wildcard selection.
47  *
48  * todo: add rename directory support.
49  *
50  * a general structure has been used for the cd, rd and md commands. this
51  * will be better in the long run. it is too hard to maintain such diverse
52  * functions when you are involved in a group project like this.
53  *
54  * 12/14/95 (Tim Norman)
55  * fixed DIR so that it will stick \*.* if a directory is specified and
56  * that it will stick on .* if a file with no extension is specified or
57  * *.* if it ends in a \
58  *
59  * 1/6/96 (Tim Norman)
60  * added an isatty call to DIR so it won't prompt for keypresses unless
61  * stdin and stdout are the console.
62  *
63  * changed parameters to be mutually consistent to make calling the
64  * functions easier
65  *
66  * rem()
67  * started.
68  *
69  * doskey()
70  * started.
71  *
72  * 01/22/96 (Oliver Mueller)
73  * error messages are now handled by perror.
74  *
75  * 02/05/96 (Tim Norman)
76  * converted all functions to accept first/rest parameters
77  *
78  * 07/26/96 (Tim Norman)
79  * changed return values to int instead of void
80  *
81  * path() started.
82  *
83  * 12/23/96 (Aaron Kaufman)
84  * rewrote dir() to mimic MS-DOS's dir
85  *
86  * 01/28/97 (Tim Norman)
87  * cleaned up Aaron's DIR code
88  *
89  * 06/13/97 (Tim Norman)
90  * moved DIR code to dir.c
91  * re-implemented Aaron's DIR code
92  *
93  * 06/14/97 (Steffan Kaiser)
94  * ctrl-break handling
95  * bug fixes
96  *
97  * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
98  * added config.h include
99  *
100  * 03-Dec-1998 (Eric Kohl)
101  * Replaced DOS calls by Win32 calls.
102  *
103  * 08-Dec-1998 (Eric Kohl)
104  * Added help texts ("/?").
105  *
106  * 18-Dec-1998 (Eric Kohl)
107  * Added support for quoted arguments (cd "program files").
108  *
109  * 07-Jan-1999 (Eric Kohl)
110  * Clean up.
111  *
112  * 26-Jan-1999 (Eric Kohl)
113  * Replaced remaining CRT io functions by Win32 io functions.
114  * Unicode safe!
115  *
116  * 30-Jan-1999 (Eric Kohl)
117  * Added "cd -" feature. Changes to the previous directory.
118  *
119  * 15-Mar-1999 (Eric Kohl)
120  * Fixed bug in "cd -" feature. If the previous directory was a root
121  * directory, it was ignored.
122  *
123  * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
124  * Improved chdir/cd command.
125  *
126  * 02-Apr-2004 (Magnus Olsen <magnus@greatlord.com>)
127  * Remove all hard code string so they can be
128  * translate to other langues.
129  *
130  * 19-Jul-2005 (Brandon Turner <turnerb7@msu.edu>)
131  * Rewrite the CD, it working as Windows 2000 CMD
132  *
133  * 19-Jul-2005 (Magnus Olsen <magnus@greatlord.com>)
134  * Add SetRootPath and GetRootPath
135  *
136  * 14-Jul-2007 (Pierre Schweitzer <heis_spiter@hotmail.com>)
137  * Added commands help display to help command (ex. : "help cmd")
138  */
139 
140 #include "precomp.h"
141 
142 #ifdef INCLUDE_CMD_CHDIR
143 
144 /* helper functions for getting current path from drive
145  without changing drive. Return code 0 = ok, 1 = fail.
146  INT GetRootPath("C:",outbuffer,chater size of outbuffer);
147  the first param can have any size, if the the two frist
148  letter are not a drive with : it will get Currentpath on
149  current drive exactly as GetCurrentDirectory does.
150  */
151 
152 INT GetRootPath(TCHAR *InPath,TCHAR *OutPath,INT size)
153 {
154  if (InPath[0] && InPath[1] == _T(':'))
155  {
156  INT t=0;
157 
158  if ((InPath[0] >= _T('0')) && (InPath[0] <= _T('9')))
159  {
160  t = (InPath[0] - _T('0')) +28;
161  }
162 
163  if ((InPath[0] >= _T('a')) && (InPath[0] <= _T('z')))
164  {
165  t = (InPath[0] - _T('a')) +1;
166  InPath[0] = t + _T('A') - 1;
167  }
168 
169  if ((InPath[0] >= _T('A')) && (InPath[0] <= _T('Z')))
170  {
171  t = (InPath[0] - _T('A')) +1;
172  }
173 
174  return _tgetdcwd(t,OutPath,size) == NULL;
175  }
176 
177  /* Get current directory */
178  return !GetCurrentDirectory(size,OutPath);
179 }
180 
181 
182 BOOL SetRootPath(TCHAR *oldpath, TCHAR *InPath)
183 {
184  TCHAR OutPath[MAX_PATH];
185  TCHAR OutPathTemp[MAX_PATH];
186 
187  StripQuotes(InPath);
188 
189  /* Retrieve the full path name from the (possibly relative) InPath */
190  if (GetFullPathName(InPath, MAX_PATH, OutPathTemp, NULL) == 0)
191  goto Fail;
192 
193  /* Convert the full path to its correct case.
194  * Example: c:\windows\SYSTEM32 => C:\WINDOWS\System32 */
195  GetPathCase(OutPathTemp, OutPath);
196 
197  /* Use _tchdir, since unlike SetCurrentDirectory it updates
198  * the current-directory-on-drive environment variables. */
199  if (_tchdir(OutPath) != 0)
200  goto Fail;
201 
202  /* Keep original drive in ordinary CD/CHDIR (without /D switch). */
203  if (oldpath != NULL && _tcsncicmp(OutPath, oldpath, 2) != 0)
204  SetCurrentDirectory(oldpath);
205 
206  return TRUE;
207 
208 Fail:
210  nErrorLevel = 1;
211  return FALSE;
212 }
213 
214 
215 /*
216  * CD / CHDIR
217  *
218  */
220 {
221  BOOL bChangeDrive = FALSE;
222  LPTSTR tmp;
223  TCHAR szCurrent[MAX_PATH];
224 
225  /* Filter out special cases first */
226 
227  /* Print Help */
228  if (!_tcsncmp(param, _T("/?"), 2))
229  {
231  return 0;
232  }
233 
234  /* Remove extra quotes and strip trailing whitespace */
236  tmp = param + _tcslen(param) - 1;
237  while (tmp > param && _istspace(*tmp))
238  tmp--;
239  *(tmp + 1) = _T('\0');
240 
241  /* Set Error Level to Success */
242  nErrorLevel = 0;
243 
244  /* Print Current Directory on a disk */
245  if (_tcslen(param) == 2 && param[1] == _T(':'))
246  {
247  if (GetRootPath(param, szCurrent, MAX_PATH))
248  {
250  return 1;
251  }
252  ConOutPrintf(_T("%s\n"), szCurrent);
253  return 0;
254  }
255 
256  /* Get Current Directory */
257  GetCurrentDirectory(MAX_PATH, szCurrent);
258  if (param[0] == _T('\0'))
259  {
260  ConOutPrintf(_T("%s\n"), szCurrent);
261  return 0;
262  }
263 
264  /* Input String Contains /D Switch */
265  if (!_tcsncicmp(param, _T("/D"), 2))
266  {
267  bChangeDrive = TRUE;
268  param += 2;
269  while (_istspace(*param))
270  param++;
271  }
272 
273  if (!SetRootPath(bChangeDrive ? NULL : szCurrent, param))
274  {
275  nErrorLevel = 1;
276  return 1;
277  }
278 
279  return 0;
280 }
281 
282 #endif
283 
284 #ifdef INCLUDE_CMD_MKDIR
285 
286 /* Helper function for mkdir to make directories in a path.
287 Don't use the api to decrease dependence on libs */
288 BOOL
289 MakeFullPath(TCHAR * DirPath)
290 {
292  TCHAR *p = DirPath;
293  INT_PTR n;
294 
295  if (CreateDirectory(DirPath, NULL))
296  return TRUE;
297  else if (GetLastError() != ERROR_PATH_NOT_FOUND)
298  return FALSE;
299 
300  /* got ERROR_PATH_NOT_FOUND, so try building it up one component at a time */
301  if (p[0] && p[1] == _T(':'))
302  p += 2;
303  while (*p == _T('\\'))
304  p++; /* skip drive root */
305  do
306  {
307  p = _tcschr(p, _T('\\'));
308  n = p ? p++ - DirPath : _tcslen(DirPath);
309  _tcsncpy(path, DirPath, n);
310  path[n] = _T('\0');
311  if ( !CreateDirectory(path, NULL) &&
313  {
314  return FALSE;
315  }
316  } while (p != NULL);
317 
318  return TRUE;
319 }
320 
321 /*
322  * MD / MKDIR
323  */
325 {
326  LPTSTR *p;
327  INT argc, i;
328  if (!_tcsncmp (param, _T("/?"), 2))
329  {
331  return 0;
332  }
333 
334  p = split (param, &argc, FALSE, FALSE);
335  if (argc == 0)
336  {
338  freep(p);
339  nErrorLevel = 1;
340  return 1;
341  }
342 
343  nErrorLevel = 0;
344  for (i = 0; i < argc; i++)
345  {
346  if (!MakeFullPath(p[i]))
347  {
349  {
351  }
352  else
353  {
354  ErrorMessage (GetLastError(), _T("MD"));
355  }
356  nErrorLevel = 1;
357  }
358  }
359 
360  freep (p);
361  return nErrorLevel;
362 }
363 #endif
364 
365 
366 #ifdef INCLUDE_CMD_RMDIR
367 /*
368  * RD / RMDIR
369  */
371 {
373  TCHAR TempFileName[MAX_PATH];
374  HANDLE hFile;
377  _tcscat(Base,_T("\\*"));
378  hFile = FindFirstFile(Base, &f);
379  Base[_tcslen(Base) - 1] = _T('\0');
381  {
382  do
383  {
384  if (!_tcscmp(f.cFileName, _T(".")) ||
385  !_tcscmp(f.cFileName, _T("..")))
386  continue;
387  _tcscpy(TempFileName,Base);
388  _tcscat(TempFileName,f.cFileName);
389 
390  if (f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
391  DeleteFolder(TempFileName);
392  else
393  {
395  if (!DeleteFile(TempFileName))
396  {
397  FindClose (hFile);
398  return 0;
399  }
400  }
401 
402  }while (FindNextFile (hFile, &f));
403  FindClose (hFile);
404  }
405  return RemoveDirectory(FileName);
406 }
407 
409 {
410  TCHAR ch;
411  INT args;
412  INT dirCount;
413  LPTSTR *arg;
414  INT i;
415  BOOL RD_SUB = FALSE;
416  BOOL RD_QUIET = FALSE;
417  INT res;
418  INT nError = 0;
419  TCHAR szFullPath[MAX_PATH];
420 
421  if (!_tcsncmp (param, _T("/?"), 2))
422  {
424  return 0;
425  }
426 
427  arg = split (param, &args, FALSE, FALSE);
428  dirCount = 0;
429 
430  /* check for options anywhere in command line */
431  for (i = 0; i < args; i++)
432  {
433  if (*arg[i] == _T('/'))
434  {
435  /*found a command, but check to make sure it has something after it*/
436  if (_tcslen (arg[i]) == 2)
437  {
438  ch = _totupper (arg[i][1]);
439 
440  if (ch == _T('S'))
441  {
442  RD_SUB = TRUE;
443  }
444  else if (ch == _T('Q'))
445  {
446  RD_QUIET = TRUE;
447  }
448  }
449  }
450  else
451  {
452  dirCount++;
453  }
454  }
455 
456  if (dirCount == 0)
457  {
458  /* No folder to remove */
460  freep(arg);
461  return 1;
462  }
463 
464  for (i = 0; i < args; i++)
465  {
466  if (*arg[i] == _T('/'))
467  continue;
468 
469  if (RD_SUB)
470  {
471  /* ask if they want to delete everything in the folder */
472  if (!RD_QUIET)
473  {
475  if (res == PROMPT_NO || res == PROMPT_BREAK)
476  {
477  nError = 1;
478  continue;
479  }
480  if (res == PROMPT_ALL)
481  RD_QUIET = TRUE;
482  }
483  /* get the folder name */
484  GetFullPathName(arg[i],MAX_PATH,szFullPath,NULL);
485 
486  /* remove trailing \ if any, but ONLY if dir is not the root dir */
487  if (_tcslen (szFullPath) >= 2 && szFullPath[_tcslen (szFullPath) - 1] == _T('\\'))
488  szFullPath[_tcslen(szFullPath) - 1] = _T('\0');
489 
490  res = DeleteFolder(szFullPath);
491  }
492  else
493  {
494  res = RemoveDirectory(arg[i]);
495  }
496 
497  if (!res)
498  {
499  /* Couldn't delete the folder, print out the error */
500  nError = GetLastError();
501  ErrorMessage(nError, _T("RD"));
502  }
503  }
504 
505  freep (arg);
506  return nError;
507 }
508 #endif
509 
510 
511 /*
512  * set the exitflag to true
513  */
515 {
516  if (!_tcsncmp(param, _T("/?"), 2))
517  {
519 
520  /* Just make sure we don't exit */
521  bExit = FALSE;
522  return 0;
523  }
524 
525  if (_tcsnicmp(param, _T("/b"), 2) == 0)
526  {
527  param += 2;
528 
529  /*
530  * If a current batch file is running, exit it,
531  * otherwise exit this command interpreter instance.
532  */
533  if (bc)
534  ExitBatch();
535  else
536  bExit = TRUE;
537  }
538  else
539  {
540  /* Exit this command interpreter instance */
541  bExit = TRUE;
542  }
543 
544  /* Search for an optional exit code */
545  while (_istspace(*param))
546  param++;
547 
548  /* Set the errorlevel to the exit code */
549  if (_istdigit(*param))
551 
552  return 0;
553 }
554 
555 #ifdef INCLUDE_CMD_REM
556 /*
557  * does nothing
558  */
560 {
561  if (!_tcsncmp (param, _T("/?"), 2))
562  {
564  }
565 
566  return 0;
567 }
568 #endif /* INCLUDE_CMD_REM */
569 
570 
572 {
574  return 0;
575 }
576 
577 /* EOF */
INT nErrorLevel
Definition: cmd.c:157
VOID PrintCommandList(VOID)
Definition: cmdtable.c:234
static int argc
Definition: ServiceArgs.c:12
#define _istdigit
Definition: tchar.h:1494
#define TRUE
Definition: types.h:120
#define ConErrFormatMessage(MessageId,...)
Definition: console.h:57
#define STRING_RMDIR_HELP
Definition: resource.h:165
VOID error_invalid_drive(VOID)
Definition: error.c:119
LPBATCH_CONTEXT bc
Definition: batch.c:66
INT cmd_mkdir(LPTSTR param)
Definition: internal.c:324
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
static VOID ErrorMessage(DWORD dwErrorCode, LPWSTR szFormat,...)
Definition: attrib.c:51
#define ConErrResPuts(uID)
Definition: console.h:39
#define RemoveDirectory
Definition: winbase.h:3735
_TCHAR * _tcsncpy(_TCHAR *dst, const _TCHAR *src, size_t n)
Definition: tcsncpy.h:9
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2373
GLdouble n
Definition: glext.h:7729
GLdouble GLdouble t
Definition: gl.h:2047
INT CommandShowCommands(LPTSTR param)
Definition: internal.c:571
#define INVALID_HANDLE_VALUE
Definition: compat.h:400
_TCHAR * _tcscpy(_TCHAR *to, const _TCHAR *from)
Definition: tcscpy.h:8
#define PROMPT_BREAK
Definition: cmd.h:291
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define STRING_ERROR_REQ_PARAM_MISSING
Definition: resource.h:10
#define ConOutPrintf(szStr,...)
Definition: console.h:42
void * arg
Definition: msvc.h:10
#define STRING_MD_ERROR2
Definition: resource.h:221
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
#define PROMPT_NO
Definition: cmd.h:288
#define _totupper
Definition: tchar.h:1509
int32_t INT_PTR
Definition: typedefs.h:63
#define DeleteFile
Definition: winbase.h:3604
Definition: match.c:390
static VOID StripQuotes(LPSTR in)
Definition: cmdcons.c:116
#define PROMPT_ALL
Definition: cmd.h:290
int32_t INT
Definition: typedefs.h:57
BOOL DeleteFolder(LPTSTR FileName)
Definition: internal.c:370
CHAR * LPTSTR
Definition: xmlstorage.h:192
INT cmd_chdir(LPTSTR param)
Definition: internal.c:219
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 const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int BOOL
Definition: ntddk_ex.h:94
#define _tcsncicmp
Definition: tchar.h:1429
#define _tcsnicmp
Definition: xmlstorage.h:207
VOID error_req_param_missing(VOID)
Definition: error.c:112
#define GetCurrentDirectory
Definition: winbase.h:3645
#define STRING_DEL_HELP2
Definition: resource.h:101
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
static VOID freep(LPSTR *p)
Definition: cmdcons.c:98
smooth NULL
Definition: ftsmooth.c:416
VOID ExitBatch(VOID)
Definition: batch.c:186
#define FindFirstFile
Definition: winbase.h:3622
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
INT FilePromptYNA(UINT)
Definition: misc.c:664
char TCHAR
Definition: xmlstorage.h:189
GLfloat f
Definition: glext.h:7540
#define _T(x)
Definition: vfdio.h:22
GLsizeiptr size
Definition: glext.h:5919
#define SetFileAttributes
Definition: winbase.h:3749
#define FindNextFile
Definition: winbase.h:3628
INT CommandRem(LPTSTR param)
Definition: internal.c:559
BOOL MakeFullPath(TCHAR *DirPath)
Definition: internal.c:289
GLfloat param
Definition: glext.h:5796
BOOL SetRootPath(TCHAR *oldpath, TCHAR *InPath)
Definition: internal.c:182
#define MAX_PATH
Definition: compat.h:26
VOID GetPathCase(TCHAR *, TCHAR *)
Definition: misc.c:86
static LPSTR * split(LPSTR s, LPINT args)
Definition: cmdcons.c:163
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
_TCHAR * _tgetdcwd(int drive, _TCHAR *buf, int size)
Definition: getdcwd.c:22
INT cmd_rmdir(LPTSTR param)
Definition: internal.c:408
INT CommandExit(LPTSTR param)
Definition: internal.c:514
#define GetFullPathName
Definition: winbase.h:3661
_In_ HANDLE hFile
Definition: mswsock.h:90
Definition: hiveinit.c:368
#define STRING_MKDIR_HELP
Definition: resource.h:139
#define STRING_EXIT_HELP
Definition: resource.h:126
#define f
Definition: ke_i.h:83
int CDECL _ttoi(const _TCHAR *str)
Definition: atoi.c:10
#define STRING_REM_HELP
Definition: resource.h:159
#define STRING_CD_HELP
Definition: resource.h:72
BOOL bExit
Definition: cmd.c:152
_TCHAR * _tcscat(_TCHAR *s, const _TCHAR *append)
Definition: tcscat.h:8
GLuint res
Definition: glext.h:9613
#define _istspace
Definition: tchar.h:1504
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
GLfloat GLfloat p
Definition: glext.h:8902
#define args
Definition: format.c:66
INT GetRootPath(TCHAR *InPath, TCHAR *OutPath, INT size)
Definition: internal.c:152
int _tcsncmp(const _TCHAR *s1, const _TCHAR *s2, size_t n)
Definition: tcsncmp.h:9
int _tchdir(const _TCHAR *_path)
Definition: chdir.c:8
#define SetCurrentDirectory
Definition: winbase.h:3743
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502