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
201 Mailbox Services
202 Mailboxes, Part 2
203 DEFINE
204 CRELNM
205 DISABLE
206 STOP
207 OPCCRASH and SHUTDOWN
208 APPEND

Glossary/Index


Downloads

LIB_Get_Default_File_Protection and LIB_Substitute_Wildcards

In this article we will we look at two of the new services we've been referencing in the past several articles. First the user documentation and then the code.

LIB_Get_Default_File_Protection

Returns the default file protection mask for a given process.

Format

LIB_Get_Default_File_Protection pid

Arguments

pid
The process ID of the process whose default file protection mask is to be returned. A value of 0 indicates to return the current process default file protection mask.

Description

This service returns the default file protection mask for the specified process. This mask is a set of 4 fields, each 4 bits, which indicate the protection for newly created files. Each field indicates protection for a given type of user: owner, group, system, and world. The fields are layed out in the following order:
TypeAccessBit value (hex)
OwnerRead1
OwnerWrite2
OwnerDelete/Control4
OwnerExecute8
GroupRead10
GroupWrite20
GroupDelete/Control40
GroupExecute80
SystemRead100
SystemWrite200
SystemDelete/Control400
SystemExecute800
WorldRead1000
WorldWrite2000
WorldDelete/Control4000
WorldExecute8000

Condition codes returned
SS_NONEXPR Specified process does not exist.
SS_NORMAL Normal completion of service.


function Get_Default_File_Protection( PID : TPID ) : int64 ;

begin
    Result := 0 ;
    LIB_Get_Default_File_Protection( int64( @PID ), int64( @Result ) ) ;
end ;
This PasStartlet function is a wrapper for the Starlet function.

function LIB_Get_Default_File_Protection( PID, Res : int64 ) : int64 ;

begin
    //TODO: Hard-coded for now
    Result := 0 ;
    if( Res <> 0 ) then
    begin
        pint64( Res )^ := PROTECTION_OWNER_MASK or PROTECTION_SYSTEM_MASK or
            PROTECTION_GROUP_READ or PROTECTION_GROUP_EXECUTE ;
    end ;
end ;
This Starlet function is used to return the default file protection for the passed process. For now, this is simply defaults to O:RWED,S:RWED,G:RE
In the future, we will address how this can be changed.

The question may come to the mind of some readers: why is there a separate READ and EXECUTE protection flag? Isn't execution simply a form of reading? Couldn't someone copy the file (read), mark it as executable and then run it anyway? Though that is true, there is one important consideration: execution of a file is done with the file's privilege mask such that those privileges are active while the file is executing. But a user cannot grant privileges they do not have to any of their files. Thus, they cannot give those privileges to their copy of the file and then run it with said privileges. And if they only have read access to the original file, they cannot run it with it's assigned privileges either. So, though READ and EXECUTE protections usually go hand-in-hand, there are important security reasons for allowing them to be separate.

One other thing of note with file protections. The DELETE protection is also used as a CONTROL protection. The CONTROL concept has no effect on files, but it does have an effect on other system resources which use the file protection flags. The exact effect(s) depend on the resource in question and we will address those as they come up.


LIB_Substitute_Wildcards

Returns a file specification substituting wildcards with defaults and values from a non-wildcard specification.

Format

LIB_Substitute_Wildcards source target defaults result length

Arguments

source
The address of an SRB that points to the source file specification.
target
The address of an SRB that points to the target file specification. This is the specification that can contain wildcards. Note that empty fields are implied "*" wildcards.
defaults
The address of an SRB that points to the default file specification. Any fields missing (null) in the target specification are filled from this specification before the wildcard substitution is done.
result
The address of an SRB that points to the buffer to receive the resulting file specification. The length indicates the maximum size of the buffer, in bytes.
length
The address of a 64-bit integer to receive the actual size of the result. If 0, no size is returned.

Description

