home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-07-05 | 196.2 KB | 7,380 lines | [TEXT/TPAS] |
- program VCheck;
- (****************************************************************
-
- Startup System Test program
-
- by Albert Lunde, Northwestern University
-
- Copyright ⌐ 1988 - All Rights Reserved
-
- See "Terms of Distribution","Use" and "To get started"
- in comments below:
-
- ****************************************************************)
-
- {$U-} {don't use turbo pascal default units}
-
- {$R-} {range check off}
- {**R-} {these two strings}
- {**R+} {signal places where range checks are needed in debugging}
-
- {$D+} {debug symbols on}
- {$B-} {bundle bit not set}
- {$S+} {segment load on}
-
- uses pasInout,memtypes,quickdraw,osintf,toolintf,
- fixmath,packintf,SANE;
-
- const
-
- StartVersion='Vcheck - Version 1.3 ';
-
- TitleVersion=' 1.3 7/5/88';
-
- checksumsaltinc=$00010001;{change this to modify the way
- checksums are computed}
-
- (****************************************************************
-
- Startup System Test program
- by Albert Lunde, Northwestern University
- Copyright ⌐ 1988 - All Rights Reserved
-
- This is a program to detect software viruses by checking for
- changes in the contents of the active system folder, the boot
- blocks and all applications on connected volumes. It does
- not prevent viruses from spreading in your system, but can
- alert you to their existence. It is not designed to be
- specific to particular viruses, except for warning of
- "dangerous" resource types when found.
-
- Terms of Distribution:
-
- Non-commercial distribution is encouraged, with several
- conditions:
-
- 1) You must distribute the source code if you distribute the
- compiled program. (The main purpose of this is to make it
- difficult for viruses to spread. Users are encouraged to
- recompile from the source code, since source code cannot
- carry a virus.)
-
- 2) If you modify the source code, distribute both the
- original code and the modified code and include the original
- comment headers with copyright notice and remarks in both
- files. List a summary of your changes after the header, and
- add the word "Modified" to the two Version identifiers. You
- may not attach additional restrictions to distribution of the
- modified code. If I receive useful modifications, I may add
- them to my versions. (Distributing the original source makes
- it clearer what has been changed and may aid support.)
-
- 3) You may change a copying fee not to exceed $10 or the cost
- of media whichever is greater. (The intent is to put
- distribution of the original program and/or modified versions
- into non-profit channels to allow wider distribution) Normal
- communications and connect charges for downloading software
- are permitted.
-
- ***********************************************************
-
- New features and changes since version 1.2
-
- 1) Checksums may change from earlier versions since the list
- "safe" resources and files has been changed to work better
- with system update 6.0.
-
- 2) Added automatic full checksum on applications that have
- changed size - this reduces false alarms on an "Application
- Scan".
-
- 3) Fixed a bug which caused named resources with trailing blanks
- in the name to be treated as not equal to themselves.
-
-
- New features and changes since version "1.0 Beta":
-
- It is easier to keep your checksums file up to date. Features
- have been added to do checksums of new applications and/or
- replace the old checksums file with the new file.
-
- It is possible to check other system folders than the
- currently active system.
-
- Several options that previously were available only by
- recompiling the program are now specified in a dialog and the
- input file.
-
- Checksums may change from the earlier version since the list
- "safe" resources has changed.
-
- Four bugs fixed -
-
- 1) a bug affecting the results when an output file was
- written after an application scan.
-
- 2) errors in folder names on non-boot disk volumes,
-
- 3) a bug causing applications to be falsely declared as "new"
- in some circumstances
-
- 4) a bug causing the program to freeze or bomb just after
- checking the boot blocks.
-
- Changes have been made in heap and stack treatment which I
- hope will fix the intermittent errors in previous version (I
- suspect a heap/stack collision during an interrupt handler).
-
- ***********************************************************
-
- Hardware and Software:
-
- Written in Turbo Pascal 1.1 for the Mac (tested on a Mac SE
- and a Mac II) this should run on a Mac Plus,Mac SE or Mac II.
- I am not sure if a Mac 512E has enough memory. This assumes
- you have HFS and a relatively recent system so it is not
- appropriate for the 128K or 512K Macs with the old 64K ROMs.
- Some versions of the program compiled and ran with Turbo 1.0
- but I haven't tested this much.
-
- Use:
-
- The program expects to find an input file named
- "OldSystemCheckSum" in either the default folder or the
- system folder. It will optionally write an output file in
- the same format as the input file. (Both are text files with
- items separated by tab characters. The output file is named
- "OldSystemCheckSum" if no input file exists and
- "NewSystemCheckSum" otherwise.)
-
- The program compares the contents of your system folder with
- information in the input file, and tells you about changes.
- It also does a less detailed check of applications. It monitors
- the existence of hidden files.
-
- You have the option of replacing the input file with the
- output file after reviewing changes on-screen.
-
- Use of this program does not prevent a virus infecting your
- system, but it may give you an indication that you are
- infected, and thereby prevent infection of your backups. (Yet
- another reason to keep several sets of backups.)
-
- When the program starts you are presented with a choice of
- five buttons:
-
- "System Only" button:
-
- This does a complete check of the system folder, and does
- nothing with applications and hidden files elsewhere.
-
- "Application Scan" button:
-
- This will start a complete check of the system folder and
- a check for changes in the sizes the resource forks of
- applications. After about 10 seconds the Mac will continue as
- if you had clicked this option. This is faster but less
- accurate than the "Full Check". Because some applications
- write preferences information to their own resource fork,
- checking the size is not an ideal check. When an application
- appears to have changed size, a full checksum is done on it.
- This reduces false alarms. However, the size check can still
- be evaded by a careful virus.
-
- "Full Check" button:
-
- This does a complete check of the system folder and a
- check for changes in resources of applications. Only resource
- types marked as known to contain executable code are checked
- in applications and invisible files. It is recommended that
- you use "Full Check" periodically, especially before making
- backups, as it is much more difficult than "Application Scan"
- for a virus to evade. It is not the default, because it can
- take several minutes to run.
-
- "Skip It" button:
-
- Halts the program
-
- "ShutDown" button:
-
- Flush all drives and do a system shutdown. (similar to
- the item in the Finder Special Menu).
-
- If you press the option key before or while clicking one of
- these buttons, you will be presented with additional options,
- including the option to write an output file and/or to check
- a different system folder than the startup system. (More
- about this below).
-
- Key Commands:
-
- (the command key is ignored)
-
-
- "Q"- Quit after closing files
-
- "F"- same as "Full Check" button
-
- "A"- same as "System Only" Button
-
-
- "Y"- same as Yes Button
-
- "N"- same as No Button
-
- "."- Quit immediately
-
- Return Key - Default button (with bold outline)
-
- "*"- invoke MacsBug debugger and turn on additional output.
-
- (don't use this command without a debugger)
-
- "^"- invoke MacsBug debugger
- (don't use this command without a debugger)
-
- "&"- turn on debugging output
-
- "#"- turn on debugging output for resource/application detail
- comparison routines
-
- After the program starts, at any time you may quit the
- program by clicking the "Halt" button or pressing the "Q"
- key. You may shut down the system with the "Shutdown" button.
-
- To get started:
-
- Place the compiled program anywhere outside the system folder
- and run it, clicking on "Full Check". It may be necessary to
- increase the memory allowed by MultiFinder using the Get Info
- dialog. (500K is reasonable).
-
- The first time you run it, the program will not find the
- input file, and will ask you if you want to specify another
- input file. Click on NO. Click YES when it asks you to
- specify an output file. You will then see a standard dialog
- to save a file using the name "OldSystemCheckSum". Click on
- the save button.
-
- When the program runs, the output file should contain a
- summary of resources in the system file and of applications
- and hidden files. This checks all connected disk drives,
- optionally excluding floppies and folders on AppleShare file
- servers.
-
- Now, whenever you run the program, it will use the file
- "OldSystemCheckSum" as a standard of comparison and inform
- you of changes. If you want maximum protection, make this
- program your startup application with Set Startup.
-
- When you install new software in the system folder or make
- some changes in system settings you may get messages about
- new or changed resources. You will also get messages when
- you add an application, or move, rename or duplicate an
- application. If an application writes setup/preferences
- information into itself, it will be listed as a "Safe change
- in size", provided no unsafe resource types are changed.
-
- To see how these messages look, move some small application
- into the system folder and re-run the program.
-
- These messages reporting changes will continue to appear
- until you create an new output file (default name
- "NewSystemCheckSum") and rename it to "OldSystemCheckSum".
- You will be offered the option to create an output file and
- later to rename it whenever changes are reported.
-
- If you have not done a full checksum, and you choose to write
- an output file the program will recompute checksums for some
- applications, usually new application or applications moved
- between folders. This is a feature designed to keep your
- checksums file up to date. To be safe and informed of all
- changes, however, you should run "FullCheck" periodically,
- and only OK replacing your input file at other times when you
- know the reason for changes in the system or applications.
-
- To get a complete check and create a output file, hold down
- the option key while clicking of the "FullCheck" button at
- startup. Running "FullCheck" whenever you write an output
- file gives you the information necessary to do a complete
- comparison later.
-
- If changes seem minor (like a moved or new application), you
- can rename the output file within the program and replace the
- input file, or you can compare and or print the input and
- output files with a text editor after running the program,
- then rename the output file with the Finder.
-
- In the output file, new or changed resources are flagged
- "new??" or "changed??". Deletions are not marked.
- Applications are marked as "moved/renamed??',"new??",
- "changed??" or "safe changed??". Hidden files are marked as
- "(hidden)" if they are not applications.
-
- The output file is first written, then you are asked if you
- want to rename it. If you say yes, the input file is deleted
- and then the output file is moved and renamed to the same
- folder and filename used by the input file.
-
- You will not be offered the option to rename the output file
- if it and the input file are on different disk drives.
-
- Since the output file is written before deleting the input,
- there must be space on disk for both files. You can quit
- anytime prior to telling the computer to rename the output
- without affecting the input file.
-
- Options:
-
- Pressing the option key before or while you click on the
- startup dialog buttons will cause the program to offer you a
- number of options.
-
- You are asked if you want to write an output file.
-
- Several options that control what is checked are collected
- together on a dialog screen.
-
- "Check Floppies" is a check box that controls if floppy
- diskettes are checksummed. (no by default)
-
- "Check Non-Startup Drives" is a check box that controls if
- disk volumes besides the volume containing the system folder
- being checked are checked.
-
- By default the program only looks at the top level of
- AppleShare file Servers, and does not descend into folders
- unless you are the owner. The "Appleshare Access" buttons
- allows you to change this, and search all folders for which
- you have read/write access or "everything in sight" (folders
- for which you have search access). (Using these options can
- place quite a load on Appleshare.)
-
- All the options in the dialog screen are stored in the output
- file and default values are read from the input file if any.
-
- Specifying a different system to check:
-
- If you hold down the options key, another question you are
- asked is if you want to specify another system folder to
- check. If you say yes, you are presented with a file dialog.
- Pick a system folder and select the "System" or any other
- file in the folder.
-
- This is useful when checking a system you believe to be
- infected after booting from a floppy disk.
-
- If you want to check the system on a suspect floppy disk,
- turn on "Check Floppies", turn off "Check Non-Startup Drives"
- and then select the system folder on the floppy disk to
- check. (DO NOT BOOT from a suspect disk or run any
- applications on it).
-
- More about the Checksums:
-
- In order to reduce unnecessary messages and speed processing,
- some resources and some parts of the boot blocks are excluded
- from the checks. Resources types are classified as:
-
- 0 "Safe"
-
- (Not containing executable code)
- for example:
- "STR#","FONT","ICON"
-
- 1 "Unknown"
-
- (Not otherwise classified)
-
- 2 "Unsafe"
-
- (Containing executable code)
- for example:"CODE","INIT"
- (or sometimes occurring in reported viruses,
- sometimes in normal use)
-
- 3 "Dangerous"
-
- (Known only to occur in reported viruses)
-
- "Safe" resources are excluded from system folder checksums.
-
- Only "unsafe" resources are checked in application and hidden
- files and only a file by file checksum is kept, not a
- resource by resource checksum.
-
- A basic list of resource types is in the program, and
- "unknown" resources can be reclassified by changing the input
- file.
-
- There is also a list of key phrases which indicate a file in
- the system folder may safely contain changes in "unknown"
- resource types. If one of these keywords is found as a
- substring in the filename both "safe" and "unknown" resources
- are excluded from checksums. This is used to reduce
- unnecessary warnings about changes in the Clipboard,
- Scrapbook, Macro and settings files stored in the system folder.
-
- A checksum of checksums is done across resource types. This
- will change when any contents of the checked resources change
- or when the criteria for what is to be checked change. This
- will change when resources are deleted, while the resource by
- resource lists of changes only indicate new or changed
- resource.
-
- No grand checksum is done for applications. The way that
- applications are identified is by their 4 character creator
- signature and creation date and time.
-
- Hidden files are not checked for size on a short check and
- they are only checked for "unsafe" resource type changes on a
- full check. This is because the DeskTop and other normal
- hidden files change size.
-
- To make it more difficult to evade checksums, users are
- encouraged to change the value of the constant
- "checksumsaltinc" from $00010001 to some other longword hex
- value containing mostly zeros, but some non-zero digits in
- both the lower and upper half. Changing this value changes
- the non-linearity of the checksums, and changes the results,
- so that a change that would be undetected for one value might
- not be for another.
-
- Disclaimers:
-
- I do not warrant that this software will alert you to all
- viruses. (It won't.) I don't claim to be an expert in
- eradicating software viruses and can not do long-distance
- consulting on problems with them. I have designed this
- program from general considerations rather than experience
- with particular viruses.
-
- I have taken reasonable care that this program do no harm,
- but I cannot assure this. My main consideration has been to
- put something together quickly to help detect viruses and
- reduce their spread. Getting this out the door in time to be
- useful precludes exhaustive testing.
-
- Northwestern University Apple Tech Support is assisting in
- distributing this program, but they do not take
- responsibility for its continued support.
-
- Acknowledgements:
-
- Thanks to Bob Hablutzel and John Norstad for their advice and
- support during the development of the program.
-
- This code owes a lot to a number of sources. My resources
- include:
-
- "Inside Macintosh" Volumes I to V
-
- (A lot of use is made of the resource section and the Volume
- IV parameter block file system calls}
-
- Apple Tech Notes (in particular):
-
- 67 Finding the blessed folder
- 68 Searching all Directories on an HFS Volume
- 69 Setting ioFDirIndex in PBGetCatInfo Calls
- 77 HFS ruminations
-
- "MacTutor" Magazine
- "Macintosh Revealed" Vol I & II by Stephen Chernicoff
- "How to Write Macintosh Software" by Scott Knaster
- "Macintosh Programming Secrets" by Scott Knaster
- "Programming with Macintosh Programmer's Workshop" by Joel
- West
- "Fundamentals of Data Structures" by Ellis Horowitz and
- Sartaj Sahni
- "Programming Pearls" Jon Bentley
-
- MacNosy disassembler/debugger by Steve Jasik
-
- Bug Reporting:
-
- I can be reached at:
-
- E-Mail
-
- LUNDE@NUACC.BITNET
-
- LUNDE@NUACC.ACNS.NWU.EDU (Internet)
-
- U.S. Mail
-
- Albert Lunde
- Academic Computing
- Northwestern University
- 2129 Sheridan Road
- Evanston, IL 60208
-
- Related messages can also be sent to me care of Northwestern
- University Apple Tech Support:
-
- A42 - AppleLink;
-
- or
-
- 76474,154 - CompuServe
-
- If you get system bombs, record the ID number and what was
- happening prior to the error. If you have Macsbug, use "wh"
- to see where you are in memory. If you have any debugger,
- record the registers. Since this is a non-commercial effort,
- and I am giving out the source code, whatever you can do to
- localize and diagnose bugs will be appreciated. I do not
- know at this time how much time I can or will spend on
- support and revisions.
-
- Notes to Hackers:
-
- There is room for improvement here. An assembly language
- checksum function could be faster. I suggest any checksum
- method should meet a few criteria: Any one bit change should
- be likely to change the checksum. Transpositions of bytes
- should change the checksum. Any checksum function should be
- non-linear with respect to addition and exclusive or.
-
- That is, roughly speaking:
-
- F(a xor b) <> F(a) xor F(b)
-
- F(a + b) <> F(a) + F(b)
-
- I think my combination of shifts,xors and sums satisfies
- these conditions.
-
- The code was patched together from other projects and has
- odds and ends that are unnecessary for this reason..
-
- I would be interested to know of conversion issues going to
- other Pascal compilers. My use of Turbo's "shr" "shift
- right", "xor" and other inline bit manipulation operators for
- speed may cause some localized portability problems.
-
- The program is designed over-all to make spreading viruses
- more difficult, not impossible, with trade-offs relative to
- speed and convenience. This is why I do a less elaborate
- checksum on applications. The program does not use custom
- icons or any other resources, so that it will be easier to
- give out in source code form.
-
- I am checking the contents of the resource file by reading
- the resource map myself, opening the resource fork as a read-
- only file. An earlier version used LoadResource and
- DetachResource, but this had bugs which may come from
- fragmentation of the system heap when resources were
- repeatedly loaded into it.
-
- ****************************************************************)
-
- {Development versions by Albert Lunde:}
-
- {version 22 modified to read resource maps directly}
- {this version has some bugs in memory usage that are gradually
- eating up free memory - I suspect open/close - and/or TE 4/1/88}
- {version 23 the size of the TE handle is increasing but the text size is
- stating about the same , also memory allocation is a bit out of balance}
- {version 24 rewrite of memory allocation to reduce the change of
- stray handles in the resource reading routines- still has trouble
- with the TE handle size 4/3/88}
- {version 25 fix new TE bug by explictly changing
- the tehandle size when it gets clearly too big 4/4/88}
- {version 27 hide debugging code, fix problem with ids, fix problem
- with input/output '*****' flag recognition}
- {version 28 hidden "D" key to invoke Macsbug added 4/5/88}
- {version 29 added relative positioning in resource reading code to
- allow buffering to work better 4/5/88}
- {version 30 reduce minimum memory safety factor, hide debugging
- output 4/5/88}
- {version 31 add auto-start after delay}
- {version 32 cleanup for distribution, remove zero size handle check,
- add more safe keys, add beep at end 4/8/88}
- {version 33 add a bit of debuggging and I/O checking 4/8/88}
- {version 34 add application size checks 4/10/88}
- {version 36 application checksums/detail output added but buggy 4/10/88}
- {version 37 fix bugs,trim blanks before file name comparisions 4/11/88}
- {version 38 shift creationdates 4 bits, modify startup interface
- this needs more testing 4/11/88}
- {version 39 minor mods to application sort/compare, interface 4/12/88}
- {version 40 add check of invisible files 4/14/88}
- {version 41 add folder names to info on applications
- add delay after disk operations to
- fix intermittent bug in SCSI interrupt handler
- fiddle with user interface 4/14/88}
- {version 42 tweak new features and revise comments 4/14/88}
- {version 43 add system/only option and tweak startup 4/15/88}
- {version 44 bug fix in version 43 mods, add more key abbreviations
- change debugger invocation to "*" to avoid miskeys 4/15/88}
- {version 45 modify treatment of application scan output 4/16/88}
- {version 46 fix minor bug in % display, clean up comments
- add PREF to safe types list 4/17/88}
- {version 47 add to safe types list - display resource names 4/17/88}
- {version 50 begin adding multi-volume checks 4/18/88}
- {version 51 1st version with full multi-volume checks
- seems to be working - 4/18/88}
- {version 52 tweak multi-volume checks - 4/19/88}
- {release as version 1.0 beta 4/19/88}
- {version 53 ** fix bug in copy of checksums from old file to output
- after partial scan
- ** Add RLRL and ppat to safe resource types
- ** Add DEFAULT to safekeys 5/1/88}
- {version 54 ** add recheck of new/changed/moved for output 5/3/88}
- {version 55 ** add option to specify another system folder to check 5/3/88}
- {version 56 ** add options screen and propagation of options
- through the input file 5/3/88}
- {version 57 combine two redundant globals flags to fix a bug
- which showed up after version 53
- add ^ as escape to debugger
- add periodic call to doevent in scsi_wait
- add count to recheck warning 5/6/88}
- {version 58 ** add optional rename of output
- only volume checked always "matches" the only
- old volume in the input file 5/6/88}
- {version 59 fix output rename to avoid dup filenames before move
- modify recheck logic to avoid message
- when nothing is done
- Improve testing for option keys down 5/7/88}
- {version 60 ** use improved code to get folder name and/or path
- 5/7/88}
- {version 61 fix message on output rename
- revise message about rechecks
- increase scsi_wait delays 5/7/88}
- {version 62 add scsi_wait call in enumeration code
- add UnloadSeg calls and fiddle with segmentation 5/9/88}
- {version 63 adjust segmentation to try to increase free memory
- adjust scsi_wait parameters 5/10/88}
- {version 64 put null event and message posting in main segment
- reduce number of unload_all calls
- to reduce fragmentation due to segments
- increase stack,decrease heap to reduce chance of collisions
- add "&" to turn on debug output without macsbug 5/10/88}
- {version 65 move allocate_big_mem earlier and put in main
- segment to get blocks it allocates lower in
- the heap. Add stack size monitor to postmem 5/11/88}
- {version 66 fix bug in sizes used in allocate_big_mem
- move still earlier, put initialize in blank seg 5/11/88}
- {version 67 revise comments for distribution 5/12/88}
- {release as version 1.1 - not widely distributed}
- {version 68 **fix possible problems in initialization of PBHGetVol file calls
- may be a bug at the start of the enumerate code from TN68 5/14/88}
-
- {version 69 ** add code to skip to end of section in detail comparision if
- end_on_new before end on_old (avoid false new appls) 5/14/88}
- {release as version 1.2}
- {version 70 add debugging output "#" hidden key for detail comparisons
- fix problem when resource type names end with a space 6/1/88}
-
- {version 71 start adding code to reposition input file if necessary 6/14/88}
- {version 72 more work 6/15/88}
- {version 73 ** add code to do full check on size-changed applications
- if ok list as "safe size changes"
- ** add WIND to safe resource types
- ** add MACRO and MAP to safekeys 6/21/88}
- {version 74 remove automatic application check on output
- consolidate output dialog code
- add output dialog to over-all checksums
- and boot blocks messages
- add code to match one new vol to old boot vol 6/22/88}
- {version 75 add code to make output file name "OldSystemCheckSum"
- if no input file to make startup easier
- clean up for distribution 6/29/88}
- {release with added comments as release version 1.3 7/5/88}
- const
- {bytes to add to stack size and reduce heap size:}
- stack_extra_size=20000;
- {parameters of delay to avoid overloading disk drivers}
- scsi_wait_limit=4{8};{wait after this many disk operations}
- scsi_wait_ticks=2{2};{wait this long}
-
- {periodic calls to event handler for breakout}
- {call postmem,doevent after this many disk ops}
- scsi_wait_doevent_debug=3;{if debug output is on}
- scsi_wait_doevent_normal=100;{otherwise}
-
- {debugging stuff}
- dbaopen=1;
- dbatype=2;
- dbaref=3;
- dbadata=4;
- dbamax=4;
-
- {buttons}
- mbutton=9;
- nodefaultbut=0;
- yesbut=2;
- nobut=4;
- haltbut=1;
- continuebut=3;
- shutdownbut=5;
-
- skipitbut=6;
- sysonlybut=7;
- shortbut=8;
- fullbut=9;
-
-
-
- startupdefaultbutton=shortbut;
-
- {option controls}
- moptcon=5;
- floppyoptcon=1;
- nonstartupoptcon=2;
- owneroptcon=3;
- writeoptcon=4;
- everythingoptcon=5;
-
- startupdelay=10;{seconds}
-
- {limits on what can be checked}
- maxinfo=800;{total resources in system folder }
- maxtype=200;{total resource types in system folder }
- maxsysfiles=100;{total files in system folder}
- maxappl=300;{total applications and hidden files}
- maxvols=16;{volumes}
- maxsafekeywords=20;
- myfilenamesize=31;
- thenamesize=10;
- maxtokens=12;{input scanner limit}
- floppycutoffsize=900;{size limit used to identify
- floppy drives}
- recheckappllimit=10;{number of new/moved/changed applications to
- recheck without asking when writing an output file}
- {number of status lines}
- mstatus=7;
- {postions of status lines}
- titleline=1;
- byline=2;
- pathline=3;
- fileline=4;
- errorline=5;
- memline=5;
- AskLine=6;
- resline=6;
- detailbugline=1;
-
- {positions of sections in input file}
- sect_num_header=1;
- sect_num_safe_names=2;
- sect_num_more_checks=3;
- sect_num_volumes=4;
- sect_num_types=5;
- sect_num_res_checks=6;
- sect_num_applications=7;
-
- {rescaling of creation dates by factor of 1/16}
- creationdateshr=4;
- creationdatemask=$0FFFFFFF;
-
- {appleshare access mask values}
- owneraccessmask=$FF;
- readwriteaccessmask=$07;{read,write,search}
- everythingaccessmask=$01;{search}
-
- {constants to control what drives/folders are checked
- by default}
- appleshareaccessmaskdefault=owneraccessmask;
- checkfloppiesdefault=false;
- checknonbootdrivesdefault=true;
-
- {resource match flags}
- fnamemask=$3FFF;{mask off top bits of filename index}
- idmatchmask=$8000;
- exactmatchmask=$4000;
-
- {application match flags}
- applrenamemask=$0100;
- applexactmatchmask=$0200;
- applchangedmask=$0400;
- applsafechangedmask=$0080;
- appldangermask=$0800;
- applbadsizemask=$1000;
- applbadcheckmask=$2000;
- applinvisiblemask=$4000;{flag invisible files}
- applvolumemask=$001F;{subscript of volume}
- notcounted=-9;{flag results of short check in unsafecount}
-
- {grow zone function guard block size:
- This block is released if the heap is full and the
- program stops with a warning. Reducing this would make the program
- run in less memory but if it runs out it would die unpleasantly}
-
- GZguardblocksize=70000;
-
- {stuff from tech note#77}
-
- SysWDProcID = $4552494B; {╥ERIK╙}
- BootDrive = $210; {address of Low-Mem global BootDrive}
- FSFCBLen = $3F6; {address of Low-Mem global to distinguish file systems }
- SysMap = $A58; {address of Low-Mem global that contains system map reference number}
-
- type
- myfilenametype=string[myfilenamesize];
- myresnametype=string[thenamesize];{truncated resource names}
- WordPtr = ^Integer; {Pointer to a word(2 bytes)}
-
- {info on system folder resources}
- resourceinforec = record
- thesize:longint;
- thetype:restype;
- theid:integer;
- filenameindex:integer;{also flags in the high bits}
- checksum:integer;
- thename:myresnametype;
- end;
- resourceinfoarray=array[1..maxinfo] of resourceinforec;
- resourceinfoarrayptr=^resourceinfoarray;
- safetype=(safe,unknown,unsafe,dangerous);
- resourcetypeinforec = record
- thetype:restype;
- safety:safetype;
- occurs:integer;
- oldocurrs:integer;
- end;
- resourcetypeinfoarray = array[1..maxtype] of resourcetypeinforec;
- tokenstype=array[1..maxtokens] of str255;
- {info on volumes}
-
- myvolumerec= record
- volrefnum:integer;
- vcreation:longint;
- vname:myfilenametype;{change this}
- vsize:longint;
- vindex:integer;
- isboot:boolean;
- attributes:integer;
- matchto:integer;
- checkvol:boolean;
- end;
-
- myvolumearraytype=array[1..maxvols] of myvolumerec;
-
- {info on applications and hidden files}
- applinforec=record
- thesize:longint;
- creator:OStype;
- creationdate:longint;{shifted right}
- dirid:longint;
- filename:myfilenametype;
- unsafecount:integer;
- checksum:integer;
- checksize:longint;
- flags:integer;
- end;
-
- applinfoarray=array[1..maxappl] of applinforec;
- applinfoarrayptr=^applinfoarray;
-
- {Types for directly reading resource maps}
-
- type
- myresstatustype=(pathbad,pathempty,pathopen,
- typelistopen,reflistopen);
-
-
- {resource map}
- myresMaptype=record
- dummy1:array[1..5] of longint;
- dummy2:integer;
- res_file_attributes:integer;
- offset_map_to_typelist:integer;
- offset_map_to_namelist:integer;
- end;
-
- {resource type list items}
- myresTypeListitemtype=record
- thetype:restype;
- count_minus_one:integer;
- offset_typelist_to_reflist:integer;
- end;
-
- myresTypeList=array[0..0] of myresTypeListitemtype;
- myresTypeListptr=^myresTypeList;
- myresTypeListhandle=^myresTypeListptr;
-
- {resource reference list items}
- myresRefListitemtype=record
- theid:integer;
- offset_namelist_to_name:integer;
- attrib_and_offset:longint;
- dummy1:longint;
- end;
-
- myresreflisttype=array[0..0] of myresRefListitemtype;
- myresreflistptr=^myresreflisttype;
- myresreflisthandle=^myresreflistptr;
-
- {My "path" to the resource data. This includes
- some redundant information and buffer space}
- myresPathtype=record
- volref:integer;
- fileref:integer;
- filename:str255;
- {absolute offsets}
- offset_to_res_data:longint;
- offset_to_res_map:longint;
- offset_to_typelist:longint;{derived}
- offset_to_namelist:longint;{derived}
- map:myresmaptype;
- typelist:myresTypeListHandle;
- reflist:myresReflistHandle;
- resdata:handle;
- current_type:restype;
- current_type_subscript:integer;
- status:myresstatustype;{state of path}
- ntypes:integer;{number of types}
- nrefs:integer;{number of references to current type}
- end;
-
- var
- currentsection:integer;{divisions of input file -
- number starting with one}
- on_section_boundry:boolean;{true if ***** just read or at start or end}
- abmfail:boolean;
- appleshareaccessmask:integer;
- checkfloppies:boolean;
- checknonbootdrives:boolean;
- scsi_wait_count,scsi_wait_count2:integer;
- scsi_wait_doevent:integer;
- currentvolumesubscript:integer;
- StartupOptionKeyFlag:boolean;
- myRpath:myresPathtype;
- showdebuginfo:boolean;
- detaildebugflag:boolean;
- fastapplcheck:boolean;
- skipapplcheck:boolean;
- dbarray:array[1..dbamax] of longint;{for debug}
- notsafecount:longint;{number of resources not in a safe category}
- safetynames:array[safe..dangerous] of string[10];
- blessed:longint;{dir id of the blessed folder}
- blessedpath:str255;{path name of blessed folder}
- blessedbootvolwd:integer;
- startupwd:integer;{working directory on startup}
- buttons:array[1..mbutton] of controlhandle;
- buttonrects:array[1..mbutton] of rect;
- defaultbutton:integer;
-
- optcons:array[1..mbutton] of controlhandle;
- optconrects:array[1..mbutton] of rect;
- optconorigin:point;
- optioncontrolsactiveflag:boolean;
-
- quitting,finished:boolean;
- bootblockchecksum,oldbootblockchecksum:integer;
- checksumchecksum,oldchecksumchecksum:longint;
- askanswer:boolean;{answer from yes,no buttons}
- askanswered:boolean;{set true when button clicked}
- optionkeyflag:boolean;
-
- {event handler globals}
- theevent: EventRecord;
- mainwindow:Windowptr;
- wbounds,textbounds,textframe:rect;
- statustext:tehandle;
-
- rcount:longint;{count of resources checked in system folder}
- acount:longint;{count of apps and hidden files}
- oldvcount,vcount:integer;{count of volumes}
- oldvols,newvols:myvolumearraytype;{lists of volumes checked}
-
- {pointers to the two big blocks of memory which are seperately
- allocated to reduced the total size of globals}
- rinfo:resourceinfoarrayptr;
- ainfo:applinfoarrayptr;
-
- rtypes:resourcetypeinfoarray;
- rtypes_count:integer;
-
- infile,outfile:text;
- inputopen,outputopen,inputnotdefault:boolean;
- inputfile_dirid:longint;
- inputfile_Vrefnum:integer;
- inputfile_filename:str255;
- outputfile_dirid:longint;
- outputfile_Vrefnum:integer;
- outputfile_filename:str255;
-
- cancel:boolean;
-
- sysfiles:array[1..maxsysfiles] of myfilenametype;
-
- safekeywords_count:integer;
- safekeywords:array[1..maxsafekeywords] of myfilenametype;
-
- {Mydebug message globals}
- mydebugport : grafptr;
-
- {growzone function stuff}
- growzoneguardblock:handle;
- lowmemoryGZflag:boolean;
-
-
- {forward procedure declarations, not in any
- particular order}
-
- procedure recheck_changed(i:integer;
- oldunsafecount:longint;
- oldchecksize:longint;
- oldchecksum:integer);forward;
-
- function test_end_flag(line:str255):boolean;forward;
- procedure position_to_section(secnum:integer);forward;
- procedure debugger;inline $A9FF;{invoke macsbug}
- procedure debugStr(str:str255);inline $ABFF;{macsbug with string}
- procedure postmem(linenum:integer);forward;
- procedure halt_on_error(err:oserr;sss:str255);forward;
- procedure detail_appl_check;forward;
- procedure show_appl_detail_changes;forward;
- procedure setup_optioncon;forward;
- procedure draw_optcon_text;forward;
- procedure adjust_option_controls;forward;
-
- procedure Doevent(dontloop:boolean);forward;
-
- { ShutDown is new, but works with all machines with new system. }
- PROCEDURE ShutDwnPower;
- INLINE $3F3C,$0001,$A895;
-
- procedure check_a_file(index:integer);forward;
- procedure checksum_all_appl;forward;
- procedure checksum_unchecked_appl;forward;
- procedure poststatus(ss:str255;linenum:integer);forward;
- procedure replaceline(ss:str255;linenum:integer);forward;
- procedure dobutton(whichbutton:integer);forward;
- procedure drawbuttons;forward;
- procedure showstatus;forward;
- procedure close_all_and_halt(beep:boolean);forward;
- procedure close_and_flush(var filevar:text;var openflag:boolean);forward;
-
- procedure folder_info_two(dirid:longint;
- volume:integer;
- var name:str255;
- var path:str255;
- findpath:boolean);forward;
-
- function Ask(question:str255;default:integer):boolean;forward;
- procedure wait_for_buttons(ss:str255;default:integer);forward;
- procedure clear_to_end(linenum:integer);forward;
- procedure summary;forward;
- procedure set_default_blessed;forward;
- procedure set_default_by_id(DirID:longint);forward;
- function checksumHdataOLD(h:handle):integer;forward;
- function checksumHdata(h:handle):integer;forward;
- function checksum_boot_blocks:integer;forward;
- procedure sorttypes(var X:resourcetypeinfoarray;N:integer);forward;
- procedure tabscan(line:str255; var tokens:tokenstype;var ntokens:integer);forward;
- procedure filltype(var tt:restype;ss:str255);forward;
- procedure open_output;forward;
- procedure open_input;forward;
- procedure get_set_blessed;forward;
- {$S start2}
- procedure open_output_dialog(appask:boolean;defbut:integer);
-
- begin
- if not outputopen then
- if ask('Do you want to write a new summary output file?',defbut) then
- begin
- open_output;
- if outputopen and fastapplcheck and appask then
- fastapplcheck:=not Ask('Do you want a full checksum of applications',yesbut);
- end;
- end;
- procedure setupmydebug;{setup extra graphics port
- for drawing direct to the screen without using the window manager}
- const dbtop=260;
- dbleft=40;
- dbwidth=200;
- dblength=50;
-
- var saveport:grafptr;
- dbrect : rect;
- begin
- getport(saveport);{save current port}
- mydebugport:=grafptr(NewPtr(sizeof(grafport)));
- {make non-relocatable block}
- openport(mydebugport);
- setorigin(-dbleft,-dbtop);
- {set new origin so (0,0) is at (dbleft,dbtop)
- on the screen }
- (*debug_mess('Start Debug');*)
- setport(saveport);{restore current port}
- end; {of proc mysetup debug}
- {$S }
- procedure debug_mess(message:str255);
- const dbtop=260;
- dbleft=40;
- dbwidth=200;
- dblength=50;
- waitsec=2;
-
- var saveport:grafptr;
- dbrect : rect;
- waittick,dumm:longint;
- begin
-
- {---------------------------}
- getport(saveport);{save current port}
- setport(mydebugport);{change to debug port}
- setrect(dbrect,0,0,dbwidth,dblength);
- fillrect(dbrect,Dkgray); {draw a pseudo-window} {make this fancer later}
- penpat(white);
- framerect(dbrect);
- moveto(20,20);
- TextMode(Srcbic);{white letters}
- DrawString(message);
- waittick:=60*waitsec;
- delay(waittick,dumm);
- setport(saveport);{restore current port}
- {-------------------------}
-
- end; {of function debug_message}
- procedure debug_long(l:longint;tag:str255);
- var ss:str255;
- begin
- numtostring(l,ss);
- ss:=concat(tag,ss);
- debug_mess(ss);
- end;
-
- {---memory management tools---}
- function GoodPointer(p:ptr;tag:str255):boolean;
- {check that this is a pointer to non-nil data
- within the application memory area}
- const
- CurrentA5=$0904;
- ApplZone=$02AA;
- Lo3Bytes=$00FFFFFF;
- type
- lp=^longint;
-
- var a:lp;
- high,low,add:longint;
- ok:boolean;
- begin
- ok:=false;
- if p<>nil then
- begin
- add:=longint(ord4(p) and Lo3bytes);
- if not odd(add)then
- begin
- {this test is a bit strict/mem-map dependent}
- a:=pointer(ApplZone);
- low:=a^;
- a:=pointer(CurrentA5);
- high:=a^;
- if (add>=low) and (add<high) then
- begin
- ok:=true;
- end
- else
- begin
- debug_mess('Pointer outside User Memory');
- sysbeep(5);sysbeep(5);
- end;
- end
- else
- begin
- debug_mess('Pointer With Odd Address');
- end
- ;{endif}
-
- end;
- if not ok and (p<>nil) then
- begin
- debug_mess(concat('GP>',tag));
- repeat until button;
- end;
- Goodpointer:=ok;
- end;{goodPointer}
- function GoodHandle(h:handle;tag:str255):boolean;
- var a:ptr;
- ok:boolean;
-
- begin
- ok:=false;
- if GoodPointer(ptr(h),concat('GH1:',tag)) then
- begin
- if GoodPointer(h^,concat('GH2:',tag)) then
- begin
- {if GetHandleSize(h) >0 then}
- begin;
- ok:=true
- end
- {else
- begin
- debug_mess('Handle Size<0');
- end}
- ;{endif}
- end
-
- else
- begin
- debug_mess('Handle^ is bad or nil');
- end
- ;{end if}
- end
- else
- begin
- if h<>nil then
- debug_mess('Handle is bad');
- end
- ;{endif}
-
- if not ok and (h<>nil) then
- begin
- debug_mess(concat('GH>',tag));
- repeat until button;
- end;
-
- GoodHandle:=ok;
- end;{goodhandle}
- {$S }
- procedure scsi_wait;
- {periodic delays to keep from overwhelming the scsi driver}
- {also doevents to allow breakout}
- var wait,endit:longint;
- begin
- scsi_wait_count:=scsi_wait_count+1;
- scsi_wait_count2:=scsi_wait_count2+1;
- if scsi_wait_count>scsi_wait_limit then
- begin
- wait:=scsi_wait_ticks;
- delay(wait,endit);
- scsi_wait_count:=0;
- end;
- if scsi_wait_count2>scsi_wait_doevent then
- begin
- postmem(memline);
- doevent(true);{don't loop}
- scsi_wait_count2:=0;
- end;
- end;
-
- procedure read_input(var line:str255);
- {readln(infile,line) with delay added}
- var dummy:boolean;
- begin
- scsi_wait;
- line:='';
- if eof(infile)then
- begin
- currentsection:=currentsection+1;
- on_section_boundry:=true;
- exit;
- end;
- readln(infile,line);
- if test_end_flag(line)
- then
- begin
- currentsection:=currentsection+1;
- on_section_boundry:=true;
- end
- else
- begin
- on_section_boundry:=false;
- end
- end;{proc}
- procedure read_input_integer(var ii:integer);
- var ss:str255;
- work:longint;
- begin
- read_input(ss);
- stringtonum(ss,work);
- ii:=work;
- end;{proc}
-
- procedure read_input_long(var jj:longint);
- var ss:str255;
- begin
- read_input(ss);
- stringtonum(ss,jj);
- end;{proc}
- {$S start2 }
- procedure kill_nil;
- {for debugging}
- {put an odd value in memory location zero to hit nil's early}
- type lptr=^longint;
- var p:lptr;
- begin
- p:=lptr(Pointer(0));
- P^:=$4E494C21;{NIL!}
- end;
- procedure myteshow;
- var i,nn,jj:integer;
- ss,ww:str255;
- begin
- nn:=statustext^^.nlines;
- ss:='';
- for i:=0 to nn do
- begin
- jj:=statustext^^.linestarts[i];
- numtostring(jj,ww);
- ss:=concat(concat(ss,ww),' ');
- end;
- numtostring(statustext^^.telength,ww);
- ss:=concat(concat(ss,ww),' ');
- poststatus(ss,byline);
-
- end;{proc}
-
- procedure dbashow;
- var i:integer;
- ss,nn:str255;
- begin
- myteshow;
- ss:='';
- for i:=1 to dbamax do
- begin
- numtostring(dbarray[i],nn);
- ss:=concat(concat(ss,nn),' ');
- end;
- numtostring(statustext^^.nlines,nn);
- ss:=concat(concat(ss,nn),' ');
-
- poststatus(ss,pathline);
- end;{proc}
- {$S startup}
-
- function option_key_down:boolean;
- const optionkeycode1=58;
- optionkeycode2=61;
- {alternate key codes from inside mac vol 5}
- type keyp=^keymap;
- var
- p:keyp;
- fakekeymap:array[0..7] of integer;
- i:integer;
- begin
- p:=keyp(@fakekeymap);
- getkeys(p^);
- option_key_down:=BitTst(@fakekeymap,optionkeycode1)
- or BitTst(@fakekeymap,optionkeycode2);
- end;{function}
-
- procedure select_system_folder(var wdrefnum:integer;
- var dirid:longint;
- var volume:integer;
- var cancel:boolean);
- {select a system folder}
- var
- topleft,center :point;
- ShowTypes : SFTypeList;
- NTypes :integer ;
- theErr :OSErr;
- Reply :SFreply;
- filename :string[63];
- err : OSErr;
- myWDPB : WDPBRec;
- dummy :str255;
- vserr,ignore :OSerr;
- prompt: str255;
- oldwd:integer;
-
- begin
- {save default wd}
- ignore:=getvol(nil,oldwd);
-
- prompt:='Pick System File';
- wdrefnum:=0;
-
- with center do
- begin
- with screenbits.bounds do
- begin
- v:=(top+bottom) div 2;
- h:=(left+right) div 2;
- end;
- end;
-
- topleft.h:=center.h-170; {position of topleft}
- topleft.v:=center.v-120;
-
- ShowTypes[0]:='ZSYS';
- ShowTypes[1]:='FNDR';
- ShowTypes[2]:='TEXT';{for debugging}
- Ntypes:=2;
- Cancel:=false;
- SFGetFile(topleft,prompt,nil,NTypes,ShowTypes,nil,Reply);
- if Reply.good then
- begin
- wdrefnum:=reply.vrefnum;
- end
- else
- begin
- {may be a cancel or other error}
- Cancel:=true;
-
- end;
- if not cancel then
- begin
-
- {get volume and dirid from wdref number}
- with mywdpb do
- begin
- dummy:='';
- ioCompletion:= NIL;
- ionameptr:=@dummy;
- iovrefnum:=wdrefnum;
- iowdindex:=0;
- iowdprocid:=0;
- end;
- scsi_wait;
- err:=PBgetWDinfo(@mywdpb,false);
- if err=noerr then
- begin
- with mywdpb do
- begin
- dirid:=iowddirid;
- volume:=iowdvrefnum;
- end;
- end
- else
- begin
- cancel:=true;
- end
-
- end;
- ignore:=setvol(nil,oldwd);
- end; {select systemfolder}
- procedure pick_set_blessed;
- {optionally select an alternate system folder to check}
- {this is treated as if it were the startup volume hereafter}
- var wdrefnum:integer;
- volume:integer;
- dirid:longint;
- cancel:boolean;
- name:str255;
- begin
- if not StartupOptionKeyFlag then exit;
- poststatus(blessedpath,pathline);
- if not ask('Do you want to pick a different system file to check?',nobut) then exit;
- cancel:=true;
- select_system_folder(wdrefnum,dirid,volume,cancel);
- if not cancel then
- begin
- blessedbootvolwd:=volume;
- blessed:=dirid;
- set_default_blessed;{because folder_info is volume specific}
- folder_info_two(blessed,blessedbootvolwd,name,blessedpath,true);
- end
- else
- begin
- sysbeep(1);
- end;
- poststatus(blessedpath,pathline);
- set_default_blessed;
- end;{proc}
-
- {$S core}
- procedure write_end_flag(tag:str255);
- var tab:char;
- begin
- if not outputopen then exit;
- tab:=chr(9);
- scsi_wait;
- writeln(outfile,'*****',tab,tag);
- end;{proc}
-
- function test_end_flag{(line:str255):boolean};
- begin
- test_end_flag:=copy(line,1,5)='*****';
- end;{function}
-
- procedure position_to_section{(secnum:integer)};
- label 88;
- var skip_count,i:integer;
- line:str255;
- begin
- if not inputopen then exit;
-
- if ((currentsection=secnum) and on_section_boundry )then exit;
-
- if currentsection>=secnum then
- begin
- reset(infile);
- currentsection:=1;
- on_section_boundry:=true;
- end;
- poststatus('Reread input',pathline);
-
- while currentsection<secnum do
- begin
- if eof(infile)then exit;
- read_input(line);
- end;
- clear_to_end(pathline);
-
- end;{procedure}
-
- function filenamecompare(aa,bb:myfilenametype):integer;
- {compare filenames after trimming leading and trailing blanks}
- {and mapping to uppercase}
- {metaphore is sign of aa-bb
- if aa<bb return -1
- if aa=bb return 0
- if aa>bb return 1}
- label 10,20,30,40;
- var result:integer;
- w:str255;
- begin
- if aa=bb then
- begin
- filenamecompare:=0;
- exit
- end;
- {while loops to trim blanks}
- 10:if aa<>'' then
- if aa[1]=' ' then
- begin
- aa:=copy(aa,2,length(aa)-1);
- goto 10;
- end;
- 20:if aa<>'' then
- if aa[length(aa)]=' ' then
- begin
- aa:=copy(aa,1,length(aa)-1);
- goto 20;
- end;
- {while loops to trim blanks}
- 30:if bb<>'' then
- if bb[1]=' ' then
- begin
- bb:=copy(bb,2,length(bb)-1);
- goto 30;
- end;
- 40:if bb<>'' then
- if bb[length(bb)]=' ' then
- begin
- bb:=copy(bb,1,length(bb)-1);
- goto 40;
- end;
- w:=aa;
- uprstring(w,true);
- aa:=w;
- w:=bb;
- uprstring(w,true);
- bb:=w;
- if aa=bb then
- result:=0
- else if aa>bb then
- result:=1
- else
- result:=-1;
- filenamecompare:=result;
- end;
-
- function resnamecompare(aa,bb:myresnametype):integer;
- {compare filenames after trimming leading and trailing blanks}
- {metaphore is sign of aa-bb
- if aa<bb return -1
- if aa=bb return 0
- if aa>bb return 1}
- label 10,20,30,40;
- var result:integer;
- w:str255;
- begin
- if aa=bb then
- begin
- resnamecompare:=0;
- exit
- end;
-
- {while loops to trim blanks}
- 10:if aa<>'' then
- if aa[1]=' ' then
- begin
- aa:=copy(aa,2,length(aa)-1);
- goto 10;
- end;
- 20:if aa<>'' then
- if aa[length(aa)]=' ' then
- begin
- aa:=copy(aa,1,length(aa)-1);
- goto 20;
- end;
- {while loops to trim blanks}
- 30:if bb<>'' then
- if bb[1]=' ' then
- begin
- bb:=copy(bb,2,length(bb)-1);
- goto 30;
- end;
- 40:if bb<>'' then
- if bb[length(bb)]=' ' then
- begin
- bb:=copy(bb,1,length(bb)-1);
- goto 40;
- end;
- if aa=bb then
- result:=0
- else if aa>bb then
- result:=1
- else
- result:=-1;
- resnamecompare:=result;
- end;
-
- {$S vols}
- procedure find_vols;
- label 88;
- var
- mypb:hparamblockrec;
- name:str255;
- err:oserr;
- index:integer;
-
- begin
- vcount:=0;
- index:=0;
- repeat
- index:=index+1;
- with mypb do
- begin
- iocompletion:=nil;
- name:='';
- ionameptr:=@name;
- iovrefnum:=0;
- iovolindex:=index;
- end;
- err:=pbhgetvinfo(@mypb,false);
-
- if err=noerr then
- begin
- if vcount>=maxvols then goto 88;
- vcount:=vcount+1;
- with newvols[vcount] do
- with mypb do
- begin
- volrefnum:=iovrefnum;
- vindex:=index;
- vname:=name;
- {compute size to the nearest K}
- vsize:=round((float(abs((longint(iovNmAlblks) and $0000FFFF)))*float(ioVAlBlkSiz))/1024);
- {shifted creation date}
- vcreation:=(iovcrdate shr creationdateshr) and creationdatemask;
- isboot:=(blessedbootvolwd=volrefnum);
- attributes:=iovAtrb;
- matchto:=0;
- checkvol:=true;
-
- {optionally exclude floppies}
- {check the blessed/boot drive even if it is a floppy}
- if (not checkfloppies) and (not isboot) then
- if vsize<floppycutoffsize then
- begin
- {skip floppies}
- checkvol:=false;
- end;
- if not checknonbootdrives then
- if not isboot then
- begin
- {skip non-boot drives}
- checkvol:=false;
- end;
-
- end;
- end;
-
- until(err<>noerr);
- 88:
- end;{find_vols}
-
- procedure write_vols;
- var i:integer;
- tab:string[1];
- begin
- tab:=chr(9);
- if not outputopen then exit;
- for i:=1 to vcount do
- with newvols[i] do
- begin
- scsi_wait;
- writeln(outfile,vname,tab,vsize,tab,vcreation,tab,ord(isboot));
- end;
- write_end_flag('end volumes');
- end;{procedure write_vols}
-
- procedure read_vols;
- var line:str255;
- tokens:tokenstype;
- ntokens:integer;
- work:longint;
- begin
- oldvcount:=0;
- if not inputopen then exit;
- position_to_section(sect_num_volumes);
- while not eof(infile) do
- begin
- read_input(line);
- if test_end_flag(line) then exit;
- tabscan(line,tokens,ntokens);
- if ntokens>=4 then
- begin
- oldvcount:=oldvcount+1;
- with oldvols[oldvcount] do
- begin
- vname:=tokens[1];
- stringtonum(tokens[2],vsize);
- stringtonum(tokens[3],vcreation);
- stringtonum(tokens[4],work);
- isboot:=boolean(ord(work));
- matchto:=0;
- {unused stuff}
- volrefnum:=0;
- vindex:=0;
- attributes:=0;
- end;
- end;
- end;
-
- end;
-
- procedure match_vols;
- {decide what old volumes match what new volumes}
- {this trys to match in several ways}
- var iold,inew:integer;
- ccount:integer;
- ckv:integer;
- lastckv:integer;
- oldboot:integer;
- nomatch:longint;
- w1,w2:str255;
- begin
- if oldvcount<=0 then exit;
-
- ckv:=0;{count of new volumes to check}
- lastckv:=0;{last checkable volume found}
- for inew:=1 to vcount do
- if newvols[inew].checkvol then
- begin
- lastckv:=inew;
- ckv:=ckv+1;
- end;{for/if}
-
- if ((oldvcount=1) and (ckv=1)) then
- begin
- {if one checkable new and old vol, always match}
- oldvols[1].matchto:=lastckv;
- newvols[lastckv].matchto:=1;
- exit;
- end;
-
- if ((oldvcount=1) and (vcount=1)) then
- begin
- {if one vol, always match}
- oldvols[1].matchto:=1;
- newvols[1].matchto:=1;
- exit;
- end;
-
-
- {check for exact matches first}
- for inew:=1 to vcount do
- if newvols[inew].matchto=0 then
- begin
- for iold:=1 to oldvcount do
- if oldvols[iold].matchto=0 then
- begin
- if (filenamecompare(oldvols[iold].vname,newvols[inew].vname)=0) then
- if oldvols[iold].vsize=newvols[inew].vsize then
- if oldvols[iold].vcreation=newvols[inew].vcreation then
- begin
- oldvols[iold].matchto:=inew;
- newvols[inew].matchto:=iold;
- end;{if match}
- end;{for/if}
- end;{for/if}
-
- {check for matches ignoring name}
- {this assumes a rename may happen}
- for inew:=1 to vcount do
- if newvols[inew].matchto=0 then
- begin
- for iold:=1 to oldvcount do
- if oldvols[iold].matchto=0 then
- begin
- if oldvols[iold].vsize=newvols[inew].vsize then
- if oldvols[iold].vcreation=newvols[inew].vcreation then
- begin
- oldvols[iold].matchto:=inew;
- newvols[inew].matchto:=iold;
- end;{if match}
- end;{for/if}
- end;{for/if}
-
- {match by name only}
- {this will match a volume that has been reinitialized
- with the same name}
- for inew:=1 to vcount do
- if newvols[inew].matchto=0 then
- begin
- for iold:=1 to oldvcount do
- if oldvols[iold].matchto=0 then
- begin
- if (filenamecompare(oldvols[iold].vname,newvols[inew].vname)=0) then
- if oldvols[iold].vsize=newvols[inew].vsize then
- if oldvols[iold].vcreation=newvols[inew].vcreation then
- begin
- oldvols[iold].matchto:=inew;
- newvols[inew].matchto:=iold;
- end;{if match}
- end;{for/if}
- end;{for/if}
-
- {if only one checkable new volume match to old boot volume}
- {this is to help floppy disk checks}
- if (ckv=1) and (newvols[lastckv].matchto=0) then
- begin
- for iold:=1 to vcount do
- if oldvols[iold].isboot then
- begin
- oldboot:=iold;
- end;{for/if}
- oldvols[oldboot].matchto:=lastckv;
- newvols[lastckv].matchto:=oldboot;
- exit;
- end;
-
-
- nomatch:=0;
- ccount:=0;
- for inew:=1 to vcount do
- if newvols[inew].checkvol then
- begin
- ccount:=ccount+1;
- if newvols[inew].matchto=0 then
- nomatch:=nomatch+1;
- end;
- if nomatch=0 then exit;
- if not inputopen then exit;
- numtostring(nomatch,w1);
- numtostring(ccount,w2);
- w1:=concat(concat(concat(concat(concat('Note: ',w1),' of '),w2),
- ' mounted disk volumes to be checked do not match any in the input file. '),
- 'No application changes will be reported on these volumes.');
- wait_for_buttons(w1,continuebut);
- end;{procedure}
-
- {$S vols}
- procedure sortnewvols(var X:myvolumearraytype;N:integer);
- {sort array of volumes in a consistent but arbitrary order}
- {this is done after matching with old volumes to put the
- new volumes in the same order, except for mismatches}
-
- { HEAP SORT
- C
- C BASED ON PROGRAMMING PEARLS BY JON BENTLEY P 182
- C X IS THE ARRAY CONTAINING NX ELEMENTS TO BE SORTED
- C CALL SWAPX(I,J) SWAPS X(I) WITH X(J)
- C GEX(X,I,J) IS TRUE IFF X(I) >= X(J)
- C GTX(X,I,J) IS TRUE IFF X(I) > X(J)
- C}
-
-
- var i: integer;
-
-
- procedure SWAPX(I:integer;J:integer);
- var T:myvolumerec;
- {swap new vols and update matchto fields in new vols}
- begin
- T:=X[I];
- X[I]:=X[J];
- X[J]:=T;
-
- IF X[I].matchto<>0 then
- oldvols[X[I].matchto].matchto:=I;
- IF X[J].matchto<>0 then
- oldvols[X[J].matchto].matchto:=J;
-
- END; {of procedure swapx}
-
- FUNCTION GTX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort by order of matches then index }
- gtx:=false;
-
- if (X[I].matchto>X[J].matchto) then
- begin
- gtx:=true
- end
- else if (X[I].matchto=X[J].matchto) then
- begin
- if (X[I].vindex>X[J].vindex)then
- begin
- gtx:=true;
- end;
- end;
-
- end;
-
- FUNCTION GEX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort by order of matches then index }
- gex:=false;
-
- if (X[I].matchto>X[J].matchto) then
- begin
- gex:=true
- end
- else if (X[I].matchto=X[J].matchto) then
- begin
- if (X[I].vindex>=X[J].vindex)then
- begin
- gex:=true;
- end;
- end;
-
- END;
-
- procedure siftdown(L:integer;U:integer);
- label 300,999{return};
- var
- i,child:integer;
-
- begin
-
- {
- C
- C BEFORE MAXHEAP(L+1,U)
- C AFTER MAXHEAP(L,U)
- }
- I:=L;
-
- {LOOP}
- 300:
- {
- C INVARIANT: MAXHEAP(L,U) EXCEPT PERHAPS
- C BETWEEN I AND ITS (0,1 OR 2) CHILDREN
- C
- }
- CHILD:=2*I;
-
- IF CHILD > U then goto 999;
- {
- C
- C IF C+1 <= U AND X(C+1) > X(C) THEN C=C+1
- C
- }
- IF(CHILD+1 <= U) THEN
- IF(GTX(CHILD+1,CHILD))THEN
- CHILD:=CHILD+1;
-
- {
- C
- C CHILD IS THE GREATEST CHILD OF I
- C
- C IF X(I) >= X(CHILD) THEN RETURN
- C
- }
- IF(GEX(I,CHILD)) then goto 999;
-
- {
- C
- C X(I) IS LESS THAN ITS GREATEST CHILD SO SWAP IT DOWNWARD
- C AND REPEAT LOOP
- C
- }
- SWAPX(CHILD,I);
- I:=CHILD;
- GOTO 300;
- {END LOOP}
- 999:{return}
- END; {of proc siftdown}
-
-
-
- begin {main body of sortnewvols}
-
- for I:=N div 2 downto 1 do
- begin
- { echo(i);}
- SIFTDOWN(I,N);
- end;
-
- {echo(0);}
-
- for I:=N downto 2 do
- begin
- { echo(i);}
- SWAPX(1,I);
- {echo(i);}
- SIFTDOWN(1,I-1);
- { echo(i);}
- end;
-
-
-
- END; {sortnewvols}
-
- procedure dovols;
- {multi-volume processing}
- begin
- find_vols;
- read_vols;
- match_vols;
- sortnewvols(newvols,vcount);
- end;
-
- {$S appl}
- procedure note_application( fname:str255;
- pdirID:longint;
- index:integer;
- mycpb:CInfoPBRec;
- hidden:boolean);
-
- (*
- {info on applications}
- applinforec=record
- thesize:longint;
- creator:OStype;
- creationdate:longint;
- dirid:longint;
- filename:myfilenametype;
- unsafecount:integer;
- checksum:integer;
- fileindex:integer;
- flags:integer;
- end;
-
- applinfoarray=array[1..maxappl] of applinforec;
- applinfoarrayptr=^applinfoarray;
-
- *)
- {add to a list of applications in memory}
- begin
- if acount<maxappl then
- begin
- poststatus(fname,fileline);
- acount:=acount+1;
- with ainfo^[acount] do
- begin
- flags:=currentvolumesubscript and applvolumemask;{save volume}
- checksum:=0;
- checksize:=0;
- if fastapplcheck then
- unsafecount:=notcounted
- else
- unsafecount:=0;
- filename:=fname;
- dirid:=pdirid;
- if hidden then
- begin
- {make as hidden non-application file}
- flags:=flags or applInvisiblemask;
- end;
- with mycpb do
- begin
- thesize:=ioflRLgLen;{logical size of resource fork}
- creationdate:=(ioflcrdat shr creationdateshr) and creationdatemask;
- {creation date and time}
- creator:=ioFlFndrInfo.fdcreator;
- end;{with}
- end;{with}
- end
- else
- begin
- poststatus('Max applications exceeded.',errorline);
- end;
- end;{procedure}
-
- PROCEDURE EnumerAPPLShell;
- {search applications on current default volume staring with root}
- VAR
-
- myCPB: CInfoPBRec;
- err: OSErr;
- myWDPB: WDPBRec;
- DirIDToSearch:Longint;
- fname,dummy:str255;
- p:wordptr;
- accessrights:integer;
-
- PROCEDURE EnumerateAPPLCatalog(dirIDToSearch: longint);
-
- VAR
- index: integer;
-
-
-
- Begin {EnumerateAPPLCatalog}
-
- index:= 1;
-
- repeat
-
- FName:= ''; {nil out name}
- myCPB.ioFDirIndex:= index;
- myCPB.ioDrDirID:= dirIDToSearch; {we need to do this every time through}
- p:=@mycpb.ioflAttrib;{clear word with appleshare permissions in 2nd byte}
- p^:=0;
-
- scsi_wait;
- err:= PBGetCatInfo(@myCPB,FALSE);
-
-
- If err = noErr then
-
- if BitTst(@myCPB.ioFlAttrib,3) then
- Begin
- {we have a dir}
- p:=@mycpb.ioflAttrib;{appleshare permissions are at offset 31}
- accessrights:=p^ and $00FF;
- if (accessrights and appleshareaccessmask)=0 then
- begin
- {only descend tree if we have specified rights}
- EnumerateAPPLCatalog(myCPB.ioDrDirID);
- end;
- err:= 0; {clear error return on way back}
- End {if dir}
- Else
- Begin
- {we have a file}
- {test if application or invisible file}
- if (myCPB.ioFlFndrInfo.fdtype='APPL')then
- begin
- {It is an application, add it to list in memory}
- note_application(fname,dirIDToSearch,index,mycpb,false)
- end
- else if (myCPB.ioFlFndrInfo.fdflags and fInvisible)<>0 then
- begin
- {It is a hidden file add it to list in memory}
- note_application(fname,dirIDToSearch,index,mycpb,true)
- end;
- End; {end if}
-
- index:= index + 1;
-
- until err <> noErr;
-
- End; {EnumerateAPPLCatalog}
-
-
-
- Begin {EnumerAPPLShell}
-
- DirIDToSearch:=2;{root}
- {add initialize of pb 5/14/88
- may not be needed but seems to fix a bug}
- with mywdpb do
- begin
- dummy:='';
- ioCompletion:= NIL;
- ionameptr:=@dummy;
- iovrefnum:=0;
- iowdindex:=0;
- end;
- err:= PBHGetVol(@myWDPB,FALSE); {get the default volume}
-
- with MyCPB do Begin
- iocompletion:= Nil;
- ioNamePtr:= @FName;
- ioVRefNum:= myWDPB.ioVRefNum; {for now, default vol, set this to what you want}
- End; {with}
-
- EnumerateAPPLCatalog(DIRIDTOSEARCH);{DirID 2, is the root level}
-
- End; {procedure EnumerAPPLShell}
- {$S sortappl }
-
- procedure sortapplications(var X:applinfoarrayptr;N:integer);
- {sort array of applications and their checksums}
- { HEAP SORT
- C
- C BASED ON PROGRAMMING PEARLS BY JON BENTLEY P 182
- C X IS THE ARRAY CONTAINING NX ELEMENTS TO BE SORTED
- C CALL SWAPX(I,J) SWAPS X(I) WITH X(J)
- C GEX(X,I,J) IS TRUE IFF X(I) >= X(J)
- C GTX(X,I,J) IS TRUE IFF X(I) > X(J)
- C}
-
-
- var i: integer;
-
-
- procedure SWAPX(I:integer;J:integer);
- var T:applinforec;
-
- begin
- T:=X^[I];
- X^[I]:=X^[J];
- X^[J]:=T;
- END; {of procedure swapx}
-
- FUNCTION GTX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort by creator signature,creation date,filename,volume,dirID}
- gtx:=false;
- if (X^[I].creator>X^[J].creator) then
- begin{1}
- gtx:=true;
- end{1}
- else if (X^[I].creator=X^[J].creator) then
- begin{2}
- if (X^[I].creationdate>X^[J].creationdate) then
- begin{3}
- gtx:=true;
- end{3}
- else if (X^[I].creationdate=X^[J].creationdate) then
- begin{4}
- filecomp:=filenamecompare(X^[I].filename,X^[J].filename);
- if filecomp>0{(X^[I].filename>X^[J].filename)} then
- begin{5}
- gtx:=true;
- end{5}
- else if filecomp=0{(X^[I].filename=X^[J].filename)} then
- begin{6}
- if (X^[I].flags and applvolumemask)>(X^[J].flags and applvolumemask) then
- begin{7}
- gtx:=true;
- end{7}
- else if (X^[I].flags and applvolumemask)=(X^[J].flags and applvolumemask) then
- begin{8}
- if (X^[I].dirID>X^[J].dirID) then
- begin{9}
- gtx:=true;
- end;{9}
- end;{8}
- end;{6}
- end;{4}
- end;{2}
-
- end;
-
- FUNCTION GEX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort by creator signature,creation date,filename,volume,dirID}
- gex:=false;
- if (X^[I].creator>X^[J].creator) then
- begin{1}
- gex:=true;
- end{1}
- else if (X^[I].creator=X^[J].creator) then
- begin{2}
- if (X^[I].creationdate>X^[J].creationdate) then
- begin{3}
- gex:=true;
- end{3}
- else if (X^[I].creationdate=X^[J].creationdate) then
- begin{4}
- filecomp:=filenamecompare(X^[I].filename,X^[J].filename);
- if filecomp>0{(X^[I].filename>X^[J].filename)} then
- begin{5}
- gex:=true;
- end{5}
- else if filecomp=0{(X^[I].filename=X^[J].filename)} then
- begin{6}
- if (X^[I].flags and applvolumemask)>(X^[J].flags and applvolumemask) then
- begin{7}
- gex:=true;
- end{7}
- else if (X^[I].flags and applvolumemask)=(X^[J].flags and applvolumemask) then
- begin{8}
- if (X^[I].dirID>=X^[J].dirID) then
- begin{9}
- gex:=true;
- end;{9}
- end;{8}
- end;{6}
- end;{4}
- end;{2}
-
- END;
-
- procedure siftdown(L:integer;U:integer);
- label 300,999{return};
- var
- i,child:integer;
-
- begin
-
- {
- C
- C BEFORE MAXHEAP(L+1,U)
- C AFTER MAXHEAP(L,U)
- }
- I:=L;
-
- {LOOP}
- 300:
- {
- C INVARIANT: MAXHEAP(L,U) EXCEPT PERHAPS
- C BETWEEN I AND ITS (0,1 OR 2) CHILDREN
- C
- }
- CHILD:=2*I;
-
- IF CHILD > U then goto 999;
- {
- C
- C IF C+1 <= U AND X^(C+1) > X^(C) THEN C=C+1
- C
- }
- IF(CHILD+1 <= U) THEN
- IF(GTX(CHILD+1,CHILD))THEN
- CHILD:=CHILD+1;
-
- {
- C
- C CHILD IS THE GREATEST CHILD OF I
- C
- C IF X^(I) >= X^(CHILD) THEN RETURN
- C
- }
- IF(GEX(I,CHILD)) then goto 999;
-
- {
- C
- C X^(I) IS LESS THAN ITS GREATEST CHILD SO SWAP IT DOWNWARD
- C AND REPEAT LOOP
- C
- }
- SWAPX(CHILD,I);
- I:=CHILD;
- GOTO 300;
- {END LOOP}
- 999:{return}
- END; {of proc siftdown}
-
-
-
- begin {main body of sortapplications}
-
- for I:=N div 2 downto 1 do
- begin
- { echo(i);}
- SIFTDOWN(I,N);
- end;
-
- {echo(0);}
-
- for I:=N downto 2 do
- begin
- { echo(i);}
- SWAPX(1,I);
- {echo(i);}
- SIFTDOWN(1,I-1);
- { echo(i);}
- end;
-
-
-
- END; {sortapplications}
- {$S applout}
- procedure APPLsummary;
- {write summary of info on applications}
- var i:integer;
- tab:char;
- tags:str255;
- dname:str255;
- dummy:str255;
- vref:integer;
- begin
- set_default_blessed;
- tab:=chr(9);
- if not outputopen then exit;
- poststatus('Writing Application Summary Output',pathline);
- for i:=1 to acount do
- with ainfo^[i] do
- begin
- dname:='?';
- vref:=newvols[(flags and applvolumemask)].volrefnum;
- folder_info_two(dirid,vref,dname,dummy,false);
- tags:='';
- if inputopen then
- begin
- if (flags and applexactmatchmask)<>applexactmatchmask then
- begin
- if (flags and applrenamemask)=applrenamemask then
- begin
- {moved or renamed or duplicated}
- tags:='moved/renamed??';
- end
- else
- begin
- if (flags and applchangedmask)=applchangedmask then
- begin
- {changed}
- tags:='changed??';
- end
- else if (flags and applsafechangedmask)=applsafechangedmask then
- begin
- {safe changed}
- tags:='safe size changed??';
- end
- else
- begin
- {"new"}
- tags:='new??';
- end
- end;
- end;
- if (flags and appldangermask)=appldangermask then
- begin
- tags:=concat(tags,' Danger??');
- end;
- end;{inputopen}
- if (flags and applinvisiblemask)<>0 then
- begin
- tags:=concat(tags,'(hidden)');
- end;
- scsi_wait;
- write(outfile,creator:4,tab,
- creationdate,tab,
- filename,tab,
- dirid,tab,
- (flags and applvolumemask),tab,
- thesize,tab,
- unsafecount,tab,
- checksize,tab,
- checksum,tab,
- dname);
- scsi_wait;
- if tags='' then writeln(outfile) else writeln(outfile,tab,tags);
-
- end;{for/with}
-
- write_end_flag('end applications and hidden files');
- end;{applsummary}
-
- procedure copyapplsummary;
- {copy old applications summary when no application checks are done}
- label 88;
- var line:str255;
-
- begin
- if not outputopen then exit;
-
- if inputopen then
- begin
- position_to_section(sect_num_applications);
- while(not(eof(infile))) do
- begin
- read_input(line);
- if test_end_flag(line) then goto 88;
- scsi_wait;
- writeln(outfile,line);
- end;
- 88:
- end;
- write_end_flag('end applications and hidden files(copy)');
- end;
- {$S appl }
- procedure scan_all_vols;
- label 88;
- var i:integer;
- err:oserr;
- begin
- for i:=1 to vcount do
- begin
- if newvols[i].checkvol then
- begin
- err:=setvol(nil,newvols[i].volrefnum);
- if err=noerr then
- begin
- poststatus(concat('Scan applications and hidden files:',newvols[i].vname),pathline);
- currentvolumesubscript:=i;
- enumerAPPLshell;
- end;
- end;
- end;
-
- set_default_blessed;
- end;
-
-
-
- {$S start2}
- procedure initmypath(var mypath:myresPathtype);
- const bigneg=-16000;
- startsize=32;
- begin
- with mypath do
- begin
- volref:=0;
- fileref:=0;
- filename:='';
- {absolute offsets}
- offset_to_res_data:=bigneg;
- offset_to_res_map:=bigneg;
- offset_to_typelist:=bigneg;{derived}
- offset_to_namelist:=bigneg;{derived}
- typelist:=myresTypeListHandle(newhandle(startsize));
- reflist:=myresReflistHandle(newhandle(startsize));
- resdata:=newhandle(startsize);
- current_type:=' ';
- current_type_subscript:=0;
- status:=pathbad;{state of path}
- ntypes:=0;{number of types}
- nrefs:=0;{number of references to current type}
- end;
-
- end;{proc}
- {$S myres}
- function my_openRF_readonly(filename:str255;
- vrefnum:integer; var refnum:integer):oserr;
-
- {Open Resource File - as a file - read only}
-
- var mypb:Paramblockrec;
- err:oserr;
- begin
- with mypb do
- begin
- iocompletion:=nil;
- ionameptr:=@filename;
- ioVrefnum:=vrefnum;
- iorefnum:=0;{dummy for bad returns}
- ioVersNum:=0;
- IoPermssn:=fsRdPerm;{read only}
- ioMisc:=nil;
- end;{with}
- scsi_wait;
- err:=PBOpenRF(@mypb,false);
- refnum:=mypb.iorefnum;
- my_openRF_readonly:=err;
- end;{proc}
- function setmytype( var mypath:myresPathtype;
- index:integer;
- var atype:restype
- ):boolean;
- {set the current type, return true if suceeded}
- {eith index (1 to ntypes) or set by type}
- label 99,88,77;
- var offset:longint;
- ii:integer;
- rlsize:longint;
- bcount:longint;
- begin
- with mypath do
- begin
- if status<typelistopen then goto 99;
- if index>0 then
- begin
- {pick type by index}
- if index>ntypes then goto 99;
- {**R-}
- current_type:=typelist^^[index-1].thetype;
- offset:=typelist^^[index-1].offset_typelist_to_reflist;
- nrefs:=typelist^^[index-1].count_minus_one+1;
- {**R+}
- atype:=current_type;
- current_type_subscript:=index-1;
- end
- else
- begin
- {pick type by name}
- for ii:=0 to nrefs-1 do
- begin
- {**R-}
- if typelist^^[ii].thetype=atype then
- begin
- current_type:=typelist^^[ii].thetype;
- offset:=typelist^^[ii].offset_typelist_to_reflist;
- nrefs:=typelist^^[ii].count_minus_one+1;
- current_type_subscript:=ii;
- goto 77;{match}
- end;
- {**R+}
- end;
- goto 99;{fail}
- end;
- 77:
- {load the reference list for this type}
- Hunlock(handle(reflist));
- status:=typelistopen;
- offset:=offset_to_typelist+offset;{compute absolute offset}
-
- {reserve memory}
- rlsize:=nrefs*12;
- hunlock(handle(reflist));
- sethandlesize(handle(reflist),rlsize);
- if memerror<>noerr then goto 99;
-
- Hlock(handle(reflist));
- {actually do the read}
- if SetFPos(fileref,fsFromStart,offset)<>noerr then goto 88;
- bcount:=rlsize;
- scsi_wait;
- if FsRead(fileref,bcount,ptr(reflist^))<>noerr then goto 88;
- if bcount<>rlsize then goto 88;
- {we've got the reflist "open"}
- hunlock(handle(reflist));
- status:=reflistopen;
- end;{while}
- setmytype:=true;
- exit;{normal}
- 88:
- Hunlock(handle(mypath.reflist));
- mypath.status:=typelistopen;
- 99:
- setmytype:=false;{failure}
- end;{setmytype}
-
- Function CopyResData( var mypath:myresPathtype;
- var index:integer;
- var id:integer;
- var psize:longint;
- var pattr:integer;
- var pname:str255 ):boolean;
- {copy resource data to handle
- either index(1 to nrefs) or search for id}
- const offsetmask=$00FFFFFF;
- ash=24;
- amask=$000000FF;
- label 99,88,77,85;
- var offset,noffset:longint;
- ii:integer;
- bcount:longint;
- rdsize:longint;
- noname:boolean;
- nsize:integer;
- begin
- psize:=0;
- pname:='';
- pattr:=0;
- with mypath do
- begin
- if status<reflistopen then goto 99;
- hlock(handle(reflist));
- if index>0 then
- begin
- {**R-}
- offset:=(reflist^^[index-1].attrib_and_offset) and offsetmask;
- pattr:=((reflist^^[index-1].attrib_and_offset) shr ash) and amask;
- id:=reflist^^[index-1].theid;
- noffset:=reflist^^[index-1].offset_namelist_to_name;
- {**R+}
- end
- else
- begin
- for ii:=0 to ntypes-1 do
- begin
- {**R-}
- if reflist^^[ii].theid=id then
- begin
- offset:=(reflist^^[ii].attrib_and_offset) and offsetmask;
- pattr:=((reflist^^[ii].attrib_and_offset) shr ash) and amask;
- noffset:=reflist^^[ii].offset_namelist_to_name;
- goto 77;
- end;
- {**R+}
- end;{for}
- hunlock(handle(reflist));
- goto 88;{fail}
- 77:
- end;
- hunlock(handle(reflist));
-
- {convert to absolute offsets}
- offset:=offset_to_res_data+offset;
- noname:=(noffset=-1);
- if not noname then noffset:=noffset+offset_to_namelist;
-
- if not noname then
- begin
- {get name length}
- if SetFPos(fileref,fsFromStart,noffset)<>noerr then goto 88;
- bcount:=2;
- scsi_wait;
- if FsRead(fileref,bcount,@nsize)<>noerr then goto 88;
- if bcount<>2 then goto 88;
- nsize:=(nsize shr 8) and $00FF;{convert first byte to integer}
- nsize:=nsize+1;{length of pascal string}
- {get the whole name}
- {get name length}{use relative positioning}
- scsi_wait;
- if SetFPos(fileref,fsfrommark,-2)<>noerr then goto 88;
- bcount:=nsize;
- scsi_wait;
- if FsRead(fileref,bcount,@pname)<>noerr then goto 88;
- if bcount<>nsize then goto 88;
- end;{if name}
-
- {get data length}
- scsi_wait;
- if SetFPos(fileref,fsfromstart,offset)<>noerr then goto 88;
- bcount:=4;
- scsi_wait;
- if FsRead(fileref,bcount,@rdsize)<>noerr then goto 88;
- if bcount<>4 then goto 88;
-
- {allocate space for data}
- hunlock(resdata);
- sethandlesize(resdata,rdsize);
- if memerror<>noerr then goto 99;
-
- {read in the data}
- {offset:=offset+4;}{read from mark after data length}
- {if SetFPos(fileref,fsfromStart,offset)<>noerr then goto 85;}
- bcount:=rdsize;
- hlock(resdata);
- scsi_wait;
- if FsRead(fileref,bcount,(resdata^))<>noerr then goto 85;
- hunlock(resdata);
- if bcount<>rdsize then goto 85;
- {we have got it}
- psize:=rdsize+4;{add 4 to size to make consistent with
- result of SIzeResource}
-
- end;{with}
-
- Hunlock(mypath.resdata);
- copyResData:=true;
- exit;
- {failure}
- 85:
- 88:
- 99:
- Hunlock(mypath.resdata);
- copyResData:=false;
- end;{function}
-
- procedure closepath(var mypath:myresPathtype);
- var err:oserr;
- begin
-
- if goodhandle(handle(mypath.reflist),'closepath1') then
- Hunlock(handle(mypath.reflist))
- else
- sysbeep(1);
- if goodhandle(handle(mypath.typelist),'closepath2') then
- Hunlock(handle(mypath.typelist))
- else
- sysbeep(1);
- if goodhandle(mypath.resdata,'closepath3')then
- Hunlock(handle(mypath.resdata))
- else
- sysbeep(1);
-
- if mypath.reflist<>nil then
- sethandlesize(handle(mypath.reflist ),32);
- if mypath.typelist<>nil then
- sethandlesize(handle(mypath.typelist ),32);
- if mypath.resdata<>nil then
- sethandlesize(handle(mypath.resdata ),32);
- if mypath.status>=pathempty then
- begin
- { dbarray[dbaopen]:=dbarray[dbaopen]-1;}
- err:=FSclose(mypath.fileref);
- end;
-
- mypath.status:=pathbad;
- end;{proc closepath}
-
- function openpath(var mypath:myresPathtype;pfilename:str255;pvolref:integer):oserr;
- label 99,98;
- const myerr=-999;
- minimumRFsize=16;
- var err,err2:oserr;
- lsize:longint;
- bcount:longint;
- theeof:longint;
- begin
- err:=myerr;
- with mypath do
- begin
- volref:=pvolref;
- filename:=pfilename;
- current_type:=' ';
- ntypes:=0;
- nrefs:=0;
- status:=pathbad;
-
- {open resource fork}
- err:=my_openRF_readonly(pfilename,pvolref,fileref);
- if err<>noerr then goto 99;
- {dbarray[dbaopen]:=dbarray[dbaopen]+1;}
- status:=pathopen;
-
- {get Eof to see if this file has a resource fork}
- err:=geteof(fileref,theeof);
- if err<>noerr then goto 99;
- {do a normal exit on an empty resource fork}
- if theeof<minimumRFsize then
- begin
- ntypes:=0;
- nrefs:=0;
- status:=pathempty;
- openpath:=noerr;
- closepath(mypath);
- exit;
- end;
-
-
-
- {get offsets to data and start}
- err:=SetFPos(fileref,fsFromStart,0);
- if err<>noerr then goto 99;
- bcount:=8;
- scsi_wait;
- err:=FsRead(fileref,bcount,@offset_to_res_data);
- if err<>noerr then goto 99;
- if bcount<>8 then goto 98;
-
- {get resource map}
- err:=SetFPos(fileref,fsFromStart,offset_to_res_map);
- if err<>noerr then goto 99;
- bcount:=sizeof(myresMaptype);
- scsi_wait;
- err:=FsRead(fileref,bcount,@map);
- if err<>noerr then goto 99;
- if bcount<>sizeof(myresMaptype) then goto 98;
-
- {compute absolute offset to type list,name list}
- offset_to_typelist:=offset_to_res_map+map.offset_map_to_typelist;
- offset_to_namelist:=offset_to_res_map+map.offset_map_to_namelist;
-
- {get number of types}
- err:=SetFPos(fileref,fsFromStart,offset_to_typelist);
- if err<>noerr then goto 99;
- bcount:=2 {sizeof(myresMaptype)};
- scsi_wait;
- err:=FsRead(fileref,bcount,@ntypes);
- if err<>noerr then goto 99;
- if bcount<>2 {sizeof(myresMaptype)}then goto 98;
- ntypes:=ntypes+1;
-
- {resize handle for type list}
- lsize:=8*ntypes;
- Hunlock(handle(typelist));
- sethandlesize(handle(typelist),lsize);
- if memerror<>noerr then
- begin
- err:=memerror;
- goto 99;
- end;
-
- status:=typelistopen;
- hlock(handle(typelist));
-
- {read type list into handle}
- { err:=SetFPos(fileref,fsfromstart,offset_to_typelist+2);
- if err<>noerr then goto 99;} {read from mark}
- bcount:=lsize;
- scsi_wait;
- err:=FsRead(fileref,bcount,Ptr(typelist^));
- hunlock(handle(typelist));
- if err<>noerr then goto 99;
- if bcount<>lsize then goto 98;
-
- end;{with mypath}
-
- openpath:=noerr;
- exit;{normal exit}
- 98:err:=myerr;
- 99:{error exit}
- closepath(mypath);
- openpath:=err;
- end;{proc openpath}
-
-
-
- {$S }
- function Mygrowzone(cbneeded:size):longint;
- var dontmove:handle;
- result:longint;
- begin
- result:=0;
- dontmove:=GZsaveHnd;
- if growzoneguardblock<>nil then
- if growzoneguardblock<>dontmove then
- begin
- result:=GetHandleSize(growzoneguardblock);
- DisposHandle(growzoneguardblock);
- growzoneguardblock:=nil;
- sysbeep(1);
- end;
-
- lowmemoryGZflag:=true;
-
- mygrowzone:=result;
- end;{function}
- procedure setup_mygrowzone;
-
- begin
- lowmemoryGZflag:=false;
- growzoneguardblock:=newhandle(GZguardblocksize);
- SetGrowZone(@mygrowzone);
-
- end;
- procedure low_memory_halt;
- {low memory warning - post message in a different way to work better}
- var
- wait,endit:longint;
- begin
- if rinfo<>nil then
- begin
- DisposPtr(ptr(rinfo));
- rinfo:=nil;
- end;
- if ainfo<>nil then
- begin
- DisposPtr(ptr(ainfo));
- ainfo:=nil;
- end;
- replaceline('Not enough memory to continue safely',errorline);
- showstatus;
- wait:=120;
- delay(wait,endit);
- close_all_and_halt(true);
- end;
-
- {$S }
- procedure allocate_big_memory(var failed:boolean);
- const
- safety=150000;{minimum free space}
- var needed:size;
- wevegot,grow:size;
- begin
- failed:=false;
- needed:=Sizeof(resourceinfoarray)+Sizeof(applinfoarray);
- ResrvMem(needed+safety);
- Wevegot:=MaxMem(grow);
- if wevegot<(needed+safety) then
- begin
- failed:=true;
- end
- else
- begin
- rinfo:=resourceinfoarrayptr(NewPtr(Sizeof(resourceinfoarray)));
- ainfo:=applinfoarrayptr(NewPtr(Sizeof(applinfoarray)));
- if (rinfo=nil) or(ainfo=nil) then
- begin
- failed:=true;
- end
- end;
-
- end;
- {$S safekey}
- procedure add_safekey(ss:str255);
- var i:integer;
- begin
- uprString(ss,true);{upper case}
- if safekeywords_count<maxsafekeywords then
- begin
- for i:=1 to safekeywords_count do
- begin
- if safekeywords[i]=ss then exit;{already in the list}
- end;
- safekeywords_count:=safekeywords_count+1;
- safekeywords[safekeywords_count]:=ss;
- end;
- end;{procedure}
-
- procedure write_safekeys;
- var i:integer;
- begin
- if not outputopen then exit;
- for i:=1 to safekeywords_count do
- begin
- scsi_wait;
- writeln(outfile,safekeywords[i]);
- end;
- write_end_flag('end safe names');
-
- end;
-
- procedure read_safekeys;
- {read list of safe keyword file exclusions}
- var line:str255;
- tokens:tokenstype;
- ntokens:integer;
- begin
- if not inputopen then exit;
- position_to_section(sect_num_safe_names);
- line:='';
- while not eof(infile) do
- begin
- read_input(line);
- if test_end_flag(line) then exit;
- tabscan(line,tokens,ntokens);
- if ntokens>=1 then add_safekey(tokens[1]);
- end;
- end;
- {$S start2 }
- procedure write_morechecks;
- {write list of additional (boot block?) checksums
- shell procedure for future expansion}
- var i:integer;
- begin
- if not outputopen then exit;
- (* write it here *)
- write_end_flag('end morechecks');
- end;
-
- procedure read_morechecks;
- {read list of additional (boot block?) checksums
- shell procedure for future expansion}
- var line:str255;
- tokens:tokenstype;
- ntokens:integer;
- begin
- if not inputopen then exit;
- position_to_section(sect_num_more_checks);
- line:='';
- while not eof(infile) do
- begin
- read_input(line);
- if test_end_flag(line) then exit;
- (* process here *)
- end;
- end;
-
- {$S core}
- function filenamesafetylevel(name:str255):safetype;
- {checksum all resources above this level}
- label 99;
- var i:integer;
- result:safetype;
- begin
- uprString(name,true);{upper case}
- for i:=1 to safekeywords_count do
- begin
- if Pos(safekeywords[i],name)<>0 then
- begin
- result:=unknown;
- goto 99;
- end;
- end;
- result:=safe;
- 99:
- {poststatus(safetynames[result],errorline);}
- filenamesafetylevel:=result;
- end;
-
- {$S safekey}
- procedure start_safekey;
- {Make list of substrings in file names that
- indicate the file is a temporary file or settings file
- that frequently changes and may contain
- "unknown" resource types that are really safe}
- begin
- safekeywords_count:=0;
- add_safekey('Scrapbook');
- add_safekey('Clipboard');
- add_safekey('TEMP');
- add_safekey('WORK');
- add_safekey('SETTING');
- add_safekey('RESUME');
- add_safekey('PREFER');
- add_safekey('OPTION');
- add_safekey('SCRATCH');
- add_safekey('DEFAULT');
- add_safekey('MACRO');
- add_safekey('MAP');
-
- end;
- {$S start2}
- FUNCTION HFSExists: BOOLEAN;
- {From Tech note #77}
- var w:wordptr;
- Begin {HFSExists}
- w:=WordPtr(Pointer(FSFCBLen));
- HFSExists := (w^) > 0;
- End; {HFSExists}
-
- procedure HFSWarning;
- {Quit if HFS not available}
- var wait,endit:longint;
- begin
- if not HFSexists then
- begin
- wait:=180;
- Poststatus('This program requires the HFS file system',errorline);
- delay(wait,endit);
- doevent(false);
- close_all_and_halt(true);
- end;
- end; {HFSWarning}
-
- FUNCTION GetRealBootDrive: INTEGER;
- {From Tech Note #77}
- VAR
- MyHPB : HParamBlockRec;
- MyWDPB : WDPBRec;
- err : OSErr;
- w:wordptr;
- sysVRef : integer; {will be the vRefNum of open system╒s vol}
-
- Begin {GetRealBootDrive}
- if HFSExists then Begin {If we╒re running under HFS... }
-
- {get the VRefNum of the volume that }
- {contains the open System File }
- w:=WordPtr(Pointer(SysMap));
- err:= GetVRefNum(w^,sysVRef);
-
- with MyHPB do Begin
- {Get the ╥System╙ vRefNum and ╥Blessed╙ dirID}
- ioNamePtr := NIL;
- ioVRefNum := sysVRef; {from the GetVrefNum call}
- ioVolIndex := 0;
- End; {with}
- err := PBHGetVInfo(@MyHPB, FALSE);
-
-
- with myWDPB do Begin {Open a working directory there}
- ioNamePtr := NIL;
- ioVRefNum := sysVRef;
- ioWDProcID := SysWDProcID; {Using the system proc ID}
- ioWDDirID := myHPB.ioVFndrInfo[1];{ see TechNote 67}
- End; {with}
- err := PBOpenWD(@myWDPB, FALSE);
-
- GetRealBootDrive := myWDPB.ioVRefNum;
- {We╒ve got the real WD}
- End Else {we╒re running MFS}
- begin
- w:=WordPtr(Pointer(BootDrive));
- GetRealBootDrive := w^;
- end;
- {BootDrive is valid under MFS}
- End; {GetRealBootDrive}
-
- {$S core}
- procedure tabscan{(line:str255; var tokens:tokenstype;var ntokens:integer)};
- {Input scanner: breaks a line into tokens separated by tabs}
- {Trims leading and trailing blanks}
- label 99,88;
- var tab,sp:char;
- i,j,next,last:integer;
- begin
- tab:=chr(9);
- sp:=' ';
-
- for i:=1 to maxtokens do tokens[i]:='';
-
- ntokens:=0;
- next:=1;
- last:=length(line);
- while(next<=last) do
- begin
- {skip leading blanks}
- while(line[next]=sp) do
- begin
- next:=next+1;
- if(next>last) then goto 99;
- end;{while not space}
-
- {copy up to tab or end of line}
- ntokens:=ntokens+1;
- while(line[next]<>tab) do
- begin
- tokens[ntokens]:=concat(tokens[ntokens],line[next]);
- next:=next+1;
- if(next>last)then goto 99;
- end;{while not tab}
- next:=next+1;{skip tab}
- end;{while}
- 99:
- {remove trailing spaces}
- for i:=1 to ntokens do
- begin
- last:=length(tokens[i]);
- for j:=length(tokens[i]) downto 1 do
- begin
- if tokens[i][j]<>sp then
- begin
- last:=j;
- goto 88;
- end;
- end;
- 88:
- if last>0 then
- tokens[i]:=copy(tokens[i],1,last)
- else
- tokens[i]:='';
- end;{for i}
- end;{proc}
-
-
- function find_type(atype:restype):integer;
- {find a resource type if it exists. Return the current supscript or zero
- if it does not exist}
- {binary search}
- var low,high,mid:integer;
- begin
- low:=1;
- high:=rtypes_count;
- while low<=high do
- begin
- mid:=(low+high) div 2;
- if atype=rtypes[mid].thetype then
- begin
- find_type:=mid;
- exit;
- end
- else if atype>rtypes[mid].thetype then
- begin
- low:=mid+1;
- end
- else
- begin
- high:=mid-1;
- end;
- end;{while}
- find_type:=0;{no match}
- end;{function}
-
- function find_and_add_type(atype:restype;howsafe:safetype):integer;
- {find a resource type if it exists, otherwise add it to rtypes in sorted
- order. Return the current supscript}
- {binary search and insertion}
- var low,high,mid,ii,at:integer;
- ss:str255;
- begin
- low:=1;
- high:=rtypes_count;
- at:=low;
- while low<=high do
- begin
- mid:=(low+high) div 2;
- if atype=rtypes[mid].thetype then
- begin
- find_and_add_type:=mid;
- exit;
- end
- else if atype>rtypes[mid].thetype then
- begin
- low:=mid+1;
- at:=mid+1;
- end
- else {atype<rtypes[mid].thetype}
- begin
- high:=mid-1;
- at:=mid;
- end;
-
- end;{while}
-
- if rtypes_count>=maxtype then
- begin
- poststatus('My maximum resource type count exceeded',errorline);
- find_and_add_type:=0;
- exit;
- end;
- for ii:=rtypes_count downto at do
- begin
- rtypes[ii+1]:=rtypes[ii]
- end;
- rtypes[at].thetype:=atype;
- rtypes[at].safety:=howsafe;
- rtypes[at].occurs:=0;
- {wait_for_buttons(concat(atype,safetynames[howsafe],continuebut));}
-
- rtypes_count:=rtypes_count+1;
- find_and_add_type:=at;
- end;{function}
- {$S wascore}
- function find_type_old(atype:restype):integer;
- {old version}
- label 99;
- var i:integer;
- result:integer;
- begin
- result:=0;
- for i:=1 to rtypes_count do
- begin
- with rtypes[i] do
- begin
- if thetype=atype then
- begin
- result:=i;
- goto 99;
- end;
- end;
- end;
- 99:
- find_type_old:=result;
-
- end;{find_type}
- {$S core }
- procedure add_type(atype:restype;howsafe:safetype);
- {add a type and it's classification to the list in memory
- if it does not already exist}
- var ignore:integer;
- begin
- ignore:=find_and_add_type(atype,howsafe);
- end;
- {$S wascore }
- procedure add_type_old(atype:restype;howsafe:safetype);
- var i,result:integer;
- {add type to tables if it does not already exist}
- {old version}
- begin
- if find_type(atype)=0 then
- begin
- if rtypes_count<maxtype then
- begin
- rtypes_count:=rtypes_count+1;
- with rtypes[rtypes_count] do
- begin
- thetype:=atype;
- safety:=howsafe;
- occurs:=0;
- end ;{with}
- sorttypes(rtypes,rtypes_count);
- end
- else
- begin
- poststatus('My maximum resource type count exceeded',errorline);
- end;
-
- end;
-
- end;{add_type}
-
- {$S appldet}
- procedure detail_appl_check;
- {Compare the checksums in memory with the old checksums on file for applications}
- {This assumes both are sorted by creator,creationdate,filename,dirid}
- {if no checksums were done before, just compare sizes}
-
- type statetype=(oldgreater,newgreater,
- checkequality,sizeequality,
- sameappl,sameapplbadsize,sameapplbadcheck);
- var
- jnew:integer;
- jcreator:ostype;
- jcreatorstart:integer;
- jcreatorend:integer;
- state:statetype;
- oldfile,newfile:myfilenametype;
- filecomp:integer;
- oldcreator,newcreator:OStype;
- oldcreationdate,newcreationdate:longint;
- oldsize,newsize:longint;
- oldunsafecount,newunsafecount:longint;
- oldchecksize,newchecksize:longint;
- oldchecksum,newchecksum:integer;
- olddirid,newdirid:longint;
- oldvol,newvol:integer;
- newhidden:boolean;
- end_on_old,end_on_new:boolean;
- oid,nid:str255;
-
- procedure get_next_old;
- label 22;{repeat}
- var line:str255;
- tokens:tokenstype;
- ntokens:integer;
- work:longint;
- begin
- 22:
- ntokens:=0;
- repeat
- if end_on_old then exit;
- if eof(infile) then
- begin
- end_on_old:=true;
- exit;
- end;
- read_input(line);
- {treat "*****" as end}
- if test_end_flag(line) then
- begin
- end_on_old:=true;
- exit;
- end;
- tabscan(line,tokens,ntokens)
-
- until(ntokens>=9);{ignore short/blank lines}
-
- {breakdown line as:}
- {creator <tab> creationdate <tab> filename <tab> dirid <tab> volume
- <tab> thesize <tab> unsafecount <tab> checksize <tab> checksum}
-
- filltype(oldcreator,tokens[1]);{blank fill type}
- stringtonum(tokens[2],oldcreationdate);
- oldfile:=tokens[3];
- stringtonum(tokens[4],olddirid);
- stringtonum(tokens[5],work);
- oldvol:=work;
- stringtonum(tokens[6],oldsize);
- stringtonum(tokens[7],work);
- oldunsafecount:=work;
- stringtonum(tokens[8],oldchecksize);
- stringtonum(tokens[9],work);
- oldchecksum:=work;
- {additional stuff at end of line will be ignored}
- {skip non-matching volumes}
- if oldvol<>0 then
- if oldvols[oldvol].matchto=0 then goto 22;
- end;{get_next_old}
-
- procedure get_next_new;
- label 88,22;
- var jj:integer;
- begin
- 22:
- jnew:=jnew+1;
- if jnew>acount then
- begin
- end_on_new:=true;
- exit;
- end;
- (*
- {info on applications}
- applinforec=record
- thesize:longint;
- creator:OStype;
- creationdate:longint;
- dirid:longint;
- filename:myfilenametype;
- unsafecount:integer;
- checksum:integer;
- checksize:longint;
- flags:integer;
- end;
-
- *)
- with ainfo^[jnew] do
- begin
- newcreator:=creator;
- newcreationdate:=creationdate;
- newfile:=filename;
- newsize:=thesize;
- newunsafecount:=unsafecount;
- newchecksize:=checksize;
- newchecksum:=checksum;
- newdirid:=dirid;
- {matching old volume if any}
- if (flags and applvolumemask)=0 then
- begin
- newvol:=0
- end
- else
- begin
- newvol:=newvols[(flags and applvolumemask)].matchto;
- {skip non-matching volumes}
- if newvol=0 then goto 22;
- end;
-
- newhidden:=(flags and applinvisiblemask)<>0;
- end;{with}
-
- {find last occurance of current signature}
- if newcreator<>jcreator then
- begin
- jcreator:=newcreator;
- jcreatorstart:=jnew;
- for jj:=jnew+1 to acount do
- if ainfo^[jj].creator<>jcreator then
- begin
- jcreatorend:=jj-1;
- goto 88;
- end;
- jcreatorend:=acount;
- 88:
- end;
-
- end;{get_next_new}
-
- procedure was_renamed_or_moved;
- label 88;
- {one to many check for current signature}
- {call this if no match and there is more than one occurance}
- {this assumes that an application is OK regardless of name and
- directory changes if other features match:
- creationdate
- checksize
- checksum
- unsafecount
-
- or if (oldunsafecount=notcounted)
- creationdate
- thesize}
- var
- jj:integer;
- begin
- for jj:=jcreatorstart to jcreatorend do
- with ainfo^[jj] do
- begin
- if creationdate=oldcreationdate then
- if (oldunsafecount=notcounted) or (fastapplcheck) then
- begin
- if (oldsize=thesize) then
- begin
- flags:=flags or applrenamemask;
- end
- end
- else
- begin
- if oldunsafecount=unsafecount then
- if oldchecksize=checksize then
- if oldchecksum=checksum then;
- begin
- flags:=flags or applrenamemask;
- end;
- end;
- end;
- end;{was_moved_or_renamed}
-
- begin{detail_appl_check}
- jcreator:='$$$$';
- if not inputopen then exit;
- position_to_section(sect_num_applications);
- jnew:=0;
- end_on_old:=false;
- end_on_new:=false;
- get_next_old;
- get_next_new;
-
- while not(end_on_old or end_on_new) do
- begin
-
- {debug info}
- if detaildebugflag then
- begin
- poststatus(concat(concat(oldfile,':'),newfile),detailbugline);
- poststatus(concat(concat(oldcreator,':'),newcreator),detailbugline+1);
- numtostring(oldcreationdate,oid);
- numtostring(newcreationdate,nid);
- poststatus(concat(concat(oid,':'),nid),detailbugline+2);
- numtostring(olddirid,oid);
- numtostring(newdirid,nid);
- poststatus(concat(concat(oid,':'),nid),detailbugline+3);
- end;
-
- state:=newgreater;
-
- {if creator signature matches, check for rename/move on partial match}
- if oldcreator=newcreator then
- begin
- if oldcreationdate=newcreationdate then
- begin
- {wait_for_buttons('creation match',continuebut);}
- filecomp:=filenamecompare(oldfile,newfile);
- if filecomp=0{equal} then
- begin
- {wait_for_buttons('filename match',continuebut);}
- if oldvol=newvol then
- begin
- if olddirid=newdirid then
- begin
- {wait_for_buttons('dir match',continuebut);}
- {this is the same file name in the same directory}
- state:=sameappl;
- {now check for changed vs exact match}
- {match on
- checksize
- checksum
- unsafecount
-
- or if oldunsafecount=notcounted
- thesize}
- if (oldunsafecount=notcounted) or (fastapplcheck) then
- begin
- if not newhidden then state:=sameapplbadsize;
- if (oldsize=newsize) or newhidden then
- {less stringent check on non-application
- hidden files - Desktop changes size}
- state:=sizeequality;
- end
- else
- begin
- state:=sameapplbadcheck;
- if oldchecksize=newchecksize then
- if oldchecksum=newchecksum then
- if oldunsafecount=newunsafecount then
- state:=checkequality;
- end;
-
- end{=dir}
- else
- begin
- if olddirid>newdirid then
- begin
- state:=oldgreater;
- end;
- was_renamed_or_moved;
- end{<>dir}
- end{=vol}
- else
- begin
- if oldvol>newvol then
- begin
- state:=oldgreater;
- end;
- was_renamed_or_moved;
- end{<>vol}
- end{=file}
- else
- begin
- if filecomp>0{oldfile>newfile} then
- begin
- state:=oldgreater;
- end;
- was_renamed_or_moved;
- end{<>file}
-
- end{=creation date}
- else
- begin
- if oldcreationdate>newcreationdate then
- begin
- state:=oldgreater;
- end;
- was_renamed_or_moved;
- end{<>creation date}
-
- end{= creator}
- else if oldcreator>newcreator then
- begin
- state:=oldgreater;
- end;
-
- postmem(memline);
- {end of compares}
- case state of
- sizeequality:
- begin
- {equality on the basis of size - fast check}
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applexactmatchmask;
- {wait_for_buttons('equal appl',continuebut);}
- if fastapplcheck and (oldunsafecount<>notcounted) then
- begin
- {copy old checksums etc.
- for future reference so that info
- is not lost by writing output from
- a short check}
- with ainfo^[jnew] do
- begin
- checksum:=oldchecksum;
- unsafecount:=oldunsafecount;
- checksize:=oldchecksize;
- end;
- end;
- {moved from above to fix bug in version 53 5/1/88}
- get_next_old;
- get_next_new;
- end;
- checkequality: begin
- {equality on the basis of all checksums - full check}
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applexactmatchmask;
- get_next_old;
- get_next_new;
- {wait_for_buttons('equal appl',continuebut);}
- end;
- sameappl: begin
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applchangedmask;
- if detaildebugflag then
- wait_for_buttons('same appl no match',continuebut);
- get_next_old;
- get_next_new;
- end;
- sameapplbadsize: begin
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applchangedmask;
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applbadsizemask;
- if detaildebugflag then
- wait_for_buttons('same appl no match/bad size',continuebut);
- {automatic recheck}
- recheck_changed(jnew,oldunsafecount,oldchecksize,oldchecksum);
- get_next_old;
- get_next_new;
- end;
- sameapplbadcheck: begin
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applchangedmask;
- ainfo^[jnew].flags:=ainfo^[jnew].flags or applbadcheckmask;
- if detaildebugflag then
- wait_for_buttons('same appl no match/bad check',continuebut);
- get_next_old;
- get_next_new;
- end;
- oldgreater:begin
- if detaildebugflag then
- wait_for_buttons('old greater',continuebut);
- get_next_new;
- end;
- newgreater:begin
- if detaildebugflag then
- wait_for_buttons('new greater',continuebut);
- get_next_old;
- end;
- end;{case of state}
-
- end;{while not done}
-
- {skip to end of input for this section}
- while (not end_on_old) do get_next_old;
- if detaildebugflag then clear_to_end(detailbugline);
- end;
- procedure show_APPL_detail_changes;
- {On Screen Summary of Application Changes}
- label 77;
- const
- chlimit=10;
- var
- j:integer;
- charray:array[1..chlimit] of integer;
- ch,chcount:integer;
- filename,dname:str255;
- work:str255;
- jtype:integer;
- dd:longint;
- newappl:longint;
- moveorrenamedappl:longint;
- changedappl:longint;
- safechangedappl:longint;
- dangerappl:longint;
- ans_show,notify:boolean;
- hidden:boolean;
- vnum:integer;
- dummy:str255;
- procedure show_change(mess:str255);
- begin
- folder_info_two(dd,newvols[vnum].volrefnum,dname,dummy,false);
- clear_to_end(fileline);
- PostStatus(newvols[vnum].vname,fileline);
- work:= concat(concat(dname,':'),filename);
- poststatus(work,fileline+1);
-
- wait_for_buttons(mess,continuebut);
- clear_to_end(fileline);
- end;
-
- procedure mark_change(jj:integer);
- begin
- notify:=true;
- {keep pointers to the first few changes to speed up display}
- if chcount<chlimit then
- begin
- chcount:=chcount+1;
- charray[chcount]:=jj;
- end;
- end;
-
- begin
- chcount:=0;
- {skip this all if there was no input file}
- if not inputopen then exit;
- {count changes}
- newappl:=0;
- moveorrenamedappl:=0;
- changedappl:=0;
- safechangedappl:=0;
- dangerappl:=0;
- notify:=false;
- for j:=1 to acount do
- begin
- {only flag changes to stuff on matched volumes}
- if newvols[(ainfo^[j].flags and applvolumemask)].matchto<>0 then
- begin
- if (ainfo^[j].flags and applexactmatchmask)<>applexactmatchmask then
- if (ainfo^[j].flags and applrenamemask)=applrenamemask then
- begin
- {moved or renamed or duplicated}
- moveorrenamedappl:=moveorrenamedappl+1;
- mark_change(j);
- end
- else
- begin
- if (ainfo^[j].flags and applchangedmask)=applchangedmask then
- begin
- {changed}
- changedappl:=changedappl+1;
- mark_change(j);
- end
- else if (ainfo^[j].flags and applsafechangedmask)=applsafechangedmask then
- begin
- {safe changed - size only}
- safechangedappl:=safechangedappl+1;
- mark_change(j);
- end
- else
- begin
- {"new"}
- newappl:=newappl+1;
- mark_change(j);
-
- end
- end;
- end;
- if (ainfo^[j].flags and appldangermask)=appldangermask then
- begin
- dangerappl:=dangerappl+1;
- mark_change(j);
- end;
- end;{for}
- {quick skip to end}
- if chcount<chlimit then
- begin
- chcount:=chcount+1;
- charray[chcount]:=acount+1;
- end;
-
- {exit if no changes}
- if not notify then exit;
-
- {notify of changes and give a chance to see the changes on screen and on disk}
- sysbeep(1);
- clear_to_end(askline-3);
- poststatus('',askline-4);
- poststatus('',askline-5);
- numtostring(safechangedappl,work);
- work:=concat('Safe size changes: ',work);
- poststatus(work,askline-5);
- numtostring(newappl,work);
- work:=concat('New: ',work);
- poststatus(work,askline-4);
- numtostring(moveorrenamedappl,work);
- work:=concat('Renamed/Moved: ',work);
- poststatus(work,askline-3);
- numtostring(changedappl,work);
- work:=concat('Changed: ',work);
- poststatus(work,askline-2);
-
- if Dangerappl<>0 then
- begin
- numtostring(dangerappl,work);
- work:=concat('Dangerous: ',work);
- poststatus(work,askline-1);
- end;
-
- work:=
- 'These are differences in the applications or hidden files. Do you want to see the details on screen?';
- ans_show:=ask(work,nodefaultbut);
- clear_to_end(askline-5);
-
- open_output_dialog(false,nodefaultbut);
-
- if not ans_show then exit;
- poststatus('List differences in applications or hidden files:',pathline);
- {loop to show individual changes}
- j:=0;
- ch:=0;
- while(j<=acount)do
- begin
- {faster skip to marked changes}
- if ch<chcount then
- begin
- ch:=ch+1;
- j:=charray[ch];
- end
- else
- begin
- j:=j+1;
- end;
- if j>acount then goto 77;
-
- filename:=ainfo^[j].filename;
- dd:=ainfo^[j].dirid;
- vnum:=ainfo^[j].flags and applvolumemask;
- hidden:=(ainfo^[j].flags and applinvisiblemask)<>0;
- if newvols[(ainfo^[j].flags and applvolumemask)].matchto<>0 then
- begin
- if (ainfo^[j].flags and applexactmatchmask)<>applexactmatchmask then
- if (ainfo^[j].flags and applrenamemask)=applrenamemask then
- begin
- {moved or renamed or duplicated}
- Show_change('was moved, renamed or duplicated')
- end
- else
- begin
- if (ainfo^[j].flags and applchangedmask)=applchangedmask then
- begin
- {changed}
- if hidden then
- Show_change('Changed Invisible File')
- else
- Show_change('Changed Application');
- end
- else if (ainfo^[j].flags and applsafechangedmask)=applsafechangedmask then
- begin
- {safe changed}
- Show_change('Application: Safe change in size');
- end
-
- else
- begin
- if hidden then
- Show_change('New Invisible File')
- else
- Show_change('New Application');
- end
- end;
- end;
- if (ainfo^[j].flags and appldangermask)=appldangermask then
- begin
- Show_change('Infected with a dangerous resource type');
- end;
- end;{for}
- 77:
- clear_to_end(pathline);
- end;{proc show_APPL_detail_changes}
-
- {$S detail}
- procedure detail_resource_check;
- {Compare the checksums in memory with the old checksums on file}
- {This assumes both are sorted by filename,type,id}
- {If there is more than one entry per id the old file is
- assumed sorted by filename,type,id,size,name and checksum.
- This is to allow a old checksum file valid for two system
- versions to be constructed, but this feature is not fully
- supported}
-
- type statetype=(oldgreater,newgreater,equality,sameid);
- var
- jnew:integer;
- state:statetype;
- oldtype,newtype:restype;
- oldfile,newfile:myfilenametype;
- oldid,newid:integer;
- oldsize,newsize:longint;
- oldchecksum,newchecksum:integer;
- oldname,newname:myresnametype;
- end_on_old,end_on_new:boolean;
- oid,nid:str255;
- filecomp:integer;
-
- procedure get_next_old;
- var line:str255;
- tokens:tokenstype;
- ntokens:integer;
- work:longint;
- begin
- ntokens:=0;
- repeat
- if end_on_old then exit;
- if eof(infile) then
- begin
- end_on_old:=true;
- exit;
- end;
- read_input(line);
- {treat "*****" as end}
- if test_end_flag(line) then
- begin
- end_on_old:=true;
- exit;
- end;
- tabscan(line,tokens,ntokens)
-
- until(ntokens>=6);{ignore short/blank lines}
-
- {breakdown line as:}
- {type <tab> id <tab> size <tab> checksum <tab> name <tab> filename}
- filltype(oldtype,tokens[1]);{blank fill type}
- stringtonum(tokens[2],work);
- oldid:=work;
- stringtonum(tokens[3],oldsize);
- stringtonum(tokens[4],work);
- oldchecksum:=work;
- oldname:=tokens[5];
- oldfile:=tokens[6];
- {additional stuff at end of line will be ignored}
-
- end;{get_next_old}
-
- procedure get_next_new;
-
- begin
- jnew:=jnew+1;
- if jnew>rcount then
- begin
- end_on_new:=true;
- exit;
- end;
- with rinfo^[jnew] do
- begin
- newtype:=thetype;
- newfile:=sysfiles[(filenameindex and fnamemask)];
- newid:=theid;
- newsize:=thesize;
- newchecksum:=checksum;
- newname:=thename;
- end;
-
- end;{get_next_new}
- procedure nums(n1,n2,n3,n4:longint;var s:string);
- {build line for debug output}
- var w:str255;
- begin
- numtostring(n1,w);
- s:=w;
- numtostring(n2,w);
- s:=concat(concat(s,' ',w));
- numtostring(n3,w);
- s:=concat(concat(s,':',w));
- numtostring(n4,w);
- s:=concat(concat(s,' ',w));
- end;
-
- begin{detail_resource_check}
- if not inputopen then exit;
- position_to_section(sect_num_res_checks);
- poststatus('Compare System Folder Resources',fileline);
- jnew:=0;
- end_on_old:=false;
- end_on_new:=false;
- get_next_old;
- get_next_new;
- while not(end_on_old or end_on_new) do
- begin
- {debug info}
- if detaildebugflag then
- begin
- poststatus(concat(concat(oldfile,':'),newfile),detailbugline);
- poststatus(concat(concat(oldtype,':'),newtype),detailbugline+1);
- numtostring(oldid,oid);
- numtostring(newid,nid);
- poststatus(concat(concat(oid,':'),nid),detailbugline+2);
- nums(oldsize,oldchecksum,newsize,newchecksum,oid);
- poststatus(oid,detailbugline+3);
- poststatus(concat(concat(concat(concat('"',oldname),':'),
- newname),'"'),detailbugline+4);
- end;
- state:=newgreater;
- filecomp:=filenamecompare(oldfile,newfile);
- if filecomp=0{oldfile=newfile} then
- begin
- if oldtype=newtype then
- begin
- if oldid=newid then
- begin
-
- {---mark new as id level match---
- since id's are unique this can be used to distingush
- added resources from changed resources}
-
- state:=sameid;
- rinfo^[jnew].filenameindex:=(rinfo^[jnew].filenameindex or idmatchmask);
-
- if oldsize=newsize then
- begin
- if resnamecompare(oldname,newname)=0 {oldname=newname} then
- begin
- if oldchecksum=newchecksum then
- begin
-
- {---mark exact equality---}
-
- state:=equality;
- rinfo^[jnew].filenameindex:=(rinfo^[jnew].filenameindex or exactmatchmask);
-
- end{checksum equal}
- end{name equal}
- end{size equal}
- end{id equal}
-
- else if oldid>newid then
- state:=oldgreater;
- end{type equal}
-
- else if oldtype>newtype then
- state:=oldgreater;
- end{file equal}
-
- else if filecomp>0{oldfile>newfile} then
- state:=oldgreater;
-
- {end of compares}
- case state of
- equality: begin
- get_next_old;
- get_next_new;
- end;
- sameid: begin
- {in case the old file has multiple entries for the same id}
- if detaildebugflag then
- wait_for_buttons('same id no match',continuebut);
- get_next_old;
- end;
- oldgreater:begin
- if detaildebugflag then
- wait_for_buttons('old greater',continuebut);
- get_next_new;
- end;
- newgreater:begin
- if detaildebugflag then
- wait_for_buttons('new greater',continuebut);
- get_next_old;
- end;
- end;{case of state}
-
- end;{while not done}
-
- {skip to end of input for this section}
- while (not end_on_old) do get_next_old;
- if detaildebugflag then clear_to_end(detailbugline);
- end;
- procedure show_detail_changes;
- {On Screen Summary of Changes}
- {this will show added or changed resources but not
- deleted resources}
- var jres:integer;
- new:boolean;
- filename:str255;
- safename:str255;
- id,work,name:str255;
- jtype:integer;
- neworchanged:longint;
- norc:str255;
- ans_show:boolean;
- procedure show_change(mess:str255);
- begin
- clear_to_end(fileline);
- work:= concat('File: ',filename);
- poststatus(work,fileline);
- work:=concat(concat('Type:',rinfo^[jres].thetype),' (');
- work:=concat(concat(concat(work,safename),') Id:'),id);
- name:=rinfo^[jres].thename;
- if name<>'' then
- begin
- work:=concat(concat(work,' Name:'),name);
- end;
- poststatus(work,errorline);
- wait_for_buttons(mess,continuebut);
- clear_to_end(fileline);
- end;
- begin
- {skip this all if there was no input file}
- if not inputopen then exit;
- {count changes}
- neworchanged:=0;
- for jres:=1 to rcount do
- begin
- if (rinfo^[jres].filenameindex and exactmatchmask)<>exactmatchmask then
- neworchanged:=neworchanged+1;
- end;{for}
-
- {exit if no changes}
- if neworchanged=0 then exit;
-
- {notify of changes and give a chance to see the changes on screen and on disk}
- sysbeep(1);
- numtostring(neworchanged,norc);
- norc:=concat(concat('There are ',norc),
- ' new or changed resources in the system folder. Do you want to see the details on screen?');
- ans_show:=ask(norc,nodefaultbut);
-
- open_output_dialog(true,nodefaultbut);
-
- if not ans_show then exit;
-
- {loop to show individual changes}
- for jres:=1 to rcount do
- begin
-
- {test flag to see if exact match}
- if (rinfo^[jres].filenameindex and exactmatchmask)<>exactmatchmask then
- begin
- {test flag to see if new or changed}
- new:=not ((rinfo^[jres].filenameindex and idmatchmask)=idmatchmask);
- filename:=sysfiles[(rinfo^[jres].filenameindex and fnamemask)];
- {name for safety level of type}
- jtype:=find_type(rinfo^[jres].thetype);
- if jtype=0 then
- safename:=safetynames[Unknown]
- else
- begin
- safename:=safetynames[rtypes[jtype].safety];
- end;
- numtostring(rinfo^[jres].theid,id);
- if new then
- show_change('This resource is new')
- else
- show_change('This resource is changed');
- end
- else
- if rtypes[find_type(rinfo^[jres].thetype)].safety=dangerous then
- begin
- show_change('This is a dangerous resource type associated with viruses');
- end;
- end;{for}
-
-
- end;{proc show_detail_changes}
- {$S start3 }
- procedure start_types;
- {set up table of some resource types to allow starting without an
- input file and for testing}
- {See Inside Mac Volume V resource manager for a listing
- of many types}
- begin
- rtypes_count:=0;
- safetynames[Safe]:='Safe';
- safetynames[Unsafe]:='Unsafe';
- safetynames[Unknown]:='Unknown';
- safetynames[Dangerous]:='Dangerous';
- {resource types associated with known viruses}
- add_type('nVIR',Dangerous);
- {Some RESOURCE TYPES KNOWN TO CONTAIN EXECUTABLE CODE}
- {also include types that occur sometimes in known viruses,sometimes
- in normal use}
- add_type('CODE',unsafe);
- add_type('INIT',unsafe);
- add_type('ROvr',unsafe);
- add_type('ROv#',unsafe);
- add_type('PTCH',unsafe);
- add_type('PACK',unsafe);
- add_type('PDEF',unsafe);
- add_type('ADBS',unsafe);
- add_type('CACH',unsafe);
- add_type('CDEF',unsafe);
- add_type('cdev',unsafe);
- add_type('DRVR',unsafe);
- add_type('FKEY',unsafe);
- add_type('FMTR',unsafe);
- add_type('KCHR',unsafe);
- add_type('LDEF',unsafe);
- add_type('MBDF',unsafe);
- add_type('MDEF',unsafe);
- add_type('MMAP',unsafe);
- add_type('SERD',unsafe);
- add_type('WDEF',unsafe);
- add_type('boot',unsafe);
- add_type('insc',unsafe);
- add_type('XCMD',unsafe);
- add_type('XFNC',unsafe);
- add_type('atpl',unsafe);{used by the "scores" virus}
- add_type('DATA',unsafe);{used by the "scores" virus}
- {RESOURCE TYPES KNOWN NOT TO CONTAIN EXECUTABLE CODE}
- add_type('FONT',safe);
- add_type('ALRT',safe);
- add_type('BNSL',safe);
- add_type('DITL',safe);
- add_type('DLOG',safe);
- add_type('FOND',safe);
- add_type('FONT',safe);
- add_type('ICN#',safe);
- add_type('ICON',safe);
- add_type('MENU',safe);
- add_type('PAT ',safe);
- add_type('PAT#',safe);
- add_type('PICT',safe);
- add_type('PREC',safe);
- add_type('SIZE',safe);
- add_type('STR ',safe);
- add_type('STR#',safe);
- add_type('TEXT',safe);
- add_type('LAYO',safe);{desktop layout}
- add_type('PAPA',safe);{chooser setting}
- add_type('PREF',safe);{print monitor preferences}
- add_type('RLRL',safe);{print monitor settings-such as window position}
- add_type('CNTL',safe);
- add_type('CURS',safe);
- add_type('NFNT',safe);
- add_type('WIND',safe);{Window template - used in system 6.0 DAs}
- add_type('fndr',safe);
- add_type('itl0',safe);{date/time formats no code hooks}
- add_type('scrn',safe);{control panel screen settings}
- add_type('BMLS',safe);{appleshare server settings in Appleshare Prep}
- add_type('clut',safe);
- add_type('clst',safe);
- add_type('mach',safe);
- add_type('nrct',safe);
- add_type('ppat',safe);{pixel pattern}
-
- {add_type('',safe);}
- end;
- {$S }
- procedure setdefaultbutton(value:integer);
- {set default button for pauses, questions and force updates}
- var rr:rect;
- begin
- setport(mainwindow);
- if defaultbutton<>0 then
- begin
- rr:=buttonrects[defaultbutton];
- insetrect(rr,-5,-5);
- Invalrect(rr);
- end;
- defaultbutton:=value;
- if defaultbutton<>0 then
- begin
- rr:=buttonrects[defaultbutton];
- insetrect(rr,-5,-5);
- Invalrect(rr);
- end;
- end;
- {$S event}
- procedure wait_for_buttons{(ss:str255;default:integer)};
- {Wait, display message, and give a chance to:
- "continue", "halt" or "shutdown"}
- begin
- setdefaultbutton(default);
- askanswered:=false;
- HiLiteControl(buttons[continuebut],0);{active}
- PostStatus(ss,AskLine);
- repeat
- doEvent(true);
- until askanswered;
- setdefaultbutton(nodefaultbut);
- clear_to_end(askline);
- HiLiteControl(buttons[continuebut],255);{inactive}
- doevent(false);
- end;
- procedure wait_for_options;
- var i:integer;
- begin
- setdefaultbutton(continuebut);
- optioncontrolsactiveflag:=true;
- adjust_option_controls;
- Invalrect(mainwindow^.portrect);
- askanswered:=false;
- HiLiteControl(buttons[continuebut],0);{active}
- for i:=1 to moptcon do Showcontrol(optcons[i]);
- repeat
- doEvent(true);
- until askanswered;
-
- setdefaultbutton(nodefaultbut);
- optioncontrolsactiveflag:=false;
- for i:=1 to moptcon do Hidecontrol(optcons[i]);
- Invalrect(mainwindow^.portrect);
- HiLiteControl(buttons[continuebut],255);{inactive}
- doevent(false);
- end;
- procedure wait_for_start(ss:str255;waitsecs:integer);
- {wait, display message and startup buttons:
- "ShortCheck", "FullCheck", "SkipIt" "Shutdown"}
- {if a certian time has elapsed, continue}
- var default:integer;
- wait,waituntil:longint;
- tag:str255;
- begin
- default:=startupdefaultbutton;;
- wait:=waitsecs*60;
- numtostring(waitsecs,tag);
- tag:=concat(concat(' (Auto start after ',tag), ' sec)');
- setdefaultbutton(default);
- {askanswered:=false;}{set in initialize instead}
- HiLiteControl(buttons[continuebut],0);{active}
- {poststatus(tag,errorline);}
- ss:=concat(ss,tag);
- PostStatus(ss,AskLine);
- doevent(false);
- optionkeyflag:=optionkeyflag or option_key_down;{test option key}
- waituntil:=wait+tickcount;
- repeat
- optionkeyflag:=optionkeyflag or option_key_down;{test option key}
- doEvent(true);
- until ((askanswered) or (tickcount>waituntil));
- setdefaultbutton(nodefaultbut);
- clear_to_end(errorline);
- FlushEvents(MDownMask,0);
- HiLiteControl(buttons[continuebut],255);{inactive}
- doevent(false);
- end;
-
- {$S startup}
- procedure offer_to_replace_input;
- var doit:boolean;
- mess:str255;
- err:oserr;
- myhpb:Hparamblockrec;
- mycmpb:CmovePBrec;
- work:longint;
- cr:string[1];
- now:longint;
- uname:str255;
- (*
- infile,outfile:text;
- inputopen,outputopen,inputnotdefault:boolean;
- inputfile_dirid:longint;
- inputfile_Vrefnum:integer;
- inputfile_filename:str255;
- outputfile_dirid:longint;
- outputfile_Vrefnum:integer;
- outputfile_filename:str255;
- *)
- begin
- cr:=chr(13);
- if (inputfile_filename='') or (outputfile_filename='') then exit;
- if inputfile_Vrefnum<>outputfile_vrefnum then exit;
- if inputopen then close_and_flush(infile,inputopen);
- if outputopen then close_and_flush(outfile,outputopen);
- {build unique file name for use in rename}
-
- getdatetime(now);
- now:=$00FFFFF and now;
- now:=now+((tickcount shl 16) and $00FFFFFF);
- now:=$00FFFFF and now;
- numtostring(now,uname);
- uname:=concat('VcheckTempOut',uname);
-
- mess:=concat(concat(concat(concat(concat(concat(
- 'Rename Output File:"',outputfile_filename),'" to'),cr),
- 'Replace Input File:"'),inputfile_filename),'"?');
- doit:=ask(mess,nobut);
- if doit then
- begin
-
- err:=setvol(nil,inputfile_vrefnum);
- if err=noerr then {if set vol ok}
- begin
- {Delete input file}
- with myhpb do
- begin
- iocompletion:=nil;
- ionameptr:=@inputfile_filename;
- iovrefnum:=inputfile_Vrefnum;
- ioDirid:=inputfile_dirid;
- end;{with}
-
- err:=PBHDelete(@myhpb,false);
-
- if err=noerr then {if delete ok}
- begin
- {Rename output file to unique temp name}
- with myhpb do
- begin
- iocompletion:=nil;
- ionameptr:=@outputfile_filename;
- iovrefnum:=outputfile_Vrefnum;
- iomisc:=@uname;
- iodirid:=outputfile_dirid;
- end;{with}
-
- err:=PBHRename(@myhpb,false);
-
- if err=noerr then{1st rename ok}
- begin
- {Move output file}
- with mycmpb do
- begin
- iocompletion:=nil;
- ionameptr:=@uname;
- iovrefnum:=outputfile_Vrefnum;
- ionewname:=nil;
- ionewdirid:=inputfile_dirid;
- iodirid:=outputfile_dirid;
- end;{with}
-
- err:=PBCATMOVE(@mycmpb,false);
-
- if err=noerr then{if move ok}
- begin
- {Rename output file from temp name
- to input name}
- with myhpb do
- begin
- iocompletion:=nil;
- ionameptr:=@uname;
- iovrefnum:=outputfile_Vrefnum;
- iomisc:=@inputfile_filename;
- iodirid:=inputfile_dirid;
- end;{with}
-
- err:=PBHRename(@myhpb,false);
-
- if err<>noerr then{if 2nd rename not ok}
- begin
- numtostring(err,mess);
- mess:=concat(concat(concat
- ('Rename of Output File Failed:',mess),'. Output in:'),uname);
- wait_for_buttons(mess,ContinueBut);;
- end;{2nd rename ok}
- end{move ok}
- else
- begin
- mess:=concat(concat(concat
- ('Move of Output File Failed:',mess),'. Output in:'),uname);
- wait_for_buttons(mess,ContinueBut);;
- end;{move not ok}
- end{1st rename ok}
- else
- begin
- numtostring(err,mess);
- mess:=concat('Rename of Output File Failed:',mess);
- wait_for_buttons(mess,ContinueBut);
- end; {1st rename not ok}
- end{delete ok}
- else
- begin
- numtostring(err,mess);
- mess:=concat('Delete of Input File Failed:',mess);
- wait_for_buttons(mess,ContinueBut);
- end{delete not ok}
- end;{set vol ok}
- end;{doit}
- end;{proc}
-
- procedure reset_and_save_info( var filevar:text;filename:str255);
- {replace reset with this in all instances when opening input
- to save the input directory and filename info}
- var mywdpb:wdpbrec;
- dummy:str255;
- err:oserr;
- begin
- with mywdpb do
- begin
- dummy:='';
- ioCompletion:= NIL;
- ionameptr:=@dummy;
- iovrefnum:=0;
- iowdindex:=0;
- end;
- err:=PBHgetVol(@mywdpb,false);
- if err=noerr then
- with mywdpb do
- begin
- inputfile_dirid:=iowddirid;
- inputfile_vrefnum:=ioWDVrefnum;
- inputfile_filename:=filename;
- end
- else
- begin
- inputfile_dirid:=2;
- inputfile_vrefnum:=0;
- inputfile_filename:='';
- end;
-
-
- reset(filevar,filename); {do turbo open}
-
- end;
-
- procedure rewrite_and_save_info( var filevar:text;filename:str255);
- {replace rewrite with this in all instances when opening output
- to save the output directory and filename info}
- var mywdpb:wdpbrec;
- dummy:str255;
- err:oserr;
- begin
- with mywdpb do
- begin
- dummy:='';
- ioCompletion:= NIL;
- ionameptr:=@dummy;
- iovrefnum:=0;
- iowdindex:=0;
- end;
- err:=PBHgetVol(@mywdpb,false);
- if err=noerr then
- with mywdpb do
- begin
- outputfile_dirid:=iowddirid;
- outputfile_vrefnum:=ioWDVrefnum;
- outputfile_filename:=filename;
- end
- else
- begin
- outputfile_dirid:=2;
- outputfile_vrefnum:=0;
- outputfile_filename:='';
- end;
-
- outputfile_filename:=filename;
-
- rewrite(filevar,filename); {do turbo open}
-
- end;
-
- procedure mySFold( Var filevar : text;
- prompt :str255;
- var filepara :str255;
- var cancel:boolean);
- {
- Do a Standard file open dialog to open an existing TEXT file
- as a TURBO PASCAL text file.
- Use the toolbox to get the file name and set the default vol/folder.
- Use Reset to do the actual open for Turbo.
- This may work only on the 128k ROMS
- }
- var
- topleft,center :point;
- ShowTypes : SFTypeList;
- NTypes :integer ;
- theErr :OSErr;
- Reply :SFreply;
- filename :string[63];
- ScrHres,ScrVres : integer;
- vol : integer;
- vserr :OSerr;
-
-
- begin
- filepara:='';
- with center do
- begin
- with screenbits.bounds do
- begin
- v:=(top+bottom) div 2;
- h:=(left+right) div 2;
- end;
- end;
-
- topleft.h:=center.h-170; {position of topleft}
- topleft.v:=center.v-120;
-
- ShowTypes[0]:='TEXT';
- Ntypes:=1;
- Cancel:=false;
- SFGetFile(topleft,prompt,nil,NTypes,ShowTypes,nil,Reply);
- if Reply.good then
- begin
-
- vol:=reply.vrefnum;
- filename:=reply.fname;
- vserr:=SetVol(nil,vol); {change default volume}
-
- {SFGetFile does not do an actual open : FSOpen or PBOpen
- are called to do this in the examples I have seen}
-
- reset_and_save_info(filevar,filename); {do turbo open}
- filepara:=filename;
- end
- else
- begin
- {may be a cancel or other error}
- Cancel:=true;
-
- end;
-
- end; {of proc MySFold }
-
- procedure mySFnew( Var filevar : text;
- prompt :str255;
- orgname :str255;
- Creator :OStype;
- var cancel:boolean);
- {
- Do a Standard file put dialog to open a new TEXT file as a TURBO PASCAL
- text file for output.
- Use the toolbox to get the file name and set the default vol/folder.
- The use Rewrite to do the actual open for Turbo.
- This may work only on the 128k ROMS.
- }
- var
- topleft,center :point;
- theErr :OSErr;
- Reply :SFreply;
- filename :string[63];
- ScrHres,ScrVres : integer;
- vol :integer;
- vserr :OSerr;
- finderinfo :finfo;
-
- begin
- with center do
- begin
- with screenbits.bounds do
- begin
- v:=(top+bottom) div 2;
- h:=(left+right) div 2;
- end;
- end;
-
- topleft.h:=center.h-170; {position of topleft}
- topleft.v:=center.v-120;
-
- Cancel:=false;
- SFPutFile(topleft,prompt,orgname,nil,Reply);
- if Reply.good then
- begin
-
- vol:=reply.vrefnum;
- filename:=reply.fname;
-
- vserr:=SetVol(nil,vol); {change default volume}
-
- {SFGetFile does not do an actual open : FSOpen or PBOpen
- are called to do this in the examples I have seen}
-
- rewrite_and_save_info(filevar,filename); {do turbo open}
-
- {set file creator}
- if getFinfo(filename,vol,finderinfo)=NoErr then
- begin
- finderinfo.fdCreator:=creator;
-
- if setFinfo(filename,vol,finderinfo) <> NoErr then
- begin
- sysbeep(10);
- cancel:=true;
- end
- ;
- end
- else
- begin
- sysbeep(10);
- cancel:=true;
- end
-
- end
- else
- begin
- {may be a cancel or other error}
- Cancel:=true;
-
- end;
-
- end; {of proc MySFopen }
- {$S start2 }
- procedure open_output;
- {Open Output file}
- var cancel:boolean;
- name:str255;
- begin
- set_default_blessed;
- if inputopen then
- begin
- name:='NewSystemCheckSum';
- end
- else
- begin
- {to make it easier to start from scratch}
- name:='OldSystemCheckSum';
- end;
-
- {default folder to the system folder}
- mySFnew(outfile,'Output File?',name,'EDIT',cancel);
- if not cancel then
- begin
- outputopen:=true;
- end
- else
- begin
- outputopen:=false;
- end;
- set_default_blessed;
- end;
- procedure open_input;
- {look for input file 'OldSystemCheckSum' in startup and blessed folder
- if not found ask for it}
- label 99;
- var savewd:integer;
- err,ierr,ignore:oserr;
- name:str255;
- finder:Finfo;
- begin
- name:='OldSystemCheckSum';
- inputnotdefault:=true;
-
- if inputopen then exit;
- ignore:=getvol(nil,savewd);
- {startup folder}
- ignore:=setvol(nil,startupwd);
- err:=GetFInfo(name,0,finder);
- if err=noerr then
- begin
- if finder.fdtype='TEXT' THEN
- begin
- reset_and_save_info(infile,name);
- ierr:=IOResult;{turbo pascal error codes}
- if Ierr<>0 then halt_on_error(ierr,'Open Input-default folder');
- inputopen:=true;
- currentsection:=1;
- on_section_boundry:=true;
- inputnotdefault:=false;
- goto 99;
- end;
- end;
- {system folder}
- set_default_blessed;
- err:=GetFInfo(name,0,finder);
- if err=noerr then
- begin
- if finder.fdtype='TEXT' THEN
- begin
- reset_and_save_info(infile,name);
- ierr:=IOResult;{turbo pascal error codes}
- if Ierr<>0 then halt_on_error(ierr,'Open Input-system folder');
- inputopen:=true;
- currentsection:=1;
- on_section_boundry:=true;
- inputnotdefault:=false;
- goto 99;
- end;
- end;
- poststatus(concat('I can''t find: ',name),errorline);
- if Ask('Do you want to specify another input file?',nodefaultbut) then
- begin
- poststatus('',errorline);
- mySFold(infile,'Old checksums file',name,cancel);
- if cancel then goto 99;
- inputopen:=true;
- currentsection:=1;
- on_section_boundry:=true;
- goto 99;
- end
- else
- begin
- poststatus('',errorline);
- end;
- 99:
- ignore:=setvol(nil,savewd);
- end;{open_input}
-
- {$S event}
- procedure close_and_flush{(var filevar:text;var openflag:boolean)};
- {close file and flush default volume}
- var ignore:oserr;
- begin
- if openflag then close(filevar);
- openflag:=false;
- ignore:=FlushVol(nil,0);{flush default volume}
- end;{procedure close_and_flush}
-
- procedure close_all_and_halt{(beep:boolean)};
- {Close input and output files if open and halt}
- var ignore:oserr;
- begin
- if beep then
- begin sysbeep(1);sysbeep(1); end;
- if inputopen then close_and_flush(infile,inputopen);
- if outputopen then close_and_flush(outfile,outputopen);
- closepath(myRpath);
- ignore:=setvol(nil,startupwd);
- halt;
- end;
- {$S boot}
- function absolute_read(buffer:handle;count:longint;offset:longint):oserr;
- {read data from an absolute position-used to check the boot blocks}
- var pblock:paramBlockRec;
- mypb:hparamblockrec;
- vname:str255;
- err:oserr;
- drivenum:integer;
- driver:integer;
- begin
- {get drive number of default volume}
- with mypb do
- begin
- iocompletion:=nil;
- vname:='';
- ionameptr:=@vname;
- iovrefnum:=0;
- ioVolIndex:=0;
- end;
- scsi_wait;
- err:=pbhgetvinfo(@mypb,false);
- with mypb do
- begin
- drivenum:=iovdrvinfo;
- driver:=iovdrefnum;
- end;
-
- absolute_read:=err;
-
- if err<>noerr then
- begin
- exit;
- end;
-
- {work on reading the data}
- hlock(buffer);
- with pblock do
- begin
- iocompletion:=nil;
- iovrefnum:=drivenum;
- iorefnum:=driver;
- iobuffer:=buffer^;
- ioreqcount:=count;
- ioPosMode:=FsFromStart;{relative from first sector}
- ioPosoffset:=offset;
- end;
- scsi_wait;
- err:=PBRead(@pblock,false);
- hunlock(buffer);
- absolute_read:=err;
- end;{proc absolute_read}
-
- {$S boot}
- procedure boot_ignore(buffer:handle);
- {zero out fields where boot block changes are safe/common}
- type boots=array[0..511] of integer;
- bootptr=^boots;
- var i:integer;
- p:bootptr;
- begin
- hlock(buffer);
- p:=bootptr(buffer^);
- {info that changes on set startup}
- for i:=45 to 52 do p^[i]:=0;
- hunlock(buffer);
- end;
-
- function checksum_boot_blocks{:integer};
- var count,offset:longint;
- buffer:handle;
- err:oserr;
- result:integer;
- begin
- result:=0;
- count:=1024;{two logical blocks}
- offset:=0;
- buffer:=newhandle(count);
- if buffer<>nil then
- begin
- err:=absolute_read(buffer,count,offset);
- if err=noerr then
- begin
- boot_ignore(buffer);{zero out safe stuff}
- result:=checksumHdata(buffer);
- end;
- disposHandle(buffer);
- end;
-
- checksum_boot_blocks:=result;
-
- end;{proc}
-
- {$S }
- procedure tefixup(statustext:tehandle);
- {shrink the size of the TERec if a bug in TE has made the
- linestarts array too big}
- var base,needed,actual:longint;
- begin
- actual:=gethandlesize(handle(statustext));
- {figure nominal size}
- base:=sizeof(statustext^^)-sizeof(statustext^^.linestarts);
- needed:=(statustext^^.nlines+1)*2+base;
- if actual>needed+64 then
- begin
- {reset to needed size plus a bit extra}
- Hunlock(handle(statustext));
- sethandlesize(handle(statustext),needed+8);
- end
- end;{procedure tefixup}
-
- procedure replaceline{(ss:str255;linenum:integer)};
- {On screen messages}
- {replace a line in the statustext TERec}
- var start,finish:longint;
- cr:string[1];
- begin
- cr:=chr(13);
- ss:=concat(ss,cr);
- if linenum<statustext^^.nlines then
- begin
- start:=statustext^^.linestarts[linenum-1];
- finish:=statustext^^.linestarts[linenum];
- end
- else
- begin
- start:=0;
- finish:=0;
- end;
- TESetSelect(start,finish,statustext);
- TeDeLete(statustext);
- TEInsert(Pointer(ord4(@ss)+1),length(ss),statustext);
- tefixup(statustext);
- TESetSelect(0,0,statustext);
- end;
-
- procedure clear_to_end{(linenum:integer)};
- {On screen messages}
- {clear lines in the statustext TERec from linenum to end}
- var start,finish:longint;
- nn:integer;
- cr:string[1];
- ss:str255;
- begin
- cr:=chr(13);
- if linenum<statustext^^.nlines then
- begin
- start:=statustext^^.linestarts[linenum-1];
- finish:=statustext^^.telength;
- end
- else
- begin
- start:=0;
- finish:=0;
- end;
- {create empty lines as filler}
- ss:=cr;
- for nn:=linenum to mstatus do ss:=concat(cr,ss);
-
- TESetSelect(start,finish,statustext);
- TeDeLete(statustext);
- TEInsert(Pointer(ord4(@ss)+1),length(ss),statustext);
- TESetSelect(0,0,statustext);
- {replace title and byline}
- if linenum<=byline then
- begin
- Replaceline(concat('Startup System Check ',TitleVersion),titleline);
- ReplaceLine('by Albert Lunde, Northwestern University Copyright ⌐ 1988'
- ,byline);
- end;
-
- end;
- {$S }
- procedure postmem{(linenum:integer)};
- {free memory in heap and approximate stack size}
- const
- currstackbase=$908;
- type lp=^longint;
-
- var ff,kk:str255;
- p:lp;
- begin
- if not showdebuginfo then exit;
- numtostring(freemem,ff);
- kk:=concat('Free memory: ',ff);
- p:=lp(pointer(currstackbase));{compare global var for base of stack}
- numtostring((p^-ord4(@kk)),ff);
- kk:=concat(kk,' Stack Size:');
- kk:=concat(kk,ff);
- numtostring(currentsection,ff);
- kk:=concat(kk,' Section:');
- kk:=concat(kk,ff);
- poststatus(kk,linenum);
- end;
- {$S }
- procedure poststatus{(ss:str255;linenum:integer)};
- {On screen messages}
- {post a message on the screen and go into the event
- loop long enought to update the screen or process halt button}
- var ff,kk:str255;
- begin
- (*
- numtostring(freemem,ff);
- kk:=ff;
- numtostring(gethandlesize(handle(statustext)),ff);
- kk:=concat(kk,concat(' ',ff));
- numtostring(sizeof(resourceinfoarray),ff);
- kk:=concat(kk,concat(' ',ff));
- *)
- replaceline(ss,linenum);
- {replaceline(kk,mstatus);}
- DoEvent(false);
- end;
- {$S event}
- function Ask{(question:str255;default:integer):boolean};
-
- begin
- setdefaultbutton(default);
- hidecontrol(buttons[continuebut]);
- hidecontrol(buttons[shutdownbut]);
- hidecontrol(buttons[haltbut]);
- showcontrol(buttons[yesbut]);
- showcontrol(buttons[nobut]);
- askanswered:=false;
- poststatus(question,askline);
- sysbeep(1);
- repeat
- doevent(false);
- until askanswered;
- setdefaultbutton(nodefaultbut);
- clear_to_end(askline);
- showcontrol(buttons[continuebut]);
- showcontrol(buttons[shutdownbut]);
- showcontrol(buttons[haltbut]);
- hidecontrol(buttons[yesbut]);
- hidecontrol(buttons[nobut]);
- ask:=askanswer;
- doevent(true);
- end;
-
- procedure halt_on_error{(err:oserr;sss:str255)};
- {check for OSerr code}
- var ss:str255;
- begin
- if err=noerr then exit;
- Numtostring(err,ss);
- ss:=concat(concat('Unexpected Error:',ss),sss);
- poststatus(ss,errorline);
- repeat until button;
- close_all_and_halt(true);
- end;
- {$S files}
- procedure folder_info_two{(dirid:longint;
- volume:integer;
- var name:str255;
- var path:str255;
- findpath:boolean)};
- {get info (name and/or path) on a directory specified by
- a 32 bit id directory ID and a volume reference number}
- {revised to used fewer file system calls and to work
- correctly given on any volume}
- label 99;
- var vname:str255;
- mywdpb:wdpbrec;
- mycinfopb:cinfopbrec;
- err,ignore:oserr;
- oldwd:integer;
- tempdirid:longint;
- tempname:str255;
- count:integer;
- begin
- {save default wd}
- ignore:=getvol(nil,oldwd);
-
- {Build path}
- {This is based roughly on C code from
- "Programming with Macintosh Programmer's Workshop" by Joel West
- Page 467-469}
-
- path:='';
- tempdirid:=dirid;{dir ID for folders along the path}
- tempname:='';
- count:=0;{infinite loop protection}
- repeat
- count:=count+1;
- with mycinfopb do
- begin
- {setup for pbgetcatinfo}
- iocompletion:=nil;
- ionameptr:=@tempname;
- iovrefnum:=volume;
- iodirid:=tempdirid;
- iofdirindex:=-1;{info about directories only see tn#69}
- end;
- scsi_wait;
- err:=pbgetcatinfo(@mycinfopb,false);
- if err=noerr then
- with mycinfopb do
- begin
- if count=1 then
- begin
- name:=tempname;
- if not findpath then goto 99;
- end;
- path:=concat(tempname,':',path);
- tempdirid:=iodrparid;
- end;
-
- until((count>100) or (tempdirid=fsrtparid) );
- 99:
- {restore default wd}
- ignore:=setvol(nil,oldwd);
- end;{folder_info_two}
-
- {$S files }
- procedure set_default_blessed;
- {set default volume and folder to the blessed(active system) folder}
- var
- err: OSErr;
- myWDPB: WDPBRec;
- dummy:str255;
- begin
- {set default folder to dirID}
- with mywdpb do
- begin
- {set up for PBHSetVol call}
- ioCompletion:= NIL;
- dummy:='';
- ioNamePtr:= @dummy; {initialize may not be needed}
- ionameptr:=nil;
- ioWDDirID:=blessed;
- ioVRefNum:=blessedbootvolwd;
- end;
- scsi_wait;
- err:=PBHSetVol(@mywdpb,false);
-
- halt_on_error(err,'PBsetvol-set_default_blessed');
-
-
- end;{procedure}
-
- procedure set_default_by_id{(DirID:longint)};
- {set default folder by 32 bit DirId}
- var
- err: OSErr;
- myWDPB: WDPBRec;
- dummy:str255;
- begin
- {set default folder to dirID}
- with mywdpb do
- begin
- {set up for PBHSetVol call}
- ioCompletion:= NIL;
- dummy:='';
- ioNamePtr:= @dummy; {initialize may not be needed}
- ionameptr:=nil;
- ioWDDirID:=dirID;
- ioVRefNum:=0;
- end;
- scsi_wait;
- err:=PBHSetVol(@mywdpb,false);
-
- halt_on_error(err,'PBsetvol-set_default_by_id');
-
-
- end;{procedure}
-
- PROCEDURE EnumerateCatalog(dirIDToSearch: longint);
-
- {process all files in a folder but ignore subfolders}
-
- VAR
-
- myCPB: CInfoPBRec;
-
- err: OSErr;
-
- myWDPB: WDPBRec;
-
- TotalFiles,TotalDirectories: LONGINT;
- fname,dummy:str255;
-
- index: integer;
-
- ignore:oserr;
- oldwd:integer;
-
- Begin {EnumerateCatalog}
- ignore:=getvol(nil,oldwd);{save old wd}
-
-
- TotalFiles:= 0;
-
- TotalDirectories:= 0;
-
- {add initialize of pb 5/14/88
- may not be needed but seems to fix a bug}
- with mywdpb do
- begin
- dummy:='';
- ioCompletion:= NIL;
- ionameptr:=@dummy;
- iovrefnum:=0;
- iowdindex:=0;
- end;
- err:= PBHGetVol(@myWDPB,FALSE); {get the default volume}
-
-
- with MyCPB do Begin
-
- iocompletion:= Nil;
-
- ioNamePtr:= @FName;
-
- ioVRefNum:= myWDPB.ioVRefNum; {for now, default vol, set this to what you want}
-
- End; {with}
-
- {set default folder to diridtosearch to allow
- use of high level calls in called procedures}
-
- set_default_by_id(diridtosearch);
-
- index:= 1;
-
- repeat{loop over folder with index}
- doEvent(false);
- FName:= ''; {nil out name}
-
- myCPB.ioFDirIndex:= index;
-
- myCPB.ioDrDirID:= dirIDToSearch; {we need to do this every time through}
-
-
- scsi_wait;
- err:= PBGetCatInfo(@myCPB,FALSE);
-
-
-
- If err = noErr then
-
- if BitTst(@myCPB.ioFlAttrib,3) then
- Begin {we have a dir}
- TotalDirectories:=TotalDirectories+1;
- {do nothing for directories}
- err:= 0; {clear error return on way back}
- End {if BitTst}
- Else
- Begin{we have a file}
-
- TotalFiles:= TotalFiles + 1;
-
- Poststatus(concat('Checking: ',fname),fileline);
- (* Do_for_file(dirIDToSearch,MyCPB.ioFrefNum,Fname,Totalfiles,MYCPB)*)
- sysfiles[index]:=fname;
- check_a_file(index);
- End; {else}
- PostStatus('',fileline);
- index:= index + 1;
-
- until err <> noErr;
-
- ignore:=setvol(nil,oldwd); {restore WD}
-
- End; {EnumerateCatalog}
- {$S start2}
- procedure get_blessed;
- {get the blessed folder 32 bit dir id,
- given either volume ref or a working directory ref on that volume}
- {this version stores the blessed folder id and the working dir ref
- of the boot volume in global variables}
- CONST
-
- FSFCBLen = $3F6; {location of low-memory global FSFCBLen}
-
-
- VAR
-
- myHPB: HParamBlockRec; {for the PBHGetVInfo call}
-
- myWDPB: WDPBRec; {for the PBHSetVol call}
-
- err,ignore: OSErr;
-
- oldVol: integer;
-
- vName,fName: str255;
-
- HFS: ^integer; {to check to see if we are running HFS}
- bootwdptr: ^integer; {to find the boot drive}
- oldwd:integer;
-
- begin
- {save default wd}
- ignore:=getvol(nil,oldwd);
-
- HFS:= POINTER(FSFCBLen); {point our variable at the low-memory global}
-
- if HFS^ > 0 then Begin {we're running HFS}
-
- blessedbootvolwd:=GetRealBootDrive;
- {"working directory reference number" for system startup volume}
-
- {change to system startup volume - this is so we always find the
- blessed folder on the startup device, even when running from a floppy}
-
- ignore:=setvol(nil ,blessedbootvolwd);
-
- vName:= ''; {initialize this}
-
- with myHPB do Begin
-
- ioCompletion:= NIL;
-
- ioNamePtr:= @vName; {initialize}
-
- ioVRefNum:= 0; {0 is get for default volume}
-
- ioVolIndex:= 0; {we're not making indexed calls}
-
-
- End; {with}
-
-
-
- err:= PBHGetVInfo(@myHPB,FALSE);
-
- if err <> 0 then poststatus('PBHGetVInfo Error',errorline)
-
- Else
-
-
- End {if HFS^ > 0}
- ;
- {At this point, the dirID of the blessed folder on the volume}
- blessed:=myHPB.ioVFndrInfo[1];
- {writeln(vname);}
- {restore default wd}
- ignore:=setvol(nil,oldwd);
-
-
- end;{get blessed}
-
- {$S core}
- procedure filltype{(var tt:restype;ss:str255)};
- {blank fill and convert string to resource type}
- var work:string[8];
- begin
- work:=concat(ss,' ');
- tt[1]:=work[1];
- tt[2]:=work[2];
- tt[3]:=work[3];
- tt[4]:=work[4];
- end;{fill type}
-
- {$S startup}
- procedure parse_options(line:str255);
- {read options line:
- 1st 3 values are resource counts retained
- for backward compatibility}
- var tokens:tokenstype;
- ntokens:integer;
- work:longint;
- begin
- tabscan(line,tokens,ntokens);
- if ntokens<4 then exit;
- stringtonum(tokens[4],work);
- checkfloppies:=(work<>0);
- if ntokens<5 then exit;
- stringtonum(tokens[5],work);
- checknonbootdrives:=(work<>0);
- if ntokens<6 then exit;
- stringtonum(tokens[6],work);
- appleshareaccessmask:=(work and $FF);
- end;
-
- procedure read_input_header;
- {read beginning of input file before resource types list}
- var ignore,oline:str255;
- begin
- if not inputopen then exit;
- position_to_section(sect_num_header);
- {Mac SE:System Folder: path,date,time,version
- 12742 bootblockchecksum
- 789087 checksumchecksum
- 322 104 322 resource counts
- ***** end of header}
- if eof(infile) then exit;
- read_input(ignore);{path}
- if eof(infile) then exit;
- oldbootblockchecksum:=0;
- read_input_integer(oldbootblockchecksum);{grand resource checksum}
-
- if eof(infile) then exit;
- oldchecksumchecksum:=0;
- read_input_long(oldchecksumchecksum); {boot block checksum}
-
- if eof(infile) then exit;
- read_input(oline);
- parse_options(oline);
-
- {skip down to *****}
- repeat
- if eof(infile) then exit;
- read_input(ignore);
- until(test_end_flag(ignore));
-
- read_safekeys;
- read_morechecks;
- end;{proc}
-
- procedure readoklist;
- {read a list of resource types/stop at eof or "*****"}
- {each line contains TYPE,safety level,and optional number of occurances}
- label 99;
- var line:str255;
- ntokens:integer;
- tokens:tokenstype;
- atype:restype;
- howsafe:safetype;
- work:longint;
- begin
- if not inputopen then exit;
- PostStatus('Reading safe types list',fileline);
- while(not eof(infile)) do
- begin
- line:='';
- read_input(line);
- {sysbeep(1);
- poststatus(line,fileline);}
- if test_end_flag(line) then goto 99;
- tabscan(line,tokens,ntokens);
- { poststatus(concat(concat('$',tokens[1]),'$'),errorline);}
- if ntokens>=2 then
- begin
- filltype(atype,tokens[1]);
- work:=ord(unknown);
- stringtonum(tokens[2],work);
- if (work>3) or (work<0) then
- begin
- poststatus(concat('Bad input:',line),errorline);
- wait_for_buttons(' ',continuebut);
- howsafe:=unknown;
- end
- else
- howsafe:=safetype(work);
- add_type(atype,howsafe);
- end
- else if ntokens=1 then
- begin
- filltype(atype,tokens[1]);
- add_type(atype,safe);
- end;
-
- end;{while}
- 99:
- PostStatus('',fileline);
- end;{readoklist}
-
- {$S sortres}
- procedure sortresources(var X:resourceinfoarrayptr;N:integer);
- {sort array of resources and their checksums}
- { HEAP SORT
- C
- C BASED ON PROGRAMMING PEARLS BY JON BENTLEY P 182
- C X IS THE ARRAY CONTAINING NX ELEMENTS TO BE SORTED
- C CALL SWAPX(I,J) SWAPS X(I) WITH X(J)
- C GEX(X,I,J) IS TRUE IFF X(I) >= X(J)
- C GTX(X,I,J) IS TRUE IFF X(I) > X(J)
- C}
-
-
- var i: integer;
-
-
- procedure SWAPX(I:integer;J:integer);
- var T:resourceinforec;
-
- begin
- T:=X^[I];
- X^[I]:=X^[J];
- X^[J]:=T;
- END; {of procedure swapx}
-
- FUNCTION GTX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort type,id,size }
- gtx:=false;
-
- filecomp:=filenamecompare(
- sysfiles[(X^[I].filenameindex and fnamemask)],
- sysfiles[(X^[J].filenameindex and fnamemask)]);
-
- if filecomp>0
- {(sysfiles[(X^[I].filenameindex and fnamemask)]>
- sysfiles[(X^[J].filenameindex and fnamemask)])} then
- begin
- gtx:=true
- end
- else if filecomp=0
- {((X^[I].filenameindex and fnamemask)=
- (X^[J].filenameindex and fnamemask))} then
- if (X^[I].thetype>X^[J].thetype) then
- begin
- gtx:=true
- end
- else if (X^[I].thetype=X^[J].thetype) then
- begin
- if (X^[I].theid>X^[J].theid)then
- begin
- gtx:=true;
- end
- else if (X^[I].theid=X^[J].theid)then
- begin
- if (X^[I].thesize>X^[J].thesize)then
- begin
- gtx:=true;
- end
- end
- ;
- end
- ;
-
- end;
-
- FUNCTION GEX(I:integer;J:integer):boolean;
- var filecomp:integer;
- begin
- {sort type,id,size }
- gex:=false;
-
- filecomp:=filenamecompare(
- sysfiles[(X^[I].filenameindex and fnamemask)],
- sysfiles[(X^[J].filenameindex and fnamemask)]);
-
- if filecomp>0
- {(sysfiles[(X^[I].filenameindex and fnamemask)]>
- sysfiles[(X^[J].filenameindex and fnamemask)])} then
- begin
- gex:=true
- end
- else if filecomp=0
- {((X^[I].filenameindex and fnamemask)=
- (X^[J].filenameindex and fnamemask))} then
- if (X^[I].thetype>X^[J].thetype) then
- begin
- gex:=true
- end
- else if (X^[I].thetype=X^[J].thetype) then
- begin
- if (X^[I].theid>X^[J].theid)then
- begin
- gex:=true;
- end
- else if (X^[I].theid=X^[J].theid)then
- begin
- if (X^[I].thesize>=X^[J].thesize)then
- begin
- gex:=true;
- end
- end
- ;
- end
- ;
-
- END;
-
- procedure siftdown(L:integer;U:integer);
- label 300,999{return};
- var
- i,child:integer;
-
- begin
-
- {
- C
- C BEFORE MAXHEAP(L+1,U)
- C AFTER MAXHEAP(L,U)
- }
- I:=L;
-
- {LOOP}
- 300:
- {
- C INVARIANT: MAXHEAP(L,U) EXCEPT PERHAPS
- C BETWEEN I AND ITS (0,1 OR 2) CHILDREN
- C
- }
- CHILD:=2*I;
-
- IF CHILD > U then goto 999;
- {
- C
- C IF C+1 <= U AND X^(C+1) > X^(C) THEN C=C+1
- C
- }
- IF(CHILD+1 <= U) THEN
- IF(GTX(CHILD+1,CHILD))THEN
- CHILD:=CHILD+1;
-
- {
- C
- C CHILD IS THE GREATEST CHILD OF I
- C
- C IF X^(I) >= X^(CHILD) THEN RETURN
- C
- }
- IF(GEX(I,CHILD)) then goto 999;
-
- {
- C
- C X^(I) IS LESS THAN ITS GREATEST CHILD SO SWAP IT DOWNWARD
- C AND REPEAT LOOP
- C
- }
- SWAPX(CHILD,I);
- I:=CHILD;
- GOTO 300;
- {END LOOP}
- 999:{return}
- END; {of proc siftdown}
-
-
-
- begin {main body of sortresources}
-
- for I:=N div 2 downto 1 do
- begin
- { echo(i);}
- SIFTDOWN(I,N);
- end;
-
- {echo(0);}
-
- for I:=N downto 2 do
- begin
- { echo(i);}
- SWAPX(1,I);
- {echo(i);}
- SIFTDOWN(1,I-1);
- { echo(i);}
- end;
-
-
-
- END; {sortresources}
-
- procedure sorttypes{(var X:resourcetypeinfoarray;N:integer)};
- {sort resource types array}
- { HEAP SORT
- C
- C BASED ON PROGRAMMING PEARLS BY JON BENTLEY P 182
- C X IS THE ARRAY CONTAINING NX ELEMENTS TO BE SORTED
- C CALL SWAPX(I,J) SWAPS X(I) WITH X(J)
- C GEX(X,I,J) IS TRUE IFF X(I) >= X(J)
- C GTX(X,I,J) IS TRUE IFF X(I) > X(J)
- C}
-
-
- var i: integer;
-
-
- procedure SWAPX(I:integer;J:integer);
- var T:resourcetypeinforec;
-
- begin
- T:=X[I];
- X[I]:=X[J];
- X[J]:=T;
- END; {of procedure swapx}
-
- FUNCTION GTX(I:integer;J:integer):boolean;
-
- begin
- {sort type,id,size }
- gtx:=false;
- if (X[I].thetype>X[J].thetype) then
- begin
- gtx:=true;
- end
- ;
-
- end;
-
- FUNCTION GEX(I:integer;J:integer):boolean;
-
- begin
- {sort type,id,size }
- gex:=false;
- if (X[I].thetype>=X[J].thetype) then
- begin
- gex:=true
- end
-
- END;
-
- procedure siftdown(L:integer;U:integer);
- label 300,999{return};
- var
- i,child:integer;
-
- begin
-
- {
- C
- C BEFORE MAXHEAP(L+1,U)
- C AFTER MAXHEAP(L,U)
- }
- I:=L;
-
- {LOOP}
- 300:
- {
- C INVARIANT: MAXHEAP(L,U) EXCEPT PERHAPS
- C BETWEEN I AND ITS (0,1 OR 2) CHILDREN
- C
- }
- CHILD:=2*I;
-
- IF CHILD > U then goto 999;
- {
- C
- C IF C+1 <= U AND X(C+1) > X(C) THEN C=C+1
- C
- }
- IF(CHILD+1 <= U) THEN
- IF(GTX(CHILD+1,CHILD))THEN
- CHILD:=CHILD+1;
-
- {
- C
- C CHILD IS THE GREATEST CHILD OF I
- C
- C IF X(I) >= X(CHILD) THEN RETURN
- C
- }
- IF(GEX(I,CHILD)) then goto 999;
-
- {
- C
- C X(I) IS LESS THAN ITS GREATEST CHILD SO SWAP IT DOWNWARD
- C AND REPEAT LOOP
- C
- }
- SWAPX(CHILD,I);
- I:=CHILD;
- GOTO 300;
- {END LOOP}
- 999:{return}
- END; {of proc siftdown}
-
-
-
- begin {main body of sorttypes}
-
- for I:=N div 2 downto 1 do
- begin
- { echo(i);}
- SIFTDOWN(I,N);
- end;
-
- {echo(0);}
-
- for I:=N downto 2 do
- begin
- { echo(i);}
- SWAPX(1,I);
- {echo(i);}
- SIFTDOWN(1,I-1);
- { echo(i);}
- end;
-
-
-
- END; {sorttypes}
- {$S wascore}
- function min(i,j:longint):longint;
- begin
- if i<j then min:=i else min:=j;
- end;
- function rotatelong(i:longint):longint;
- {left circular shift by one bit}
- const leftbitnum=0;
- rightbitnum=31;
- var j:longint;
- begin
- j:=BitShift(i,1);{left logical shift one}
- if bittst(@i,leftbitnum) then
- begin
- {high bit set in i}
- bitset(@j,rightbitnum);
- end
- ;
- rotatelong:=j;
- end;
-
- function checksumHdataOLD{(h:handle):integer};
- {OLD version using the toolbox bit manipulation stuff
- and an intermediate buffer array (abount 10 times slower)}
- {non-standard checksum for virus detection
- depends on all bits and can detect transpositions}
- {modified to increase non-linearity 3/29/88}
- const mask=$00FFFFFF;
- blocklongsize=64;
- blockbytesize=256;{4x above}
- var size:longint;
- p:ptr;
- p0:longint;
- sum:integer;
- lsum:longint;
- offset:longint;
- longxxxx:longint;
- j,kk:longint;
- work:array[1..blocklongsize] of longint;
- begin
- sum:=0;
- lsum:=0;
- longxxxx:=0;
- if h<>nil then
- if (h^<>nil) then
- begin
- size:=GetHandleSize(h);
- offset:=0;
- while offset<(size-1) do
- begin
-
- for j:=1 to blocklongsize do work[j]:=0;
- p0:=bitand(mask,ord4(h^));
- p:=pointer(p0+offset);
- kk:=min(longint(blockbytesize),size-offset);
- blockmove(p,@work,kk);{copy a block}
- for j:=1 to (kk+3) div 4 do {do for longints}
- begin
- lsum:=bitxor(lsum,work[j]);
- longxxxx:=longxxxx+checksumsaltinc;
- {lsum:=bitxor(lsum,longxxxx);}{3/29/88}
- lsum:=lsum+longxxxx;
- lsum:=rotatelong(lsum);
- end;
- offset:=offset+blockbytesize;
- end;
- sum:=loword(bitxor(longint(loword(lsum)),longint(hiword(lsum)) ));
- end;
-
- checksumhdataOLD:=sum;
-
- end;
- {$S core}
- function checksumHdata{(h:handle):integer};
- {faster version using more stuff specific to turbo pascal 3/28/88}
- {non-standard checksum for virus detection
- depends on all bits and can detect transpositions}
- {modified to use Turbo's inline code bit masking operators
- rather than the toolbox bitxor etc}
- {modified to operate directly on the data in the handle
- rather than copying blocks into a buffer}
- {modified to increase non-linearity 3/29/88}
- const mask=$00FFFFFF;
- leftbitmask= $80000000;
- rightbitmask=$00000001;
- blocklongsize=8000;
- blockbytesize=32000;{4x above}
- type workblocktype=array[1..blocklongsize] of longint;
- workptr=^workblocktype;
- var size,realsize,sizeextra:longint;
- p:ptr;
- wrk:workptr;
- p0:longint;
- sum:integer;
- lsum:longint;
- offset:longint;
- longxxxx:longint;
- j,kk:longint;
- shwork:longint;
- last:longint;
- begin
- sum:=0;
- lsum:=0;
- longxxxx:=0;
- if h<>nil then
- if (h^<>nil) then
- begin
- hlock(h);
- size:=GetHandleSize(h);
- realsize:=size;
- sizeextra:=size mod 4;
- size:=size-sizeextra;
- offset:=0;
- p0:=bitand(mask,ord4(h^));
- while offset<(size-1) do
- begin
- p:=pointer(p0+offset);
- kk:=min(longint(blockbytesize),size-offset);
- wrk:=workptr(p);
- for j:=1 to (kk+3) div 4 do {do for longints}
- begin
- lsum:=(lsum xor wrk^[j]);
- longxxxx:=longxxxx+checksumsaltinc;
- {lsum:=(lsum xor longxxxx);}{3/29/88}
- lsum:=lsum+longxxxx;
-
- {simulate a left circular shift of one on lsum}
- shwork:=lsum shl 1;{left logical shift one}
- if (lsum and leftbitmask)<>0 then
- begin
- {high bit set in lsum}
- shwork:=shwork or rightbitmask
- end;
- lsum:=shwork;
- {end shift}
- end;
- offset:=offset+blockbytesize;
- end;
- if sizeextra<>0 then
- begin
- {special case for trailing bytes in last longword}
- wrk:=workptr(pointer(p0+size));
- last:=wrk^[1];
- case sizeextra of
- 1:last:=last and $FF000000;
- 2:last:=last and $FFFF0000;
- 3:last:=last and $FFFFFF00;
- end;{case}
- begin{copy of code above except 1st line}
- lsum:=(lsum xor last);
- longxxxx:=longxxxx+checksumsaltinc;
- {lsum:=(lsum xor longxxxx);}{3/29/88}
- lsum:=lsum+longxxxx;
-
- {simulate a left circular shift of one on lsum}
- shwork:=lsum shl 1;{left logical shift one}
- if (lsum and leftbitmask)<>0 then
- begin
- {high bit set in lsum}
- shwork:=shwork or rightbitmask
- end;
- lsum:=shwork;
- {end shift}
- end;
-
- end;{sizeextra non-zero}
- sum:=loword(bitxor(longint(loword(lsum)),longint(hiword(lsum)) ));
- hunlock(h);
- end;
-
- checksumhdata:=sum;
- end;{function}
-
- {$S core}
- procedure check_all_types(filename:str255;
- fnindex:integer;{index of file name - system folder checks only}
- apindex:integer;{subscript of application - application checks only}
- SYSTEMFOLDER:boolean);{true for system check, false for application check}
- {This is the routine that checks all types in a given file}
- {called by check_a_file}
- const
- applsalt=$1234;{to make application checksum over resources non-linear}
- var
- j:integer;
- tt:restype;
- ok:boolean;
- err:oserr;
- index:integer;
- itt:integer;
- CHECKIT:BOOLEAN;
- sl:safetype;
- rhand:handle;
- rid:integer;
- rsize:longint;
- rattr:integer;
- rname:str255;
- aevent:EventRecord;
- volref:integer;
- begin
- {dbashow;}
- {Open resource fork as a file and load the
- header info into my own data structures}
-
- if systemfolder then
- begin
- sl:=filenamesafetylevel(filename);
- end
- else
- begin
- sl:=unknown;
- end;
- volref:=0;{look in default directory}
- err:=openpath(myRpath,filename,volref);
-
- if err=noerr then
- with myRpath do
- begin
- { ntypes number of resource types in the current resource file}
- { dbashow;}
- { wait_for_buttons(' start types',continuebut);}
- for j:=1 to ntypes do
- if setmytype(myRpath,j,tt) then
- begin
- {nrefs is count of this type}
- {poststatus(concat(concat('$',tt),'$'),resline);}
- if showdebuginfo then poststatus(tt,resline);
-
- if systemfolder then add_type(tt,unknown);{the detailed list of types
- is for the system folder only
- except for "dangerous" types}
-
- {decide what types should be checked}
- itt:=find_type(tt);
- CHECKIT:=(tt='INIT') or (tt='CODE');
- if itt<>0 then
- with rtypes[itt] do
- begin
- checkit:=safety>sl;{check resources above
- safe or unknown depending on file,location}
- if (not systemfolder) and (safety=dangerous) then
- begin
- {record dangerous types in applications}
- ainfo^[apindex].flags:=
- ainfo^[apindex].flags or appldangermask
- end;
- if (systemfolder) or (safety=dangerous) then
- begin
- occurs:=occurs+nrefs;
- if checkit then
- notsafecount:=notsafecount+nrefs;
- end;
- end;
-
- if checkit then
- begin
- for index:=1 to nrefs do
- begin
- {copy resource data and get name and size}
- if CopyResData(myRpath,index,
- rid,rsize,rattr,rname) then
- if systemfolder then
- begin
- {system folder check}
- if rcount<maxinfo then
- begin
- rcount:=rcount+1;
- with rinfo^[rcount] do
- begin
- thetype:=tt;
- theid:=rid;
- filenameindex:=fnindex;
- thesize:=rsize;
- thename:=rname;
- checksum:=0;{in case all else fails}
- {dbashow;}
- {compute checksums}
- checksum:=checksumHdata(resdata);
- checksumchecksum:=checksumchecksum+checksum;
- end;{with}
- end;{rcount<maxinfo/rhand<>nil}
- end
- else
- begin
- {application check}
- with ainfo^[apindex] do
- begin
- if unsafecount<0 then unsafecount:=0;
- unsafecount:=unsafecount+1;
- checksize:=checksize+rsize;
- {compute checksums}
- checksum:=(checksum xor applsalt)+checksumHdata(resdata);
- end;
- end
- {dbashow;}
- end;{for index}
- end;{if checkit}
- {dbashow;}
- end;{for types/set ok}
- end;{if open ok/with mypath}
-
- closepath(myRpath);
- {dbashow;}
- end;{proc check_all_types}
-
-
-
- procedure check_a_file{(index:integer)};
-
- var
- i:integer;
- filename:str255;
- volref:integer;
- begin
- filename:=sysfiles[index];
- postmem(memline);
- check_all_types(filename,index,1,true);
- end;
- {$S appl}
- procedure checksum_all_appl;
- {go back and checksum applications
- from list in memory}
- var i:integer;
- oldvol:integer;
- ignore:oserr;
- percent:longint;
- pct:str255;
- err:oserr;
- vr:integer;
- begin
- if fastapplcheck then exit;{skip in fast mode}
- ignore:=getvol(nil,oldvol);
- set_default_blessed;
- for i:=1 to acount do
- with ainfo^[i] do
- begin
- vr:=newvols[flags and applvolumemask].volrefnum;
- err:=setvol(nil,vr);
- if err=noerr then
- begin
- set_default_by_id(dirid);{set directory}
- percent:=i*100;
- percent:=percent div acount;
- numtostring(percent,pct);
- pct:=concat(pct,'%');
- pct:=concat(concat(filename,' '),pct);
- poststatus(pct,fileline);
- check_all_types(filename,1,i,false);
- end;
- end;
- clear_to_end(fileline);
- ignore:=setvol(nil,oldvol);
- end;{proc}
- procedure checksum_unchecked_appl;
- {if an output file is to be written, then
- go back and checksum applications for which
- a full checksum has not been done or been copied from
- the input file}
- var i:integer;
- oldvol:integer;
- ignore:oserr;
- percent:longint;
- pct:str255;
- err:oserr;
- vr:integer;
- savefastmode,doit:boolean;
- jj,mcount:longint;
- mess:str255;
- begin
- if not outputopen then exit;
- savefastmode:=fastapplcheck;
- ignore:=getvol(nil,oldvol);
- mcount:=0;
- for i:=1 to acount do
- with ainfo^[i] do
- begin
- if unsafecount=notcounted then mcount:=mcount+1;
- end;
- {do check automatically if a small number of applications are affected}
- doit:=mcount<=recheckappllimit;
- if not doit then
- begin
- numtostring(mcount,mess);
- mess:=concat(concat('Do Full checksum on all ',mess),
- ' Applications new/changed/moved or not previously checked?');
- doit:=ask(mess,nobut);
- end;
- if doit and (mcount>0) then
- begin
- set_default_blessed;
- poststatus('Recheck new/changed/renamed',pathline);
- jj:=0;
- for i:=1 to acount do
- with ainfo^[i] do
- if unsafecount=notcounted then
- begin
- fastapplcheck:=false;
- unsafecount:=0;
- jj:=jj+1;
- vr:=newvols[flags and applvolumemask].volrefnum;
- err:=setvol(nil,vr);
- if err=noerr then
- begin
- set_default_by_id(dirid);{set directory}
- percent:=jj*100;
- percent:=percent div mcount;
- numtostring(percent,pct);
- pct:=concat(pct,'%');
- pct:=concat(concat(filename,' '),pct);
- poststatus(pct,fileline);
- check_all_types(filename,1,i,false);
- end;
- end;
- end;
- clear_to_end(pathline);
- ignore:=setvol(nil,oldvol);
- fastapplcheck:=savefastmode;
- end;{proc}
-
-
- procedure recheck_changed{(i:integer;
- oldunsafecount:longint;
- oldchecksize:longint;
- oldchecksum:integer)};
-
- {call this procedure immediately after determining that an application has
- changed size and do a full checksum to reduce false positives}
-
- var
- oldvol:integer;
- ignore:oserr;
- err:oserr;
- vr:integer;
- safechange:boolean;
- savefastmode:boolean;
-
- begin
- if (ainfo^[i].flags and applchangedmask)=0 then exit;
- postmem(memline);
- savefastmode:=fastapplcheck;
- ignore:=getvol(nil,oldvol);
- set_default_blessed;
- poststatus('Full check on file whose size has changed',pathline);
- with ainfo^[i] do
- begin
- if unsafecount=notcounted then
- begin
- fastapplcheck:=false;
- unsafecount:=0;
- vr:=newvols[flags and applvolumemask].volrefnum;
- err:=setvol(nil,vr);
- if err=noerr then
- begin
- set_default_by_id(dirid);{set directory}
- poststatus(filename,fileline);
- check_all_types(filename,1,i,false);
- end;
- end;
- {check for exact match with new checksums}
- safechange:=true;
- if oldchecksize=checksize then
- if oldchecksum=checksum then
- if oldunsafecount=unsafecount then
- begin
- safechange:=true;
- end;
-
- if safechange then
- begin
- flags:=(flags and (not applchangedmask)) or applsafechangedmask;
- end
- else
- begin
- flags:=(flags or applchangedmask);
- end;
-
- end;
-
- clear_to_end(pathline);
- poststatus('Compare application sizes',pathline);
- ignore:=setvol(nil,oldvol);
- fastapplcheck:=savefastmode
- end;{recheck_changed}
- {$S core}
- procedure summary;
- {write summary to output file in same format as input file}
- var i:integer;
- tab:string[1];
- now:longint;
- ndate,ntime:str255;
- begin
- if not outputopen then exit;
- {-----------------------------------}
- tab:=chr(9);
- poststatus('Writing System Summary Output',pathline);
-
- {get time stamp}
- getdatetime(now);
- IUDateString(now,abbrevdate,ndate);
- IUTImeString(now,false,ntime);
- scsi_wait;
- writeln(outfile,blessedpath,tab,ndate,tab,ntime,tab,titleversion);
- scsi_wait;
- writeln(outfile,bootblockchecksum);
- scsi_wait;
- writeln(outfile,checksumchecksum);{grand checksum}
- scsi_wait;
- writeln(outfile,rcount,tab,rtypes_count,tab,notsafecount,
- tab,ord(checkfloppies),tab,ord(checknonbootdrives),
- tab,appleshareaccessmask);
- write_end_flag('end header');
- write_safekeys;
- write_morechecks;
- {end of "header"}
- write_vols;{volumes list}
- for i:=1 to rtypes_count do
- begin
- with rtypes[i] do
- begin
- scsi_wait;
- writeln(outfile,thetype,tab,ord(safety),tab,occurs);
- end;
- end;
- write_end_flag('end types');
- for i:=1 to rcount do
- with rinfo^[i] do
- begin
- scsi_wait;
- write(outfile,
- thetype:4,tab,theid:7,tab,thesize:10,tab,
- checksum:7,tab,thename,tab,sysfiles[(filenameindex and fnamemask)]);
- if inputopen then
- begin
- if (filenameindex and exactmatchmask)=exactmatchmask then
- begin
- {normal}
- writeln(outfile);
- end
- else
- begin
- if (filenameindex and idmatchmask)=idmatchmask then
- begin
- writeln(outfile,tab,'changed??');
- end
- else
- begin
- writeln(outfile,tab,'new??');
- end
- end;
- end
- else
- begin
- {normal no input file}
- writeln(outfile)
- end;
-
- end;{for}
- write_end_flag('end res checks');
- end;{proc summary}
-
- {$S core}
- procedure get_set_blessed;
- {get the blessed folder and make it the default and
- build it's pathname}
- var
- volume:integer;
- name:str255;
- begin
- get_blessed;
- set_default_blessed;
- folder_info_two(blessed,blessedbootvolwd,name,blessedpath,true);
- end;{proc}
-
-
-
- {$S event }
- procedure dokeypress;
- {key events
- ignore modifier keys
- Q is quit
- . is halt
- F is Full Check on start up
- A is system only check on startup
- * is debugger
- ^ is debugger without extra output
- & is debug output wutout macsbug
- Y N are replies to questions Yes and No
- return is default button if any}
- var
- whichWindow : WindowPtr;
- chcode:integer;
- ch:str255;
- menuchoice:longint;
-
- begin
- with theevent do
- begin
- chcode:=bitand(message,CharCodeMask);
- ch:=chr(chcode);
- uprstring(ch,true);
- if (ch='Q') then
- begin
- quitting:=true;
- end
- else if (ch='*') then
- begin
- scsi_wait_doevent:=scsi_wait_doevent_debug;
- showdebuginfo:=true;
- debugger;{Macsbug}
- end
- else if (ch='&') then
- begin
- scsi_wait_doevent:=scsi_wait_doevent_debug;
- showdebuginfo:=true;
- end
- else if (ch='#') then
- begin
- detaildebugflag:=true;
- end
- else if (ch='^') then
- begin
- debugger;{Macsbug}
- end
- else if (ch='Y') and (not askanswered) then
- begin
- dobutton(yesbut);
- end
- else if (ch='N') and (not askanswered) then
- begin
- dobutton(nobut);
- end
- else if (ch='A') and (not askanswered) then
- begin
- dobutton(sysonlybut);
- end
- else if (ch='F') and (not askanswered) then
- begin
- dobutton(fullbut);
- end
- else if (ch='.') then
- begin
- halt;{emergency exit}
- end
- else if (chcode=13) and (not askanswered) then
- begin
- dobutton(defaultbutton);
- end
- else
- begin
- sysbeep(1);
- end
- end;{with}
-
- end;
-
- procedure drawlong(l:longint);
- var s:str255;
- begin
- NumtoString(l,s);
- DrawString(concat(s,' '));
- end;
-
- {$S }
- procedure drawbuttons;
- {draw buttons and frame around the default}
- var
- saveport:grafptr;
- wait,endtick:longint;
- h,v:integer;
- ii:integer;
- rr:rect;
- begin
- getport(saveport);
- setport(mainwindow);
- (*
- {zap invisibles}
- for ii:=1 to mbutton do
- if buttons[ii]^^.contrlVis<>255 then
- begin
- rr:=buttonrects[ii];
- insetrect(rr,-4,-4);
- eraseroundrect(rr,22,22);
- end;
- *)
- {draw visibles}
- for ii:=1 to mbutton do
- if buttons[ii]^^.contrlVis=255 then
- begin
- rr:=buttonrects[ii];
- if (ii=defaultbutton) then forecolor(blackcolor) else forecolor(whitecolor);
- insetrect(rr,-4,-4);
- pensize(2,2);
- frameroundrect(rr,22,22);
- pensize(1,1);
- end;
- forecolor(blackcolor);
- drawcontrols(mainwindow);
- setport(saveport);
- end;
-
- {$S }
- procedure showstatus;
- {redraw the status message display and buttons}
- var
- saveport:grafptr;
- wait,endtick:longint;
- h,v:integer;
- begin
- getport(saveport);
- setport(mainwindow);
- EraseRect(mainwindow^.portrect);
- if optioncontrolsactiveflag then
- begin
- draw_optcon_text;
- framerect(textframe);
- end
- else
- begin
- teupdate(textbounds,statustext);
- framerect(textframe);
- end;
- drawbuttons;
- setport(saveport);
- end;
-
- {$S event }
- procedure doshutdown;
- {flush drives and do a system shutdown}
- const maxdrive=32;
- var theerr:oserr;
- volref:integer;
- freebytes:longint;
- drive:integer;
- vname:str255;
- begin
- flushevents(everyevent,0); {clear out event queue}
- {flush default volume}
- theerr:=FlushVol(nil,0);
- {loop over small drive numbers to try and flush the rest}
-
- for drive:=1 to maxdrive do begin
- theerr:=getvinfo(drive,@vname,volref,freebytes);
- if theerr=noerr then
- begin
- {writeln(theerr,' ',vname,' ',drive);}
- theerr:=FlushVol(nil,drive);
- {writeln(theerr);}
- theerr:=eject(nil,drive);
- {writeln(theerr);}
- end
- end;
-
- ShutDwnPower;
- end;{doshutdown}
-
- procedure dobutton{(whichbutton:integer)};
- {actions for buttons and default buttons}
- begin
- case whichbutton of
- nodefaultbut:{do nothing};
- continuebut:
- begin
- {continue}
- askanswered:=true;
- end;
- haltbut:
- begin
- {halt}
- close_all_and_halt(true);
- askanswered:=true;
- end;
- skipitbut:
- begin
- {same as halt}
- close_all_and_halt(true);
- askanswered:=true;
- end;
- shutdownbut:
- begin
- {Shutdown}
- doshutdown;
- askanswered:=true;
- end;
- yesbut:
- begin
- {yes}
- askanswer:=true;
- askanswered:=true;
- end;
- nobut:
- begin
- {no}
- askanswer:=false;
- askanswered:=true;
- end;
- shortbut:
- begin
- {short check}
- fastapplcheck:=true;
- skipapplcheck:=false;
- askanswered:=true;
- end;
- sysonlybut:
- begin
- {short check}
- fastapplcheck:=true;
- skipapplcheck:=true;
- askanswered:=true;
- end;
- fullbut:
- begin
- {full check}
- fastapplcheck:=false;
- skipapplcheck:=false;
- askanswered:=true;
- end;
- end;{case}
-
- end;{proc}
- {$S event }
- procedure dooptcom(jjj:integer);
- {do check box and radio button controls on the screen for specifying
- options}
- var value:integer;
- bvalue:boolean;
- i:integer;
- begin
- value:=getctlvalue(optcons[jjj]);
-
- case jjj of
- floppyoptcon,nonstartupoptcon:
- begin
- {radio buttons}
- if value=0 then
- begin
- setctlvalue(optcons[jjj],1);
- bvalue:=true;
- end
- else
- begin
- setctlvalue(optcons[jjj],0);
- bvalue:=false;
- end;
- end;
-
- owneroptcon,writeoptcon,everythingoptcon:
- begin
- for i:=owneroptcon to everythingoptcon do
- begin
- if jjj=i then
- begin
- setctlvalue(optcons[i],1);
- end
- else
- begin
- setctlvalue(optcons[i],0);
- end;
- end;{for}
-
- end;
- otherwise
-
- end;{case}
-
- case jjj of
- floppyoptcon:
- begin
- checkfloppies:=bvalue;
- end;
- nonstartupoptcon:
- begin
- checknonbootdrives:=bvalue;
- end;
- owneroptcon:
- begin
- appleshareaccessmask:=owneraccessmask;
- end;
- writeoptcon:
- begin
- appleshareaccessmask:=readwriteaccessmask;
- end;
- everythingoptcon:
- begin
- appleshareaccessmask:=everythingaccessmask;
- end;
- end;{case}
- end;{proc}
- procedure adjust_option_controls;
- {make control settings consistent with the values}
-
- procedure setit(ii:integer;bb:boolean);
- begin
- if bb then
- setctlvalue(optcons[ii],1)
- else
- setctlvalue(optcons[ii],0)
- end;
-
- begin
-
- setit(floppyoptcon,checkfloppies);
- setit(nonstartupoptcon,checknonbootdrives);
- setit(owneroptcon,appleshareaccessmask=owneraccessmask);
- setit(writeoptcon,appleshareaccessmask=readwriteaccessmask);
- setit(everythingoptcon,appleshareaccessmask=everythingaccessmask);
-
- end;
- procedure DoControls(whichwindow:windowptr;local:point);
- {process hits on controls}
- label 88,99;
- var whichcontrol:controlhandle;
- part,tresult:integer;
- wait,endwait:longint;
- jbut:integer;
- begin
- setport(whichwindow);
- part:=findcontrol(local,whichwindow,whichcontrol);
- if (part<>0) and (whichcontrol<>nil) then
- begin
- HiLiteControl(whichcontrol,part);{highlight part}
- case part of
- InButton:
- begin
- drawbuttons;
- wait:=30;
- delay(wait,endwait);
- if trackcontrol(whichcontrol,local,nil)<>0 then
- begin
- for jbut:=1 to mbutton do
- if whichcontrol=buttons[jbut] then
- begin
- dobutton(jbut);
- goto 88;
- end;
- end;
- 88:
- HiLiteControl(whichcontrol,0);{unhighlight}
- drawbuttons;
- end;
- InCheckBox:
- begin
- if trackcontrol(whichcontrol,local,nil)<>0 then
- begin
- for jbut:=1 to moptcon do
- if whichcontrol=optcons[jbut] then
- begin
- dooptcom(jbut);
- goto 99;
- end;
- end;
- 99:
- HiLiteControl(whichcontrol,0);{unhighlight}
- end;
- end;{case}
- end;
-
- end;
-
- procedure doclick;
- {process mouse down events}
- var whichwindow:windowptr;
- global,local:point;
- saveport:grafptr;
- inwhat:integer;
- begin
- getport(saveport);
- global:=theEvent.where;
- inwhat:=findwindow(global,whichwindow);
- if whichwindow<>nil then
- begin
- setport(whichwindow);
- end;
- local:=global;
- globaltolocal(local);
- case inwhat of
- indesk:;
- inmenubar:;
- insyswindow:;
- incontent:
- begin
- DoControls(whichwindow,local);
- end;
- indrag:;
- ingrow:;
- ingoaway:quitting:=true;
- end;{case}
-
- setport(saveport);
- end;
- {$S event}
- procedure eventmonitor;
- {for debugging}
- var s1,s2,s3:str255;
- begin
- NumToString(longint(theevent.what),s1);
- case theevent.what of
- NullEvent:s1:='Null';
- MouseDown:s1:='MouseDn';
- MouseUp:s1:='MouseUp';
- UpdateEvt:s1:='Update';
- ActivateEvt:begin
- if odd(theevent.modifiers) then s1:='Act' else s1:='DeAct';
- end;
- otherwise
- {pass s1 as is}
- end;{case}
- numtostring(longint(theevent.modifiers),s2);
- s3:=concat(s1, ' ',s2);
- {debug_mess(s3);}
- end;
- {$S }
- procedure DoNull(dontloop:boolean);
- {background/idle Event processing}
- begin
- if Quitting and (TheEvent.what = NullEvent) then
- begin
- finished:=true;
- close_all_and_halt(true);
- end {if}
- else if (theevent.what =nullevent) then
- begin
-
- {showstatus;}
- if lowmemoryGZflag then low_memory_halt;
- end;
-
- end;{DoNull}
- procedure doevent{(dontloop:boolean)};
- {modified event loop for calling with other routines
- process events till it sees a null event if dontloop is false}
- var
- looplimiter:integer;
- Eventstatus:boolean;{indicates if we should handle this event}
- oureventmask:integer;
- savemouse:EventRecord;
- foundin:integer;
- begin
- looplimiter:=0;
- repeat
- looplimiter:=looplimiter+1;
- oureventmask:=EveryEvent;
- begin
- systemtask;
- EventStatus:=GetNextEvent(oureventmask,TheEvent);
- end;
-
- {Event Processing:}
- if EventStatus then
- case TheEvent.what of
- MouseDown:
- begin
- {use mousedown to test option key}
- optionkeyflag:=optionkeyflag or
- (bitand(theevent.modifiers,optionkey)<>0);
- DoClick;
- end;
- MouseUp:
- begin
- end;
- UpdateEvt:
- begin
- beginupdate(mainwindow);
- drawbuttons;
- showstatus;
- endupdate(mainwindow);
- end;
- ActivateEvt:
- begin
- {use activate to test option key}
- optionkeyflag:=optionkeyflag or
- (bitand(theevent.modifiers,optionkey)<>0);
- end;
- KeyDown,AutoKey:
- begin
- {use keydown to test option key}
- optionkeyflag:=optionkeyflag or
- (bitand(theevent.modifiers,optionkey)<>0);
- Dokeypress;
- end;
- otherwise
- end{case}
- {nullevents:}
- else if (theevent.what =nullevent) then
- DoNull(dontloop);
- until((theevent.what=nullevent) or (dontloop) or (looplimiter>20))
-
- end; {of proc DoEvent}
- {$S startup}
- procedure centerit(var rr:rect;height:integer;width:integer);
- {center a rectangle on the screen}
- var at:point;
- begin
- rr:=screenbits.bounds;
- insetrect(rr,40,40);
- with at do
- begin
- with screenbits.bounds do
- begin
- v:=(top+bottom) div 2;
- h:=(left+right) div 2;
- end;
- with rr do
- begin
- top:=v-(height div 2);
- bottom:=v+(height div 2);
- left:=h-(width div 2);
- right:=h+(width div 2);
- end;
- end;
- end;{proc centerit}
-
- {$S start2}
- procedure mytextsetup;
- {set up textedit record to display status information}
- var i:integer;
- ll:integer;
- begin
-
- {define rect for textedit record for posting messages}
- textbounds:=wbounds;
- globaltolocal(textbounds.topleft);
- globaltolocal(textbounds.botright);
- insetrect(textbounds,10,10);
- textbounds.bottom:=textbounds.bottom-60;
- textframe:=textbounds;
- Insetrect(textframe,-1,-1);
- framerect(textframe);
-
- {create TE Record}
- statustext:=TENew(textbounds,textbounds);
- {set to centered justification}
- TeSetJust(tejustcenter,statustext);
- {set to wider spacing}
- with statustext^^ do
- begin
- {ll:=lineHeight div 2;}
- ll:=5;
- lineheight:=lineheight+ll;
- fontascent:=fontascent+ll;
- end;
- tecaltext(statustext);
- {insert empty lines}
- for i:=1 to mstatus+1 do replaceline(' ',i);
- {put in startup info}
- Replaceline(concat('Startup System Check ',TitleVersion),titleline);
- ReplaceLine('by Albert Lunde, Northwestern University Copyright ⌐ 1988'
- ,byline);
- replaceline(startversion,fileline);
- {set inactive to hide insertion point}
- tedeactivate(statustext);
- framerect(textframe);
- end;
-
- {$S }
- procedure add_to_stack_size(bytecount:size);
- {decrease the heap and increase the stack}
- begin
- setappllimit(ptr(ord4(getappllimit)-bytecount));
- end;
-
- procedure initialize;
-
- var i:integer;
- ignore:oserr;
- begin
- rinfo:=nil;
- ainfo:=nil;
- rcount:=0;
- acount:=0;
- inputfile_filename:='';
- outputfile_filename:='';
- appleshareaccessmask:=appleshareaccessmaskdefault;
- checkfloppies:=checkfloppiesdefault;
- checknonbootdrives:=checknonbootdrivesdefault;
- scsi_wait_doevent:=scsi_wait_doevent_normal;
-
- optioncontrolsactiveflag:=false;
- currentvolumesubscript:=0;
- showdebuginfo:=false;
- detaildebugflag:=false;
- scsi_wait_count:=scsi_wait_limit div 2;
- defaultbutton:=startupdefaultbutton;
- askanswered:=false;
- checksumchecksum:=0;
- fastapplcheck:=true;
- skipapplcheck:=false;
- finished:=false;
- quitting:=false;
- mainwindow:=nil;
- inputopen:=false;
- currentsection:=0;
- on_section_boundry:=true;
- outputopen:=false;
- optionkeyflag:=false;
- StartupOptionKeyFlag:=false;
- notsafecount:=0;
-
- add_to_stack_size(stack_extra_size);
- MaxApplZone;
- MoreMasters;
- MoreMasters;
- MoreMasters;
- MoreMasters;
- FlushEvents(everyevent,0);
- InitGraf(@thePort);
- InitFonts;
- InitWindows;
- InitCursor;
- TEInit;
- for i:=1 to dbamax do dbarray[i]:=0;
- ignore:=getvol(nil,startupwd);
- setup_mygrowzone;{memory management}
- allocate_big_memory(abmfail);
- setupmydebug;
- {setup mainwindow centered on the screen}
- centerit(wbounds,260,470);
-
- mainwindow:=NewWindow(nil,wbounds,'Startup System Check',true,
- dboxProc,pointer(-1),false,0);
- setport(mainwindow);
- textfont(0);
-
- mytextsetup;
- initmypath(myRpath);
- end;
-
- {$S start2 }
-
- procedure setup_buttons;
- var i:integer;
- h,v:integer;
- cr,cmd:string[1];
- tag:str255;
- begin
- h:=12;
- v:=210;
- cr:=chr(13);
- cmd:=chr(17);
- for i:=1 to shutdownbut do
- with buttonrects[i] do
- begin
- top:=v;
- left:=h;
- right:=h+80;
- bottom:=v+38;
- h:=h+91;
- end;
- h:=12;
- v:=210;
- for i:=shutdownbut+1 to mbutton do
- with buttonrects[i] do
- begin
- top:=v;
- left:=h;
- right:=h+80;
- bottom:=v+38;
- h:=h+91;
- end;
-
- buttons[continuebut]:=NewControl(mainwindow,buttonrects[continuebut],
- 'Continue',false,0,0,1,PushButProc,0);
-
- buttons[yesbut]:=NewControl(mainwindow,buttonrects[yesbut],'Yes',false,
- 0,0,1,PushButProc,0);
- tag:=concat(concat(concat('Halt',cr),cmd),'Q');
- buttons[haltbut]:=NewControl(mainwindow,buttonrects[haltbut],tag,false,
- 0,0,1,PushButProc,0);
- buttons[nobut]:=NewControl(mainwindow,buttonrects[nobut],'No',false,
- 0,0,1,PushButProc,0);
- tag:=concat(concat('Shut',cr),'Down');
- buttons[shutdownbut]:=NewControl(mainwindow,buttonrects[shutdownbut],tag,true,
- 0,0,1,PushButProc,0);
- tag:=concat(concat(concat(concat('System ',cr),' Only '),cmd),'A');
- buttons[sysonlybut]:=NewControl(mainwindow,buttonrects[sysonlybut],tag,true,
- 0,0,1,PushButProc,0);
- tag:=concat(concat('Application',cr),'Scan');
- buttons[shortbut]:=NewControl(mainwindow,buttonrects[shortbut],tag,true,
- 0,0,1,PushButProc,0);
- tag:=concat(concat('Full ',cr),concat(concat('Check ',cmd),'F'));
- buttons[Fullbut]:=NewControl(mainwindow,buttonrects[fullbut],tag,true,
- 0,0,1,PushButProc,0);
- tag:=concat(concat(concat('Skip It',cr),cmd),'Q');
- buttons[skipitbut]:=NewControl(mainwindow,buttonrects[skipitbut],tag,true,
- 0,0,1,PushButProc,0);
-
- end;{proc setup_buttons}
- procedure in_progress_buttons;
- begin
- HiliteControl(buttons[continuebut],255);{make inactive but visible}
- HideControl(buttons[sysonlybut]);
- HideControl(buttons[shortbut]);
- HideControl(buttons[fullbut]);
- HideControl(buttons[skipitbut]);
- ShowControl(buttons[continuebut]);
- ShowControl(buttons[haltbut]);
- ShowControl(buttons[shutdownbut]);
- doevent(true);
- end;
- procedure setup_optioncon;
- var i:integer;
- vv:integer;
- cr,cmd:string[1];
- tag:str255;
- rr:rect;
- at:point;
- procedure addit(ii:integer;tag:str255;r:rect;origin:point;pid:integer);
- const
- visible=false;
- begin
- if ii>moptcon then
- begin
- sysbeep(1);
- exit;
- end;
- with r do
- with origin do
- begin
- top:=top+v;
- bottom:=bottom+v;
- right:=right+h;
- left:=left+h;
- end;
- optconrects[ii]:=r;
- optcons[ii]:=NewControl(mainwindow,r,tag,visible,0,0,1,Pid,0);
-
-
- end;{proc}
-
- procedure rris(ptop,pleft:integer);
- begin
- with rr do
- begin
- top:=ptop;
- left:=pleft;
- bottom:=ptop+18;
- right:=pleft+StringWidth(tag)+20;
- end;
- end;{proc}
-
- begin
- at.h:=90;
- at.v:=0;
- optconorigin:=at;
- tag:='Check Floppy Diskettes';
- vv:=55;
- rris(vv, 16);
- addit(floppyoptcon,tag,rr,at,checkboxproc);
-
- vv:=vv+19;
- tag:='Check Non-Startup Disk Volumes';
- rris(vv,16);
- addit(nonstartupoptcon,tag,rr,at,checkboxproc);
-
- vv:=125;
- tag:='Only check folders if owner';
- rris(vv,16);
- addit(owneroptcon,tag,rr,at,RadioButProc);
-
- vv:=vv+19;
- tag:='Only check folders if read/write access';
- rris(vv,16);
- addit(writeoptcon,tag,rr,at,RadioButProc);
-
- vv:=vv+19;
- tag:='Check everything in sight';
- rris(vv,16);
- addit(everythingoptcon,tag,rr,at,RadioButProc);
-
- end;{proc}
-
- procedure draw_optcon_text;
-
- begin
- with optconorigin do moveto(h,v);
- move(16,30);
- DrawString('Specify Options - What will be checked');
- with optconorigin do moveto(h,v);
- move(35,50);
- DrawString('General:');
- with optconorigin do moveto(h,v);
- move(35,120);
- DrawString('AppleShare Access:');
- end;
- {$S }
- procedure unload_all;
- {unload seg on most segments}
- var grow,gg:longint;
- begin
- unloadseg(@offer_to_replace_input);{startup}
- unloadseg(@find_vols);{vols}
- unloadseg(@note_application );{appl }
- unloadseg(@setmytype );{myres }
- unloadseg(@checksumHdataOLD);{wascore}
- unloadseg(@detail_resource_check );{detail }
- unloadseg(@dokeypress );{event }
- unloadseg(@absolute_read);{boot }
- unloadseg(@folder_info_two );{files }
- unloadseg(@sortresources );{sortres }
- unloadseg(@write_morechecks );{start2 }
- unloadseg(@sortapplications );{sortappl }
- unloadseg(@applsummary );{applout }
- unloadseg(@add_safekey );{safekey }
- unloadseg(@detail_appl_check );{appldet }
- unloadseg(@start_types );{start3 }
- unloadseg(@write_end_flag);{core}
- postmem(memline);
- end;
- procedure docheck;
- {top level procedure for the section of the program that
- does the work. Note there is no main event loop in the usual sense
- I call DoEvent from all over, mostly when posting progress
- messages on the screen and loop till I get a null event}
-
- begin
- rcount:=0;
- acount:=0;
- {display the system folder}
- poststatus(blessedpath,pathline);
-
- {checksum the boot blocks}
- set_default_blessed;
- poststatus('Checking boot blocks',fileline);
- bootblockchecksum:=checksum_boot_blocks;
- clear_to_end(fileline);
-
- {checksum all resources in the system folder}
- set_default_blessed;
- unload_all;
- enumeratecatalog(blessed);
- unload_all;
-
- poststatus('Sort Resources',fileline);
- sortresources(rinfo,rcount);
- clear_to_end(fileline);
- {compare over-all checksums}
- if inputopen then
- begin
- if bootblockchecksum<>oldbootblockchecksum then
- begin
- Wait_for_buttons('The boot blocks appear to have changed',continuebut);
- open_output_dialog(true,yesbut);
- end;
- if checksumchecksum<>oldchecksumchecksum then
- begin
- Wait_for_buttons('The over-all checksum of resources has changed',continuebut);
- open_output_dialog(true,yesbut);
- end;
- end;{if inputopen}
- detail_resource_check;
- unload_all;
- show_detail_changes;
- poststatus('',resline);
-
- end;{docheck}
-
- procedure docheck_applications;
-
- begin
- set_default_blessed;
- acount:=0;
- clear_to_end(pathline);
-
- unload_all;
- scan_all_vols;
- unload_all;
-
- clear_to_end(fileline);
- poststatus('Checksum applications',pathline);
-
- unload_all;
- checksum_all_appl;
- unload_all;
-
- clear_to_end(pathline);
- Poststatus('Sort Application info',pathline);
-
- sortapplications(ainfo,acount);
-
-
- if fastapplcheck then
- poststatus('Compare application sizes',pathline)
- else
- poststatus('Compare application resource checks',pathline);
- clear_to_end(fileline);
-
- unload_all;
- detail_appl_check;
- unload_all;
-
- set_default_blessed;
- clear_to_end(pathline);
-
- show_appl_detail_changes;
-
- unload_all;
- checksum_unchecked_appl;
- end;{procedure}
- {$S }
- begin
-
- initialize;
- kill_nil;
- setup_buttons;
- setup_optioncon;
- if abmfail then low_memory_halt;
- start_types;
- start_safekey;
- doEvent(true);
-
- HFSwarning;{quit if no HFS}
-
- get_set_blessed;{set default to system folder}
- Poststatus(blessedpath,pathline);
- postmem(memline);
- optionkeyflag:=optionkeyflag or option_key_down;{test option key}
- wait_for_start(
- 'This will take a minute or two to check the system folder and applications.'
- ,startupdelay);
- in_progress_buttons;
-
- StartupOptionKeyFlag:=optionKeyFlag;{get state of option key from
- button click or activate}
-
- {look for input file}
- open_input;
- {read header to get options}
- read_input_header;
-
- if StartupOptionKeyFlag then wait_for_options;
-
- {ask about output file if option key down or input file not found}
- if StartupOptionKeyFlag or InputNotdefault then
- begin
-
- open_output_dialog(true,yesbut);
-
- end
- else
- begin
- poststatus(
- '(start with option key to write output file or select features)'
- ,pathline);
- end;
-
-
- {pick alternate system file}
- pick_set_blessed;
-
- unload_all;
- {enumerate connected volumes}
- dovols;
-
-
- readoklist;
- {debugger;}
-
- unload_all;
- docheck;
- unload_all;
-
- (* if outputopen then skipapplcheck:=false; *)
-
- if not skipapplcheck then docheck_applications;
- summary;
- if not skipapplcheck then
- APPLsummary
- else
- copyAPPLSummary;
-
-
- offer_to_replace_input;
- PostStatus('DONE',fileline);
- sysbeep(1);
- close_all_and_halt(false);
- end.{Vcheck main}
-