Read out FILEDIR.SAG on Open Systems

Hello all!

Last month I wrote a program to read out FILEDIR.SAG. It was useful to get the name of the programmers which did the last save and/or catalog on a module plus the date of the regarding event. The program is tested on Windows XP and Solaris 8.

One questions remains: What do all the fields mean, which I marked with question marks? Any ideas?

*
* Read out FILEDIR.SAG on Open Systems
* ************************************
*
define data local
01 #options
  02 filedir     (A)  DYNAMIC const
*
* uncomment the following line for an example on Solaris
* <'/sag/nat/fuser/SYSTEM/FILEDIR.SAG'>
*
* uncomment the following line for an example on windows
<'C:\Programme\Software AG\Natural\Natapps\Fuser\SYSTEM\FILEDIR.SAG'>
*
01 #header136            (B136)      /* for SUN_SOLA
01 redefine #header136
  02 STRUCTURE                       /* for move by name
    03 NUMBER_OF_MODULES (I02)       /* Number of modules in FILEDIR.SAG
    03 unknown_01        (I02)       /* ???? always 1
    03 unknown_02        (A08)       /* ???? always space
    03 unknown_03        (B04)       /* ???? always H'00530000'
    03 unknown_04        (I04)       /* ???? always 0
    03 unknown_05        (I04)       /* ???? always 0 /* missed on Windows
    03 unknown_06        (I04)       /* ???? always 1
    03 unknown_07        (I04)       /* ???? always 1
    03 HEADER_SIZE       (I04)       /* Size of Header in Bytes
    03 LINE_SIZE         (I04)       /* Size of Line in Bytes
    03 unknown_08        (I04)       /* ???? always 0 /* missed on Windows
    03 CHANGE_COUNTER    (I04)       /* Number of changes (stow = +2)
    03 unknown_09        (I04/1:22)  /* ???? always 0
*
01 #header116            (B116)      /* for WNT-X86 and LINUX
01 redefine #header116
  02 STRUCTURE                       /* for move by name
    03 NUMBER_OF_MODULES  (I02)      /* Number of modules in FILEDIR.SAG
    03 unknown_01         (I02)      /* Size of Header in Bytes
    03 unknown_02         (A08)
    03 unknown_03         (B04)
    03 unknown_04         (I04)
    03 unknown_06         (I04)
    03 unknown_07         (I04)
    03 HEADER_SIZE        (I04)      /* Size of Header in Bytes
    03 LINE_SIZE          (I04)      /* Size of Line in Bytes
    03 CHANGE_COUNTER     (I04)
    03 unknown_09         (I04/1:19)
*
01 #line                  (B288)
01 redefine #line
  02 LINE_TYPE          (I04)
*           /* 1 = normal
*           /* 2 = assignment long names to short names for Subroutines
*           /* 5 = assignment long names to short names for Classes
*           /* 6 = assignment long names to short names for Functions
  02 MODULE_LONG        (A32)    /* long names for subroutine etc.
  02 unknown_01         (I04)    /*    ???? always 0
  02 unknown_02         (I04)    /*    ???? always 0
  02 MODULE             (A08)    /* short module name on filesystem
  02 unknown_03         (I04)    /*    ???? always 0
  02 SUB_TYPE           (I04)    /*    ???? probably
*                                /* 1 = normal
*                                /* 3 = Dialog with OCX
*                                /* 5 = new Source-Format of DDM
  02 unknown_04         (I04)    /*    ???? always 1
  02 MODULE_TYPE        (I04)
*                                /* decimal value of character, e.g.
*                                /* 65 --> "A" --> Parameter
*                                /* 67 --> "C" --> Copycode
  02 DDM_DBID           (I04)
  02 DDM_FILE_NO        (I04)
  02 MODE               (I04)    /* 0 = REPORT, 1 = STRUCTURED
  02 SOURCE_CATALOG     (I04)
*                                /* 1 = only source available
*                                /* 2 = only catalog available
*                                /* 3 = both available
  02 SOURCE_USER_ID     (A08)
  02 unknown_05         (I04)      /*    ???? always 0
  02 SOURCE_SIZE        (I04)
  02 SOURCE_DATE_DAY    (I04)
  02 SOURCE_DATE_MONTH  (I04)
  02 SOURCE_DATE_YEAR   (I04)      /* sometimes only the last 2 digits
  02 SOURCE_DATE_HOUR   (I04)
  02 SOURCE_DATE_MIN    (I04)
  02 unknown_06         (I04/1:8)  /*    ???? always 0
  02 CATALOG_USER_ID    (A08)
  02 unknown_07         (I04)      /*    ???? always 0
  02 CATALOG_SIZE       (I04)
  02 CATALOG_DATE_DAY   (I04)
  02 CATALOG_DATE_MONTH (I04)
  02 CATALOG_DATE_YEAR  (I04)      /* sometimes only the last 2 digits
  02 CATALOG_DATE_HOUR  (I04)
  02 CATALOG_DATE_MIN   (I04)
  02 unknown_08         (I04/1:25) /*    ???? always 0
*
01 #line_type2           (B288)
01 redefine #line_type2
  02 LINE_TYPE          (I04)
  02 MODULE_LONG        (A32)
  02 unknown_01         (I04)      /*    ???? always 0
  02 MODULE             (A08)
  02 unknown_02         (I04/1:60) /*    ???? always 0
*
01 #header
  02 NUMBER_OF_MODULES  (I02)
  02 HEADER_SIZE        (I04)
  02 LINE_SIZE          (I04)
  02 CHANGE_COUNTER     (I04)
*
end-define
*
define work file 1 #options.filedir type 'UNFORMATTED'
*
reset #header
*
decide on first value of *OPSYS
*
  value 'SUN_SOLA'  /* --> read first 136 Bytes as a header
    read work file 1 once #header136
    move by name #header136.STRUCTURE to #header
    if #header.header_size ne 136
      write 'invalid header size for OPSYS' *OPSYS
      stop
    end-if
*
  value 'WNT-X86'   /* --> read first 116 Bytes as a header
    read work file 1 once #header116
    move by name #header116.STRUCTURE to #header
    if #header.header_size ne 116
      write 'invalid header size for OPSYS' *OPSYS
      stop
    end-if
*
  none value
    write 'operating system' *OPSYS 'not supported'
    stop
*
end-decide
*
write nohdr
  'HEADER INFORMATION' /
  '----------------------------------' /
  'Number of Modules    :' 6X #header.NUMBER_OF_MODULES /
  'HEADER_SIZE in Bytes :'    #header.HEADER_SIZE     /
  'LINE_SIZE in Bytes   :'    #header.LINE_SIZE       /
  'CHANGE_COUNTER       :'    #header.CHANGE_COUNTER
*
NEWPAGE
*
if #header.line_size ne 288
  write 'invalid line size' #header.line_size
  stop
end-if
*
read work file 1 #line
*
  decide on first value of #line.LINE_TYPE
    value 1
      perform display_linetype1
*
    value 2,5,6
      move #line    to #line_type2
      write #line_type2.MODULE_LONG '-->' #line_type2.MODULE
*
    none value
      write 'invalid linetype' #line.LINE_TYPE 'detected'
      stop
  end-decide
*
  SKIP 1

end-work
*
close work file 1
*
*
DEFINE SUBROUTINE DISPLAY_LINETYPE1
*
display
*   '='         #line.LINE_TYPE
*   '='         #line.SUB_TYPE
*   '='         #line.MODULE_LONG
  '='         #line.MODULE             /
  'TYPE'      #line.MODULE_TYPE
  '='         #line.DDM_DBID           /
  '='         #line.DDM_FILE_NO
  '='         #line.MODE               /
  'SRC+CAT'   #line.SOURCE_CATALOG
  'SRC-USER'  #line.SOURCE_USER_ID     /
  'CAT-USER'  #line.CATALOG_USER_ID
  'SRC-SIZE'  #line.SOURCE_SIZE        /
  'CAT-SIZE'  #line.CATALOG_SIZE
*    'SRC-DAY'   #line.SOURCE_DATE_DAY    /
*    'CAT-DAY'   #line.CATALOG_DATE_DAY
*    'SRC-MONTH' #line.SOURCE_DATE_MONTH  /
*    'CAT-MONTH' #line.CATALOG_DATE_MONTH
  'SRC-YEAR'  #line.SOURCE_DATE_YEAR   /
  'CAT-YEAR'  #line.CATALOG_DATE_YEAR
*    'SRC-HOUR'  #line.SOURCE_DATE_HOUR   /
*    'CAT-HOUR'  #line.CATALOG_DATE_HOUR
*    'SRC-MIN'   #line.SOURCE_DATE_MIN    /
*    'CAT-MIN'   #line.CATALOG_DATE_MIN
*
END-SUBROUTINE /* DISPLAY_LINE
*
end

If this doesn’t cross the line, then it comes dangerously close to “reverse engineering,” which is contrary to the SAG license agreement.

It’s almost like creating DDMs for the MF FUSR/FNAT and reading those files directly instead of using the supplied APIs, but I’m sure no one has ever done that :wink:

If it’s already in human-readable form I’m not sure it would be concidered reverse engineering since there isn’t anything to reverse, it’s just formatting… although since there are I and B format fields being used the output does need to be translated somewhat.

It would be interesting to hear what the “official” response would be.

Just wondering, why putting that much effort into it when USR0330N does just the same thing out of the box ?

… and there are much more in SYSEXT: search for keyword FUSER!

@Ralph Zbrog: Reverse engineering? No I’m not that good! If you hexdump the FILEDIR.SAG you can almost read it like a newspaper. :wink:
But if this is treated as reverse engineering by SAG, I will delete this post immediately.

@Wolfgang Winter: I promise: I’ve searched for that in SYSEXT approx. half an hour. I thought about using USR1057N for that, but it was way to slow for my over 10.000 modules to list. So I thougt it is easier to read out FILEDIR.SAG by myself.

And to be honest: I didn’t read out FILEDIR.SAG the first time, so it doesn’t take that much time to do a “quick Natural hack”. About two years ago, we got a problem with unreadable FILEDIR.SAG on NFS-Mounted devices (between Linux and Windows). At that time, the Software AG couldn’t help us immediately. But that problem became obsolete by installing the Natural Development server.

After your tips and hints I tried to solve the problem just using SYSEXT-Modules. I just want to learn … :wink:
But then I realized, that USR0330 doesn’t ouput DDM-Modules. So I tried to get the DDM-Information from anywhere else. But USR1056N doesn’t deliver user and time information. Any ideas to solve that?

Here’s my try:

/* USR0330P - Get NATURAL Object Directory Information
/*******************************************************************
/*  This program serves as example how to design a user-defined
/*  program to call 'USR0330N'
/*******************************************************************
DEFINE DATA LOCAL
1 #CBDIR               (B94)
1 REDEFINE #CBDIR
  2 FILLER             1X
  2 #CBDIR-OPT2        (A01)
  2 #CBDIR-RSP1        (I02)
  2 #CBDIR-RSP2        (I02)
  2 FILLER             20X
  2 #CBDIR-NAME        (A64)
  2 REDEFINE #CBDIR-NAME
    3 #CBDIR-NLIB      (A08)
    3 #CBDIR-NNAM      (A08)
  2 #CBDIR-DBID        (B02)
  2 REDEFINE #CBDIR-DBID
    3 #CBDIR-DBID-H    (B01)
    3 #CBDIR-DBID-L    (B01)
  2 #CBDIR-FNR         (B02)
  2 REDEFINE #CBDIR-FNR
    3 #CBDIR-FNR-H     (B01)
    3 #CBDIR-FNR-L     (B01)
/*
1 #DIR-OB1             (B100/1:3)        /*  saved object directory
1 REDEFINE #DIR-OB1
  2 NATVERSM           (A4)
  2 NATVER             (A4)
  2 NATSM              (A4)
  2 REDEFINE NATSM
    3 NATSMN           (N4)
  2 USERID             (A8)
  2 TID                (A8)
  2 TIME               (A8)
  2 DATE               (A8)
  2 OBJ-TYPE           (A1)   /* Internal object type ('F' is 'Program')
  2 OBJ-LONGNAME       (A11)
  2 DIR-STATE          (A12)
  2 CREATE-LIB         (A8)
  2 CREATE-OBJ-NAME    (A8)
  2 TERM-USER          (A8)
  2 SA-SIZE            (I4)
  2 REC-SIZE           (I2)
  2 DEV-MODE           (A15)
  2 SAV-CAT-DATE-TIME  (T)
  2 OP-SYSTEM          (A8)
  2 TP-SYSTEM          (A8)
  2 TA-NAME            (A8)
  2 VCS-IAPPLID        (A8)
  2 REDEFINE VCS-IAPPLID
    3 APPL-ID          (B2)
    3 APPL-VER         (B2)
    3 CNTL-VER         (B2)
    3 OBJ-VER          (B2)
  2 AIV-LENGTH         (I4)
  2 BP-SIZE            (I4)
  2 U-SIZE             (I2)
  2 INV-SUBTAB         (I2)
  2 DEF-SUBTAB         (I2)
  2 TURBO-CODE         (A3)
  2 RECAT-POSS         (A3)
  2 OBJ-RELINKED       (A3)
  2 TIMESTMP           (B8)
  2 TURBO-CODE-LEN     (I4)
  2 GDA-SIZE           (I2)
  2 NUM-SUBR           (I2)
  2 NUM-GDA            (I2)
  2 NUM-REP            (I2)
  2 NUM-WFILE          (I2)
/*
1 #DIR-OB2             (B100/1:3)        /* cataloged object directory
1 REDEFINE #DIR-OB2
  2 NATVERSM           (A4)
  2 NATVER             (A4)
  2 NATSM              (A4)
  2 REDEFINE NATSM
    3 NATSMN           (N4)
  2 USERID             (A8)
  2 TID                (A8)
  2 TIME               (A8)
  2 DATE               (A8)
  2 OBJ-TYPE           (A1)   /* Internal object type ('F' is 'Program')
  2 OBJ-LONGNAME       (A11)
  2 DIR-STATE          (A12)
  2 CREATE-LIB         (A8)
  2 CREATE-OBJ-NAME    (A8)
  2 TERM-USER          (A8)
  2 SA-SIZE            (I4)
  2 REC-SIZE           (I2)
  2 DEV-MODE           (A15)
  2 SAV-CAT-DATE-TIME  (T)
  2 OP-SYSTEM          (A8)
  2 TP-SYSTEM          (A8)
  2 TA-NAME            (A8)
  2 VCS-IAPPLID        (A8)
  2 REDEFINE VCS-IAPPLID
    3 APPL-ID          (B2)
    3 APPL-VER         (B2)
    3 CNTL-VER         (B2)
    3 OBJ-VER          (B2)
  2 AIV-LENGTH         (I4)
  2 BP-SIZE            (I4)
  2 U-SIZE             (I2)
  2 INV-SUBTAB         (I2)
  2 DEF-SUBTAB         (I2)
  2 TURBO-CODE         (A3)
  2 RECAT-POSS         (A3)
  2 OBJ-RELINKED       (A3)
  2 TIMESTMP           (B8)
  2 TURBO-CODE-LEN     (I4)
  2 GDA-SIZE           (I2)
  2 NUM-SUBR           (I2)
  2 NUM-GDA            (I2)
  2 NUM-REP            (I2)
  2 NUM-WFILE          (I2)
  2 DUMMY              (A10)
  2 GDA-NAME           (A8)
*
01 #USR1033
   02 DBID         (N05)      /* DBID of FDIC
   02 FNR          (N05)      /* File number of FDIC
   02 PASSWORD     (A08)      /* Password of FDIC
   02 CIPHERCODE   (B08)      /* Ciphercode of FDIC
   02 DDM-NAME     (A32)      /* Name of the DDM
   02 RESPONSE     (N04)      /* Error code
   02 DDM-DBID     (N05)      /* DBID of DDM
   02 DDM-FNR      (N05)      /* File number of DDM
   02 DDM-TYPE     (A01)      /* Type of DDM
   02 VSAM-SUBTYPE (A01)      /* Subtype of VSAM DDM
   02 FILE-NAME    (A08)      /* Used by VSAM, ISAM, LEASY
*
END-DEFINE
*******************************************************************
*
ASSIGN #CBDIR-OPT2 = 'N'   /* Search objects starting with #CBDIR-NNAM
ASSIGN #CBDIR-NNAM = '!'   /* next character after space (space doesn't work)
*
ASSIGN #CBDIR-NLIB = *LIBRARY-ID
*
ASSIGN #USR1033.DBID := 90
ASSIGN #USR1033.FNR  := 91
*
repeat
  CALLNAT 'USR0330N' #CBDIR #DIR-OB1 (*) #DIR-OB2 (*)
*
  IF #CBDIR-RSP1 NE 0 AND #CBDIR-RSP2 NE 0
    ESCAPE BOTTOM
  END-IF
*
* Get DDM-DBID and DDDM-FNR here --> no DDM delivered!
* #USR1033.DDM-NAME := ????
* CALLNAT 'USR1033N' #USR1033
*
  display
    'MODULE'      #CBDIR-NNAM  /
    'TYPE'        #DIR-OB1.OBJ-LONGNAME
    '='           #USR1033.DDM-DBID           /
    '='           #USR1033.DDM-FNR
    'MODE'        #DIR-OB1.DEV-MODE               /
    'CATALOGUED?' #CBDIR-RSP2
    'SRC-USER'    #DIR-OB1.USERID /
    'CAT-USER'    #DIR-OB2.USERID
    'SRC-SIZE'    #DIR-OB1.SA-SIZE /
    'CAT-SIZE'    #DIR-OB2.BP-SIZE
    'SRC-DATE'    #DIR-OB1.DATE   /
    'CAT-DATE'    #DIR-OB2.DATE
*
  skip 1
*
end-repeat
*
* Initiate a USR1056N-Loop here?
* --> not possible to get USER/TIME Information via USR0330N
*
END

All things must change :slight_smile:

Natural 6.2.2 has a new Structure for the FILEDIR.SAG. I adjust the code from Matthias to process 6.2.2-files and i tried to use a class oriented approach.

The result is shown below (it is the load-Method for the FileDir-Class):


define data
Parameter
1 #pobjColl   Handle of Object  /* SAG.Global.Collection
1 #pobjParameter Handle of Object  /* SOS.Nat.FileDir
* <usercode name="oda" class='SOS.Nat.FileDir' >
* Object using oFileD
* Object using oClsDflt /* Interface iSAGClassDefault
* </usercode> <!-- name="oda" class='SOS.Nat.FileDir' -->
*
Local using oFileDir
local using def-test
*
* <usercode name="localdata" >
Local
1 #objCollection handle of object  /* SAG.Global.Collection
1 #objI       handle of object  /* SOS.Nat.FileDir
1 #ISN (P10)
1 #flgEscape (L)
*
Local
1 #iCount (i4)
1 #objTemp Handle of Object
1 #strName (a8)
*
1 #DateAndTime (A14)
1 Redefine #DateAndTime
2 #YYYY (a4)
2 #DateWithoutYear (A10)
2 Redefine #DateWithoutYear
3 #MM (a2)
3 #DD (a2)
3 #HH (A2)
3 #II (A2)
3 #SS (A2)
Local
1 #objFileDir Handle of Object  /* SAG.IO.File
1 #flgT (l)
1 #I (i4)
* change it to your requirements
1 filedirPath (A256) init <'/sag/shr/fuser/'>
1 filedirLib (A256)
1 filedirFile (A11)  const <'FILEDIR.SAG'>
*
1 #FileDirSAGName (A256)
1 #FileDirXMLName (A256)
1 #sav-Date (A20)
1 #cat-Date (A20)
*
1 #header80 (B80) /* Nat6.2.2
1 Redefine #header80
2 Structure
3 #text (a4)
3 #Filler-1 (i4/1:5)
3 Number_of_Modules (i4)
3 #Text2 (a8)
3 #Filler-2 (i4/1:4)
3 Header_Size (i4)
3 Line_Size (i4)
3 CHANGE_COUNT (I4)  /* Number of changes (stow = +2)
*
1 #header136 (B136)
1 redefine #header136
2 STRUCTURE
3 NUMBER_OF_MODULES (I02) /* Number of modules in FILEDIR.SAG
3 f_01 (I02)
3 f_02 (A08)
3 f_03 (B04)
3 f_04 (I04)
3 f_05 (I04)
3 f_06 (I04)
3 f_07 (I04)
3 HEADER_SIZE (I04) /* Size of Header in Bytes
3 LINE_SIZE (I04) /* Size of Line in Bytes
3 f_08 (I04)
3 CHANGE_COUNTER (I04) /* Number of changes on SRC and GP
3 f_09 (I04/1:22)
*
1 #header116 (B116)  /* for WNT-X86 and LINUX
1 redefine #header116
2 STRUCTURE
3 NUMBER_OF_MODULES (I02)  /* Number of modules in FILEDIR.SAG
3 f_01 (I02)
3 f_02 (A08)
3 f_03 (B04)
3 f_04 (I04)
3 f_06 (I04)
3 f_07 (I04)
3 HEADER_SIZE (I04)  /* Size of Header in Bytes
3 LINE_SIZE (I04)  /* Size of Line in Bytes
3 CHANGE_COUNTER (I04)
3 f_09 (I04/1:19)
*
1 #l (B312) /* Nat 6.2.2
1 redefine #l
2 Structure
3 LINE_TYPE (I4)
3 MODULE_LONG (A32)  /* long names for subroutine etc.
3 f_02 (I4)
3 MODULE (a8) /* short module name on filesystem
3 f_03 (I4)
3 f_030 (I4)
3 SUB_TYPE (I4)
*  /* 1 = normal
*  /* 3 = Dialog with OCX
*  /* 5 = new Source-Format of DDM
3 f_04 (I4)
3 MODULE_TYPE (I4) /* internal Object Type:
3 Redefine Module_Type
4 Filler-MT (B3)
4 ModuleTypeA (a1)
3 DDM_DBID (I4)
3 DDM_FILE_NO (I4)
3 MODE (I4) /* 0 = REPORT, 1 = STRUCTURED
3 Src_CATALOG (I4)
*  1 = source only, 2 = catalog only, 3 = both available
3 Src_SIZE (I4)
3 SD_YEAR (I4) /* sometimes only the last 2 digits
3 SD_MONTH (I4)
3 SD_DAY (I4)
3 SD_HOUR (I4)
3 SD_MIN (I4)
3 SD_Secnds (I4) /*    ???? always 0  nat622
3 Src_USER_ID (a8)
3 f_07 (I4) /*    ???? always 0
3 Cat_SIZE (I4)
3 Cat_DATE_YEAR (I4) /* sometimes only the last 2 digits
3 Cat_DATE_MONTH (I4)
3 Cat_DATE_DAY (I4)
3 Cat_DATE_HOUR (I4)
3 Cat_DATE_MIN (I4)
3 Cat_Date_Secnds (I4)
3 Cat_USER_ID (a8)
*
1 #l-old (B288)
1 redefine #l-old
2 Structure
3 LINE_TYPE (I04)
3 MODULE_LONG (A32)  /* long names for subroutine etc.
3 f_01 (I04)
3 f_02 (I04)
3 MODULE (A08)  /* short module name on filesystem
3 f_03 (I04)
3 SUB_TYPE (I04)
*  1 = normal, 3 = Dialog with OCX, 5 = new Source-Format of DDM
3 f_04 (I04)
3 MODULE_TYPE (I04)
3 DDM_DBID (I04)
3 DDM_FILE_NO (I04)
3 MODE (I04)  /* 0 = REPORT, 1 = STRUCTURED
3 Src_CATALOG (I04)
3 Src_USER_ID (A08)
3 f_05 (I04)
3 Src_SIZE (I04)
3 SD_DAY (I04)
3 SD_MONTH (I04)
3 SD_YEAR (I04)  /* sometimes only the last 2 digits
3 SD_HOUR (I04)
3 SD_MIN (I04)
3 f_06 (I04/1:8)
3 Cat_USER_ID (A08)
3 f_07 (I04)
3 Cat_SIZE (I04)
3 Cat_DATE_DAY (I04)
3 Cat_DATE_MONTH (I04)
3 Cat_DATE_YEAR (I04)  /* sometimes only the last 2 digits
3 Cat_DATE_HOUR (I04)
3 Cat_DATE_MIN (I04)
3 f_08 (I04/1:25)
*
1 #l_type2 (B312)
1 redefine #l_type2
2 LINE_TYPE (I4)
2 MODULE_LONG (A32)
2 f_01 (I4)
2 MODULE (a8)
2 f_02 (I4/1:60)
*
1 #header
2 NUMBER_OF_MODULES (I2)
2 HEADER_SIZE (I4)
2 LINE_SIZE (I4)
2 CHANGE_COUNT (I4)
*
end-define
Send Method 'Clear' to #pobjColl
FileDirLib := #pobjParameter.LibraryName
*
Perform LoadData
*
Define Subroutine LoadData
* <usercode name="loaddata">
Compress filedirPath filedirLib  '/' filedirFile into #FileDirSAGName leaving no space
*
create object #objFileDir of Class 'SAG.IO.FILE'
#objFileDir.FileName := #FileDirSAGName
send 'Exist' to #objFileDir with #flgT
if not #flgT Then
write 'not found:' #FileDirSAGName (al=70)
escape Routine
end-if
*
define work file 1 #FileDirSAGName type 'UNFORMATTED'
*
reset #header
read work file 1 once #header80
*
if #header80.#text = mask(NNNN) Then
move by name #header80.Structure to #header
read work file 1 #l
Perform ProcessLine
end-work
*
else
close work file 1
decide on first value of *OPSYS
*
value 'SUN_SOLA', 'HPUX_64'
read work file 1 once #header136
move by name #header136.STRUCTURE to #header
if #header.header_size ne 136
write 'invalid header size for OPSYS' *OPSYS
escape routine
end-if
*
value 'WNT-X86'
read work file 1 once #header116
move by name #header116.STRUCTURE to #header
if #header.header_size ne 116
write 'invalid header size for OPSYS' *OPSYS
escape routine
end-if
*
none value
write 'operating system' *OPSYS 'not supported'
escape routine
*
end-decide
*
read work file 1 #l-old
move by name #l-old.structure to #l.Structure
Perform ProcessLine
end-work
*
end-if
*
close work file 1
* </usercode>   <!-- name="loaddata" -->
ignore
End-Subroutine /* LoadData
* <usercode name="subroutines">
Define Subroutine ProcessLine
*
examine #l.Module      for H'00' and replace with ' '
examine #l.Module_long for H'00' and replace with ' '
examine #l.Src_USER_ID for H'00' and replace with ' '
examine #l.Cat_USER_ID for H'00' and replace with ' '
*
send Method 'New' to #pobjColl with #objI
if #objI eq null-handle then
escape routine
end-if
*
decide on first value of #l.LINE_TYPE
value 1
reset #Object-Data.#Saved-Date
reset #Object-Data.#Compiled-Date
*
if #l.Src_CATALOG = 1 or= 3 Then
if #l.SD_Year < 50 then
add 2000 to #l.SD_Year
else
add 1900 to #l.SD_Year
end-if
*
Move Edited #l.SD_Year (em=9999) to #yyyy
Move Edited #l.SD_Month (em=99) to #mm
Move Edited #l.SD_Day (em=99) to #dd
Move Edited #l.SD_hour (em=99) to #hh
Move Edited #l.SD_Min (em=99) to #ii
if #DateWithoutYear ne '00000000' Then
Move edited #DateAndTime to
#Object-Data.#saved-Date (em=yyyymmddhhii)
end-if
end-if
*
if #l.Src_CATALOG = 2 or= 3 then
if #l.Cat_Date_Year < 50 then
add 2000 to #l.Cat_Date_Year
else
add 1900 to #l.Cat_Date_Year
end-if
*
Move Edited #l.Cat_Date_Year (em=9999) to #yyyy
Move Edited #l.Cat_Date_Month (em=99) to #mm
Move Edited #l.Cat_Date_Day (em=99) to #dd
Move Edited #l.Cat_Date_hour (em=99) to #hh
Move Edited #l.Cat_Date_Min (em=99) to #ii
if #DateWithoutYear ne '00000000' Then
Move edited #DateAndTime to
#Object-Data.#Compiled-Date (em=yyyymmddhhii)
end-if
end-if
*
#objI.Line_Type := #l.LINE_TYPE
#objI.Sub_Type := #l.SUB_TYPE
#objI.Long_Name := #l.MODULE_LONG
#objI.Name := #l.MODULE
#objI.Object_Type := #l.MODULE_TYPE
#objI.DBID := #l.DDM_DBID
#objI.File_No := #l.DDM_FILE_NO
#objI.Mode := #l.MODE
#objI.Object_Form := #l.Src_CATALOG
#objI.Saved_by := #l.Src_USER_ID
#objI.Compiled_by := #l.Cat_USER_ID
#objI.Src_Size :=  #l.Src_SIZE
#objI.Object_Size := #l.Cat_SIZE
#objI.Saved_Date := #Object-Data.#saved-Date
#objI.Compiled_Date := #Object-Data.#Compiled-Date
*
decide on first value of #l.Module_Type
Value  52
#objI.FileName_Extension := 'NS4'
Value  55
#objI.FileName_Extension := 'NS7'
Value  65
#objI.FileName_Extension := 'NSA'
Value 67
#objI.FileName_Extension := 'NSC'
Value 68
#objI.FileName_Extension := 'NSD'
Value 76
#objI.FileName_Extension := 'NSL'
Value 77
#objI.FileName_Extension := 'NSM'
Value 78
#objI.FileName_Extension := 'NSN'
Value 80
#objI.FileName_Extension := 'NSP'
Value 83
#objI.FileName_Extension := 'NSS'
Value 84
#objI.FileName_Extension := 'NST'
none value
#objI.FileName_Extension := '???'
end-decide
*
value 2 ,  5 , 6
move #l    to #l_type2
#objI.Sub_Type := #l.SUB_TYPE
#objI.Line_Type := #l.LINE_TYPE
#objI.Name := #l_type2.MODULE
#objI.Long_Name := #l_type2.MODULE_LONG
send 'ItemByKey' to #pobjColl with #l_type2.Module #objTemp
if #objTemp ne null-handle then
#objTemp.Long_Name := #l_type2.Module_long
end-if
none value
write 'invalid linetype' #l.LINE_TYPE 'detected'
escape Bottom
end-decide
*
* </usercode>   <!-- name="subroutines" -->
End-Subroutine  /* ProcessLine
*
Define Subroutine getNewItem
send Method 'New' to #pobjColl with #objI
if #objI ne null-handle then
ignore
else
write *program 'Null-Handle, terminate ...'
escape bottom
end-if
End-Subroutine  /* getNewItem
*
end /* SOS.Nat.FileDir::Load (cFILED00.nsn)

(sorry for the strange indentation, but the maximum message length here is 10000 characters. “struct” is your friend :slight_smile: )
if someone wants to get the code of the class pls give me a hint.

Has someone else experiences with (local) natural-classes (not COM or DCOM)?

Beware that FILEDIR.SAG layout also changes with NATURAL 6.2.
(you are probably aware of it but if not …)

Header is X’50’ byes and each entry X’138’.

I am in same position as you - could use USR* exits but too slow.
Also there is no USR* which gives just the dir info.
There appears to be an exit which gives minimal dir info and the
read source code (1st…) entry which will give the dir info but is slow.

KlaBlue wrote about it …

BTW: Is there is a bug in USR0330N?
See http://natural.forums.softwareag.com/viewtopic.php?t=415