File Control Block
The File Control Block (FCB) is a data structure used in the CP/M operating system and early versions of MS-DOS to maintain the state of an open file. It stores essential metadata about a file in the application's memory, enabling file operations such as opening, reading, writing, and closing.[1] The FCB typically includes the file name (padded to 8.3 format), current record position, file size, and drive/user information, along with allocation details for disk blocks.[2] The FCB originated in CP/M, developed by Gary Kildall and first released in 1974 as one of the earliest operating systems for microcomputers. It was designed to provide a simple interface for programs to access files without direct hardware interaction. This structure was adopted in MS-DOS 1.0 in 1981 to ensure compatibility with CP/M software, remaining a core component until MS-DOS 2.0 introduced directory support, though FCB functions persisted in later versions until deprecation in favor of handle-based APIs.[3][4] In file system implementation for these systems, the FCB serves as a per-open-file unit managed by the application, bridging logical file operations with physical disk storage via system calls to the BDOS (in CP/M) or DOS kernel. When a file is opened, the application initializes an FCB, which the OS uses to locate and access the file's directory entry and data blocks.[2] This contrasts with modern systems, where file state is typically tracked in kernel-managed tables; for example, Unix-like systems use inodes for on-disk metadata, while Windows NTFS stores equivalent file records in the Master File Table and employs a separate in-memory FCB structure in file system drivers for open files.[1][2] The FCB plays a critical role in ensuring basic data access and integrity in CP/M and early DOS by supporting sequential file access and simple allocation methods, such as extent-based allocation in CP/M.[1]Introduction
Definition and Purpose
A File Control Block (FCB) is a data structure employed in early operating systems to represent and manage the state of an open file. It serves as a kernel-level construct that encapsulates essential file metadata, such as the drive identifier, filename, file extension, record count, and allocation information, enabling the operating system to track and manipulate files on disk.[5][6][7] The primary purpose of an FCB is to provide a standardized interface for file input/output operations, including opening, reading, writing, closing, and deleting files, while maintaining the file's current position for sequential or random access. By holding a memory-resident copy of directory entry data, the FCB allows programs to interact with the file system without directly accessing disk sectors, thereby abstracting low-level details and ensuring data integrity during operations. This structure is managed by the operating system's basic disk operating system (BDOS) or equivalent, which updates the FCB as needed and synchronizes changes back to the disk upon file closure.[5][6][7] In CP/M, the FCB is a fixed 36-byte structure (33 bytes in CP/M 1.0) typically located in low memory, such as at offset 0x5C, and is passed to BDOS functions via registers for all file-related calls, supporting extents of up to 16 KB each to handle larger files. MS-DOS inherits and extends this model with a 37-byte normal FCB and a 44-byte extended variant, incorporating additional fields like file attributes (e.g., read-only), with timestamps and further attributes added in later versions such as MS-DOS 2.0 and 3.0, while using Interrupt 21h for operations to enable compatibility with CP/M-style applications. Both implementations prioritize simplicity for 8-bit systems, limiting concurrent open files and record sizes to 128 bytes by default.[5][6][7]Historical Development
The File Control Block (FCB) originated in the CP/M operating system, developed by Gary Kildall at Digital Research in 1974 as a disk operating system for the Intel Intellec-8 microcomputer.[8][6] In CP/M version 1.0, the FCB was a 33-byte data structure used exclusively for file operations, including opening, reading, writing, and closing files, providing a standardized interface for applications to interact with the file system on floppy disks.[6] This design emphasized simplicity and portability across early microcomputers, with the FCB containing fields for drive specification, an 8-character filename, a 3-character extension, file type (text or binary), and extent information to manage file fragmentation.[6] CP/M's FCB evolved through subsequent versions to support growing hardware capabilities. In CP/M 2.0 (1979), it expanded to 36 bytes, incorporating a 16-bit random record number for sequential and direct file access, along with a file write flag to track modifications.[6] CP/M 3.0 (1982) further enhanced it with an 18-bit record addressing scheme and the F_TRUNCATE function (BDOS call #99) for efficient file resizing, while introducing user areas and limited subdirectory support in third-party implementations like DOS Plus.[6] These updates maintained backward compatibility but highlighted the FCB's limitations in handling hierarchical structures, as CP/M retained a flat file system model.[6] The FCB was adopted into MS-DOS through its predecessor, 86-DOS (also known as QDOS), developed by Tim Paterson in 1980, which closely mirrored CP/M's architecture for compatibility with existing software.[9] Microsoft licensed and released it as MS-DOS 1.0 in 1981 for the IBM PC, where the 37-byte FCB remained the primary mechanism for file I/O via INT 21h interrupts, supporting up to 15 open files per process without path or subdirectory capabilities.[9] This ensured a smooth transition for CP/M applications ported to the IBM PC platform.[9] With MS-DOS 2.0 in 1983, the introduction of hierarchical directories and the File Allocation Table (FAT) file system rendered the traditional FCB incompatible for path-based operations, prompting the addition of a handle-based API inspired by UNIX for more flexible file management.[10][9] FCB support persisted for legacy compatibility, evolving into an extended 44-byte form in later versions to include attributes like hidden files and volume labels, but it was gradually deprecated as handle functions dominated.[9] By MS-DOS 3.0 (1984), the FILES= directive in CONFIG.SYS allowed up to 255 FCBs for sharing, though usage declined with the rise of graphical interfaces and modern file systems.[9]Structure
CP/M File Control Block
The File Control Block (FCB) in CP/M is a fixed-size data structure that serves as the primary interface for file operations within the operating system, enabling programs to specify, open, read, write, and manage files on disk. Introduced in the original CP/M version 1.0 and standardized across subsequent releases up to CP/M 2.2, the FCB encapsulates essential file attributes such as the drive, filename, filetype, and allocation details, which are passed to the Basic Disk Operating System (BDOS) for processing. This design reflects CP/M's emphasis on simplicity and portability across early microcomputer hardware, where files are organized into 128-byte records grouped into 16K-byte extents, and the FCB provides the necessary mapping for both sequential and random access modes.[11] The FCB measures 36 bytes in length for full random-access functionality, though sequential operations utilize only the first 33 bytes; it is conventionally located at memory address 005CH in the Transient Program Area (TPA), immediately following the command buffer. User programs initialize the FCB by setting the filename and filetype fields, while the BDOS populates and updates system-reserved fields during file operations like opening or closing. For instance, when executing a command such as copying a file, the Console Command Processor (CCP) parses the command line to fill one or two FCBs—one for the source and one for the destination—before invoking BDOS functions. This structure ensures that all disk I/O, including directory searches and record allocation, revolves around the FCB, making it integral to CP/M's flat file system without hierarchical directories.[11] The layout of the FCB is rigidly defined to align with CP/M's 8-bit architecture and disk sector organization, as outlined in the following table:| Byte Offset | Field | Size (Bytes) | Description |
|---|---|---|---|
| 00 | Drive Code (dr) | 1 | Specifies the disk drive (0 = default, 1 = A:, up to 16 = P:); defaults to the current drive if unset. |
| 01–08 | Filename (f1–f8) | 8 | Eight uppercase ASCII characters for the filename, left-justified and space-padded; high bits cleared (0). No wildcards or special characters allowed. |
| 09–11 | Filetype (t1–t3) | 3 | Three uppercase ASCII characters for the extension (e.g., "ASM"), left-justified and space-padded; high bits cleared. Byte 09's high bit indicates read-only status if set. |
| 12 | Extent (ex) | 1 | Low byte of the extent number (0–31), representing 16K-byte file segments; high byte in byte 13 for multi-extent files. |
| 13 | Extent High (s1) | 1 | High byte of extent (usually 0); reserved and set to 0 on file creation or open. |
| 14 | System Use (s2) | 1 | Reserved; initialized to 0 by user and managed by BDOS. |
| 15 | Record Count (rc) | 1 | Number of 128-byte records in the current extent (0–127); updated by BDOS on write operations. |
| 16–31 | Disk Map (d0–d15) | 16 | Allocation bitmap or directory code; filled by BDOS during search/open and reserved for system use. |
| 32 | Current Record (cr) | 1 | Position within the current extent for sequential access (0–127); reset to 0 for new operations. |
| 33–35 | Random Record (r0–r2) | 3 | Three-byte random record number for direct access (r0 = low byte, r1 = middle, r2 = high/overflow); enables jumping to specific records up to 65,535 (2^{16}-1), with r2 as an overflow indicator. |
[d:]filename.ext, where the drive is optional, filenames are 1–8 characters, and extensions are 1–3 characters, all converted to uppercase ASCII without case sensitivity. For example, the file "PROGRAM.BAS" would populate bytes 01–07 with "PROGRAM" (space-padded) and bytes 09–11 with "BAS" (space-padded). The BDOS uses the FCB to match against directory entries on disk, which mirror this structure, ensuring consistent file identification across 512-byte directory blocks.[11]
In practice, the FCB facilitates BDOS function calls invoked via software interrupt at address 0005H, such as function 15 (open) to validate and load directory data into the FCB, or function 20 (close) to update the directory with extent and record counts from bytes 12–15. For random access, programs compute the desired record number and store it in bytes 33–35 before issuing a read or write call, allowing efficient navigation in larger files spanning multiple extents. Limitations inherent to the FCB include its fixed 36-byte size, which caps filenames at eight characters and precludes support for long paths or metadata like timestamps, though these constraints aligned with the era's hardware constraints and influenced later systems like MS-DOS. The structure remained largely unchanged from CP/M 1.4 through 2.2, with minor enhancements in CP/M 3 for multitasking via MP/M, but the core FCB design persisted as the foundation for file handling.[11]
MS-DOS File Control Block
The MS-DOS File Control Block (FCB) is a fixed-size data structure used by the operating system to manage file operations, particularly for compatibility with CP/M-style sequential and random access. It is allocated in the application's memory space and passed to MS-DOS interrupt 21h functions for tasks such as opening, reading, writing, and closing files. In MS-DOS versions 1.0 through 2.0, the standard FCB is 37 bytes long, while later versions introduced an extended variant for additional attributes.[12][9] The standard FCB begins with fields for file identification and proceeds to metadata for access control. The drive number (1 byte at offset 00h) specifies the disk (0 for default, 1 for A:, 2 for B:, etc.), set by the program before opening. The filename (8 bytes at offset 01h) and extension (3 bytes at offset 09h) are left-justified and padded with spaces, supporting CP/M conventions but limited to the 8.3 format without paths in early MS-DOS. The current block number (2 bytes at offset 0Ch), initialized to 0 on open, tracks the 128-record block position for sequential access. The record size (2 bytes at offset 0Eh) defaults to 128 bytes but can be modified by the program. File size (4 bytes at offset 10h) is set by MS-DOS upon opening, representing the total bytes. The last write date (2 bytes at offset 14h) encodes year (bits 9-15, offset from 1980), month (bits 5-8), and day (bits 0-4), while the time (2 bytes at offset 16h) uses hours (bits 11-15), minutes (bits 5-10), and two-second increments (bits 0-4). Eight reserved bytes at offset 18h are for MS-DOS internal use, varying by version (e.g., cluster numbers in DOS 2.x). The current record (1 byte at offset 20h) ranges from 0 to 127 within the block, and the random record number (4 bytes at offset 21h) enables direct access calculations as (block * records_per_block) + current_record.[7][13][9] For more advanced file handling, MS-DOS 2.0 and later support an extended FCB, which prepends 7 bytes to the standard structure, making it 44 bytes total. The first byte (offset 00h) is set to 0FFh to identify it as extended. Five reserved bytes follow at offset 01h. The file attribute byte (1 byte at offset 06h) includes bits for read-only (bit 0), hidden (bit 1), system (bit 2), volume label (bit 3), subdirectory (bit 4), and archive (bit 5), allowing operations on non-standard files. The remaining fields mirror the standard FCB but are offset by 7 bytes (e.g., drive at 07h, filename at 08h). This extension addresses limitations in the original FCB, such as attribute support, while maintaining backward compatibility. In DOS 3.x and beyond, reserved fields at offsets 18h-1Fh evolved to include sharing modes, device attributes, and cluster information, reflecting enhancements like file sharing and larger disks.[7][9][13] The following table summarizes the standard FCB structure for MS-DOS 2.0:| Offset (hex) | Size (bytes) | Field Name | Description |
|---|---|---|---|
| 00 | 1 | Drive number | 0=default; 1=A:, etc. Program-set. |
| 01 | 8 | Filename | Left-justified, space-padded. Program-set. |
| 09 | 3 | Extension | Left-justified, space-padded. Program-set. |
| 0C | 2 | Current block | Block index (0-based). MS-DOS-set on open. |
| 0E | 2 | Record size | Bytes per record (default 128). Program-set. |
| 10 | 4 | File size | Total bytes. MS-DOS-set. |
| 14 | 2 | Last write date | Packed: year/month/day. MS-DOS-set. |
| 16 | 2 | Last write time | Packed: hour/minute/2s. MS-DOS-set. |
| 18 | 8 | Reserved | MS-DOS internal (e.g., clusters in 2.x). |
| 20 | 1 | Current record | 0-127 in block. Program-set. |
| 21 | 4 | Random record | For direct access. Program-set. |
Usage
In CP/M and Early DOS
In CP/M, the File Control Block (FCB) served as the primary data structure for applications to perform file input/output operations through the Basic Disk Operating System (BDOS) interface. Programs would allocate an FCB in memory, typically at fixed locations such as offset 005CH for the first file specification, and populate its fields with details like the drive code, filename (up to 8 characters), filetype (up to 3 characters), and extent number before invoking BDOS function calls. For instance, to open a file, an application sets the filename in the FCB and calls BDOS function 15 (open file), which activates the file on disk and returns a directory code indicating success or failure; subsequent sequential reads or writes use functions 20 and 21, respectively, transferring 128-byte records while the BDOS automatically increments the current record field (CR) in the FCB. Random access was supported via function 33 (read random record), where the application updated the random record number fields (R0-R2) in the FCB to seek to a specific 128-byte record. The Command Processor (CCP) also utilized FCBs by constructing them from command-line arguments, enabling transient programs to access input and output files without manual setup.[14][6] Early versions of MS-DOS, such as 1.x and 2.x, retained the FCB model from CP/M to ensure compatibility with existing software, allowing applications to manage files using a 37-byte normal FCB or a 44-byte extended FCB that included additional attribute bytes for features like read-only or hidden status. Applications reserved space for the FCB in their memory segment, filled it with file details similar to CP/M (drive, 8.3 filename format, and record size defaulting to 128 bytes), and invoked DOS via Interrupt 21h with CP/M-compatible function numbers; for example, function 0Fh opened a file by parsing the FCB and returning an error code if the file was not found in the current directory, while functions 14h and 15h handled sequential reads and writes by advancing the current record field. Random block operations used functions 27h and 28h, enabling direct access to disk blocks based on the FCB's block number and record size fields, which proved useful for ported CP/M programs handling fixed-record files like databases. However, FCB-based I/O was inherently sequential and directory-limited, lacking support for paths or hierarchical structures until later DOS versions introduced handle-based alternatives.[7][9] This FCB approach in both systems emphasized simplicity for 8-bit microcomputers with limited resources, where applications directly managed record positioning and error handling through the structure's fields, such as the record count (RC) for tracking file extents. In practice, utilities like the CP/M LINK program or early DOS file copiers manipulated FCB fields like the extent (EX) and current record (CR) to perform seeks without dedicated random-access calls, demonstrating its role in enabling efficient, low-level file manipulation on resource-constrained hardware.[6][14]Limitations and Deprecation
The File Control Block (FCB) in early MS-DOS versions suffered from several inherent limitations stemming from its origins in CP/M's flat file system design. Primarily, the FCB enforced an 8.3 filename convention, with names and extensions limited to eight and three characters respectively, padded with spaces and converted to uppercase, which restricted usability as file systems evolved to support longer, case-sensitive names.[9] Additionally, the fixed 37-byte structure of a standard FCB provided no fields for pathnames or hierarchical directories, confining operations to the current directory and rendering it incompatible with the tree-structured directories introduced in MS-DOS 2.0.[15][9] Access patterns were another constraint, as FCB-based I/O relied on fixed-length records—defaulting to 128 bytes—with random access limited by a three-byte relative record field that capped effective addressing at smaller file sizes in practice, making it less efficient for byte-oriented or variable-length data compared to modern stream-based interfaces.[7] The number of concurrently open FCB-handled files was also restricted by memory allocation, typically set via the FCBS parameter in CONFIG.SYS (defaulting to a low value like four), beyond which MS-DOS would close earlier files to free resources, hindering multitasking or multi-file applications.[9] These limitations contributed to the FCB's deprecation starting with MS-DOS 2.0 in 1983, when Microsoft introduced a handle-based file API (via Interrupt 21h functions such as 3Dh for opening and 3Fh/40h for read/write) that supported paths, larger files, and more flexible access without the rigid structure of FCBs.[15][16] While retained for backward compatibility with CP/M and DOS 1.x software, FCB functions were explicitly marked as legacy, with new programs encouraged to use handles for better integration with the hierarchical FAT file system and to avoid compatibility issues on larger volumes.[16] By MS-DOS 3.0 and later, handle APIs became the standard, further marginalizing FCBs, which saw incomplete support for features like extended attributes and volumes over 32 MB without additional utilities like SHARE.EXE.[15] In contemporary contexts, FCBs are obsolete, supported only in legacy DOS emulators for running vintage software.Related Components
Disk Transfer Area
The Disk Transfer Area (DTA) is a dedicated memory buffer employed alongside the File Control Block (FCB) in operating systems like CP/M and MS-DOS to handle data transfers during file input/output operations. It acts as an intermediary storage space for records moved between disk storage and the program's addressable memory, enabling efficient low-level file access without direct hardware interaction. The DTA's design reflects the era's emphasis on simplicity and compatibility, typically sized to match the underlying sector or record granularity of the filesystem.[17][18] In CP/M, the DTA constitutes a contiguous 128-byte region, aligned to the system's standard sector size, serving as the default destination or source for data in FCB-mediated reads and writes. Positioned by default at offset 0080H within the Transient Program Area (TPA)—immediately following the FCB default locations at 005CH and 006CH—it can be reassigned via BDOS Function 26 (SETDMA), where the DE register pair specifies the new starting address to ensure at least 128 bytes of free, contiguous memory. This relocation capability prevents overlaps with program code or other buffers, promoting flexible memory utilization in resource-constrained environments. During operations such as sequential reading (BDOS Function 20) or writing (Function 21), the Basic Disk Operating System (BDOS) uses the FCB to identify the target file, extent, and record number, then performs the transfer exclusively through the current DTA; for random access, Functions 33 (Read Random) and 34 (Write Random) similarly rely on the DTA while updating the FCB's random record field. Failure to set an appropriate DTA address results in data corruption or undefined behavior, underscoring the programmer's responsibility for buffer management.[17] MS-DOS inherited and extended the DTA concept from CP/M to maintain backward compatibility for FCB-based applications, designating it as a variable-length buffer (defaulting to 128 bytes) for legacy file I/O and additional utilities like directory enumeration. By convention, the default DTA resides at offset 80H in the Program Segment Prefix (PSP), overlapping the command-tail storage area (offsets 80H-FFH), which mandates explicit reconfiguration via interrupt 21h with AH=1Ah (DS:DX pointing to the desired buffer address) to avoid inadvertent overwrites during command-line processing. Retrieval of the current DTA address occurs through AH=2Fh (returning ES:BX). In FCB contexts, functions like sequential read (AH=0Fh) or random write (AH=22h) direct data transfers to or from the DTA, with the FCB providing file metadata such as drive, name, and record pointers; MS-DOS supports record sizes beyond 128 bytes for enhanced flexibility, though CP/M-compatible programs adhere to the standard. Beyond pure I/O, the DTA supports non-FCB operations, such as file searches via AH=4Eh (Find First) and AH=4Fh (Find Next), where it stores structured results including a 21-byte reserved prefix followed by the file's attribute byte, time/date stamps (two words), size (doubleword), and a null-terminated 13-character pathname. This dual role illustrates the DTA's evolution as a versatile, albeit rudimentary, data conduit in MS-DOS's transitional architecture.[18]| DTA Usage in Key MS-DOS Functions (Interrupt 21h) | Description | Relation to FCB |
|---|---|---|
| AH=1Ah (Set DTA) | Specifies buffer address for subsequent I/O or searches | Prepares DTA for FCB read/write operations |
| AH=2Fh (Get DTA) | Returns current buffer address | Allows verification before FCB-based transfers |
| AH=0Fh (Sequential Read) | Reads record into DTA | Uses FCB for file/record selection |
| AH=4Eh/4Fh (Find First/Next) | Populates DTA with matching file details | Independent of FCB; stores search results in DTA format |