FAT Root Directory Structure on Floppy Disk and File Information

Introduction

In my previous article, “Extract Floppy Disk Geometry from the Boot Sector,” you learned about floppy disk geometry formatted in a Windows environment for FAT. In this article, you will look at the FAT root directory entry on a floppy disk. So far, you know that a floppy disk formatted in a Windows environment has a total of 2880 sectors. Out of this, the 0th sector (the first 512 bytes) is reserved as the boot sector. The next 18 sectors are reserved for FATs.

Immediately after these FAT sectors, the root directory sectors start. In a FAT file sytem, root directories comprise 14 sectors. Today’s discussion will be on this area.

You know that the maximum directory entry allowed under the root directory for the FAT file system on a 3.5″ floppy disk is 224. The size for root directory entries is (14 * 512) bytes, which is equivalent to 7168 bytes. Divide 7168 bytes with the max root entries for the FAT; you will get each entry size for the root directory, which is 32 bytes. Each 32 bytes holds information about a file or directory.

I would like to advise you to go through the FAT 32-byte directory structure as mentioned by Microsoft in http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx.

Structure for FAT 32-Byte Directory Entry

Byte Range Description
0 – 10 Short name (8+3) for file/folder
11 File attribute (Read only, directory, System file, and so on)
12 Reserved
13 Millisecond time for file creation
14 – 15 File creation time
16 – 17 File creation date
18 – 19 File access date
20 – 21 High 16-bit cluster number
22 – 23 File modification time
24 – 25 File modification date
26 – 27 16-bit cluster number
28 – 31 File size in bytes

Notes on the first byte of the FAT directory entry:

  1. If the first byte is equal to 0x00, this entry is available and no entry beyond this one has been used.
  2. If the first byte is equal to 0xE5, this entry has been erased and is available for use.
  3. If the first byte is equal to 0x05, the actual filename character for this byte is 0xE5.

C++ Data Structure for 32-Byte Root Directory Entry

I have created one structure, as shown below, to hold the root directory entry:

typedef struct root_Entries
{
   BYTE short_FileName[11];
   BYTE fileAttributes;
   BYTE reserved;
   BYTE createTime_ms;
   WORD createTime;
   WORD createDate;
   WORD accessedDate;
   WORD clusterNumber_High;
   WORD modifiedTime;
   WORD modifiedDate;
   WORD firstClusterAddress_FAT12;
   DWORD sizeofFile;
} root;

Notes on the file attribute byte of the FAT directory entry:

  1. 0x01(0000 0001) – Read Only
  2. 0x10(0000 0002) – Hidden File
  3. 0x04(0000 0100) – System File
  4. 0x08(0000 1000) – Volume label
  5. 0x10(0001 0000) – Directory
  6. 0x20(0010 0000) – Archive

Notes on the Date/Time format of the FAT directory entry:

Date Format: The date field is 16-bit. This is relative to 01/01/1980.

  1. Bits 0 – 4: Day of month, range 1-31
  2. Bits 5 – 8: Month of year, range 1-12
  3. Bits 9 – 15: Count of years, range 0 – 127

Time format: This is also 16-bit and its granularity is 2 seconds.

  1. Bits 0 – 4: 2-second count, valid value range 0-29 inclusive (0 – 58 seconds)
  2. Bits 5 – 10: Minutes, rane 0-59
  3. Bits 11 – 15: Hours, range 0-23

Reading file information from a 32-byte root directory

The following code snippet will give the basic operation to read file information stored directly under the drive’s root (‘A:\’). For the simplicity of the program, I have formatted the floppy under the Windows environment for FAT and a short-named file (file name with an 8+3 format) copied into it. Then, I tried the following code snippet and got file information.

#define INVALID_SET_FILE_POINTER ((DWORD)-1)