This service constructs a result file specification from a source specification, a target (containing wildcards) and a default specification. The default specification is first used to fill any null fields in the target. Wildcard fields are not filled from the default. Next the source specification is used to fill any remaining null fields or wildcards in the target. The result is returned to the specificed buffer. If the buffer is too small to contain the result, as much as will fit is returned and the service returns a SS_BUFFEROVF condition. Note that null fields that are not specified in any of the three specifications will be null in the result. This service does not perform any validation of the file specifications' syntax nor does it check to see if the resulting specification refers to an existing file.

Condition codes returned
SS_NORMAL Normal completion of service.
SS_BUFFEROVF Result buffer was not large enough to fit the entire result specification.


function Substitute_Wildcards( Source, Target, Defaults : string ) : string ;

var SRB_Source, SRB_Target, SRB_Defaults, Res : TSRB ;
    ResLen : int64 ;

begin
    Result := Source + Target + Defaults ;
    Set_String( Result, Res ) ;
    Set_String( Source, SRB_Source ) ;
    Set_String( Target, SRB_Target ) ;
    Set_String( Defaults, SRB_Defaults ) ;
    ResLen := 0 ;
    if( LIB_Substitute_Wildcards( int64( @SRB_Source ), int64( @SRB_Target ),
        int64( @SRB_Defaults ), int64( @Res ), int64( @ResLen ) ) <> 0 ) then
    begin
        Result := '' ;
        exit ;
    end ;
end ;
This function is PasStarlet is a wrapper for the Starlet routine.

function Substitute_Wildcards( Source, Target, Defaults : string ) : string ;

var SRB_Source, SRB_Target, SRB_Defaults, Res : TSRB ;
    ResLen : int64 ;

begin
    Result := Source + Target + Defaults ;
    Set_String( Result, Res ) ;
    Set_String( Source, SRB_Source ) ;
    Set_String( Target, SRB_Target ) ;
    Set_String( Defaults, SRB_Defaults ) ;
    ResLen := 0 ;
    if( LIB_Substitute_Wildcards( int64( @SRB_Source ), int64( @SRB_Target ),
        int64( @SRB_Defaults ), int64( @Res ), int64( @ResLen ) ) <> 0 ) then
    begin
        Result := '' ;
        exit ;
    end ;
end ;
This Paslib function is a Pascal wrapper for LIB_Substitute_Wildcards. The reason for the first assignment is that the resulting string cannot be longer than all three of the source strings, so by appending them together, we get a result buffer that is guaranteed to be long enough to hold the entire result.

function LIB_Substitute_Wildcards( _Source, _Target, _Defaults, _Res,
    Reslen : int64 ) : int64 ;

var Source, Wildcards, Target, Defaults, Res : string ;
    SNode, SAccess, SNode2, SDevice, SPath, SName, SFType, SVersion : string ;
    TNode, TAccess, TNode2, TDevice, TPath, TName, TFType, TVersion : string ;
    DNode, DAccess, DNode2, DDevice, DPath, DName, DFType, DVersion : string ;

begin
    // Setup...
    Result := 0 ; // Assume success
    Source := Get_String( PSRB( _Source )^ ) ;
    Target := Get_String( PSRB( _Target )^ ) ;
    Defaults := Get_String( PSRB( _Defaults )^ ) ;

    // Parse each filespec...
    Parse_Filename( Source, SNode, SAccess, SNode2, SDevice, SPath, SName, SFType, 
        SVersion ) ;
    Parse_Filename( Target, TNode, TAccess, TNode2, TDevice, TPath, TName, TFType, 
        TVersion ) ;
    Parse_Filename( Defaults, DNode, DAccess, DNode2, DDevice, DPath, DName, DFType, 
        DVersion ) ;
