/*++ Copyright (c) 1989 Microsoft Corporation Module Name: tfat.c Abstract: Test program for the Fat File system Author: Gary Kimura [GaryKi] 24-May-1989 Revision History: --*/ #include #include #define toupper(C) ((C) >= 'a' && (C) <= 'z' ? (C) - ('a' - 'A') : (C)) #define isdigit(C) ((C) >= '0' && (C) <= '9') #include #include #include #define simprintf(X,Y) {if (!Silent) {printf(X,Y);} } BOOLEAN Silent; // // The buffer size must be a multiple of 512 // #define BUFFERSIZE 1024 UCHAR Buffer[BUFFERSIZE]; CHAR Prefix[64]; ULONG WriteThrough = 0; VOID WaitForSingleObjectError( IN NTSTATUS Status ); VOID CreateFileError( IN NTSTATUS Status, PCHAR File ); VOID OpenFileError( IN NTSTATUS Status, PCHAR File ); VOID ReadFileError( IN NTSTATUS Status ); VOID WriteFileError( IN NTSTATUS Status ); VOID CheckIoStatus( IN PIO_STATUS_BLOCK IoStatus, IN ULONG Length, IN BOOLEAN Read ); VOID SetInformationFileError( IN NTSTATUS Status ); VOID QueryInformationFileError( IN NTSTATUS Status ); VOID CloseError( IN NTSTATUS Status ); VOID IoStatusError( IN NTSTATUS Status ); VOID main( int argc, char *argv[] ) { ULONG i; ULONG Count; VOID FatMain(); CHAR Device[8]; STRING NtDevice; CHAR NtDeviceBuffer[32]; if (argc <= 1) { printf("usage: %s drive: [iterations [writethrough] ]\n", argv[0]); return; } // // Decode the device/drive // strcpy( Device, argv[1] ); NtDevice.MaximumLength = NtDevice.Length = 32; NtDevice.Buffer = NtDeviceBuffer; if (!RtlDosPathNameToNtPathName( Device, &NtDevice, NULL, NULL )) { printf( "Invalid Dos Device Name\n" ); RtlFreeHeap(RtlProcessHeap(), 0, NtDevice.Buffer); return; } if (NtDevice.Length > 31) { NtDevice.Length = 31; } NtDevice.Buffer[NtDevice.Length] = 0; // // Now do the iteration count // if (argc >= 3) { Count = 0; for (i = 0; isdigit(argv[2][i]); i += 1) { Count = Count * 10 + argv[2][i] - '0'; } } else { Count = 1; } // // Check for write through // if (argc >= 4) { WriteThrough = FILE_WRITE_THROUGH; } // // Check for silent operation // if (toupper(Device[0]) != Device[0]) { Silent = TRUE; } else { Silent = FALSE; } // // Do the work // FatMain(Count, NtDevice.Buffer); RtlFreeHeap(RtlProcessHeap(), 0, NtDevice.Buffer); return; } VOID FatMain( IN ULONG LoopCount, IN CHAR Device[] ) { VOID Create(),Delete(),Mkdir(),Directory(),Read(); CHAR Str[64]; CHAR LoopStr[64]; ULONG i; LARGE_INTEGER Time; printf("FatMain %d\n", LoopCount); NtQuerySystemTime(&Time); strcpy( Prefix, Device); Prefix[48] = 0; RtlIntegerToChar((ULONG)NtCurrentTeb()->ClientId.UniqueProcess, 16, -8, &Prefix[strlen(Device)]); Mkdir( Prefix ); Directory( Device ); Directory( Prefix ); for (i = 0; i < LoopCount; i += 1) { NtQuerySystemTime(&Time); strcpy(LoopStr, "Start loop xxxxxxxx "); RtlIntegerToChar(i, 16, -8, &LoopStr[11]); strcat( LoopStr, Prefix ); printf(LoopStr); printf("\n"); strcpy( Str, Prefix ); Create( strcat( Str, "\\1.tmp" ), Time.LowPart, 1 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\2.tmp" ), Time.LowPart, 2 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\4.tmp" ), Time.LowPart, 4 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\8.tmp" ), Time.LowPart, 8 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\16.tmp" ), Time.LowPart, 16 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\32.tmp" ), Time.LowPart, 32 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\64.tmp" ), Time.LowPart, 64 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\128.tmp" ), Time.LowPart, 128 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\236.tmp" ), Time.LowPart, 256 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\512.tmp" ), Time.LowPart, 512 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\1024.tmp" ), Time.LowPart, 1024 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\2048.tmp" ), Time.LowPart, 2048 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\4096.tmp" ), Time.LowPart, 4096 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\8192.tmp" ), Time.LowPart, 8192 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\16384.tmp" ), Time.LowPart, 16384 ); strcpy( Str, Prefix ); Create( strcat( Str, "\\32768.tmp" ), Time.LowPart, 32768 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\1.tmp" ), Time.LowPart, 1 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\2.tmp" ), Time.LowPart, 2 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\4.tmp" ), Time.LowPart, 4 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\8.tmp" ), Time.LowPart, 8 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\16.tmp" ), Time.LowPart, 16 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\32.tmp" ), Time.LowPart, 32 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\64.tmp" ), Time.LowPart, 64 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\128.tmp" ), Time.LowPart, 128 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\236.tmp" ), Time.LowPart, 256 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\512.tmp" ), Time.LowPart, 512 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\1024.tmp" ), Time.LowPart, 1024 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\2048.tmp" ), Time.LowPart, 2048 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\4096.tmp" ), Time.LowPart, 4096 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\8192.tmp" ), Time.LowPart, 8192 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\16384.tmp" ), Time.LowPart, 16384 ); strcpy( Str, Prefix ); Read( strcat( Str, "\\32768.tmp" ), Time.LowPart, 32768 ); Directory( Device ); Directory( Prefix ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\1.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\2.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\4.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\8.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\16.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\32.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\64.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\128.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\236.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\512.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\1024.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\2048.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\4096.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\8192.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\16384.tmp" ) ); strcpy( Str, Prefix ); Delete( strcat( Str, "\\32768.tmp" ) ); Directory( Device ); Directory( Prefix ); } printf( "Done\n" ); return; } VOID Create( IN PCHAR FileName, IN ULONG FileTime, IN ULONG FileCount ) { NTSTATUS Status; HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; STRING NameString; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER AllocationSize; LARGE_INTEGER ByteOffset; ULONG Count; ULONG Pattern[3]; // // Get the filename // simprintf("Create ", 0); simprintf(FileName, 0); simprintf("\n", 0); // // Create the new file // AllocationSize = LiFromUlong( FileCount * 4 ); RtlInitString( &NameString, FileName ); InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL ); if (!NT_SUCCESS(Status = NtCreateFile( &FileHandle, FILE_WRITE_DATA | SYNCHRONIZE, &ObjectAttributes, &IoStatus, &AllocationSize, FILE_ATTRIBUTE_NORMAL, 0L, FILE_SUPERSEDE, WriteThrough, (PVOID)NULL, 0L ))) { CreateFileError( Status , FileName ); return; } // // The main loop writes out the test pattern our test pattern // is where count is the current // iteration count for the current test pattern output. // Pattern[0] = FileTime; Pattern[1] = FileCount; for (Count = 0; Count < FileCount; Count += 1) { Pattern[2] = Count; ByteOffset = LiFromUlong( Count * 3 * 4 ); if (!NT_SUCCESS(Status = NtWriteFile( FileHandle, (HANDLE)NULL, (PIO_APC_ROUTINE)NULL, (PVOID)NULL, &IoStatus, Pattern, 3 * 4, &ByteOffset, (PULONG) NULL ))) { WriteFileError( Status ); return; } if (!NT_SUCCESS(Status = NtWaitForSingleObject(FileHandle, TRUE, NULL))) { WaitForSingleObjectError( Status ); return; } // // check how the write turned out // CheckIoStatus( &IoStatus, 3 * 4, FALSE ); if (!NT_SUCCESS(IoStatus.Status)) { IoStatusError( IoStatus.Status ); break; } } // // Now close the file // if (!NT_SUCCESS(Status = NtClose( FileHandle ))) { CloseError( Status ); } // // And return to our caller // return; } VOID Read( IN PCHAR FileName, IN ULONG FileTime, IN ULONG FileCount ) { NTSTATUS Status; HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; STRING NameString; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER AllocationSize; LARGE_INTEGER ByteOffset; ULONG Count; ULONG Pattern[3]; // // Get the filename // simprintf("Read ", 0); simprintf(FileName, 0); simprintf("\n", 0); // // Open the existing file // AllocationSize = LiFromUlong( FileCount * 4 ); RtlInitString( &NameString, FileName ); InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL ); if (!NT_SUCCESS(Status = NtOpenFile( &FileHandle, FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &IoStatus, 0L, WriteThrough ))) { OpenFileError( Status, FileName ); return; } // // The main loop read in the test pattern our test pattern // is where count is the current // iteration count for the current test pattern output. // for (Count = 0; Count < FileCount; Count += 1) { ByteOffset = LiFromUlong( Count * 3 * 4 ); if (!NT_SUCCESS(Status = NtReadFile( FileHandle, (HANDLE)NULL, (PIO_APC_ROUTINE)NULL, (PVOID)NULL, &IoStatus, Pattern, 3 * 4, &ByteOffset, (PULONG) NULL ))) { ReadFileError( Status ); return; } if (!NT_SUCCESS(Status = NtWaitForSingleObject(FileHandle, TRUE, NULL))) { WaitForSingleObjectError( Status ); return; } // // check how the read turned out // CheckIoStatus( &IoStatus, 3 * 4, TRUE ); if (!NT_SUCCESS(IoStatus.Status)) { IoStatusError( IoStatus.Status ); break; } // // Now compare the what we read with what we should have read // if ((Pattern[0] != FileTime) || (Pattern[1] != FileCount) || (Pattern[2] != Count)) { printf("**** Read Error ****\n"); NtPartyByNumber( 50 ); return; } } // // Now close the file // if (!NT_SUCCESS(Status = NtClose( FileHandle ))) { CloseError( Status ); } // // And return to our caller // return; } VOID Delete( IN PCHAR FileName ) { NTSTATUS Status; HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; STRING NameString; IO_STATUS_BLOCK IoStatus; // // Get the filename // simprintf("Delete ", 0); simprintf(FileName, 0); simprintf("\n", 0); // // Open the file for delete access // RtlInitString( &NameString, FileName ); InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL ); if (!NT_SUCCESS(Status = NtCreateFile( &FileHandle, DELETE | SYNCHRONIZE, &ObjectAttributes, &IoStatus, (PLARGE_INTEGER)NULL, 0L, 0L, FILE_OPEN, WriteThrough, (PVOID)NULL, 0L ))) { CreateFileError( Status, FileName ); return; } // // Mark the file for delete // ((PFILE_DISPOSITION_INFORMATION)&Buffer[0])->DeleteFile = TRUE; if (!NT_SUCCESS(Status = NtSetInformationFile( FileHandle, &IoStatus, Buffer, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation))) { SetInformationFileError( Status ); return; } // // Now close the file // if (!NT_SUCCESS(Status = NtClose( FileHandle ))) { CloseError( Status ); } // // And return to our caller // return; } VOID Directory( IN PCHAR String ) { NTSTATUS Status; HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; STRING NameString; IO_STATUS_BLOCK IoStatus; NTSTATUS NtStatus; PFILE_ADIRECTORY_INFORMATION FileInfo; ULONG i; // // Get the filename // simprintf("Directory ", 0); simprintf(String, 0); simprintf("\n", 0); // // Open the file for list directory access // RtlInitString( &NameString, String ); InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL ); if (!NT_SUCCESS(Status = NtOpenFile( &FileHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjectAttributes, &IoStatus, FILE_SHARE_READ, WriteThrough | FILE_DIRECTORY_FILE ))) { OpenFileError( Status , String ); return; } // // zero out the buffer so next time we'll recognize the end of data // for (i = 0; i < BUFFERSIZE; i += 1) { Buffer[i] = 0; } // // Do the directory loop // for (NtStatus = NtQueryDirectoryFile( FileHandle, (HANDLE)NULL, (PIO_APC_ROUTINE)NULL, (PVOID)NULL, &IoStatus, Buffer, BUFFERSIZE, FileADirectoryInformation, FALSE, (PSTRING)NULL, TRUE); NT_SUCCESS(NtStatus); NtStatus = NtQueryDirectoryFile( FileHandle, (HANDLE)NULL, (PIO_APC_ROUTINE)NULL, (PVOID)NULL, &IoStatus, Buffer, BUFFERSIZE, FileADirectoryInformation, FALSE, (PSTRING)NULL, FALSE) ) { if (!NT_SUCCESS(Status = NtWaitForSingleObject(FileHandle, TRUE, NULL))) { // NtPartyByNumber(50); WaitForSingleObjectError( Status ); return; } // // Check the Irp for success // if (!NT_SUCCESS(IoStatus.Status)) { break; } // // For every record in the buffer type out the directory information // // // Point to the first record in the buffer, we are guaranteed to have // one otherwise IoStatus would have been No More Files // FileInfo = (PFILE_ADIRECTORY_INFORMATION)&Buffer[0]; while (TRUE) { // // Print out information about the file // simprintf("%8lx ", FileInfo->FileAttributes); simprintf("%8lx/", FileInfo->EndOfFile.LowPart); simprintf("%8lx ", FileInfo->AllocationSize.LowPart); { CHAR Saved; Saved = FileInfo->FileName[FileInfo->FileNameLength]; FileInfo->FileName[FileInfo->FileNameLength] = 0; simprintf(FileInfo->FileName, 0); FileInfo->FileName[FileInfo->FileNameLength] = Saved; } simprintf("\n", 0); // // Check if there is another record, if there isn't then we // simply get out of this loop // if (FileInfo->NextEntryOffset == 0) { break; } // // There is another record so advance FileInfo to the next // record // FileInfo = (PFILE_ADIRECTORY_INFORMATION)(((PUCHAR)FileInfo) + FileInfo->NextEntryOffset); } // // zero out the buffer so next time we'll recognize the end of data // for (i = 0; i < BUFFERSIZE; i += 1) { Buffer[i] = 0; } } // // Now close the file // if (!NT_SUCCESS(Status = NtClose( FileHandle ))) { CloseError( Status ); } // // And return to our caller // return; } VOID Mkdir( IN PCHAR String ) { NTSTATUS Status; HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; STRING NameString; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER AllocationSize; // // Get the filename // simprintf("Mkdir ", 0); simprintf(String, 0); simprintf("\n", 0); // // Create the new directory // AllocationSize = LiFromLong( 4 ); RtlInitString( &NameString, String ); InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL ); if (!NT_SUCCESS(Status = NtCreateFile( &FileHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatus, &AllocationSize, 0L, 0L, FILE_CREATE, WriteThrough | FILE_DIRECTORY_FILE, (PVOID)NULL, 0L ))) { CreateFileError( Status , String ); return; } // // Now close the directory // if (!NT_SUCCESS(Status = NtClose( FileHandle ))) { CloseError( Status ); } // // And return to our caller // return; } VOID WaitForSingleObjectError(NTSTATUS Status) { printf("%s WaitForSingleObject Error %X\n", Prefix, Status); } VOID CreateFileError(NTSTATUS Status, PCHAR File) { printf("%s CreateFile of %s Error %X\n", Prefix, File, Status); } VOID OpenFileError(NTSTATUS Status, PCHAR File) { printf("%s OpenFile of %s Error %X\n", Prefix, File, Status); } VOID ReadFileError(NTSTATUS Status) { printf("%s ReadFile Error %X\n", Prefix, Status); } VOID WriteFileError(NTSTATUS Status) { printf("%s WriteFile Error %X\n", Prefix, Status); } VOID SetInformationFileError(NTSTATUS Status) { printf("%s SetInfoFile Error %X\n", Prefix, Status); } VOID QueryInformationFileError(NTSTATUS Status) { printf("%s QueryInfoFile Error %X\n", Prefix, Status); } VOID CloseError(NTSTATUS Status) { printf("%s Close Error %X\n", Prefix, Status); } VOID IoStatusError(NTSTATUS Status) { printf("%s IoStatus Error %X\n", Prefix, Status); } VOID CheckIoStatus(PIO_STATUS_BLOCK IoStatus, ULONG Length, BOOLEAN Read) { if (!NT_SUCCESS(IoStatus->Status)) { printf(" IoStatus->Status Error %08lx\n", IoStatus->Status); } if ((!Read && (IoStatus->Information != Length)) || (Read && (IoStatus->Information > Length))) { printf(" IoStatus->Information Error %08lx\n", IoStatus->Information); } }