RPG-ILE - Converting Decimal to Octal values for STAT function
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 for you to retrieve the information needed to determine 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 = 17924 => return '------r--'; st_Mode = 32776 => return '-----x---'; etc
To make the process easier, 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: [1]
*======================================================================* * 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 permissions have been determined as per this url: [2]
*======================================================================* * Subroutine.... RetrievAuthority * * 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);