1 Introduction
2 Ground Rules

Building a File System
3 File Systems
4 File Content Data Structure
5 Allocation Cluster Manager
6 Exceptions and Emancipation
7 Base Classes, Testing, and More
8 File Meta Data
9 Native File Class
10 Our File System
11 Allocation Table
12 File System Support Code
13 Initializing the File System
14 Contiguous Files
15 Rebuilding the File System
16 Native File System Support Methods
17 Lookups, Wildcards, and Unicode, Oh My
18 Finishing the File System Class

The Init Program
19 Hardware Abstraction and UOS Architecture
20 Init Command Mode
21 Using Our File System
22 Hardware and Device Lists
23 Fun with Stores: Partitions
24 Fun with Stores: RAID
25 Fun with Stores: RAM Disks
26 Init wrap-up

The Executive
27 Overview of The Executive
28 Starting the Kernel
29 The Kernel
30 Making a Store Bootable
31 The MMC
32 The HMC
33 Loading the components
34 Using the File Processor
35 Symbols and the SSC
36 The File Processor and Device Management
37 The File Processor and File System Management
38 Finishing Executive Startup

Users and Security
39 Introduction to Users and Security
40 More Fun With Stores: File Heaps
41 File Heaps, part 2
42 SysUAF
43 TUser
44 SysUAF API

Terminal I/O
45 Shells and UCL
46 UOS API, the Application Side
47 UOS API, the Executive Side
48 I/O Devices
49 Streams
50 Terminal Output Filters
51 The TTerminal Class
52 Handles
53 Putting it All Together
54 Getting Terminal Input
55 QIO
56 Cooking Terminal Input
57 Putting it all together, part 2
58 Quotas and I/O

UCL
59 UCL Basics
60 Symbol Substitution
61 Command execution
62 Command execution, part 2
63 Command Abbreviation
64 ASTs
65 Expressions, Part 1
66 Expressions, Part 2: Support code
67 Expressions, part 3: Parsing
68 SYS_GETJPIW and SYS_TRNLNM
69 Expressions, part 4: Evaluation

UCL Lexical Functions
70 PROCESS_SCAN
71 PROCESS_SCAN, Part 2
72 TProcess updates
73 Unicode revisted
74 Lexical functions: F$CONTEXT
75 Lexical functions: F$PID
76 Lexical Functions: F$CUNITS
77 Lexical Functions: F$CVSI and F$CVUI
78 UOS Date and Time Formatting
79 Lexical Functions: F$CVTIME
80 LIB_CVTIME
81 Date/Time Contexts
82 SYS_GETTIM, LIB_Get_Timestamp, SYS_ASCTIM, and LIB_SYS_ASCTIM
83 Lexical Functions: F$DELTA_TIME
84 Lexical functions: F$DEVICE
85 SYS_DEVICE_SCAN
86 Lexical functions: F$DIRECTORY
87 Lexical functions: F$EDIT and F$ELEMENT
88 Lexical functions: F$ENVIRONMENT
89 SYS_GETUAI
90 Lexical functions: F$EXTRACT and F$IDENTIFIER
91 LIB_FAO and LIB_FAOL
92 LIB_FAO and LIB_FAOL, part 2
93 Lexical functions: F$FAO
94 File Processing Structures
95 Lexical functions: F$FILE_ATTRIBUTES
96 SYS_DISPLAY
97 Lexical functions: F$GETDVI
98 Parse_GetDVI
99 GetDVI
100 GetDVI, part 2
101 GetDVI, part 3
102 Lexical functions: F$GETJPI
103 GETJPI
104 Lexical functions: F$GETSYI
105 GETSYI
106 Lexical functions: F$INTEGER, F$LENGTH, F$LOCATE, and F$MATCH_WILD
107 Lexical function: F$PARSE
108 FILESCAN
109 SYS_PARSE
110 Lexical Functions: F$MODE, F$PRIVILEGE, and F$PROCESS
111 File Lookup Service
112 Lexical Functions: F$SEARCH
113 SYS_SEARCH
114 F$SETPRV and SYS_SETPRV
115 Lexical Functions: F$STRING, F$TIME, and F$TYPE
116 More on symbols
117 Lexical Functions: F$TRNLNM
118 SYS_TRNLNM, Part 2
119 Lexical functions: F$UNIQUE, F$USER, and F$VERIFY
120 Lexical functions: F$MESSAGE
121 TUOS_File_Wrapper
122 OPEN, CLOSE, and READ system services

