void WINAPI redirect_RtlFreeOemString(OEM_STRING *string) { if (is_dynamo_address((app_pc)string->Buffer)) { PEB *peb = get_peb(NT_CURRENT_PROCESS); redirect_RtlFreeHeap(peb->ProcessHeap, 0, (byte *)string->Buffer); memset(string, 0, sizeof(*string)); } else RtlFreeOemString(string); }
NTSTATUS NTAPI NtDisplayString(IN PUNICODE_STRING DisplayString) { OEM_STRING OemString; /* Convert the string to OEM and display it */ RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE); InbvDisplayString(OemString.Buffer); RtlFreeOemString(&OemString); /* Return success */ return STATUS_SUCCESS; }
bool mod_hash::lm(wstring * chaine, wstring * hash) { bool status = false; UNICODE_STRING maChaine; OEM_STRING maDestination; BYTE monTab[16]; RtlInitUnicodeString(&maChaine, chaine->c_str()); if(NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&maDestination, &maChaine, TRUE))) { if(status = NT_SUCCESS(SystemFunction006(maDestination.Buffer, monTab))) hash->assign(mod_text::stringOfHex(monTab, sizeof(monTab))); RtlFreeOemString(&maDestination); } return status; }
VOID FatRemoveNames ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ) /*++ Routine Description: This routine will remove the short name and any long names associated with the files from their repsective splay tree. Arguments: Name - Supplies the Fcb to process. Return Value: None. --*/ { PDCB Parent; PRTL_SPLAY_LINKS NewRoot; PAGED_CODE(); Parent = Fcb->ParentDcb; // // We used to assert this condition, but it really isn't good. If // someone rapidly renames a directory multiple times and we can't // flush the lower fcbs fast enough (that didn't go away synch.) // well, well hit some of them again. // // ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )); // if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) { // // Delete the node short name. // NewRoot = RtlDelete(&Fcb->ShortName.Links); Parent->Specific.Dcb.RootOemNode = NewRoot; // // Now check for the presence of long name and delete it. // if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME )) { NewRoot = RtlDelete(&Fcb->LongName.Oem.Links); Parent->Specific.Dcb.RootOemNode = NewRoot; RtlFreeOemString( &Fcb->LongName.Oem.Name.Oem ); ClearFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME ); } if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME )) { NewRoot = RtlDelete(&Fcb->LongName.Unicode.Links); Parent->Specific.Dcb.RootUnicodeNode = NewRoot; RtlFreeUnicodeString( &Fcb->LongName.Unicode.Name.Unicode ); ClearFlag( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME ); } ClearFlag( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE ); } return; }
NTSTATUS Fat32Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context) { FAT32_BOOT_SECTOR BootSector; OEM_STRING VolumeLabel; ULONG TmpVal1; ULONG TmpVal2; NTSTATUS Status; /* Calculate cluster size */ if (ClusterSize == 0) { if (PartitionInfo->PartitionLength.QuadPart < 8LL * 1024LL * 1024LL * 1024LL) { /* Partition < 8GB ==> 4KB Cluster */ ClusterSize = 4096; } else if (PartitionInfo->PartitionLength.QuadPart < 16LL * 1024LL * 1024LL * 1024LL) { /* Partition 8GB - 16GB ==> 8KB Cluster */ ClusterSize = 8192; } else if (PartitionInfo->PartitionLength.QuadPart < 32LL * 1024LL * 1024LL * 1024LL) { /* Partition 16GB - 32GB ==> 16KB Cluster */ ClusterSize = 16384; } else { /* Partition >= 32GB ==> 32KB Cluster */ ClusterSize = 32768; } } memset(&BootSector, 0, sizeof(FAT32_BOOT_SECTOR)); memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); BootSector.BytesPerSector = DiskGeometry->BytesPerSector; BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; BootSector.ReservedSectors = 32; BootSector.FATCount = 2; BootSector.RootEntries = 0; BootSector.Sectors = 0; BootSector.Media = 0xf8; BootSector.FATSectors = 0; BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; BootSector.Heads = DiskGeometry->TracksPerCylinder; BootSector.HiddenSectors = PartitionInfo->HiddenSectors; BootSector.SectorsHuge = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(BootSector.BytesPerSector); /* Use shifting to avoid 64-bit division */ BootSector.FATSectors32 = 0; /* Set later */ BootSector.ExtFlag = 0; /* Mirror all FATs */ BootSector.FSVersion = 0x0000; /* 0:0 */ BootSector.RootCluster = 2; BootSector.FSInfoSector = 1; BootSector.BootBackup = 6; BootSector.Drive = (DiskGeometry->MediaType == FixedMedia) ? 0x80 : 0x00; BootSector.ExtBootSignature = 0x29; BootSector.VolumeID = CalcVolumeSerialNumber (); if ((Label == NULL) || (Label->Buffer == NULL)) { memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); } else { RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE); memset(&BootSector.VolumeLabel[0], ' ', 11); memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); RtlFreeOemString(&VolumeLabel); } memcpy(&BootSector.SysType[0], "FAT32 ", 8); /* Calculate number of FAT sectors */ /* (BytesPerSector / 4) FAT entries (32bit) fit into one sector */ TmpVal1 = BootSector.SectorsHuge - BootSector.ReservedSectors; TmpVal2 = ((BootSector.BytesPerSector / 4) * BootSector.SectorsPerCluster) + BootSector.FATCount; BootSector.FATSectors32 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; DPRINT("FATSectors32 = %lu\n", BootSector.FATSectors32); /* Init context data */ Context->TotalSectorCount = 2 + (BootSector.FATSectors32 * BootSector.FATCount) + BootSector.SectorsPerCluster; if (!QuickFormat) { Context->TotalSectorCount += BootSector.SectorsHuge; Status = Fat32WipeSectors(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WipeSectors() failed with status 0x%.08x\n", Status); return Status; } } Status = Fat32WriteBootSector(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status); return Status; } Status = Fat32WriteFsInfo(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status); return Status; } /* Write first FAT copy */ Status = Fat32WriteFAT(FileHandle, 0, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status); return Status; } /* Write second FAT copy */ Status = Fat32WriteFAT(FileHandle, BootSector.FATSectors32, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status); return Status; } Status = Fat32WriteRootDirectory(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status); } return Status; }
NTSTATUS NdasFatSecondaryQueryDirectory ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This routine performs the query directory operation. It is responsible for either completing of enqueuing the input Irp. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVCB Vcb; PDCB Dcb; PCCB Ccb; PBCB Bcb; ULONG i; PUCHAR Buffer; CLONG UserBufferLength; PUNICODE_STRING UniArgFileName; WCHAR LongFileNameBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE]; UNICODE_STRING LongFileName; FILE_INFORMATION_CLASS FileInformationClass; ULONG FileIndex; BOOLEAN RestartScan; BOOLEAN ReturnSingleEntry; BOOLEAN IndexSpecified; BOOLEAN InitialQuery; VBO CurrentVbo; BOOLEAN UpdateCcb; PDIRENT Dirent; UCHAR Fat8Dot3Buffer[12]; OEM_STRING Fat8Dot3String; ULONG DiskAllocSize; ULONG NextEntry; ULONG LastEntry; PFILE_DIRECTORY_INFORMATION DirInfo; PFILE_FULL_DIR_INFORMATION FullDirInfo; PFILE_BOTH_DIR_INFORMATION BothDirInfo; PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo; PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo; PFILE_NAMES_INFORMATION NamesInfo; #if 1 PVOLUME_DEVICE_OBJECT volDo; BOOLEAN secondarySessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; _U8 *ndfsWinxpRequestData; LARGE_INTEGER timeOut; struct QueryDirectory queryDirectory; PVOID inputBuffer; ULONG inputBufferLength; ULONG returnedDataSize; #endif PAGED_CODE(); // // Get the current Stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Display the input values. // DebugTrace(+1, Dbg, "FatQueryDirectory...\n", 0); DebugTrace( 0, Dbg, " Wait = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.QueryDirectory.Length); DebugTrace( 0, Dbg, " ->FileName = %08lx\n", IrpSp->Parameters.QueryDirectory.FileName); DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass); DebugTrace( 0, Dbg, " ->FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex); DebugTrace( 0, Dbg, " ->UserBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer); DebugTrace( 0, Dbg, " ->RestartScan = %08lx\n", FlagOn( IrpSp->Flags, SL_RESTART_SCAN )); DebugTrace( 0, Dbg, " ->ReturnSingleEntry = %08lx\n", FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )); DebugTrace( 0, Dbg, " ->IndexSpecified = %08lx\n", FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )); // // Reference our input parameters to make things easier // UserBufferLength = IrpSp->Parameters.QueryDirectory.Length; FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; UniArgFileName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName; RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN); ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); // // Check on the type of open. We return invalid parameter for all // but UserDirectoryOpens. Also check that the filename is a valid // UNICODE string. // if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Dcb, &Ccb) != UserDirectoryOpen || (UniArgFileName && UniArgFileName->Length % sizeof(WCHAR))) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg, "FatQueryDirectory -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; } #if 1 if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { ASSERT( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); FatCompleteRequest( IrpContext, Irp, STATUS_FILE_CORRUPT_ERROR ); DebugTrace2( -1, Dbg, ("NtfsCommonDirectoryControl -> STATUS_FILE_CORRUPT_ERROR\n") ); return STATUS_FILE_CORRUPT_ERROR; } #endif // // Initialize the local variables. // Bcb = NULL; UpdateCcb = TRUE; Dirent = NULL; Fat8Dot3String.MaximumLength = 12; Fat8Dot3String.Buffer = Fat8Dot3Buffer; LongFileName.Length = 0; LongFileName.MaximumLength = sizeof( LongFileNameBuffer); LongFileName.Buffer = LongFileNameBuffer; InitialQuery = (BOOLEAN)((Ccb->UnicodeQueryTemplate.Buffer == NULL) && !FlagOn(Ccb->Flags, CCB_FLAG_MATCH_ALL)); Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; DiskAllocSize = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster; // // If this is the initial query, then grab exclusive access in // order to update the search string in the Ccb. We may // discover that we are not the initial query once we grab the Fcb // and downgrade our status. // if (InitialQuery) { if (!FatAcquireExclusiveFcb( IrpContext, Dcb )) { DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0); Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status); return Status; } if (Ccb->UnicodeQueryTemplate.Buffer != NULL) { InitialQuery = FALSE; FatConvertToSharedFcb( IrpContext, Dcb ); } } else { if (!FatAcquireSharedFcb( IrpContext, Dcb )) { DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0); Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status); return Status; } } try { ULONG BaseLength; ULONG BytesConverted; // // If we are in the Fsp now because we had to wait earlier, // we must map the user buffer, otherwise we can use the // user's buffer directly. // Buffer = FatMapUserBuffer( IrpContext, Irp ); #if 1 volDo = CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ); secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } queryDirectory.FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; queryDirectory.FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; queryDirectory.FileName = IrpSp->Parameters.QueryDirectory.FileName; queryDirectory.Length = IrpSp->Parameters.QueryDirectory.Length; inputBuffer = (queryDirectory.FileName) ? (queryDirectory.FileName->Buffer) : NULL; inputBufferLength = (queryDirectory.FileName) ? (queryDirectory.FileName->Length) : 0; if (queryDirectory.FileName) { DebugTrace2( 0, Dbg, ("NdNtfsSecondaryQueryDirectory: queryFileName = %wZ\n", queryDirectory.FileName) ); } ASSERT( inputBufferLength <= volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize ); ASSERT( UserBufferLength <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize ); secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_DIRECTORY_CONTROL, ((inputBufferLength > UserBufferLength) ? inputBufferLength : UserBufferLength) ); if (secondaryRequest == NULL) { try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_DIRECTORY_CONTROL, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, Ccb->PrimaryFileHandle ); ndfsWinxpRequestHeader->QueryDirectory.Length = UserBufferLength; ndfsWinxpRequestHeader->QueryDirectory.FileInformationClass = queryDirectory.FileInformationClass; ndfsWinxpRequestHeader->QueryDirectory.FileIndex = queryDirectory.FileIndex; ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); if (inputBufferLength) RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); KeClearEvent( &secondaryRequest->CompleteEvent ); if (Status != STATUS_SUCCESS) { secondaryRequest = NULL; try_return( Status = STATUS_IO_DEVICE_ERROR ); } SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); secondarySessionResourceAcquired = FALSE; if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; Status = Irp->IoStatus.Status = ndfsWinxpReplytHeader->Status; Irp->IoStatus.Information = ndfsWinxpReplytHeader->Information; returnedDataSize = secondaryRequest->NdfsReplyHeader.MessageSize - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER); if (returnedDataSize) { ASSERT( ndfsWinxpReplytHeader->Information != 0 ); ASSERT(returnedDataSize <= ADD_ALIGN8(queryDirectory.Length)); ASSERT( Buffer ); RtlCopyMemory( Buffer, (_U8 *)(ndfsWinxpReplytHeader+1), (returnedDataSize < queryDirectory.Length) ? returnedDataSize : queryDirectory.Length ); } #endif #if 0 // // Make sure the Dcb is still good. // FatVerifyFcb( IrpContext, Dcb ); // // Determine where to start the scan. Highest priority is given // to the file index. Lower priority is the restart flag. If // neither of these is specified, then the Vbo offset field in the // Ccb is used. // if (IndexSpecified) { CurrentVbo = FileIndex + sizeof( DIRENT ); } else if (RestartScan) { CurrentVbo = 0; } else { CurrentVbo = Ccb->OffsetToStartSearchFrom; } // // If this is the first try then allocate a buffer for the file // name. // if (InitialQuery) { // // If either: // // - No name was specified // - An empty name was specified // - We received a '*' // - The user specified the DOS equivolent of ????????.??? // // then match all names. // if ((UniArgFileName == NULL) || (UniArgFileName->Length == 0) || (UniArgFileName->Buffer == NULL) || ((UniArgFileName->Length == sizeof(WCHAR)) && (UniArgFileName->Buffer[0] == L'*')) || ((UniArgFileName->Length == 12*sizeof(WCHAR)) && (RtlEqualMemory( UniArgFileName->Buffer, Fat8QMdot3QM, 12*sizeof(WCHAR) )))) { Ccb->ContainsWildCards = TRUE; SetFlag( Ccb->Flags, CCB_FLAG_MATCH_ALL ); } else { BOOLEAN ExtendedName = FALSE; OEM_STRING LocalBestFit; // // First and formost, see if the name has wild cards. // Ccb->ContainsWildCards = FsRtlDoesNameContainWildCards( UniArgFileName ); // // Now check to see if the name contains any extended // characters // for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) { if (UniArgFileName->Buffer[i] >= 0x80) { ExtendedName = TRUE; break; } } // // OK, now do the conversions we need. // if (ExtendedName) { Status = RtlUpcaseUnicodeString( &Ccb->UnicodeQueryTemplate, UniArgFileName, TRUE ); if (!NT_SUCCESS(Status)) { try_return( Status ); } SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE ); // // Upcase the name and convert it to the Oem code page. // Status = RtlUpcaseUnicodeStringToCountedOemString( &LocalBestFit, UniArgFileName, TRUE ); // // If this conversion failed for any reason other than // an unmappable character fail the request. // if (!NT_SUCCESS(Status)) { if (Status == STATUS_UNMAPPABLE_CHARACTER) { SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ); } else { try_return( Status ); } } else { SetFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } } else { PVOID Buffers; // // This case is optimized because I know I only have to // worry about a-z. // Buffers = FsRtlAllocatePoolWithTag( PagedPool, UniArgFileName->Length + UniArgFileName->Length / sizeof(WCHAR), TAG_FILENAME_BUFFER ); Ccb->UnicodeQueryTemplate.Buffer = Buffers; Ccb->UnicodeQueryTemplate.Length = UniArgFileName->Length; Ccb->UnicodeQueryTemplate.MaximumLength = UniArgFileName->Length; LocalBestFit.Buffer = (PUCHAR)Buffers + UniArgFileName->Length; LocalBestFit.Length = UniArgFileName->Length / sizeof(WCHAR); LocalBestFit.MaximumLength = LocalBestFit.Length; SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE ); for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) { WCHAR c = UniArgFileName->Buffer[i]; LocalBestFit.Buffer[i] = (UCHAR) (Ccb->UnicodeQueryTemplate.Buffer[i] = (c < 'a' ? c : c <= 'z' ? c - ('a' - 'A') : c)); } } // // At this point we now have the upcased unicode name, // and the two Oem names if they could be represented in // this code page. // // Now determine if the Oem names are legal for what we // going to try and do. Mark them as not usable is they // are not legal. Note that we can optimize extended names // since they are actually both the same string. // if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ) && !FatIsNameShortOemValid( IrpContext, LocalBestFit, Ccb->ContainsWildCards, FALSE, FALSE )) { if (ExtendedName) { RtlFreeOemString( &LocalBestFit ); ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ); } // // OK, now both locals oem strings correctly reflect their // usability. Now we want to load up the Ccb structure. // // Now we will branch on two paths of wheather the name // is wild or not. // if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE )) { if (Ccb->ContainsWildCards) { Ccb->OemQueryTemplate.Wild = LocalBestFit; } else { FatStringTo8dot3( IrpContext, LocalBestFit, &Ccb->OemQueryTemplate.Constant ); if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) { RtlFreeOemString( &LocalBestFit ); ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } } } } // // We convert to shared access. // FatConvertToSharedFcb( IrpContext, Dcb ); } LastEntry = 0; NextEntry = 0; switch (FileInformationClass) { case FileDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break; case FileFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break; case FileIdFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName[0] ); break; case FileNamesInformation: BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break; case FileBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break; case FileIdBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName[0] ); break; default: try_return( Status = STATUS_INVALID_INFO_CLASS ); } // // At this point we are about to enter our query loop. We have // determined the index into the directory file to begin the // search. LastEntry and NextEntry are used to index into the user // buffer. LastEntry is the last entry we've added, NextEntry is // current one we're working on. If NextEntry is non-zero, then // at least one entry was added. // while ( TRUE ) { VBO NextVbo; ULONG FileNameLength; ULONG BytesRemainingInBuffer; DebugTrace(0, Dbg, "FatQueryDirectory -> Top of loop\n", 0); // // If the user had requested only a single match and we have // returned that, then we stop at this point. // if (ReturnSingleEntry && NextEntry != 0) { try_return( Status ); } // // We call FatLocateDirent to lock down the next matching dirent. // FatLocateDirent( IrpContext, Dcb, Ccb, CurrentVbo, &Dirent, &Bcb, &NextVbo, NULL, &LongFileName); // // If we didn't receive a dirent, then we are at the end of the // directory. If we have returned any files, we exit with // success, otherwise we return STATUS_NO_MORE_FILES. // if (!Dirent) { DebugTrace(0, Dbg, "FatQueryDirectory -> No dirent\n", 0); if (NextEntry == 0) { UpdateCcb = FALSE; if (InitialQuery) { Status = STATUS_NO_SUCH_FILE; } else { Status = STATUS_NO_MORE_FILES; } } try_return( Status ); } // // Protect access to the user buffer with an exception handler. // Since (at our request) IO doesn't buffer these requests, we have // to guard against a user messing with the page protection and other // such trickery. // try { if (LongFileName.Length == 0) { // // Now we have an entry to return to our caller. We'll convert // the name from the form in the dirent to a <name>.<ext> form. // We'll case on the type of information requested and fill up // the user buffer if everything fits. // Fat8dot3ToString( IrpContext, Dirent, TRUE, &Fat8Dot3String ); // // Determine the UNICODE length of the file name. // FileNameLength = RtlOemStringToCountedUnicodeSize(&Fat8Dot3String); // // Here are the rules concerning filling up the buffer: // // 1. The Io system garentees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. // BytesRemainingInBuffer = UserBufferLength - NextEntry; if ( (NextEntry != 0) && ( (BaseLength + FileNameLength > BytesRemainingInBuffer) || (UserBufferLength < NextEntry) ) ) { DebugTrace(0, Dbg, "Next entry won't fit\n", 0); try_return( Status = STATUS_SUCCESS ); } ASSERT( BytesRemainingInBuffer >= BaseLength ); // // Zero the base part of the structure. // RtlZeroMemory( &Buffer[NextEntry], BaseLength ); switch ( FileInformationClass ) { // // Now fill the base parts of the strucure that are applicable. // case FileBothDirectoryInformation: case FileFullDirectoryInformation: case FileIdBothDirectoryInformation: case FileIdFullDirectoryInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0); // // Get the Ea file length. // FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry]; // // If the EAs are corrupt, ignore the error. We don't want // to abort the directory query. // try { FatGetEaLength( IrpContext, Vcb, Dirent, &FullDirInfo->EaSize ); } except(EXCEPTION_EXECUTE_HANDLER) { FatResetExceptionState( IrpContext ); FullDirInfo->EaSize = 0; } case FileDirectoryInformation: DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry]; FatGetDirTimes( IrpContext, Dirent, DirInfo ); DirInfo->EndOfFile.QuadPart = Dirent->FileSize; if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { DirInfo->AllocationSize.QuadPart = (((Dirent->FileSize + DiskAllocSize - 1) / DiskAllocSize) * DiskAllocSize ); } DirInfo->FileAttributes = Dirent->Attributes != 0 ? Dirent->Attributes : FILE_ATTRIBUTE_NORMAL; DirInfo->FileIndex = NextVbo; DirInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String); break; case FileNamesInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0); NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry]; NamesInfo->FileIndex = NextVbo; NamesInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String ); break; default: FatBugCheck( FileInformationClass, 0, 0 ); } BytesConverted = 0; Status = RtlOemToUnicodeN( (PWCH)&Buffer[NextEntry + BaseLength], BytesRemainingInBuffer - BaseLength, &BytesConverted, Fat8Dot3String.Buffer, Fat8Dot3String.Length ); // // Check for the case that a single entry doesn't fit. // This should only get this far on the first entry // if (BytesConverted < FileNameLength) { ASSERT( NextEntry == 0 ); Status = STATUS_BUFFER_OVERFLOW; } // // Set up the previous next entry offset // *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry; // // And indicate how much of the user buffer we have currently // used up. We must compute this value before we long align // ourselves for the next entry // Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) + BaseLength + BytesConverted; // // If something happened with the conversion, bail here. // if ( !NT_SUCCESS( Status ) ) { try_return( NOTHING ); } } else { ULONG ShortNameLength; FileNameLength = LongFileName.Length; // // Here are the rules concerning filling up the buffer: // // 1. The Io system garentees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. // BytesRemainingInBuffer = UserBufferLength - NextEntry; if ( (NextEntry != 0) && ( (BaseLength + FileNameLength > BytesRemainingInBuffer) || (UserBufferLength < NextEntry) ) ) { DebugTrace(0, Dbg, "Next entry won't fit\n", 0); try_return( Status = STATUS_SUCCESS ); } ASSERT( BytesRemainingInBuffer >= BaseLength ); // // Zero the base part of the structure. // RtlZeroMemory( &Buffer[NextEntry], BaseLength ); switch ( FileInformationClass ) { // // Now fill the base parts of the strucure that are applicable. // case FileBothDirectoryInformation: case FileIdBothDirectoryInformation: BothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&Buffer[NextEntry]; // // Now we have an entry to return to our caller. We'll convert // the name from the form in the dirent to a <name>.<ext> form. // We'll case on the type of information requested and fill up // the user buffer if everything fits. // Fat8dot3ToString( IrpContext, Dirent, FALSE, &Fat8Dot3String ); ASSERT( Fat8Dot3String.Length <= 12 ); Status = RtlOemToUnicodeN( &BothDirInfo->ShortName[0], 12*sizeof(WCHAR), &ShortNameLength, Fat8Dot3String.Buffer, Fat8Dot3String.Length ); ASSERT( Status != STATUS_BUFFER_OVERFLOW ); ASSERT( ShortNameLength <= 12*sizeof(WCHAR) ); // // Copy the length into the dirinfo structure. Note // that the LHS below is a USHORT, so it can not // be specificed as the OUT parameter above. // BothDirInfo->ShortNameLength = (UCHAR)ShortNameLength; // // If something happened with the conversion, bail here. // if ( !NT_SUCCESS( Status ) ) { try_return( NOTHING ); } case FileFullDirectoryInformation: case FileIdFullDirectoryInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0); // // Get the Ea file length. // FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry]; // // If the EAs are corrupt, ignore the error. We don't want // to abort the directory query. // try { FatGetEaLength( IrpContext, Vcb, Dirent, &FullDirInfo->EaSize ); } except(EXCEPTION_EXECUTE_HANDLER) { FatResetExceptionState( IrpContext ); FullDirInfo->EaSize = 0; } case FileDirectoryInformation: DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry]; FatGetDirTimes( IrpContext, Dirent, DirInfo ); DirInfo->EndOfFile.QuadPart = Dirent->FileSize; if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { DirInfo->AllocationSize.QuadPart = ( (( Dirent->FileSize + DiskAllocSize - 1 ) / DiskAllocSize ) * DiskAllocSize ); } DirInfo->FileAttributes = Dirent->Attributes != 0 ? Dirent->Attributes : FILE_ATTRIBUTE_NORMAL; DirInfo->FileIndex = NextVbo; DirInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String); break; case FileNamesInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0); NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry]; NamesInfo->FileIndex = NextVbo; NamesInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String ); break; default: FatBugCheck( FileInformationClass, 0, 0 ); } BytesConverted = BytesRemainingInBuffer - BaseLength >= FileNameLength ? FileNameLength : BytesRemainingInBuffer - BaseLength; RtlCopyMemory( &Buffer[NextEntry + BaseLength], &LongFileName.Buffer[0], BytesConverted ); // // Set up the previous next entry offset // *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry; // // And indicate how much of the user buffer we have currently // used up. We must compute this value before we long align // ourselves for the next entry // Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) + BaseLength + BytesConverted; // // Check for the case that a single entry doesn't fit. // This should only get this far on the first entry. // if (BytesConverted < FileNameLength) { ASSERT( NextEntry == 0 ); try_return( Status = STATUS_BUFFER_OVERFLOW ); } } // // Finish up by filling in the FileId // switch ( FileInformationClass ) { case FileIdBothDirectoryInformation: IdBothDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)&Buffer[NextEntry]; IdBothDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo ); break; case FileIdFullDirectoryInformation: IdFullDirInfo = (PFILE_ID_FULL_DIR_INFORMATION)&Buffer[NextEntry]; IdFullDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo ); break; default: break; } } except (EXCEPTION_EXECUTE_HANDLER) { // // We had a problem filling in the user's buffer, so stop and // fail this request. This is the only reason any exception // would have occured at this level. // Irp->IoStatus.Information = 0; UpdateCcb = FALSE; try_return( Status = GetExceptionCode()); } // // Set ourselves up for the next iteration // LastEntry = NextEntry; NextEntry += (ULONG)QuadAlign(BaseLength + BytesConverted); CurrentVbo = NextVbo + sizeof( DIRENT ); } #endif try_exit: NOTHING; } finally {
NTSTATUS Fat16Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context) { FAT16_BOOT_SECTOR BootSector; OEM_STRING VolumeLabel; ULONG SectorCount; ULONG RootDirSectors; ULONG TmpVal1; ULONG TmpVal2; ULONG TmpVal3; NTSTATUS Status; /* Calculate cluster size */ if (ClusterSize == 0) { if (PartitionInfo->PartitionLength.QuadPart < 16LL * 1024LL * 1024LL) { /* Partition < 16MB ==> 1KB Cluster */ ClusterSize = 1024; } else if (PartitionInfo->PartitionLength.QuadPart < 128LL * 1024LL * 1024LL) { /* Partition < 128MB ==> 2KB Cluster */ ClusterSize = 2048; } else if (PartitionInfo->PartitionLength.QuadPart < 256LL * 1024LL * 1024LL) { /* Partition < 256MB ==> 4KB Cluster */ ClusterSize = 4096; } else { /* Partition >= 256MB (< 512MB) ==> 8KB Cluster */ ClusterSize = 8192; } } SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */ RtlZeroMemory(&BootSector, sizeof(FAT16_BOOT_SECTOR)); memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); /* FIXME: Add dummy bootloader for real */ BootSector.Jump[0] = 0xeb; BootSector.Jump[1] = 0x3c; BootSector.Jump[2] = 0x90; BootSector.BytesPerSector = DiskGeometry->BytesPerSector; BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; BootSector.ReservedSectors = 1; BootSector.FATCount = 2; BootSector.RootEntries = 512; BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; BootSector.Media = 0xf8; BootSector.FATSectors = 0; /* Set later. See below. */ BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; BootSector.Heads = DiskGeometry->TracksPerCylinder; BootSector.HiddenSectors = PartitionInfo->HiddenSectors; BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; BootSector.Drive = (DiskGeometry->MediaType == FixedMedia) ? 0x80 : 0x00; BootSector.ExtBootSignature = 0x29; BootSector.VolumeID = CalcVolumeSerialNumber(); if ((Label == NULL) || (Label->Buffer == NULL)) { memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); } else { RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE); RtlFillMemory(&BootSector.VolumeLabel[0], 11, ' '); memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); RtlFreeOemString(&VolumeLabel); } memcpy(&BootSector.SysType[0], "FAT16 ", 8); DPRINT("BootSector.SectorsHuge = %lx\n", BootSector.SectorsHuge); RootDirSectors = ((BootSector.RootEntries * 32) + (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; /* Calculate number of FAT sectors */ /* (BootSector.BytesPerSector / 2) FAT entries (16bit) fit into one sector */ TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); TmpVal2 = ((BootSector.BytesPerSector / 2) * BootSector.SectorsPerCluster) + BootSector.FATCount; TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); DPRINT("BootSector.FATSectors = %hu\n", BootSector.FATSectors); /* Init context data */ Context->TotalSectorCount = 1 + (BootSector.FATSectors * 2) + RootDirSectors; if (!QuickFormat) { Context->TotalSectorCount += SectorCount; Status = FatWipeSectors(FileHandle, SectorCount, (ULONG)BootSector.SectorsPerCluster, (ULONG)BootSector.BytesPerSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status); return Status; } } Status = Fat16WriteBootSector(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat16WriteBootSector() failed with status 0x%.08x\n", Status); return Status; } /* Write first FAT copy */ Status = Fat16WriteFAT(FileHandle, 0, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat16WriteFAT() failed with status 0x%.08x\n", Status); return Status; } /* Write second FAT copy */ Status = Fat16WriteFAT(FileHandle, (ULONG)BootSector.FATSectors, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat16WriteFAT() failed with status 0x%.08x.\n", Status); return Status; } Status = Fat16WriteRootDirectory(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat16WriteRootDirectory() failed with status 0x%.08x\n", Status); } return Status; }
NTSTATUS Fat12Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context) { FAT16_BOOT_SECTOR BootSector; OEM_STRING VolumeLabel; ULONG SectorCount; ULONG RootDirSectors; ULONG TmpVal1; ULONG TmpVal2; ULONG TmpVal3; NTSTATUS Status; /* Calculate cluster size */ if (ClusterSize == 0) { if (DiskGeometry->MediaType == FixedMedia) { /* 4KB Cluster (Harddisk only) */ ClusterSize = 4096; } else { /* 512 byte cluster (floppy) */ ClusterSize = 512; } } SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */ DPRINT("SectorCount = %lu\n", SectorCount); memset(&BootSector, 0, sizeof(FAT16_BOOT_SECTOR)); memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); BootSector.BytesPerSector = DiskGeometry->BytesPerSector; BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; BootSector.ReservedSectors = 1; BootSector.FATCount = 2; BootSector.RootEntries = 512; BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; BootSector.Media = 0xf8; BootSector.FATSectors = 0; /* Set later. See below. */ BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; BootSector.Heads = DiskGeometry->TracksPerCylinder; BootSector.HiddenSectors = PartitionInfo->HiddenSectors; BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; BootSector.Drive = DiskGeometry->MediaType == FixedMedia ? 0x80 : 0x00; BootSector.ExtBootSignature = 0x29; BootSector.VolumeID = CalcVolumeSerialNumber(); if ((Label == NULL) || (Label->Buffer == NULL)) { memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); } else { RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE); memset(&BootSector.VolumeLabel[0], ' ', 11); memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); RtlFreeOemString(&VolumeLabel); } memcpy(&BootSector.SysType[0], "FAT12 ", 8); RootDirSectors = ((BootSector.RootEntries * 32) + (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; /* Calculate number of FAT sectors */ /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */ TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); TmpVal2 = (((BootSector.BytesPerSector * 2) / 3) * BootSector.SectorsPerCluster) + BootSector.FATCount; TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); DPRINT("BootSector.FATSectors = %hx\n", BootSector.FATSectors); /* Init context data */ Context->TotalSectorCount = 1 + (BootSector.FATSectors * 2) + RootDirSectors; Status = Fat12WriteBootSector(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status); return Status; } /* Write first FAT copy */ Status = Fat12WriteFAT(FileHandle, 0, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status); return Status; } /* Write second FAT copy */ Status = Fat12WriteFAT(FileHandle, (ULONG)BootSector.FATSectors, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status); return Status; } Status = Fat12WriteRootDirectory(FileHandle, &BootSector, Context); if (!NT_SUCCESS(Status)) { DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status); } if (!QuickFormat) { /* FIXME: Fill remaining sectors */ } return Status; }