@ -1,3 +1,195 @@ |
|||||||
\chapter{The FAT16 Filesystem and Its Emulation} \label{sec:fat16} |
\chapter{The FAT16 File System and Its Emulation} \label{sec:fat16} |
||||||
|
|
||||||
|
A file system (FS) is used by GEX to provide a comfortable access to the configuration files. By emulating a Mass Storage USB device, the module appears as a thumb drive on the host PC, and the user can edit its configuration using their preferred text editor. The FAT16 file system was selected for its simplicity and a good cross-platform support. |
||||||
|
|
||||||
|
Three variants of the FAT (File Allocation Table) file system exist: FAT12, FAT16, and FAT32. FAT12 was used on floppy disks and it is similar to FAT16, except for additional size constraints and a FAT entry packing scheme. FAT16 and FAT32 are FAT12's later developments from the time when hard disks became more common and the old addressing scheme couldn't support their larger capacity. |
||||||
|
|
||||||
|
This chapter will explain the structure of FAT16 and the challenges faced when trying to emulate it without a physical data storage. |
||||||
|
|
||||||
|
\section{The General Structure of the FAT File System} |
||||||
|
|
||||||
|
The storage medium is organized into \textit{sectors} (or \textit{blocks}), usually 512 bytes long. Those are the smallest addressing unit in the disk structure. The disk starts with a \textit{boot sector}, also called \textit{master boot record} (MBR). That is followed by optional reserved sectors, one or two copies of the file allocation table, and the root directory. All disk areas are aligned to a sector boundary: |
||||||
|
|
||||||
|
\begin{table}[h] |
||||||
|
\centering |
||||||
|
\begin{tabular}{ll} |
||||||
|
\toprule |
||||||
|
\textbf{Disk area} & \textbf{Size / Notes} \\ |
||||||
|
\midrule |
||||||
|
Boot sector & 1 sector \\ |
||||||
|
Reserved sectors & optional \\ |
||||||
|
FAT 1 & 1 or more sectors, depends on disk size \\ |
||||||
|
FAT 2 & optional, a back-up copy of FAT 1 \\ |
||||||
|
Root directory & 1 or more sectors \\ |
||||||
|
Data area & Organized in \textit{clusters} \\ |
||||||
|
\bottomrule |
||||||
|
\end{tabular} |
||||||
|
\caption{\label{tab:fat16-disk-areas}Areas of a FAT-formatted disk} |
||||||
|
\end{table} |
||||||
|
|
||||||
|
\subsection{Boot Sector} |
||||||
|
|
||||||
|
This is a 1-sector structure which holds the OS bootstrap code for bootable disks. The first 3 bytes are a jump instruction to the actual bootstrap code located later in the sector. What matters to us when implementing the file system is that the boot sector also contains data fields describing how the disk is organized, what file system is used, who formatted it, etc. The size of the FAT and the root directory is defined here. The exact structure of the boot sector can be found in XXX\todo{add ref link} or in the attached GEX source code. |
||||||
|
|
||||||
|
\subsection{File Allocation Table} |
||||||
|
|
||||||
|
The data area of the disk is organized in clusters, logical allocation units composed of groups of sectors. The use of a larger allocation unit allows the system to use shorter addresses and thus support a larger disk capacity. |
||||||
|
|
||||||
|
The FAT acts as a look-up table combined with linked lists. In FAT16, it is organized in 16-bit fields, each corresponding to one cluster. The first two entries in the allocation table are reserved and hold special values set by the disk formatter and the host OS: a "media descriptor" 0xFFF8 and a "clean/dirty flag" 0xFFFF/0x3FFF. |
||||||
|
|
||||||
|
Files can span multiple clusters; each FAT entry either holds the address of the following file cluster, or a value with a special meaning: |
||||||
|
|
||||||
|
\begin{itemize} |
||||||
|
\item 0x0000 - free cluster |
||||||
|
\item 0xFFFF - last cluster of the file (still including file data!) |
||||||
|
\item 0xFFF7 - bad cluster |
||||||
|
\end{itemize} |
||||||
|
|
||||||
|
The bad cluster mark, 0xFFF7, is used for clusters which are known to corrupt data due to a flaw in the storage medium, such us a bad memory cell. |
||||||
|
|
||||||
|
\subsection{Root Directory} |
||||||
|
|
||||||
|
The root directory has the same structure as any other directories, which reside in clusters the same way like ordinary files. The difference is that the root directory is allocated when the disk is formatted and it has a fixed and known position and size. Sub-directories are stored on the disk in a similar way to regular files, therefore they can span multiple sectors and their file count can be much larger than that of the root directory. |
||||||
|
|
||||||
|
\begin{table} |
||||||
|
\centering |
||||||
|
\begin{tabular}{lll} |
||||||
|
\toprule |
||||||
|
\textbf{Offset} & \textbf{Size (bytes)} & \textbf{Description}\\ |
||||||
|
\midrule |
||||||
|
0 & 8 & File name (padded with spaces) \\ |
||||||
|
8 & 3 & File extension \\ |
||||||
|
11 & 1 & File attributes \\ |
||||||
|
12 & 10 & Reserved \\ |
||||||
|
22 & 2 & Creation time \\ |
||||||
|
24 & 2 & Creation date \\ |
||||||
|
26 & 2 & Address of the first cluster \\ |
||||||
|
28 & 4 & File size (bytes) \\ |
||||||
|
\bottomrule |
||||||
|
\end{tabular} |
||||||
|
\caption{\label{tab:fat16-dir-entry}Structure of a FAT16 directory entry} |
||||||
|
\end{table} |
||||||
|
|
||||||
|
A directory is organized in 32-byte entries representing individual files. Table \ref{tab:fat16-dir-entry} shows the structure of one such entry. |
||||||
|
|
||||||
|
The name and extension fields form together the well-known 8.3 filename format. Longer file names are encoded using a \textit{long file name} (LFN) scheme as special hidden entries stored in the directory table alongside the regular 8.3 entries, ensuring backward compatibility. |
||||||
|
|
||||||
|
The first byte of the file name has a special meaning: |
||||||
|
|
||||||
|
\begin{itemize} |
||||||
|
\item 0x00 - indicates that there are no more files when searching the directory |
||||||
|
\item 0xE5 - marks a free slot; this is used when a file is deleted |
||||||
|
\item 0x05 - indicates that the first byte should actually be 0xE5, which was used in a Japanese character set. |
||||||
|
\item Any other value, except 0x20 (space) and characters forbidden in a DOS file name, starts a valid file entry. Generally, only space, A-Z, 0-9, \verb|-| and \verb|_| should be used in file names for maximum compatibility. |
||||||
|
\end{itemize} |
||||||
|
|
||||||
|
The attributes field contains flags such as \textit{directory}, \textit{volume label}, \textit{read-only} and \textit{hidden}. Volume label is a special entry in the root directory, which defines the disk's label shown on the host PC. A file with the directory bit set is actually a pointer to a subdirectory, meaning that when we open the linked cluster, we'll find a new directory table. |
||||||
|
|
||||||
|
Figure \ref{fig:fat-example} shows a possible organization of the GEX file system with two INI files, one spanning two clusters, the other being entirely inside one. The clusters need not be used completely; an exact file size is stored in the directory entries. |
||||||
|
|
||||||
|
\begin{figure}[h] |
||||||
|
\centering |
||||||
|
\includegraphics[scale=1.3] {img/fat-links.pdf} |
||||||
|
\caption{\label{fig:fat-example}An example of the GEX virtual file system} |
||||||
|
\end{figure} |
||||||
|
|
||||||
|
|
||||||
|
\section{FAT16 Emulation} |
||||||
|
|
||||||
|
The FAT16 file system is relatively straightforward and easy to implement. This is the reason why an emulation driver for it was developed as part of the open-source ARM mbed DAPLink project. \todo{reference} It is used there for a drag-and-drop flashing of firmware images to the target microcontroller, taking advantage of it working well across different host platforms. ARM mbed uses a browser-based IDE and cloud build servers, thus the end user does not need to install or set up any software or drivers to program a compatible development kit. The GEX firmware adapts several parts of this code, optimizes its RAM usage and further expands its functionality to support our specific use case. |
||||||
|
|
||||||
|
It is not practical or even possible to keep the entire file system in memory, especially with a microcontroller like the STM32F072, which has only 16\,kB of RAM in total. This means that we have to generate and parse disk sectors and clusters on-demand, when the host reads or writes them. The STM32 USB Device library helpfully implements the Mass Storage USB class and provides API endpoints to which we connect our file system emulator. Specifically, those are requests to read and write a sector, and to read disk status and parameters, such as its size. |
||||||
|
|
||||||
|
As shown in table \ref{tab:fat16-disk-areas}, the disk consists of several areas. The boot sector is immutable and can be stored in Flash. The handling of the other areas (FAT, data area) depends on whether we're dealing with a read or write access: |
||||||
|
|
||||||
|
\subsection{Handling a Read Access} |
||||||
|
|
||||||
|
The user can only read files that already exist on the disk, in our case, \verb|UNITS.INI| and \verb|SYSTEM.INI|. Those files are generated from the binary settings storage, and conversely, parsed, line-by-line, without ever existing in their full form. This fact makes our task more challenging, as the files can't be easily measured and there's no obvious way to read a sector from the middle of a longer file. We solve this by implementing two additional functions in the INI file writer: a \textit{read window} and a \textit{dummy read mode}. |
||||||
|
|
||||||
|
A read window is a byte range which we wish to generate. The INI writer discards bytes before the start of the read window, writes those inside the window to our data buffer, and stops when its end is reached. This lets us extract a sector from anywhere in a file. The second function, dummy read, is tied to the window function: we set the start index so high that it's never reached (e.g. 0xFFFFFFFF), and have the writer count discarded characters. When the dummy file generation ends, this character counter holds its size. |
||||||
|
|
||||||
|
Now, just one problem remains: how to tell which sectors contain which part of our files? This is straightforward when we realize that the files change only when the user modifies the settings. After each such change, an algorithm is run which allocates clusters to the files and preserves this information in a holding structure. A subsequent read access simply requires a look into this structure and the corresponding chunk of a file may be served using the read window function. The FAT can be dynamically generated from this information as well. |
||||||
|
|
||||||
|
\subsection{Handling a Write Access} |
||||||
|
|
||||||
|
A file write access is more challenging to emulate than a read access, as the host OS tends to be somewhat unpredictable. In GEX's case we're interested only in the action of overwriting an already existing file, but it's interesting to also analyze other actions the host may perform. |
||||||
|
|
||||||
|
It must be noted that due to the nonexistence of a physical storage medium, it's not possible to read back a file the host has written. The OS may show the written file on the disk, but when the user tried to read it, it either fails, or shows a cached copy. In the DAPLink emulator this is worked around by temporarily reporting that the storage medium has been removed, forcing the host to re-load its contents. In GEX, the loaded INI file will be a newly generated copy, embedding possible error messages as comments. |
||||||
|
|
||||||
|
\subsubsection{File Deletion} |
||||||
|
|
||||||
|
A file is deleted by: |
||||||
|
|
||||||
|
\begin{enumerate} |
||||||
|
\item Marking all sectors used by it as free in the FAT |
||||||
|
\item Replacing the first character of its name in the directory table by 0xE5 to indicate the slot is free |
||||||
|
\end{enumerate} |
||||||
|
|
||||||
|
From the perspective of emulation, we can ignore the FAT access and only detect writes to the directory sectors. This is slightly more complicated when one considers that all disk access is performed in sectors: the emulator must compare the written data with the original bytes to detect what change has been performed. Alternatively, we could parse the written sector as a directory table and compare it with our knowledge of its original contents. |
||||||
|
|
||||||
|
\subsection{File Name Change} |
||||||
|
|
||||||
|
A file is renamed by modifying its directory entry. This can be be detected in a similar way to a file deletion. In the simple case of a short, 8.3 file name, this is a in-place modification of the file entry. Long file names, using the LFN extension, are a complication, as the number of dummy entries might change when the file name is shortened or made longer, and subsequently the following entries in the table may shift or be entirely re-arranged. |
||||||
|
|
||||||
|
\subsection{File Creation} |
||||||
|
|
||||||
|
A new file is created in three steps: |
||||||
|
|
||||||
|
\begin{enumerate} |
||||||
|
\item Finding free clusters and chaining them by writing the following cluster addresses (or 0xFFFF for the last cluster) into the FAT |
||||||
|
\item Finding and overwriting a free entry in the directory table |
||||||
|
\item Writing the file content |
||||||
|
\end{enumerate} |
||||||
|
|
||||||
|
It can be expected the host OS first finds the free sectors and a free file entry before performing any write operations, to prevent a potential disk corruption. |
||||||
|
|
||||||
|
To properly handle such a file by the emulator, we could, in theory, find its name from the directory table, which has been updated, and then collect the data written to the corresponding clusters. In practice, confirmed by experiments with a real Linux host, those three steps may happen in any order, and often the content is written before the directory table is updated. |
||||||
|
|
||||||
|
The uncertain order of the written disk areas poses a problem when the file name has any significance, as we can't store the received file data while waiting for the name to be written. The DAPLink mbed flashing firmware solves this by analyzing the content of the first written sector of the file, which may contain the binary NVIC table, or an ASCII pattern typical for Intel hex files. |
||||||
|
|
||||||
|
\subsection{File Content Change} |
||||||
|
|
||||||
|
A change to a file's content is performed in a similar way to the creation of a new file, except instead of creating a new entry in the directory table, an existing one is updated with the new file size. The name of the file may be, again, unknown until the content is written, but we could detect the file by comparing the starting sector with those of all files known to the virtual file system. |
||||||
|
|
||||||
|
In the case of GEX, the detection of a file name is not important; We expect only INI files to be written, and the particular file may be detected by its first section marker, such as \verb|[UNITS]| or \verb|[SYSTEM]|. Should a non-INI file be written by accident, the INI parser will likely detect a syntax error and discard it. |
||||||
|
|
||||||
|
It should be noted that a file could be updated only partially, skipping the clusters which remain unchanged, and there's also no guarantee regarding the order in which the file's sectors are written. This is hard to detect and handle and the current firmware is not able to interpret it correctly, thus such a write operation will fail. Fortunately, this host behavior has not been conclusively observed in practice, but a write operation rarely fails for still unknown reasons and this could be a possible cause. |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
... |
|
@ -0,0 +1,96 @@ |
|||||||
|
\chapter{Functional Blocks} |
||||||
|
|
||||||
|
This chapter describes all functional blocks (units) implemented in GEX at the time of publication of this work. Each unit supports a different set of binary commands and events. A complete specification of this API is attached in an electronic form. \todo{add the github docs repo as a ref} |
||||||
|
|
||||||
|
|
||||||
|
\section{Digital Output Unit} |
||||||
|
|
||||||
|
The digital output unit provides a write access to one or more pins of a GPIO port. The group of pins need not be contiguous (e.g. pin 0 and 6 can be accessed as a 2-bit output). All selected pins are accessed simultaneously using the port control registers. |
||||||
|
|
||||||
|
This unit additionally supports pulse generation on any of its pins. It is implemented in software with the timing derived from the system timebase, as the hardware timer outputs, otherwise used for PWM or pulse generation, are available only on several dedicated pins. Two pulse length resolutions are available, depending on the scale: microseconds for pulses shorter than 1\,ms, milliseconds for longer ones. |
||||||
|
|
||||||
|
\todo[inline]{Measure jitter and add it here} |
||||||
|
|
||||||
|
|
||||||
|
\section{Digital Input Unit} |
||||||
|
|
||||||
|
The digital input unit is the input counterpart of the digital output unit. |
||||||
|
|
||||||
|
In addition to reading the immediate digital levels of the selected pins, this unit can generate asynchronous events on a pin change. The state of the entire input port, together with a microsecond timestamp (as is the case for all asynchronous events), is reported to the host either on a rising, falling, or any pin change. |
||||||
|
|
||||||
|
The pin change event can be configured independently for each pin. In order to receive a pin change event, it must be armed first; The pin can be armed for a single event, or it may be re-armed automatically with a hold-off time. It's further possible to automatically arm selected pin triggers on start-up. |
||||||
|
|
||||||
|
|
||||||
|
\section{Shift Registers Driver Unit} |
||||||
|
|
||||||
|
The shift registers driver unit is designed for the loading of data into \textit{serial-in, parallel-out} (SIPO) shift registers, such as 74HC4094 or 74HC595. Those are commonly used to control segmented LED displays, LED matrices etc. |
||||||
|
|
||||||
|
This unit handles both the \textit{Shift} and \textit{Store} signals and is capable of loading multiple shift registers simultaneously, reducing visible glitches in the display. It's also possible to set the data lines to arbitrary level(s) before sending the Store pulse, which can be latched and used for some additional feature of the LED display, such as brightness control. |
||||||
|
|
||||||
|
|
||||||
|
\section{NeoPixel Unit} |
||||||
|
|
||||||
|
The NeoPixel unit implements the protocol needed to control a digital LED strip with WS2812, WS2811, or compatible LED driver chips. The protocol timing is implemented in software, therefore it is available on any GPIO pin of the module. The unit accepts sequences of RGB color values from the host and loads them into the LED strip. |
||||||
|
|
||||||
|
|
||||||
|
\section{SPI Unit} |
||||||
|
|
||||||
|
The SPI unit provides access to one of the microcontroller's SPI peripherals. It can be configured to use any of the different speeds, clock polarity and phase settings available in its control registers. The unit handles up to 16 slave select (NSS) signals. |
||||||
|
|
||||||
|
Both write-only and read-write (query) transactions are implemented. |
||||||
|
|
||||||
|
\todo[inline]{Query diagram} |
||||||
|
|
||||||
|
|
||||||
|
\section{I2C Unit} |
||||||
|
|
||||||
|
The I2C unit provides access to one of the microcontroller's I2C peripherals. It can be configured to use either of the three speeds (Standard, Fast and Fast+) and supports both 10-bit and 8-bit addressing. |
||||||
|
|
||||||
|
|
||||||
|
\section{USART Unit} |
||||||
|
|
||||||
|
The USART unit provides access to one of the microcontroller's USART peripherals. All USART parameters can be configured to match the application's needs. |
||||||
|
|
||||||
|
The clock output and hardware flow control may be enabled, as well as the Driver Enable (DE) output used by RS485 transceivers to switch between a reception and transmission mode. |
||||||
|
|
||||||
|
|
||||||
|
\section{1-Wire Unit} |
||||||
|
|
||||||
|
The 1-Wire unit implements the Dallas Semiconductor's 1-Wire protocol, most commonly used to interface smart thermometers (DS18x20). The protocol is explained in section \ref{sec:theory-1wire}. This unit implements the basic protocol, as well as the ROM Search algorithm used to recognizes all unique 1-Wire devices connected to the bus. |
||||||
|
|
||||||
|
|
||||||
|
\section{Frequency Capture Unit} |
||||||
|
|
||||||
|
The frequency capture unit implements both the frequency measurement methods explained in section \ref{sec:theory-fcap}: direct and reciprocal. It can be operated in an on-demand or continuous measurement mode. The unit can be switched to two other modes: pulse counter, and the measurement of a single pulse. |
||||||
|
|
||||||
|
|
||||||
|
\section{ADC Unit} |
||||||
|
|
||||||
|
The analog/digital converter unit is one of the most complicated units implemented in the project. The unit can measure the voltage on an input pin, either as its immediate value, or averaged with exponential forgetting. Isochronous sampling is available as well: It's possible to capture a fixed-length block of data on demand, or as a response to a triggering condition on any of the enabled input pins. The ADC must continuously sample the inputs to make the averaging and level based triggering possible; As a consequence, a pre-trigger buffer is available that can be read together with the block of samples following a trigger. The ADC unit can also be switched to a continuous streaming mode. |
||||||
|
|
||||||
|
It's possible to activate any number of the 16 analog inputs of the ADC peripheral simultaneously. The maximum continuous sampling frequency, which reaches 70\,ksps with one channel, lowers with an increasing number of enabled channels as the amount of data to transfer to the host increases. |
||||||
|
|
||||||
|
|
||||||
|
\section{DAC Unit} |
||||||
|
|
||||||
|
The digital/analog unit works with the two-channel DAC peripheral of the microcontroller. It can be used in two modes: DC output, and waveform generation. |
||||||
|
|
||||||
|
The waveform mode implements direct digital synthesis (explained in section \ref{sec:theory-dac-dds}) of a sine, rectangle, sawtooth or triangle wave. The generated frequency can be set with a sub-hertz precision up to the lower tens of kHz. The two outputs can use a different waveform shape, be synchronized, and their phase offset, as well as frequency, is dynamically adjustable. |
||||||
|
|
||||||
|
|
||||||
|
\section{PWM Unit} |
||||||
|
|
||||||
|
The PWM unit uses a timer/counter to generate a PWM signal. There are four outputs with a common frequency and phase, but independent duty cycles. Each channel can be individually enabled or disabled. |
||||||
|
|
||||||
|
This unit is intended for applications like light dimming, heater regulation, or the control of H-bridges. |
||||||
|
|
||||||
|
|
||||||
|
\section{Touch Sensing Unit} |
||||||
|
|
||||||
|
The touch sensing unit provides an access to the touch sensing controller. Its function is explained in section \ref{sec:theory-touch}. The unit configures the TSC and reads the output values of each enabled touch pad. |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 250 KiB |
After Width: | Height: | Size: 152 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 46 KiB |
@ -0,0 +1,517 @@ |
|||||||
|
<html> |
||||||
|
|
||||||
|
<!-- http://home.teleport.com/~brainy/fat16.htm --> |
||||||
|
|
||||||
|
<head> |
||||||
|
<meta name="GENERATOR" content="Microsoft FrontPage 3.0"> |
||||||
|
<title>FAT16 Structure Information</title> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
|
||||||
|
<p align="center"><strong><u><big>FAT16 Structure Information - Written by Jack Dobiash</big></u></strong></p> |
||||||
|
|
||||||
|
<p align="center"><em><small>Updated : June 17th, 1999</small></em></p> |
||||||
|
|
||||||
|
<p>Looking for FAT32 Info? Go <a href="http://home.teleport.com/~brainy/fat32.htm">here</a>.<br> |
||||||
|
Looking for Informaton on how to Read and Write to your Hard Drive? Go <a |
||||||
|
href="http://home.teleport.com/~brainy/diskaccess.htm">here</a>.</p> |
||||||
|
|
||||||
|
<p>I've written this page for anyone who wishes to write software that can do low-level |
||||||
|
reading and writing of a hard drive, and needs to know what the underlying structure of a |
||||||
|
FAT16 Drive is, in order to interpret the information properly. Basically I've |
||||||
|
searched all over the web, and have compiled this information in one spot. |
||||||
|
Hopefully it can be of use to someone. I don't guarantee that all of this |
||||||
|
information is correct or complete, but so far is seems to have been working for me. |
||||||
|
</p> |
||||||
|
|
||||||
|
<p>A lot of the number references I've made in this document are in Hexadecimal. Any |
||||||
|
that are have an 'h' after them. Also, just in case my terminology may be different |
||||||
|
from yours; a 'WORD' is 2 Bytes and a 'DOUBLE WORD' is 4 Bytes.</p> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
|
||||||
|
<p><u><strong>Master Boot Record</strong></u></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>The Master Boot Record is the same for pretty much all Operating Systems. It is |
||||||
|
located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1. It |
||||||
|
is the first piece of code that your computer runs after it has checked all of your |
||||||
|
hardware (POST) and turned control of loading software over the hard drive. It also |
||||||
|
contains the partition table, which defines the different sections of your hard |
||||||
|
drive. Basically if anything happens to this little 512 byte section, your hard |
||||||
|
drive is brain dead. Kinda scary, eh? :)</p> |
||||||
|
</blockquote> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="455" height="79"> |
||||||
|
<tr> |
||||||
|
<td width="44" height="25">Offset</td> |
||||||
|
<td width="269" height="25">Description</td> |
||||||
|
<td width="52" height="25">Size</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="25">000h</td> |
||||||
|
<td width="269" height="25">Executable Code (Boots Computer)</td> |
||||||
|
<td width="52" height="25">446 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="22">1BEh</td> |
||||||
|
<td width="269" height="1">1st Partition Entry (See Next Table)</td> |
||||||
|
<td width="52" height="22">16 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="17">1CEh</td> |
||||||
|
<td width="269" height="17">2nd Partition Entry</td> |
||||||
|
<td width="52" height="17">16 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="12">1DEh</td> |
||||||
|
<td width="269" height="12">3rd Partition Entry</td> |
||||||
|
<td width="52" height="12">16 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="20">1EEh</td> |
||||||
|
<td width="269" height="20">4th Partition Entry</td> |
||||||
|
<td width="52" height="20">16 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="44" height="16">1FEh</td> |
||||||
|
<td width="269" height="16">Executable Marker (55h AAh)</td> |
||||||
|
<td width="52" height="16">2 Bytes</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<strong>Partition Entry (Part of MBR)</strong></p> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="523" height="236"> |
||||||
|
<tr> |
||||||
|
<td width="47" height="7">Offset</td> |
||||||
|
<td width="328" height="7">Description</td> |
||||||
|
<td width="130" height="7">Size</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="8">00h</td> |
||||||
|
<td width="328" height="8">Current State of Partition (00h=Inactive, 80h=Active)</td> |
||||||
|
<td width="130" height="8">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="18">01h</td> |
||||||
|
<td width="328" height="18">Beginning of Partition - Head</td> |
||||||
|
<td width="130" height="18">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="19">02h </td> |
||||||
|
<td width="328" height="19">Beginning of Partition - Cylinder/Sector (See Below)</td> |
||||||
|
<td width="130" height="19">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="15">04h</td> |
||||||
|
<td width="328" height="15">Type of Partition (See List Below)</td> |
||||||
|
<td width="130" height="15">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="13">05h</td> |
||||||
|
<td width="328" height="13">End of Partition - Head</td> |
||||||
|
<td width="130" height="13">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="15">06h</td> |
||||||
|
<td width="328" height="15">End of Partition - Cylinder/Sector</td> |
||||||
|
<td width="130" height="15">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="22">08h</td> |
||||||
|
<td width="328" height="22">Number of Sectors Between the MBR and the First Sector in the |
||||||
|
Partition</td> |
||||||
|
<td width="130" height="22">1 Double Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="47" height="22">0Ch</td> |
||||||
|
<td width="328" height="22">Number of Sectors in the Partition</td> |
||||||
|
<td width="130" height="22">1 Double Word</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<strong>Cylinder/Sector Encoding</strong></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>I guess back in the days of 10MB hard drives and 8086's, code was at a premium. |
||||||
|
So they did everything they could to preserve space. Unfortunately now we have to |
||||||
|
live with it, but luckily they created new ways of translating the system so the 1024 |
||||||
|
Cylinder Limit (2^10) isn't too big of a problem, for newer computers, at least. |
||||||
|
Older ones usually need some sort of Disk Overlay program to make them see the whole hard |
||||||
|
drive. </p> |
||||||
|
<p>Anyway, to get the Sector out of this, you need to apply an AND mask ($3F) to it. |
||||||
|
To get the Cylinder, you take the high byte and OR it with the low byte that has |
||||||
|
been AND masked with ($C0) and then Shifted Left Two. It's not very easy to explain, |
||||||
|
so I'll just show you how I did it with two routines I made (In Pascal) for Encoding and |
||||||
|
Decoding the Cylinder/Sector. Hopefully even if you don't know Pascal you'll be able |
||||||
|
to read it.</p> |
||||||
|
<p>Function CylSecEncode(Cylinder, Sector : Word) : Word;<br> |
||||||
|
Begin<br> |
||||||
|
CylSecEncode := (Lo(Cylinder) shl 8) or (Hi(Cylinder) shl 6) or Sector;<br> |
||||||
|
End;<br> |
||||||
|
<br> |
||||||
|
Procedure CylSecDecode(Var Cylinder, Sector : Word; CylSec : Word);<br> |
||||||
|
Begin<br> |
||||||
|
Cylinder := Hi(CylSec) or ((Lo(CylSec) and $C0) shl 2);<br> |
||||||
|
Sector := (CylSec and $3F);<br> |
||||||
|
End;<br> |
||||||
|
</p> |
||||||
|
</blockquote> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="418" height="48"> |
||||||
|
<tr> |
||||||
|
<td width="10" height="23">15</td> |
||||||
|
<td width="13" height="23">14</td> |
||||||
|
<td width="18" height="23">13</td> |
||||||
|
<td width="7" height="23">12</td> |
||||||
|
<td width="12" height="23">11</td> |
||||||
|
<td width="20" height="23">10</td> |
||||||
|
<td width="19" height="23">9</td> |
||||||
|
<td width="20" height="23">8</td> |
||||||
|
<td width="36" height="23">7</td> |
||||||
|
<td width="29" height="23">6</td> |
||||||
|
<td width="20" height="23">5</td> |
||||||
|
<td width="22" height="23">4</td> |
||||||
|
<td width="21" height="23">3</td> |
||||||
|
<td width="22" height="23">2</td> |
||||||
|
<td width="25" height="23">1</td> |
||||||
|
<td width="23" height="23">0</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="184" height="13" colspan="8">Cylinder Bits 7 to 0</td> |
||||||
|
<td width="67" height="13" colspan="2">Cylinder Bits 9+8</td> |
||||||
|
<td width="149" height="13" colspan="6">Sector Bits 5 to 0</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<strong>Partition Type Listing</strong></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>There are more than just these shown, but I've only included that ones relevant to MS |
||||||
|
Operating Systems.</p> |
||||||
|
</blockquote> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="418" height="57"> |
||||||
|
<tr> |
||||||
|
<td width="52" height="23">Value</td> |
||||||
|
<td width="354" height="23">Description</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="10">00h</td> |
||||||
|
<td width="354" height="10">Unknown or Nothing</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="13">01h</td> |
||||||
|
<td width="354" height="13">12-bit FAT</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="0">04h</td> |
||||||
|
<td width="354" height="0">16-bit FAT (Partition Smaller than 32MB)</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="8">05h</td> |
||||||
|
<td width="354" height="8">Extended MS-DOS Partition</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="7">06h</td> |
||||||
|
<td width="354" height="7">16-bit FAT (Partition Larger than 32MB)</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="6">0Bh</td> |
||||||
|
<td width="354" height="6">32-bit FAT (Partition Up to 2048GB)</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="10">0Ch</td> |
||||||
|
<td width="354" height="10">Same as 0BH, but uses LBA<sub>1</sub> 13h Extensions</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="12">0Eh</td> |
||||||
|
<td width="354" height="12">Same as 06H, but uses LBA<sub>1</sub> 13h Extensions</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="52" height="1">0Fh</td> |
||||||
|
<td width="354" height="1">Same as 05H, but uses LBA<sub>1</sub> 13h Extensions</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<u><strong>Reading Multiple Partitions</strong></u></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>Since FAT16 is limited to 2GB per partition, drives that use it tend to have multiple |
||||||
|
partitions. The first partition is the Primary Partition, and everything else is |
||||||
|
stored in the Extended Partition. It's a little tricky when it comes to reading |
||||||
|
those extra partitions though (not a lot, just a little). The first record in the |
||||||
|
partition table shows where the Primary partition is (how big it is, where it starts, and |
||||||
|
where it ends). The second entry in the partition table shows where the Entire |
||||||
|
Extended Partition is (which may include more than just one partition). To read any |
||||||
|
more partitions, you go to the where it says the Extended Partition starts, and read the |
||||||
|
first sector. It acts just like the MBR. It'll have blank where the code is |
||||||
|
supposed to be, and in the partition table it will have for it's first entry the next |
||||||
|
Partition in the Drive, and if there are anymore, there will be another Extended |
||||||
|
partition, just like before. However, all references to Sector Numbers are made |
||||||
|
using the that new MBR point as the reference, making it a virtual drive. Just |
||||||
|
incase this doesn't make much sense (and by the way I explain things I can understand if |
||||||
|
it doesn't), let me show you how a drive with three partitions is setup.</p> |
||||||
|
<p>MBR of Whole Drive</p> |
||||||
|
<p> Entry #1 - Points to Partition #1<br> |
||||||
|
Entry #2 - Points to the Entire Extended Partition</p> |
||||||
|
<p>You would read the first sector of that Extended Partition, and see another MBR |
||||||
|
Structure.</p> |
||||||
|
<p>MBR of Extended Partition</p> |
||||||
|
<p> Entry #1 - Points to Partition #2<br> |
||||||
|
Entry #2 - Points to Rest of Extended Partition after Partition #2</p> |
||||||
|
<p>Now, all references to Sector Numbers (most specifically the entry at Offset 08h) in |
||||||
|
those Entries wouldn't be referenced from the start of the drive, but from the start of |
||||||
|
the Extended Partition. However, the CHS (Cylinder, Head, Sector) numbers would |
||||||
|
still be right.</p> |
||||||
|
<p>Once again, you would read the first sector of that Extended Partition, and see the |
||||||
|
next MBR.</p> |
||||||
|
<p>MBR of Rest of Extended Partition</p> |
||||||
|
<p> Entry #1 - Points to Partition #3<br> |
||||||
|
No Entry #2, since this was the Last Partition</p> |
||||||
|
<p>If there were another partition, the pattern would continue just like before, until the |
||||||
|
last one was reached.</p> |
||||||
|
</blockquote> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<u><strong>FAT16 Boot Record</strong></u></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>This information is located in the first sector of every partition.</p> |
||||||
|
</blockquote> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="518" height="192"> |
||||||
|
<tr> |
||||||
|
<td width="60" height="19">Offset</td> |
||||||
|
<td width="329" height="19">Description</td> |
||||||
|
<td width="110" height="19">Size</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="10">00h</td> |
||||||
|
<td width="329" height="10">Jump Code + NOP</td> |
||||||
|
<td width="110" height="10">3 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="25">03h</td> |
||||||
|
<td width="329" height="25">OEM Name</td> |
||||||
|
<td width="110" height="25">8 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="6">0Bh</td> |
||||||
|
<td width="329" height="6">Bytes Per Sector</td> |
||||||
|
<td width="110" height="6">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="7">0Dh</td> |
||||||
|
<td width="329" height="7">Sectors Per Cluster</td> |
||||||
|
<td width="110" height="7">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="12">0Eh</td> |
||||||
|
<td width="329" height="12">Reserved Sectors</td> |
||||||
|
<td width="110" height="12">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="7">10h</td> |
||||||
|
<td width="328" height="7">Number of Copies of FAT</td> |
||||||
|
<td width="111" height="7">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="4">11h</td> |
||||||
|
<td width="328" height="4">Maximum Root Directory Entries</td> |
||||||
|
<td width="111" height="4">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="5">13h</td> |
||||||
|
<td width="328" height="5">Number of Sectors in Partition Smaller than 32MB</td> |
||||||
|
<td width="111" height="5">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="8">15h</td> |
||||||
|
<td width="328" height="8">Media Descriptor (F8h for Hard Disks)</td> |
||||||
|
<td width="111" height="8">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="60" height="4">16h</td> |
||||||
|
<td width="328" height="4">Sectors Per FAT</td> |
||||||
|
<td width="111" height="4">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="14">18h</td> |
||||||
|
<td width="328" height="14">Sectors Per Track</td> |
||||||
|
<td width="111" height="14">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="23">1Ah</td> |
||||||
|
<td width="328" height="23">Number of Heads</td> |
||||||
|
<td width="111" height="23">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">1Ch</td> |
||||||
|
<td width="328" height="22">Number of Hidden Sectors in Partition</td> |
||||||
|
<td width="111" height="22">1 Double Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">20h</td> |
||||||
|
<td width="328" height="22">Number of Sectors in Partition</td> |
||||||
|
<td width="111" height="22">1 Double Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">24h</td> |
||||||
|
<td width="328" height="22">Logical Drive Number of Partition</td> |
||||||
|
<td width="111" height="22">1 Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">26h</td> |
||||||
|
<td width="328" height="22">Extended Signature (29h)</td> |
||||||
|
<td width="111" height="22">1 Byte</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">27h</td> |
||||||
|
<td width="328" height="22">Serial Number of Partition</td> |
||||||
|
<td width="111" height="22">1 Double Word</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">2Bh</td> |
||||||
|
<td width="328" height="22">Volume Name of Partition</td> |
||||||
|
<td width="111" height="22">11 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">36h</td> |
||||||
|
<td width="328" height="22">FAT Name (FAT16)</td> |
||||||
|
<td width="111" height="22">8 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">3Eh</td> |
||||||
|
<td width="328" height="22">Executable Code</td> |
||||||
|
<td width="111" height="22">448 Bytes</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="61" height="22">1FEh</td> |
||||||
|
<td width="328" height="22">Executable Marker (55h AAh)</td> |
||||||
|
<td width="111" height="22">2 Bytes</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><br> |
||||||
|
<br> |
||||||
|
<u><strong>FAT16 Drive Layout</strong></u></p> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="521" height="64"> |
||||||
|
<tr> |
||||||
|
<td width="374" height="23">Offset</td> |
||||||
|
<td width="111" height="23">Description</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="374" height="10">Start of Partition</td> |
||||||
|
<td width="111" height="10">Boot Sector</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="374" height="14">Start + # of Reserved Sectors</td> |
||||||
|
<td width="111" height="14">Fat Tables</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="374" height="-1">Start + # of Reserved + (# of Sectors Per FAT * 2)</td> |
||||||
|
<td width="111" height="-1">Root Directory Entry</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="374" height="3">Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum |
||||||
|
Root Directory Entries * 32) / Bytes per Sector) </td> |
||||||
|
<td width="111" height="3">Data Area (Starts with Cluster #2)</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
|
||||||
|
<p><u><strong>Cluster Meaning (FAT Table Entries)</strong></u></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>A Cluster is a Group of Sectors on the Hard Drive that have information in them. |
||||||
|
A 16K Cluster has 32 Sectors in it (512*32=16384). Each Cluster is given a spot in |
||||||
|
the FAT Table. When you look at an Entry in the FAT, the number there tells you |
||||||
|
whether or not that cluster has data in it, and if so, if it is the end of the data or |
||||||
|
there is another cluster after it. All Data on a Partition starts with Cluster #2 |
||||||
|
(Right after Root Directory). If the FAT Entry is 0, then there is no data in |
||||||
|
that cluster. If the FAT Entry is FFFFh, then it is the last entry in the |
||||||
|
chain. </p> |
||||||
|
</blockquote> |
||||||
|
<div align="left"> |
||||||
|
|
||||||
|
<table border="1" width="430" height="78"> |
||||||
|
<tr> |
||||||
|
<td width="247" height="19">FAT Code Range</td> |
||||||
|
<td width="171" height="19">Meaning</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="247" height="11">0000h</td> |
||||||
|
<td width="171" height="11">Available Cluster</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="247" height="10">0002h-FFEFh</td> |
||||||
|
<td width="171" height="10">Used, Next Cluster in File</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="247" height="7">FFF0h-FFF6h</td> |
||||||
|
<td width="171" height="7">Reserved Cluster</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="247" height="4">FFF7h</td> |
||||||
|
<td width="171" height="4">BAD Cluster</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td width="247" height="9">FFF8h-FFFF</td> |
||||||
|
<td width="171" height="9">Used, Last Cluster in File</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p><u><strong>Directory Table</strong></u></p> |
||||||
|
|
||||||
|
<blockquote> |
||||||
|
<p>Another aspect when looking at a File System at Low Level is the Directory Table. |
||||||
|
The Directory Table is what stores all of the File and Directory Entries. |
||||||
|
Someone else has already written a good resource for this information on the net, so |
||||||
|
go <a href="http://home.teleport.com/~brainy/lfn.htm">here</a> to look at it. The |
||||||
|
link doesn't work anymore, but luckily I saved the page a while back, so i'll just post it |
||||||
|
on my site.</p> |
||||||
|
</blockquote> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
|
||||||
|
<p>Footnotes</p> |
||||||
|
|
||||||
|
<p>1 - LBA = Logical Block Addressing - Uses the Int 13h Extensions built into newer |
||||||
|
BIOS's to access data above the 8GB |
||||||
|
|
||||||
|
barrier, or to access strickly in LBA mode, instead of CHS (Cylinder, Head, Sector).</p> |
||||||
|
|
||||||
|
<p align="center"><a href="http://home.teleport.com/~brainy">Home</a> <a |
||||||
|
href="http://home.teleport.com/~brainy/rps.html">Reference Point Software</a> <a |
||||||
|
href="http://home.teleport.com/~brainy/fat32.htm">FAT32 Structure Information</a> FAT16 |
||||||
|
Structure Information <a href="http://home.teleport.com/~brainy/diskaccess.htm">Disk Access |
||||||
|
Information</a> <br> |
||||||
|
<a href="http://home.teleport.com/~brainy/bio.html">About Me</a> <a |
||||||
|
href="http://home.teleport.com/~brainy/links.html">Links</a> <a |
||||||
|
href="http://home.teleport.com/~brainy/dobiash.html">Dobiash?</a></p> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,580 @@ |
|||||||
|
<!doctype html public "-//w3c//DTD HTML 3.2//EN"> |
||||||
|
<html> |
||||||
|
|
||||||
|
<!-- http://home.teleport.com/~brainy/lfn.htm --> |
||||||
|
|
||||||
|
<!-- http://members.aol.com/vindaci/pub/doc/lfn/lfn.html --> |
||||||
|
<!-- Copyright (c)1996-1998 vinDaci --> |
||||||
|
|
||||||
|
<head> |
||||||
|
<title>Long Filename Specification</title> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
|
||||||
|
<h2 align="center">Long Filename Specification</h2> |
||||||
|
<font size="-1"> |
||||||
|
|
||||||
|
<p align="center">by vinDaci</font> <font size="-2"><br> |
||||||
|
fourth release</font> <font size="-1"><br> |
||||||
|
First Release: November 18th, 1996</font> <font size="-1"><br> |
||||||
|
Last Update: January 6th, 1998 (Document readability update)</font> </p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>Compatibility</h3> |
||||||
|
|
||||||
|
<p>Long filename (here on forth referred to as "LFN") design for Windows95 is |
||||||
|
designed to be 99% compatible with the old DOS 8.3 format. The 1% discripency comes in |
||||||
|
when old DOS programs can detect the <em>presence</em> of LFN (but unfortunately not the |
||||||
|
LFN itself), which in no way interferes with regular program operations except for perhaps |
||||||
|
low-level disk utility programs (such as disk error fixing programs, disk optimization |
||||||
|
programs, anti-virus program, etc.) <a name="background"></p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>DOS 8.3 Filename Background</h3> |
||||||
|
|
||||||
|
<p>I trust that anyone who wish to know the details of LFN has at least a small knowledge |
||||||
|
in DOS 8.3 filename specification. In this document, however, I'll assume you know very |
||||||
|
little about the 8.3 filename specs, however. What you need to know in order to understand |
||||||
|
this documentation is that 8.3 filenames are stored in a place on the disk called the <dfn>directory |
||||||
|
table</dfn>. This place contains the list of filenames and other information associated |
||||||
|
with each file, such as the file date, time, size, attributes, etc. (Note: Contrary to |
||||||
|
some belief, the directory table is <em>not</em> the same as the FAT -- e-mail me if you |
||||||
|
wish to know what FAT is.) </p> |
||||||
|
|
||||||
|
<p>The file attributes, mentioned above, play some big roles in LFN. It is important to |
||||||
|
note that a file's attributes are may consist of one or more of the following: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="50%" border="1"> |
||||||
|
<tr> |
||||||
|
<td><code>Archive</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>Read-Only</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>System</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>Hidden</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>Directory</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>Volume</code> </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>Most programmers are aware of the Archive, Read-Only, System, and Hidden attrbiutes, |
||||||
|
but for those of you who don't know, please allow me to explain what each of these |
||||||
|
attributes is/does: |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li>The <dfn>Archive attribute</dfn> tells that a file has been backed up (though most |
||||||
|
programs just ignore this). </li> |
||||||
|
<li>The <dfn>Read-Only attribute</dfn> keeps a file from accidentally getting overwritten; |
||||||
|
note that any program can unset this attribute should it know how to detect this attribute |
||||||
|
and unset it -- that's why it is used just to keep a file from <em>accidentally</em> |
||||||
|
getting overwritten. </li> |
||||||
|
<li>The <dfn>System attribute</dfn> tells that the file is used for some important operation |
||||||
|
so it should not be messed with except by the program that created it; any file with this |
||||||
|
attribute cannot be seen with the <kbd>DIR</kbd> command except with the <kbd>/a</kbd> or <kbd>/as</kbd> |
||||||
|
arguments in DOS 5 and above. </li> |
||||||
|
<li>The <dfn>Hidden</dfn> attribute tells that a file should normally be hidden from the |
||||||
|
user's view. Any file with this attribute cannot be seen with <kbd>DIR</kbd> command |
||||||
|
either, except with the <kbd>/a</kbd> or <kbd>/ah</kbd> arguments in DOS 5 and above. </li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<p>And the explanation of the other attributes (the <em>really</em> important ones): |
||||||
|
|
||||||
|
<ul> |
||||||
|
<li>The <dfn>Directory attribute</dfn> is used to tell that a file is not actually a file |
||||||
|
but a directory. This type of file contains a pointer to a part of the disk that contains |
||||||
|
another directory table; this directory table that's pointed to is the subdirectory of the |
||||||
|
directory that has the pointer. In another words, when you "CD" to that file, |
||||||
|
you go into the directory table the file points to, making it look as though you are |
||||||
|
"inside" that directory. In reality, you only switch the directory tables. </li> |
||||||
|
<li>The <dfn>volume attribute</dfn> too is used to tell that a file is not actually a file. |
||||||
|
This attribute is used to indicate the volume label of the drive (the name of the disk). A |
||||||
|
file with this attribute can never be displayed with the <kbd>DIR</kbd> command. |
||||||
|
Furthermore, there can be only one file with this attribute on the entire disk, and this |
||||||
|
file must be in the root directory of the disk. <br> |
||||||
|
The volume attribute has a funny story attached to it -- There |
||||||
|
not only exists a file with the volume attribute, but a copy of the volume label is also |
||||||
|
located in the boot sector (the very beginning of the disk that has weird code and disk |
||||||
|
info on it) as a readable text. But when you view a directory with the <kbd>DIR</kbd> |
||||||
|
command, the one that actually gets displayed is the volume attributed file's name, not |
||||||
|
the volume label in the boot sector. Furthermore, even though files with volume attribute |
||||||
|
is hidden from the <kbd>DIR</kbd> command, programs, when retrieving filenames, can |
||||||
|
retrieve volume labels.</a> All these factors about volume attributes come into a big |
||||||
|
factor when we look at Long Filenames. </li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<p>As an addendum, it might be interesting to note that each 8.3 file entry is 32 bytes |
||||||
|
long but that not all 32 bytes are used to store data -- some of them are plainly left as |
||||||
|
blank bytes. In Windows95 version of the directory table, however, all 32 bytes are used. </p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>General Specification</h3> |
||||||
|
|
||||||
|
<p>Just like DOS 8.3 filenames, Windows95 LFNs are also stored on directory tables, |
||||||
|
side-by-side with DOS 8.3 filenames. On top of that, to achieve compatibility with old DOS |
||||||
|
programs Microsoft designed LFN in a way so it resembles the old DOS 8.3 format. |
||||||
|
Furthermore, an 8.3 format version of LFN (<code>tttttt~n.xxx</code>) is also present next |
||||||
|
to each LFN entry for compatibility with non-LFN supporting programs. <a |
||||||
|
name="organization"></p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>Organization</h3> |
||||||
|
|
||||||
|
<p>From a low-level point-of-view, a normal directory table that only contains 8.3 |
||||||
|
filenames look like this: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="50%" border="1"> |
||||||
|
<tr> |
||||||
|
<td><code>...</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>8.3 entry</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>8.3 entry</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>8.3 entry</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>8.3 entry</code> </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>If you look at a directory table that contains LFN entries, however, this is what you |
||||||
|
will see: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="50%" border="1"> |
||||||
|
<tr> |
||||||
|
<td><code>...</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>LFN entry 3</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>LFN entry 2</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>LFN entry 1</code> </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td><code>8.3 entry (tttttt~n.xxx)</code> </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>Notice that Long Filenames can be pretty long, so LFN entries in a 8.3 directory |
||||||
|
structure can take up several 8.3 directory entry spaces. This is why the above file entry |
||||||
|
has several LFN entries for a single 8.3 file entry. </p> |
||||||
|
|
||||||
|
<p>Despite taking up 8.3 filename spaces, Long Filenames do not show up with the <kbd>DIR</kbd> |
||||||
|
command or with any other program, even the ones that do not recognize the LFN. How, then, |
||||||
|
do LFN entries get hidden from DOS? The answer is quite simple: By giving LFN entries |
||||||
|
"Read-only, System, Hidden, and Volume" attributes. (If you do not know details |
||||||
|
about file attributes, read the above text about </a><a href="#background">DOS 8.3 |
||||||
|
Filename Background</a>.) </p> |
||||||
|
|
||||||
|
<p>A special attention should be given to the fact that this combination of attributes -- |
||||||
|
Read-only, System, Hidden, Volume -- is not possible to make under normal circumstances |
||||||
|
using common utilities found in the market place (special disk-editing programs, such as |
||||||
|
Norton Disk Editor, is an exception.) </p> |
||||||
|
|
||||||
|
<p>This technique of setting Read-only, System, Hidden, Volume attributes works because |
||||||
|
most programs ignore files with volume attributes altogether, and even if they don't, they |
||||||
|
won't display any program that has system or hidden attributes set. And since the |
||||||
|
Read-only attribute is set, programs won't write anything over it. However, you can view |
||||||
|
"parts" of the LFN entries if any program is designed to show Volume attributed |
||||||
|
files. </p> |
||||||
|
<a name="storage"> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>Storage Organization</h3> |
||||||
|
|
||||||
|
<p>To understand the LFN storage organization within a directory table, it is important to |
||||||
|
understand the 8.3 storage organization. This is mainly due to the fact that LFN entries |
||||||
|
are stored similar to 8.3 filenames to avoid conflicts with DOS applications. </p> |
||||||
|
|
||||||
|
<p>The format of the traditional DOS 8.3 is as follows: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="80%" border="1"> |
||||||
|
<tr> |
||||||
|
<th width="15%" align="center">Offset </th> |
||||||
|
<th width="15%" align="center">Length </th> |
||||||
|
<th width="*" align="left"> Value </th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">0 </td> |
||||||
|
<td align="center">8 bytes </td> |
||||||
|
<td align="left"> Name </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">8 </td> |
||||||
|
<td align="center">3 bytes </td> |
||||||
|
<td align="left"> Extension </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">11 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Attribute (<code>00ARSHDV</code>) <br> |
||||||
|
<code>0</code>: unused bit <br> |
||||||
|
<code>A</code>: archive bit, <br> |
||||||
|
<code>R</code>: read-only bit <br> |
||||||
|
<code>S</code>: system bit <br> |
||||||
|
<code>D</code>: directory bit <br> |
||||||
|
<code>V</code>: volume bit </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">22 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Time </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">24 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Date </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">26 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Cluster (desc. below) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">28 </td> |
||||||
|
<td align="center">dword </td> |
||||||
|
<td align="left"> File Size </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p align="center">Note: <dfn>WORD</dfn> = 2 bytes, <dfn>DWORD</dfn> = 4 bytes </p> |
||||||
|
|
||||||
|
<p>Everything above you should know what they are except perhaps for the cluster. The |
||||||
|
cluster is a value representing another part of the disk, normally used to tell where the |
||||||
|
beginning of a file is. In case of a directory, it is the cluster that tells where the |
||||||
|
subdirectory's directory table starts. </p> |
||||||
|
|
||||||
|
<p>You may not know this, but LFN specification not only added the capability of having |
||||||
|
longer filenames, but it also improved the capability of 8.3 filenames as well. This new |
||||||
|
8.3 filename improvements are accomplished by using the unused directory table spaces |
||||||
|
(Remember how I told you that 8.3 filenames take up 32 bytes but not all 32 bytes are |
||||||
|
used? Now it's all used up!) This new format is as follows -- try comparing it with the |
||||||
|
traditional format shown above!: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="80%" border="1"> |
||||||
|
<tr> |
||||||
|
<th width="15%" align="center">Offset </th> |
||||||
|
<th width="15%" align="center">Length </th> |
||||||
|
<th width="*" align="left"> Value </th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">0 </td> |
||||||
|
<td align="center">8 bytes </td> |
||||||
|
<td align="left"> Name </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">8 </td> |
||||||
|
<td align="center">3 bytes </td> |
||||||
|
<td align="left"> Extension </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">11 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Attribute (<code>00ARSHDV</code>) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">12 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left" nowrap> NT (Reserved for WindowsNT; <br> |
||||||
|
always 0) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">13 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Created time; millisecond portion </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">14 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Created time; hour and minute </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">16 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Created date </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">18 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Last accessed date </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">20 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left" nowrap> Extended Attribute <br> |
||||||
|
(reserved for OS/2; always 0) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">22 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Time </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">24 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Date </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">26 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Cluster </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">28 </td> |
||||||
|
<td align="center">dword </td> |
||||||
|
<td align="left"> File Size </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>In any case, this new 8.3 filename format is the format used with the LFN. As for the |
||||||
|
LFN format itself (seen </a><a href="#organization">previously</a>) is stored |
||||||
|
"backwards", with the first entry toward the bottom and the last entry at the |
||||||
|
top, right above the new 8.3 filename entry. </p> |
||||||
|
|
||||||
|
<p>Each LFN entry is stored as follows: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="80%" border="1"> |
||||||
|
<tr> |
||||||
|
<th width="15%" align="center">Offset </th> |
||||||
|
<th width="15%" align="center">Length </th> |
||||||
|
<th width="*" align="left"> Value </th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">0 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Ordinal field (desc. below) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">1 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 1 (desc. below) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">3 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 2 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">5 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 3 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">7 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 4 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">9 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 5 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">11 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Attribute </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">12 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Type (reserved; always 0) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">13 </td> |
||||||
|
<td align="center">byte </td> |
||||||
|
<td align="left"> Checksum (desc. below) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">14 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 6 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">16 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 7 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">18 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 8 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">20 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 9 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">22 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 10 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">24 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 11 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">26 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Cluster (unused; always 0) </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">28 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 12 </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">30 </td> |
||||||
|
<td align="center">word </td> |
||||||
|
<td align="left"> Unicode character 13 </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>Throughout this entry, you see "unicode characters". Unicode characters are |
||||||
|
2-byte long characters (as opposed to ASCII characters that are 1-byte long each) that |
||||||
|
support not only traditional latin alphabet characters and arabic numbers but they also |
||||||
|
support the languages of the rest of the world, including the CJK trio (Chinese, Japanese, |
||||||
|
Korean), Arabic, Hebrew, etc. Plus you have some space left over for more math and science |
||||||
|
symbols. Unicode characters are still going through revisions (on their second revision as |
||||||
|
I am writing, I believe) but Windows95 has left spaces to more fully support unicodes in |
||||||
|
the future. You can keep up with the Unicode development by visiting the Unicode webpage |
||||||
|
at <a href="http://www.unicode.org/">www.unicode.org</a>. Note that, in the 2-byte unicode |
||||||
|
character, the first byte is always the character and the second byte is always the blank, |
||||||
|
as opposed to having the first byte blank and the second byte blank. There is a perfectly |
||||||
|
logical explanation for this but it's kind of long to get into at the moment so e-mail me |
||||||
|
if you are curious. (If you have a computer dictionary, look up "little endian" |
||||||
|
and it'll explain everything.) For our purposes, though, just treat every other word as an |
||||||
|
ASCII character as long as the following byte is a blank character. Anyways, notice that, |
||||||
|
in order to maintain the compatibility with older programs, the attribute byte and the |
||||||
|
cluster word had to be kept. Because of this, each unicode character had to be scattered |
||||||
|
throughout the entry. </p> |
||||||
|
|
||||||
|
<p>By now you probably noticed that there is no file information (size, date, etc.) stored |
||||||
|
in the LFN entry. Any information about the file itself is stored in the 8.3 filename, |
||||||
|
located below all the LFN entries (as <a href="#organization">mentioned before</a>). </p> |
||||||
|
|
||||||
|
<p>The checksum is created from the shortname data. The steps/equation used to calculate |
||||||
|
this checksum is as follows: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="80%" border="1"> |
||||||
|
<tr> |
||||||
|
<th>Step # </th> |
||||||
|
<th>Task </th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">1 </td> |
||||||
|
<td align="left"> Take the ASCII value of the first character. This is your |
||||||
|
first sum. </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">2 </td> |
||||||
|
<td align="left"> Rotate all the bits of the sum rightward by one bit. </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">3 </td> |
||||||
|
<td align="left"> Add the ASCII value of the next character with the value |
||||||
|
from above. This is your next sum. </td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td align="center">4 </td> |
||||||
|
<td align="left"> Repeat steps 2 through 3 until you are all through with the |
||||||
|
11 characters in the 8.3 filename. </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p align="center">In C/C++, the above steps look like this: </p> |
||||||
|
<div align="center"><center> |
||||||
|
|
||||||
|
<table width="80%" border="0"> |
||||||
|
<tr> |
||||||
|
<td><br> |
||||||
|
<code>for (sum = i = 0; i < 11; i++) {</code> <br> |
||||||
|
<code> sum = (((sum & 1) << 7) | ((sum & 0xfe) |
||||||
|
>> 1)) + name[i];</code> <br> |
||||||
|
<code>}</code> </td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</center></div> |
||||||
|
|
||||||
|
<p>This resulting checksum value is stored in each of the LFN entry to ensure that the |
||||||
|
short filename it points to indeed is the currently 8.3 entry it should be pointing to. </p> |
||||||
|
|
||||||
|
<p>Also, note that any file with a name that does not fill up the 8.3 spaces completely |
||||||
|
leaves a trace of space characters (ASCII value 32) in the blank spaces. These blank |
||||||
|
spaces do go into the calculation of the checksum and does not get left out of the |
||||||
|
calculation. </p> |
||||||
|
|
||||||
|
<p>I'm sure you're dying to know what the ordinal field is. This byte of information tells |
||||||
|
the order of the LFN entries (1st LFN entry, 2nd LFN entry, etc.) If it's out of order, |
||||||
|
something is wrong! How Windows95 would deal with LFN when such a thing happen is a |
||||||
|
mystery to me. <br> |
||||||
|
An example of how ordinal field work: The first LFN entry, located at the |
||||||
|
very bottom as we have <a href="#organization">seen before</a>, has an ordinal field value |
||||||
|
1; the second entry (if any -- remember that a LFN doesn't always have to be tens of |
||||||
|
characters long), located just before the first entry, has an ordinal field value of 2; |
||||||
|
etc. As an added precaution, the last entry has a marking on the ordinal field that tells |
||||||
|
that it is the last entry. This marking is done by setting the 6th bit of the ordinal |
||||||
|
field. </p> |
||||||
|
|
||||||
|
<p>That is basically all there is to long filenames. But before we end this conversation |
||||||
|
(while we're on the subject of LFN,) I think it would be interesting to note that, since |
||||||
|
any long filename can be up to 255 bytes long and each entry can hold up to 13 characters, |
||||||
|
there can only be up to 20 entries of LFN per file. That means it only needs 5 bits (0th |
||||||
|
bit to 4th bit) of the ordinal field. And with the 6th bit used to mark the last entry, |
||||||
|
two bits are left for open usage -- the 5th and the 7th bit. Whether or not Microsoft is |
||||||
|
going to do anything with these bits -- or why Microsoft used the 6th bit to indicate the |
||||||
|
last entry instead of 7th or 5th bit and limited the file length to 255 bits -- remains to |
||||||
|
be a mystery only Microsoft will keep to itself. </p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<h3>Credit</h3> |
||||||
|
|
||||||
|
<p><font size="-1">Much the information in this documentation has been gathered from |
||||||
|
Norton Utilities for Windows95 user's manual. Detailed researches were done using Norton |
||||||
|
Utilities Disk Edit. The checksum calculation was graciously donated by Jacob Verhoeks to <code>comp.os.msdos.programmer</code> |
||||||
|
Newsgroup as a reply to my request. Apparently the file Mr. Verhoeks used to get me the |
||||||
|
checksum code, <code>vfat.txt</code>, that comes with newer Linux operating systems have |
||||||
|
some good information on Windows95 LFN. BTW, I just (like, right now) found out that |
||||||
|
checksum algorithm is also in Ralf Brown's Interrupt List. </font></p> |
||||||
|
|
||||||
|
<hr> |
||||||
|
|
||||||
|
<p>Copyright ©1996-1998 vinDaci </p> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,319 @@ |
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" |
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd"> |
||||||
|
|
||||||
|
<!-- http://www.maverick-os.dk/FileSystemFormats/VFAT_LongFileNames.html --> |
||||||
|
|
||||||
|
<HTML LANG="en"> |
||||||
|
|
||||||
|
<HEAD> |
||||||
|
<TITLE>Maverick - The Operating System</TITLE> |
||||||
|
<META NAME="author" CONTENT="Lasse Krogh Thygesen"> |
||||||
|
<META NAME="copyright" CONTENT="(C) 1999 Lasse Krogh Thygesen"> |
||||||
|
<META NAME="keywords" CONTENT="maverick,operating system,os,x86,intel,ata,ide,eide,atapi,pic,pit,dma,protected mode,pmode"> |
||||||
|
<META NAME="description" CONTENT=""> |
||||||
|
<LINK REL="stylesheet" TYPE="text/css" HREF="Maverick.css"> |
||||||
|
</HEAD> |
||||||
|
|
||||||
|
<BODY> |
||||||
|
<DIV CLASS="MiniMenu"> |
||||||
|
[<A HREF="FAT32_FileSystem.html" TITLE="FAT32 File System">Previous</A>] |
||||||
|
- [<A HREF="../Mainmenu_NoFrames.html" TITLE="Go to main menu">Main menu</A>] |
||||||
|
- [<A HREF="../FileFormats/FileFormatID.html" TITLE="File Format ID">Next</A>]<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<H1 CLASS="PreTitle">Specifications</H1> |
||||||
|
<H1>VFAT Long File Names</H1> |
||||||
|
<H1 CLASS="SubTitle">Usage: Stores long filenames (LFN) for Windows</H1> |
||||||
|
|
||||||
|
<HR> |
||||||
|
|
||||||
|
<DIV ID="Introduction"> |
||||||
|
<H2>Introduction</H2> |
||||||
|
This isn't a file system in itself, but a kind of sub file system, which can be placed over a FAT12, FAT16 or FAT32 file system. The VFAT system is a way of hiding long file names in the directory structure of the FAT file systems.<BR> |
||||||
|
<BR> |
||||||
|
The filenames are stored using unicode characters which are 16 bit long.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="CoexistenceWithFAT"> |
||||||
|
<H2>Coexistence with FAT12, FAT16 & FAT32</H2> |
||||||
|
Depending on the length of the long filename, the system will create a number of invalid 8.3 entries in the Directory Table, these are the LFN (Long Filename) entries. These <ABBR TITLE="Long Filename">LFN</ABBR> entries are stored with the with the last LFN entry topmost, and the first LFN entry just above a valid Directory Entry. So when looked upon from the top and down, the Directory Table looks something like this:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="DirectoryExample" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Directory Example"> |
||||||
|
<CAPTION> |
||||||
|
Directory Example |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="20%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="40%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="40%" ALIGN="Center" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Entry Nr.</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Without LFN Entries</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">With LFN Entries</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>...</TD><TD>...</TD><TD>...</TD></TR> |
||||||
|
<TR><TD>n</TD><TD>Normal 1</TD><TD>Normal 1</TD></TR> |
||||||
|
<TR><TD>n+1</TD><TD>Normal 2</TD><TD>LFN for Normal 2 - Part 3</TD></TR> |
||||||
|
<TR><TD>n+2</TD><TD>Normal 3</TD><TD>LFN for Normal 2 - Part 2</TD></TR> |
||||||
|
<TR><TD>n+3</TD><TD>Normal 4</TD><TD>LFN for Normal 2 - Part 1</TD></TR> |
||||||
|
<TR><TD>n+4</TD><TD>Normal 5</TD><TD>Normal 2</TD></TR> |
||||||
|
<TR><TD>n+5</TD><TD>Normal 6</TD><TD>Normal 3</TD></TR> |
||||||
|
<TR><TD>...</TD><TD>...</TD><TD>...</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
The LFN entries have the Volume Name, Hidden, System and the Read-Only flags set. So most programs won't display them because of the Volume Name flag (Volume entries are rarely displayed), and they won't be overwridden because of the Read-Only flag.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="DirectoryEntries"> |
||||||
|
<H2>Directory Entries</H2> |
||||||
|
The VFAT Directory Format, can coexist on a normal FATxx system. The LFN entries are hidden from normal programs, and available to those who know how to read them. But in addition to the LFN entries the VFAT Directory Format enhances the original structure of the Directory Table as found in FAT16. The Directory Table can still be read by older applications, but all the unused space from the FAT16 format, is now used to store some additional information. This is the format of the VFAT Directory entries:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="DirectoryEntryStructure" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Structure of the VFAT Directory Entries"> |
||||||
|
<CAPTION> |
||||||
|
Structure of the VFAT Directory Entries |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Offset</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Size</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Description</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>00h</TD><TD>8 bytes</TD><TD>Filename</TD></TR> |
||||||
|
<TR><TD>08h</TD><TD>3 bytes</TD><TD>Filename extension</TD></TR> |
||||||
|
<TR><TD>0Bh</TD><TD>1 bytes</TD><TD><A HREF="#FlagByte">Flag byte</A></TD></TR> |
||||||
|
<TR><TD>0Ch</TD><TD>1 bytes</TD><TD>NT - Reserved for Windows NT - Should always be 0000h</TD></TR> |
||||||
|
<TR><TD>0Dh</TD><TD>1 bytes</TD><TD>Creation Time - Millisecond</TD></TR> |
||||||
|
<TR><TD>0Eh</TD><TD>2 bytes</TD><TD>Creation Time - Hour & Minute</TD></TR> |
||||||
|
<TR><TD>10h</TD><TD>2 bytes</TD><TD>Created Date</TD></TR> |
||||||
|
<TR><TD>12h</TD><TD>2 bytes</TD><TD>Last Accessed Data</TD></TR> |
||||||
|
<TR><TD>14h</TD><TD>2 bytes</TD><TD>Starting cluster (High word) on FAT32 file systems, else 0000h</TD></TR> |
||||||
|
<TR><TD>16h</TD><TD>2 bytes</TD><TD>Time</TD></TR> |
||||||
|
<TR><TD>18h</TD><TD>2 bytes</TD><TD>Date</TD></TR> |
||||||
|
<TR><TD>1Ah</TD><TD>2 bytes</TD><TD>Starting cluster (Low word)</TD></TR> |
||||||
|
<TR><TD>1Ch</TD><TD>4 bytes</TD><TD>File size in bytes</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="FlagByte"> |
||||||
|
<H3>Flag Byte</H3> |
||||||
|
The flag byte defines a set of flags which is set for directories, volume name, hidden files, system files, etc. These are the flags:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="Flags" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="60%" SUMMARY="Flags in the flag byte"> |
||||||
|
<CAPTION> |
||||||
|
Flags in the flag byte |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="8" WIDTH="3%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable" COLSPAN="2">Unused</TD> |
||||||
|
<TD CLASS="BitTable">A</TD> |
||||||
|
<TD CLASS="BitTable">D</TD> |
||||||
|
<TD CLASS="BitTable">V</TD> |
||||||
|
<TD CLASS="BitTable">S</TD> |
||||||
|
<TD CLASS="BitTable">H</TD> |
||||||
|
<TD CLASS="BitTable">R</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Achieved"> |
||||||
|
<H4>Achieved Flag</H4> |
||||||
|
The A flag is set by a backup program, so that the user/program knows which files that has been backed up. This flag is not used correctly by many user and perhaps also by many operating systems.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="System"> |
||||||
|
<H4>System</H4> |
||||||
|
This flag shows that the file/directory is important for the system, and shouldn't be manipulated.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Hidden"> |
||||||
|
<H4>Hidden</H4> |
||||||
|
This flag tell the system and programs that the file should be hidden for the user. But in a lot of programs this can be overwritten by the user.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ReadOnly"> |
||||||
|
<H4>Read Only</H4> |
||||||
|
The flag is used to prevent programs from not automatically overwriting or deleting this file/directory.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Directory"> |
||||||
|
<H4>Directory</H4> |
||||||
|
This flag is set, when an entry in the directory table is not pointing to the beginning of a file, but to another directory table. A sub-directory. The sub-directory is placed in the cluster, where the Starting Cluster field points to. The format of this sub-directory table is identical to the root directory table.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="VolumeName"> |
||||||
|
<H4>Volume Name</H4> |
||||||
|
When this flag is set, the directory entry is not pointing to a file, but to nothing. The only information used from this entry is the filename (8 bytes) plus the filename extension (3 bytes). These bytes form an 11 bytes long volume label (without any .) There may be only <B>one</B> valid entry on the entire disk with this flag set. And preferably this entry should be among the first 3 entries in the root directory table, if not, then MS-DOS can have trouble displaying the right volume label. This volume name should be the same as the one in the boot sector. The latter one is infact rarely used.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="LFNEntry"> |
||||||
|
<H2>LFN Entry</H2> |
||||||
|
The LFN entries are, as described, placed above the real directory entry, for which they contain the long filename. The first 13 letters are in the first entry, letters 14-26 are in the second LFN entry, letters 27-39 are in the third LFN entry, and so on until the filename has ended. The maximum length of a filename has been limited to 255, even though this scheme has the potential to make them 1664 bytes long, Microsoft - who designed FAT32 - decided not to. The structure of each LFN entry is as follows:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="LFNEntryStructure" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Structure of a LFN Entry"> |
||||||
|
<CAPTION> |
||||||
|
Structure of a LFN Entry |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Offset</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Size</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Description</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>00h</TD><TD>1 bytes</TD><TD><A HREF="#OrdinalField">Ordinal field</A></TD></TR> |
||||||
|
<TR><TD>01h</TD><TD>2 bytes</TD><TD>Unicode Character 1</TD></TR> |
||||||
|
<TR><TD>03h</TD><TD>2 bytes</TD><TD>Unicode Character 2</TD></TR> |
||||||
|
<TR><TD>05h</TD><TD>2 bytes</TD><TD>Unicode Character 3</TD></TR> |
||||||
|
<TR><TD>07h</TD><TD>2 bytes</TD><TD>Unicode Character 4</TD></TR> |
||||||
|
<TR><TD>09h</TD><TD>2 bytes</TD><TD>Unicode Character 5</TD></TR> |
||||||
|
<TR><TD>0Bh</TD><TD>1 bytes</TD><TD><A HREF="#FlagByte">Flag byte</A></TD></TR> |
||||||
|
<TR><TD>0Ch</TD><TD>1 bytes</TD><TD>Reserved - Always 00h</TD></TR> |
||||||
|
<TR><TD>0Dh</TD><TD>1 bytes</TD><TD><A HREF="#Checksum">Checksum</A></TD></TR> |
||||||
|
<TR><TD>0Eh</TD><TD>2 bytes</TD><TD>Unicode Character 6</TD></TR> |
||||||
|
<TR><TD>10h</TD><TD>2 bytes</TD><TD>Unicode Character 7</TD></TR> |
||||||
|
<TR><TD>12h</TD><TD>2 bytes</TD><TD>Unicode Character 8</TD></TR> |
||||||
|
<TR><TD>14h</TD><TD>2 bytes</TD><TD>Unicode Character 9</TD></TR> |
||||||
|
<TR><TD>16h</TD><TD>2 bytes</TD><TD>Unicode Character 10</TD></TR> |
||||||
|
<TR><TD>18h</TD><TD>2 bytes</TD><TD>Unicode Character 11</TD></TR> |
||||||
|
<TR><TD>1Ah</TD><TD>2 bytes</TD><TD>Always 0000h</TD></TR> |
||||||
|
<TR><TD>1Ch</TD><TD>2 bytes</TD><TD>Unicode Character 12</TD></TR> |
||||||
|
<TR><TD>1Eh</TD><TD>2 bytes</TD><TD>Unicode Character 13</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
Only the cluster word (offset 1Ah) and the flag byte (offset 0Bh), are required for compatibility reasons.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="OrdinalField"> |
||||||
|
<H3>Ordinal Field</H3> |
||||||
|
The ordinal field is used to tell the system which number the LFN entry has, in the LFN string. The first LFN entry will have a value of 01h. The second LFN entry, if there is one, will have a value of 02h, and so on it continues. When a LFN entry contains the last character in the name the Last LFN bit is set (bit 6 in the Ordinal Field).<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="OrdinalFieldStructurePartTwo" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="LFN Numbering Field"> |
||||||
|
<CAPTION> |
||||||
|
The Ordinal Field |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="8" WIDTH="3%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable">Deleted LFN</TD> |
||||||
|
<TD CLASS="BitTable">Last LFN</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="6">LFN Number</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Checksum"> |
||||||
|
<H3>Calculating the Checksum</H3> |
||||||
|
The Checksum byte in each LFN entry is there to make sure that the LFN entry points to the right file. The checksum value is calculated on the basis of the 8.3 filename, which is present in the valid Directory Table entry. Spaces (ASCII: 20h) are also calculated. The algorithm for calculating the checksum is:<BR> |
||||||
|
<BR> |
||||||
|
<OL> |
||||||
|
<LI>The ASCII value of the first character is the base sum.</LI> |
||||||
|
<LI>Rotate the sum bitwise one bit to the right.</LI> |
||||||
|
<LI>Add the ASCII value of the next character to the sum.</LI> |
||||||
|
<LI>Repeat step 2 and 3 until all 11 characters has been added.</LI> |
||||||
|
</OL> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="UnicodeCharacters"> |
||||||
|
<H3>Unicode Characters</H3> |
||||||
|
The Unicode characters in the specification is a 16 bit value, where the lower 8 bits represent the respective ASCII value and the upper 8 bits are clear. The means that the LFN names are just ASCII style names, with extra holes.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="Conclusion"> |
||||||
|
<H2>Conclusion</H2> |
||||||
|
The VFAT Directory Format is a very clever way to add long filename support to the older FAT file systems, while still maintaining compatibility. It is however strange why Microsoft (who designed FAT32) didn't implemented native support for long filenames in FAT32 when they created it a few years back.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
</BODY> |
||||||
|
|
||||||
|
</HTML> |
@ -0,0 +1,816 @@ |
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" |
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd"> |
||||||
|
|
||||||
|
<!-- http://www.maverick-os.dk/FileSystemFormats/FAT16_FileSystem.html --> |
||||||
|
|
||||||
|
<HTML LANG="en"> |
||||||
|
|
||||||
|
<HEAD> |
||||||
|
<TITLE>Maverick - The Operating System</TITLE> |
||||||
|
<META NAME="author" CONTENT="Lasse Krogh Thygesen"> |
||||||
|
<META NAME="copyright" CONTENT="(C) 1999 Lasse Krogh Thygesen"> |
||||||
|
<META NAME="keywords" CONTENT="maverick,operating system,os,x86,intel,ata,ide,eide,atapi,pic,pit,dma,protected mode,pmode"> |
||||||
|
<META NAME="description" CONTENT=""> |
||||||
|
<LINK REL="stylesheet" TYPE="text/css" HREF="Maverick.css"> |
||||||
|
</HEAD> |
||||||
|
|
||||||
|
<BODY> |
||||||
|
<DIV CLASS="MiniMenu"> |
||||||
|
[<A HREF="FAT12_FileSystem.html" TITLE="FAT12 File System">Previous</A>] |
||||||
|
- [<A HREF="../Mainmenu_NoFrames.html" TITLE="Go to main menu">Main menu</A>] |
||||||
|
- [<A HREF="FAT32_FileSystem.html" TITLE="FAT32 File System">Next</A>]<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<H1 CLASS="PreTitle">Specifications</H1> |
||||||
|
<H1>FAT16 File System</H1> |
||||||
|
<H1 CLASS="SubTitle">Used: On machines with small harddrives running MS-DOS, Windows 95/98</H1> |
||||||
|
|
||||||
|
<HR> |
||||||
|
|
||||||
|
<DIV ID="Introduction"> |
||||||
|
<H2>Introduction</H2> |
||||||
|
This is the 16-bit version of the FAT file system. The 16-bit part describes the way units are allocated on the drive. The FAT16 file system uses a 16-bit number to identify each allocation unit (called cluster), and this gives it a total of 65.536 clusters. The size of each cluster is defined in the boot sector of the volume (volume = partition). The File System ID number usually associated with FAT16 volumes are 04h and 06h. The first is used on volumes with less than 65536 sectors (typical this is on drives less than 32 Mb in size), and the latter one is used on volumes with more than 65536 sectors. There is also another variant which is used with the LBA address mode, that variant has a File System ID of 0Eh. <SPAN CLASS="Note">I do not know if the LBA variant is different from the CHS type. So far I don't se why anything should be changed to support LBA addresses.</SPAN><BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="BasicStructure"> |
||||||
|
<H3>Basic Structure</H3> |
||||||
|
The FAT16 file system structure contains the following regions:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="FAT16Structure" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="40%" SUMMARY="FAT16 File System Structure"> |
||||||
|
<CAPTION> |
||||||
|
FAT16 File System Structure |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="100%" ALIGN="Center" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Region</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>Reserved Region (incl. Boot Sector)</TD></TR> |
||||||
|
<TR><TD>File Allocation Table (FAT)</TD></TR> |
||||||
|
<TR><TD>Root Directory</TD></TR> |
||||||
|
<TR><TD>Data Region</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
The first sector (boot sector) contain information which is used to calculate the sizes and locations of the other regions. The boot sector also contain code to boot the operating system installed on the volume. The data region is split up into logical blocks called clusters. Each of these clusters has an accompanying entry in the FAT region. The cluster specific entry can either contain a value of the next cluster which contain data from the file, or a so called End-of-file value which means that there are no more clusters which contain data from the file. The root directory and its sub-directories contain filename, dates, attribute flags and starting cluster information about the filesystem objects.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="BootSector"> |
||||||
|
<H2>Boot Sector</H2> |
||||||
|
The first sector in the reserved region is the boot sector. Though this sector is typical 512 bytes in can be longer depending on the media. The boot sector typical start with a 3 byte jump instruction to where the bootstrap code is stored, followed by an 8 byte long string set by the creating operating system. This is followed by the BIOS Parameter Block, and then by an Extended BIOS Parameter Block. Finally the boot sector contain boot code and a signature.<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="BootSectorStructure" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Structure of the FAT16 Boot sector"> |
||||||
|
<CAPTION> |
||||||
|
Structure of the FAT16 Boot sector |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="10%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
<COL WIDTH="10%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="10%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Part</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Offset</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Size</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Description</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>Code</TD><TD>0000h</TD><TD>3 bytes</TD><TD>Code to jump to the bootstrap code.</TD></TR> |
||||||
|
<TR><TD>OS Name</TD><TD>0003h</TD><TD>8 bytes</TD><TD>Oem ID - Name of the formatting OS</TD></TR> |
||||||
|
<TR><TD ROWSPAN="12">BIOS Para- meter Block</TD><TD>000Bh</TD><TD>2 bytes</TD><TD><A HREF="#BytesPerSector">Bytes per Sector</A></TD></TR> |
||||||
|
<TR><TD>000Dh</TD><TD>1 bytes</TD><TD><A HREF="#SectorsPerCluster">Sectors per Cluster</A> - Usual there is 512 bytes per sector.</TD></TR> |
||||||
|
<TR><TD>000Eh</TD><TD>2 bytes</TD><TD><A HREF="#ReservedSectors">Reserved sectors</A> from the start of the volume.</TD></TR> |
||||||
|
<TR><TD>0010h</TD><TD>1 bytes</TD><TD><A HREF="#NumberOfFATs">Number of FAT copies</A> - Usual 2 copies are used to prevent data loss.</TD></TR> |
||||||
|
<TR><TD>0011h</TD><TD>2 bytes</TD><TD><A HREF="#RootEntriesCount">Number of possible root entries</A> - 512 entries are recommended.</TD></TR> |
||||||
|
<TR><TD>0013h</TD><TD>2 bytes</TD><TD><A HREF="#SmallNumberOfSectors">Small number of sectors</A> - Used when volume size is less than 32 Mb.</TD></TR> |
||||||
|
<TR><TD>0015h</TD><TD>1 bytes</TD><TD><A HREF="#MediaDescriptor">Media Descriptor</A></TD></TR> |
||||||
|
<TR><TD>0016h</TD><TD>2 bytes</TD><TD><A HREF="#SectorsPerFAT">Sectors per FAT</A></TD></TR> |
||||||
|
<TR><TD>0018h</TD><TD>2 bytes</TD><TD><A HREF="#SectorsPerTrack">Sectors per Track</A></TD></TR> |
||||||
|
<TR><TD>001Ah</TD><TD>2 bytes</TD><TD><A HREF="#NumberOfHeads">Number of Heads</A></TD></TR> |
||||||
|
<TR><TD>001Ch</TD><TD>4 bytes</TD><TD><A HREF="#HiddenSectors">Hidden Sectors</A></TD></TR> |
||||||
|
<TR><TD>0020h</TD><TD>4 bytes</TD><TD><A HREF="#LargeNumberOfSectors">Large number of sectors</A> - Used when volume size is greater than 32 Mb.</TD></TR> |
||||||
|
<TR><TD ROWSPAN="6">Ext. BIOS Para- meter Block</TD><TD>0024h</TD><TD>1 bytes</TD><TD><A HREF="#DriveNumber">Drive Number</A> - Used by some bootstrap code, fx. MS-DOS.</TD></TR> |
||||||
|
<TR><TD>0025h</TD><TD>1 bytes</TD><TD><A HREF="#Reserved">Reserved</A> - Is used by Windows NT to decide if it shall check disk integrity.</TD></TR> |
||||||
|
<TR><TD>0026h</TD><TD>1 bytes</TD><TD><A HREF="#ExtendedBootSignature">Extended Boot Signature</A> - Indicates that the next three fields are available.</TD></TR> |
||||||
|
<TR><TD>0027h</TD><TD>4 bytes</TD><TD><A HREF="#VolumeSerialNumber">Volume Serial Number</A></TD></TR> |
||||||
|
<TR><TD>002Bh</TD><TD>11 bytes</TD><TD><A HREF="#VolumeLabel">Volume Label</A> - Should be the same as in the root directory.</TD></TR> |
||||||
|
<TR><TD>0036h</TD><TD>8 bytes</TD><TD><A HREF="#FileSystemType">File System Type</A> - The string should be 'FAT16 '</TD></TR> |
||||||
|
<TR><TD>Code</TD><TD>003Eh</TD><TD>448 bytes</TD><TD><A HREF="#BootstrapCode">Bootstrap code</A> - May schrink in the future.</TD></TR> |
||||||
|
<TR><TD>Sig.</TD><TD>01FEh</TD><TD>2</TD><TD><A HREF="#BootSectorSignature">Boot sector signature</A> - This is the AA55h signature.</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="BIOSParameterBlock"> |
||||||
|
<H3>BIOS Parameter Block</H3> |
||||||
|
The BIOS Parameter Block contains basic information about the overall structure of the FAT file system. That is information such as sector and cluster size, location information of FAT copies, the root directory size etc..<BR> |
||||||
|
<BR> |
||||||
|
|
||||||
|
<DIV ID="BytesPerSector"> |
||||||
|
<H4>Bytes Per Sector</H4> |
||||||
|
This value is the number of bytes in each physical sector. The allowed values are: 512, 1024, 2048 or 4096 bytes. A lot of code outthere are assuming 512 bytes per sectors, so any other values can give compatibility problems.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="SectorsPerCluster"> |
||||||
|
<H4>Sectors Per Cluster</H4> |
||||||
|
This is the number of sectors per cluster. The allowed values are: 1, 2, 4, 8, 16, 32 or 128. But de-facto is that most combinations of 'BytesPerCluster' * 'SectorsPerCluster' which gives a total value over 32 Kb per cluster, are not supported on many system.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ReservedSectors"> |
||||||
|
<H4>Reserved Sectors</H4> |
||||||
|
Since the reserved region always contain the boot sector a zero value in this field is not allowed. The usual setting of this value is 1. The value is used to calculate the location for the first sector containing the FAT.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="NumberOfFATs"> |
||||||
|
<H4>Number of FAT copies</H4> |
||||||
|
This is the number of FAT copies in the file system. The recommended value is 2 (and then have two FAT copies), but other values are validm though they may not be supported on some system. The usage of two copies are to prevent data loss if one or part of one FAT copy is corrupted.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="RootEntriesCount"> |
||||||
|
<H4>Root Entries Count</H4> |
||||||
|
This value contain the number of entries in the root directory. Its recommended that the number of entries is an even multiple of the BytesPerSector values. The recommended value for FAT16 volumes is 512 entries (compatibility reasons).<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="SmallNumberOfSectors"> |
||||||
|
<H4>Small Number of Sectors</H4> |
||||||
|
This field states the total number of sectors in the volume. That includes the number of sectors occupied by the four regions which the FAT16 file system consist of. For FAT16 volumes that use less than 65536 sectors this field is used. The File System Id in the MBR is then 04h. For FAT16 volumes that use more the 65535 sectors the <A HREF="#LargeNumberOfSectors">Large Number of Sectors</A> field is used and this one should be set to 0h.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="MediaDescriptor"> |
||||||
|
<H4>Media Descriptor</H4> |
||||||
|
These are the possible media descriptors values in the FAT boot sector. <SPAN CLASS="Note">This is the same value which must be in the low byte in the first entry of the FAT.</SPAN><BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="MediaDescriptors" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="60%" SUMMARY="The possible media descriptors"> |
||||||
|
<CAPTION> |
||||||
|
Media Descriptors |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="20%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="20%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="60%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Hex Value</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Capacity</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Physical Format</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>F0</TD><TD>2.88 MB</TD><TD>3.5-inch, 2-sided, 36-sector</TD></TR> |
||||||
|
<TR><TD>F0</TD><TD>1.44 MB</TD><TD>3.5-inch, 2-sided, 18-sector</TD></TR> |
||||||
|
<TR><TD>F8</TD><TD>?</TD><TD>Fixed disk</TD></TR> |
||||||
|
<TR><TD>F9</TD><TD>720 KB</TD><TD>3.5-inch, 2-sided, 9-sector</TD></TR> |
||||||
|
<TR><TD>F9</TD><TD>1.2 MB</TD><TD>5.25-inch, 2-sided, 15-sector</TD></TR> |
||||||
|
<TR><TD>FA</TD><TD>?</TD><TD>?</TD></TR> |
||||||
|
<TR><TD>FB</TD><TD>?</TD><TD>?</TD></TR> |
||||||
|
<TR><TD>FC</TD><TD>180 KB</TD><TD>5.25-inch, 1-sided, 9-sector</TD></TR> |
||||||
|
<TR><TD>FD</TD><TD>360 KB</TD><TD>5.25-inch, 2-sided, 9-sector</TD></TR> |
||||||
|
<TR><TD>FE</TD><TD>160 KB</TD><TD>5.25-inch, 1-sided, 8-sector</TD></TR> |
||||||
|
<TR><TD>FF</TD><TD>320 KB</TD><TD>5.25-inch, 2-sided, 8-sector</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="SectorsPerFAT"> |
||||||
|
<H4>Sectors Per FAT</H4> |
||||||
|
This is the number of sectors occupied by one copy of the FAT.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="SectorsPerTrack"> |
||||||
|
<H4>Sectors Per Track</H4> |
||||||
|
This value is used when the volume is on a media which have a geometry, that is when the <ABBR TITLE="Logical Block Address">LBA</ABBR> number is broken down into a Cylinder-Head-Sector address. This field represents the multiple of the max. Head and Sector value used when the volume was formatted. The field itself is used to check if the LBA to <ABBR TITLE="Cylinder-Head-Sector">CHS</ABBR> translation has changed, since the formatting. And for calculating the correct Cylinder, Head and Sector values for the translation algorithm.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="NumberOfHeads"> |
||||||
|
<H4>Number of Heads</H4> |
||||||
|
This value is used when the volume is on a media which have a geometry, that is when the <ABBR TITLE="Logical Block Address">LBA</ABBR> number is broken down into a Cylinder-Head-Sector address. This field represents the Head value used when the volume was formatted. The field itself is used to check if the LBA to <ABBR TITLE="Cylinder-Head-Sector">CHS</ABBR> translation has changed, since the formatting. And for calculating the correct Cylinder, Head and Sector values for the translation algorithm.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="HiddenSectors"> |
||||||
|
<H4>Hidden Sectors</H4> |
||||||
|
When the volume is on a media that is partitioned, this value contains the number of sectors preceeding the first sector of the volume.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="LargeNumberOfSectors"> |
||||||
|
<H4>Large Number of Sectors</H4> |
||||||
|
This field states the total number of sectors in the volume. That includes the number of sectors occupied by the four regions which the FAT16 file system consist of. For FAT16 volumes that use more than 65535 sectors this field is used. The File System Id in the MBR is then 06h. For FAT16 volumes that use less than 65536 sectors the <A HREF="#SmallNumberOfSectors">Small Number of Sectors</A> field is used and this one should be set to 0h.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="ExtendedBIOSParameterBlock"> |
||||||
|
<H3>Extended BIOS Parameter Block</H3> |
||||||
|
The Extended BIOS Parameter Block contains information that is only used in the FAT16 file system.<BR> |
||||||
|
<BR> |
||||||
|
|
||||||
|
<DIV ID="DriveNumber"> |
||||||
|
<H4>Drive Number</H4> |
||||||
|
This is the int 13h drive number of the drive. The value 00h is used for the first floppy drive and the value 80h is used for the first harddrive. MS-DOS's bootstrap uses this value to find the correct drive.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Reserved"> |
||||||
|
<H4>Reserved</H4> |
||||||
|
Reserved byte. It was original used to store the cylinder on which the boot sector is located. But Windows NT uses this byte to store two flags. The lowest bit would indicates that a check disk should be run at boot time, and the second lowest flag indicates that a surface scan should be run.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ExtendedBootSignature"> |
||||||
|
<H4>Extended Boot Signature</H4> |
||||||
|
If this byte contain a value of 29h it indicates that the following three fields are available.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="VolumeSerialNumber"> |
||||||
|
<H4>Volume Serial Number</H4> |
||||||
|
This value is a 32 bit random number, which, combined with the <A HREF="#VolumeLabel">volume label</A>, makes is possible to track removable media and check if the correct one is inserted.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="VolumeLabel"> |
||||||
|
<H4>Volume Label</H4> |
||||||
|
This 11 byte long string should match the volume label entry in the root directory. If no such entry is available this field should contain the string 'NO NAME ' (11 bytes long string). When updating the volume label, both, this field and the entry in the root directory should be updated.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="FileSystemType"> |
||||||
|
<H4>File System Type</H4> |
||||||
|
This 8 byte long string should be used for informational display only. Thats because its sometime incorrectly set. The field should contain the string 'FAT16 ' (8 bytes long string).<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="BootstrapCode"> |
||||||
|
<H3>Bootstrap Code</H3> |
||||||
|
The bootstrap code is different between operating system and versions which are intended to be loaded of this FAT16 volume. The responsability of the bootstrap code is to continue the boot sequence. If ex. MS-DOS is installed the bootstrap code will locate the file IO.SYS in the file system, load part of it into memory and then jump to a specific entrypoint in IO.SYS. What the bootstrap code does is vary between operating system.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="BootSectorSignature"> |
||||||
|
<H3>Boot Sector Signature</H3> |
||||||
|
The word at offset 1FEh should contain the signature AA55h. This will indicate to the BIOS that the sector is executable. The signature is also used by other applications when validating that the correct sector has been loaded. <SPAN CLASS="Note">No matter what the Bytes Per Sector value is this signature should always be at offset 1FEh.</SPAN><BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="FileAllocationTable"> |
||||||
|
<H2>File Allocation Table</H2> |
||||||
|
The <ABBR TITLE="File Allocation Table">FAT</ABBR> structure contain linked lists of files in the file system. Any file or directory entry in a (sub)directory list contain a cluster number for the first chunk of the file/directory. This cluster number also has an associated entry in the FAT. At this entry in the FAT a single word value either points to the next cluster/chunk or it contain an End-of-file value. These are the valid values:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="ValidFATValue" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="60%" SUMMARY="Valid FAT16 values"> |
||||||
|
<CAPTION> |
||||||
|
Valid FAT16 values |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="30%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Value</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Description</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>0000h</TD><TD>Free cluster</TD></TR> |
||||||
|
<TR><TD>0001h - 0002h</TD><TD>Not allowed</TD></TR> |
||||||
|
<TR><TD>0003h - FFEFh</TD><TD>Number of the next cluster</TD></TR> |
||||||
|
<TR><TD>FFF7h</TD><TD>One or more bad sectors in cluster</TD></TR> |
||||||
|
<TR><TD>FFF8h - FFFFh</TD><TD>End-of-file</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
Each FAT copy start with a value of FFxxh for the first cluster, where xx is equal to the <A HREF="#MediaDescriptor">Media Descriptor</A> field in the BIOS Parameter Block. The FAT entry for the second cluster is set to the End-of-file value (FFFFh). The two highest bits of this value may be used for dirty volume flags in the following way.<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="FATValue" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="60%" SUMMARY="FAT Entry Value for 2nd cluster"> |
||||||
|
<CAPTION> |
||||||
|
FAT Entry Value for 2nd cluster |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="32" WIDTH="6%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">15</TH> |
||||||
|
<TH CLASS="BitTable">14</TH> |
||||||
|
<TH CLASS="BitTable">13</TH> |
||||||
|
<TH CLASS="BitTable">12</TH> |
||||||
|
<TH CLASS="BitTable">11</TH> |
||||||
|
<TH CLASS="BitTable">10</TH> |
||||||
|
<TH CLASS="BitTable">9</TH> |
||||||
|
<TH CLASS="BitTable">8</TH> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable">C</TD> |
||||||
|
<TD CLASS="BitTable">E</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="14">These bits must be set</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="NoColor" COLSPAN="15" ALIGN="Left"> |
||||||
|
C = If clear then the volume may be dirty because it was not cleanly dismounted. If the bit is set then the volume is clean.<BR> |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
<TR> |
||||||
|
<TD CLASS="NoColor" COLSPAN="15" ALIGN="Left"> |
||||||
|
E = If clear a read/write error was encountered during the last time the volume was mounted. If the bit is set then no read/write error was encountered.<BR> |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
It should be noted that the last entry in the FAT should be calculated by taking the number of clusters in the data area, and not relying on the <A HREF="#SectorsPerFAT">Sectors Per FAT</A> field in the BIOS Parameter Block. This is because the number of entries in the FAT doesn't have to be an even multiple of the bytes per sector value.<BR> |
||||||
|
<BR> |
||||||
|
The maximum size of each FAT copy is 128 Kb (2 * 65536).<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="DirectoryEntry"> |
||||||
|
<H2>Directory Entry Structure</H2> |
||||||
|
Each of the entries in a directory list is 32 byte long. The only directory which is in a fixed location is the root directory. This is also the only directory which may contain an entry with the Volume Label attribute set. The size of the <A HREF="#RootEntriesCount">root directory</A> is defined in the BIOS Parameter Block.<BR> |
||||||
|
<BR> |
||||||
|
Sub-directories are created by allocating a cluster which then are cleared so it doesn't contain any directory entries. Two default entries are then created: The '.' entry point to the directory itself, and the '..' entry points to the parent directory. If the contents of a sub-directory grows beyond what can be in the cluster a new cluster is allocated in the same way as for files.<BR> |
||||||
|
<BR> |
||||||
|
This is the format of the directory entries:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="DirectoryEntryStructure" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Structure of the Directory Entries"> |
||||||
|
<CAPTION> |
||||||
|
Structure of the Directory Entries |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="15%" ALIGN="Center" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Offset</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Size</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">Description</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>00h</TD><TD>8 bytes</TD><TD><A HREF="#FilenameAndExtension">Filename</A></TD></TR> |
||||||
|
<TR><TD>08h</TD><TD>3 bytes</TD><TD><A HREF="#FilenameAndExtension">Filename Extension</A></TD></TR> |
||||||
|
<TR><TD>0Bh</TD><TD>1 bytes</TD><TD><A HREF="#AttributeByte">Attribute Byte</A></TD></TR> |
||||||
|
<TR><TD>0Ch</TD><TD>1 bytes</TD><TD><A HREF="#ReservedForWindowsNT">Reserved</A> for Windows NT</TD></TR> |
||||||
|
<TR><TD>0Dh</TD><TD>1 bytes</TD><TD><A HREF="#CreationTimeMillisecond">Creation</A> - Millisecond stamp (actual 100th of a second)</TD></TR> |
||||||
|
<TR><TD>0Eh</TD><TD>2 bytes</TD><TD><A HREF="#CreationTimeDate">Creation Time</A></TD></TR> |
||||||
|
<TR><TD>10h</TD><TD>2 bytes</TD><TD><A HREF="#CreationTimeDate">Creation Date</A></TD></TR> |
||||||
|
<TR><TD>12h</TD><TD>2 bytes</TD><TD><A HREF="#LastAccessDate">Last Access Date</A></TD></TR> |
||||||
|
<TR><TD>14h</TD><TD>2 bytes</TD><TD><A HREF="#ReservedForFAT32">Reserved for FAT32</A></TD></TR> |
||||||
|
<TR><TD>16h</TD><TD>2 bytes</TD><TD><A HREF="#LastWriteTime">Last Write Time</A></TD></TR> |
||||||
|
<TR><TD>18h</TD><TD>2 bytes</TD><TD><A HREF="#LastWriteDate">Last Write Date</A></TD></TR> |
||||||
|
<TR><TD>1Ah</TD><TD>2 bytes</TD><TD><A HREF="#StatingCluster">Starting cluster</A></TD></TR> |
||||||
|
<TR><TD>1Ch</TD><TD>4 bytes</TD><TD><A HREF="#FileSize">File size</A> in bytes</TD></TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="FilenameAndExtension"> |
||||||
|
<H4>Filename & Extension</H4> |
||||||
|
The filename is 8 byte long. Shorter names must be trailing padded with space bytes (ASCII: 20h). The extension is 3 byte long and shorter names also have to be trailing padded. The characters allowed in the filename and extension are basicly the uppercase letters of the english alphabet, plus the digits 0 to 9.<BR> |
||||||
|
<BR> |
||||||
|
The first byte in the filename is treated special. The following rules apply:<BR> |
||||||
|
<OL> |
||||||
|
<LI>A value of 00h is interpertated as 'stop the search, there is no more entries in this directory'.</LI> |
||||||
|
<LI>A value of 05h is should be replaced with the ASCII character E5h. The character is used in Japan.</LI> |
||||||
|
<LI>Must not contain the value 20h.</LI> |
||||||
|
<LI>A value of E5h is interpertated as 'the entry is free'.</LI> |
||||||
|
<LI>Any of the values mentioned below are allowed.</LI> |
||||||
|
</OL> |
||||||
|
<BR> |
||||||
|
The following characters are not allowed in the filename or its extension:<BR> |
||||||
|
<OL> |
||||||
|
<LI>Any character below 20h, except the 05h character.</LI> |
||||||
|
<LI>Any character in the following list: 22h ("), 2Ah (*), 2Bh (+), 2Ch (,), 2Eh (.), 2Fh (/), 3Ah (:), 3Bh (;), 3Ch (<), 3Dh (=), 3Eh (>), 3Fh (?), 5Bh ([), 5Ch (\), 5Dh (]), 7Ch (|).</LI> |
||||||
|
</OL> |
||||||
|
<BR> |
||||||
|
For compatibility reasons it is recommended to limit the characters to:<BR> |
||||||
|
<OL> |
||||||
|
<LI>Any uppercase characters from A to Z.</LI> |
||||||
|
<LI>Any digit from 0 to 1.</LI> |
||||||
|
<LI>Any of the following characters: #, $, %, &, ', (, ), -, @</LI> |
||||||
|
</OL> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="AttributeByte"> |
||||||
|
<H4>Attribute Byte</H4> |
||||||
|
The attribute byte defines a set of flags which can be set for directories, volume name, hidden files, system files, etc. These are the flags:<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="Flags" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="60%" SUMMARY="Flags in the Attribute byte"> |
||||||
|
<CAPTION> |
||||||
|
Flags in the Attribute byte |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="8" WIDTH="3%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable" COLSPAN="2">Reserved</TD> |
||||||
|
<TD CLASS="BitTable">A</TD> |
||||||
|
<TD CLASS="BitTable">D</TD> |
||||||
|
<TD CLASS="BitTable">V</TD> |
||||||
|
<TD CLASS="BitTable">S</TD> |
||||||
|
<TD CLASS="BitTable">H</TD> |
||||||
|
<TD CLASS="BitTable">R</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ReadOnly"> |
||||||
|
<H5>Read Only</H5> |
||||||
|
This flag is used to prevent programs from not automatically overwriting or deleting this entry.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Hidden"> |
||||||
|
<H6>Hidden</H6> |
||||||
|
This flag indicates to the system that the file should be hidden when doing normal directory listings. But in a lot of programs this can be overwritten by the user.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="System"> |
||||||
|
<H5>System</H5> |
||||||
|
This flag indicates that the file/directory is important for the system, and shouldn't be manipulated without any concern.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="VolumeName"> |
||||||
|
<H5>Volume Name</H5> |
||||||
|
When this flag is set, the directory entry is not pointing to a file, but to nothing. Thus the the Starting cluster must point the cluster 0. The only information used from this entry is the filename (8 bytes) plus the filename extension (3 bytes). These bytes form an 11 byte long volume label (without any .) There may be only <B>one</B> valid entry in the entire volume with this flag set. This entry must be in the root directory and preferably among the first entries, if not, then MS-DOS can have trouble displaying the right volume label if there are long file names present. This volume name should be the same as the one in the boot sector.<BR> |
||||||
|
<BR> |
||||||
|
|
||||||
|
<DIV ID="Directory"> |
||||||
|
<H5>Directory</H5> |
||||||
|
This flag is set, when an entry in the directory table is not pointing to the beginning of a file, but to another directory table. A sub-directory. The sub-directory is placed in the cluster, which the Starting Cluster field points to. The format of this sub-directory table is identical to the root directory table.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="Achieve"> |
||||||
|
<H5>Achieve Flag</H5> |
||||||
|
This flag is used by backup utilities. The flag is set when ever a file is created, renamed or changed. Backup utilities can then use this flag to determine which files that has been modified since the last backup.<BR> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ReservedForWindowsNT"> |
||||||
|
<H4>Reserved for Windows NT</H4> |
||||||
|
This byte is used by Windows NT. It set the value to 0 when the file is created and then never look at it again. For what purpose it uses it is unknown.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="CreationTimeMillisecond"> |
||||||
|
<H4>Creation Time - Millisecond</H4> |
||||||
|
Due to size limitations this field (1 byte) only contains the millisecond stamp in counts of 10 milliseconds. Therefore valid values are between 0 and 199 inclusive.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="CreationTimeDate"> |
||||||
|
<H4>Creation Time & Date</H4> |
||||||
|
The 16 bit time field contain the time of day when this entry was created. The 16 bit date field contain the date when the entry was created. These two values never change. Both the <A HREF="#TimeFormat">time</A> field and the <A HREF="#DateFormat">date</A> field are in a special format.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="LastAccessDate"> |
||||||
|
<H4>Last Access Date</H4> |
||||||
|
This 16 bit field contain the date when the entry was last read or written to. In case of writes this field of cause contain the same value as the <A HREF="#LastWriteDate">Last Write Date</A> field. The <A HREF="#DateFormat">date</A> field is the same special format as the other dates.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="ReservedForFAT32"> |
||||||
|
<H4>Reserved for FAT32</H4> |
||||||
|
This word is reserved for the FAT32 File System. When used in that file system it will contain the high word of the starting cluster. In the FAT16 File System this word should be set to 0.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="LastWriteTime"> |
||||||
|
<H4>Last Write Time</H4> |
||||||
|
This 16 bit field is set to the time when the last write occured. When the entry is create this field and the <A HREF="#CreationTimeDate">Creation Time</A> field should contain the same values. In case the entry is a directory entry this field should change when the contents of the sub-directory changes.<BR> |
||||||
|
<BR> |
||||||
|
The field is in the special format described below:<BR> |
||||||
|
<DIV ID="TimeFormat" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Time Format"> |
||||||
|
<CAPTION> |
||||||
|
Time Format |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="32" WIDTH="6%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">15</TH> |
||||||
|
<TH CLASS="BitTable">14</TH> |
||||||
|
<TH CLASS="BitTable">13</TH> |
||||||
|
<TH CLASS="BitTable">12</TH> |
||||||
|
<TH CLASS="BitTable">11</TH> |
||||||
|
<TH CLASS="BitTable">10</TH> |
||||||
|
<TH CLASS="BitTable">9</TH> |
||||||
|
<TH CLASS="BitTable">8</TH> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable" COLSPAN="5">Hours (0-23)</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="6">Minutes (0-59)</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="5">Seconds (0-29)</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD ALIGN="Left" CLASS="NoColor" COLSPAN="16"><SPAN CLASS="Note">Seconds are counted with 2 seconds interval, so a value of 29 in this field gives 58 seconds.</SPAN></TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="LastWriteDate"> |
||||||
|
<H4>Last Write Date</H4> |
||||||
|
This 16 bit field is set to the date when the last write occured. When the entry is create this field and the <A HREF="#CreationTimeDate">Creation Date</A> field should contain the same values. In case the entry is a directory entry this field should change when the contents of the sub-directory changes.<BR> |
||||||
|
<BR> |
||||||
|
The field is in the special format described below:<BR> |
||||||
|
<DIV ID="DateFormat" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="Date Format"> |
||||||
|
<CAPTION> |
||||||
|
Date Format |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP SPAN="32" WIDTH="6%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="4%" ALIGN="Center" VALIGN="Middle"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH CLASS="BitTable">15</TH> |
||||||
|
<TH CLASS="BitTable">14</TH> |
||||||
|
<TH CLASS="BitTable">13</TH> |
||||||
|
<TH CLASS="BitTable">12</TH> |
||||||
|
<TH CLASS="BitTable">11</TH> |
||||||
|
<TH CLASS="BitTable">10</TH> |
||||||
|
<TH CLASS="BitTable">9</TH> |
||||||
|
<TH CLASS="BitTable">8</TH> |
||||||
|
<TH CLASS="BitTable">7</TH> |
||||||
|
<TH CLASS="BitTable">6</TH> |
||||||
|
<TH CLASS="BitTable">5</TH> |
||||||
|
<TH CLASS="BitTable">4</TH> |
||||||
|
<TH CLASS="BitTable">3</TH> |
||||||
|
<TH CLASS="BitTable">2</TH> |
||||||
|
<TH CLASS="BitTable">1</TH> |
||||||
|
<TH CLASS="BitTable">0</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD CLASS="BitTable" COLSPAN="7">Years from 1980 (0-127 -> 1980-2107)</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="4">Month of year (1-12)</TD> |
||||||
|
<TD CLASS="BitTable" COLSPAN="5">Day of month (1-31)</TD> |
||||||
|
<TH CLASS="BitTable">0000h</TH> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD ALIGN="Left" CLASS="NoColor" COLSPAN="16"></TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="FirstCluster"> |
||||||
|
<H4>First Cluster</H4> |
||||||
|
This 16-bit field points to the starting cluster number of entrys data. If the entry is a directory this entry point to the cluster which contain the beginning of the sub-directory. If the entry is a file then this entry point to the cluster holding the first chunk of data from the file.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<DIV ID="FileSize"> |
||||||
|
<H4>File Size</H4> |
||||||
|
This 32-bit field count the total file size in bytes. For this reason the file system driver must not allow more than 4 Gb to be allocated to a file. For other entries than files then file size field should be set to 0.<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="CalculationAlgorithms"> |
||||||
|
<H2>Calculation Algorithms</H2> |
||||||
|
How to calculate the starting location of each region. The VolumeStart variable contain a <ABBR TITLE="Logical Block Addressing">LBA address</ABBR> of the first sector in the volume. On drives which are not partitioned the VolumeStart value is 0. On drives which are partitioned the VolumeStart variable contain the sector number at which the partition start.<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="RegionCalculations" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="How to calculate regions and their sizes"> |
||||||
|
<CAPTION> |
||||||
|
How to calculate regions and their size (in sectors) |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="30%" ALIGN="Right" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">What to calculate</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">How to calculate it</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>ReservedRegion start =</TD><TD>VolumeStart</TD></TR> |
||||||
|
<TR><TD>FATRegion start =</TD><TD><SPAN CLASS="PreviousCalculated">ReservedRegion</SPAN> + <A HREF="#ReservedSectors">ReservedSectors</A></TD></TR> |
||||||
|
<TR><TD>RootDirectoryRegion start =</TD><TD><SPAN CLASS="PreviousCalculated">FATRegion</SPAN> + (<A HREF="#NumberOfFATs">NumberOfFATs</A> * <A HREF="#SectorsPerFAT">SectorsPerFAT</A>)</TD></TR> |
||||||
|
<TR><TD>DataRegion start =</TD><TD><SPAN CLASS="PreviousCalculated">RootDirectoryRegion</SPAN> + ((<A HREF="#RootEntriesCount">RootEntiesCount</A> * 32) / <A HREF="#BytesPerSector">BytesPerSector</A>)</TD></TR> |
||||||
|
<TR><TD>ReservedRegion size =</TD><TD><A HREF="#ReservedSectors">ReservedSectors</A></TD></TR> |
||||||
|
<TR><TD>FATRegion size =</TD><TD><A HREF="#NumberOfFATs">NumberOfFATs</A> * <A HREF="#SectorsPerFAT">SectorsPerFAT</A></TD></TR> |
||||||
|
<TR><TD>RootDirectoryRegion size =</TD><TD>(<A HREF="#RootEntriesCount">RootEntiesCount</A> * 32) / <A HREF="#BytesPerSector">BytesPerSector</A> (Remember to round up, if there is a remainder)</TD></TR> |
||||||
|
<TR><TD>DataRegion size =</TD><TD><A HREF="#LargeNumberOfSectors">TotalNumberOfSectors</A> - (<SPAN CLASS="PreviousCalculated">ReservedRegion_Size</SPAN> + <SPAN CLASS="PreviousCalculated">FATRegion_Size</SPAN> + <SPAN CLASS="PreviousCalculated">RootDirectoryRegion_Size</SPAN>)</TD></TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD ALIGN="Center" CLASS="NoColor" COLSPAN="2"> |
||||||
|
Previous calculated values which are used again, are marked with <SPAN CLASS="PreviousCalculated">this color</SPAN>. |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="FATRelatedValues" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="How to calculate FAT related values"> |
||||||
|
<CAPTION> |
||||||
|
How to calculate FAT related values |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="30%" ALIGN="Right" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">What to calculate</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">How to calculate it</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>Location of n'th FAT copy</TD><TD><SPAN CLASS="PreviousCalculated">ReservedRegion</SPAN> + (N * <A HREF="#ReservedSectors">SectorsPerFAT</A>)</TD></TR> |
||||||
|
<TR><TD>Number of FAT entries</TD><TD><SPAN CLASS="PreviousCalculated">DataRegion_Size</SPAN> / <A HREF="#SectorsPerCluster">SectorsPerCluster</A> (Remember to round down if there is a remainder)</TD></TR> |
||||||
|
<TR><TD>Which FAT sector contain the Nth cluster entry I need ?</TD><TD><SPAN CLASS="PreviousCalculated">Location of FAT copy</SPAN> + (( N * 2) / <A HREF="#BytesPerSector">BytesPerSector</A>)</TD></TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD ALIGN="Center" CLASS="NoColor" COLSPAN="2"> |
||||||
|
Previous calculated values which are used again, are marked with <SPAN CLASS="PreviousCalculated">this color</SPAN>. |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
<DIV ID="OtherValues" CLASS="Centered"> |
||||||
|
<TABLE WIDTH="90%" SUMMARY="How to calculate other values"> |
||||||
|
<CAPTION> |
||||||
|
How to calculate other values |
||||||
|
</CAPTION> |
||||||
|
<COLGROUP> |
||||||
|
<COL WIDTH="30%" ALIGN="Right" VALIGN="Top"> |
||||||
|
<COL WIDTH="70%" ALIGN="Left" VALIGN="Top"> |
||||||
|
</COLGROUP> |
||||||
|
<THEAD> |
||||||
|
<TR> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">What to calculate</TH> |
||||||
|
<TH ALIGN="Center" VALIGN="Middle">How to calculate it</TH> |
||||||
|
</TR> |
||||||
|
</THEAD> |
||||||
|
<TBODY> |
||||||
|
<TR><TD>First sector of cluster N =</TD><TD><SPAN CLASS="PreviousCalculated">DataRegion</SPAN> + ((N - 2) * <A HREF="#SectorsPerCluster">SectorsPerCluster</A>)</TD></TR> |
||||||
|
</TBODY> |
||||||
|
<TBODY> |
||||||
|
<TR> |
||||||
|
<TD ALIGN="Center" CLASS="NoColor" COLSPAN="2"> |
||||||
|
Previous calculated values which are used again, are marked with <SPAN CLASS="PreviousCalculated">this color</SPAN>. |
||||||
|
</TD> |
||||||
|
</TR> |
||||||
|
</TBODY> |
||||||
|
</TABLE> |
||||||
|
</DIV> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="SpecialNotes"> |
||||||
|
<H2>Special Notes</H2> |
||||||
|
When creating a FAT16 volume special care should be taken to ensure best compatibility. Following these rules ensure the best compatibility:<BR> |
||||||
|
<UL> |
||||||
|
<LI>A FAT16 partition may not have less than 4085 clusters or more than 65524 clusters.</LI> |
||||||
|
</UL> |
||||||
|
<BR> |
||||||
|
<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
<DIV ID="Conclusion"> |
||||||
|
<H2>Conclusion</H2> |
||||||
|
The FAT family of file systems are relative simple file systems. The complexity can be enhanced by adding support for long file names, using the <A HREF="VFAT_LongFileNames.html">VFAT Long File Names</A>. Also have a look at the <A HREF="FAT32_FileSystem.html">32 bit version</A> of the FAT file system.<BR> |
||||||
|
</DIV> |
||||||
|
|
||||||
|
|
||||||
|
</BODY> |
||||||
|
|
||||||
|
</HTML> |
@ -0,0 +1,323 @@ |
|||||||
|
/* External Style Sheet |
||||||
|
for the |
||||||
|
Maverick Operating System website |
||||||
|
|
||||||
|
Cascading Style Sheet Level 2 |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Body general styles */ |
||||||
|
BODY { |
||||||
|
background-color: #FFFFFF; |
||||||
|
color: #202020; |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: 8pt; |
||||||
|
font-weight: normal; |
||||||
|
letter-spacing: normal; /* normal, or a lenght in em units */ |
||||||
|
margin: 0.5em; /* sets all the margins */ |
||||||
|
text-align: left; /* left, right, center, justify */ |
||||||
|
text-decoration: none; /* none, underline, overline, line-through, blink */ |
||||||
|
text-indent: 0; /* either a legnht in em units or a percentage */ |
||||||
|
text-transform: none; /* capitalize, uppercase, lowercase, none, inherit */ |
||||||
|
white-space: normal; /* normal, pre, nowrap */ |
||||||
|
word-spacing: normal; /* normal, or a lenght in em units */ |
||||||
|
} |
||||||
|
|
||||||
|
BODY.Menu { |
||||||
|
background-color: #F0F0FF; |
||||||
|
color: #000000; |
||||||
|
} |
||||||
|
|
||||||
|
BODY.Title { |
||||||
|
background-color: #F0F0FF; |
||||||
|
color: #000000; |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* General styles */ |
||||||
|
.Calculation { |
||||||
|
color: #000080; |
||||||
|
} |
||||||
|
|
||||||
|
.Centered { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.Code { |
||||||
|
background-color: #E0E0E0; |
||||||
|
border-color: #000000; |
||||||
|
border-style: solid; |
||||||
|
border-width: 1px; |
||||||
|
font-family: monospace; |
||||||
|
font-size: 7pt; |
||||||
|
font-weight: normal; |
||||||
|
margin-left: 2em; |
||||||
|
margin-right: 2em; |
||||||
|
padding: 10px; |
||||||
|
text-align: left; |
||||||
|
white-space: pre; |
||||||
|
} |
||||||
|
|
||||||
|
.Copyright { |
||||||
|
font-size: 6pt; |
||||||
|
margin: 1em; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.Date { |
||||||
|
font-size: 10pt; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.DefinitionTerm { |
||||||
|
background-color: #C0FFC0; |
||||||
|
font-weight: bolder; |
||||||
|
} |
||||||
|
|
||||||
|
.DefinitionData { |
||||||
|
background-color: #F0F0FF; |
||||||
|
} |
||||||
|
|
||||||
|
.Important { |
||||||
|
color: #FF0000; |
||||||
|
font-weight: bold; |
||||||
|
font-size: 110%; |
||||||
|
} |
||||||
|
|
||||||
|
.MiniMenu { |
||||||
|
font-size: 6pt; |
||||||
|
text-align: right; |
||||||
|
} |
||||||
|
|
||||||
|
.Note { |
||||||
|
color: #FF0000; |
||||||
|
} |
||||||
|
|
||||||
|
.Note:before { |
||||||
|
content: "Note: "; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.PreviousCalculated { |
||||||
|
color: #8000FF; |
||||||
|
} |
||||||
|
|
||||||
|
.Recomendation { |
||||||
|
color: #FF0000; |
||||||
|
} |
||||||
|
|
||||||
|
.Reserved { |
||||||
|
color: #FF0000; |
||||||
|
} |
||||||
|
|
||||||
|
.Revision { |
||||||
|
font-size: 7pt; |
||||||
|
text-align: right; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Anchor (link) styles */ |
||||||
|
A { |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
A:link { |
||||||
|
color: #0000FF; |
||||||
|
} |
||||||
|
|
||||||
|
A:visited { |
||||||
|
color: #0000FF; |
||||||
|
} |
||||||
|
|
||||||
|
A:hover { |
||||||
|
color: #FF0000; |
||||||
|
} |
||||||
|
|
||||||
|
A:active { |
||||||
|
color: #FF0000; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Styles for headlines in 6 different levels */ |
||||||
|
H1 { |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: 24pt; |
||||||
|
font-weight: bold; |
||||||
|
margin: 0em; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
H1.Menu { |
||||||
|
font-size: 10pt; |
||||||
|
text-decoration: underline overline; |
||||||
|
text-transform: uppercase; |
||||||
|
} |
||||||
|
|
||||||
|
H1.PreTitle { |
||||||
|
color: #505050; |
||||||
|
font-size: 10pt; |
||||||
|
} |
||||||
|
|
||||||
|
H1.SubTitle { |
||||||
|
color: #505050; |
||||||
|
font-size: 10pt; |
||||||
|
} |
||||||
|
|
||||||
|
H2 { |
||||||
|
font-size: 14pt; |
||||||
|
margin: 0em; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
|
||||||
|
H2.Menu { |
||||||
|
font-size: 9pt; |
||||||
|
font-weight: normal; |
||||||
|
margin: 0em; |
||||||
|
text-align: left; |
||||||
|
text-decoration: underline; |
||||||
|
text-transform: lowercase; |
||||||
|
} |
||||||
|
|
||||||
|
H3 { |
||||||
|
font-size: 10pt; |
||||||
|
font-weight: bold; |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
H3.Menu { |
||||||
|
font-size: 9pt; |
||||||
|
font-weight: italic; |
||||||
|
margin: 0em; |
||||||
|
text-align: left; |
||||||
|
text-decoration: underline; |
||||||
|
text-transform: lowercase; |
||||||
|
} |
||||||
|
|
||||||
|
H4 { |
||||||
|
font-size: 9pt; |
||||||
|
font-weight: normal; |
||||||
|
margin: 0em; |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
|
|
||||||
|
H5 { |
||||||
|
font-size: 9pt; |
||||||
|
font-style: italic; |
||||||
|
font-weight: normal; |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
H6 { |
||||||
|
font-size: 9pt; |
||||||
|
font-style: oblique; |
||||||
|
font-weight: normal; |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Styles for other elements */ |
||||||
|
HR { |
||||||
|
color: #505050; |
||||||
|
text-align: right; |
||||||
|
height: 1px; |
||||||
|
} |
||||||
|
|
||||||
|
P { |
||||||
|
margin: 0px; |
||||||
|
margin-top: 0.1em; |
||||||
|
margin-bottom: 0.9em; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Styles for tables */ |
||||||
|
TABLE, TR, TD, TH, CAPTION { |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: 8pt; |
||||||
|
} |
||||||
|
|
||||||
|
TD { |
||||||
|
background-color: #F0F0FF; |
||||||
|
} |
||||||
|
|
||||||
|
TH { |
||||||
|
background-color: #C0C0FF; |
||||||
|
} |
||||||
|
|
||||||
|
TD.BitTable { |
||||||
|
font-size: 7pt; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
TH.BitTable { |
||||||
|
font-size: 7pt; |
||||||
|
font-weight: normal; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
TD.Code { |
||||||
|
background-color: #E0E0E0; |
||||||
|
border-color: #000000; |
||||||
|
border-style: solid; |
||||||
|
border-width: 1px; |
||||||
|
font-size: 6pt; |
||||||
|
font-weight: normal; |
||||||
|
margin-left: 1em; |
||||||
|
margin-right: 1em; |
||||||
|
padding: 1px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
TD.NoColor { |
||||||
|
background-color: transparent; |
||||||
|
background-color: #FFFFFF; /* This line is for Netscape */ |
||||||
|
} |
||||||
|
|
||||||
|
TH.NoColor { |
||||||
|
background-color: transparent; |
||||||
|
background-color: #FFFFFF; /* This line is for Netscape */ |
||||||
|
} |
||||||
|
|
||||||
|
CAPTION { |
||||||
|
font-size: 9pt; |
||||||
|
font-weight: normal; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Styles for unordered, ordered and definition lists */ |
||||||
|
DL { |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
DD { |
||||||
|
margin: 0em; |
||||||
|
} |
||||||
|
|
||||||
|
DT { |
||||||
|
font-family: sans-serif; |
||||||
|
font-size: 10pt; |
||||||
|
font-weight: bold; |
||||||
|
margin-left: 0.2em; |
||||||
|
margin-top: 1.5em; |
||||||
|
} |
||||||
|
|
||||||
|
UL { |
||||||
|
margin: 0em; |
||||||
|
margin-left: 2em; |
||||||
|
} |
||||||
|
|
||||||
|
OL { |
||||||
|
margin: 0em; |
||||||
|
margin-left: 2em; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* end of file */ |
@ -0,0 +1,944 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
|
||||||
|
<!-- http://www.tavi.co.uk/phobos/fat.html --> |
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||||
|
|
||||||
|
<head> |
||||||
|
<link rel="stylesheet" type="text/css" href="phobos.css" /> |
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" /> |
||||||
|
<meta name="keywords" content="PHOBOS, FAT, file system" /> |
||||||
|
<title>A tutorial on the FAT file system</title> |
||||||
|
</head> |
||||||
|
|
||||||
|
<!-- T I T L E ============================================================ --> |
||||||
|
|
||||||
|
<body> |
||||||
|
|
||||||
|
<table class="titlebox"> |
||||||
|
<tr> |
||||||
|
<td class="smalltitle" align="center">Phobos</td> |
||||||
|
<td class="subtitle">A tutorial on the FAT file system</td> |
||||||
|
<td align="right" class="smalltitle"></td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
|
||||||
|
<!-- B O D Y ============================================================== --> |
||||||
|
<hr /> |
||||||
|
<!-- M a i n ============================================================== --> |
||||||
|
|
||||||
|
<h2>Introduction</h2> |
||||||
|
<p> |
||||||
|
This page is intended to provide an introduction to the original File |
||||||
|
Allocation Table (FAT) file system. This file system was used on all |
||||||
|
versions of MS-DOS and PC-DOS, and on early versions of Windows; it is |
||||||
|
still used on floppy disks formatted by Windows and some other systems. |
||||||
|
Modified versions are also still supported by Windows on hard disks, if |
||||||
|
required. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
The FAT file system is heavily based on the <em>file map</em> model in |
||||||
|
terms of its on-disk layout; that model was around for many years before |
||||||
|
Microsoft inherited the initial FAT file system from the original |
||||||
|
writers of DOS (Seattle Computer Products). It is a reasonably simple, |
||||||
|
reasonably robust file system. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
There are three basic variants of the FAT file system, which differ |
||||||
|
mainly in the construction of the actual file allocation table. Floppy |
||||||
|
disks and small hard disks usually use the <em>12-bit</em> version, |
||||||
|
which was superseded by the <em>16-bit</em> version as hard disks became |
||||||
|
bigger. This in turn was superseded by the <em>32-bit</em> version as |
||||||
|
disks became bigger still. We shall concentrate on the 16-bit version, |
||||||
|
since the 12-bit version can be tricky for beginners, and the 32-bit |
||||||
|
version is more complex than needed for this tutorial. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Overview</h3> |
||||||
|
<p> |
||||||
|
Any disk is made up of <em>surfaces</em> (one for each head), |
||||||
|
<em>tracks</em> and <em>sectors</em>. However, for simplicity, we can |
||||||
|
consider a disk as a simple storage area made up just of a number of |
||||||
|
sectors. Further, these sectors are considered to be numbered |
||||||
|
consecutively, the first being numbered 0, the second numbered 1, etc.; |
||||||
|
we will not worry about the physical location of any sector on the |
||||||
|
actual disk. Because we want to emphasise that the location of a sector is |
||||||
|
irrelevant to the actual disk structure, and because sectors have their |
||||||
|
own numbers within each track, we shall call these sectors |
||||||
|
<em>blocks</em> from now on; as previously stated, they form a linear, |
||||||
|
densely numbered list. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
All blocks are the same size, 512 bytes, on practically all FAT file |
||||||
|
systems. Howewer, large disks can have too many blocks for comfort, so |
||||||
|
blocks are sometimes grouped together in pairs (or fours, or eights, |
||||||
|
etc...); each such grouping is called an <em>allocation unit</em>. The |
||||||
|
FAT file system actually works in allocation units, not blocks, but for |
||||||
|
simplicity we shall assume in the description below that each allocation |
||||||
|
unit contains exactly one block, which means that we can use the terms |
||||||
|
interchangeably. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>A note on numerical values</h3> |
||||||
|
<p> |
||||||
|
Hexadecimal numbers are indicated using the convention commonly used in |
||||||
|
C; that is, a leading <samp>0x</samp>. The decimal number |
||||||
|
<samp>17</samp> would thus be written as <samp>0x11</samp> in |
||||||
|
hexadecimal notation here. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Values in the FAT file system are either stored in <em>bytes</em> (8 bit |
||||||
|
values, 0-255 unsigned) or in <em>words</em> (pairs of bytes, 16 bit |
||||||
|
values, 0-65535 unsigned). Note that the first byte of a pair is the |
||||||
|
least significant byte, and the second byte of a pair is the most |
||||||
|
significant byte. For example, if the byte at position 3 has a value of |
||||||
|
0x15, and the byte at position 4 has a value of 0x74, they together make |
||||||
|
up a word with value 0x7415 (not 0x1574). |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
There are occasional 32-bit values (<em>doublewords</em>), and these use |
||||||
|
a similar approach (in this case 4 bytes, with least significant byte |
||||||
|
stored first). |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Lastly, note that individual bits within a byte or word are numbered |
||||||
|
from the least significant end (right hand end), starting with bit 0. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h2>The disk format</h2> |
||||||
|
<p> |
||||||
|
This section describes the <em>on-disk structure</em> of a FAT file |
||||||
|
system; that is, how the various areas of the disk are laid out, and |
||||||
|
what is stored in them. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Basic layout</h3> |
||||||
|
<p> |
||||||
|
All disks using the FAT file system are divided into several areas. The |
||||||
|
following table summarises the areas in the order that they appear on |
||||||
|
the disk, starting at block 0: |
||||||
|
</p> |
||||||
|
<table class="spec" width="70%" cellpadding="3"> |
||||||
|
<tr> |
||||||
|
<th class="spec">Area description</th> |
||||||
|
<th class="spec">Area size</th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec"><a href="#boot_block">Boot block</a></td> |
||||||
|
<td class="spec">1 block</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec"><a href="#file_allocation_table">File Allocation |
||||||
|
Table</a> (may be multiple copies)</td> |
||||||
|
<td class="spec">Depends on file system size</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">Disk <a href="#root_directory">root directory</a></td> |
||||||
|
<td class="spec">Variable (selected when disk is formatted)</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">File data area</td> |
||||||
|
<td class="spec">The rest of the disk</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
|
||||||
|
<h3 id="boot_block">The boot block</h3> |
||||||
|
<p> |
||||||
|
The boot block occupies just the first block of the disk. It holds a |
||||||
|
special program (the <em>bootstrap program</em>) which is used for |
||||||
|
loading the operating system into memory. It would thus appear to be |
||||||
|
fairly irrelevant to this discussion. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
However, in the FAT file system it also contains several important data |
||||||
|
areas which help to describe the rest of the file system. Thus, to |
||||||
|
understand how a particular disk is laid out, it is necessary first to |
||||||
|
understand at least part of the contents of the boot block. The relevant |
||||||
|
areas are shown in the following table, together with their byte offsets |
||||||
|
from the start of the boot block. We will see, later, which of these are |
||||||
|
actually important to us. |
||||||
|
</p> |
||||||
|
<table class="spec" width="70%" cellpadding="3"> |
||||||
|
<tr> |
||||||
|
<th class="spec">Offset from start</th> |
||||||
|
<th class="spec">Length</th> |
||||||
|
<th class="spec">Description</th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x00</td> |
||||||
|
<td class="spec">3 bytes</td> |
||||||
|
<td class="spec">Part of the bootstrap program.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x03</td> |
||||||
|
<td class="spec">8 bytes</td> |
||||||
|
<td class="spec">Optional manufacturer description.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x0b</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Number of bytes per block (almost always 512).</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x0d</td> |
||||||
|
<td class="spec">1 byte</td> |
||||||
|
<td class="spec">Number of blocks per allocation unit.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x0e</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Number of reserved blocks. This is the number of blocks on the disk |
||||||
|
that are not actually part of the file system; in most cases this is |
||||||
|
exactly 1, being the allowance for the boot block.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x10</td> |
||||||
|
<td class="spec">1 byte</td> |
||||||
|
<td class="spec">Number of <a href="#file_allocation_table">File Allocation |
||||||
|
Tables.</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x11</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Number of <a href="#root_directory">root directory</a> entries |
||||||
|
(including unused ones).</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td id="offset_0x13">0x13</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Total number of blocks in the entire disk. If the disk size is |
||||||
|
larger than 65535 blocks (and thus will not fit in these two bytes), |
||||||
|
this value is set to zero, and the true size is stored at |
||||||
|
<a href="#offset_0x20">offset 0x20</a>.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x15</td> |
||||||
|
<td class="spec">1 byte</td> |
||||||
|
<td class="spec"><a href="#media_descriptor">Media Descriptor</a>. This |
||||||
|
is rarely used, but still exists. |
||||||
|
.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x16</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">The number of blocks occupied by one copy of the |
||||||
|
<a href="#file_allocation_table">File Allocation Table</a>.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x18</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">The number of blocks per track. This information is present |
||||||
|
primarily for the use of the bootstrap program, and need not concern us |
||||||
|
further here.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x1a</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">The number of heads (disk surfaces). This information is present |
||||||
|
primarily for the use of the bootstrap program, and need not concern us |
||||||
|
further here.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x1c</td> |
||||||
|
<td class="spec">4 bytes</td> |
||||||
|
<td class="spec">The number of <em>hidden blocks</em>. The use of this is largely |
||||||
|
historical, and it is nearly always set to 0; thus it can be |
||||||
|
ignored.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td id="offset_0x20">0x20</td> |
||||||
|
<td class="spec">4 bytes</td> |
||||||
|
<td class="spec">Total number of blocks in the entire disk (see also |
||||||
|
<a href="#offset_0x13">offset 0x13</a>).</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x24</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Physical drive number. This information is present primarily for the |
||||||
|
use of the bootstrap program, and need not concern us further here.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x26</td> |
||||||
|
<td class="spec">1 byte</td> |
||||||
|
<td class="spec">Extended Boot Record Signature This information is present |
||||||
|
primarily for the use of the bootstrap program, and need not concern us |
||||||
|
further here.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x27</td> |
||||||
|
<td class="spec">4 bytes</td> |
||||||
|
<td class="spec">Volume Serial Number. Unique number used for identification of a |
||||||
|
particular disk.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x2b</td> |
||||||
|
<td class="spec">11 bytes</td> |
||||||
|
<td class="spec">Volume Label. This is a string of characters for human-readable |
||||||
|
identification of the disk (padded with spaces if shorter); it is |
||||||
|
selected when the disk is formatted.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x36</td> |
||||||
|
<td class="spec">8 bytes</td> |
||||||
|
<td class="spec">File system identifier (padded at the end with spaces if |
||||||
|
shorter).</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x3e</td> |
||||||
|
<td class="spec">0x1c0 bytes</td> |
||||||
|
<td class="spec">The remainder of the bootstrap program.</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x1fe</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec">Boot block 'signature' (0x55 followed by 0xaa).</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
|
||||||
|
<h4 id="media_descriptor">The Media Descriptor</h4> |
||||||
|
<p> |
||||||
|
Historically, the size and type of disk were difficult for the operating |
||||||
|
system to determine by hardware interrogation alone. A 'magic byte' was |
||||||
|
thus used to classify disks. This are still present, but rarely used, |
||||||
|
and its contents are known as the Media Descriptor. Generally, for hard |
||||||
|
disks, this is set to 0xf0. |
||||||
|
</p> |
||||||
|
<h3 id="file_allocation_table">The File Allocation Table (FAT)</h3> |
||||||
|
<p> |
||||||
|
The FAT occupies one or more blocks immediately following the boot |
||||||
|
block. Commonly, part of its last block will remain unused, since it is |
||||||
|
unlikely that the required number of entries will exactly fill a |
||||||
|
complete number of blocks. If there is a second FAT, this immediately |
||||||
|
follows the first (but starting in a new block). This is repeated for |
||||||
|
any further FATs. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Note that multiple FATs are used particularly on floppy disks, because |
||||||
|
of the higher likelihood of errors when reading the disk. If the FAT is |
||||||
|
unreadable, files cannot be accessed and another copy of the FAT must be |
||||||
|
used. On hard disks, there is often only one FAT. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
In the case of the 16-bit FAT file system, each entry in the FAT is two bytes in length |
||||||
|
(i.e. 16 bits). The disk data area is divided into <em>clusters</em>, which are the same thing |
||||||
|
as allocation units, but numbered differently (instead of being numbered from the start |
||||||
|
of the disk, they are numbered from the start of the disk data area). So, the cluster number |
||||||
|
is the allocation unit number, minus a constant value which is the size of the areas in between |
||||||
|
the start of the disk and the start of the data area. |
||||||
|
</p> |
||||||
|
<p class="warning"> |
||||||
|
Well, almost. The clusters are numbered starting at 2, not 0! So the |
||||||
|
above calculation has to have 2 added to it to get the cluster number of |
||||||
|
a given allocation unit...and a cluster number is converted to an |
||||||
|
allocation unit number by subtracting 2...! |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
So, how does the FAT work? Simply, there is one entry in the FAT for |
||||||
|
every cluster (data area block) on the disk. Entry N relates to cluster |
||||||
|
N. Clusters 0 and 1 don't exist (because of the 'fiddle by 2' above), |
||||||
|
and those FAT entries are special. The first byte of the first entry is |
||||||
|
a copy of the <a href="#media_descriptor">media descriptor</a> byte, and |
||||||
|
the second byte is set to 0xff. Both bytes in the second entry are set to |
||||||
|
0xff. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
What does a normal FAT entry for a cluster contain? It contains the |
||||||
|
<em>successor cluster number</em> - that is, the number of the cluster |
||||||
|
that follows this one in the file to which the current cluster belongs. |
||||||
|
The last cluster of a file has the value 0xffff in its FAT entry to |
||||||
|
indicate that there are no more clusters. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3 id="root_directory">The Root Directory</h3> |
||||||
|
<p> |
||||||
|
The root directory contains an entry for each file whose name appears at |
||||||
|
the <em>root</em> (the top level) of the file system. Other directories |
||||||
|
can appear within the root directory; they are called |
||||||
|
<em>subdirectories</em>. The main difference between the two is that |
||||||
|
space for the root directory is allocated statically, when the disk is |
||||||
|
formatted; there is thus a finite upper limit on the number of files |
||||||
|
that can appear in the root directory. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Subdirectories are just files with special data in them, so they can be |
||||||
|
as large or small as desired. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
The format of all directories is the same. Each entry is 32 bytes (0x20) |
||||||
|
in size, so a single block can contain 16 of them. The following table |
||||||
|
shows a summary of a single directory entry; note that the offset is |
||||||
|
merely from the start of that particular entry, not from the start of |
||||||
|
the block. |
||||||
|
</p> |
||||||
|
|
||||||
|
<table class="spec" width="50%" cellpadding="3"> |
||||||
|
<tr> |
||||||
|
<th class="spec">Offset</th> |
||||||
|
<th class="spec">Length</th> |
||||||
|
<th class="spec">Description</th> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x00</td> |
||||||
|
<td class="spec">8 bytes</td> |
||||||
|
<td class="spec"><a href="#filename">Filename</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x08</td> |
||||||
|
<td class="spec">3 bytes</td> |
||||||
|
<td class="spec"><a href="#filename_extension">Filename extension</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x0b</td> |
||||||
|
<td class="spec">1 byte</td> |
||||||
|
<td class="spec"><a href="#file_attributes">File attributes</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x0c</td> |
||||||
|
<td class="spec">10 bytes</td> |
||||||
|
<td class="spec">Reserved</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x16</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec"><a href="#file_time">Time created or last updated</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x18</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec"><a href="#file_date">Date created or last updated</a></td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x1a</td> |
||||||
|
<td class="spec">2 bytes</td> |
||||||
|
<td class="spec"><a href="#starting_cluster">Starting cluster number</a> for file</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td class="spec">0x1c</td> |
||||||
|
<td class="spec">4 bytes</td> |
||||||
|
<td class="spec"><a href="#file_size">File size in bytes</a></td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
|
||||||
|
<h4 id="filename">The Filename</h4> |
||||||
|
<p> |
||||||
|
The eight bytes from offset 0x00 to 0x07 represent the filename. The |
||||||
|
first byte of the filename indicates its status. Usually, it contains a |
||||||
|
normal filename character (e.g. 'A'), but there are some special values: |
||||||
|
</p> |
||||||
|
<dl> |
||||||
|
<dt>0x00</dt> |
||||||
|
<dd>Filename never used.</dd> |
||||||
|
<dt>0xe5</dt> |
||||||
|
<dd>The filename has been used, but the file has been deleted.</dd> |
||||||
|
<dt>0x05</dt> |
||||||
|
<dd>The first character of the filename is actually 0xe5.</dd> |
||||||
|
<dt>0x2e</dt> |
||||||
|
<dd>The entry is for a directory, not a normal file. If the second byte |
||||||
|
is also 0x2e, the cluster field contains the cluster number of this |
||||||
|
directory's parent directory. If the parent directory is the root |
||||||
|
directory (which is statically allocated and doesn't have a cluster |
||||||
|
number), cluster number 0x0000 is specified here.</dd> <dt>Any other |
||||||
|
character</dt> |
||||||
|
<dd>This is the first character of a real filename.</dd> |
||||||
|
</dl> |
||||||
|
<p> |
||||||
|
If a filename is fewer than eight characters in length, it is padded |
||||||
|
with space characters. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h4 id="filename_extension">The Filename Extension</h4> |
||||||
|
<p> |
||||||
|
The three bytes from offset 0x08 to 0x0a indicate the filename |
||||||
|
extension. There are no special characters. Note that the dot used to |
||||||
|
separate the filename and the filename extension is implied, and is not |
||||||
|
actually stored anywhere; it is just used when referring to the file. |
||||||
|
If the filename extension is fewer than three characters in length, it |
||||||
|
is padded with space characters. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h4 id="file_attributes">The File Attributes</h4> |
||||||
|
<p> |
||||||
|
The single byte at offset 0x0b contains flags that provide information |
||||||
|
about the file and its permissions, etc. The flags are single bits, and |
||||||
|
have meanings as follows. Each bit is given as its numerical value, and |
||||||
|
these are combined to give the actual attribute value: |
||||||
|
</p> |
||||||
|
<dl id="attribute_values"> |
||||||
|
<dt>0x01</dt> |
||||||
|
<dd>Indicates that the file is read only.</dd> |
||||||
|
<dt>0x02</dt> |
||||||
|
<dd>Indicates a hidden file. Such files can be displayed |
||||||
|
if it is really required.</dd> |
||||||
|
<dt>0x04</dt> |
||||||
|
<dd>Indicates a system file. These are hidden as well.</dd> |
||||||
|
<dt>0x08</dt> |
||||||
|
<dd>Indicates a special entry containing the disk's volume label, |
||||||
|
instead of describing a file. This kind of entry appears only in the |
||||||
|
root directory.</dd> |
||||||
|
<dt>0x10</dt> |
||||||
|
<dd>The entry describes a subdirectory.</dd> |
||||||
|
<dt>0x20</dt> |
||||||
|
<dd>This is the archive flag. This can be set and cleared by the |
||||||
|
programmer or user, but is always set when the file is modified. It is |
||||||
|
used by backup programs.</dd> |
||||||
|
<dt>0x40</dt> |
||||||
|
<dd>Not used; must be set to 0.</dd> |
||||||
|
<dt>0x80</dt> |
||||||
|
<dd>Not used; must be set to 0.</dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
<h4 id="file_time">The File Time</h4> |
||||||
|
<p> |
||||||
|
The two bytes at offsets 0x16 and 0x17 are treated as a 16 bit value; |
||||||
|
remember that the least significant byte is at offset 0x16. They contain |
||||||
|
the time when the file was created or last updated. The time is mapped |
||||||
|
in the bits as follows; the first line indicates the byte's offset, the |
||||||
|
second line indicates (in decimal) individual bit numbers in the 16 bit |
||||||
|
value, and the third line indicates what is stored in each bit. |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
<------- 0x17 --------> <------- 0x16 --------> |
||||||
|
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 |
||||||
|
h h h h h m m m m m m x x x x x |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
where: |
||||||
|
</p> |
||||||
|
<dl> |
||||||
|
<dt><samp>hhhhh</samp></dt> |
||||||
|
<dd>indicates the binary number of hours (0-23)</dd> |
||||||
|
<dt><samp>mmmmmm</samp></dt> |
||||||
|
<dd>indicates the binary number of minutes (0-59)</dd> |
||||||
|
<dt><samp>xxxxx</samp></dt> |
||||||
|
<dd>indicates the binary number of two-second periods (0-29), |
||||||
|
representing seconds 0 to 58.</dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
|
||||||
|
<h4 id="file_date">The File Date</h4> |
||||||
|
<p> |
||||||
|
The two bytes at offsets 0x18 and 0x19 are treated as a 16 bit value; |
||||||
|
remember that the least significant byte is at offset 0x18. They contain |
||||||
|
the date when the file was created or last updated. The date is mapped |
||||||
|
in the bits as follows; the first line indicates the byte's offset, the |
||||||
|
second line indicates (in decimal) individual bit numbers in the 16 bit |
||||||
|
value, and the third line indicates what is stored in each bit. |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
<------- 0x19 --------> <------- 0x18 --------> |
||||||
|
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 |
||||||
|
y y y y y y y m m m m d d d d d |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
where: |
||||||
|
</p> |
||||||
|
<dl> |
||||||
|
<dt><samp>yyyyyyy</samp></dt> |
||||||
|
<dd>indicates the binary year offset from 1980 (0-119), representing the |
||||||
|
years 1980 to 2099</dd> |
||||||
|
<dt><samp>mmmm</samp></dt> |
||||||
|
<dd>indicates the binary month number (1-12)</dd> |
||||||
|
<dt><samp>ddddd</samp></dt> |
||||||
|
<dd>indicates the binary day number (1-31)</dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
<h4 id="starting_cluster">The Starting Cluster Number</h4> |
||||||
|
<p> |
||||||
|
The two bytes at offsets 0x1a and 0x1b are treated as a 16 bit value; |
||||||
|
remember that the least significant byte is at offset 0x1a. The first |
||||||
|
cluster for data space on the disk is always numbered as 0x0002. This |
||||||
|
strange arrangement is because the first two entries in the FAT are |
||||||
|
reserved for other purposes. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h4 id="file_size">The File Size</h4> |
||||||
|
<p> |
||||||
|
The four bytes at offsets 0x1c to 0x1f are treated as a 32 bit value; |
||||||
|
remember that the least significant byte is at offset 0x1c. They hold |
||||||
|
the actual file size, in bytes. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h2>Worked examples</h2> |
||||||
|
<p> |
||||||
|
The best way to understand how to use the above information is to work |
||||||
|
though some simple examples. |
||||||
|
</p> |
||||||
|
<h3>Interpreting the contents of a block</h3> |
||||||
|
<p> |
||||||
|
We assume that there is a tool available to display the contents of a |
||||||
|
block in both hexadecimal and as ASCII characters. Most such tools will |
||||||
|
display unusual ASCII characters (e.g. carriage return) as a dot. For |
||||||
|
example, here is a display of a typical boot block: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/bootblk.jpg" alt="Boot block - example" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
As an illustration, one field in the boot block has been highlighted in |
||||||
|
red (the highlight appears twice, once for the hexadecimal |
||||||
|
representation and once for the ASCII representation). The numbers down |
||||||
|
the left hand side are the offsets (from the start of the block) of the |
||||||
|
first byte on that row, and the first row of digits along the top are |
||||||
|
the offset of each byte within the row. We can thus easily see that the |
||||||
|
highlighted area starts at offset 0x36. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
The area in question is (look back at the boot block layout) the file |
||||||
|
system type, in this case FAT16. To save us looking up each byte in a |
||||||
|
table of ASCII characters, we can simply consult the equivalent |
||||||
|
representation on the right hand side. 0x46 represents F, 0x41 |
||||||
|
represents A, and so on. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Example 1 - find the root directory</h3> |
||||||
|
<p> |
||||||
|
To find the root directory, we need to examine the file system data in |
||||||
|
the boot block. So, let's look again at the boot block of our example |
||||||
|
disk: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/bootblk1.jpg" alt="Boot block - find root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We know that the root directory appears immediately after the last copy |
||||||
|
of the FAT. So what we need to find out is the size of the FAT, and how |
||||||
|
many copies there are. We also need to know the size of anything else |
||||||
|
that appears before the FAT(s); there is just the single block of the |
||||||
|
boot block. So, the number of blocks that appear before the root |
||||||
|
directory is given by: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
(size of FAT)*(number of FATs) + 1 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
All we need to do, then, is discover these values. First, we know that |
||||||
|
the number of FATs is stored at offset 0x10 (highlighted in green |
||||||
|
above); this tells us that there is just one FAT. Next, we need to know |
||||||
|
the size of a FAT; this is at offsets 0x16 and 0x17, where we find 0x14 |
||||||
|
and 0x00 respectively (highlighted in red above). Remember that these |
||||||
|
two bytes together make up a 16 bit value, with the least significant |
||||||
|
byte stored first; in other words, the value is 0x0014 (in decimal, 20). |
||||||
|
So, the total number of blocks that precede the root directory is given |
||||||
|
by: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0x0014*1 + 1 => 0x0015 (decimal 21) |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
We should thus find the root directory in block 0x15, so let's look at |
||||||
|
it... |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/rootdir.jpg" alt="Root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
It seems to have something occupying the first 0x20 bytes, and it's...a |
||||||
|
directory entry! We won't go into detail here, but detailed examination |
||||||
|
of those bytes would show that it's the special entry for the disk |
||||||
|
label. There don't appear to be any more entries in this directory. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Example 2 - find the attributes of a file</h3> |
||||||
|
<p> |
||||||
|
In this example, the file FOOBAR.TXT has been created on the same disk, |
||||||
|
and it appears in the root directory. We wish to find out which |
||||||
|
attribute flags are set on the file. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
First, we need to find the root directory; we have already done this in |
||||||
|
example 1. Let's take a look at it after FOOBAR.TXT has been created: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/rootdir1.jpg" alt="Root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We can see fairly easily that the second directory entry (the one at |
||||||
|
offset 0x20) is that for FOOBAR.TXT. Remember that the dot between the |
||||||
|
filename and the filename extension is not actually stored, but is |
||||||
|
implied. We see the filename (highlighted in red) and the filename |
||||||
|
extension (highlighted in blue). We know that the attribute byte appears |
||||||
|
at offset 0x0b, and it is highlighted in green here. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
The value of the attribute byte is 0x21. We can express this in binary |
||||||
|
as: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 0 1 0 0 0 0 1 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
Taking each of the bits separately, and making a hexadecimal number out |
||||||
|
of them, we get: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 0 1 0 0 0 0 0 => 0x20 |
||||||
|
0 0 0 0 0 0 0 1 => 0x01 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
Our <a href="#attribute_values">table of attribute values</a> shows that |
||||||
|
0x20 means that the 'archive flag' is set, and 0x01 indicates that the |
||||||
|
file is read-only. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Example 3 - find the date of a file</h3> |
||||||
|
<p> |
||||||
|
Here, we want the date attached to a particular file (only one date is |
||||||
|
kept, which is the date of creation or last modification). The file in |
||||||
|
question is FOOBAR.TXT again. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Let's look once more at the root directory; we have already done this in |
||||||
|
example 2, and indeed we already know that FOOBAR.TXT has a directory |
||||||
|
entry at offset 0x20: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/rootdir3.jpg" alt="Root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
This time we are interested in the file date, and we know from our |
||||||
|
<a href="#root_directory">root directory layout</a> that this is at |
||||||
|
offset 0x18 within each directory entry. Thus, the date for FOOBAR.TXT |
||||||
|
is at offset 0x20+0x18, or 0x38 (highlighted in red above). Once again, |
||||||
|
this is a 16 bit value with the least significant byte stored first. The |
||||||
|
bytes are 0x65 and 0x39 respectively, so reversing these and putting |
||||||
|
them together gives a value of 0x3965. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Now all we have to do is analyse the components of this value. An easy |
||||||
|
way is first to convert it to binary, and this is even easier if we take |
||||||
|
it one hexadecimal digit at a time: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
3 9 6 5 |
||||||
|
| | | | |
||||||
|
V V V V |
||||||
|
|
||||||
|
0 0 1 1 1 0 0 1 0 1 1 0 0 1 0 1 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
Let's push all the digits together: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 0 1 1 1 0 0 1 0 1 1 0 0 1 0 1 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
Now we can split them again on boundaries corresponding to the |
||||||
|
individual components of the date, as defined in the |
||||||
|
<a href="#file_date">file date format</a>. Then we convert each part |
||||||
|
back to decimal: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 0 1 1 1 0 0 1 0 1 1 0 0 1 0 1 |
||||||
|
|
||||||
|
| | | |
||||||
|
V V V |
||||||
|
|
||||||
|
28 11 5 |
||||||
|
(year) (month) (day) |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
Remember that the year is based at 1980, so if we add 1980 to 28, we get |
||||||
|
2008. The entire date is thus the 5th of November 2008. |
||||||
|
</p> |
||||||
|
|
||||||
|
<h3>Example 4 - find the data blocks for a file</h3> |
||||||
|
<p> |
||||||
|
Here, we wish to find out the numbers of the blocks containing data for |
||||||
|
a particular file which has now been added to the disk. The name of the |
||||||
|
file is NETWORK.VRS. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Once again, we find the root directory. Here are its latest contents, |
||||||
|
after NETWORK.VRS has been created: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/rootdir2.jpg" alt="Root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Note that the third directory entry (starting at offset 0x40) is that |
||||||
|
for NETWORK.VRS. We know that the starting cluster number for the file |
||||||
|
data occupies bytes at offsets 0x1a and 0x1b in a particular directory |
||||||
|
entry; thus the bytes we want are at offsets 0x5a and 0x5b (we just |
||||||
|
added 0x40, the offset of the start of the entry). These (highlighted in |
||||||
|
red) contain 0x4e and 0x0f respectively, and, remembering that the first |
||||||
|
byte is the least significant one, the number we want is 0x0f4e. |
||||||
|
Incidentally, the next four bytes (highlighted in blue) are the file |
||||||
|
size, again with the least significant byte first. These are 0x92, 0x06, |
||||||
|
0x00, 0x00 respectively, making a value of 0x00000692. This (in decimal) |
||||||
|
is 1682. So, this file is <strong>1682</strong> bytes long. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Let's review what we know so far... |
||||||
|
</p> |
||||||
|
<ul> |
||||||
|
<li>The starting cluster of the file is cluster 0x0f4e.</li> |
||||||
|
<li>The root directory starts at block 0x15.</li> |
||||||
|
<li>The first allocation unit starts at the first block after the root |
||||||
|
directory.</li> |
||||||
|
</ul> |
||||||
|
<p> |
||||||
|
What else do we need to know? We know where the root directory starts, |
||||||
|
but not where it ends. So we need the size of the root directory, in |
||||||
|
blocks. Let's look once again at the boot block: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/bootblk2.jpg" alt="Boot block - find root directory" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
What we need to find this time is the maximum number of entries in the root |
||||||
|
directory; this is fixed when the disk is formatted. We know from the |
||||||
|
<a href="#boot_block">boot block layout</a> that this appears in the two |
||||||
|
bytes starting at offset 0x11 in the boot block (these are highlighted |
||||||
|
in red above). These bytes contain 0x40 and 0x00 respectively, so |
||||||
|
(arranging as usual) this gives us a value of 0x0040 (64 in decimal). So |
||||||
|
there are 64 root directory entries. We know that one directory entry |
||||||
|
occupies 32 bytes, so the total space occupied by the root directory is |
||||||
|
64*32 bytes, or 2048 bytes. Each block is 512 bytes, so the number of |
||||||
|
blocks occupied by the root directory is 2048 divided by 512...that is, |
||||||
|
4. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
So, the root directory starts at block 0x15. Thus the first allocation |
||||||
|
unit starts at 0x15+4, or 0x19. So, to convert an allocation unit number |
||||||
|
to a block number, we need to add the constant value 0x19. |
||||||
|
And to convert a cluster number (which is what appears in the root |
||||||
|
directory) to a block number, we need to add 0x17, to allow for that |
||||||
|
strange offset of 2. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We now know that the first data block of the file is at cluster |
||||||
|
number 0xf4e (see above). Adding the constant we have discovered, we |
||||||
|
find that this is block number 0xf4e+0x17, or 0xf65. Let's look at block |
||||||
|
0xf65: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/datablk1.jpg" alt="Data block 1" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Well, that certainly looks like the start of a poem! Each line of the |
||||||
|
text is separated by a special character called <em>newline</em>, which |
||||||
|
has the code 0x0a (decimal 10). The first few of these are highlighted |
||||||
|
in red. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We have nearly finished. There is obviously more of this file, and for us |
||||||
|
to find the rest of it, we need to consult the FAT. Recall that the |
||||||
|
starting <em>cluster</em> number of the file (the block we just looked |
||||||
|
at) is 0xf4e. Each entry in the FAT is two bytes in size, so we'll find |
||||||
|
the entry for that cluster at offset 0xf4e*2 in the FAT, which is offset |
||||||
|
0x1e9c (it's easier to add the value twice than attempt multiplication). |
||||||
|
We know that one disk block (and thus one block of the FAT) is 0x200 |
||||||
|
bytes in size, so we just need to divide 0x1e9c by 0x200. This sounds |
||||||
|
hard, but it isn't. You can find tools for this, or do it yourself. |
||||||
|
Let's look at these two numbers in binary: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0x0200 => 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 |
||||||
|
0x1e9c => 0 0 0 1 1 1 1 0 1 0 0 1 1 1 0 0 |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
The first number is a power of two, so to divide by it we simply shift |
||||||
|
the second number right - in this case by nine places: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 => 0x0f |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
So the entry we want is in block 0x0f of the FAT. The remainder from our |
||||||
|
division is of course all the bits we lost when we shifted: |
||||||
|
</p> |
||||||
|
<pre> |
||||||
|
0 1 0 0 1 1 1 0 0 => 0x9c |
||||||
|
</pre> |
||||||
|
<p> |
||||||
|
so this is the byte offset of the entry within the FAT block. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We need to find FAT block 0x0f. We know the FAT starts in block 1 of the |
||||||
|
disk (see earlier), so block 0x0f of the FAT will be in disk block |
||||||
|
0x0f+1, or block 0x10. Let's look at that block: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/fat.jpg" alt="FAT block" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We need to look at the FAT entry (two bytes) at offset 0x9c; this is |
||||||
|
highlighted in red above, and resolves to the 16 bit value 0x0f4f. This |
||||||
|
is actually the very next cluster, numerically, from the one we have |
||||||
|
just looked at (this will not always be the case), so we can apply a bit |
||||||
|
of common sense and deduce that the second data block of the file appears |
||||||
|
immediately after the first; thus, the first two blocks are at 0xf65 and |
||||||
|
0xf66. Here is block 0xf66: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/datablk2.jpg" alt="Data block 2" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
which certainly looks like the continuation of the poem. If we look at |
||||||
|
the FAT entry for this new cluster (which, since it's the next block, |
||||||
|
will also be the next cluster and thus in the next FAT entry), it is |
||||||
|
highlighted in blue above, and contains the value 0x0f50. This is the |
||||||
|
very next block and cluster: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/datablk3.jpg" alt="Data block 3" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
We continue this (again, it's the next block and cluster) and we find |
||||||
|
0x0f51 as the cluster number (highlighted in green above). Here is that block: |
||||||
|
</p> |
||||||
|
<p class="center"> |
||||||
|
<img src="images/datablk4.jpg" alt="Data block 4" /> |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Lastly, we look at the FAT entry for this block/cluster (highlighted in |
||||||
|
black). This time the entry is 0xffff, which indicates that there are no |
||||||
|
more blocks in the file. We have finished! |
||||||
|
</p> |
||||||
|
|
||||||
|
<h2>Conclusion</h2> |
||||||
|
<p> |
||||||
|
If you've managed to get this far (and understood it all) you have a |
||||||
|
good working understanding of the 16-bit FAT file system. You should be |
||||||
|
able to analyse a disk, and see if it is corrupted. You may even be able |
||||||
|
to repair it! |
||||||
|
</p> |
||||||
|
|
||||||
|
<!-- E n d o f M a i n ================================================ --> |
||||||
|
<hr /> |
||||||
|
|
||||||
|
<!-- F o o t e r ========================================================== --> |
||||||
|
|
||||||
|
<script type="text/javascript"><!-- |
||||||
|
amazon_ad_tag="thmlimapr-21"; |
||||||
|
amazon_ad_width="728"; |
||||||
|
amazon_ad_height="90"; |
||||||
|
amazon_color_background="EBE8C0"; |
||||||
|
amazon_color_border="386424"; |
||||||
|
amazon_color_logo="DDD37F"; |
||||||
|
amazon_color_text="38352A"; |
||||||
|
amazon_color_link="34338B"; |
||||||
|
amazon_ad_logo="hide"; |
||||||
|
amazon_ad_title="Bob's books - books.tavi.co.uk"; //--></script> |
||||||
|
<script type="text/javascript" src="http://www.assoc-amazon.co.uk/s/asw.js"></script> |
||||||
|
|
||||||
|
<hr /> |
||||||
|
|
||||||
|
<p><a href="http://validator.w3.org/check/referer"> |
||||||
|
<img style="border:0" src="http://www.w3.org/Icons/valid-xhtml10" |
||||||
|
alt="Valid XHTML 1.0!" height="31" width="88" /></a> |
||||||
|
<a href="http://jigsaw.w3.org/css-validator"> |
||||||
|
<img style="border:0" src="http://jigsaw.w3.org/css-validator/images/vcss" |
||||||
|
alt="Valid CSS!" /></a> |
||||||
|
</p> |
||||||
|
<p class="footnote"> |
||||||
|
This site is copyright |
||||||
|
© 2017 |
||||||
|
<a href="mail.html">Bob Eager</a> |
||||||
|
<br />Last updated: |
||||||
|
27 Nov 2017 |
||||||
|
</p> |
||||||
|
</body> |
||||||
|
</html> |
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 142 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 140 KiB |
@ -0,0 +1,306 @@ |
|||||||
|
a:hover { |
||||||
|
color: red; |
||||||
|
} |
||||||
|
|
||||||
|
hr { |
||||||
|
height: 1px; |
||||||
|
border-top: none; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
background-color: #FAEBD7; /* antiquewhite */ |
||||||
|
} |
||||||
|
|
||||||
|
h1,h2,h3,h4,h5,h6 { |
||||||
|
font-family: sans-serif; |
||||||
|
color: #00008B; /* darkblue */ |
||||||
|
} |
||||||
|
|
||||||
|
table.titlebox { |
||||||
|
text-align: center; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
td.title { |
||||||
|
font-family: sans-serif; |
||||||
|
font-weight: bold; |
||||||
|
color: blue; |
||||||
|
font-size: 220%; |
||||||
|
text-align: center; |
||||||
|
width: 70%; |
||||||
|
} |
||||||
|
|
||||||
|
td.subtitle { |
||||||
|
font-family: sans-serif; |
||||||
|
font-weight: bold; |
||||||
|
color: red; |
||||||
|
font-size: 150%; |
||||||
|
text-align: center; |
||||||
|
width: 70%; |
||||||
|
} |
||||||
|
|
||||||
|
td.smalltitle { |
||||||
|
font-family: sans-serif; |
||||||
|
font-weight: bold; |
||||||
|
color: #00008B; /* darkblue */ |
||||||
|
font-size: 150%; |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
td.sidebox { |
||||||
|
background-color: #FAEBD7; /* antiquewhite */ |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
table.sidebar { |
||||||
|
font-family: serif; |
||||||
|
font-size: 90%; |
||||||
|
color: black; |
||||||
|
background-color: white; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
td.main { |
||||||
|
background-color: #FAEBD7; /* antiquewhite */ |
||||||
|
font-family: serif; |
||||||
|
font-size: 100%; |
||||||
|
color: black; |
||||||
|
width: 85%; |
||||||
|
} |
||||||
|
|
||||||
|
table.spec { |
||||||
|
background-color: white; |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
border-collapse: collapse; |
||||||
|
border-style: solid; |
||||||
|
border-width: medium; |
||||||
|
border-color: black; |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
img { |
||||||
|
border-style: solid; |
||||||
|
border-width: medium; |
||||||
|
border-color: black; |
||||||
|
} |
||||||
|
|
||||||
|
th.spec { |
||||||
|
border-collapse: collapse; |
||||||
|
border-style: solid; |
||||||
|
border-width: thin; |
||||||
|
border-color: black; |
||||||
|
} |
||||||
|
|
||||||
|
td.spec { |
||||||
|
border-collapse: collapse; |
||||||
|
border-style: solid; |
||||||
|
border-width: thin; |
||||||
|
border-color: black; |
||||||
|
} |
||||||
|
|
||||||
|
table.doc { |
||||||
|
background-color: white; |
||||||
|
font-family: serif; |
||||||
|
font-size: 100%; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
|
||||||
|
td.docname { |
||||||
|
padding-left: 3%; |
||||||
|
} |
||||||
|
|
||||||
|
td.doclink { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
td.docinfo { |
||||||
|
padding-left: 3%; |
||||||
|
} |
||||||
|
|
||||||
|
table.info { |
||||||
|
background-color: white; |
||||||
|
font-family: serif; |
||||||
|
font-size: 100%; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
|
||||||
|
th.infotitle { |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
th.infolink { |
||||||
|
width: 20%; |
||||||
|
} |
||||||
|
|
||||||
|
td.infotitle { |
||||||
|
text-align: left; |
||||||
|
padding-left: 3%; |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
td.infolink { |
||||||
|
text-align: center; |
||||||
|
width: 20%; |
||||||
|
} |
||||||
|
|
||||||
|
table.file { |
||||||
|
background-color: white; |
||||||
|
font-family: serif; |
||||||
|
font-size: 100%; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
|
||||||
|
td.fversion { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
td.flink { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
td.fname { |
||||||
|
padding-left: 3%; |
||||||
|
} |
||||||
|
|
||||||
|
table.ver { |
||||||
|
background-color: white; |
||||||
|
font-family: serif; |
||||||
|
font-size: 100%; |
||||||
|
color: black; |
||||||
|
} |
||||||
|
|
||||||
|
td.verfeat { |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
|
||||||
|
td.vername { |
||||||
|
padding-left: 2%; |
||||||
|
} |
||||||
|
|
||||||
|
td.verblank { |
||||||
|
background-color: #D3D3D3; /* lightgrey */ |
||||||
|
} |
||||||
|
|
||||||
|
table.mail { |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
td.maillabel { |
||||||
|
width: 22%; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
|
||||||
|
td.mailinput { |
||||||
|
width: 78%; |
||||||
|
text-align:left; |
||||||
|
} |
||||||
|
|
||||||
|
td.mailcontrol1 { |
||||||
|
width: 25%; |
||||||
|
} |
||||||
|
|
||||||
|
td.mailcontrol2 { |
||||||
|
width: 75%; |
||||||
|
} |
||||||
|
|
||||||
|
table.exeheader { |
||||||
|
background-color: white; |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
border-collapse: collapse; |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
th.exeoffset { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
th.exesize { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 10%; |
||||||
|
} |
||||||
|
|
||||||
|
th.exedesc { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 75%; |
||||||
|
} |
||||||
|
|
||||||
|
td.exeoffset { |
||||||
|
text-align: center; |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
td.exesize { |
||||||
|
text-align: center; |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 10%; |
||||||
|
} |
||||||
|
|
||||||
|
td.exedesc { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 75%; |
||||||
|
} |
||||||
|
|
||||||
|
table.registers { |
||||||
|
background-color: white; |
||||||
|
margin-left: auto; |
||||||
|
margin-right: auto; |
||||||
|
border-collapse: collapse; |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 70%; |
||||||
|
} |
||||||
|
|
||||||
|
th.registersreg { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
th.registersvalue { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 85%; |
||||||
|
} |
||||||
|
|
||||||
|
td.registersreg { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
text-align: center; |
||||||
|
width: 15%; |
||||||
|
} |
||||||
|
|
||||||
|
td.registersvalue { |
||||||
|
border-style: ridge; |
||||||
|
border-color: black; |
||||||
|
width: 85%; |
||||||
|
} |
||||||
|
|
||||||
|
p.center { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
p.footnote { |
||||||
|
font-size: smaller; |
||||||
|
} |
||||||
|
|
||||||
|
p.warning { |
||||||
|
color: red; |
||||||
|
font-weight: bold; |
||||||
|
border: thick red solid; |
||||||
|
} |
||||||
|
|
||||||
|
div.display { |
||||||
|
text-align: center; |
||||||
|
} |