mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
2154 lines
86 KiB
Plaintext
2154 lines
86 KiB
Plaintext
|
;
|
|||
|
; File: FolderMgr.a
|
|||
|
;
|
|||
|
; Contains: Folder Manager
|
|||
|
;
|
|||
|
; Written by: Darin Adler
|
|||
|
;
|
|||
|
; Copyright: <09> 1989-1992 by Apple Computer, Inc. All rights reserved.
|
|||
|
;
|
|||
|
; This file is used in these builds: BigBang
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <SM4> 10/29/92 SWC Backed out <SM3> and fixed the INCLUDE filenames.
|
|||
|
; <SM3> 10/28/92 SWC Changed the INCLUDEs to a LOAD of StandardEqu.d.
|
|||
|
; <SM2> 10/22/92 CSS Change short branches to word branches.
|
|||
|
; <24> 6/12/91 LN added #include 'SysPrivateEqu.a'
|
|||
|
; <23> 4/16/91 PP sad,#??????:After making _LockRng call for Network Trash, return
|
|||
|
; errors ioErr and paramErr (for unimplemented afp _LockRng) to
|
|||
|
; the caller.
|
|||
|
; <22> 4/7/91 PP csd,#ich-FoldMgr-0002:When reassigning and cleaning out a
|
|||
|
; previous Trash Can folder inside a Network Trash Folder, ignore
|
|||
|
; file locked error.
|
|||
|
; <21> 3/22/91 PP sad,#85189:On a client, always use GetNetTrashID if a net trash
|
|||
|
; folder is to be created. Also, if Net Trash Folder SetCatInfo
|
|||
|
; fails, pass the error.
|
|||
|
; <20> 3/19/91 PP dba,#WS RRE-290:Do locking of Desktop and Trash folders
|
|||
|
; correctly after they are found.
|
|||
|
; <19> 2/11/91 PP dba,#DCL-274:Make non network trash folders visible. Also, all
|
|||
|
; trash folders get locked after they are found if the volume
|
|||
|
; supports locking.
|
|||
|
; <18> 1/14/91 PP (sad) Add GetFolderName.
|
|||
|
; <17> 12/14/90 PP (sad) Do not lock special folders except for Desktop Folder for
|
|||
|
; FileShare case. Reorganized hard-wired strings for internal
|
|||
|
; names.
|
|||
|
; <16> 8/30/90 PP gestaltFolderMgrAttr is gestaltFindFolderAttr.
|
|||
|
; gestaltFolderMgrPresent is gestaltFindFolderPresent.
|
|||
|
; <15> 8/6/90 PP Remove obsolete code for making old desktop visible. Do not set
|
|||
|
; folder manager created bit in FndrInfo since it is not used by
|
|||
|
; the Finder.
|
|||
|
; <14> 7/19/90 PP Before getting fld# resource, make sure that SetResLoad(TRUE) is
|
|||
|
; done in all cases.
|
|||
|
; <13> 7/16/90 PP Set attributes of Network Trash folder before giving away the
|
|||
|
; ownership to administrator.
|
|||
|
; <12> 7/11/90 PP If error during TrashCan creation, close the UsageMap file.
|
|||
|
; <11> 7/2/90 PP Integrate new shared trash folder scheme for servers. Algorithm
|
|||
|
; is as defined by FileShare people (Pat Dirks).
|
|||
|
; Desktop folder is visible again.
|
|||
|
; 6/14/90 PWD Integrated new network trash algorithm. Changed to include separate
|
|||
|
; cache for things to be remembered for all time, such as trash folder IDs.
|
|||
|
; <10> 6/5/90 PP Set the invisible bit in FinderInfo for Desktop Folder and all
|
|||
|
; Trash Folders.
|
|||
|
; <9> 5/16/90 PP Set bit 11 of FinderFlags for locked folders created by
|
|||
|
; FolderMgr. This lets Finder know that FolderMgr created that
|
|||
|
; folder.
|
|||
|
; <8> 5/7/90 JSM Change BSR's to JSR's in preparation for becoming a linked
|
|||
|
; patch.
|
|||
|
; <7> 5/3/90 PP Fix bug related to passing cleared dirID field to HGetVInfo. If
|
|||
|
; we don't, it may affect current working directories. Change
|
|||
|
; "Temporary Folder" to "Temporary Items".
|
|||
|
; <6> 3/20/90 PP Support Temporary folder just like Trash or Desktop folder.
|
|||
|
; <5> 2/6/90 PP Open up Trash Folder privileges when it is shared through
|
|||
|
; Personal AppleShare. Check Desktop folder lock when sharing.
|
|||
|
; <4> 2/4/90 dba move some equates to SysEqu.a
|
|||
|
; <3> 1/22/90 PP Ignore cached error if createFolder is true.
|
|||
|
; <2.1> 11/17/89 dba changed names of desktop folder and trash folder again,
|
|||
|
; invisible characters were a bad idea
|
|||
|
; <2.0> 10/17/89 prp Fixed bug in caching. Guest login on AppleShare volumes creates
|
|||
|
; correct Trash folder.
|
|||
|
; <1.9> 10/13/89 prp Bug fix related to Trash folder privileges. Bug fix related to
|
|||
|
; getting volume attributes correctly. Also, look for System
|
|||
|
; Folder dirID in fndrInfo instead of System File FCB.
|
|||
|
; 10/13/89 prp fullPrivileges constant had bits reversed. Bug in loading disk
|
|||
|
; attributes. Get SystemFolder dirID from fndrInfo and not FCB.
|
|||
|
; Set loginName Trash Folder privileges correctly.
|
|||
|
; <1.8> 10/4/89 dba fix bug by correcting ioObjNamePtr equate
|
|||
|
; <1.7> 9/26/89 prp Add support for Installer people. There is a routine
|
|||
|
; FindFolderInternal for them. Fix bug related to branching to
|
|||
|
; CreateNewEntry instead of NewDiskAndFolder
|
|||
|
; 9/26/89 prp FindFolderInternal done for installer people, Fix bug related to
|
|||
|
; branching to NewDiskAndFolder instead CreateNewEntry
|
|||
|
; <1.6> 9/18/89 prp 'Trash' and 'Desktop' folders have ascii <cr> (decimal 13) in
|
|||
|
; front of their names instead of ascii 1 to make them work better
|
|||
|
; with different fonts.
|
|||
|
; <1.5> 8/16/89 prp Fix bugs related to CacheHandle in EnterFolderInCache.
|
|||
|
; <1.4> 8/15/89 prp The CacheHandle should be allocated in System Heap.
|
|||
|
; 8/15/89 prp Allocate initial Cache empty handle in System heap
|
|||
|
; <1.3> 8/11/89 prp Restore param blk in a0 after calling FindFolderInCache.
|
|||
|
; <1.2> 7/17/89 dba changed error handling a big; got rid of extraneous system
|
|||
|
; folder check; switched from <20>Any User<65> to <20>Administrator<6F> for
|
|||
|
; owner of shared trash
|
|||
|
; <1.1> 6/28/89 dba use ExpandMem instead of low-memory global; make some changes
|
|||
|
; from code review
|
|||
|
; 6/24/89 dba fix register bug, add comments
|
|||
|
; <1.0> 6/2/89 prp Initial release. Folder Manager now part of Alias Manager.
|
|||
|
; 6/2/89 dba roll into system source (change error code)
|
|||
|
; 5/20/89 dba prepare for Finder
|
|||
|
; 5/6/89 dba new today
|
|||
|
;
|
|||
|
; To Do:
|
|||
|
; check to make sure that no one uses $FFFF0000 and higher dirIDs
|
|||
|
; consider getting rid of <20>where to empty trash<73> as follows:
|
|||
|
; check the <20>super-user<65> bit on the result of GetVolParms or GetDirAccess
|
|||
|
; if the user is a <20>super-user<65>, then give the root trash folder
|
|||
|
; otherwise, use the login-name folder scheme
|
|||
|
;
|
|||
|
|
|||
|
; Strategy:
|
|||
|
;
|
|||
|
; The Folder Manager is a single call, FindFolder, that defines a number of folder specialties.
|
|||
|
; Examples of folder specialties are: system, desktop, trash, settings, temporary, communications,
|
|||
|
; etc. There can be one folder of each specialty per volume. These folders fall into two major
|
|||
|
; categories.
|
|||
|
;
|
|||
|
; The first category is for user-visible folders. These have different names in various countries,
|
|||
|
; and are specified by a resource in the system file. The resource contains a list of folder
|
|||
|
; specialties (long words) and folder names (strings). Currently, all user visible folders are in
|
|||
|
; the system folder and are located by name. The resource in the system file contains a version
|
|||
|
; field, so new kinds of user-visible folders can be added in the future. Note that when looking
|
|||
|
; for user-visible folders on a disk, the Folder Manager uses the system file on that disk, rather
|
|||
|
; than the current active system file.
|
|||
|
;
|
|||
|
; The second category is for special folders. These currently consist of the system folder, the
|
|||
|
; desktop folder, and the trash folder. These folders are not visible to the user, and are not
|
|||
|
; located by internationalizable names. The system folder is located by its dirID, which is
|
|||
|
; stored in the Finder<65>s volume information. The desktop and trash folders are located by their
|
|||
|
; names, and the Finder and Standard File do not dispay the folders.
|
|||
|
;
|
|||
|
; If the FindFolder call is made for a volume which does not have a particular folder, the
|
|||
|
; folder is created, if possible. (The exception to this is the system folder, which is created
|
|||
|
; by the user when he drags a System and Finder into the same folder, or uses the Installer.)
|
|||
|
; New folders are created with the <20>name-locked<65> attribute, since they are identified by name.
|
|||
|
; New folders on volumes that support folder locking are also locked. Since the current
|
|||
|
; implementation of user-visible folders is based on the system folder, disks without system
|
|||
|
; folders, like AppleShare 1.0 and 2.0 volumes, do not have any user-visible folders. The desktop
|
|||
|
; folder is not created on any disk that has the <20>noDeskItems<6D> attribute.
|
|||
|
;
|
|||
|
; The trash folder is handled specially on volumes that have access controls (privileges).
|
|||
|
; A <20>shared<65> trash folder is created, which contains all of the user-specific trash folders.
|
|||
|
; The <20>shared<65> trash folder is readable, writable, and searchable by all users, and a trash
|
|||
|
; folder is created within it for each login name. When the Finder empties the trash, it starts
|
|||
|
; from this <20>shared<65> trash folder, and moves down, emptying as much trash as privileges allow.
|
|||
|
;
|
|||
|
; To prevent excessive disk access, the Folder Manager maintains a cache of results from
|
|||
|
; calls to FindFolder. If a disk is modified or its attributes change (it is unlocked), the
|
|||
|
; cache is ignored. The cache is maintained as a purgeable handle in the system heap. The cache
|
|||
|
; stores error results, as well as folder<65>s that have been found. (It uses unusually high dirIDs
|
|||
|
; to represent these error results internally: $FFFF0000 and up.)
|
|||
|
|
|||
|
; the following are a few notes about error handling (Darin and Prashant)
|
|||
|
;pass GetFCBInfo returns error for System file
|
|||
|
;pass HGetVInfo returns error for vRefNum passed in or system disk vRefNum
|
|||
|
;pass GetVolParms returns an error other than paramErr
|
|||
|
;fnfErr unknown specialty in the fld# resource
|
|||
|
;pass GetCatInfo error while looking in system folder
|
|||
|
;fnfErr folder not found and createFolder is false
|
|||
|
;pass DirCreate error while creating folder
|
|||
|
;pass Get/CatInfo error while setting info of folder
|
|||
|
;pass HSetFLock error when locking folder
|
|||
|
;pass Get/SetDirAccess error while setting privileges
|
|||
|
;pass GetLogInInfo error while getting name of trash folder
|
|||
|
;fnfErr trying to find folder on disk without system folder support
|
|||
|
;fnfErr trying to find fodler on disk without system folder in volume header
|
|||
|
;fnfErr trying to find desktop folder on disk without desktop support
|
|||
|
;dupFNErr file found instead of folder
|
|||
|
;pass HOpenResFile error opening another system file
|
|||
|
;pass GetResource (or Get1Resource error from the fld# resource)
|
|||
|
;fnfErr invalid fld# resource
|
|||
|
;fnfErr unknown version in fld# resource
|
|||
|
;fnfErr string too long in kFolderByName fld# resource
|
|||
|
; ***
|
|||
|
|
|||
|
|
|||
|
case on
|
|||
|
|
|||
|
print push,off
|
|||
|
|
|||
|
include 'SysEqu.a'
|
|||
|
INCLUDE 'SysPrivateEqu.a'
|
|||
|
|
|||
|
; The following are missing from SysEqu.a:
|
|||
|
|
|||
|
ioLockFlg equ 0 ; file/directory locked bit in ioFlAttrib field
|
|||
|
|
|||
|
bFndrInvisible equ 6 ; Finder Info Invisible bit in upper byte of flags
|
|||
|
mFNameLock equ $1000 ; rename-inhibit bit mask in file/folder flags
|
|||
|
|
|||
|
vMAttrib equ 2 ; attributes word
|
|||
|
|
|||
|
bNoDeskItems equ 20 ; bit for whether disk supports desktop
|
|||
|
bAccessCntl equ 18 ; bit for whether disk supports privileges
|
|||
|
bExtFSVol equ 16 ; bit for whether disk is External FS volume
|
|||
|
bNoSysDir equ 17 ; bit for whether disk supports system folder
|
|||
|
bHasFolderLock equ 10 ; bit for whether disk supports folder lock
|
|||
|
|
|||
|
include 'ToolUtils.a'
|
|||
|
include 'SysErr.a'
|
|||
|
include 'Traps.a'
|
|||
|
include 'GestaltEqu.a'
|
|||
|
|
|||
|
include 'InternalMacros.a' ; useful macros
|
|||
|
|
|||
|
include 'Folders.a' ; public interface to folder manager
|
|||
|
|
|||
|
print pop, nogen
|
|||
|
|
|||
|
DEBUG default false ; debugging off by default
|
|||
|
CACHING default true ; caching on by default
|
|||
|
FOR_FOLDERMGR_INIT default false ; not for INIT by default
|
|||
|
FOR_INSTALLER default false ; not for INSTALLER by default
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; The FolderMgrGlobals currently hold just two pointers: one non-purgable handle for the permanent
|
|||
|
; cache of special, non-changing directory IDs [currently just trash folder IDs], and one purgable
|
|||
|
; handle to cache all other calls to the folder manager. The latter can be emptied at any time and
|
|||
|
; is invalidated when the volume's modification date changes.
|
|||
|
;
|
|||
|
; NOTE: The name emFolderCache for the Expanded Lo-Mem variable that now holds our global ptr is
|
|||
|
; rather misleading: it should probably be renamed to 'FolderMgrGlobals', or some such.
|
|||
|
|
|||
|
FolderMgrGlobalRec record 0 ;
|
|||
|
normalCacheHndl ds.l 1 ; handle to purgable cache
|
|||
|
specialCacheHndl ds.l 1 ; handle to non-purgable special cache
|
|||
|
FolderMgrGlobalSize equ * ;
|
|||
|
endr
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; The special cache consists of a table of entries, each one identified by the volume's VRefnum.
|
|||
|
; Associated with each VRefNum is the Trash Map file lrefNum and the Trash Folder DirID.
|
|||
|
;
|
|||
|
SpecialCacheEntry record 0 ;
|
|||
|
scVRefNum ds.w 1 ; VRefNum of volume this entry is for
|
|||
|
scTrashMapRefNum ds.w 1 ; Trash map file refNum
|
|||
|
scTrashDirID ds.l 1 ; The trash folder DirID
|
|||
|
SpecialCacheEntrySize equ * ;
|
|||
|
endr
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; The FolderNameList resource contains an element for each folder specialty.
|
|||
|
; The element contains the folder specialty that it is a name for, a version (0 for current version),
|
|||
|
; a length, and data. For the first implementation, the data is the name of a folder in the
|
|||
|
; system folder.
|
|||
|
|
|||
|
kFolderNameListType equ 'fld#' ; resource type and ID for the folder name list
|
|||
|
kFolderNameListID equ 0
|
|||
|
|
|||
|
FolderName record 0
|
|||
|
type ds.l 1 ; folder specialty for which this is an entry
|
|||
|
version ds.w 1 ; type of entry (0 for folder name)
|
|||
|
length ds.w 1 ; length of this folder name
|
|||
|
data equ * ; the data (text for version 0)
|
|||
|
endr
|
|||
|
|
|||
|
kFolderByNameVersion equ 0 ; this version<6F>s data is just the name
|
|||
|
|
|||
|
kStringMaxLength equ 255 ; if string is too big, it<69>s invalid
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
; We put dirIDs in the cache. We also cache error results from previous lookups.
|
|||
|
; This is the dirID range that is used for errors (the low word holds the error code).
|
|||
|
|
|||
|
kCachedErrorBase equ $FFFF0000 ; low word holds error code
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
InternalNames proc
|
|||
|
|
|||
|
; These are names of folders used internally by the Folder Manager.
|
|||
|
; They are hard-wired here, and not internationalized, so that you can mix scripts
|
|||
|
; and hard disks and file servers and always use the same folders for the files on
|
|||
|
; the desktop in the trash and for the guest trash. This is acceptable, because the
|
|||
|
; names should only be visible to programmers and to users who use 6.X systems on a
|
|||
|
; disk that has been used with 7.X previously.
|
|||
|
|
|||
|
; The Desktop Folder has to be named <20>Desktop Folder<65> instead of <20>Desktop<6F> because that
|
|||
|
; name is already taken for the resource file containing the resource-based desktop file.
|
|||
|
|
|||
|
string pascal
|
|||
|
|
|||
|
entry DesktopFolderName, TrashFolderName, TemporaryFolderName, NetTrashFolderName, NetTrashPrefix, TrashMapName
|
|||
|
|
|||
|
DesktopFolderName dc.b 'Desktop Folder'
|
|||
|
align
|
|||
|
|
|||
|
TrashFolderName dc.b 'Trash'
|
|||
|
align
|
|||
|
|
|||
|
TemporaryFolderName dc.b 'Temporary Items'
|
|||
|
align
|
|||
|
|
|||
|
NetTrashFolderName dc.b 'Network Trash Folder'
|
|||
|
align
|
|||
|
|
|||
|
NetTrashPrefix dc.b 'Trash Can #' ; Prefix for each trash can name
|
|||
|
align
|
|||
|
|
|||
|
TrashMapName: dc.b 'Trash Can Usage Map' ; Name of trashcan arbitration file
|
|||
|
align
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; PROCEDURE InitFolderManager;
|
|||
|
|
|||
|
InitFolderManager proc export
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
export FolderMgrGlobalPtr
|
|||
|
endif
|
|||
|
with FolderMgrGlobalRec, SpecialCacheEntry
|
|||
|
linkSave
|
|||
|
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
lea FolderMgrGlobalPtr,a1 ; if already allocated, get out
|
|||
|
tst.l (a1)
|
|||
|
bnz.s @NoSpecialCache
|
|||
|
endif
|
|||
|
|
|||
|
moveq #FolderMgrGlobalSize, d0 ;
|
|||
|
_NewPtr ,sys,clear ; Allocate a block of sysheap memory to hold folder mgr globals
|
|||
|
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
lea FolderMgrGlobalPtr,a1
|
|||
|
move.l a0,(a1)
|
|||
|
else
|
|||
|
move.l ExpandMem,a1
|
|||
|
move.l a0,ExpandMemRec.emFolderCache(a1)
|
|||
|
endif
|
|||
|
|
|||
|
move.l a0, a1 ; save the ptr to our globals
|
|||
|
_NewEmptyHandle ,sys ; get a handle for the normal disposable cache
|
|||
|
move.l a0, normalCacheHndl(a1) ; save it off in our globals
|
|||
|
|
|||
|
moveq #SpecialCacheEntrySize*5, d0 ; Try to grab space for 5 shared volumes
|
|||
|
_NewHandle ,sys,clear ; Get non-purgable handle for our special, permanent cache
|
|||
|
bne.s @NoSpecialCache ; We're in trouble here...
|
|||
|
move.l a0, specialCacheHndl(a1) ; save it off in our globals
|
|||
|
|
|||
|
@NoSpecialCache:
|
|||
|
; Note that we do not do error checking here. Instead we check for a
|
|||
|
; nil handle whenever we use it. Since the cache handle is normally
|
|||
|
; kept purgeable, we start it out empty, as if it was just purged.
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
endwith
|
|||
|
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
FolderMgrGlobalPtr dc.l 0
|
|||
|
endif
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;===============================================================================
|
|||
|
;
|
|||
|
; PROCEDURE gestaltFolderMgr(); - Folder manager gestalt function
|
|||
|
;
|
|||
|
; FUNCTION gestaltFolderMgr (
|
|||
|
; gestaltSelector: OSType; = PACKED ARRAY [1..4] OF CHAR;
|
|||
|
; VAR gestaltResult: Longint;
|
|||
|
; ): OSErr; = Integer;
|
|||
|
;
|
|||
|
;===============================================================================
|
|||
|
|
|||
|
gestaltFolderMgr proc export
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
error ds.w 1 ; the resulting error code
|
|||
|
parametersStackFrame
|
|||
|
gestaltSelector ds.l 1 ; the selector type
|
|||
|
gestaltResult ds.l 1 ; returned result
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave
|
|||
|
|
|||
|
move.w #gestaltUndefSelectorErr,d0 ; assume bad selector was passed
|
|||
|
clr.l d1 ; prepare for return result
|
|||
|
cmp.l #gestaltFindFolderAttr,gestaltSelector(a6)
|
|||
|
bne.s @done ; not the right selector
|
|||
|
bset.l #gestaltFindFolderPresent,d1 ; set the presence bit
|
|||
|
clr.w d0 ; no error
|
|||
|
@done
|
|||
|
move.l gestaltResult(a6),a0 ; load address of result
|
|||
|
move.l d1,(a0) ; return the computed result
|
|||
|
move.w d0,error(a6); ; return error code
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
ENDPROC
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION FindFolder(vRefNum: INTEGER; folderType: OSType; createFolder: BOOLEAN;
|
|||
|
; VAR foundVRefNum: INTEGER; VAR foundDirID: LONGINT): OSErr;
|
|||
|
;
|
|||
|
; This routine is a wrapper around an internal routine that expects a resource handle as an
|
|||
|
; additional parameter. This routine calls it with a nil resource handle.
|
|||
|
;
|
|||
|
FindFolder proc export
|
|||
|
import FindFolderInternal
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
error ds.w 1 ; the resulting error code
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; the vRefNum of the disk we want to look at
|
|||
|
which ds.l 1 ; which folder we are interested in
|
|||
|
createFolder ds.w 1 ; should we create the folder if not found
|
|||
|
pFoundVRefNum ds.l 1 ; the vRefNum of the folder we found
|
|||
|
pFoundDirID ds.l 1 ; the dirID of the folder we found
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave
|
|||
|
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
jsr InitFolderManager ; do initialization of global pointers
|
|||
|
endif
|
|||
|
|
|||
|
rsrv.w ; room for return code
|
|||
|
push.w vRefNum(a6) ; push all params for calling internal routine
|
|||
|
push.l which(a6)
|
|||
|
push.w createFolder(a6)
|
|||
|
push.l pFoundVRefNum(a6)
|
|||
|
push.l pFoundDirID(a6)
|
|||
|
push.l #nil ; 'fld#' resource is not loaded
|
|||
|
jsr FindFolderInternal
|
|||
|
pop.w d0 ; get return code
|
|||
|
move.w d0,error(a6) ; return error code
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION GetFolderName (vRefNum: INTEGER; folderType: OSType;
|
|||
|
; VAR foundVRefNum: INTEGER; VAR name: StringPtr): OSErr;
|
|||
|
;
|
|||
|
; This routine returns the name of a special folder. Currently, implemented only for
|
|||
|
; hard-wired internal names
|
|||
|
;
|
|||
|
GetFolderName proc export
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
error ds.w 1 ; the resulting error code
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; the vRefNum of the disk we want to look at
|
|||
|
whichFolder ds.l 1 ; which folder we are interested in
|
|||
|
pFoundVRefNum ds.l 1 ; the vRefNum of the folder we found
|
|||
|
pName ds.l 1 ; the pointer to buffer where name is returned
|
|||
|
endStackFrame
|
|||
|
|
|||
|
folderType equ d1 ; register for folder specialty
|
|||
|
|
|||
|
linkSave
|
|||
|
|
|||
|
move.l whichFolder(a6),folderType ; get the folder specialty we return name for
|
|||
|
cmp.l #kDesktopFolderType,folderType ; is it the desktop folder?
|
|||
|
beq.s @DesktopFolder ; yes, the desktop folder
|
|||
|
cmp.l #kWhereToEmptyTrashFolderType,folderType ; is it the network trash folder?
|
|||
|
beq.s @NetTrashFolder ; yes, the network trash folder
|
|||
|
cmp.l #kTrashFolderType,folderType ; is it the trash folder?
|
|||
|
beq.s @TrashFolder ; yes, the trash folder
|
|||
|
cmp.l #kTemporaryFolderType,folderType; is it the temporary folder?
|
|||
|
beq.s @TemporaryFolder ; yes, the temporary folder
|
|||
|
|
|||
|
moveq #paramErr,d0 ; Unrecognized folder type
|
|||
|
bra.s @done
|
|||
|
|
|||
|
@DesktopFolder
|
|||
|
lea DesktopFolderName,a0 ; desktop folder name
|
|||
|
bra.s @fillName
|
|||
|
@NetTrashFolder
|
|||
|
lea NetTrashFolderName,a0 ; Network trash folder name
|
|||
|
bra.s @fillName
|
|||
|
@TrashFolder
|
|||
|
lea TrashFolderName,a0 ; trash folder name
|
|||
|
bra.s @fillName
|
|||
|
@TemporaryFolder
|
|||
|
lea TemporaryFolderName,a0 ; temporary folder name
|
|||
|
@fillName
|
|||
|
move.l pName(a6),a1 ; get return name string pointer
|
|||
|
moveq #0,d0 ; Clean upper 3 bytes
|
|||
|
move.b (a0),d0 ; Pick up string length
|
|||
|
addq.l #1, d0 ; Add 1 for the length byte itself
|
|||
|
_BlockMove ; Copy the name
|
|||
|
move.l pFoundVRefNum(a6),a0 ; return the vRefNum
|
|||
|
move.w vRefNum(a6),(a0) ;
|
|||
|
moveq #noErr,d0 ; no error
|
|||
|
|
|||
|
@done
|
|||
|
move.w d0,error(a6) ; return error code
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION FindFolderInternal(vRefNum: INTEGER; folderType: OSType; createFolder: BOOLEAN;
|
|||
|
; VAR foundVRefNum: INTEGER; VAR foundDirID: LONGINT; resHandle : Handle): OSErr;
|
|||
|
;
|
|||
|
; Find the folder of the specified type or create it if it doesn<73>t already exist.
|
|||
|
; The vRefNum and dirID will be cached in a handle maintained in the system heap.
|
|||
|
;
|
|||
|
; The cache is kept so that no disk access will occur if you ask for the same folder
|
|||
|
; many times in a row. The cache is kept as long as the modification date and attributes
|
|||
|
; of a disk remain the same. If the modification date changes, folder may have moved or
|
|||
|
; been deleted. If the attributes change, a folder my be created on a disk that was
|
|||
|
; previously locked.
|
|||
|
;
|
|||
|
; The resHandle is a handle to loaded resource of type 'fld#' and id 0. If it is nil, the
|
|||
|
; routine loads the resource from the system file.
|
|||
|
|
|||
|
FindFolderInternal proc export
|
|||
|
if FOR_INSTALLER then
|
|||
|
import HOPENRESFILE
|
|||
|
endif
|
|||
|
if CACHING then
|
|||
|
import FindFolderInCache,EnterFolderInCache
|
|||
|
endif
|
|||
|
import FindSpecialCacheEntry,AddSpecialCacheEntry
|
|||
|
import GetNetTrashID,GetTrashMapRefnum,GetTrashCanID
|
|||
|
|
|||
|
; if FOR_FOLDERMGR_INIT then
|
|||
|
; import INITFolderNameListHandle
|
|||
|
; endif
|
|||
|
|
|||
|
kFileNotOpen equ -1 ; a refNum representing a file that isn<73>t open
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
error ds.w 1 ; the resulting error code
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; the vRefNum of the disk we want to look at
|
|||
|
which ds.l 1 ; which folder we are interested in
|
|||
|
createFolder ds.w 1 ; should we create the folder if not found
|
|||
|
pFoundVRefNum ds.l 1 ; the vRefNum of the folder we found
|
|||
|
pFoundDirID ds.l 1 ; the dirID of the folder we found
|
|||
|
resHandle ds.l 1 ; the handle to 'fld#' resource
|
|||
|
localsStackFrame
|
|||
|
diskPB ds.b ioHVQElSize ; the disk parameter block
|
|||
|
diskPBVolParms ds.b ioActCount+4 ; the disk parameter block for GetVolParms
|
|||
|
diskVolParms ds.b vMAttrib + 4 ; room for attributes
|
|||
|
folderPB ds.b ioHFQElSiz ; the folder parameter block
|
|||
|
loginName ds.b 32 ; room for the log-in name
|
|||
|
savedResFile ds.w 1 ; room for the saved current res file refNum
|
|||
|
savedNetTrashID ds.l 1 ; room for the saved NetWork Trash dirID
|
|||
|
savedTrashMapRefNum ds.w 1 ; room for the saved NetWork TrashMapUsage ref num
|
|||
|
endStackFrame
|
|||
|
|
|||
|
assert ioFCBQElSize <= ioHVQElSize ; make sure both fit in diskPB
|
|||
|
assert ioHQElSize <= ioHFQElSiz ; make sure both fit in folderPB
|
|||
|
|
|||
|
systemVRefNum equ d3 ; register for system disk vRefNum
|
|||
|
cookedVRefNum equ d4 ; register for vRefNum
|
|||
|
dirID equ d5 ; register for dirID
|
|||
|
resourceFileRefNum equ d6 ; register for resource file refNum
|
|||
|
diskAttributes equ d7 ; register for disk attributes
|
|||
|
folderType equ a2 ; register for folder specialty
|
|||
|
namesResource equ systemVRefNum ; register for resource containing names
|
|||
|
|
|||
|
linkSave d2-d7/a2
|
|||
|
|
|||
|
moveq #kFileNotOpen,resourceFileRefNum ; no resource file open yet
|
|||
|
move.l which(a6),folderType ; get the folder specialty we must find
|
|||
|
rsrv.w ; room for returned refNum
|
|||
|
_CurResFile ; get the current ResFile refNum
|
|||
|
pop.w savedResFile(a6) ; save it for restoring later on
|
|||
|
push.w #0 ; System file refNum
|
|||
|
_UseResFile ; Make System file current
|
|||
|
|
|||
|
lea diskPB(a6),a0 ; point to the parameter block
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Here we get information about the vRefNum passed to us. We also get the vRefNum of the system
|
|||
|
; disk, since we need it know to handle the kOnSystemDisk case, and will need it later in most
|
|||
|
; cases. Also note that the calls we make, GetFCBInfo and HGetVInfo, should be fairly quick, since
|
|||
|
; they simply look for the FCB and VCB respectively.
|
|||
|
|
|||
|
GetSystemFileInfo
|
|||
|
clr.l ioFileName(a0) ; not interested in file name
|
|||
|
move.w SysMap,ioRefNum(a0) ; the system file<6C>s refNum
|
|||
|
clr.w ioFCBIndx(a0) ; get file by refNum
|
|||
|
moveq #fsRtDirID,d0 ; initialize in case of an MFS disk
|
|||
|
move.l d0,ioFCBParID(a0) ; (MFS FCBs do not have parIDs in them)
|
|||
|
_GetFCBInfo ; get the FCB
|
|||
|
bnz GotError ; it is an error
|
|||
|
move.w ioFCBVRefNum(a0),systemVRefNum ; get the system vRefNum
|
|||
|
|
|||
|
GetDiskInfo
|
|||
|
move.w vRefNum(a6),d0 ; put vRefNum in parameter block
|
|||
|
cmp.w #kOnSystemDisk,d0 ; this means the system folder
|
|||
|
bne.s @notSystemDisk ; if they pass us this, it<69>s the system disk
|
|||
|
move.w systemVRefNum,d0 ; get the system disk vRefNum
|
|||
|
@notSystemDisk
|
|||
|
|
|||
|
move.w d0,ioVRefNum(a0) ; put the vRefNum in the parameter block
|
|||
|
assert ioVolIndex = ioFCBIndx ; get the information by vRefNum (set up above)
|
|||
|
clr.l ioVFndrInfo(a0) ; initialize in case of an MFS disk
|
|||
|
; If we don't init dirID field, it causes an HFS bug related to changing working
|
|||
|
; directory number on us.
|
|||
|
clr.l ioDirID(a0) ; work-around HFS bug
|
|||
|
_HGetVInfo ; get the real vRefNum
|
|||
|
bnz GotError ; it is an error?
|
|||
|
move.w ioVRefNum(a0),cookedVRefNum ; get the vRefNum
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Search the cache to see if this folder specialty has been entered into the cache for this disk.
|
|||
|
; If we find a dirID here, go directly to the end of the routine.
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
rsrv.l ; make room for the return value
|
|||
|
push.l a0 ; pass the disk information
|
|||
|
push.l folderType ; pass which folder we want
|
|||
|
jsr FindFolderInCache ; found the folder in the cache
|
|||
|
lea diskPB(a6),a0 ; restore the parameter block
|
|||
|
pop.l d0 ; did we get a dirID?
|
|||
|
bz.s @notInCache ; no, it<69>s not in the cache
|
|||
|
; If we got a cache error and if the createFolder bit is set, ignore the cache and try to create the
|
|||
|
; folder.
|
|||
|
cmp.l #kCachedErrorBase,d0 ; is the folder an error?
|
|||
|
blo.s @notCachedError
|
|||
|
tst.b createFolder(a6) ; are we supposed to create the folder?
|
|||
|
bnz.s @notInCache ; if yes, ignore the cache and create the folder
|
|||
|
@notCachedError
|
|||
|
move.l d0,dirID ; return that dirID
|
|||
|
bra GotFolderFromCache ; we got the cache item
|
|||
|
@notInCache
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Since we didn<64>t find the folder in the cache, we need the list of disk attributes.
|
|||
|
; This is used when finding the system folder, creating new folders, and determining whether
|
|||
|
; there should be a desktop folder.
|
|||
|
|
|||
|
lea diskPBVolParms(a6),a0 ; point buffer for GetVolParms call
|
|||
|
clr.l ioFileName(a0) ; give vRefNum instead of fileName
|
|||
|
move.w cookedVRefNum,ioVRefNum(a0) ; for this disk
|
|||
|
lea diskVolParms(a6),a1 ; point buffer at parameters
|
|||
|
move.l a1,ioBuffer(a0) ; read the parameters in here
|
|||
|
moveq #vMAttrib+4,d0 ; read just enough to get the attributes
|
|||
|
move.l d0,ioReqCount(a0) ; read in the attributes
|
|||
|
_GetVolParms ; get the disk parameters
|
|||
|
bz.s @success
|
|||
|
cmp.w #paramErr,d0 ; was the error just a lack of GetVolParms?
|
|||
|
bne GotError
|
|||
|
moveq #0,diskAttributes ; all attributes are zero by default
|
|||
|
bra.s @gotParms
|
|||
|
@success
|
|||
|
move.l diskVolParms+vMAttrib(a6),diskAttributes ; got all the attributes
|
|||
|
@gotParms
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Now, we check for the special folders that are not inside the system folder.
|
|||
|
;
|
|||
|
|
|||
|
cmp.l #kDesktopFolderType,folderType ; is it the desktop folder?
|
|||
|
beq DesktopFolder ; yes, the desktop folder
|
|||
|
cmp.l #kWhereToEmptyTrashFolderType,folderType ; is it the other trash folder?
|
|||
|
beq TrashFolder ; yes, the trash folder
|
|||
|
cmp.l #kTrashFolderType,folderType ; is it the trash folder?
|
|||
|
beq TrashFolder ; yes, the trash folder
|
|||
|
cmp.l #kTemporaryFolderType,folderType; is it the temporary folder?
|
|||
|
beq TemporaryFolder ; yes, the temporary folder
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We still have to get the System Folder dirID.
|
|||
|
|
|||
|
btst.l #bNoSysDir,diskAttributes ; is the system folder supported on this disk
|
|||
|
bnz.s NotFoundError ; no system folder? no others either
|
|||
|
move.l diskPB+ioVFndrInfo(a6),dirID ; get the system folder on this disk
|
|||
|
bnz.s FoundSystemFolder ; no system folder? no others either
|
|||
|
|
|||
|
NotFoundError
|
|||
|
moveq #fnfErr,d0 ; folder not found
|
|||
|
bra GotErrorForCache ; go report that error
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We have found the dirID of the system folder. If that is the folder we were looking for, then
|
|||
|
; we can return immediately.
|
|||
|
|
|||
|
FoundSystemFolder
|
|||
|
cmp.l #kSystemFolderType,folderType ; is it the system folder?
|
|||
|
beq GotFolderForCache ; return with the system dirID
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We now have identified the disk and the system folder that we wish to find a folder specialty
|
|||
|
; on/in. We will now open the system file on that disk and extract the folder name list resource
|
|||
|
; from it. Note that the name of the system file (in low memory) is the same across international
|
|||
|
; and script boundaries. If we are looking on the current System disk, we do not open the
|
|||
|
; System file. We have already made it the current one for getting resources.
|
|||
|
; namesResource and systemVRefNum are same registers. Do not optimize following test.
|
|||
|
|
|||
|
tst.l resHandle(a6) ; Was 'fld#' resource already loaded?
|
|||
|
bz.s @GetResourceFromSystem ; no, get it from the System file
|
|||
|
move.l resHandle(a6),namesResource ; set up resource handle correctly
|
|||
|
bra.s GotResHandle ; we have the handle to the loaded resource
|
|||
|
|
|||
|
@GetResourceFromSystem
|
|||
|
push.b #true ; always load 'fld#' resource in memory
|
|||
|
_SetResLoad
|
|||
|
|
|||
|
cmp.w cookedVRefNum,systemVRefNum ; is it the system disk?
|
|||
|
beq.s GetFolderList ; It is already open and current
|
|||
|
|
|||
|
push.b #false ; don<6F>t load any resources from the system file
|
|||
|
_SetResLoad ; while opening it
|
|||
|
|
|||
|
rsrv.w ; make room for result refNum
|
|||
|
push.w cookedVRefNum ; disk
|
|||
|
push.l dirID ; folder
|
|||
|
pea SysResName ; system file name from low memory
|
|||
|
push.b #fsRdPerm ; read-only
|
|||
|
if FOR_INSTALLER then
|
|||
|
jsr HOPENRESFILE ; open the system, installer does not have trap
|
|||
|
else
|
|||
|
_HOpenResFile ; open the system
|
|||
|
endif
|
|||
|
pop.w resourceFileRefNum ; get system file refNum
|
|||
|
|
|||
|
rsrv.w ; make room for error
|
|||
|
_ResError ; get error
|
|||
|
|
|||
|
push.b #true ; restore resource loading
|
|||
|
_SetResLoad
|
|||
|
|
|||
|
pop.w d0 ; pop that error from the resource manager
|
|||
|
bnz GotErrorForCache
|
|||
|
|
|||
|
GetFolderList
|
|||
|
rsrv.l ; room for resource handle
|
|||
|
push.l #kFolderNameListType ; get folder list resource
|
|||
|
push.w #kFolderNameListID
|
|||
|
_Get1Resource ; get resource from other file
|
|||
|
pop.l namesResource ; get handle to resource
|
|||
|
bz GotResourceErrorForCache
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Now that we have the resource, we can search the resource for the folder specialty we desire.
|
|||
|
; We keep searching until we reach the end of the resource.
|
|||
|
|
|||
|
GotResHandle
|
|||
|
move.l namesResource,a0 ; get the size of this handle
|
|||
|
_GetHandleSize
|
|||
|
move.l (a0),a0 ; dereference the handle
|
|||
|
lea -FolderName.data(a0,d0.l),a1 ; point to last possible entry
|
|||
|
|
|||
|
@next
|
|||
|
cmp.l a1,a0 ; are we at the end of the resource?
|
|||
|
bhi.s NotFoundError ; yes, return an error
|
|||
|
|
|||
|
moveq #0,d1 ; get the size of this element
|
|||
|
move.w FolderName.length(a0),d1 ; in a long word
|
|||
|
|
|||
|
cmp.l FolderName.type(a0),folderType ; is this the right kind of folder?
|
|||
|
beq.s FolderNameInResource
|
|||
|
|
|||
|
addq.l #1,d1 ; round size up to an even number
|
|||
|
bclr #0,d1
|
|||
|
|
|||
|
lea FolderName.data(a0,d1.l),a0 ; advance to next folder name
|
|||
|
bra.s @next
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We found a folder name in the folder name list resource. Make sure that it is a version 0
|
|||
|
; name (a sub-folder of the system folder): we haven<65>t defined any others yet, but folder
|
|||
|
; name lists might be from a newer system that has new ones. Once we are sure it is a
|
|||
|
; version 0 name, get the pascal string name of the sub-folder, and go on. If we notice that
|
|||
|
; the fld# resouce is damaged, we return a <20>not found<6E> error
|
|||
|
|
|||
|
FolderNameInResource
|
|||
|
sub.l d1,a1 ; subtract the size of the data
|
|||
|
cmp.l a1,a0 ; check if the data fits
|
|||
|
bhi NotFoundError ; no, we are done
|
|||
|
|
|||
|
cmp.w #kFolderByNameVersion,FolderName.version(a0) ; this version?
|
|||
|
bne NotFoundError ; no, must be unknown version
|
|||
|
|
|||
|
cmp.w #kStringMaxLength,d1 ; is the data short enough?
|
|||
|
bhi NotFoundError ; too long, get out of here
|
|||
|
|
|||
|
lea FolderName.length+1(a0),a1 ; point at the string
|
|||
|
bra FolderNameInA1
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Here is where the <20>root<6F> folders rejoin the main code path. The main difference of these
|
|||
|
; folders is that they start in the root, and have names that do not come from resources.
|
|||
|
|
|||
|
; These are folders like Trash, Desktop and Temporary. Trash folders on shared volumes are
|
|||
|
; handled very differently. **** Describe the complete algorithm here!!
|
|||
|
;
|
|||
|
; **PWD** Somewhere here we have to decide whether this volume is shared and, if so, whether
|
|||
|
; to create a new trash folder (we wouldn't be here if a trash folder had been created already):
|
|||
|
;
|
|||
|
|
|||
|
TrashFolder
|
|||
|
lea TrashFolderName,a1 ; trash folder name
|
|||
|
btst.l #bAccessCntl,diskAttributes ; does this disk support privileges?
|
|||
|
bz FolderInRoot ; otherwise, nothing special about this trash
|
|||
|
; following test differentiates a server from the client
|
|||
|
btst.l #bExtFSVol,diskAttributes ; Is this disk external file system?
|
|||
|
bz FolderInRoot ; otherwise, nothing special about trash
|
|||
|
cmp.l #kWhereToEmptyTrashFolderType,folderType ; is it the other trash folder?
|
|||
|
bne.s @GetClientTrash ; no, get the client trash folder within NetTrash
|
|||
|
; load upper level NetTrash folder name and handle it like any other special folder if not creating it
|
|||
|
lea NetTrashFolderName,a1 ; NetTrash folder name
|
|||
|
tst.b createFolder(a6) ; are we supposed to create Network Trash folder?
|
|||
|
bz FolderInRoot ; if not, treat it just like any other folder
|
|||
|
move.w cookedVRefNum,d0 ; set correct vRefNum for getting NetTrashID
|
|||
|
jsr GetNetTrashID ; upper level NetTrash folder ID
|
|||
|
bne GotErrorForCache ; if not, go enter it into the cache
|
|||
|
move.l d1,dirID ; got the Network Trash Folder dirID
|
|||
|
bra GotFolderForCache ;
|
|||
|
|
|||
|
; Find the NetWork Trash in special cache. If not there, may be the upper level trash as well as
|
|||
|
; the other trash can within it and the trash usage map file need to be created.
|
|||
|
@GetClientTrash
|
|||
|
with SpecialCacheEntry
|
|||
|
rsrv.l ; make room for ptr to cache entry
|
|||
|
push.w cookedVRefNum ; pass vRefNum
|
|||
|
jsr FindSpecialCacheEntry ; search the special cache
|
|||
|
pop.l d0 ; check search result
|
|||
|
beq.s @trashNotInSpecialCache ; if search fails, try creating a new trash folder
|
|||
|
movea.l d0, a0 ; point to cache entry for this volume
|
|||
|
move.l scTrashDirID(a0), dirID ; pick up the trash folder dirID
|
|||
|
bra GotFolderForCache ; got the Trash dirID
|
|||
|
endwith
|
|||
|
|
|||
|
@trashNotInSpecialCache
|
|||
|
move.w #fnfErr,d0 ; assume createFolder bit is not set
|
|||
|
tst.b createFolder(a6) ; are we supposed to create the folder?
|
|||
|
bz GotErrorForCache ; if not, go enter it into the cache
|
|||
|
|
|||
|
move.w cookedVRefNum,d0 ; set correct vRefNum for getting NetTrashID
|
|||
|
jsr GetNetTrashID ; upper level NetTrash folder ID
|
|||
|
bne GotErrorForCache ; if not, go enter it into the cache
|
|||
|
move.l d1,savedNetTrashID(a6) ; save it for a while
|
|||
|
pea diskPB(a6) ; pass the disk information
|
|||
|
push.l #kWhereToEmptyTrashFolderType ; pass the type
|
|||
|
push.l d1 ; pass the dirID
|
|||
|
jsr EnterFolderInCache ; call the cache to enter it in
|
|||
|
|
|||
|
move.w cookedVRefNum,d0 ; set correct vRefNum for getting TrashUsageMap refNum
|
|||
|
move.l savedNetTrashID(a6),d1 ; pass Network Trash Folder dirID
|
|||
|
jsr GetTrashMapRefnum ; Trash Map usage refNum
|
|||
|
bne GotErrorForCache ; if not, go enter it into the cache
|
|||
|
move.w d1,savedTrashMapRefNum(a6) ; save it for a while
|
|||
|
|
|||
|
move.w cookedVRefNum,d0 ; set correct vRefNum for getting Trash Can ID
|
|||
|
move.l savedNetTrashID(a6),d1 ; pass Network Trash Folder dirID
|
|||
|
move.w savedTrashMapRefNum(a6),d2 ; pass TrashMapUsage refNum to GetTrashCanID call
|
|||
|
jsr GetTrashCanID ; real Trash can ID
|
|||
|
bne.s @TrashCanError ; if not, go enter it into the cache
|
|||
|
move.l d1,dirID ; also, remember it for purgeable cache
|
|||
|
|
|||
|
push.w cookedVRefNum ; pass the vRefNum
|
|||
|
push.w savedTrashMapRefNum(a6) ; pass NetWork Trash map file refNum
|
|||
|
push.l dirID ; this is the real Trash can dirID
|
|||
|
jsr AddSpecialCacheEntry ; remember it in non-purgeable cache
|
|||
|
|
|||
|
bra GotFolderForCache ; we have created the trash can
|
|||
|
|
|||
|
@TrashCanError
|
|||
|
move.w d0,d2 ; save the TrashCan creation error for a while
|
|||
|
lea folderPB(a6),a0 ; get ready for calls
|
|||
|
move.w savedTrashMapRefNum(a6), ioRefNum(a0); Set up trash map file refnum
|
|||
|
_Close ; close Trash Map file
|
|||
|
move.w d2,d0 ; TrashCan creation error
|
|||
|
bra.s GotErrorForCache ; if not, go enter it into the cache
|
|||
|
|
|||
|
DesktopFolder
|
|||
|
btst.l #bNoDeskItems,diskAttributes ; no desktop?
|
|||
|
bnz NotFoundError ; if not, return an error
|
|||
|
lea DesktopFolderName,a1 ; desktop folder name
|
|||
|
bra.s FolderInRoot
|
|||
|
TemporaryFolder
|
|||
|
lea TemporaryFolderName,a1 ; temporary folder name
|
|||
|
|
|||
|
FolderInRoot
|
|||
|
moveq #fsRtDirID,dirID ; look for these in the root
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Now we have the name of the folder in a1 and its parent folder<65>s dirID in <20>dirID<49>.
|
|||
|
; Find the folder by that name. If it is a file instead of a folder, we fail with a
|
|||
|
; <20>duplicate file name<6D> error.
|
|||
|
|
|||
|
FolderNameInA1
|
|||
|
lea folderPB(a6),a0 ; get ready for calls
|
|||
|
|
|||
|
move.l a1,ioFileName(a0) ; look for this name
|
|||
|
move.w cookedVRefNum,ioVRefNum(a0) ; on this disk
|
|||
|
clr.w ioFDirIndex(a0) ; by vRefNum and dirID
|
|||
|
move.l dirID,ioDrDirID(a0) ; in this folder
|
|||
|
_GetCatInfo
|
|||
|
cmp.w #fnfErr,d0 ; is there a folder by that name?
|
|||
|
beq.s NewFolderNeeded
|
|||
|
tst.w d0 ; another error?
|
|||
|
bnz.s GotErrorForCache
|
|||
|
|
|||
|
move.l ioDrDirID(a0),dirID ; got the dirID!
|
|||
|
btst.b #ioDirFlg,ioFlAttrib(a0) ; check if it is a folder
|
|||
|
bnz.s FoundFolder ; it is!
|
|||
|
|
|||
|
moveq #dupFNErr,d0 ; if there is a file instead of a folder
|
|||
|
bra.s GotErrorForCache
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Here is where we come when we find an error that should be cached. If this is a
|
|||
|
; caching version of the folder manager, we convert it info a dirID and fall into the folder
|
|||
|
; caching case. If we are not caching we just return the error.
|
|||
|
|
|||
|
GotResourceErrorForCache
|
|||
|
rsrv.w ; make room for error
|
|||
|
_ResError ; get error
|
|||
|
pop.w d0 ; from resource manager
|
|||
|
bnz.s GotErrorForCache
|
|||
|
move.w #resNotFound,d0 ; resource not found error
|
|||
|
|
|||
|
GotErrorForCache
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
moveq #(kCachedErrorBase or $FFFF),dirID ; build a dirID from the error
|
|||
|
move.w d0,dirID ; put the error in the low word
|
|||
|
bra.s GotFolderForCache
|
|||
|
|
|||
|
else
|
|||
|
|
|||
|
bra.s GotError ; just a normal error
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We come here if we find that there is no folder by the right name. We now have to create the
|
|||
|
; new folder and set its attributes appropriately. *** It may be inappropriate to set the
|
|||
|
; attributes for a new folder, and not do the same for folders that we find for the first time. ***
|
|||
|
|
|||
|
NewFolderNeeded
|
|||
|
tst.b createFolder(a6) ; are we supposed to create the folder?
|
|||
|
bz.s GotErrorForCache ; if not, go enter it into the cache
|
|||
|
|
|||
|
move.l dirID,ioDrDirID(a0) ; in this folder
|
|||
|
_DirCreate ; create the folder
|
|||
|
bnz.s GotErrorForCache ; get out if we couldn<64>t create it
|
|||
|
|
|||
|
move.l ioDrDirID(a0),d2 ; save away the dirID for a bit
|
|||
|
|
|||
|
clr.l ioFileName(a0) ; get info on the folder
|
|||
|
move.w #-1,ioFDirIndex(a0) ; look up by dirID
|
|||
|
_GetCatInfo ; get info about that folder
|
|||
|
bnz.s GotErrorForCache ; get out if there was a problem
|
|||
|
|
|||
|
; Note that although the above GetCatInfo is done by dirID, the rest of these
|
|||
|
; operations are done by name and parent dirID, because that<61>s the only way
|
|||
|
; HFS lets us do them.
|
|||
|
|
|||
|
move.l a1,ioFileName(a0) ; set info by name
|
|||
|
ori.w #mFNameLock,ioDrUsrWds+frFlags(a0) ; make it rename-inhibit
|
|||
|
move.l dirID,ioDrDirID(a0) ; in this folder
|
|||
|
|
|||
|
_SetCatInfo ; change those bits a bit
|
|||
|
bnz.s GotErrorForCache ; couldn<64>t do it
|
|||
|
|
|||
|
move.l d2,dirID ; now we<77>ve got the dirID
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Now we have the folder we are looking for. Either we created it, or it was already on the disk.
|
|||
|
; Set Desktop Folder/Trash attributes appropriately whether it was created for first time or we found it.
|
|||
|
; This is for reasons like Personal Appleshare sharing the folder and hence its attributes need to be set.
|
|||
|
|
|||
|
FoundFolder
|
|||
|
;--------------------------------------------------
|
|||
|
;
|
|||
|
; Does Desktop Folder/Trash now need to be locked?
|
|||
|
; This could happen if the disk is now allowing sharing and hence the locking need to be set correctly.
|
|||
|
; Set the folder locking for Desktop Folder/Trash only. For example, after FileShare is
|
|||
|
; running, we may need to set the lock so that the desktop folder cannot be moved,
|
|||
|
; renamed or deleted by other Super user remotely.
|
|||
|
|
|||
|
cmp.l #kWhereToEmptyTrashFolderType,folderType ; is it the other trash folder?
|
|||
|
beq.s @DoLocking ; yes, the root level trash folder
|
|||
|
cmp.l #kTrashFolderType,folderType ; is it the trash folder?
|
|||
|
beq.s @DoLocking ; all trash folders get locked if locking supported
|
|||
|
cmp.l #kDesktopFolderType,folderType ; is it the desktop folder?
|
|||
|
bne.s @done ; see if its lock needs to be set
|
|||
|
@DoLocking
|
|||
|
btst.l #bHasFolderLock,diskAttributes ; does this disk support locking folders?
|
|||
|
bz.s @done ; no, don<6F>t bother trying
|
|||
|
btst.b #ioLockFlg,ioFlAttrib(a0) ; check if it is already locked
|
|||
|
bnz.s @done ; it is!
|
|||
|
clr.l ioFileName(a0) ; no name, lock it by dirID
|
|||
|
move.l dirID,ioDrDirID(a0) ; lock the folder
|
|||
|
_HSetFLock ; lock it right here
|
|||
|
; ignore error
|
|||
|
@done
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We<57>ve got the dirID for the folder. Enter it into the folder cache.
|
|||
|
|
|||
|
GotFolderForCache
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
pea diskPB(a6) ; pass the disk information
|
|||
|
push.l folderType ; pass the type
|
|||
|
push.l dirID ; pass the dirID
|
|||
|
jsr EnterFolderInCache ; call the cache to enter it in
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We get here just after entering a folder into the cache, or just after getting a folder
|
|||
|
; from the cache. In both cases, the dirID could be either a real dirID, or a cached error
|
|||
|
; which is stored as a dirID greater than kCachedErrorBase.
|
|||
|
;
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
GotFolderFromCache
|
|||
|
cmp.l #kCachedErrorBase,dirID ; is the folder an error?
|
|||
|
blo.s @notError
|
|||
|
move.w dirID,d0 ; get the error code
|
|||
|
bra.s GotError
|
|||
|
@notError
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We found the folder, return to the caller.
|
|||
|
|
|||
|
GotFolder
|
|||
|
move.l pFoundVRefNum(a6),a0 ; return the vRefNum
|
|||
|
move.w cookedVRefNum,(a0) ; save the vRefNum
|
|||
|
move.l pFoundDirID(a6),a0 ; return the dirID
|
|||
|
move.l dirID,(a0) ; save the dirID
|
|||
|
moveq #noErr,d0 ; no error
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We are finished, and have the error code in d0. Close the other system<65>s resource file.
|
|||
|
|
|||
|
GotError
|
|||
|
move.w d0,error(a6) ; return result
|
|||
|
|
|||
|
cmp.w #kFileNotOpen,resourceFileRefNum ; is an alternate system file open?
|
|||
|
beq.s @done
|
|||
|
push.w resourceFileRefNum ; get that system file refNum
|
|||
|
_CloseResFile
|
|||
|
|
|||
|
rsrv.w ; make room for error
|
|||
|
_ResError ; get error
|
|||
|
pop.w d0 ; from resource manager
|
|||
|
bz.s @done
|
|||
|
|
|||
|
tst.w error(a6) ; is there an error yet
|
|||
|
bnz.s @done
|
|||
|
move.w d0,error(a6) ; no, use the CloseResFile error
|
|||
|
@done
|
|||
|
|
|||
|
push.w savedResFile(a6) ; restore saved ResFile refNum
|
|||
|
_UseResFile
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; Code to implement the cache starts here:
|
|||
|
|
|||
|
if CACHING then
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
FolderCacheFolder record 0
|
|||
|
type ds.l 1 ; the folderType that this is a cache for
|
|||
|
dirID ds.l 1 ; the dirID that is stored here
|
|||
|
endrsize
|
|||
|
|
|||
|
FolderCacheDisk record 0
|
|||
|
vRefNum ds.w 1 ; the vRefNum of the disk
|
|||
|
creationDate ds.l 1 ; creation date of the disk
|
|||
|
attributes ds.w 1 ; saved attributes of the disk
|
|||
|
modificationDate ds.l 1 ; last modification date of the disk
|
|||
|
numFoldersMinusOne ds.w 1 ; number of folders cached - 1
|
|||
|
firstFolder ds.b FolderCacheFolder ; folders to cache start here
|
|||
|
sizeWithOneFolder equ * ; size if we have exactly one folder cached
|
|||
|
endr
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; PROCEDURE EnterFolderInCache(diskPB: HParmBlkPtr; folderType: OSType; dirID: LONGINT);
|
|||
|
;
|
|||
|
; Add an entry to the folder cache, a handle kept in the system heap (purgeable).
|
|||
|
;
|
|||
|
; The folder cache keeps entries for each disk, and pairs of OSType and dirID for each
|
|||
|
; folder specialty on each disk. The cache is kept as long as the modification date and attributes
|
|||
|
; of a disk remain the same. Note that this means that cache entries are often thrown away.
|
|||
|
|
|||
|
EnterFolderInCache proc export
|
|||
|
import FindEntryInCache
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
import FolderMgrGlobalPtr
|
|||
|
endif
|
|||
|
|
|||
|
parametersStackFrame
|
|||
|
pDiskPB ds.l 1 ; result of HGetVolInfo on the disk
|
|||
|
which ds.l 1 ; which folder specialty we are interested in
|
|||
|
dirID ds.l 1 ; the dirID we want to cache
|
|||
|
localsStackFrame
|
|||
|
diskEntry ds.l 1 ; disk entry found by FindEntryInCache
|
|||
|
stage ds.b FolderCacheDisk ; staging area for new disk
|
|||
|
endStackFrame
|
|||
|
|
|||
|
cacheHandle equ a3 ; store the cacheHandle here
|
|||
|
|
|||
|
linkSave a3
|
|||
|
|
|||
|
if DEBUG then
|
|||
|
tst.l dirID(a6) ; can<61>t enter a 0 into the cache
|
|||
|
bnz.s @ok
|
|||
|
_Debugger
|
|||
|
@ok
|
|||
|
endif
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Reconstitute the cache handle if it was purged.
|
|||
|
|
|||
|
with FolderMgrGlobalRec
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
move.l FolderMgrGlobalPtr,d0
|
|||
|
else
|
|||
|
move.l ExpandMem,a0
|
|||
|
move.l ExpandMemRec.emFolderCache(a0),d0 ; get cache handle
|
|||
|
endif
|
|||
|
bz Done ; no globals, we're doomed
|
|||
|
movea.l d0, a0 ; set up ptr to our globals
|
|||
|
move.l normalCacheHndl(a0), d0 ; pick up cache handle
|
|||
|
bz Done ; no cache, we are done
|
|||
|
endwith
|
|||
|
move.l d0,cacheHandle ; save cacheHandle for later use
|
|||
|
tst.l (cacheHandle) ; is the cache handle empty?
|
|||
|
bnz.s @findEntry ; no, look for existing contents
|
|||
|
|
|||
|
move.l cacheHandle,a0 ; copy in a0 for the calls
|
|||
|
moveq #0,d0 ; reallocate handle (no contents)
|
|||
|
_ReallocHandle sys
|
|||
|
bnz Done ; can<61>t reallocate, get out
|
|||
|
_HPurge ; keep it purgeable
|
|||
|
bra.s NewDiskAndFolder ; we reallocated the handle
|
|||
|
|
|||
|
@findEntry
|
|||
|
rsrv.l ; make room for result
|
|||
|
push.l pDiskPB(a6) ; search on this disk
|
|||
|
push.l which(a6) ; for this type
|
|||
|
pea diskEntry(a6) ; and remember where the disk is
|
|||
|
jsr FindEntryInCache ; find the entry for this folder
|
|||
|
pop.l d0 ; get pointer to entry
|
|||
|
bnz.s FoundEntry
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We get here if there is no existing entry in the cache for this folder specialty and disk.
|
|||
|
; Inserting a new entry is different if the disk has other entries already.
|
|||
|
|
|||
|
CreateNewEntry
|
|||
|
move.l diskEntry(a6),d0 ; get entry for the disk
|
|||
|
bnz.s NewFolderOnly
|
|||
|
|
|||
|
NewDiskAndFolder
|
|||
|
; in this case, we insert a new disk and a new folder (at the beginning of the handle)
|
|||
|
|
|||
|
move.l pDiskPB(a6),a1 ; get parameter block pointer
|
|||
|
move.l ioVRefNum(a1),stage.vRefNum(a6) ; put in the vRefNum
|
|||
|
move.l ioVCrDate(a1),stage.creationDate(a6) ; put in the creation date
|
|||
|
move.w ioVAtrb(a1),stage.attributes(a6) ; put in the attributes
|
|||
|
move.l ioVLsMod(a1),stage.modificationDate(a6) ; put in the modification date
|
|||
|
move.w #1-1,stage.numFoldersMinusOne(a6) ; initialize number of folders
|
|||
|
|
|||
|
lea stage(a6),a1 ; set up for both disk and folder
|
|||
|
moveq #FolderCacheDisk.sizeWithOneFolder,d1 ; get size
|
|||
|
moveq #0,d2 ; don<6F>t replace anything
|
|||
|
bra.s FillInFolder
|
|||
|
|
|||
|
NewFolderOnly
|
|||
|
; in this case, we insert a new folder count and a new folder over the old folder count
|
|||
|
|
|||
|
moveq #FolderCacheDisk.numFoldersMinusOne,d1 ; advance to proper place to insert a folder
|
|||
|
add.l d1,d0
|
|||
|
|
|||
|
move.l d0,a1 ; get pointer to old entry
|
|||
|
move.w (a1),d1 ; get old number of folders
|
|||
|
addq.w #1,d1 ; we are about to add a folder
|
|||
|
move.w d1,stage.numFoldersMinusOne(a6) ; the new, incremented, number of folders
|
|||
|
|
|||
|
sub.l (cacheHandle),d0 ; convert disk entry address to an offset
|
|||
|
|
|||
|
lea stage.numFoldersMinusOne(a6),a1 ; set up for folder only
|
|||
|
assert FolderCacheDisk.numFoldersMinusOne + 2 = FolderCacheDisk.firstFolder
|
|||
|
moveq #2 + FolderCacheFolder.size,d1 ; get size
|
|||
|
moveq #2,d2 ; get size we are replacing
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Now we have the place to insert the new entry, size to be replaced, new entry composed on the
|
|||
|
; stack frame, pointer to the new entry, and size of the new entry. All that<61>s left it to munge
|
|||
|
; it in.
|
|||
|
|
|||
|
FillInFolder
|
|||
|
move.l which(a6),stage.firstFolder.type(a6) ; put in the folderType
|
|||
|
move.l dirID(a6),stage.firstFolder.dirID(a6) ; put in the dirID
|
|||
|
|
|||
|
rsrv.l ; room for the result
|
|||
|
push.l cacheHandle ; munge this handle
|
|||
|
push.l d0 ; munge it in here
|
|||
|
push.l #nil ; don<6F>t search, just insert
|
|||
|
push.l d2 ; number of bytes to replace
|
|||
|
push.l a1 ; here<72>s what you should insert
|
|||
|
push.l d1 ; here<72>s the length of what you should insert
|
|||
|
_Munger
|
|||
|
free.l ; ignore the result
|
|||
|
|
|||
|
bra.s Done ; it<69>s in, now we<77>re done
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; If we find an entry, we simply change its dirID in place. This could happen if a cached error
|
|||
|
; was found and the createFolder is set. In this case, the cached entry is updated to have the
|
|||
|
; real diID which was just created.
|
|||
|
|
|||
|
FoundEntry
|
|||
|
move.l d0,a0 ; fill in this entry
|
|||
|
move.l dirID(a6),FolderCacheFolder.dirID(a0)
|
|||
|
|
|||
|
Done
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION FindFolderInCache(diskPB: HParmBlkPtr; folderType: OSType): LONGINT;
|
|||
|
;
|
|||
|
; Find an entry in the folder cache for a folder specialty on a particular disk.
|
|||
|
; Return the entry, or if there is no entry, return 0.
|
|||
|
|
|||
|
FindFolderInCache proc export
|
|||
|
import FindEntryInCache
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
import FolderMgrGlobalPtr
|
|||
|
endif
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
dirID ds.l 1 ; the dirID we found in the cache
|
|||
|
parametersStackFrame
|
|||
|
pDiskPB ds.l 1 ; result of HGetVolInfo on the disk
|
|||
|
which ds.l 1 ; which folder specialty we are interested in
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave
|
|||
|
|
|||
|
rsrv.l ; make room for result
|
|||
|
push.l pDiskPB(a6) ; search on this disk
|
|||
|
push.l which(a6) ; for this type
|
|||
|
push.l #nil ; no disk result desired
|
|||
|
jsr FindEntryInCache ; find the entry for this folder
|
|||
|
pop.l d0 ; get pointer to entry
|
|||
|
bz.s Done ; zero means no entry
|
|||
|
|
|||
|
move.l d0,a0 ; get dirID from this entry
|
|||
|
move.l FolderCacheFolder.dirID(a0),d0
|
|||
|
|
|||
|
Done
|
|||
|
move.l d0,dirID(a6) ; dirID from cache
|
|||
|
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION FindEntryInCache(diskPB: HParmBlkPtr; folderType: OSType;
|
|||
|
; VAR disk: FolderCacheDiskPtr): FolderCacheFolderPtr;
|
|||
|
;
|
|||
|
; Find a cache entry for a folder. Regardless of whether the folder is found, return the
|
|||
|
; cache entry for the whole disk too.
|
|||
|
|
|||
|
FindEntryInCache proc export
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
entry ds.l 1 ; the entry we found in the cache
|
|||
|
parametersStackFrame
|
|||
|
pDiskPB ds.l 1 ; result of HGetVolInfo on the disk
|
|||
|
which ds.l 1 ; which folder specialty we are interested in
|
|||
|
pDiskEntry ds.l 1 ; store a pointer to the disk entry here
|
|||
|
endStackFrame
|
|||
|
|
|||
|
pb equ a2 ; keep the parameter block here
|
|||
|
cacheHandle equ a3 ; store the cacheHandle here
|
|||
|
pDiskResult equ a4 ; pointer to the resulting disk
|
|||
|
|
|||
|
linkSave a2-a4
|
|||
|
|
|||
|
move.l pDiskPB(a6),pb ; keep PB handy
|
|||
|
clr.l entry(a6) ; nothing is default result
|
|||
|
move.l pDiskEntry(a6),pDiskResult ; get disk result
|
|||
|
move.l pDiskResult,d0 ; check for NIL
|
|||
|
bz.s @noDiskResult
|
|||
|
clr.l (pDiskResult) ; no disk result by default
|
|||
|
@noDiskResult
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; Get the cache from low-memory. Search it for an appropriate entry.
|
|||
|
|
|||
|
with FolderMgrGlobalRec
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
move.l FolderMgrGlobalPtr,d0
|
|||
|
else
|
|||
|
move.l ExpandMem,a0
|
|||
|
move.l ExpandMemRec.emFolderCache(a0),d0 ; get cache handle
|
|||
|
endif
|
|||
|
bz Done ; no globals, get out
|
|||
|
movea.l d0, a0 ; set up pointer to our globals
|
|||
|
move.l normalCacheHndl(a0), d0 ; pick up normal cache handle
|
|||
|
bz Done ; no handle, get out
|
|||
|
endwith
|
|||
|
move.l d0,a0 ; get handle in address register, too
|
|||
|
tst.l (a0) ; check if it is purged
|
|||
|
bz Done ; <SM2> CSS
|
|||
|
|
|||
|
move.l a0,cacheHandle ; use this later
|
|||
|
_GetHandleSize ; get the full length of the handle
|
|||
|
move.l (a0),a0 ; dereference the handle
|
|||
|
lea -FolderCacheDisk.firstFolder(a0,d0.l),a1 ; point to last possible entry
|
|||
|
|
|||
|
@next
|
|||
|
cmp.l a1,a0 ; check if we are done yet
|
|||
|
bhi.s Done ; yes, no entry for this disk
|
|||
|
|
|||
|
move.w FolderCacheDisk.numFoldersMinusOne(a0),d0 ; get the number of folders
|
|||
|
moveq #0,d1 ; calculate size of excess folders (more than 1)
|
|||
|
move.w d0,d1 ; which must be a long word
|
|||
|
assert FolderCacheFolder.size = (1 << 3)
|
|||
|
asl.l #3,d1 ; use a quick shift
|
|||
|
moveq #FolderCacheDisk.sizeWithOneFolder,d2
|
|||
|
add.l d2,d1 ; calculate total size of disk entry
|
|||
|
|
|||
|
move.w ioVRefNum(pb),d2 ; check if this is the disk
|
|||
|
cmp.w FolderCacheDisk.vRefNum(a0),d2 ; is this the right disk?
|
|||
|
beq.s FoundEntry
|
|||
|
|
|||
|
add.l d1,a0 ; advance to next disk
|
|||
|
bra.s @next
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We get here when a cache entry for a disk is found. Now we must decide if it is obsolete.
|
|||
|
; If it is obsolete for this disk, we can munge the entry for the disk out of the cache.
|
|||
|
|
|||
|
FoundEntry
|
|||
|
move.l ioVCrDate(pb),d2
|
|||
|
cmp.l FolderCacheDisk.creationDate(a0),d2
|
|||
|
bne.s EntryObsolete ; dates do not match
|
|||
|
move.w ioVAtrb(pb),d2
|
|||
|
cmp.w FolderCacheDisk.attributes(a0),d2
|
|||
|
bne.s EntryObsolete ; attributes do not match
|
|||
|
move.l ioVLsMod(pb),d2
|
|||
|
cmp.l FolderCacheDisk.modificationDate(a0),d2
|
|||
|
beq.s EntryNotObsolete ; dates do not match
|
|||
|
|
|||
|
EntryObsolete
|
|||
|
rsrv.l ; room for the result
|
|||
|
push.l cacheHandle ; munge this handle
|
|||
|
sub.l (cacheHandle),a0 ; get offset
|
|||
|
push.l a0 ; pass offset
|
|||
|
push.l #nil ; don<6F>t search, just delete
|
|||
|
push.l d1 ; length to delete
|
|||
|
assert 1 <> nil
|
|||
|
push.l #1 ; pass something non-nil so Munger will delete
|
|||
|
push.l #0 ; if second length is 0, Munger deletes
|
|||
|
_Munger
|
|||
|
free.l ; ignore the result
|
|||
|
|
|||
|
bra.s Done
|
|||
|
EntryNotObsolete
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
; We get here when a cache entry for a disk is found, and is not obsolete. We can now tell
|
|||
|
; the user where the disk was found. After that, we search for the folder specialty, and
|
|||
|
; return it if we find it.
|
|||
|
|
|||
|
move.l pDiskResult,d2 ; check for NIL
|
|||
|
bz.s @noDiskResult
|
|||
|
move.l a0,(pDiskResult) ; store disk result here
|
|||
|
@noDiskResult
|
|||
|
|
|||
|
addq.l #FolderCacheDisk.firstFolder-FolderCacheFolder.size,a0 ; where to start
|
|||
|
move.l which(a6),d1 ; folder specialty to search for
|
|||
|
@loop
|
|||
|
addq.l #FolderCacheFolder.size,a0 ; advance to next folder
|
|||
|
cmp.l FolderCacheFolder.type(a0),d1 ; is this the type?
|
|||
|
dbeq d0,@loop ; loop until it is found
|
|||
|
bne.s Done ; not found, we are done
|
|||
|
move.l a0,entry(a6) ; found, we are done
|
|||
|
|
|||
|
;--------------------------------------------------
|
|||
|
|
|||
|
Done
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
;****************************************************************************************************
|
|||
|
; What follows is special code for handling SharedTrash for AppleShare (specially Personal
|
|||
|
; AppleShare.
|
|||
|
;****************************************************************************************************
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; FUNCTION FindSpecialCacheEntry(vRefNum: Integer): CacheEntryPtr;
|
|||
|
;
|
|||
|
; Find an entry in the special folder cache for a [trash] folder on a particular disk.
|
|||
|
; Return the entry, or if there is no entry, return nil.
|
|||
|
|
|||
|
FindSpecialCacheEntry proc export
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
import FolderMgrGlobalPtr
|
|||
|
endif
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
entry ds.l 1 ; the entry we found in the cache
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; VRefNum for target volume
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave d1
|
|||
|
|
|||
|
clr.l entry(a6) ; nothing is default result
|
|||
|
|
|||
|
; Get the special cache handle from low-memory. Search it for an appropriate entry.
|
|||
|
|
|||
|
with FolderMgrGlobalRec, SpecialCacheEntry
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
move.l FolderMgrGlobalPtr,d0
|
|||
|
else
|
|||
|
move.l ExpandMem,a0
|
|||
|
move.l ExpandMemRec.emFolderCache(a0),d0 ; get cache handle
|
|||
|
endif
|
|||
|
bz.s Done ; no globals, get out
|
|||
|
movea.l d0, a0 ; set up pointer to our globals
|
|||
|
move.l specialCacheHndl(a0), d0 ; pick up special cache handle
|
|||
|
bz.s Done ; no handle, get out
|
|||
|
move.l d0,a0 ; get handle in address register, too
|
|||
|
;;; tst.l (a0) ; check if it is purged
|
|||
|
;;; bz.s Done
|
|||
|
|
|||
|
_GetHandleSize ; get the full length of the handle
|
|||
|
move.l (a0),a0 ; dereference the handle
|
|||
|
|
|||
|
CacheLoop:
|
|||
|
subi.l #SpecialCacheEntrySize, d0 ; another entry left unseen?
|
|||
|
blt.s Done ; if not, we're done
|
|||
|
move.w scVRefNum(a0), d1 ; is this entry in use?
|
|||
|
beq.s NextEntry ; if not, skip to next entry
|
|||
|
cmp.w vRefNum(a6), d1 ; is it for the target volume?
|
|||
|
bne.s NextEntry ; if not, just skip it
|
|||
|
move.l a0, entry(a6) ; otherwise, we've found a match
|
|||
|
bra.s Done
|
|||
|
NextEntry:
|
|||
|
addq.l #SpecialCacheEntrySize, a0 ; advance the pointer to the next entry
|
|||
|
bra.s CacheLoop ; ... and keep on checking
|
|||
|
|
|||
|
Done
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endwith
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE AddSpecialCacheEntry(vRefNum: Integer; mapRefNum: Integer; trashDirID: LongInt);
|
|||
|
;
|
|||
|
; Add an entry in the special folder cache for a [trash] folder on a particular disk.
|
|||
|
|
|||
|
AddSpecialCacheEntry proc export
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
import FolderMgrGlobalPtr
|
|||
|
endif
|
|||
|
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; VRefNum for target volume
|
|||
|
mapRefNum ds.w 1 ; File refnum of Trash map file
|
|||
|
trashDirID ds.l 1 ; DirID of trash folder
|
|||
|
endStackFrame
|
|||
|
|
|||
|
cacheHndl equ a1 ; Used to save a copy of the cache handle
|
|||
|
cacheSize equ d1 ; Size of cache block at start
|
|||
|
|
|||
|
linkSave a1/d2
|
|||
|
|
|||
|
; Get the special cache handle from low-memory. Search it for an empty entry.
|
|||
|
|
|||
|
with FolderMgrGlobalRec, SpecialCacheEntry
|
|||
|
if FOR_FOLDERMGR_INIT then
|
|||
|
move.l FolderMgrGlobalPtr,d0
|
|||
|
else
|
|||
|
move.l ExpandMem,a0
|
|||
|
move.l ExpandMemRec.emFolderCache(a0),d0 ; get cache handle
|
|||
|
endif
|
|||
|
bz.s Done ; no globals, get out
|
|||
|
movea.l d0, a0 ; set up pointer to our globals
|
|||
|
move.l specialCacheHndl(a0), d0 ; pick up special cache handle
|
|||
|
bz.s Done ; no handle, get out
|
|||
|
move.l d0,a0 ; get handle in address register, too
|
|||
|
move.l a0, cacheHndl ; make a copy for later use
|
|||
|
;;; tst.l (a0) ; check if it is purged
|
|||
|
;;; bz.s Done
|
|||
|
|
|||
|
_GetHandleSize ; get the full length of the handle
|
|||
|
move.l d0, cacheSize ; save original size in case block must be expanded
|
|||
|
move.l (a0),a0 ; dereference the handle
|
|||
|
|
|||
|
CacheLoop:
|
|||
|
subi.l #SpecialCacheEntrySize, d0 ; another entry left unseen?
|
|||
|
blt.s GrowCache ; if not, time to grow the cache
|
|||
|
tst.w scVRefNum(a0) ; is this entry in use?
|
|||
|
beq.s FillEntry ; if so, skip to next entry
|
|||
|
addq.l #SpecialCacheEntrySize, a0 ; advance the pointer to the next entry
|
|||
|
bra.s CacheLoop ; ... and keep on checking
|
|||
|
|
|||
|
GrowCache:
|
|||
|
movea.l cacheHndl, a0 ; recover orignal cache handle
|
|||
|
move.l cacheSize, d0 ; ... and original size
|
|||
|
addq.l #SpecialCacheEntrySize, d0 ; increase size by 1 entry
|
|||
|
_SetHandleSize ; Try to grow the handle
|
|||
|
bne.s Done ; if we get an error, punt
|
|||
|
move.l (a0), a0 ; dereference handle again
|
|||
|
add.l cacheSize, a0 ; point to new entry in handle
|
|||
|
|
|||
|
FillEntry:
|
|||
|
move.w vRefNum(a6), scVRefNum(a0) ; otherwise, occupy this empty slot
|
|||
|
move.w mapRefNum(a6), scTrashMapRefNum(a0) ; copy trash map refnum
|
|||
|
move.l trashDirID(a6), scTrashDirID(a0); ... and the trash folder DirID
|
|||
|
Done
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endwith
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
; FUNCTION ReleaseFolder(vRefNum: INTEGER; folderType: OSType): OSErr;
|
|||
|
;
|
|||
|
; This routine releases the locked byte for a given Trash folder and closes the Trash Map
|
|||
|
; file. Passed vRefNum is assumed to be cooked.
|
|||
|
;
|
|||
|
ReleaseFolder proc export
|
|||
|
|
|||
|
resultsStackFrame
|
|||
|
error ds.w 1 ; the resulting error code
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; the vRefNum of the disk we want to look at
|
|||
|
which ds.l 1 ; which folder we are interested in
|
|||
|
localsStackFrame
|
|||
|
PBRec ds.b ioHFQElSiz ; the folder parameter block
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave a1
|
|||
|
|
|||
|
moveq #0,d0 ; assume returning success
|
|||
|
cmp.l #kTrashFolderType,which(a6) ; is it the trash folder?
|
|||
|
bne.s @done ; operation valid only for net trash files
|
|||
|
|
|||
|
with SpecialCacheEntry
|
|||
|
rsrv.l ; make room for ptr to cache entry
|
|||
|
push.w vRefNum(a6) ; pass vRefNum
|
|||
|
jsr FindSpecialCacheEntry ; search the special cache
|
|||
|
pop.l d0 ; check search result
|
|||
|
beq.s @done ; if search fails, nothing to release
|
|||
|
movea.l d0, a1 ; point to cache entry for this volume
|
|||
|
clr.w scVRefNum(a1) ; mark this entry invalid
|
|||
|
|
|||
|
lea PBRec(a6), a0 ; Point to parameter block
|
|||
|
moveq #(ioHFQElSiz/2)-1,d1 ; Compute DBRA loop index
|
|||
|
@ClearPB
|
|||
|
clr.w (a0)+ ; Clear a word in the PBRec
|
|||
|
dbra d1,@ClearPB ;
|
|||
|
|
|||
|
lea PBRec(a6), a0 ; Point to parameter block
|
|||
|
move.w scTrashMapRefNum(a1), ioRefNum(a0); Set up trash map file refnum
|
|||
|
_Close ; close Trash Map file
|
|||
|
endwith
|
|||
|
|
|||
|
@done
|
|||
|
move.w d0,error(a6) ; no, use the CloseResFile error
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
;
|
|||
|
; PROCEDURE CleanOutFolder(vRefNum: Integer; dirForDelete: LongInt);
|
|||
|
;
|
|||
|
; Delete everything in a given folder, recursively if necessary
|
|||
|
|
|||
|
CleanOutFolder proc export
|
|||
|
|
|||
|
parametersStackFrame
|
|||
|
vRefNum ds.w 1 ; VRefNum for target volume
|
|||
|
dirForDelete ds.l 1 ; directory whose contents need to be deleted
|
|||
|
localsStackFrame
|
|||
|
PBRec ds.b ioHFQElSiz ; the folder parameter block
|
|||
|
fileName ds.b 32 ; file name
|
|||
|
endStackFrame
|
|||
|
|
|||
|
linkSave a1
|
|||
|
|
|||
|
lea PBRec(a6), a0 ; Point to parameter block
|
|||
|
moveq #(ioHFQElSiz/2)-1,d0 ; Compute DBRA loop index
|
|||
|
@ClearPB
|
|||
|
clr.w (a0)+ ; Clear a word in the PBRec
|
|||
|
dbra d0,@ClearPB ;
|
|||
|
|
|||
|
lea PBRec(a6), a0 ; Point to parameter block
|
|||
|
lea fileName(a6),a1 ; load file name
|
|||
|
move.l a1,ioNamePtr(a0) ; get file name from _GetCatInfo
|
|||
|
@EnumLoop
|
|||
|
move.w vRefNum(a6), ioVRefNum(a0) ; Set up target VRefNum
|
|||
|
move.l dirForDelete(a6), ioDirID(a0) ; Set up target DirID
|
|||
|
move.w #1,ioFDirIndex(a0) ; Set up enumeration index
|
|||
|
_GetCatInfo ;
|
|||
|
bne.s @Done ; Punt on error
|
|||
|
btst #ioDirFlg, ioFlAttrib(a0) ; Is it a folder?
|
|||
|
beq.s @DeleteIt ; Nope - just go for it
|
|||
|
push.w vRefNum(a6) ; Copy target VRefNum for recursive call
|
|||
|
push.l ioDirID(a0) ; Target DirID is newfound folder's ID
|
|||
|
jsr CleanOutFolder ; Delete contents of folder just found
|
|||
|
bne.s @Exit ; Punt on errors
|
|||
|
lea PBRec(a6), a0 ; Point to parameter block
|
|||
|
|
|||
|
@DeleteIt
|
|||
|
move.l dirForDelete(a6), ioDirID(a0) ; Reset to parent DirID
|
|||
|
_HDelete ; Delete the file
|
|||
|
beq.s @EnumLoop ; onwards to next entry
|
|||
|
cmp.w #fLckdErr, d0 ; If locked, unlock it and then try delete
|
|||
|
bne.s @Exit ; Punt immediately on any other error
|
|||
|
_HRstFLock ; Try to reset the lock
|
|||
|
_HDelete ; Try deleting the file again after unlocking it
|
|||
|
bne.s @Exit ; Punt immediately on any error
|
|||
|
bra.s @EnumLoop ; Otherwise try again on next entry
|
|||
|
|
|||
|
@Done
|
|||
|
cmp.w #fnfErr, d0 ; Expected termination error?
|
|||
|
bne.s @Exit ; If not, get out as-is
|
|||
|
moveq #0, d0 ; Yes - all is well
|
|||
|
@Exit
|
|||
|
restoreUnlinkReturn
|
|||
|
|
|||
|
endwith
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
SharedTrashCode proc export
|
|||
|
|
|||
|
;___________________________________________________________________________________
|
|||
|
;
|
|||
|
; GetNetTrashID - Get the DirID of the Network Trash folder for a given VRefNum
|
|||
|
;
|
|||
|
; Input:
|
|||
|
; D0.W: VRefNum of target volume
|
|||
|
;
|
|||
|
; Output:
|
|||
|
; D0.W: Error code
|
|||
|
; D1.L: NetTrash DirID (if D0.W=0)
|
|||
|
;___________________________________________________________________________________
|
|||
|
|
|||
|
GNIDRegs REG A0-A1 ; scratch registers used
|
|||
|
|
|||
|
GNIDStackFrame RECORD -(ioHFQElSiz) ; offset for local variables
|
|||
|
FirstLocal EQU * ; First local variable
|
|||
|
PBRec DS.B ioHFQElSiz ; Local parameter block for use
|
|||
|
LocalSize EQU *-FirstLocal ; Size of local variable size
|
|||
|
A6Link DS.L 1 ; A6 stack frame link (this should be zero!)
|
|||
|
RetPC DS.L 1 ; Return address
|
|||
|
LastArg EQU *
|
|||
|
ArgsSize EQU *-LastArg ; Size of incoming arguments
|
|||
|
;retValue DS.W 1 ; Space reserved for return value
|
|||
|
ENDR
|
|||
|
;
|
|||
|
EXPORT GetNetTrashID
|
|||
|
|
|||
|
GetNetTrashID:
|
|||
|
WITH GNIDStackFrame
|
|||
|
LINK A6,#-LocalSize ; Allocate an HFS parameter block & other locals
|
|||
|
MOVEM.L GNIDRegs, -(SP) ; Free for use as scratch
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVEQ #(ioHFQElSiz/2)-1,D1 ; Compute DBRA loop index
|
|||
|
@ClearPB CLR.W (A0)+ ; Clear a word in the PBRec
|
|||
|
DBRA D1,@ClearPB ;
|
|||
|
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.W D0,ioVRefNum(A0) ; Set up for target volume
|
|||
|
MOVE.L #fsRtDirID, ioDirID(A0) ; Folder is located in root directory
|
|||
|
LEA NetTrashFolderName, A1 ; Point to the name of the Net Trash folder
|
|||
|
MOVE.L A1,ioFileName(A0) ; Set up as target name
|
|||
|
_GetCatInfo ; See if the folder exists
|
|||
|
BNE.S @NoTrashFolder ; Try to recover from the shock
|
|||
|
BTST #ioDirFlg, ioFlAttrib(A0) ; Make sure it's a folder
|
|||
|
BNE.S @GotTrashFolder ; If it does, we're set
|
|||
|
MOVE.W #dupFNErr, D0 ; Otherwise, return an error
|
|||
|
BRA.S @Exit ; ... and get out
|
|||
|
|
|||
|
@NoTrashFolder:
|
|||
|
CMP.W #fnfErr, D0 ; File not found error?
|
|||
|
BNE.S @Exit ; If some other error, punt
|
|||
|
MOVE.L #fsRtDirID, ioDirID(A0) ; Folder is located in root directory
|
|||
|
_DirCreate ; Try to create the folder
|
|||
|
BNE.S @Exit ; Punt on errors
|
|||
|
MOVE.L ioDirID(A0), D1 ; Pick up the Network trash folder ID
|
|||
|
MOVE.L #fsRtDirID, ioDirID(A0) ; Folder is located in root directory
|
|||
|
_GetCatInfo ; Look up the Finder info for this folder
|
|||
|
BNE.S @Exit ;
|
|||
|
ORI.W #mFNameLock,ioDrUsrWds+frFlags(A0) ; make it rename-inhibit
|
|||
|
BSET.B #bFndrInvisible,ioDrUsrWds+frFlags(A0) ; Invisible to Finder
|
|||
|
MOVE.L #fsRtDirID, ioDirID(A0) ; Folder is located in root directory
|
|||
|
_SetCatInfo ; Set new folder attributes
|
|||
|
BNE.S @Exit ;
|
|||
|
MOVE.L #administratorUser, ioACOwnerID(A0) ; Give the Network Trash Folder to the Administrator
|
|||
|
MOVE.L #noGroup, ioACGroupID(A0) ; No group affiliation
|
|||
|
MOVE.L #fullPrivileges, ioACAccess(A0) ; Free access to all other users inside
|
|||
|
_SetDirAccess ; Set the access privileges for the folder
|
|||
|
BRA.S @Exit ; We're done, D1=Network Trash folder DirID
|
|||
|
|
|||
|
@GotTrashFolder:
|
|||
|
MOVE.L ioDirID(A0), D1 ; Pick up the folder ID
|
|||
|
MOVEQ #0,D0 ; Indicate successful completion
|
|||
|
|
|||
|
@Exit MOVEM.L (SP)+, GNIDRegs ; Restore scratch registers
|
|||
|
UNLK A6 ; Pop off stack frame
|
|||
|
TST.W D0 ; Set condition codes
|
|||
|
RTS ;
|
|||
|
ENDWITH
|
|||
|
|
|||
|
;___________________________________________________________________________________
|
|||
|
;
|
|||
|
; GetTrashMapRefnum - Get the file refnum for the Trash map file for a given volume,
|
|||
|
; given its Network Trash folder ID.
|
|||
|
;
|
|||
|
; Input:
|
|||
|
; D0.W: VRefNum of target volume
|
|||
|
; D1.L: Network Trash folder DirID
|
|||
|
;
|
|||
|
; Output:
|
|||
|
; D0.W: Error code
|
|||
|
; D1.W: Trash map file refnum (if D0.W=0)
|
|||
|
;___________________________________________________________________________________
|
|||
|
|
|||
|
GMRRegs REG A0-A1 ; scratch registers used
|
|||
|
|
|||
|
GMRStackFrame RECORD -(ioHFQElSiz+2+4) ; offset for local variables
|
|||
|
FirstLocal EQU * ; First local variable
|
|||
|
PBRec DS.B ioHFQElSiz ; Local parameter block for use
|
|||
|
TargetVRef DS.W 1 ; Target volume VRefNum
|
|||
|
NetTrashID DS.L 1 ; Net Trash DirID
|
|||
|
LocalSize EQU *-FirstLocal ; Size of local variable size
|
|||
|
A6Link DS.L 1 ; A6 stack frame link (this should be zero!)
|
|||
|
RetPC DS.L 1 ; Return address
|
|||
|
LastArg EQU *
|
|||
|
ArgsSize EQU *-LastArg ; Size of incoming arguments
|
|||
|
;retValue DS.W 1 ; Space reserved for return value
|
|||
|
ENDR
|
|||
|
|
|||
|
EXPORT GetTrashMapRefnum
|
|||
|
;
|
|||
|
GetTrashMapRefnum:
|
|||
|
WITH GMRStackFrame
|
|||
|
LINK A6,#-LocalSize ; Allocate an HFS parameter block & other locals
|
|||
|
MOVEM.L GMRRegs,-(SP) ; Free for use as scratch
|
|||
|
MOVE.W D0, TargetVRef(A6) ; Save copy of target volume VRefNum
|
|||
|
MOVE.L D1, NetTrashID(A6) ; Save copy of Network Trash folder ID
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVEQ #(ioHFQElSiz/2)-1,D0 ; Compute DBRA loop index
|
|||
|
@ClearPB CLR.W (A0)+ ; Clear a word in the PBRec
|
|||
|
DBRA D0,@ClearPB ;
|
|||
|
|
|||
|
@OpenMapFile;
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.W TargetVRef(A6), ioVRefNum(A0) ; Set up to specify target volume
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Set up to look in Network Trash folder
|
|||
|
LEA TrashMapName, A1 ; Point to the name of the trash map file
|
|||
|
MOVE.L A1, ioFileName(A0) ; Set up for _Open
|
|||
|
MOVE.B #fsRdPerm, ioPermssn(A0); Open the file Read-Only
|
|||
|
_HOpen ; Try to open the file
|
|||
|
BEQ.S @Done ; If it works, we're set
|
|||
|
CMP.W #fnfErr, D0 ; File not found?
|
|||
|
BNE.S @Exit ; Nope - this is just too much to handle
|
|||
|
_HCreate ; Yes - try to create the file
|
|||
|
BNE.S @Exit ; Give up at the first hint of trouble
|
|||
|
;
|
|||
|
; We've just created a new Trash map file -
|
|||
|
; Set its Finder attributes to make it invisible and lock the name.
|
|||
|
;
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Reset the DirID to the Network Trash Folder
|
|||
|
_GetCatInfo ; Get the file's information
|
|||
|
BNE.S @Exit ; This SHOULD never fail...
|
|||
|
ORI.W #mFNameLock,ioFlUsrWds+fdFlags(A0) ; make it rename-inhibit
|
|||
|
BSET #bFndrInvisible, ioFlUsrWds+fdFlags(A0) ; Set the invisible bit
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Reset the DirID to the Network Trash Folder
|
|||
|
_SetCatInfo ; Set the new attributes for the file
|
|||
|
BNE.S @Exit ; This SHOULD be even LESS like to fail...
|
|||
|
BRA.S @OpenMapFile ; Try to open the file again
|
|||
|
|
|||
|
@Done MOVE.W ioRefNum(A0), D1 ; Return file refnum
|
|||
|
MOVEQ #0, D0 ; Indicate total stunning success
|
|||
|
|
|||
|
@Exit MOVEM.L (SP)+, GMRRegs ; Restore scratch registers
|
|||
|
UNLK A6 ; Pop off stack frame
|
|||
|
TST.W D0 ; Set condition codes
|
|||
|
RTS ;
|
|||
|
ENDWITH
|
|||
|
|
|||
|
;___________________________________________________________________________________
|
|||
|
;
|
|||
|
; GetTrashCanID - Get the DirID of the trash folder for use on a given volume/Network Trash folder
|
|||
|
;
|
|||
|
; Input:
|
|||
|
; D0.W: VRefNum of target volume
|
|||
|
; D1.L: Network Trash folder DirID
|
|||
|
; D2.W: RefNum of Trash Can Usage Map file
|
|||
|
;
|
|||
|
; Output:
|
|||
|
; D0.W: Error code
|
|||
|
; D1.L: NetTrash DirID (if D0.W=0)
|
|||
|
;___________________________________________________________________________________
|
|||
|
|
|||
|
GetTrashRegs REG A0-A1/D2-D3 ; scratch registers used
|
|||
|
|
|||
|
GTIDStackFrame RECORD -(ioHFQElSiz+2+4+2+32+6+4) ; offset for local variables
|
|||
|
FirstLocal EQU * ; First local variable
|
|||
|
PBRec DS.B ioHFQElSiz ; Local parameter block for use
|
|||
|
TargetVRef DS.W 1 ; Target volume VRefNum
|
|||
|
NetTrashID DS.L 1 ; Net Trash DirID
|
|||
|
TrashMapRefnum DS.W 1 ; File refnum of trash map file
|
|||
|
FileName DS.B 32 ; 32 bytes for file name storage
|
|||
|
TrashNumber DS.B 6 ; Str5 for trash can number string
|
|||
|
TrashCanID DS.L 1 ; DirID of trash can
|
|||
|
LocalSize EQU *-FirstLocal ; Size of local variable size
|
|||
|
A6Link DS.L 1 ; A6 stack frame link (this should be zero!)
|
|||
|
RetPC DS.L 1 ; Return address
|
|||
|
LastArg EQU *
|
|||
|
ArgsSize EQU *-LastArg ; Size of incoming arguments
|
|||
|
;retValue DS.W 1 ; Space reserved for return value
|
|||
|
ENDR
|
|||
|
|
|||
|
EXPORT GetTrashCanID
|
|||
|
;
|
|||
|
GetTrashCanID:
|
|||
|
WITH GTIDStackFrame
|
|||
|
LINK A6,#-LocalSize ; Allocate an HFS parameter block & other locals
|
|||
|
MOVEM.L GetTrashRegs,-(SP) ; Free for use as scratch
|
|||
|
MOVE.W D0, TargetVRef(A6) ; Save copy of target volume VRefNum
|
|||
|
MOVE.L D1, NetTrashID(A6) ; Save copy of Network Trash folder ID
|
|||
|
MOVE.W D2, TrashMapRefnum(A6) ; stash file refnum for future use
|
|||
|
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVEQ #(ioHFQElSiz/2)-1,D0 ; Compute DBRA loop index
|
|||
|
@ClearPB CLR.W (A0)+ ; Clear a word in the PBRec
|
|||
|
DBRA D0,@ClearPB ;
|
|||
|
|
|||
|
MOVEQ #1,D3 ; Starting guess at trashcan #
|
|||
|
;
|
|||
|
; Start by enumerating the Network Trash Folder on the detination volume,
|
|||
|
; looking for existing trash folders that aren't currently in use:
|
|||
|
;
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.W TargetVRef(A6),ioVRefNum(A0) ; Set up for target volume
|
|||
|
MOVE.L NetTrashID(A6),ioDirID(A0) ; Set up Network Trash folder ID
|
|||
|
LEA FileName(A6), A1 ; Point to local file name buffer
|
|||
|
MOVE.L A1,ioFileName(A0) ; Set up to be return on _GetCatInfo
|
|||
|
MOVEQ #0,D2 ; Initialize enumerate index
|
|||
|
|
|||
|
@EnumLoop LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Reset target DirID
|
|||
|
ADDQ.W #1,D2 ; Bump up to request next object in folder
|
|||
|
MOVE.W D2,ioFDirIndex(A0) ; Set up requested index
|
|||
|
_GetCatInfo ; See if there's a folder by that index
|
|||
|
BNE @NewTrashCan ; Stop enumerating on any error
|
|||
|
BTST #ioDirFlg, ioFlAttrib(A0) ; Is it a folder?
|
|||
|
BEQ.S @EnumLoop ; If not, skip it
|
|||
|
MOVE.L ioDirID(A0), TrashCanID(A6) ; Save a copy of the folder's DirID
|
|||
|
BTST #7,ioFlAttrib+1(A0) ; Check 'owner' bit on folder
|
|||
|
BEQ.S @CheckTrashCan ; If we're the owner, go check it out
|
|||
|
MOVE.B ioFlAttrib+1(A0), D0 ; Pick up the access privilege summary
|
|||
|
ANDI.B #$07, D0 ; Mask off all but 3-bit summary
|
|||
|
BNE.S @EnumLoop ; Some access wasn't allowed
|
|||
|
;
|
|||
|
; We've come across a folder we don't own, but DO have full privileges to:
|
|||
|
; Even if the owner flag isn't set, we might be the owner of the machine, in which
|
|||
|
; case the owner flag might not be set because the root of the volume is not shared
|
|||
|
; with the network and we gained access by virtue of being the owner of the machine.
|
|||
|
; Since the Network Trash folder will lie outside the shared area, the owner flag
|
|||
|
; will never be set for any folder. Explicitly check the owner ID here, then:
|
|||
|
;
|
|||
|
; NOTE: Should probably do an explicity check of the ioACOwnerID agains the login
|
|||
|
; user ID here, but this'll do in a pinch:
|
|||
|
;
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Reset target DirID
|
|||
|
CLR.W ioFDirIndex(A0) ;
|
|||
|
_GetDirAccess ; Look up the access privileges
|
|||
|
BNE.S @EnumLoop ; Punt on any error
|
|||
|
CMPI.L #administratorUser, ioACOwnerID(A0) ; Owned by Administrator?
|
|||
|
BNE.S @EnumLoop ; Nope - who knows what's going on
|
|||
|
MOVE.L ioACAccess(A0), D0 ; Pick up folder's access privileges
|
|||
|
ANDI.L #$00FFFFFF, D0 ; Strip off access summary
|
|||
|
CMPI.L #ownerPrivileges, D0 ; Set to owner only access?
|
|||
|
BNE.S @EnumLoop ; If not, something strange is going on
|
|||
|
;
|
|||
|
; Check to see if the folder just found is 'Trash Can #xxx':
|
|||
|
;
|
|||
|
@CheckTrashCan:
|
|||
|
LEA FileName(A6), A0 ; Point to local file name buffer
|
|||
|
LEA NetTrashPrefix, A1 ; Point to trash folder prefix
|
|||
|
MOVE.B (A1),D0 ; Pick up length of prefix
|
|||
|
CMP.B (A0), D0 ; Check if folder length is > prefix length
|
|||
|
BGE.S @EnumLoop ; If so, there's no interest
|
|||
|
SWAP D0 ; Switch string length into top byte
|
|||
|
MOVE.B (A1)+, D0 ; Pick up prefix length & advance name ptr
|
|||
|
ADDQ.L #1,A0 ; Ignore actual length of file name
|
|||
|
_CmpString ; See if the string is identical
|
|||
|
BNE.S @EnumLoop ; If not, ignore it
|
|||
|
|
|||
|
;
|
|||
|
; Get the number of the trash can from the name:
|
|||
|
;
|
|||
|
LEA FileName(A6), A0 ; Point to the file name
|
|||
|
MOVE.B (A0)+,D0 ; Pick up the name length
|
|||
|
LEA NetTrashPrefix, A1 ; Point to trash folder prefix
|
|||
|
MOVEQ #0, D1 ; Clear top 3 bytes
|
|||
|
MOVE.B (A1), D1 ; Pick up prefix length
|
|||
|
ADDA.L D1, A0 ; Skip prefix in file name
|
|||
|
SUB.B D1, D0 ; Subtract from file name length to yield number length
|
|||
|
CLR.L D3 ; Initialize the number
|
|||
|
@GetNumLoop SUBQ.B #1,D0 ; One less digit to process
|
|||
|
BLT.S @GotTrashNum ; If no chars left, D3 holds the trash can #
|
|||
|
MOVEQ #0, D1 ; Clear top 3 bytes in longword
|
|||
|
MOVE.B (A0)+, D1 ; Pick up a character from the name
|
|||
|
CMPI.B #'0', D1 ; Is < 0?
|
|||
|
BLT @EnumLoop ; If so, it's a bad name
|
|||
|
CMPI.B #'9', D1 ; Is it > 9?
|
|||
|
BGT @EnumLoop ; If so, it's a bad name
|
|||
|
SUBI.B #'0',D1 ; Convert to decimal digit
|
|||
|
MULU.W #10, D3 ; Multiply number so far by 10,
|
|||
|
ADD.L D1,D3 ; ... add in the new digit
|
|||
|
BRA.S @GetNumLoop ; ... and loop to get the next digit
|
|||
|
|
|||
|
@GotTrashNum:
|
|||
|
MOVE.L D3, -(SP) ; Specify trash can of interest
|
|||
|
BSR SeizeTrashCan ; Try to get the semaphore byte locked
|
|||
|
BNE @EnumLoop ; If can't lock it, try another folder
|
|||
|
;
|
|||
|
; We've found an existing trash can suitable for our use - start
|
|||
|
; by emptying out whatever files or folder may have been left in there:
|
|||
|
;
|
|||
|
MOVE.W TargetVRef(A6), -(SP) ; Point to target volume VRefNum
|
|||
|
MOVE.L TrashCanID(A6), -(SP) ; Recover trash can folder ID
|
|||
|
JSR CleanOutFolder ; Clean out the indicated folder
|
|||
|
BNE @EnumLoop ; Punt on error
|
|||
|
BRA @Done ; Otherwise, we're set
|
|||
|
;
|
|||
|
; No suitable existing trash can was found - time to create a brand new one.
|
|||
|
; D3 currently holds the number of the highest trash can in the Network Trash
|
|||
|
; folder: adding 1 yields a pretty good bet for the next available trash folder:
|
|||
|
;
|
|||
|
@NewTrashCan:
|
|||
|
ADDQ.L #1, D3 ; Bump up to the first unused number
|
|||
|
MOVE.L D3, -(SP) ; Pass the next highest trash can #
|
|||
|
BSR SeizeTrashCan ; Try to get the semaphore byte locked
|
|||
|
BEQ.S @GotTrashCan ; Success, we got the Trash can
|
|||
|
CMPI.W #paramErr, D0 ; Byte range locking not implemented?
|
|||
|
BEQ @Exit ; Yes, return the error. Don't loop for next one.
|
|||
|
CMPI.W #ioErr, D0 ; Byte range locking not implemented? (special case for Caps)
|
|||
|
BEQ @Exit ; Yes, return the error. Don't loop for next one.
|
|||
|
CMPI.W #extFSErr, D0 ; External file system error?
|
|||
|
BEQ @Exit ; Yes, return the error. Don't loop for next one.
|
|||
|
BRA.S @NewTrashCan ; ... and try again for any other error
|
|||
|
|
|||
|
@GotTrashCan:
|
|||
|
LEA NetTrashPrefix, A0 ; Point to the standard Trash can name prefix
|
|||
|
MOVEQ #0,D0 ; Clean upper 3 bytes
|
|||
|
MOVE.B (A0), D0 ; Pick up string length
|
|||
|
ADDQ.L #1, D0 ; Add 1 for the length byte itself
|
|||
|
MOVE.L D0, D1 ; Make a copy for use in a moment
|
|||
|
LEA FileName(A6), A1 ; Point to the target file name
|
|||
|
_BlockMove ; Copy the name prefix
|
|||
|
ADDA.L D1, A1 ; Point to the end of the file name
|
|||
|
LEA TrashNumber+6(A6), A0 ; Point to last digit of trash can #
|
|||
|
MOVE.L D3, D2 ; Make a copy to convert
|
|||
|
MOVEQ #0, D1 ; Clear digit count
|
|||
|
@NextDigit ADDQ.L #1, D1 ; One more digit generated
|
|||
|
DIVU #10, D2 ; Divide by D3 and use the remainder
|
|||
|
SWAP D2 ; Get the remainder in the low word
|
|||
|
ADD.B #'0', D2 ; Change to decimal digit
|
|||
|
MOVE.B D2, -(A0) ; Add digit to number
|
|||
|
CLR.W D2 ; Clear out the processed digit
|
|||
|
SWAP D2 ; Get quotient in D3.L again
|
|||
|
BNE.S @NextDigit ; If the result is non-zero, go get another one
|
|||
|
|
|||
|
MOVE.L D1, D0 ; Get count of # of digits generated
|
|||
|
_BlockMove ; Tack on the digit sequence to the file name
|
|||
|
LEA FileName(A6), A1 ; Point to start of whole file name
|
|||
|
ADD.B D1, (A1) ; Add digit count to overall length
|
|||
|
;
|
|||
|
; Create the trash folder by the newly generated trash can name:
|
|||
|
;
|
|||
|
LEA PBRec(A6), A0 ; Point to the parameter block again
|
|||
|
MOVE.L A1, ioFileName(A0) ; Set up the newly chosen name
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Create folder in Network Trash folder
|
|||
|
_DirCreate ; Create the new trash can
|
|||
|
BEQ.S @SetupFldr ; Continue if all went well
|
|||
|
CMPI.W #dupFNErr, D0 ; Folder by that name exists already?
|
|||
|
BNE.S @Exit ; Nope - something else went wrong
|
|||
|
;
|
|||
|
; The trash can just selected was not in use but DID already exist.
|
|||
|
; Since it wasn't selected for recycling during the Network Trash Folder enumeration,
|
|||
|
; it must not have been accessible. Release the trash can flag and try again.
|
|||
|
;
|
|||
|
MOVE.L D3, -(SP) ; Pass trash can # just allocated
|
|||
|
BSR ReleaseTrashCan ; Release the trash can semaphore byte
|
|||
|
BRA.S @NewTrashCan ; ... and try again
|
|||
|
|
|||
|
@SetupFldr MOVE.L ioDirID(A0), TrashCanID(A6) ; Pick up the Network trash folder ID
|
|||
|
;
|
|||
|
; Make sure only the user has access privileges:
|
|||
|
;
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Folder is located in Network Trash folder
|
|||
|
_GetDirAccess ; Look up the access privileges assigned to the folder
|
|||
|
CMPI.L #ownerPrivileges, ioACAccess(A0) ; Already set to owner only access?
|
|||
|
BEQ.S @SetFldrAttrib ; Yes - skip to set the folder attributes
|
|||
|
MOVE.L #noGroup, ioACGroupID(A0) ; No group affiliation
|
|||
|
MOVE.L #ownerPrivileges, ioACAccess(A0) ; Access only to owner
|
|||
|
_SetDirAccess ; Set the access privileges for the folder
|
|||
|
;
|
|||
|
; Make the folder invisible and lock the name:
|
|||
|
;
|
|||
|
@SetFldrAttrib:
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Folder is located in Network Trash folder
|
|||
|
_GetCatInfo ; Look up the Finder info for this folder
|
|||
|
BNE.S @Exit ; Must be able to find it now
|
|||
|
ORI.W #mFNameLock,ioDrUsrWds+frFlags(A0) ; make it rename-inhibit
|
|||
|
BSET.B #bFndrInvisible,ioDrUsrWds+frFlags(A0) ; Invisible to Finder
|
|||
|
MOVE.L NetTrashID(A6), ioDirID(A0) ; Folder is located in Network Trash folder
|
|||
|
_SetCatInfo ; Set new folder attributes
|
|||
|
BNE.S @Exit ; What could POSSIBLY go wrong, eh?
|
|||
|
|
|||
|
@Done MOVE.L TrashCanID(A6), D1 ; Set up return value
|
|||
|
MOVEQ #0, D0 ; Total stunning success
|
|||
|
|
|||
|
@Exit MOVEM.L (SP)+, GetTrashRegs ; Restore scratch registers
|
|||
|
UNLK A6 ; Pop off stack frame
|
|||
|
TST.W D0 ; Set condition codes
|
|||
|
RTS ;
|
|||
|
|
|||
|
DC.B ($80+'G') ; Just for the debugger
|
|||
|
DC.B 'TRASHCA' ;
|
|||
|
DC.W 0
|
|||
|
;
|
|||
|
; Called with:
|
|||
|
; A6 - GetTrashCanID frame pointer
|
|||
|
; 4(SP) - Trash folder ID to seize
|
|||
|
;
|
|||
|
; Sets:
|
|||
|
; D0 - result code
|
|||
|
;
|
|||
|
SeizeTrashCan:
|
|||
|
MOVE.L A0, -(SP) ; Free for use as scratch
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.W TrashMapRefnum(A6), ioRefNum(A0) ; Set up trash map file refnum
|
|||
|
MOVE.W #fsFromStart, ioPosMode(A0) ; Indicate offset is from start of file
|
|||
|
MOVE.L 8(SP), ioPosOffset(A0) ; Set up target byte
|
|||
|
MOVE.L #1, ioReqCount(A0) ; Lock range is always just 1 byte
|
|||
|
_LockRng ; Try to lock the byte in question
|
|||
|
MOVEA.L (SP)+, A0 ; Restore scratch register
|
|||
|
MOVE.L (SP), 4(SP) ; Clobber the incoming argument w. return address
|
|||
|
TST.L (SP)+ ; Pop off the [copied] return address
|
|||
|
TST.W D0 ; Set condition codes
|
|||
|
RTS ;
|
|||
|
|
|||
|
;
|
|||
|
; Called with:
|
|||
|
; A6 - GetTrashCanID frame pointer
|
|||
|
; 4(SP) - Trash folder ID to release
|
|||
|
;
|
|||
|
; Sets:
|
|||
|
; D0 - result code
|
|||
|
;
|
|||
|
ReleaseTrashCan:
|
|||
|
MOVE.L A0, -(SP) ; Free for use as scratch
|
|||
|
LEA PBRec(A6), A0 ; Point to parameter block
|
|||
|
MOVE.W TrashMapRefnum(A6), ioRefNum(A0) ; Set up trash map file refnum
|
|||
|
MOVE.W #fsFromStart, ioPosMode(A0) ; Indicate offset is from start of file
|
|||
|
MOVE.L 8(SP), ioPosOffset(A0) ; Set up target byte
|
|||
|
MOVE.L #1, ioReqCount(A0) ; Lock range is always just 1 byte
|
|||
|
_UnlockRng ; Unlock the byte in question
|
|||
|
MOVEA.L (SP)+, A0 ; Restore scratch register
|
|||
|
MOVE.L (SP), 4(SP) ; Clobber the incoming argument w. return address
|
|||
|
TST.L (SP)+ ; Pop off the [copied] return address
|
|||
|
TST.W D0 ; Set condition codes
|
|||
|
RTS ;
|
|||
|
|
|||
|
ENDWITH
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
;----------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
end
|
|||
|
|