UCL Commands
123 WRITE
124 Symbol assignment
125 The @ command
126 @ and EXIT
127 CRELNT system service
128 DELLNT system service
129 IF...THEN...ELSE
130 Comments, labels, and GOTO
131 GOSUB and RETURN
132 CALL, SUBROUTINE, and ENDSUBROUTINE
133 ON, SET {NO}ON, and error handling
134 INQUIRE
135 SYS_WRITE Service
136 OPEN
137 CLOSE
138 DELLNM system service
139 READ
140 Command Recall
141 RECALL
142 RUN
143 LIB_RUN
144 The Data Stream Interface
145 Preparing for execution
146 EOJ and LOGOUT
147 SYS_DELPROC and LIB_GET_FOREIGN

CUSPs and utilities
148 The I/O Queue
149 Timers
150 Logging in, part one
151 Logging in, part 2
152 System configuration
153 SET NODE utility
154 UUI
155 SETTERM utility
156 SETTERM utility, part 2
157 SETTERM utility, part 3
158 AUTHORIZE utility
159 AUTHORIZE utility, UI
160 AUTHORIZE utility, Access Restrictions
161 AUTHORIZE utility, Part 4
162 AUTHORIZE utility, Reporting
163 AUTHORIZE utility, Part 6
164 Authentication
165 Hashlib
166 Authenticate, Part 7
167 Logging in, part 3
168 DAY_OF_WEEK, CVT_FROM_INTERNAL_TIME, and SPAWN
169 DAY_OF_WEEK and CVT_FROM_INTERNAL_TIME
170 LIB_SPAWN
171 CREPRC
172 CREPRC, Part 2
173 COPY
174 COPY, part 2
175 COPY, part 3
176 COPY, part 4
177 LIB_Get_Default_File_Protection and LIB_Substitute_Wildcards
178 CREATESTREAM, STREAMNAME, and Set_Contiguous
179 Help Files
180 LBR Services
181 LBR Services, Part 2
182 LIBRARY utility
183 LIBRARY utility, Part 2
184 FS Services
185 FS Services, Part 2
186 Implementing Help
187 HELP
188 HELP, Part 2
189 DMG_Get_Key and LIB_Put_Formatted_Output
190 LIBRARY utility, Part 3
191 Shutting Down UOS
192 SHUTDOWN
193 WAIT
194 SETIMR
195 WAITFR and Scheduling
196 REPLY, OPCOM, and Mailboxes
197 REPLY utility
198 Mailboxes
199 BRKTHRU
200 OPCOM

Glossary/Index


Downloads

FS services, part 2

In this article, we will look at the code to implement the FS services that we documented in the previous article. As briefly noted in a previous article, we are not yet handling the issue of locking/unlocking the FS file for the purposes of synchronizing multiple concurrent access to the file. That will be covered in a future article.

// Open a file system file, returning the context
function FS_Open( Context : int64 ; Name : int64 ; Flags : int64 = 0 ;
    Allocation : int64 = 0 ; FSLabel : int64 = 0 ; Password : int64 = 0 ;
    Clustersize : int64 = 0 ; Folder_Clustersize : int64 = 0 ) : int64 ;

var ATO : int64 ;
    Bridge : TStore64_To_UOS_File_Bridge ;
    Buffer : array[ 0..32767 ] of byte ;
    Err : int64 ;
    Fil : TCOM_UOS_File ;
    FSC : TFS_Context ;
    _Label, _Password, _Name : string ;
    P : int64 ;
    UEC : TUnified_Exception ;

