mirror of https://github.com/lianthony/NT4.0
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.
353 lines
11 KiB
353 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tree.c
|
|
|
|
Abstract:
|
|
|
|
RplTreeCopy, RplTreeDelete, RplMakeDir file-management helper routines
|
|
for the RPL service.
|
|
|
|
Author:
|
|
|
|
Jon Newman (jonn) 23 - November - 1993
|
|
|
|
Revision History:
|
|
|
|
Vladimir Z. Vulovic (vladimv) 02 - December - 1993
|
|
Integrated with the rest of RPL service code.
|
|
Jon Newman (jonn) 15 - February - 1994
|
|
Added RplGrant*Perms primitives
|
|
Jon Newman (jonn) 08 - March - 1994
|
|
RplDoTree now creates log entries on failure
|
|
|
|
--*/
|
|
|
|
#include "local.h"
|
|
#include "tree.h"
|
|
#include "treei.h"
|
|
|
|
#define FILE_SEPARATOR L"\\"
|
|
#define HERE_DIRECTORY L"."
|
|
#define PARENT_DIRECTORY L".."
|
|
#define ALLFILES_SUFFIX L"*"
|
|
|
|
#define LEN_FILE_SEPARATOR 1
|
|
#define LEN_ALLFILES_SUFFIX 1
|
|
|
|
|
|
VOID LoadError(
|
|
PWCHAR FilePath,
|
|
DWORD ActionError,
|
|
DWORD ActionFlags
|
|
)
|
|
/*++
|
|
BUGBUG if buffer inadequate, copy first part or last part?
|
|
--*/
|
|
{
|
|
DWORD Length0 = 0;
|
|
DWORD msgid = 0;
|
|
|
|
//
|
|
// Dump error log entry, where the message depends on Flags
|
|
//
|
|
if (ActionFlags == 0) {
|
|
msgid = 0;
|
|
} else if (ActionFlags & RPL_TREE_COPY) {
|
|
msgid = NELOG_RplFileCopy;
|
|
} else if (ActionFlags & RPL_TREE_DELETE) {
|
|
msgid = NELOG_RplFileDelete;
|
|
} else if (ActionFlags & RPL_TREE_AUXILIARY) {
|
|
msgid = NELOG_RplFilePerms;
|
|
} else {
|
|
RPL_ASSERT( FALSE );
|
|
}
|
|
|
|
if (msgid != 0) {
|
|
RplReportEvent( msgid, FilePath, sizeof(DWORD), &ActionError );
|
|
}
|
|
}
|
|
|
|
|
|
DWORD RplDoTree(
|
|
PWCHAR Source,
|
|
PWCHAR Target,
|
|
DWORD Flags,
|
|
RPL_TREE_CALLBACK AuxiliaryCallback,
|
|
PBOOL pAuxiliaryBlock
|
|
)
|
|
/*++
|
|
Target should only be examined if RPL_TREE_COPY case.
|
|
--*/
|
|
{
|
|
// CODEWORK too much stack space usage (1.5K / recursive invocation)
|
|
DWORD Error = NO_ERROR;
|
|
WCHAR CurrentSource[ MAX_PATH];
|
|
WCHAR CurrentTarget[ MAX_PATH];
|
|
HANDLE Handle = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA FindData;
|
|
DWORD SourceLength = 0;
|
|
DWORD TargetLength = 0;
|
|
DWORD FileLength = 0;
|
|
BOOL Auxiliary = ((Flags & RPL_TREE_AUXILIARY) != 0);
|
|
BOOL Delete = ((Flags & RPL_TREE_DELETE) != 0);
|
|
BOOL Copy = ((Flags & RPL_TREE_COPY) != 0);
|
|
|
|
//
|
|
// Delete is incompatible with Auxiliary and Copy
|
|
//
|
|
RPL_ASSERT( !Delete || (!Auxiliary && !Copy ) );
|
|
|
|
//
|
|
// Callback and callback data block required for Auxiliary
|
|
//
|
|
RPL_ASSERT( !Auxiliary
|
|
|| (AuxiliaryCallback != NULL && pAuxiliaryBlock != NULL) );
|
|
|
|
if ( Source == NULL || *Source == L'\0') {
|
|
RPL_RETURN( ERROR_INVALID_PARAMETER);
|
|
}
|
|
SourceLength = wcslen( Source);
|
|
if ( SourceLength + LEN_ALLFILES_SUFFIX >= MAX_PATH) {
|
|
Error = ERROR_FILENAME_EXCED_RANGE;
|
|
RplDump( ++RG_Assert, ( "Error=%d", Error));
|
|
LoadError( Source, Error, Flags);
|
|
return( Error);
|
|
}
|
|
//
|
|
// Initialize buffer for source names.
|
|
//
|
|
memcpy( CurrentSource, Source, SourceLength * sizeof(WCHAR));
|
|
memcpy( CurrentSource + SourceLength, FILE_SEPARATOR, LEN_FILE_SEPARATOR * sizeof(WCHAR));
|
|
memcpy( CurrentSource + SourceLength + LEN_FILE_SEPARATOR, ALLFILES_SUFFIX, (LEN_ALLFILES_SUFFIX+1) * sizeof(WCHAR));
|
|
|
|
//
|
|
// Copy directory operations are done at the beginning.
|
|
//
|
|
// BUGBUG broken if source is not a directory
|
|
//
|
|
if ( Copy) {
|
|
TargetLength = wcslen( Target);
|
|
RPL_ASSERT( TargetLength < MAX_PATH);
|
|
//
|
|
// Initialize buffer for target names.
|
|
//
|
|
memcpy( CurrentTarget, Target, (TargetLength+1) * sizeof(WCHAR));
|
|
if ( !CreateDirectoryEx( Source, Target, NULL)) {
|
|
Error = GetLastError();
|
|
if ( Error != ERROR_ALREADY_EXISTS) {
|
|
RplDump( ++RG_Assert, ( "Error=%d", Error));
|
|
LoadError( Source, Error, RPL_TREE_COPY);
|
|
return( Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stop recursing this tree if we are setting permission only and if
|
|
// SetRplPerms tells us to quit this branch. Here we depend on the fact that
|
|
// RPL_SD_BLOCK - structure not visible here, contains BOOL StopRecursion
|
|
// as its first element.
|
|
//
|
|
if ( Auxiliary) {
|
|
Error = (AuxiliaryCallback)( ((Copy)?Target:Source), pAuxiliaryBlock);
|
|
if (Error != NERR_Success) {
|
|
RplDump( ++RG_Assert, ( "Error=%d", Error));
|
|
LoadError( Source, Error, RPL_TREE_AUXILIARY);
|
|
return( Error);
|
|
}
|
|
if ( !Delete && !Copy && *pAuxiliaryBlock == TRUE) {
|
|
return( NO_ERROR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate and copy/change/delete directory contents.
|
|
//
|
|
for ( Handle = INVALID_HANDLE_VALUE; NOTHING; Error = NO_ERROR) {
|
|
|
|
if ( Handle == INVALID_HANDLE_VALUE) {
|
|
Handle = FindFirstFile( CurrentSource, &FindData);
|
|
if (Handle == INVALID_HANDLE_VALUE) {
|
|
Error = GetLastError();
|
|
//
|
|
// ERROR_PATH_NOT_FOUND occurs for non-existing Source tree
|
|
//
|
|
if (Error == ERROR_NO_MORE_FILES || Error == ERROR_PATH_NOT_FOUND) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
RplDump( ++RG_Assert, ( "Error=%d, CurrentSource=%ws", Error, CurrentSource));
|
|
LoadError( CurrentSource, Error, Flags);
|
|
}
|
|
break;
|
|
}
|
|
//
|
|
// Trim ALLFILES_SUFFIX off CurrentSource for future use
|
|
//
|
|
CurrentSource[ SourceLength + LEN_FILE_SEPARATOR] = L'\0';
|
|
} else {
|
|
if ( !FindNextFile( Handle, &FindData)) {
|
|
Error = GetLastError();
|
|
if ( Error == ERROR_NO_MORE_FILES) {
|
|
Error = NO_ERROR;
|
|
break;
|
|
} else {
|
|
RplDump( ++RG_Assert, ( "Error=%d, CurrentSource=%ws", Error, CurrentSource));
|
|
LoadError( CurrentSource, Error, Flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( 0 == wcscmp( FindData.cFileName, HERE_DIRECTORY) ||
|
|
0 == wcscmp( FindData.cFileName, PARENT_DIRECTORY)) {
|
|
continue; // get next entry
|
|
}
|
|
FileLength = wcslen( FindData.cFileName);
|
|
|
|
//
|
|
// Update source name.
|
|
//
|
|
if ( SourceLength + LEN_FILE_SEPARATOR + FileLength >= MAX_PATH) {
|
|
Error = ERROR_FILENAME_EXCED_RANGE;
|
|
RplDump(++RG_Assert,("Error=%d, SourceLength=%d, FileName=%ws",
|
|
Error, SourceLength, FindData.cFileName));
|
|
LoadError( Source, Error, Flags);
|
|
break;
|
|
}
|
|
memcpy( CurrentSource+SourceLength+LEN_FILE_SEPARATOR,
|
|
FindData.cFileName, (FileLength+1) * sizeof(WCHAR));
|
|
|
|
//
|
|
// Update target name (this is needed both for the file case &
|
|
// the directory case below).
|
|
//
|
|
if ( Copy) {
|
|
if ( TargetLength + LEN_FILE_SEPARATOR + FileLength >= MAX_PATH) {
|
|
Error = ERROR_FILENAME_EXCED_RANGE;
|
|
RplDump(++RG_Assert,("Error=%d, TargetLength=%d, FileName=%ws",
|
|
Error, TargetLength, FindData.cFileName));
|
|
LoadError( Target, Error, RPL_TREE_COPY);
|
|
break;
|
|
}
|
|
memcpy( CurrentTarget+TargetLength,
|
|
FILE_SEPARATOR, sizeof(FILE_SEPARATOR));
|
|
memcpy( CurrentTarget+TargetLength+LEN_FILE_SEPARATOR,
|
|
FindData.cFileName, (FileLength+1) * sizeof(WCHAR));
|
|
}
|
|
|
|
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
if ( Copy) {
|
|
if ( !CopyFile( CurrentSource, CurrentTarget, FALSE)) {
|
|
Error = GetLastError();
|
|
RplDump(++RG_Assert,("Error=%d CurrentSource=%ws CurrentTarget=%ws",
|
|
Error, CurrentSource, CurrentTarget));
|
|
LoadError( CurrentSource, Error, RPL_TREE_COPY);
|
|
break;
|
|
}
|
|
} else if ( Delete){
|
|
//
|
|
// If file has readonly attribute, we need to reset this
|
|
// attribute, otherwise DeleteFile() with fail with error
|
|
// access denied.
|
|
//
|
|
if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)) {
|
|
(VOID)SetFileAttributes( CurrentSource, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
if ( !DeleteFile( CurrentSource)) {
|
|
Error = GetLastError();
|
|
RplDump(++RG_Assert,("Error=%d CurrentSource=%ws", Error, CurrentSource));
|
|
LoadError( CurrentSource, Error, RPL_TREE_DELETE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set permissions after file is created (in Copy && Auxiliary case)
|
|
//
|
|
if ( Auxiliary) {
|
|
Error = (AuxiliaryCallback)( ( (Copy) ? CurrentTarget
|
|
: CurrentSource ),
|
|
pAuxiliaryBlock );
|
|
if (Error != NERR_Success) {
|
|
RplDump( ++RG_Assert, ( "Error=%d", Error));
|
|
LoadError( Source, Error, RPL_TREE_AUXILIARY);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
Error = RplDoTree( CurrentSource,
|
|
CurrentTarget,
|
|
Flags,
|
|
AuxiliaryCallback,
|
|
pAuxiliaryBlock);
|
|
}
|
|
}
|
|
|
|
if (Handle != INVALID_HANDLE_VALUE) {
|
|
FindClose( Handle );
|
|
}
|
|
|
|
//
|
|
// Delete is the only directory operation that is done at the end.
|
|
//
|
|
if ( Delete && Error == NO_ERROR) {
|
|
//
|
|
// If directory has readonly attribute, we need to reset this
|
|
// attribute, otherwise RemoveDirectory() with fail with error
|
|
// access denied.
|
|
//
|
|
(VOID)SetFileAttributes( Source, FILE_ATTRIBUTE_DIRECTORY);
|
|
if ( !RemoveDirectory( Source)) {
|
|
Error = GetLastError();
|
|
if (Error == ERROR_FILE_NOT_FOUND || Error == ERROR_PATH_NOT_FOUND) {
|
|
Error = NO_ERROR;
|
|
} else {
|
|
RplDump( ++RG_Assert, ( "Error=%d", Error));
|
|
LoadError( Source, Error, RPL_TREE_DELETE);
|
|
}
|
|
}
|
|
}
|
|
return( Error);
|
|
}
|
|
|
|
|
|
DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = RplDoTree( Source, Target, RPL_TREE_COPY,
|
|
NULL, NULL);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD RplTreeDelete( IN PWCHAR Source)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = RplDoTree( Source, L"", RPL_TREE_DELETE,
|
|
NULL, NULL);
|
|
if ( Error != NO_ERROR) {
|
|
return( Error);
|
|
}
|
|
return( NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD RplMakeDir( IN PWCHAR Source)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
if ( !CreateDirectory( Source, NULL)) {
|
|
Error = GetLastError();
|
|
RplDump( ++RG_Assert, ("Error=%d", Error));
|
|
}
|
|
return( Error);
|
|
}
|
|
|