/* * Copyright (c) 1998 Microsoft Corporation * * Module Name: * * dir.cpp * * Abstract: * * This file contains code to recursively create directories. * * Author: * * Breen Hagan (BreenH) Oct-02-98 * * Environment: * * User Mode */ #include "stdafx.h" #include "logfile.h" /* * Global variables. */ TCHAR gszDatabaseDirectory[MAX_PATH + 1] = _T("%SystemRoot%\\System32\\LServer"); /* * Helper Functions. */ DWORD CreateDirectoryRecursively( IN LPCTSTR pszDirectory ) { TCHAR Buffer[MAX_PATH + 1]; PTCHAR p,q; BOOL fDone; DWORD dwErr; if (_tcslen(pszDirectory) > (MAX_PATH)) { return(ERROR_BAD_PATHNAME); } if (ExpandEnvironmentStrings(pszDirectory, Buffer, MAX_PATH) > MAX_PATH) { return(ERROR_BAD_PATHNAME); } q = Buffer; if (q[1] == _T(':')) { // // This is a "C:" style path. Put p past the colon and first // backslash, if it exists. // if (q[2] == _T('\\')) { p = &(q[3]); } else { p = &(q[2]); } } else if (q[0] == _T('\\')) { // // This path begins with a backslash. If the second character is // also a backslash, this is a UNC path, which is not accepted. // if (q[1] == _T('\\')) { return(ERROR_BAD_PATHNAME); } else { p = &(q[1]); } } else { // // This path is a relative path from the current directory. // p = q; } q = p; fDone = FALSE; do { // // Locate the next path sep char. If there is none then // this is the deepest level of the path. // p = _tcschr(q, _T('\\')); if (p) { *p = (TCHAR)NULL; } else { fDone = TRUE; } // // Create this portion of the path. // if (CreateDirectory(Buffer,NULL)) { dwErr = NO_ERROR; } else { dwErr = GetLastError(); if(dwErr == ERROR_ALREADY_EXISTS) { dwErr = NO_ERROR; } } if(dwErr == NO_ERROR) { // // Put back the path sep and move to the next component. // if (!fDone) { *p = TEXT('\\'); q = p + sizeof(TCHAR); } } else { fDone = TRUE; } } while(!fDone); return(dwErr); } BOOL ConcatenatePaths( IN OUT LPTSTR Target, IN LPCTSTR Path, IN UINT TargetBufferSize, OUT LPUINT RequiredSize OPTIONAL ) { UINT TargetLength,PathLength; BOOL TrailingBackslash,LeadingBackslash; UINT EndingLength; TargetLength = lstrlen(Target); PathLength = lstrlen(Path); // // See whether the target has a trailing backslash. // if(TargetLength && (Target[TargetLength-1] == TEXT('\\'))) { TrailingBackslash = TRUE; TargetLength--; } else { TrailingBackslash = FALSE; } // // See whether the path has a leading backshash. // if(Path[0] == TEXT('\\')) { LeadingBackslash = TRUE; PathLength--; } else { LeadingBackslash = FALSE; } // // Calculate the ending length, which is equal to the sum of // the length of the two strings modulo leading/trailing // backslashes, plus one path separator, plus a nul. // EndingLength = TargetLength + PathLength + 2; if(RequiredSize) { *RequiredSize = EndingLength; } if(!LeadingBackslash && (TargetLength < TargetBufferSize)) { Target[TargetLength++] = TEXT('\\'); } if(TargetBufferSize > TargetLength) { lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength); } // // Make sure the buffer is nul terminated in all cases. // if (TargetBufferSize) { Target[TargetBufferSize-1] = 0; } return(EndingLength <= TargetBufferSize); } VOID Delnode( IN LPCTSTR Directory ) { TCHAR pszDirectory[MAX_PATH + 1]; TCHAR pszPattern[MAX_PATH + 1]; WIN32_FIND_DATA FindData; HANDLE FindHandle; LOGMESSAGE(_T("Delnode: Entered")); // // Delete each file in the given directory, then remove the directory // itself. If any directories are encountered along the way recurse to // delete them as they are encountered. // // Start by forming the search pattern, which is \*. // ExpandEnvironmentStrings(Directory, pszDirectory, MAX_PATH); LOGMESSAGE(_T("Delnode: Deleting %s"), pszDirectory); lstrcpyn(pszPattern, pszDirectory, MAX_PATH); ConcatenatePaths(pszPattern, _T("*"), MAX_PATH, NULL); // // Start the search. // FindHandle = FindFirstFile(pszPattern, &FindData); if(FindHandle != INVALID_HANDLE_VALUE) { do { // // Form the full name of the file or directory we just found. // lstrcpyn(pszPattern, pszDirectory, MAX_PATH); ConcatenatePaths(pszPattern, FindData.cFileName, MAX_PATH, NULL); // // Remove read-only atttribute if it's there. // if (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { SetFileAttributes(pszPattern, FILE_ATTRIBUTE_NORMAL); } if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // The current match is a directory. Recurse into it unless // it's . or ... // if ((lstrcmp(FindData.cFileName,_T("."))) && (lstrcmp(FindData.cFileName,_T("..")))) { Delnode(pszPattern); } } else { // // The current match is not a directory -- so delete it. // if (!DeleteFile(pszPattern)) { LOGMESSAGE(_T("Delnode: %s not deleted: %d"), pszPattern, GetLastError()); } } } while(FindNextFile(FindHandle, &FindData)); FindClose(FindHandle); } // // Remove the directory we just emptied out. Ignore errors. // RemoveDirectory(pszDirectory); } /* * Exported Functions. */ /* * CheckDatabaseDirectory() * * CheckDatabaseDirectory is very hardcore about which paths it will accept. * * Good Paths: * :\AbsolutePathToDirectory * * Bad Paths: * Any path that is not like above, AND any path in the form above that * is not on a fixed disk (e.g. no path to a floppy, CD-ROM, network * share). */ DWORD CheckDatabaseDirectory( IN LPCTSTR pszDatabaseDir ) { BOOL fBadChars; BOOL fBadPath; UINT DriveType; TCHAR pszExpandedDir[MAX_PATH + 1]; LOGMESSAGE(_T("CheckDatabaseDirectory: Entered")); LOGMESSAGE(_T("CheckDatabaseDirectory: Checking %s"), pszDatabaseDir); // // NULL is not accepted. // if (pszDatabaseDir == NULL) { return(ERROR_INVALID_PARAMETER); } // // A path greater than MAX_PATH will cause problems somewhere. This // will also catch pathnames with no environment variables that are // still too long. // if (ExpandEnvironmentStrings(pszDatabaseDir, pszExpandedDir, MAX_PATH) > MAX_PATH) { LOGMESSAGE(_T("CheckDatabaseDirectory: Path too long")); return(ERROR_BAD_PATHNAME); } // // A path of less than three characters can't contain ":\". // Also, don't allow anything but a letter, a colon, and a backslash. // fBadPath = FALSE; if (!fBadPath) { fBadPath = (_tcslen(pszExpandedDir) < 3); } if (!fBadPath) { fBadPath = !(_istalpha(pszExpandedDir[0])); } if (!fBadPath) { fBadPath = (pszExpandedDir[1] != _T(':')); } if (!fBadPath) { fBadPath = (pszExpandedDir[2] != _T('\\')); } if (fBadPath) { LOGMESSAGE(_T("CheckDatabaseDirectory: Not a C:\\ style directory")); return(ERROR_BAD_PATHNAME); } // // Characters like < > * ? and , won't work. Check for that now. // Also, check for additional colons after the first C:\.... // fBadChars = FALSE; if (!fBadChars) { fBadChars = (_tcschr(pszExpandedDir, _T('<')) != NULL); } if (!fBadChars) { fBadChars = (_tcschr(pszExpandedDir, _T('>')) != NULL); } if (!fBadChars) { fBadChars = (_tcschr(pszExpandedDir, _T('*')) != NULL); } if (!fBadChars) { fBadChars = (_tcschr(pszExpandedDir, _T('?')) != NULL); } if (!fBadChars) { fBadChars = (_tcschr(&(pszExpandedDir[3]), _T(':')) != NULL); } if (fBadChars) { LOGMESSAGE(_T("CheckDatabaseDirectory: Invalid characters")); return(ERROR_BAD_PATHNAME); } // // GetDriveType only works for paths in the form "C:\" or // "C:\ExistingDir". As pszDatabaseDir probably doesn't exist, it can't // be passed to GetDriveType. Set a NULL character passed the "C:\" to // pass in only the drive letter. // pszExpandedDir[3] = (TCHAR)NULL; DriveType = GetDriveType(pszExpandedDir); if (DriveType == DRIVE_FIXED) { return(NO_ERROR); } else { LOGMESSAGE(_T("CheckDatabaseDirectory: Bad DriveType %d"), DriveType); return(ERROR_BAD_PATHNAME); } } /* * CreateDatabaseDirectory() * * Creates the specified database directory. */ DWORD CreateDatabaseDirectory( VOID ) { return(CreateDirectoryRecursively(gszDatabaseDirectory)); } /* * GetDatabaseDirectory() * * Returns the current database directory. */ LPCTSTR GetDatabaseDirectory( VOID ) { return(gszDatabaseDirectory); } /* * RemoveDatabaseDirectory() * * Removes the entire database directory. */ VOID RemoveDatabaseDirectory( VOID ) { Delnode(gszDatabaseDirectory); } /* * SetDatabaseDirectory() * * This function assumes pszDatabaseDir has been verified by a call to * CheckDatabaseDir(), which verifies not NULL, within MAX_PATH, and on a * fixed hard drive. */ VOID SetDatabaseDirectory( IN LPCTSTR pszDatabaseDir ) { _tcscpy(gszDatabaseDirectory, pszDatabaseDir); }