/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: sysfileupd.c Abstract: This module implements routines to update system files on XDK. --*/ #include "dmp.h" #undef DeleteFile NTSTATUS ReplaceFile( IN OBJECT_STRING* NewFileName, IN HANDLE ExistingHandle ) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjA; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo; FILE_RENAME_INFORMATION RenameInfo; // Clear read-only file attribute as needed InitializeObjectAttributes(&ObjA, NewFileName, OBJ_CASE_INSENSITIVE, 0, 0); Status = NtOpenFile(&Handle, (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &ObjA, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (NT_SUCCESS(Status)) { RtlZeroMemory(&BasicInfo,sizeof(BasicInfo)); BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; NtSetInformationFile(Handle, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation); NtClose(Handle); } // Rename the file RenameInfo.ReplaceIfExists = TRUE; RenameInfo.RootDirectory = 0; RenameInfo.FileName.Length = NewFileName->Length; RenameInfo.FileName.MaximumLength = NewFileName->MaximumLength; RenameInfo.FileName.Buffer = NewFileName->Buffer; Status = NtSetInformationFile(ExistingHandle, &IoStatusBlock, &RenameInfo, sizeof(RenameInfo), FileRenameInformation); return Status; } HRESULT HrReceiveSystemFile(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse) { CCS *pccs = (CCS *)pdmcc->CustomData; FILE_DISPOSITION_INFORMATION fdi; IO_STATUS_BLOCK IoStatusBlock; NTSTATUS Status; if (pdmcc->DataSize) { pccs->sysupd.BytesReceived += pdmcc->DataSize; ASSERT(pccs->sysupd.BytesReceived <= DISK_BUF_SIZE); pdmcc->BytesRemaining -= pdmcc->DataSize; } else if (pdmcc->BytesRemaining) { DmFreePool(pccs->sysupd.FileBuffer); DmFreePool(pccs->sysupd.FileName.Buffer); fdi.DeleteFile = TRUE; NtSetInformationFile(pccs->sysupd.FileHandle, &IoStatusBlock, &fdi, sizeof(fdi), FileDispositionInformation); _snprintf(szResponse, cchResponse, "Unexpected data size"); szResponse[cchResponse - 1] = 0; return E_UNEXPECTED; } // See if we're ready for a disk write if (!pdmcc->BytesRemaining || pccs->sysupd.BytesReceived == DISK_BUF_SIZE) { pccs->sysupd.Crc = Crc32(pccs->sysupd.Crc, pccs->sysupd.FileBuffer, pccs->sysupd.BytesReceived); Status = NtWriteFile(pccs->sysupd.FileHandle, NULL, NULL, NULL, &IoStatusBlock, pccs->sysupd.FileBuffer, pccs->sysupd.BytesReceived, NULL); if (!NT_SUCCESS(Status)) { cleanup: fdi.DeleteFile = TRUE; NtSetInformationFile(pccs->sysupd.FileHandle, &IoStatusBlock, &fdi, sizeof(fdi), FileDispositionInformation); NtClose(pccs->sysupd.FileHandle); pccs->sysupd.FileHandle = NULL; _snprintf(szResponse, cchResponse, "File write error"); szResponse[cchResponse - 1] = 0; return HrFromStatus(Status, XBDM_CANNOTCREATE); } else if (!pdmcc->BytesRemaining) { if (pccs->sysupd.Crc != pccs->sysupd.ExpectedCrc) { _snprintf(szResponse, cchResponse, "Invalid CRC"); szResponse[cchResponse - 1] = 0; goto cleanup; } Status = ReplaceFile(&pccs->sysupd.FileName, pccs->sysupd.FileHandle); if (!NT_SUCCESS(Status)) { _snprintf(szResponse, cchResponse, "Replace file failed (0x%X)", Status); szResponse[cchResponse - 1] = 0; goto cleanup; } NtClose(pccs->sysupd.FileHandle); } pccs->sysupd.BytesReceived = 0; if (!pdmcc->BytesRemaining) { DmFreePool(pccs->sysupd.FileBuffer); pccs->sysupd.FileBuffer = NULL; } } // Make sure the buffer pointer is set up pdmcc->Buffer = pccs->sysupd.FileBuffer + pccs->sysupd.BytesReceived; pdmcc->BufferSize = DISK_BUF_SIZE - pccs->sysupd.BytesReceived; return XBDM_NOERR; } VOID CreateDirectoryFromPath( IN CONST OBJECT_STRING* Path ) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjA; HANDLE Handle; OBJECT_STRING FileName; IO_STATUS_BLOCK IoStatusBlock; WORD Length; FileName.Buffer = Path->Buffer; Length = FileName.Length = Path->Length; FileName.MaximumLength = Path->MaximumLength; InitializeObjectAttributes(&ObjA, &FileName, OBJ_CASE_INSENSITIVE, 0, 0); // REVIEW: there should be a better way to do this for (FileName.Length=1; FileName.LengthCustomData; // Get file size and CRC32 of entire file if (!FGetNamedDwParam(sz, "size", &pdmcc->BytesRemaining, szResp) || \ !FGetNamedDwParam(sz, "crc", &pccs->sysupd.ExpectedCrc, szResp)) { _snprintf(szResp, cchResp, "Invalid parameter(s)"); szResp[cchResp - 1] = 0; return E_FAIL; } // Allocate buffer for file name and file buffer pccs->sysupd.FileBuffer = DmAllocatePoolWithTag( DISK_BUF_SIZE + sizeof(buffer), 'ufsx'); if (!pccs->sysupd.FileBuffer) { _snprintf(szResp, cchResp, "Not enough memory"); szResp[cchResp - 1] = 0; return E_OUTOFMEMORY; } pccs->sysupd.FileName.Length = 0; pccs->sysupd.FileName.MaximumLength = sizeof(buffer); pccs->sysupd.FileName.Buffer = (PCHAR)\ ((ULONG_PTR)pccs->sysupd.FileBuffer + DISK_BUF_SIZE); if (!FGetSzParam(sz, "name", pccs->sysupd.FileName.Buffer, pccs->sysupd.FileName.MaximumLength/sizeof(OCHAR))) { _snprintf(szResp, cchResp, "missing or invalid file name"); szResp[cchResp - 1] = 0; hr = E_FAIL; goto cleanup; } pccs->sysupd.FileName.Length = strlen(pccs->sysupd.FileName.Buffer) * \ sizeof(OCHAR); ASSERT(pccs->sysupd.FileName.Length < sizeof(buffer)); // Create temporary file which later will be renamed to the real target strcpy(buffer, pccs->sysupd.FileName.Buffer); psz = strrchr(buffer, '\\'); if (!psz || sizeof(buffer) - ((ULONG_PTR)psz - (ULONG_PTR)buffer + 1) < \ sizeof("\\temp1234.tmp")) { _snprintf(szResp, cchResp, "Invalid file name"); szResp[cchResp - 1] = 0; hr = E_INVALIDARG; goto cleanup; } sprintf(psz, "\\temp%04x.tmp", NtGetTickCount() & 0xFFFF); RtlInitObjectString(&ObjS, buffer); InitializeObjectAttributes(&ObjA, &ObjS, OBJ_CASE_INSENSITIVE, 0, 0); CreateDirectoryFromPath(&ObjS); FileSize.HighPart = 0; FileSize.LowPart = pdmcc->BytesRemaining; Status = NtCreateFile(&pccs->sysupd.FileHandle, GENERIC_WRITE | DELETE | SYNCHRONIZE, &ObjA, &IoStatusBlock, &FileSize, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (NT_SUCCESS(Status)) { // Commit the size of the file feof.EndOfFile = FileSize; Status = NtSetInformationFile(pccs->sysupd.FileHandle, &IoStatusBlock, &feof, sizeof(feof), FileEndOfFileInformation); if (NT_SUCCESS(Status)) { pccs->sysupd.BytesReceived = 0; pccs->sysupd.Crc = ~0UL; pdmcc->Buffer = pccs->sysupd.FileBuffer; pdmcc->BufferSize = DISK_BUF_SIZE; pdmcc->HandlingFunction = HrReceiveSystemFile; return XBDM_READYFORBIN; } else { // Mark the file for deletion and close the file fdi.DeleteFile = TRUE; NtSetInformationFile(&pccs->sysupd.FileHandle, &IoStatusBlock, &fdi, sizeof(fdi), FileDispositionInformation); NtClose(pccs->sysupd.FileHandle); pccs->sysupd.FileHandle = NULL; _snprintf(szResp, cchResp, "Disk full"); szResp[cchResp - 1] = 0; } } hr = HrFromStatus(Status, XBDM_CANNOTCREATE); cleanup: DmFreePool(pccs->sysupd.FileBuffer); return hr; }