typedef struct root_Entries
{
   BYTE short_FileName[11];
   BYTE fileAttributes;
   BYTE reserved;
   BYTE createTime_ms;
   WORD createTime;
   WORD createDate;
   WORD accessedDate;
   WORD clusterNumber_High;
   WORD modifiedTime;
   WORD modifiedDate;
   WORD firstClusterAddress_FAT12;
   DWORD sizeofFile;
} root;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
   int nRetCode = 0;

   // initialize MFC and print and error on failure
   if (!AfxWinInit(::GetModuleHandle(NULL), NULL,
       ::GetCommandLine(), 0))
   {
      // TODO: change error code to suit your needs
      cerr << _T("Fatal Error: MFC initialization failed") << endl;
      nRetCode = 1;
   }
   else
   {
      DWORD dwFilePointer;
      DWORD dwBytesRead;
      root stRoot;
      BYTE byteRoot[512];
      memset(&byteRoot, 0, 512);

      HANDLE hFloppy = NULL;
      hFloppy = CreateFile("\\\\.\\A:",    // Floppy drive to open
         GENERIC_READ,                     // Access mode
         FILE_SHARE_READ,                  // Share Mode
         NULL,                             // Security Descriptor
         OPEN_EXISTING,                    // How to create
         0,                                // File attributes
         NULL);                            // Handle to template
      if(hFloppy != NULL)
      {
         dwFilePointer = SetFilePointer(hFloppy,
            (512 * 19), NULL, FILE_BEGIN);
         // Test for failure
         if (dwFilePointer != INVALID_SET_FILE_POINTER)
         {
            int iSector = 19;
            BOOL bNoEntry = FALSE;
            // Iterate through root directory sectors
            do
            {
               if (!ReadFile(hFloppy, byteRoot, 512,
                   &dwBytesRead, NULL))
               {
                  printf("Error in Reading Root Entry.\n");
               }
               else
               {
                  BYTE *pByteRoot = byteRoot;
                  // Iterate through 32 byte entries
                  for(int i = 0; i < (512/32); i++)
                  {
                     memcpy(&stRoot, pByteRoot, 32);

                      // No entry beyond this used.
                     if(stRoot.short_FileName[0] == 0x00)
                     {
                        // Stop iteration
                        bNoEntry = TRUE;
                        break;
                     }
                     else
                     {
                        // This if loops checks for file deletion
                        // status
                        if(stRoot.short_FileName[0] == 0xE5)
                        {
                           printf("First character of file after
                                   deletion :0x%x\n",
                              stRoot.short_FileName[0]);
                           printf("File status: Deleted.\n");
                        }

                        printf("File Name            : %s\n",
                                                     : stRoot.short_
                                                     : FileName);
                        if(stRoot.fileAttributes & 0x01)
                        printf("File Attribute       : Read Only File\n");
                        if(stRoot.fileAttributes & 0x02)
                           printf("File Attribute    : Hidden File\n");
                        if(stRoot.fileAttributes & 0x04)
                           printf("File Attribute    : System File\n");
                        if(stRoot.fileAttributes & 0x08)
                           printf("File Attribute    : Volume Label\n");
                        if(stRoot.fileAttributes & 0x0f)
                           printf("File Attribute    : Long File Name\n");
                        if(stRoot.fileAttributes & 0x10)
                           printf("File Attribute    : Directory\n");
                        if(stRoot.fileAttributes & 0x20)
                           printf("File Attribute    : Archive\n");

                        WORD nYear = (stRoot.createDate >> 9);
                        WORD nMonth = (stRoot.createDate << 7);
                        nMonth = nMonth >> 12;
                        WORD nDay = (stRoot.createDate << 11);
                        nDay = nDay >> 11;

                        printf("Create Date    : %d/%d/%d\n", nDay,
                                               : nMonth, (nYear+1980));

                        nYear  = (stRoot.modifiedDate >> 9);
                        nMonth = (stRoot.modifiedDate << 7);
                        nMonth = nMonth >> 12;
                        nDay   = (stRoot.modifiedDate << 11);
                        nDay   = nDay >> 11;

                        printf("Modification Date    : %d/%d/%d\n",
                                                     : nDay, nMonth,
                                                     : (nYear+1980));

                        nYear  = (stRoot.accessedDate >> 9);
                        nMonth = (stRoot.accessedDate << 7);
                        nMonth = nMonth >> 12;
                        nDay   = (stRoot.accessedDate << 11);
                        nDay   = nDay >> 11;

                        printf("Accessed Date        : %d/%d/%d\n",
                                                     : nDay, nMonth,
                                                     : (nYear+1980));

                        printf("Start Cluster Address: %d\n",
                               stRoot.firstClusterAddress_FAT12);
                        printf("File Size            : %d bytes\n",
                                                     : stRoot.
                                                     :sizeofFile);
                        pByteRoot += 32;
                     }    // End of else
                  }

                  if(bNoEntry)
                  break;
                  else
                  {
                     iSector += 1;
                  }
               }
            } while(iSector <= 33);
         }

         CloseHandle(hFloppy);
      }
   }

   return nRetCode;
}

Once you run the program above, it will give following output:

You can cross check this information with file properties from Windows Explorer. The result must be the same.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read