begin
    // Setup...
    Result := 0 ;
    _Name := '' ;
    _Label := '' ;
    _Password := '' ;

    // Get parameters...
    if( name = 0 ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    _Name := trim( Get_String( PSRB( name )^ ) ) ;
    if( _Name = '' ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    if( FSLabel <> 0 ) then
    begin
        _Label := trim( Get_String( PSRB( FSLabel )^ ) ) ;
    end ;
    if( Password <> 0 ) then
    begin
        _Password := trim( Get_String( PSRB( Password )^ ) ) ;
    end ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    if( Flags <> 0 ) then
    begin
        Flags := Pint64( Flags )^ ;
    end ;
    if( ( Flags and ( not FS_Valid_Mask ) ) <> 0 ) then
    begin
        Result := FS_INVFLAG ;
        exit ;
    end ;
    if( Allocation <> 0 ) then
    begin
        Allocation := pint64( Allocation )^ ;
    end ;
    if( Clustersize <> 0 ) then
    begin
        Clustersize := pint64( Clustersize )^ ;
    end ;
    if( Folder_Clustersize <> 0 ) then
    begin
        Folder_Clustersize := pint64( Folder_Clustersize )^ ;
    end ;
This service opens the file system and returns an initialized context. First we setup default values and then get the passed parameters.

    // Open the file...
    Fil := Open_Binary_File( _Name, Flags ) ;
    if( Fil = nil ) then // Open failed
    begin
        Err := LIB_Get_Exception( 0 ) ;
        Result := LIB_Get_Exception_Code( 0, Err ) ;
        exit ;
    end ;
Next we open the specified FS file, exiting with an error if there are any issues.

    // Create context and file system...
    FSC := TFS_Context.Create ;
    FSC.FS := TUOS_Native_File_System.Create ;
    FSC.FS.Store := TUOS_Managed_Store.Create ;
    Bridge := TStore64_To_UOS_File_Bridge.Create ;
    Bridge._File := Fil ;
    FSC.FS.Store.Store := Bridge ;
    if( ( Flags and FS_C_Create ) <> 0 ) then
    begin
        // Expand the file to the requested allocation size...
        fillchar( Buffer, sizeof( Buffer ), 0 ) ;
        P := 0 ;
        while( Allocation > 0 ) do
        begin
            if( Allocation < sizeof( Buffer ) ) then
            begin
                Fil.Write_Data( Buffer, P, Allocation, UEC ) ;
            end else
            begin
                Fil.Write_Data( Buffer, P, sizeof( Buffer ), UEC ) ;
            end ;
            if( ( UEC <> nil ) and ( UEC.Get_Error <> 0 ) ) then
            begin
                Result := UEC.Get_Error ;
                exit ;
            end ;
            Allocation := Allocation - sizeof( Buffer ) ;
            P := P + sizeof( Buffer ) ;
        end ;
        FSC.FS.Init( PChar( _Label ), PChar( _Password ), 0, Clustersize,
            Folder_Clustersize, 0, ATO, nil ) ;
    end ; // if( ( Flags and FS_Create ) <> 0 )
Next we create the context, file system, and managed store. Then we create a "bridge" object, which is used to translate between the TCOM_UOS_File instance - returned by the Open_Binary_File function - and the TCOM_Store64 instance required by the file system.

If we are creating a new FS file, we pre-extend the file to the requested allocation size and then we initialize the file system in the FS file.

    UEC := FSC.FS.Mount( PChar( _Label ), PChar( _Password ), 0 ) ;
    if( UEC <> nil ) then
    begin
        if( UEC.Get_Error = UOS_File_System_Is_Dirty ) then
        begin
            FSC.FS.Rebuild ;
            UEC := FSC.FS.Mount( PChar( _Label ), PChar( _Password ), 0 ) ; // Try again
            
        end ;
        if( UEC.Get_Error <> 0 ) then
        begin
            Result := UEC.Get_Error ;
            FSC.Free ;
            exit ;
        end ;
    end ; // if( UEC <> nil ) then
Next we mount the file system. If there was an error, we check to see if it indicated a dirty flag. If so, we tell the file system to rebuild and then we attempt to mount it again. If there is still an error (or the error wasn't about the file system being dirty), we exit.

    FSC.Sanity := #3'FSR' ;
    FSC.Password := _Password ;
    FSC.Flags := Flags ;
    Result := int64( @FSC ) ;
end ; // FS_Open
Finally, we set up the context and return it. The TFS_Context class is defined later in the article.

function FS_Close( Context : int64 ) : int64 ;

var FSC : TFS_Context ;

begin
    // Sanity checks...
    Result := 0 ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC.FS.Dismount ;
    FSC.FS.Free ;
    FSC.Sanity := '   ' ;
    FSC.Free ;
end ;
This function is used to close a FS context. First we confirm that the passed context is valid. If not, we exit with an error. Otherwise, we dismount the file system, free it, and destroy the context instance.

unction FS_Delete_File( Context, Name : int64 ) : int64 ;

var FSC : TFS_Context ;
    _Name : string ;
    UEC : TUnified_Exception ;

begin
    // Setup...
    Result := 0 ;

    // Sanity checks...
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;

    // Get parameter...
    if( name = 0 ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    _Name := trim( Get_String( PSRB( name )^ ) ) ;
    if( _Name = '' ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;

    // Delete the file...
    UEC := FSC.FS.Delete_File( PChar( _Name ) ) ;
    if( ( UEC <> nil ) and ( UEC.Get_Error <> 0 ) ) then
    begin
        Result := UEC.Get_Error ;
        UEC.Detach ;
    end ;
end ; // FS_Delete_File
This method deletes a file from the file system in the FS file. As before, we validate the context, exiting on error. Next we get the name parameter and validate that it isn't a null address or a null string. If null, we exit with an error. Finally, we tell the file system to delete the file and return any errors that result.

function FS_Create_File( Context, Name, Info : int64 ) : int64 ;

var FSC : TFS_Context ;
    _Name : string ;
    _Info : TUOS_File_Info ;

begin
    // Setup...
    Result := 0 ;

    // Sanity checks...
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;

    // Get parameters..
    if( name = 0 ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    _Name := trim( Get_String( PSRB( name )^ ) ) ;
    if( _Name = '' ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    fillchar( _Info, sizeof( _Info ), 0 ) ;
    if( Info <> 0 ) then
    begin
        move( PUOS_File_Info( Info )^, _Info, sizeof( _Info ) ) ;
    end ;

    FSC.FS.Create_File( PChar( _Name ), _Info ) ;
end ; // FS_Create_File
This method creates a new file in the file system in the FS file. Again, we first validate the context. Then we get and validate the name. Finally, we have the file system create the file.

function FS_Open_File( Context, Name, Res : int64 ) : int64 ;

var Fil : TUOS_File ;
    FSC : TFS_Context ;
    _Name : string ;
    UEC : TUnified_Exception ;

begin
    // Setup...
    Result := 0 ;

    // Sanity checks...
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;

    // Get parameters...
    if( name = 0 ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;
    _Name := trim( Get_String( PSRB( name )^ ) ) ;
    if( _Name = '' ) then
    begin
        Result := FS_INVNAME ;
        exit ;
    end ;

    // Open file...
    Fil := FSC.FS.Get_File( PChar( _Name ) ) ;
    if( Fil = nil ) then
    begin
        UEC := FSC.FS.Last_Error ;
        Result := UEC.Get_Error ;
        exit ;
    end ;
    if( Res = 0 ) then
    begin
        Fil.Free ;
    end else
    begin
        PInt64( Res )^ := int64( Fil ) ;
    end ;
end ; // FS_Open_File
This method is used to open a file in a FS file's file system for read/write access. First we validate the context and then the file name. Then we use Get_File to open the file, exiting on error. Finally, we write the instance of the open file to the result address.

function FS_Expand( Context, Size : int64 ) : int64 ;

var FSC : TFS_Context ;
    Increment : int64 ;
    Old_Size : int64 ;

begin
    // Setup...
    Result := 0 ;

    // Sanity checks...
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    if( Size <> 0 ) then
    begin
        Size := Pint64( Size )^ ;
    end ;
    Old_Size := FSC.FS.Store.Max_Storage ;
    if( Size < Old_Size ) then
    begin
        Result := FS_BADSIZE ;
        exit ;
    end ;

    // Expand the file...
    Result := FSC.FS.Expand( Size ) ;
    if( Result <> 0 ) then
    begin
        exit ;
    end ;
    Size := FSC.FS.Store.Max_Storage ;
    if( Size = Old_Size ) then
    begin
        Result := FS_NOCHNG ;
        exit ;
    end ;
end ; // FS_Expand
This method expands the size of a FS file. A file system has a specific size because it exists on a managed store. Managed stores contain an allocation table, which maps used/unused space. Making a store larger will have no effect on the file system unless the allocation table is also made larger. Generally a store will be made the size of the device, or a partition on the device. In the case of a store in a file, however - since the file can be resized - the file system can be expanded.

Reducing the size of a file system is another matter. If a managed store is reduced in size, the allocation table must also be reduced. However, if anything is allocated toward the end of the store, reducing the size of the allocation table could result in data loss. Therefore, we do not support shrinking the size of a file system. To do this, one would need to create a new managed file store of the desired size and then copy data from the old file system to the new one.

The first thing we do is validate the context, and then get and validate the new size value. We exit on error, including trying to make the size smaller than the current size. If Size isn't specified, it is 0 which will always fail with a FS_BADSIZE error. Otherwise, we tell the file system to expand.

function TUOS_Native_File_System.Expand( Size : int64 ) : int64 ;

var Increment, Original : int64 ;
    UEC : TUnified_Exception ;

begin
    // Setup...
    Result := 0 ;  // Assume no errors
    Original := Store.Max_Storage ;
    if( Size < Original ) then
    begin
        exit ; // Cannot shrink - do nothing
    end ;
    Increment := Size div Store.Min_Storage ; // How many clusters
    Increment := ( Increment + 7 ) shr 8 ; // Round up to multiples of 8

    // Resize the store...
    Size := Increment * Store.Min_Storage ; // Convert clusters to bytes
    Store.Set_Size( Size, UEC ) ;
    if( ( UEC <> nil ) and ( UEC.Get_Error <> 0 ) ) then
    begin
        Result := UEC.Get_Error ;
        exit ;
    end ;
    Size := Store.Max_Storage ;
    if( Size <= Original ) then // No change in size
    begin
        exit ;
    end ;

    // Update AT pointer...
    _Header.AT_Offset := Store.Get_Allocation_Table_Offset ;
    _Header.AT_Size := Store.Allocation_Table_Size ;
    Update_Header ;
end ; // TUOS_Native_File_System.Expand
We've added this new method to the TUOS_Native_File_System class. First we get the current size of the store, and adjust the increment in size to round it up to the nearest 8 clusters. This is because the allocation table has a flag for each cluster. Eight clusters is eight bits, or one byte. So, we simply want to make sure the extension to the size doesn't leave unused bits in the allocation table. Mind you, it isn't a problem to have unused bits, but unless one is using a gargantuan clustersize, it won't hurt to make sure all the AT bits are used.

Next we request that the managed store extend to the requested size. Finally, we get the updated allocation table position and size, and update the file system header so we can find the allocation table on the next open of the file system. We do this because likely the allocation table size has changed, and depending upon used space in the file, the location of the allocation table within the file may also have changed. In any case, we update the file system header with the updated allocation table metrics.

function FS_Defragment( Context : int64 ) : int64 ;

var FSC : TFS_Context ;

begin
    // Setup...
    Result := 0 ;

    // Sanity checks...
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    Context := Pint64( Context )^ ;
    if( Context = 0 ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;
    FSC := TFS_Context( Context ) ;
    if( FSC.Sanity <> #3'FSR' ) then
    begin
        Result := FS_INVCONT ;
        exit ;
    end ;

    FSC.FS.Dismount ;
    if( not FSC.FS.Rebuild ) then
    begin
        Result := FSC.FS.Last_Error.Get_Error ;
    end ;
    FSC.FS.Mount( PChar( FSC._Label ), PChar( FSC.Password ), 0 ) ;
end ;
This service validates the context and then tells the file system to rebuild itself. We have to dismount the file system before the rebuild, and then remound it afterwards.

type TFS_Context = class
                       public
                           Sanity : array[ 0..3 ] of char ;
                           FS : TUOS_Native_File_System ;
                           _Label, Password : string ;
                           Flags : integer ;
                   end ;
This class is used for the context in the above services.

type TStore64_To_UOS_File_Bridge = class( TCOM_Store64 )
                           public // Instance data...
                               _File : TCOM_UOS_File ;

                           public { API... }
                               function Is_Class( N : PChar ) : boolean ;
                                   override ; stdcall ;

                               function Read_Data( var Data ; Address, _Size : TStore_Address64 ;
                                   var UEC : TUnified_Exception ) : TStore_Address64 ;
                                   override ; stdcall ;
                               { Read data from specified Address in store to Data.
                                 Read _Size bytes.  Returns success of operation in UEC.
                                 Function returns the number of bytes actually read. }

                               function Write_Data( var Data ; Address, _Size : TStore_Address64 ;
                                   var UEC : TUnified_Exception ) : TStore_Address64 ;
                                   override ; stdcall ;
                               { Write data from Data to specified Address in store.
                                 Write _Size bytes.  Returns success of operation in UEC.
                                 Function returns the number of bytes actually written. }

                               function Max_Storage : TStore_Size64 ;
                                   override ; stdcall ;
                               { Returns the maximum (current) size of the store, in
                                 bytes.  In other words, this is the highest valid
                                 address (plus 1). }

                               function Min_Storage : TStore_Address64 ;
                                   override ; stdcall ;
                               { Returns the minimum atomic size of the store.  For
                                 instance, this would be the sector size for a disk. }

                               function Extend( Amount : TStore_Address64 ) : TStore_Address64 ;
                                   override ; stdcall ;
                               { Requests extension of store by the amount specified.
                                 Returns the amount actually added to store.  If Amount
                                 is 0, function returns 0 if store is extendable, and -1
                                 if it is not. }

                               function Get_Read_Only : boolean ;
                                   override ; stdcall ;
                               { Indicates that the store can only be read from. }

                               function Get_Write_Only : boolean ;
                                   override ; stdcall ;
                               { Indicates that the store can only be written to. }

                               procedure Format ; override ; stdcall ;
                               { Does a low-level format of the store. }

                               function Get_Name : Pchar ;
                                   override ; stdcall ;
                               { Returns name of store. }

                               function Get_Cache : TCOM_Cache64 ;
                                   override ; stdcall ;
                               { Returns current cache object. }

                               procedure Set_Cache( Value : TCOM_Cache64 ) ;
                                   override ; stdcall ;
                               { Sets the current cache object. }

                               function Contiguous_Store : boolean ;
                                   override ; stdcall ;
                               { Returns True if the store's addresses are contiguous
                                 (non-sparse). }

                               procedure Set_Max_Storage( Value : TStore_Address64 ;
                                   var Res : TUnified_Exception ) ;
                                   override ; stdcall ;
                               { Sets the maximum (current) size of the store, in bytes.
                                 In other words, this is the new highest valid address
                                 (plus 1).  If the store is not resizable, the call
                                 fails and an error code is returned in Res.  This should
                                 only be used to shrink the size of the store, not to
                                 extend it.  To extend, use the Extend method. }

                               function Extended_Size : TStore_Address64 ;
                                   override ; stdcall ;
                               { Returns the maximum theoretical size that the store can
                                 be extended to.  If the store is not extendable, this
                                 returns the same value as Max_Storage. }

                               function Get_Bytes_Read : longint ;
                                   override ; stdcall ;
                               function Get_Bytes_Written : longint ;
                                   override ; stdcall ;
                               function Get_Reads : longint ;
                                   override ; stdcall ;
                               function Get_Writes : longint ;
                                   override ; stdcall ;
                               function Get_Error_Count : longint ;
                                   override ; stdcall ;
                               procedure Set_Bytes_Read( Value : longint ) ;
                                   override ; stdcall ;
                               procedure Set_Bytes_Written( Value : longint ) ;
                                   override ; stdcall ;
                               procedure Set_Reads( Value : longint ) ;
                                   override ; stdcall ;
                               procedure Set_Writes( Value : longint ) ;
                                   override ; stdcall ;
                               procedure Set_Error_Count( Value : longint ) ;
                                   override ; stdcall ;
                               procedure Set_Read_Only( Value : boolean ) ;
                                   override ; stdcall ;
                               procedure Set_Write_Only( Value : boolean ) ;
                                   override ; stdcall ;
                               function Get_Verifier : TCOM_Managed_Store64_Debugger ;
                                   override ; stdcall ;
                               procedure Set_Verifier( Value : TCOM_Managed_Store64_Debugger ) ;
                                   override ; stdcall ;
                       end ; // TStore64_To_UOS_File_Bridge


{ API... }

function TStore64_To_UOS_File_Bridge.Is_Class( N : PChar ) : boolean ;

var _N : string ;

begin
    _N := lowercase( string( N ) ) ;
    Result := ( _N = 'tstore64_to_uos_file_bridge' ) ;
end ;


function TStore64_To_UOS_File_Bridge.Read_Data( var Data ; Address,
    _Size : TStore_Address64 ;
    var UEC : TUnified_Exception ) : TStore_Address64 ;

begin
    Result := _File.Read_Data( Data, Address, _Size, UEC ) ;
end ;


function TStore64_To_UOS_File_Bridge.Write_Data( var Data ;
    Address, _Size : TStore_Address64 ;
    var UEC : TUnified_Exception ) : TStore_Address64 ;

begin
    Result := _File.Write_Data( Data, Address, _Size, UEC ) ;
end ;


function TStore64_To_UOS_File_Bridge.Max_Storage : TStore_Size64 ;

begin
    Result := _File.Get_Size ;
end ;


function TStore64_To_UOS_File_Bridge.Min_Storage : TStore_Address64 ;

begin
    Result := 512 ;
end ;


function TStore64_To_UOS_File_Bridge.Extend( Amount : TStore_Address64 ) : TStore_Address64 ;

var Buffer : array[ 0..32767 ] of byte ;
    Count : TStore_Address64 ;
    UEC : TUnified_Exception ;

begin
    fillchar( Buffer, sizeof( Buffer ), 0 ) ;
    Result := 0 ;
    while( Amount > 0 ) do
    begin
        if( Amount > sizeof( Buffer ) ) then
        begin
            Count := sizeof( Buffer ) ;
        end else
        begin
            Count := Amount ;
        end ;
        Result := Result + Write_Data( Buffer, Max_Storage, Count, UEC ) ;
        if( UEC <> nil ) then
        begin
            exit ;
        end ;
        Amount := Amount - Count ;
    end ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Read_Only : boolean ;

begin
    Result := False ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Write_Only : boolean ;

begin
    Result := False ;
end ;


procedure TStore64_To_UOS_File_Bridge.Format ;

begin
end ;


function TStore64_To_UOS_File_Bridge.Get_Name : Pchar ;

begin
    Result := nil ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Cache : TCOM_Cache64 ;

begin
    Result := nil ;
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Cache( Value : TCOM_Cache64 ) ;

begin
end ;


function TStore64_To_UOS_File_Bridge.Contiguous_Store : boolean ;

begin
    Result := False ;
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Max_Storage( Value : TStore_Address64 ;
   var Res : TUnified_Exception ) ;

begin
    Res := nil ;
    _File.Set_Size( Value ) ;
end ;


function TStore64_To_UOS_File_Bridge.Extended_Size : TStore_Address64 ;

begin
    Result := 0 ;
    //todo:return available space on store contaning the file
end ;


function TStore64_To_UOS_File_Bridge.Get_Bytes_Read : longint ;

begin
    Result := 0 ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Bytes_Written : longint ;

begin
    Result := 0 ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Reads : longint ;

begin
    Result := 0 ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Writes : longint ;

begin
    Result := 0 ;
end ;


function TStore64_To_UOS_File_Bridge.Get_Error_Count : longint ;

begin
    Result := 0 ;
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Bytes_Read( Value : longint ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Bytes_Written( Value : longint ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Reads( Value : longint ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Writes( Value : longint ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Error_Count( Value : longint ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Read_Only( Value : boolean ) ;

begin
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Write_Only( Value : boolean ) ;

begin
end ;


function TStore64_To_UOS_File_Bridge.Get_Verifier : TCOM_Managed_Store64_Debugger ;

begin
    Result := nil ;
end ;


procedure TStore64_To_UOS_File_Bridge.Set_Verifier( Value : TCOM_Managed_Store64_Debugger ) ;

begin
end ;
This is the bridge class used in FS_Open, above. We've already seen classes like this, and it is straight-forward, so we won't bother discussing it. But we include it here for completeness. Note: I altered the indentation a bit to make the code fit this page better. Note also there is a "todo" in the code that we will address in the future.

In the next article, we will integrate the help system into an existing utility.