RPG-ILE - Converting Decimal to Octal values for STAT function

From MidrangeWiki
Jump to: navigation, search

Background

When you extract data with the STAT function from IFS objects, it returns a lot of information. Unfortunately, it becomes difficult to always tie that information to what you will see on the screen. One of the challenges I had was to write program in RPG that pulled information out similar to the QRYIFSLIB freeware tool. The problem came in when I wanted to know what permissions were loaded on the file or directory. This procedure will show:

- how you can translate the value received from stat for the file mode into an octal value 
- How to tie the octal value to the permissions


Problem definition

When you run the stat function on an IFS object, one of the very first fields (usually named st_mode) returns a decimal value. The value corresponds to the actual permissions on the file. However, since it is retrieved as a decimal value, it involves having a large number of permutations to make up the rwxrwxrwx permission structure. For example:

I have the following files with their respective permissions in an IFS directory:

----------   Jan 25 17:06 testfile1  
---x------   Jan 25 17:11 testfile10 
-rw-------   Jan 26 09:38 testfile11 
-rwx------   Jan 26 09:38 testfile12 
-r-x------   Jan 26 09:38 testfile13 
--wx------   Jan 26 09:38 testfile14 
----rw----   Jan 26 09:38 testfile15 

The permissions list here will each correspond to a specific decimal number:

st_Mode = 32768 => return '---------';
st_Mode = 32769 => return '--------x';
st_Mode = 32770 => return '-------w-';
st_Mode = 32776 => return '-----x---';
etc


To complicate it further, the decimal value for directories and other types of IFS objects (link symbolic links), also have different sets of numbers. In the end, if you want to program for each and every permutation, it will become a very complex and large program.


The permission structure on the IFS is shown on the screen as drwxrwxrwx, and is divided into 4 groups. See this link for more info: [1]

- Position 1 - Usually indicate special permissions, such as "d" for directory, "l" for symbolic link, etc.
- Positions 2 to 4 - Is the owner of the object's permissions
- Positions 5 to 7 - Is for the permissions of the group
- Positions 8 to 10 - Is for the permissions of everyone (or *PUBLIC as we use it on the IBMi platform)


For the permissions of my program, I am not interested in the position 1 value, just in positions 2 to 10. The octal value for each authority is:

0 = No Permission
1 = Execute
2 = Write
4 = Read


You determine the permissions by adding the values together, where 7 will imply all authority has been selected, and 0 will imply no authority selected. Example if the owner has read and write authority to the object, it will be 4+2 to give an octal value of 6 for the permissions, etc.


For each block, if you want to know what permissions has been enable, the octal value will return values in the format XXX, where each of the 3 positions determine whether it is for owner, group or public. If the IFS object has a value of 777 for its octal value, then it means the object has rwxrwxrwx for all 3 portions. A value of 500, will be r-x------, and a value of 744 will be rwxr--r--.


To make the process easier to determine the permissions, I have written a DecimalToOctal function that takes the st_mode value, translates it into octal, and then determine the correct permissions. It has been based on method 2 as described on this link: [2]


     *======================================================================*    
     *  Subroutine.... DecimalToOctal                                       *    
     *  Description... Take the st_mode decimal value and return an octal value* 
     *======================================================================*    
       dcl-proc DecimalToOctal;                                                  
       dcl-pi DecimalToOctal                 int(10);                         
               p_St_Mode                     int(10) value;                   
       end-pi;                                                                   
       //                                                                        
           dcl-s OctalVal                    char(15);                           
           dcl-s WorkField1                  int(10);                             
           dcl-s WorkField2                  int(10);                            
           dcl-s WorkField3                  int(10);                                 
           dcl-s LoopCount                   int(10);                                
           dcl-s OctalPosition               int(10);                                
       //                                                                        
           OctalPosition = 15;  // will start at the right side                  
           WorkField3 = p_St_Mode;                                               
           DoU WorkField3 = 0;                                                   
               WorkField1 = %div(WorkField3:8);                                  
               WorkField2 = WorkField3 - (8 * WorkField1);              
               %subst(OctalVal:OctalPosition:1) = %char(WorkField2);    
               OctalPosition -= 1;                                      
               WorkField3 = WorkField1;                                 
           EndDo;                                                       
           Return %Int(OctalVal);                                       
       End-proc;                                                        