This new Starlet function starts by obtaining the parameter strings and then parsing the three specifications.

    // Substitute defaults...
    if( ( TNode = '' ) and ( DNode <> '' ) ) then
    begin
        TNode := DNode ;
    end ;
    if( ( TAccess = '' ) and ( DAccess <> '' ) ) then
    begin
        TAccess := DAccess ;
    end ;
    if( ( TNode2 = '' ) and ( DNode2 <> '' ) ) then
    begin
        TNode2 := DNode2 ;
    end ;
    if( ( TDevice = '' ) and ( DDevice <> '' ) ) then
    begin
        TDevice := DDevice ;
    end ;
    if( ( TPath = '' ) and ( DPath <> '' ) ) then
    begin
        TPath := DPath ;
    end ;
    if( ( TName = '' ) and ( DName <> '' ) ) then
    begin
        TName := DName ;
    end ;
    if( ( TFType = '' ) and ( DFType <> '' ) ) then
    begin
        TFType := DFType ;
    end ;
    if( ( TVersion = '' ) and ( DVersion <> '' ) ) then
    begin
        TVersion := DVersion ;
    end ;
The first step is to substitute any null fields in the target with the values (if any) from the default specification.

    // Now substitute wildcards...
    if( ( TNode = '' ) and ( SNode <> '' ) ) then
    begin
        TNode := SNode ;
    end ;
    TNode := _Substitute( TNode, SNode ) ;
    if( ( TAccess = '' ) and ( SAccess <> '' ) ) then
    begin
        TAccess := SAccess ;
    end ;
    TAccess := _Substitute( TAccess, SAccess ) ;
    if( ( TNode2 = '' ) and ( SNode2 <> '' ) ) then
    begin
        TNode2 := SNode2 ;
    end ;
    TNode := _Substitute( TNode, SNode ) ;
    if( ( TDevice = '' ) and ( SDevice <> '' ) ) then
    begin
        TDevice := SDevice ;
    end ;
    TDevice := _Substitute( TDevice, SDevice ) ;
    if( ( TPath = '' ) and ( SPath <> '' ) ) then
    begin
        TPath := SPath ;
    end ;
    TPath := _Substitute( TPath, SPath ) ;
    if( ( TName = '' ) and ( SName <> '' ) ) then
    begin
        TName := SName ;
    end ;
    TName := _Substitute( TName, SName ) ;
    if( ( TFType = '' ) and ( SFType <> '' ) ) then
    begin
        TFType := SFType ;
    end ;
    TFType := _Substitute( TFType, SFType ) ;
    if( ( TVersion = '' ) and ( SVersion <> '' ) ) then
    begin
        TVersion := SVersion ;
    end ;
    TVersion := _Substitute( TVersion, SVersion ) ;
Next we go through each field, doing the substitution for each one.

    // Build result string...
    Res := TNode + TAccess + TDevice + TName + TFType + TVersion ;
    if( length( Res ) > PSRB( _Res )^.Length ) then
    begin
        setlength( Res, PSRB( _Res )^.Length ) ;
        Result := UOSErr_Buffer_Overflow ;
    end ;

    // Return results...
    if( ResLen <> 0 ) then
    begin
        pint64( Reslen )^ := length( Res ) ; // Return actual result length
    end ;
    move( PChar( Res )[ 0 ], PChar( PSRB( _Res )^.Buffer )[ 0 ], length( Res ) ) ;
end ; // LIB_Substitute_Wildcards
Next, we build the new result specification from the individual fields. If this is longer than the size of the result buffer, we truncate the result and set the buffer overflow notice. Finally, we update the result length if an address was provided, and then write the result value.

    function _Substitute( T, S : string ) : string ;

    begin
        if( ( T = '' ) or ( T = '*' ) ) then
        begin
            Result := S ;
        end else
        begin
            Result := T ;
        end ;
    end ;
This local function does the actual substitution for us. As noted in a previous article, this only does the substitution if the result field is a "*" wildcard or null (an implied wildcard). We may enhance this in the future.

In the next article, We will look at some more system services.