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.

466 lines
10 KiB

  1. /*
  2. * Copyright (c) 1998 Microsoft Corporation
  3. *
  4. * Module Name:
  5. *
  6. * dir.cpp
  7. *
  8. * Abstract:
  9. *
  10. * This file contains code to recursively create directories.
  11. *
  12. * Author:
  13. *
  14. * Breen Hagan (BreenH) Oct-02-98
  15. *
  16. * Environment:
  17. *
  18. * User Mode
  19. */
  20. #include "stdafx.h"
  21. #include "logfile.h"
  22. /*
  23. * Global variables.
  24. */
  25. TCHAR gszDatabaseDirectory[MAX_PATH + 1] =
  26. _T("%SystemRoot%\\System32\\LServer");
  27. /*
  28. * Helper Functions.
  29. */
  30. DWORD
  31. CreateDirectoryRecursively(
  32. IN LPCTSTR pszDirectory
  33. )
  34. {
  35. TCHAR Buffer[MAX_PATH + 1];
  36. PTCHAR p,q;
  37. BOOL fDone;
  38. DWORD dwErr;
  39. if (_tcslen(pszDirectory) > (MAX_PATH)) {
  40. return(ERROR_BAD_PATHNAME);
  41. }
  42. if (ExpandEnvironmentStrings(pszDirectory, Buffer, MAX_PATH) > MAX_PATH) {
  43. return(ERROR_BAD_PATHNAME);
  44. }
  45. q = Buffer;
  46. if (q[1] == _T(':')) {
  47. //
  48. // This is a "C:" style path. Put p past the colon and first
  49. // backslash, if it exists.
  50. //
  51. if (q[2] == _T('\\')) {
  52. p = &(q[3]);
  53. } else {
  54. p = &(q[2]);
  55. }
  56. } else if (q[0] == _T('\\')) {
  57. //
  58. // This path begins with a backslash. If the second character is
  59. // also a backslash, this is a UNC path, which is not accepted.
  60. //
  61. if (q[1] == _T('\\')) {
  62. return(ERROR_BAD_PATHNAME);
  63. } else {
  64. p = &(q[1]);
  65. }
  66. } else {
  67. //
  68. // This path is a relative path from the current directory.
  69. //
  70. p = q;
  71. }
  72. q = p;
  73. fDone = FALSE;
  74. do {
  75. //
  76. // Locate the next path sep char. If there is none then
  77. // this is the deepest level of the path.
  78. //
  79. p = _tcschr(q, _T('\\'));
  80. if (p) {
  81. *p = (TCHAR)NULL;
  82. } else {
  83. fDone = TRUE;
  84. }
  85. //
  86. // Create this portion of the path.
  87. //
  88. if (CreateDirectory(Buffer,NULL)) {
  89. dwErr = NO_ERROR;
  90. } else {
  91. dwErr = GetLastError();
  92. if(dwErr == ERROR_ALREADY_EXISTS) {
  93. dwErr = NO_ERROR;
  94. }
  95. }
  96. if(dwErr == NO_ERROR) {
  97. //
  98. // Put back the path sep and move to the next component.
  99. //
  100. if (!fDone) {
  101. *p = TEXT('\\');
  102. q = p + sizeof(TCHAR);
  103. }
  104. } else {
  105. fDone = TRUE;
  106. }
  107. } while(!fDone);
  108. return(dwErr);
  109. }
  110. BOOL
  111. ConcatenatePaths(
  112. IN OUT LPTSTR Target,
  113. IN LPCTSTR Path,
  114. IN UINT TargetBufferSize,
  115. OUT LPUINT RequiredSize OPTIONAL
  116. )
  117. {
  118. UINT TargetLength,PathLength;
  119. BOOL TrailingBackslash,LeadingBackslash;
  120. UINT EndingLength;
  121. TargetLength = lstrlen(Target);
  122. PathLength = lstrlen(Path);
  123. //
  124. // See whether the target has a trailing backslash.
  125. //
  126. if(TargetLength && (Target[TargetLength-1] == TEXT('\\'))) {
  127. TrailingBackslash = TRUE;
  128. TargetLength--;
  129. } else {
  130. TrailingBackslash = FALSE;
  131. }
  132. //
  133. // See whether the path has a leading backshash.
  134. //
  135. if(Path[0] == TEXT('\\')) {
  136. LeadingBackslash = TRUE;
  137. PathLength--;
  138. } else {
  139. LeadingBackslash = FALSE;
  140. }
  141. //
  142. // Calculate the ending length, which is equal to the sum of
  143. // the length of the two strings modulo leading/trailing
  144. // backslashes, plus one path separator, plus a nul.
  145. //
  146. EndingLength = TargetLength + PathLength + 2;
  147. if(RequiredSize) {
  148. *RequiredSize = EndingLength;
  149. }
  150. if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
  151. Target[TargetLength++] = TEXT('\\');
  152. }
  153. if(TargetBufferSize > TargetLength) {
  154. lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
  155. }
  156. //
  157. // Make sure the buffer is nul terminated in all cases.
  158. //
  159. if (TargetBufferSize) {
  160. Target[TargetBufferSize-1] = 0;
  161. }
  162. return(EndingLength <= TargetBufferSize);
  163. }
  164. VOID
  165. Delnode(
  166. IN LPCTSTR Directory
  167. )
  168. {
  169. TCHAR pszDirectory[MAX_PATH + 1];
  170. TCHAR pszPattern[MAX_PATH + 1];
  171. WIN32_FIND_DATA FindData;
  172. HANDLE FindHandle;
  173. LOGMESSAGE(_T("Delnode: Entered"));
  174. //
  175. // Delete each file in the given directory, then remove the directory
  176. // itself. If any directories are encountered along the way recurse to
  177. // delete them as they are encountered.
  178. //
  179. // Start by forming the search pattern, which is <currentdir>\*.
  180. //
  181. ExpandEnvironmentStrings(Directory, pszDirectory, MAX_PATH);
  182. LOGMESSAGE(_T("Delnode: Deleting %s"), pszDirectory);
  183. lstrcpyn(pszPattern, pszDirectory, MAX_PATH);
  184. ConcatenatePaths(pszPattern, _T("*"), MAX_PATH, NULL);
  185. //
  186. // Start the search.
  187. //
  188. FindHandle = FindFirstFile(pszPattern, &FindData);
  189. if(FindHandle != INVALID_HANDLE_VALUE) {
  190. do {
  191. //
  192. // Form the full name of the file or directory we just found.
  193. //
  194. lstrcpyn(pszPattern, pszDirectory, MAX_PATH);
  195. ConcatenatePaths(pszPattern, FindData.cFileName, MAX_PATH, NULL);
  196. //
  197. // Remove read-only atttribute if it's there.
  198. //
  199. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  200. SetFileAttributes(pszPattern, FILE_ATTRIBUTE_NORMAL);
  201. }
  202. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  203. //
  204. // The current match is a directory. Recurse into it unless
  205. // it's . or ...
  206. //
  207. if ((lstrcmp(FindData.cFileName,_T("."))) &&
  208. (lstrcmp(FindData.cFileName,_T("..")))) {
  209. Delnode(pszPattern);
  210. }
  211. } else {
  212. //
  213. // The current match is not a directory -- so delete it.
  214. //
  215. if (!DeleteFile(pszPattern)) {
  216. LOGMESSAGE(_T("Delnode: %s not deleted: %d"), pszPattern,
  217. GetLastError());
  218. }
  219. }
  220. } while(FindNextFile(FindHandle, &FindData));
  221. FindClose(FindHandle);
  222. }
  223. //
  224. // Remove the directory we just emptied out. Ignore errors.
  225. //
  226. RemoveDirectory(pszDirectory);
  227. }
  228. /*
  229. * Exported Functions.
  230. */
  231. /*
  232. * CheckDatabaseDirectory()
  233. *
  234. * CheckDatabaseDirectory is very hardcore about which paths it will accept.
  235. *
  236. * Good Paths:
  237. * <DriveLetter>:\AbsolutePathToDirectory
  238. *
  239. * Bad Paths:
  240. * Any path that is not like above, AND any path in the form above that
  241. * is not on a fixed disk (e.g. no path to a floppy, CD-ROM, network
  242. * share).
  243. */
  244. DWORD
  245. CheckDatabaseDirectory(
  246. IN LPCTSTR pszDatabaseDir
  247. )
  248. {
  249. BOOL fBadChars;
  250. BOOL fBadPath;
  251. UINT DriveType;
  252. TCHAR pszExpandedDir[MAX_PATH + 1];
  253. LOGMESSAGE(_T("CheckDatabaseDirectory: Entered"));
  254. LOGMESSAGE(_T("CheckDatabaseDirectory: Checking %s"), pszDatabaseDir);
  255. //
  256. // NULL is not accepted.
  257. //
  258. if (pszDatabaseDir == NULL) {
  259. return(ERROR_INVALID_PARAMETER);
  260. }
  261. //
  262. // A path greater than MAX_PATH will cause problems somewhere. This
  263. // will also catch pathnames with no environment variables that are
  264. // still too long.
  265. //
  266. if (ExpandEnvironmentStrings(pszDatabaseDir, pszExpandedDir, MAX_PATH) >
  267. MAX_PATH) {
  268. LOGMESSAGE(_T("CheckDatabaseDirectory: Path too long"));
  269. return(ERROR_BAD_PATHNAME);
  270. }
  271. //
  272. // A path of less than three characters can't contain "<DriveLetter>:\".
  273. // Also, don't allow anything but a letter, a colon, and a backslash.
  274. //
  275. fBadPath = FALSE;
  276. if (!fBadPath) {
  277. fBadPath = (_tcslen(pszExpandedDir) < 3);
  278. }
  279. if (!fBadPath) {
  280. fBadPath = !(_istalpha(pszExpandedDir[0]));
  281. }
  282. if (!fBadPath) {
  283. fBadPath = (pszExpandedDir[1] != _T(':'));
  284. }
  285. if (!fBadPath) {
  286. fBadPath = (pszExpandedDir[2] != _T('\\'));
  287. }
  288. if (fBadPath) {
  289. LOGMESSAGE(_T("CheckDatabaseDirectory: Not a C:\\ style directory"));
  290. return(ERROR_BAD_PATHNAME);
  291. }
  292. //
  293. // Characters like < > * ? and , won't work. Check for that now.
  294. // Also, check for additional colons after the first C:\....
  295. //
  296. fBadChars = FALSE;
  297. if (!fBadChars) {
  298. fBadChars = (_tcschr(pszExpandedDir, _T('<')) != NULL);
  299. }
  300. if (!fBadChars) {
  301. fBadChars = (_tcschr(pszExpandedDir, _T('>')) != NULL);
  302. }
  303. if (!fBadChars) {
  304. fBadChars = (_tcschr(pszExpandedDir, _T('*')) != NULL);
  305. }
  306. if (!fBadChars) {
  307. fBadChars = (_tcschr(pszExpandedDir, _T('?')) != NULL);
  308. }
  309. if (!fBadChars) {
  310. fBadChars = (_tcschr(&(pszExpandedDir[3]), _T(':')) != NULL);
  311. }
  312. if (fBadChars) {
  313. LOGMESSAGE(_T("CheckDatabaseDirectory: Invalid characters"));
  314. return(ERROR_BAD_PATHNAME);
  315. }
  316. //
  317. // GetDriveType only works for paths in the form "C:\" or
  318. // "C:\ExistingDir". As pszDatabaseDir probably doesn't exist, it can't
  319. // be passed to GetDriveType. Set a NULL character passed the "C:\" to
  320. // pass in only the drive letter.
  321. //
  322. pszExpandedDir[3] = (TCHAR)NULL;
  323. DriveType = GetDriveType(pszExpandedDir);
  324. if (DriveType == DRIVE_FIXED) {
  325. return(NO_ERROR);
  326. } else {
  327. LOGMESSAGE(_T("CheckDatabaseDirectory: Bad DriveType %d"), DriveType);
  328. return(ERROR_BAD_PATHNAME);
  329. }
  330. }
  331. /*
  332. * CreateDatabaseDirectory()
  333. *
  334. * Creates the specified database directory.
  335. */
  336. DWORD
  337. CreateDatabaseDirectory(
  338. VOID
  339. )
  340. {
  341. return(CreateDirectoryRecursively(gszDatabaseDirectory));
  342. }
  343. /*
  344. * GetDatabaseDirectory()
  345. *
  346. * Returns the current database directory.
  347. */
  348. LPCTSTR
  349. GetDatabaseDirectory(
  350. VOID
  351. )
  352. {
  353. return(gszDatabaseDirectory);
  354. }
  355. /*
  356. * RemoveDatabaseDirectory()
  357. *
  358. * Removes the entire database directory.
  359. */
  360. VOID
  361. RemoveDatabaseDirectory(
  362. VOID
  363. )
  364. {
  365. Delnode(gszDatabaseDirectory);
  366. }
  367. /*
  368. * SetDatabaseDirectory()
  369. *
  370. * This function assumes pszDatabaseDir has been verified by a call to
  371. * CheckDatabaseDir(), which verifies not NULL, within MAX_PATH, and on a
  372. * fixed hard drive.
  373. */
  374. VOID
  375. SetDatabaseDirectory(
  376. IN LPCTSTR pszDatabaseDir
  377. )
  378. {
  379. _tcscpy(gszDatabaseDirectory, pszDatabaseDir);
  380. }