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.
 
 
 
 
 
 

1337 lines
27 KiB

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
bootfile.c
Abstract:
Domain Name System (DNS) Server
Boot file write back (from registry) routines.
Author:
Denise Yuxin Miller (denisemi) December 3, 1996
Revision History:
--*/
#include "dnssrv.h"
//
// Boot file info saved for post read processing
//
DNS_BOOT_FILE_INFO BootInfo;
#define DNS_ZONE_TYPE_NAME_PRIMARY "primary"
#define DNS_ZONE_TYPE_NAME_SECONDARY "secondary"
#define DNS_ZONE_TYPE_NAME_STUB "stub"
#define DNS_ZONE_TYPE_NAME_FORWARDER "forward"
#define DNS_ZONE_TYPE_NAME_CACHE "cache"
//
// Private protos for read
//
DNS_STATUS
processBootFileLine(
IN OUT PPARSE_INFO pParseInfo
);
//
// Private protos for write
//
LPSTR
createStringFromIpAddressArray(
IN DWORD dwIpAddrCount,
IN PIP_ADDRESS pIpAddrs
);
VOID
removeTrailDotFromString(
IN OUT LPSTR lpzString
);
//
// Boot file read routines
//
DNS_STATUS
File_ReadBootFile(
IN BOOL fMustFindBootFile
)
/*++
Routine Description:
Read and process boot file.
Builds list of zone files to process.
Arguments:
fMustFindBootFile -- flag
TRUE -- if explicitly configured for boot file
FALSE -- not explicitly configured for boot file; attempt boot
file open, but no errors if fail
Return Value:
TRUE if successful
FALSE otherwise
--*/
{
DNS_STATUS status;
PWSTR pwsbootFile;
MAPPED_FILE mfBootFile;
PARSE_INFO ParseInfo;
BOOLEAN fDummy;
//
// Get boot file name\path
// - currently fixed directory and boot file name
//
pwsbootFile = DNS_BOOT_FILE_PATH;
//
// open and map boot file
//
DNS_DEBUG( INIT, (
"\n\nReading boot file %S ...\n",
pwsbootFile ));
status = OpenAndMapFileForReadW(
pwsbootFile,
& mfBootFile,
fMustFindBootFile );
if ( status != ERROR_SUCCESS )
{
DNS_DEBUG( INIT, (
"Could not open boot file: %S\n"
"\terror = %d\n",
pwsbootFile,
status ));
//
// doc mentions "boot.dns" so if we're supposed to use boot file
// use boot.dns if found
//
if ( !fMustFindBootFile )
{
return( status );
}
status = OpenAndMapFileForReadW(
DNS_BOOTDNS_FILE_PATH,
& mfBootFile,
FALSE // don't log event if don't find
);
if ( status != ERROR_SUCCESS )
{
DNS_LOG_EVENT(
DNS_EVENT_BOOT_FILE_NOT_FOUND,
1,
&pwsbootFile,
EVENTARG_ALL_UNICODE,
status );
return( status );
}
pwsbootFile = DNS_BOOTDNS_FILE_PATH;
}
// clear boot file post-processing info
RtlZeroMemory(
&BootInfo,
sizeof( DNS_BOOT_FILE_INFO ) );
// setup parsing structure
RtlZeroMemory(
&ParseInfo,
sizeof( PARSE_INFO ) );
ParseInfo.pwsFileName = pwsbootFile;
File_InitBuffer(
&ParseInfo.Buffer,
(PCHAR) mfBootFile.pvFileData,
mfBootFile.cbFileBytes );
//
// loop until all tokens in file are exhausted
//
while ( 1 )
{
DNS_DEBUG( INIT2, ( "\nBootLine %d: ", ParseInfo.cLineNumber ));
// get next tokenized line
status = File_GetNextLine( &ParseInfo );
if ( status != ERROR_SUCCESS )
{
if ( status == ERROR_NO_TOKEN )
{
break;
}
goto Failed;
}
//
// process boot file line
//
status = processBootFileLine( &ParseInfo );
if ( status != ERROR_SUCCESS )
{
goto Failed;
}
} // loop until file read
DNS_DEBUG( INIT, (
"Closing boot file.\n\n" ));
CloseMappedFile( & mfBootFile );
//
// boot file post processing
// - load additional zone info from registry
// (but do NOT load other registry zones)
// - write boot file info to SrvCfg block and registry
//
status = Boot_ProcessRegistryAfterAlternativeLoad(
TRUE, // boot file load
FALSE // do not load other zones, delete them
);
Failed:
return( status );
}
//
// Boot file line type specific processing functions
//
/*++
Routine Description:
Process boot file line type line.
Arguments:
pParseInfo - parsed line structure
Return Value:
ERROR_SUCCESS if successful.
Error code on line processing failure.
--*/
DNS_STATUS
processPrimaryLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
PZONE_INFO pzone;
DNS_STATUS status;
CHAR szfilename[ MAX_PATH + 1 ];
CHAR szzonename[ DNS_MAX_NAME_BUFFER_LENGTH ];
//
// primary <zone name> <zone file>
//
if ( Argc != 2 )
{
return DNSSRV_ERROR_MISSING_TOKEN;
}
//
// The zone name and boot file name may contain octal-escaped
// UTF-8 characters we need to convert the octal escapes
// back into characters.
//
*szzonename = '\0';
File_CopyFileTextData(
szzonename,
sizeof( szzonename ),
Argv[ 0 ].pchToken,
Argv[ 0 ].cchLength,
FALSE );
*szfilename = '\0';
File_CopyFileTextData(
szfilename,
sizeof( szfilename ),
Argv[ 1 ].pchToken,
Argv[ 1 ].cchLength,
FALSE );
//
// create primary zone
//
status = Zone_Create(
&pzone,
DNS_ZONE_TYPE_PRIMARY,
szzonename,
0,
NULL, // no masters
FALSE, // use file
NULL, // naming context
szfilename,
0,
NULL,
NULL ); // existing zone
if ( status != ERROR_SUCCESS )
{
File_LogFileParsingError(
DNS_EVENT_ZONE_CREATION_FAILED,
pParseInfo,
Argv );
DNS_DEBUG( INIT, (
"ERROR: Zone creation failed.\n" ));
}
return( status );
}
/*
This function is used to create any zone which has a master IP
list. zoneType may be
DNS_ZONE_TYPE_SECONDARY
DNS_ZONE_TYPE_STUB
DNS_ZONE_TYPE_FORWARDER
*/
DNS_STATUS
createSecondaryZone(
IN int zoneType,
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
DWORD i;
PIP_ARRAY arrayMasters = NULL;
PTOKEN zoneToken;
PTOKEN fileToken = NULL;
PZONE_INFO pzone;
DNS_STATUS status;
//
// secondary <zone name> <master IPs> [<zone file>]
//
if ( Argc < 2 )
{
return DNSSRV_ERROR_MISSING_TOKEN;
}
// save zone name token
zoneToken = Argv;
NEXT_TOKEN( Argc, Argv );
// allocate master IP array
arrayMasters = DnsCreateIpArray( Argc );
if ( !arrayMasters )
{
return( DNS_ERROR_NO_MEMORY );
}
Mem_VerifyHeapBlock( arrayMasters, MEMTAG_DNSLIB, 0 );
//
// read in master IP addresses
//
// if last string doesn't parse to IP and
// have successfully parsed at least one IP,
// then treat last string as file name
//
for( i=0; i<Argc; i++ )
{
if ( ! File_ParseIpAddress(
& arrayMasters->AddrArray[i],
Argv,
NULL // conversion not required
) )
{
if ( i == Argc-1 && i > 0 )
{
fileToken = Argv;
arrayMasters->AddrCount = i;
break;
}
File_LogFileParsingError(
DNS_EVENT_INVALID_IP_ADDRESS_STRING,
pParseInfo,
Argv );
status = DNSSRV_PARSING_ERROR;
goto Done;
}
Argv++;
}
//
// create secondary zone
//
status = Zone_Create(
&pzone,
zoneType,
zoneToken->pchToken,
zoneToken->cchLength,
arrayMasters,
FALSE, // use file
NULL, // naming context
fileToken ? fileToken->pchToken : NULL,
fileToken ? fileToken->cchLength : 0,
NULL,
NULL ); // existing zone
if ( status != ERROR_SUCCESS )
{
File_LogFileParsingError(
DNS_EVENT_ZONE_CREATION_FAILED,
pParseInfo,
Argv );
DNS_DEBUG( INIT, (
"ERROR: Secondary zone (type %d) creation failed.\n",
zoneType ));
}
Done:
FREE_HEAP( arrayMasters );
return( status );
}
DNS_STATUS
processSecondaryLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
return createSecondaryZone(
DNS_ZONE_TYPE_SECONDARY,
Argc,
Argv,
pParseInfo );
}
DNS_STATUS
processStubLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
return createSecondaryZone(
DNS_ZONE_TYPE_STUB,
Argc,
Argv,
pParseInfo );
}
DNS_STATUS
processDomainForwarderLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
return createSecondaryZone(
DNS_ZONE_TYPE_FORWARDER,
Argc,
Argv,
pParseInfo );
}
DNS_STATUS
processCacheLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
DNS_STATUS status;
//
// cache . <cache file>
//
if ( Argc != 2 )
{
return DNSSRV_ERROR_MISSING_TOKEN;
}
//
// set cache file
//
status = Zone_DatabaseSetup(
g_pCacheZone,
FALSE, // use file
Argv[1].pchToken,
Argv[1].cchLength
);
if ( status != ERROR_SUCCESS )
{
File_LogFileParsingError(
DNS_EVENT_ZONE_CREATION_FAILED,
pParseInfo,
Argv );
DNS_DEBUG( INIT, (
"ERROR: Cache zone creation failed.\n" ));
return( DNSSRV_PARSING_ERROR );
}
return( ERROR_SUCCESS );
}
DNS_STATUS
processForwardersLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
PIP_ARRAY arrayForwarders;
DWORD i;
if ( Argc == 0 )
{
File_LogFileParsingError(
DNS_EVENT_NO_FORWARDING_ADDRESSES,
pParseInfo,
NULL );
return DNSSRV_ERROR_MISSING_TOKEN;
}
// allocate forwarders array
arrayForwarders = DnsCreateIpArray( Argc );
if ( !arrayForwarders )
{
return( DNS_ERROR_NO_MEMORY );
}
Mem_VerifyHeapBlock( arrayForwarders, MEMTAG_DNSLIB, 0 );
// read in forwarders IP addresses
for( i=0; i<Argc; i++ )
{
if ( ! File_ParseIpAddress(
& arrayForwarders->AddrArray[i],
Argv,
pParseInfo ) )
{
return( DNSSRV_PARSING_ERROR );
}
Argv++;
}
BootInfo.aipForwarders = arrayForwarders;
return( ERROR_SUCCESS );
}
DNS_STATUS
processSlaveLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
if ( Argc != 0 )
{
return DNSSRV_ERROR_EXCESS_TOKEN;
}
BootInfo.fSlave = TRUE;
return( ERROR_SUCCESS );
}
DNS_STATUS
processOptionsLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
DWORD index;
if ( Argc == 0 )
{
return DNSSRV_ERROR_MISSING_TOKEN;
}
//
// read \ process all options
//
// DEVNOTE: we could expose these options in the bootfile as well
// - would need to have positive as well as negative
// - would need to limit ourselves to binary options
//
while( Argc )
{
// get option index
// currently just support "no-recursion" option
if ( Argv->cchLength == 12 &&
_stricmp( Argv->pchToken, "no-recursion" ) )
{
BootInfo.fNoRecursion = TRUE;
}
else
{
DNS_PRINT((
"ERROR: Unknown server property %*s.\n",
Argv[0].cchLength,
Argv[0].pchToken ));
File_LogFileParsingError(
DNS_EVENT_UNKNOWN_BOOTFILE_OPTION,
pParseInfo,
Argv );
}
NEXT_TOKEN( Argc, Argv );
}
return( ERROR_SUCCESS );
}
DNS_STATUS
processDirectoryLine(
IN DWORD Argc,
IN PTOKEN Argv,
IN OUT PPARSE_INFO pParseInfo
)
{
DNS_STATUS status;
//
// $directory <directory name>
//
if ( Argc == 0 )
{
File_LogFileParsingError(
DNS_EVENT_MISSING_DIRECTORY_NAME,
pParseInfo,
NULL );
return( ERROR_SUCCESS );
}
//
// create directory
//
status = Config_ReadDatabaseDirectory(
Argv->pchToken,
Argv->cchLength
);
if ( status != ERROR_SUCCESS )
{
File_LogFileParsingError(
DNS_EVENT_DIRECTORY_DIRECTIVE,
pParseInfo,
NULL );
}
return( ERROR_SUCCESS );
}
//
// Dispatching to boot file line type specific processing
//
typedef struct _DnsBootLineInfo
{
DWORD CharCount;
PCHAR String;
DNS_STATUS (* BootLineFunction)(DWORD, PTOKEN, PPARSE_INFO);
}
DNS_BOOT_LINE_INFO;
DNS_BOOT_LINE_INFO DnsBootLineTable[] =
{
7, "primary", processPrimaryLine,
9, "secondary", processSecondaryLine,
5, "cache", processCacheLine,
7, "options", processOptionsLine,
10, "forwarders", processForwardersLine,
5, "slave", processSlaveLine,
9, "directory", processDirectoryLine,
4, "stub", processStubLine,
7, "forward", processDomainForwarderLine,
0, NULL, NULL
};
DNS_STATUS
processBootFileLine(
IN OUT PPARSE_INFO pParseInfo
)
/*++
Routine Description:
Process line from boot file.
Arguments:
pParseInfo - parsed line structure
Return Value:
ERROR_SUCCESS if successful.
Error code on line processing failure.
--*/
{
DWORD argc;
PTOKEN argv;
PCHAR pch;
DWORD cch;
DWORD charCount;
INT i = 0;
// get register arg variables
//
// dispatch based on line type
//
argc = pParseInfo->Argc;
argv = pParseInfo->Argv;
ASSERT( argc > 0 );
pch = argv->pchToken;
cch = argv->cchLength;
while ( 1 )
{
charCount = DnsBootLineTable[i].CharCount;
if ( charCount == 0 )
{
break;
}
if ( charCount == cch &&
_strnicmp( pch, DnsBootLineTable[i].String, cch ) == 0 )
{
NEXT_TOKEN( argc, argv );
return( DnsBootLineTable[i].BootLineFunction(
argc,
argv,
pParseInfo ) );
}
i++;
}
// line type not matched
// - log the error
// - return SUCCESS to attempt to continue to load
File_LogFileParsingError(
DNS_EVENT_UNKNOWN_DIRECTIVE,
pParseInfo,
argv );
//return( ERROR_INVALID_PARAMETER );
return( ERROR_SUCCESS );
}
//
// Boot file writing routines
//
DNS_STATUS
writeForwardersToBootFile(
IN HANDLE hFile
)
/*++
Routine Description:
Write forwarders from registry to file.
Arguments:
hFile -- file handle.
Return Value:
ERROR_SUCCESS if successful.
Error code on failure.
--*/
{
DNS_STATUS status = ERROR_SUCCESS;
LPSTR pszforwarders = NULL;
//
// write forwarders to file
//
if ( !SrvCfg_aipForwarders )
{
DNS_DEBUG( INIT, ( "No forwarders found.\n" ));
return( status );
}
DNS_DEBUG( INIT, ( "Writing forwarders to boot file.\n" ));
pszforwarders = createStringFromIpAddressArray (
SrvCfg_aipForwarders->AddrCount,
SrvCfg_aipForwarders->AddrArray);
if ( pszforwarders )
{
FormattedWriteFile(
hFile,
"forwarders\t\t%s\r\n",
pszforwarders);
FREE_HEAP ( pszforwarders );
}
//
// write slave
//
if ( SrvCfg_fSlave )
{
FormattedWriteFile(
hFile,
"slave\r\n");
}
return( status );
}
DNS_STATUS
writeZoneToBootFile(
IN HANDLE hFile,
IN PZONE_INFO pZone
)
/*++
Routine Description:
Write back the zone info to boot file.
Arguments:
hFile -- file handle for write
pZone -- ptr to zone block
Return Value:
TRUE if successful.
FALSE otherwise.
--*/
{
#define LEN_ZONE_NAME_BUFFER (4*DNS_MAX_NAME_LENGTH + 1)
#define LEN_FILE_NAME_BUFFER (4*MAX_PATH + 1)
DNS_STATUS status = ERROR_SUCCESS;
LPSTR pszmasterIp = NULL;
CHAR szzoneName[ LEN_ZONE_NAME_BUFFER ];
CHAR szfileName[ LEN_FILE_NAME_BUFFER ] = "";
PCHAR pszZoneTypeString = NULL;
DNS_DEBUG( INIT, (
"\nWriting zone %s info to boot file.\n",
pZone->pszZoneName ));
//
// convert zone name and file name
// to handle printing of UTF8
//
File_PlaceStringInFileBuffer(
szzoneName,
szzoneName + LEN_ZONE_NAME_BUFFER,
FILE_WRITE_DOTTED_NAME,
pZone->pszZoneName,
strlen(pZone->pszZoneName) );
if ( pZone->pszDataFile )
{
File_PlaceStringInFileBuffer(
szfileName,
szfileName + LEN_FILE_NAME_BUFFER,
FILE_WRITE_FILE_NAME,
pZone->pszDataFile,
strlen(pZone->pszDataFile) );
}
//
// write zone info based on zone type
//
switch ( pZone->fZoneType )
{
case DNS_ZONE_TYPE_PRIMARY:
// no DS zones get written back, must be file backed for bootfile
if ( pZone->fDsIntegrated )
{
break;
}
FormattedWriteFile(
hFile,
"%-12s %-27s %s\r\n",
DNS_ZONE_TYPE_NAME_PRIMARY,
szzoneName,
szfileName );
break;
case DNS_ZONE_TYPE_STUB:
pszZoneTypeString = DNS_ZONE_TYPE_NAME_STUB;
// Fall through to DNS_ZONE_TYPE_FORWARDER processing.
case DNS_ZONE_TYPE_FORWARDER:
if ( !pszZoneTypeString )
{
pszZoneTypeString = DNS_ZONE_TYPE_NAME_FORWARDER;
}
// Fall through to DNS_ZONE_TYPE_FORWARDER processing.
case DNS_ZONE_TYPE_SECONDARY:
if ( !pszZoneTypeString )
{
pszZoneTypeString = DNS_ZONE_TYPE_NAME_SECONDARY;
}
if ( !pZone->aipMasters )
{
DNS_PRINT(( "ERROR: %s zone without master array!!!\n",
pszZoneTypeString ));
ASSERT( FALSE );
break;
}
pszmasterIp = createStringFromIpAddressArray (
pZone->aipMasters->AddrCount,
pZone->aipMasters->AddrArray );
if ( pZone->pszDataFile )
{
FormattedWriteFile(
hFile,
"%-12s %-27s %s %s\r\n",
pszZoneTypeString,
szzoneName,
pszmasterIp,
szfileName );
}
else
{
FormattedWriteFile(
hFile,
"%-12s %-27s %s\r\n",
pszZoneTypeString,
szzoneName,
pszmasterIp );
}
FREE_HEAP( pszmasterIp );
break;
case DNS_ZONE_TYPE_CACHE:
// if empty cache file name -- converted from DS -- put in standard name
if ( szfileName[0] == 0 )
{
strcpy( szfileName, DNS_DEFAULT_CACHE_FILE_NAME_UTF8 );
}
FormattedWriteFile(
hFile,
"%-12s %-27s %s\r\n",
DNS_ZONE_TYPE_NAME_CACHE,
".",
szfileName );
break;
default:
return( DNS_ERROR_INVALID_ZONE_TYPE );
}
return( status );
}
BOOL
File_WriteBootFilePrivate(
IN HANDLE hFile
)
/*++
Routine Description:
Write boot info in the registry to file.
Arguments:
hFile -- file handle of target file
Return Value:
TRUE if successful write.
FALSE on error.
--*/
{
DWORD status;
PZONE_INFO pzone = NULL;
//
// lock out admin access
//
Config_UpdateLock();
Zone_UpdateLock( NULL );
//
// write server configuration data
// - forwarders \ slave
// - no BIND secondaries
// - no recursion option
//
status = writeForwardersToBootFile(hFile);
if ( status != ERROR_SUCCESS )
{
return( FALSE );
}
if ( SrvCfg_fNoRecursion )
{
FormattedWriteFile(
hFile,
"options no-recursion\r\n");
}
//
// walk zones -- write each back
// note continue on failure
//
while( pzone = Zone_ListGetNextZone(pzone) )
{
if ( pzone->fAutoCreated )
{
continue;
}
if ( IS_ZONE_CACHE(pzone) && IS_ROOT_AUTHORITATIVE() )
{
continue;
}
status = writeZoneToBootFile( hFile, pzone );
if ( status != ERROR_SUCCESS )
{
DNS_PRINT((
"ERROR: Writing zone %s to boot file failed.\n",
pzone->pszZoneName ));
}
}
//
// unlock for admin access
// enable write back to registry from creation functions,
//
Config_UpdateUnlock();
Zone_UpdateUnlock( NULL );
return( TRUE );
}
LPSTR
createStringFromIpAddressArray(
IN DWORD dwIpAddrCount,
IN PIP_ADDRESS pIpAddrs
)
/*++
Routine Description:
Create a IP string from IP address array.
The caller is supposed to free the memory.
Arguments:
dwIpAddrCount -- number of Ip address in the array.
pIpAddrs -- array of Ip address
Return Value:
Ptr to string copy -- if successful
NULL on failure.
--*/
{
LPSTR pszmasterIp;
DWORD i;
DWORD countChar = 0;
if ( !pIpAddrs || dwIpAddrCount == 0 )
{
return( NULL );
}
//
// allocate memory
//
pszmasterIp = (LPSTR) ALLOCATE_HEAP(
dwIpAddrCount * (IP_ADDRESS_STRING_LENGTH + 1)
+ 1 );
if( !pszmasterIp )
{
return( NULL );
}
//
// copy IP address from pIpAddrs to string one by one
// use character print so works even if NOT DWORD aligned
//
for( i=0; i<dwIpAddrCount; i++ )
{
countChar += sprintf(
pszmasterIp + countChar,
"%d.%d.%d.%d ",
* ( (PUCHAR) &pIpAddrs[i] + 0 ),
* ( (PUCHAR) &pIpAddrs[i] + 1 ),
* ( (PUCHAR) &pIpAddrs[i] + 2 ),
* ( (PUCHAR) &pIpAddrs[i] + 3 ) );
}
return( pszmasterIp);
}
VOID
removeTrailDotFromString(
IN OUT LPSTR lpzString
)
/*++
Routine Description:
Remove the trailing dot from string.
If the string only contains a dot then keep that dot.
Arguments:
lpzString -- ptr to sting to copy
Return Value:
None.
--*/
{
DWORD length;
if ( !lpzString )
{
return;
}
//
// remove trailing dot ONLY if not root name (".")
//
length = strlen( lpzString );
if ( length != 0 && length != 1 && lpzString[length - 1] == '.')
{
lpzString[length - 1] = 0;
}
return;
}
BOOL
File_WriteBootFile(
VOID
)
/*++
Routine Description:
Write boot info in the registry back to boot file.
Arguments:
None.
Return Value:
ERROR_SUCCESS, if successful
ErrorCode on failure.
--*/
{
LPSTR pwsbootFile;
HANDLE hfileBoot;
DNS_DEBUG( WRITE, ( "\n\nWriteBootFile()\n" ));
//
// save current boot file
// - save to first backup, if no existing (attempt to save
// last human created boot file
// - save existing to last backup no matter what
//
MoveFile(
DNS_BOOT_FILE_PATH,
DNS_BOOT_FILE_FIRST_BACKUP
);
MoveFileEx(
DNS_BOOT_FILE_PATH,
DNS_BOOT_FILE_LAST_BACKUP,
MOVEFILE_REPLACE_EXISTING
);
//
// open boot file
//
hfileBoot = OpenWriteFileEx(
DNS_BOOT_FILE_PATH,
FALSE // overwrite
);
if ( ! hfileBoot )
{
DNS_PRINT(( "ERROR: Unable to open boot file for write.\n" ));
return( FALSE );
}
//
// write boot info
//
FormattedWriteFile(
hfileBoot,
";\r\n"
"; Boot information written back by DNS server.\r\n"
";\r\n\r\n");
if ( ! File_WriteBootFilePrivate(hfileBoot) )
{
DNS_LOG_EVENT(
DNS_EVENT_BOOTFILE_WRITE_ERROR,
0,
NULL,
NULL,
0 );
DNS_DEBUG( ANY, ( "ERROR: Failure writing boot file.\n" ));
CloseHandle( hfileBoot );
// save write error file for debug
// then replace boot file with last backup
MoveFileEx(
DNS_BOOT_FILE_PATH,
DNS_BOOT_FILE_WRITE_ERROR,
MOVEFILE_REPLACE_EXISTING
);
MoveFileEx(
DNS_BOOT_FILE_LAST_BACKUP,
DNS_BOOT_FILE_PATH,
MOVEFILE_REPLACE_EXISTING
);
return( FALSE );
}
//
// close up file, reset dirty flag
//
SrvCfg_fBootFileDirty = FALSE;
CloseHandle( hfileBoot );
DNS_LOG_EVENT(
DNS_EVENT_BOOTFILE_REWRITE,
0,
NULL,
NULL,
0 );
return( TRUE );
}
//
// End of bootfile.c
//