ReactOS  0.4.13-dev-79-gcd489d8
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  /* Retrieve the full path name from the (possibly relative) InPath */
188  if (GetFullPathName(InPath, MAX_PATH, OutPathTemp, NULL) == 0)
189  goto Fail;
190 
191  /* Convert the full path to its correct case.
192  * Example: c:\windows\SYSTEM32 => C:\WINDOWS\System32 */
193  GetPathCase(OutPathTemp, OutPath);
194 
195  /* Use _tchdir, since unlike SetCurrentDirectory it updates
196  * the current-directory-on-drive environment variables. */
197  if (_tchdir(OutPath) != 0)
198  goto Fail;
199 
200  /* Keep original drive in ordinary CD/CHDIR (without /D switch). */
201  if (oldpath != NULL && _tcsncicmp(OutPath, oldpath, 2) != 0)
202  SetCurrentDirectory(oldpath);
203 
204  return TRUE;
205 
206 Fail:
208  nErrorLevel = 1;
209  return FALSE;
210 }
211 
212 
213 /*
214  * CD / CHDIR
215  *
216  */
218 {
219  BOOL bChangeDrive = FALSE;
220  LPTSTR tmp;
221  TCHAR szCurrent[MAX_PATH];
222 
223  /* Filter out special cases first */
224 
225  /* Print Help */
226  if (!_tcsncmp(param, _T("/?"), 2))
227  {
229  return 0;
230  }
231 
232  /* Remove extra quotes and strip trailing whitespace */
234  tmp = param + _tcslen(param) - 1;
235  while (tmp > param && _istspace(*tmp))
236  tmp--;
237  *(tmp + 1) = _T('\0');
238 
239  /* Set Error Level to Success */
240  nErrorLevel = 0;
241 
242  /* Print Current Directory on a disk */
243  if (_tcslen(param) == 2 && param[1] == _T(':'))
244  {
245  if (GetRootPath(param, szCurrent, MAX_PATH))
246  {
248  return 1;
249  }
250  ConOutPrintf(_T("%s\n"), szCurrent);
251  return 0;
252  }
253 
254  /* Get Current Directory */
255  GetCurrentDirectory(MAX_PATH, szCurrent);
256  if (param[0] == _T('\0'))
257  {
258  ConOutPrintf(_T("%s\n"), szCurrent);
259  return 0;
260  }
261 
262  /* Input String Contains /D Switch */
263  if (!_tcsncicmp(param, _T("/D"), 2))
264  {
265  bChangeDrive = TRUE;
266  param += 2;
267  while (_istspace(*param))
268  param++;
269  }
270 
271  if (!SetRootPath(bChangeDrive ? NULL : szCurrent, param))
272  {
273  nErrorLevel = 1;
274  return 1;
275  }
276 
277  return 0;
278 }
279 
280 #endif
281 
282 #ifdef INCLUDE_CMD_MKDIR
283 
284 /* Helper function for mkdir to make directories in a path.
285 Don't use the api to decrease dependence on libs */
286 BOOL
287 MakeFullPath(TCHAR * DirPath)
288 {
290  TCHAR *p = DirPath;
291  INT_PTR n;
292 
293  if (CreateDirectory(DirPath, NULL))
294  return TRUE;
295  else if (GetLastError() != ERROR_PATH_NOT_FOUND)
296  return FALSE;
297 
298  /* got ERROR_PATH_NOT_FOUND, so try building it up one component at a time */
299  if (p[0] && p[1] == _T(':'))
300  p += 2;
301  while (*p == _T('\\'))
302  p++; /* skip drive root */
303  do
304  {
305  p = _tcschr(p, _T('\\'));
306  n = p ? p++ - DirPath : _tcslen(DirPath);
307  _tcsncpy(path, DirPath, n);
308  path[n] = _T('\0');
309  if ( !CreateDirectory(path, NULL) &&
311  {
312  return FALSE;
313  }
314  } while (p != NULL);
315 
316  return TRUE;
317 }
318 
319 /*
320  * MD / MKDIR
321  */
323 {
324  LPTSTR *p;
325  INT argc, i;
326  if (!_tcsncmp (param, _T("/?"), 2))
327  {
329  return 0;
330  }
331 
332  p = split (param, &argc, FALSE, FALSE);
333  if (argc == 0)
334  {
336  freep(p);
337  nErrorLevel = 1;
338  return 1;
339  }
340 
341  nErrorLevel = 0;
342  for (i = 0; i < argc; i++)
343  {
344  if (!MakeFullPath(p[i]))
345  {
347  {
349  }
350  else
351  {
352  ErrorMessage (GetLastError(), _T("MD"));
353  }
354  nErrorLevel = 1;
355  }
356  }
357 
358  freep (p);
359  return nErrorLevel;
360 }
361 #endif
362 
363 
364 #ifdef INCLUDE_CMD_RMDIR
365 /*
366  * RD / RMDIR
367  */
369 {
371  TCHAR TempFileName[MAX_PATH];
372  HANDLE hFile;
375  _tcscat(Base,_T("\\*"));
376  hFile = FindFirstFile(Base, &f);
377  Base[_tcslen(Base) - 1] = _T('\0');
379  {
380  do
381  {
382  if (!_tcscmp(f.cFileName, _T(".")) ||
383  !_tcscmp(f.cFileName, _T("..")))
384  continue;
385  _tcscpy(TempFileName,Base);
386  _tcscat(TempFileName,f.cFileName);
387 
388  if (f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
389  DeleteFolder(TempFileName);
390  else
391  {
393  if (!DeleteFile(TempFileName))
394  {
395  FindClose (hFile);
396  return 0;
397  }
398  }
399 
400  }while (FindNextFile (hFile, &f));
401  FindClose (hFile);
402  }
403  return RemoveDirectory(FileName);
404 }
405 
407 {
408  TCHAR ch;
409  INT args;
410  INT dirCount;
411  LPTSTR *arg;
412  INT i;
413  BOOL RD_SUB = FALSE;
414  BOOL RD_QUIET = FALSE;
415  INT res;
416  INT nError = 0;
417  TCHAR szFullPath[MAX_PATH];
418 
419  if (!_tcsncmp (param, _T("/?"), 2))
420  {
422  return 0;
423  }
424 
425  arg = split (param, &args, FALSE, FALSE);
426  dirCount = 0;
427 
428  /* check for options anywhere in command line */
429  for (i = 0; i < args; i++)
430  {
431  if (*arg[i] == _T('/'))
432  {
433  /*found a command, but check to make sure it has something after it*/
434  if (_tcslen (arg[i]) == 2)
435  {
436  ch = _totupper (arg[i][1]);
437 
438  if (ch == _T('S'))
439  {
440  RD_SUB = TRUE;
441  }
442  else if (ch == _T('Q'))
443  {
444  RD_QUIET = TRUE;
445  }
446  }
447  }
448  else
449  {
450  dirCount++;
451  }
452  }
453 
454  if (dirCount == 0)
455  {
456  /* No folder to remove */
458  freep(arg);
459  return 1;
460  }
461 
462  for (i = 0; i < args; i++)
463  {
464  if (*arg[i] == _T('/'))
465  continue;
466 
467  if (RD_SUB)
468  {
469  /* ask if they want to delete everything in the folder */
470  if (!RD_QUIET)
471  {
473  if (res == PROMPT_NO || res == PROMPT_BREAK)
474  {
475  nError = 1;
476  continue;
477  }
478  if (res == PROMPT_ALL)
479  RD_QUIET = TRUE;
480  }
481  /* get the folder name */
482  GetFullPathName(arg[i],MAX_PATH,szFullPath,NULL);
483 
484  /* remove trailing \ if any, but ONLY if dir is not the root dir */
485  if (_tcslen (szFullPath) >= 2 && szFullPath[_tcslen (szFullPath) - 1] == _T('\\'))
486  szFullPath[_tcslen(szFullPath) - 1] = _T('\0');
487 
488  res = DeleteFolder(szFullPath);
489  }
490  else
491  {
492  res = RemoveDirectory(arg[i]);
493  }
494 
495  if (!res)
496  {
497  /* Couldn't delete the folder, print out the error */
498  nError = GetLastError();
499  ErrorMessage(nError, _T("RD"));
500  }
501  }
502 
503  freep (arg);
504  return nError;
505 }
506 #endif
507 
508 
509 /*
510  * set the exitflag to true
511  */
513 {
514  if (!_tcsncmp(param, _T("/?"), 2))
515  {
517 
518  /* Just make sure we don't exit */
519  bExit = FALSE;
520  return 0;
521  }
522 
523  if (_tcsnicmp(param, _T("/b"), 2) == 0)
524  {
525  param += 2;
526 
527  /*
528  * If a current batch file is running, exit it,
529  * otherwise exit this command interpreter instance.
530  */
531  if (bc)
532  ExitBatch();
533  else
534  bExit = TRUE;
535  }
536  else
537  {
538  /* Exit this command interpreter instance */
539  bExit = TRUE;
540  }
541 
542  /* Search for an optional exit code */
543  while (_istspace(*param))
544  param++;
545 
546  /* Set the errorlevel to the exit code */
547  if (_istdigit(*param))
549 
550  return 0;
551 }
552 
553 #ifdef INCLUDE_CMD_REM
554 /*
555  * does nothing
556  */
558 {
559  if (!_tcsncmp (param, _T("/?"), 2))
560  {
562  }
563 
564  return 0;
565 }
566 #endif /* INCLUDE_CMD_REM */
567 
568 
570 {
572  return 0;
573 }
574 
575 /* EOF */
INT nErrorLevel
Definition: cmd.c:157
VOID PrintCommandList(VOID)
Definition: cmdtable.c:242
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:172
VOID error_invalid_drive(VOID)
Definition: error.c:115
LPBATCH_CONTEXT bc
Definition: batch.c:66
INT cmd_mkdir(LPTSTR param)
Definition: internal.c:322
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
VOID ErrorMessage(DWORD, LPTSTR,...)
Definition: error.c:26
#define ConErrResPuts(uID)
Definition: console.h:39
#define RemoveDirectory
Definition: winbase.h:3709
_TCHAR * _tcsncpy(_TCHAR *dst, const _TCHAR *src, size_t n)
Definition: tcsncpy.h:9
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2327
GLdouble n
Definition: glext.h:7729
GLdouble GLdouble t
Definition: gl.h:2047
INT CommandShowCommands(LPTSTR param)
Definition: internal.c:569
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
_TCHAR * _tcscpy(_TCHAR *to, const _TCHAR *from)
Definition: tcscpy.h:8
#define PROMPT_BREAK
Definition: cmd.h:285
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:12
#define STRING_MD_ERROR2
Definition: resource.h:228
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
#define PROMPT_NO
Definition: cmd.h:282
#define _totupper
Definition: tchar.h:1509
int32_t INT_PTR
Definition: typedefs.h:62
#define DeleteFile
Definition: winbase.h:3578
Definition: match.c:390
static VOID StripQuotes(LPSTR in)
Definition: cmdcons.c:116
#define PROMPT_ALL
Definition: cmd.h:284
int32_t INT
Definition: typedefs.h:56
BOOL DeleteFolder(LPTSTR FileName)
Definition: internal.c:368
CHAR * LPTSTR
Definition: xmlstorage.h:192
INT cmd_chdir(LPTSTR param)
Definition: internal.c:217
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:108
#define GetCurrentDirectory
Definition: winbase.h:3619
#define STRING_DEL_HELP2
Definition: resource.h:102
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:3596
_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:665
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:3723
#define FindNextFile
Definition: winbase.h:3602
INT CommandRem(LPTSTR param)
Definition: internal.c:557
BOOL MakeFullPath(TCHAR *DirPath)
Definition: internal.c:287
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:406
INT CommandExit(LPTSTR param)
Definition: internal.c:512
#define GetFullPathName
Definition: winbase.h:3635
_In_ HANDLE hFile
Definition: mswsock.h:90
Definition: hiveinit.c:368
#define STRING_MKDIR_HELP
Definition: resource.h:146
#define STRING_EXIT_HELP
Definition: resource.h:127
#define f
Definition: ke_i.h:83
int CDECL _ttoi(const _TCHAR *str)
Definition: atoi.c:10
Definition: services.c:325
#define STRING_REM_HELP
Definition: resource.h:166
#define STRING_CD_HELP
Definition: resource.h:73
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:3717
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502