The next step will be to use this returned value in a subprocedure to determine the correct permissions. The last 3 digits of the returned octal value is used, you can ignore the other digits.


     *======================================================================* 
     *  Subroutine.... RetrieveAuthority                                    * 
     *  Description... Take the st_mode value and return an RWX-based string* 
     *======================================================================* 
       dcl-proc RetrieveAuthority;                                            
       dcl-pi RetrieveAuthority              char(10);                        
               p_St_Mode                     int(10) value;                   
       end-pi;                                                                
       //                                                                     
           dcl-s OctalChar                   char(15);                        
           dcl-s OctalLength                 int(10);                         
           dcl-s PermissionList              char(9) inz('---------');        
           dcl-s OctalVal                    int(10);                         
       //                                                                     
           OctalVal =  DecimalToOctal(p_st_mode);                             
           OctalChar = %char(OctalVal);                                       
           OctalLength = %len(%trim(OctalChar));                              
       //      
       // Determine the owner permissions here                                                               
           Select;                                                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '7';             
              %subst(PermissionList:1:3) = 'rwx';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '6';             
              %subst(PermissionList:1:3) = 'rw-';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '5';             
              %subst(PermissionList:1:3) = 'r-x';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '4';             
              %subst(PermissionList:1:3) = 'r--';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '3';             
              %subst(PermissionList:1:3) = 'rw-';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '2';             
              %subst(PermissionList:1:3) = '-w-';                            
           When %subst(%trim(OctalChar):OctalLength - 2:1) = '1';             
              %subst(PermissionList:1:3) = '--x';                            
           Other;                                                             
              %subst(PermissionList:1:3) = '---';                            
          EndSl;                                                             
          // Determine the group permissions here                                                                
          Select;                                                            
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '7';             
              %subst(PermissionList:4:3) = 'rwx';                            
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '6';             
              %subst(PermissionList:4:3) = 'rw-';                     
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '5';      
              %subst(PermissionList:4:3) = 'r-x';                     
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '4';      
              %subst(PermissionList:4:3) = 'r--';                     
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '3';      
              %subst(PermissionList:4:3) = 'rw-';                     
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '2';      
              %subst(PermissionList:4:3) = '-w-';                     
           When %subst(%trim(OctalChar):OctalLength - 1:1) = '1';      
              %subst(PermissionList:4:3) = '--x';                     
           Other;                                                      
              %subst(PermissionList:4:3) = '---';                     
          EndSl;                                                      
          // Determine the *PUBLIC permissions here
          Select;                                                     
           When %subst(%trim(OctalChar):OctalLength:1) = '7';          
              %subst(PermissionList:7:3) = 'rwx';                     
           When %subst(%trim(OctalChar):OctalLength:1) = '6';          
              %subst(PermissionList:7:3) = 'rw-';                     
           When %subst(%trim(OctalChar):OctalLength:1) = '5';          
               %subst(PermissionList:7:3) = 'r-x';                         
           When %subst(%trim(OctalChar):OctalLength:1) = '4';              
               %subst(PermissionList:7:3) = 'r--';                         
           When %subst(%trim(OctalChar):OctalLength:1) = '3';              
               %subst(PermissionList:7:3) = 'rw-';                         
           When %subst(%trim(OctalChar):OctalLength:1) = '2';              
               %subst(PermissionList:7:3) = '-w-';                         
           When %subst(%trim(OctalChar):OctalLength:1) = '1';              
               %subst(PermissionList:7:3) = '--x';                         
           Other;                                                          
               %subst(PermissionList:7:3) = '---';                         
          EndSl;                                                          
          Return PermissionList;                                          
       End-proc;                                         

In order to use this in your program, do the following:

- Declare your permission variable

 dcl-s Permissions   char(9);

- Run your stat process against the IFS object itself

- Call the subprocedure to determine the permissions

 Permissions = RetrieveAuthority(st_mode);


Examples

Example 1:

Running the RetrieveAuthority process on a decimal value of 33279 will return an octal value of 100777.  Using this process will use the last 3 digits (777) and assign permissions as "rwxrwxrwx".


Example 2:

Running the RetrieveAuthority process on a decimal value of 33205 will return an octal value of 100665.  Using this process will use the last 3 digits (665) and assign permissions as "rw-rw-r-x".


Example 3:

Running the RetrieveAuthority process on a decimal value of 32800 will return an octal value of 100040.  Using this process will use the last 3 digits (040) and assign permissions as "---r-----".