windows-nt/Source/XPSP1/NT/termsrv/license/tlserver/setup/dir.cpp
2020-09-26 16:20:57 +08:00

467 lines
10 KiB
C++

/*
* 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 <currentdir>\*.
//
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:
* <DriveLetter>:\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 "<DriveLetter>:\".
// 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);
}