mirror of
https://github.com/elliotnunn/boot3.git
synced 2024-08-31 16:29:21 +00:00
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
2154 lines
86 KiB
Plaintext
2154 lines
86 KiB
Plaintext
;
|
|
; File: FolderMgr.a
|
|
;
|
|
; Contains: Folder Manager
|
|
;
|
|
; Written by: Darin Adler
|
|
;
|
|
; Copyright: © 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 ÒAny UserÓ to ÒAdministratorÓ 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 Òwhere to empty trashÓ as follows:
|
|
; check the Òsuper-userÓ bit on the result of GetVolParms or GetDirAccess
|
|
; if the user is a Òsuper-userÓ, 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Õ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 Òname-lockedÓ 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 ÒnoDeskItemsÓ attribute.
|
|
;
|
|
; The trash folder is handled specially on volumes that have access controls (privileges).
|
|
; A ÒsharedÓ trash folder is created, which contains all of the user-specific trash folders.
|
|
; The ÒsharedÓ 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 ÒsharedÓ 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Õ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Õs data is just the name
|
|
|
|
kStringMaxLength equ 255 ; if string is too big, itÕ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 ÒDesktop FolderÓ instead of ÒDesktopÓ 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Õ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Õ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Õ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Õ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Õ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Õ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Õ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Õ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 Ònot foundÓ 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 ÒrootÓ 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Õs dirID in ÒdirIDÓ.
|
|
; Find the folder by that name. If it is a file instead of a folder, we fail with a
|
|
; Òduplicate file nameÓ 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Õ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Õ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Õt do it
|
|
|
|
move.l d2,dirID ; now weÕ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Õ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Õ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Õ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Õ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Õ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Õ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Õ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Õt search, just insert
|
|
push.l d2 ; number of bytes to replace
|
|
push.l a1 ; hereÕs what you should insert
|
|
push.l d1 ; hereÕs the length of what you should insert
|
|
_Munger
|
|
free.l ; ignore the result
|
|
|
|
bra.s Done ; itÕs in, now weÕ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Õ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
|
|
|