Frecon code: scan.pal
From PROSE Programming Language - Wiki
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Scan Routines for Frecon % Author: Mark R. Bannister % Date: 19/Dec/2017 % % Provides routines for scanning subdirectories underneath % a path and collecting data for the File Reconnaissance Tool % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~Module EQUS {[frecon]} ._init attr/load P0, [psString], P1, [psPointer], P2, [psBoolean] func/def [scan_opendir], &[.scan_opendir], P1, P0, [path] func/def [scan_openlast], &[.scan_openlast], P1 func/def [scan_closedir], &[.scan_closedir], NULL, P1, [handle] func/def [scan_start], &[.scan_start], NULL, P2, [cksum] func/def [scan], &[.scan_prompt] error/def [BadPath], [Bad pathname] local/rtn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Open top-level path provided from which scans are to begin and return % a file object % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .scan_opendir var/addr P0, [path] attr/load P1, [psString] var/global P2, P1, [scan_dir] attr/direct P2, P1, P0, P1 .open_handle % % Set-up global variable manually % obj/def P2 class/add P2, [psFileHook], [psStatUnix] attr/copy P0, P0, P1 attr/add P2, [psFilePath], P0 obj/commitref P2, ![-], [dir_handle], P2 func/rtn P2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Open top-level path previously supplied to scan_opendir % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .scan_openlast var/addr P0, [scan_dir] attr/load P1, [psString] local/jmp &[.open_handle] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Close handle returned by scan_opendir % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .scan_closedir var/addr P0, [handle] attr/addr P0, P0, [psPointer] obj/del P0 % delete global variable func/rtn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Ask question and get Y/N response, where P0 contains the question % and SCMP will be equal (1) upon return if Y was answered % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .get_yn reg/load P14, ![.prose.sys.io.stdin], P15, ![.prose.sys.io.stdout] attr/load P12, [psStreamIn], P13, [psStreamOut] .get_choice % % Display user prompt % attr/mvadd P15, P13, P0, [? [y/n\]: ] % % Grab one line of input % .get_stdin attr/copy P0, P14, P12 % % Force to uppercase % reg/jmpeq &[.get_stdin], P0, NULL % Ignore Ctrl+D reg/load A, (P0, #0) opa/shr #0x18 opa/and #0x5f % % Test for Y/y % reg/jmpeq &[.yes], A, #0x59 % % Test for N/n % reg/jmpeq &[.no], A, #0x4e % % Sound bell on error % attr/add P15, P13, [\a] local/jmp &[.get_choice] .yes reg/load SCMP, #1 local/rtn .no reg/load SCMP, #0 local/rtn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Prompt use before scan begins to determine if checksums are required % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .scan_prompt reg/load P0, [Calculate checksums during the scan] local/jsr &[.get_yn] func/call NULL, [scan_start], SCMP func/rtn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Scan a filesystem - this will overwrite the contents of the existing % database with a fresh scan from underneath the chosen scan path % % Takes a cksum argument that will be TRUE if checksums are also to % be calculated on all regular files encountered % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .scan_start % % Truncate the database and statistics to lose all existing records % func/call NULL, [db_truncate] func/call NULL, [stat_reset] % % Save initial database record for top-level directory % func/bcall P0, [scan_openlast] attr/addr P0, P0 func/bcall NULL, [db_write_record], P0, #0, #0 func/bcall NULL, [stat_store], P0 reg/load P1, (P0) % % Walk every file and directory under the top-level and create % database records for each one % var/addr P5, [cksum] attr/index P5, P5, [psBoolean] % checksums or not? attr/load P6, [psInteger] attr/def P7, P6, #0 % last record number reg/load P8, ![.prose.sys.io.stdout], P9, ![.prose.sys.io.stderr] class/load P10, [psStatUnix] attr/load P11, [statMode], P12, [psStreamOut], P13, [psFilePath] reg/load P14, ![.prose.error.sys.AccessDenied] attr/add P8, P12, [\nScanning ...] error/jmp &[.access_denied], P14 .loop reg/load P2, (P1) reg/jmpeq &[.loop_end], P2, NULL class/add P2, P10 % % Increment record number and write a new record to the database file % op/incr P7 attr/def P3, P6, P7 func/bcall NULL, [db_write_record], P2, P3, P5 func/bcall NULL, [stat_store], P2 % % If there are child nodes, walk into subdirectory % reg/load P2, (P2) reg/jmpeq &[.loop], P2, NULL % no child nodes, continue stack/push P1 reg/move P1, P2 attr/add P8, P12, [.] local/jmp &[.loop] .access_denied error/clr error/jmp &[.access_denied], P14 reg/jmpne &[.access_p2], P2, NULL .access_p1 attr/copy P2, P1, P13 local/jmp &[.access_error] .access_p2 attr/copy P2, P2, P13 .access_error reg/copy PUSH, [\nError: access denied: ], P2, [\n] attr/add P9, P12, PULL local/jmp &[.loop] .loop_end reg/jmpeq &[.scan_stop], PEEK, LOCK stack/pull P1 local/jmp &[.loop] .scan_stop reg/clr P1 func/call NULL, [scan_closedir], P0 func/rtn