Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
8.5 KiB

  1. /*** RM.C - a generalized remove and unremove mechanism ***********************
  2. *
  3. * Copyright (c) 1987-1990, Microsoft Corporation. All rights reserved.
  4. *
  5. * Purpose:
  6. * The three tools EXP, RM and UNDEL are used to delete files so
  7. * that they can be undeleted. This is done my renaming the file into
  8. * a hidden directory called DELETED.
  9. *
  10. * Notes:
  11. * All deleted files are kept in the directory .\deleted with a unique name.
  12. * The names are then kept in .\deleted\index.
  13. * deleted name (RM_RECLEN bytes).
  14. * The rm command will rename to the appropriate directory and make an entry.
  15. * the undelete command will rename back if there is a single item otherwise
  16. * it will give a list of alternatives. The exp command will free all deleted
  17. * objects.
  18. *
  19. * Revision History:
  20. * 07-Feb-1990 bw Add 'void' to walk() definition
  21. * 08-Jan-1990 SB SLM version upgrading added; Add CopyRightYrs Macro
  22. * 03-Jan-1990 SB define QH_TOPIC_NOT_FOUND
  23. * 21-Dec-1989 SB Changes for new index file format
  24. * 20-Dec-1989 SB Add check for return code of 3 for qh
  25. * 14-Dec-1989 LN Update Copyright to include 1990
  26. * 23-Oct-1989 LN Version no bumped to 1.01
  27. * 12-Oct-1989 LN Changed Usage message
  28. * 02-Oct-1989 LN Changed Version no to 1.00
  29. * 08-Aug-1989 BW Add Version number and update copyright.
  30. * 15-May-1987 WB Add /help
  31. * 22-Apr-1987 DL Add /k
  32. * 06-Apr-1987 BW Add copyright notice to usage.
  33. * 30-Mar-1990 BW Get help on RM.EXE, not EXP.EXE
  34. * 17-Oct-1990 w-barry Temporarily replaced 'rename' with 'rename_NT' until
  35. * DosMove is completely implemented on NT.
  36. *
  37. ******************************************************************************/
  38. /* I N C L U D E Files */
  39. #include <process.h>
  40. #include <string.h>
  41. /* Next two from ZTools */
  42. #include <stdio.h>
  43. #include <conio.h>
  44. #include <windows.h>
  45. #include <tools.h>
  46. /* D E F I N E s */
  47. #define CopyRightYrs "1987-98"
  48. /* Need 2 steps, first to get correct values in and 2nd to paste them */
  49. /* paste() is hacked to allow LEADING ZEROES */
  50. #define paste(a, b, c) #a ".0" #b ".00" #c
  51. #define VERSION(major, minor, buildno) paste(major, minor, buildno)
  52. #define QH_TOPIC_NOT_FOUND 3
  53. /* G L O B A L s */
  54. flagType fRecursive = FALSE; /* TRUE => descend tree */
  55. flagType fPrompt = FALSE; /* TRUE => query for removal */
  56. flagType fForce = FALSE; /* TRUE => no query for R/O files */
  57. flagType fKeepRO = FALSE; /* TRUE => keep R/O files */
  58. flagType fTakeOwnership = FALSE; /* TRUE => attempt takeown if fail */
  59. flagType fExpunge = FALSE; /* TRUE => expunge immediately */
  60. flagType fDelayUntilReboot = FALSE; /* TRUE => do delete next reboot */
  61. // Forward Function Declarations...
  62. void Usage( void );
  63. void walk( char *, struct findType *, void * );
  64. #if 0
  65. extern BOOL TakeOwnership( char *lpFileName );
  66. #endif /* 0 */
  67. void Usage()
  68. {
  69. printf(
  70. "Microsoft File Removal Utility. Version %s\n"
  71. "Copyright (C) Microsoft Corp %s. All rights reserved.\n\n"
  72. "Usage: RM [/help] [/ikft] [/x [/d]] [/r dir] files\n"
  73. " /help invoke Quick Help for this utility\n"
  74. " /i inquire of user for each file for permission to remove\n"
  75. " /k keep read only files, no prompting to remove them\n"
  76. " /r dir recurse into subdirectories\n"
  77. " /f force delete of read only files without prompting\n"
  78. " /t attempt to take ownership of file if delete fails\n"
  79. " /x dont save deleted files in deleted subdirectory\n"
  80. " /d delay until next reboot.\n",
  81. VERSION(rmj, rmm, rup), CopyRightYrs);
  82. exit(1);
  83. }
  84. void walk(p, b, dummy)
  85. char *p;
  86. struct findType *b;
  87. void * dummy;
  88. {
  89. char buf[MAX_PATH];
  90. int i, rc;
  91. if (strcmp(b->fbuf.cFileName, ".") && strcmp(b->fbuf.cFileName, "..") &&
  92. _strcmpi(b->fbuf.cFileName, "deleted")) {
  93. if (HASATTR(b->fbuf.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY)) {
  94. if (fRecursive) {
  95. switch (strend(p)[-1]) {
  96. case '/':
  97. case '\\':
  98. sprintf(buf, "%s*.*", p);
  99. break;
  100. default:
  101. sprintf(buf, "%s\\*.*", p);
  102. }
  103. forfile(buf, -1, walk, NULL);
  104. }
  105. }
  106. else if (fKeepRO && HASATTR(b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_READONLY)) {
  107. printf("%s skipped\n", p);
  108. return;
  109. }
  110. else {
  111. if (fPrompt || (!fForce && HASATTR(b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_READONLY))) {
  112. printf("%s? ", p);
  113. fflush(stdout);
  114. switch (_getch()) {
  115. case 'y':
  116. case 'Y':
  117. printf("Yes\n");
  118. break;
  119. case 'p':
  120. case 'P':
  121. printf("Proceeding without asking again\n");
  122. fPrompt = FALSE;
  123. break;
  124. default:
  125. printf(" skipped\n");
  126. return;
  127. }
  128. }
  129. fflush(stdout);
  130. if (HASATTR(b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_READONLY))
  131. SetFileAttributes(p, b->fbuf.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
  132. for (i=0; i<2; i++) {
  133. if (fExpunge) {
  134. if (fDelayUntilReboot) {
  135. if (MoveFileEx(p, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
  136. rc = 0;
  137. }
  138. else {
  139. rc = 1;
  140. }
  141. }
  142. else
  143. if (DeleteFile(p)) {
  144. rc = 0;
  145. }
  146. else {
  147. rc = 1;
  148. }
  149. }
  150. else {
  151. rc = fdelete(p);
  152. }
  153. #if 0
  154. if (rc == 0 || !fTakeOwnership) {
  155. break;
  156. }
  157. printf( "%s file not deleted - attempting to take ownership and try again.\n" );
  158. if (!TakeOwnership( p )) {
  159. printf( "%s file not deleted - unable to take ownership.\n" );
  160. rc = 0;
  161. break;
  162. }
  163. #else
  164. break;
  165. #endif /* 0 */
  166. }
  167. switch (rc) {
  168. case 0:
  169. break;
  170. case 1:
  171. printf("%s file does not exist\n" , p);
  172. break;
  173. case 2:
  174. printf("%s rename failed: %s\n", p, error());
  175. break;
  176. default:
  177. printf("%s internal error: %s\n", p, error());
  178. break;
  179. }
  180. }
  181. }
  182. dummy;
  183. }
  184. __cdecl main(c, v)
  185. int c;
  186. char *v[];
  187. {
  188. register char *p;
  189. int iRetCode;
  190. ConvertAppToOem( c, v );
  191. SHIFT(c,v);
  192. while (c && fSwitChr(*v[0])) {
  193. p = *v;
  194. while (*++p != '\0')
  195. switch (*p) {
  196. case 'f':
  197. fForce = TRUE;
  198. break;
  199. case 'i':
  200. fPrompt = TRUE;
  201. break;
  202. case 'k':
  203. fKeepRO = TRUE;
  204. break;
  205. case 'r':
  206. fRecursive = TRUE;
  207. break;
  208. case 't':
  209. fTakeOwnership = TRUE;
  210. break;
  211. case 'x':
  212. fExpunge = TRUE;
  213. break;
  214. case 'd':
  215. if (fExpunge) {
  216. fDelayUntilReboot = TRUE;
  217. break;
  218. }
  219. // Fall thru if /d without /x
  220. case 'h':
  221. if (!_strcmpi(p, "help")) {
  222. iRetCode = (int) _spawnlp(P_WAIT, "qh.exe", "qh", "/u",
  223. "rm.exe", NULL);
  224. /* When qh returns QH_TOPIC_NOT_FOUND or when we
  225. * get -1 (returned when the spawn fails) then
  226. * give Usage() message
  227. */
  228. if (iRetCode != QH_TOPIC_NOT_FOUND && iRetCode != -1)
  229. exit(0);
  230. }
  231. /*
  232. * else fall thru...
  233. */
  234. default:
  235. Usage();
  236. }
  237. SHIFT(c,v);
  238. }
  239. while (c) {
  240. if (!forfile(*v, -1, walk, NULL)) {
  241. printf("%s does not exist\n", *v);
  242. }
  243. SHIFT(c,v);
  244. }
  245. return(0);
  246. }