executor/src/fileHighlevel.c

618 lines
15 KiB
C

/* Copyright 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
/* NOTE: This is the quick hack version that uses old-style calls.
Eventually we should extract the common functionality and
then use that for both. That will be a little cleaner, a little
faster and a little easier to debug, but not enough of any to
make it sensible to do that initially. */
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_fileHighlevel[] =
"$Id: fileHighlevel.c 86 2005-05-25 00:47:12Z ctm $";
#endif
#include "rsys/common.h"
#include "MemoryMgr.h"
#include "FileMgr.h"
#include "ProcessMgr.h"
#include "rsys/file.h"
#include "rsys/string.h"
#include "rsys/hfs.h"
#include "rsys/executor.h"
/*
* extract the last component of a name:
*
* aaa:bbb:ccc -> ccc
* aaa:bbb:ccc: -> ccc
*/
PRIVATE void
extract_name (Str255 dest, StringPtr source)
{
int len, new_len;
Byte *p;
len = source[0];
if (source[len] == ':') /* ignore trailing ':' */
--len;
for (p = source + len; p >= source+1 && *p != ':'; --p)
;
new_len = len - (p - source);
dest[0] = new_len;
memmove (dest+1, p+1, new_len);
}
P4 (PUBLIC pascal trap, OSErr, FSMakeFSSpec,
int16, vRefNum, int32, dir_id,
Str255, file_name, FSSpecPtr, spec)
{
Str255 local_file_name;
OSErr retval;
HParamBlockRec hpb;
if (!file_name)
warning_unexpected("!file_name");
/*
* Colons make things tricky because they are used both to identify volumes
* and to delimit directories and sometimes to identify partial paths. Right
* now, most of these uses of colon shouldn't cause problems, but there are
* some issues that need to be checked on a real Mac. What do all these
* mean?
*
* dir_id file_name
* 310 foo:
* 310 :foo:
* 310 foo:bar
* 310 :foo:bar
* 310 :foo:bar:
*
* what about all those file_names, but with dir_id = 0, dir_id = 1, dir_id = 2
* and dir_id = a number that isn't a directory id?
*/
if (pstr_index_after (file_name, ':', 0))
warning_unexpected ("colon found");
str255assign (local_file_name, file_name);
hpb.volumeParam.ioNamePtr = (StringPtr) RM ((Ptr) local_file_name);
hpb.volumeParam.ioVRefNum = CW (vRefNum);
if (file_name[0])
hpb.volumeParam.ioVolIndex = CLC (-1);
else
hpb.volumeParam.ioVolIndex = CLC (0);
retval = PBHGetVInfo (&hpb, FALSE);
if (retval == noErr)
{
CInfoPBRec cpb;
str255assign (local_file_name, file_name);
cpb.hFileInfo.ioNamePtr = (StringPtr) RM ((Ptr) local_file_name);
cpb.hFileInfo.ioVRefNum = CW (vRefNum);
if (file_name[0])
cpb.hFileInfo.ioFDirIndex = CWC (0);
else
cpb.hFileInfo.ioFDirIndex = CWC (-1);
cpb.hFileInfo.ioDirID = CL (dir_id);
retval = PBGetCatInfo (&cpb, FALSE);
if (retval == noErr)
{
spec->vRefNum = hpb.volumeParam.ioVRefNum;
spec->parID = cpb.hFileInfo.ioFlParID;
extract_name ((StringPtr) spec->name, MR (cpb.hFileInfo.ioNamePtr));
}
else if (retval == fnfErr)
{
OSErr err;
cpb.hFileInfo.ioNamePtr = CLC (0);
cpb.hFileInfo.ioVRefNum = CW (vRefNum);
cpb.hFileInfo.ioFDirIndex = CWC (-1);
cpb.hFileInfo.ioDirID = CL (dir_id);
err = PBGetCatInfo (&cpb, FALSE);
if (err == noErr)
{
if (cpb.hFileInfo.ioFlAttrib & ATTRIB_ISADIR)
{
spec->vRefNum = hpb.volumeParam.ioVRefNum;
spec->parID = CL (dir_id);
extract_name ((StringPtr) spec->name, file_name);
}
else
retval = dupFNErr;
}
}
}
return retval;
}
#if 0
typedef struct save_fcb_info_str
{
filecontrolblock fcb;
HVCB *vptr;
struct save_fcb_info_str *next;
INTEGER refnum; /* zero if this is just info gathered for switching
purposes */
}
save_fcb_info_t;
PRIVATE LONGINT
get_file_num (FSSpecPtr fsp)
{
return 0; /* TODO */
}
/*
* get_fcb_info squirrels away all the FCB entries that match a particular
* file. It then alters them so that we can open files that are already
* open without trouble.
*/
PRIVATE save_fcb_info_t *
get_fcb_info (FSSpecPtr fsp)
{
filecontrolblock *fcbp, *efcbp;
INTEGER total_length, fcb_size;
save_fcb_info_t *retval;
char *fcbsptr;
INTEGER swapped_vrefnum;
LONGINT swapped_fnum;
retval = 0;
swapped_vrefnum = fsp->vRefNum;
swapped_fnum = CL (get_file_num (fsp));
fcbsptr = (char *) CL (FCBSPtr);
total_length = CW(*(short *)fcbsptr);
fcbp = (filecontrolblock *) ((short *)CL(FCBSPtr)+1);
efcbp = (filecontrolblock *) ((char *)CL(FCBSPtr) + total_length);
fcb_size = CW (FSFCBLen);
for (;fcbp < efcbp; fcbp = (filecontrolblock *) ((char *)fcbp + fcb_size))
{
HVCB *vptr;
vptr = CL (fcbp->fcbVPtr);
if (vptr && vptr->vcbVRefNum == swapped_vrefnum
&& fcbp->fcbFlNum == swapped_fnum)
{
save_fcb_info_t *newp;
newp = malloc (sizeof *newp);
newp->refnum = (char *) fcbp - fcbsptr;
newp->fcb = *fcbp;
newp->next = retval;
newp->vptr = fcbp->fcbVPtr;
fcbp->fcbVPtr = 0; /* hide this open file */
retval = newp;
}
}
return retval;
}
PRIVATE OSErr
exchange_forks (FSSpecPtr src, FSSpecPtr dst, forktype type)
{
/* TODO */
return paramErr;
}
PRIVATE void
exchange_fcb (const save_fcb_info_t *dstp, const save_fcb_info_t *srcp)
{
/* TODO */
}
/*
* make_fcb_info looks up the info that we need in order to swap fcb info
* when we only have information about one side
*/
PRIVATE save_fcb_info_t *
make_fcb_info (FSSpecPtr fsp)
{
save_fcb_info_t *retval;
retval = malloc (sizeof *retval);
retval->next = 0;
retval->vptr = 0; /* not needed */
retval->refnum = 0; /* means we're not associated with a real FCB */
return retval;
}
PRIVATE void
exchange_fcbs (FSSpecPtr fs1, const save_fcb_info_t *savefcbp1,
FSSpecPtr fs2, const save_fcb_info_t *savefcbp2)
{
if (savefcbp1 || savefcbp2)
{
if (!savefcbp1)
savefcbp1 = make_fcb_info (fs1);
else if (!savefcbp2)
savefcbp2 = make_fcb_info (fs2);
}
exchange_fcb (savefcbp1, savefcbp2);
exchange_fcb (savefcbp2, savefcbp1);
}
PRIVATE void
restore_fcb (const save_fcb_info_t *infop)
{
char *fcbsptr;
fcbsptr = (char *) CL (FCBSPtr);
if (infop)
{
if (infop->refnum)
{
filecontrolblock *fcbp;
fcbp = (filecontrolblock *) (fcbsptr + infop->refnum);
fcbp->fcbVPtr = infop->vptr;
}
restore_fcb (infop->next);
}
}
PRIVATE void
release_fcb_info (save_fcb_info_t *infop)
{
if (infop)
{
release_fcb_info (infop->next);
free (infop);
}
}
#endif
/*
* Part of ugly PAUP-specific hack below
*/
PRIVATE void
create_temp_name (Str63 name, int i)
{
OSErr err;
ProcessSerialNumber psn;
err = GetCurrentProcess (&psn);
if (err == noErr)
sprintf ((char *) name+1,
"%x%x.%x", CL (psn.highLongOfPSN), CL (psn.lowLongOfPSN), i);
else
sprintf ((char *) name+1, "%d.%x", err, i);
name[0] = strlen ((char *) name+1);
}
/*
* On real HFS volumes we could do some B-tree manipulation to achieve
* the correct results, *but* we'd need this code for ufs volumes anyway,
* so for now we do the same thing on both.
*/
P2 (PUBLIC pascal trap, OSErr, FSpExchangeFiles,
FSSpecPtr, src, FSSpecPtr, dst)
{
#if 0
save_fcb_info_t *src_fcb_info, *dst_fcb_info;
OSErr retval;
src_fcb_info = get_fcb_info (src);
dst_fcb_info = get_fcb_info (dst);
retval = exchange_forks (src, dst, datafork);
if (retval == noErr)
{
retval = exchange_forks (src, dst, resourcefork);
if (retval != noErr)
exchange_forks (src, dst, datafork); /* try to put things back
together */
}
if (retval == noErr)
exchange_fcbs (src, src_fcb_info, dst, dst_fcb_info);
else
{
restore_fcb (src_fcb_info);
restore_fcb (dst_fcb_info);
}
release_fcb_info (src_fcb_info);
release_fcb_info (dst_fcb_info);
return retval;
#else
OSErr retval;
warning_unimplemented ("poorly implemented");
if (src->vRefNum != dst->vRefNum)
retval = diffVolErr;
else if (ROMlib_creator != TICK("PAUP") || src->parID != dst->parID)
retval = wrgVolTypeErr;
else
{
/* Evil hack to get PAUP to work -- doesn't bother adjusting FCBs */
FSSpec tmp_spec;
int i;
i = 0;
tmp_spec = *dst;
do
{
create_temp_name (tmp_spec.name, i++);
retval = FSpRename (dst, tmp_spec.name);
}
while (retval == dupFNErr);
if (retval == noErr)
{
retval = FSpRename (src, dst->name);
if (retval != noErr)
FSpRename (&tmp_spec, dst->name);
else
{
retval = FSpRename (&tmp_spec, src->name);
if (retval != noErr)
{
FSpRename (dst, src->name);
FSpRename (&tmp_spec, dst->name);
}
}
}
}
return retval;
#endif
}
typedef OSErrRET (*open_procp) (HParmBlkPtr pb, BOOLEAN sync);
PRIVATE OSErr
open_helper (FSSpecPtr spec, SignedByte perms, int16 *refoutp,
open_procp procp)
{
OSErr retval;
HParamBlockRec hpb;
hpb.ioParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.ioParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
if (perms == fsWrPerm)
{
warning_unexpected (NULL_STRING);
perms = fsRdWrPerm;
}
hpb.ioParam.ioPermssn = perms;
warning_unimplemented ("poorly implemented ... will try to open drivers");
retval = procp (&hpb, FALSE);
if (retval == noErr)
*refoutp = hpb.ioParam.ioRefNum;
return retval;
}
P3 (PUBLIC pascal trap, OSErr, FSpOpenDF,
FSSpecPtr, spec, SignedByte, perms, int16 *, refoutp)
{
return open_helper (spec, perms, refoutp, PBHOpen);
}
P3 (PUBLIC pascal trap, OSErr, FSpOpenRF,
FSSpecPtr, spec, SignedByte, perms, int16 *, refoutp)
{
return open_helper (spec, perms, refoutp, PBHOpenRF);
}
P4 (PUBLIC pascal trap, OSErr, FSpCreate,
FSSpecPtr, spec, OSType, creator, OSType, file_type,
ScriptCode, script)
{
OSErr retval;
retval = HCreate (CW (spec->vRefNum), CL (spec->parID), spec->name,
creator, file_type);
return retval;
}
P3 (PUBLIC pascal trap, OSErr, FSpDirCreate,
FSSpecPtr, spec, ScriptCode, script,
int32 *, created_dir_id)
{
OSErr retval;
HParamBlockRec hpb;
hpb.ioParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.ioParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
retval = PBDirCreate (&hpb, FALSE);
if (retval == noErr)
*created_dir_id = hpb.fileParam.ioDirID;
return retval;
}
P1 (PUBLIC pascal trap, OSErr, FSpDelete,
FSSpecPtr, spec)
{
OSErr retval;
HParamBlockRec hpb;
hpb.ioParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.ioParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
retval = PBHDelete (&hpb, FALSE);
return retval;
}
P2 (PUBLIC pascal trap, OSErr, FSpGetFInfo,
FSSpecPtr, spec, FInfo *, fndr_info)
{
OSErr retval;
HParamBlockRec hpb;
hpb.fileParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.fileParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
hpb.fileParam.ioFDirIndex = CWC (0);
retval = PBHGetFInfo (&hpb, FALSE);
if (retval == noErr)
*fndr_info = hpb.fileParam.ioFlFndrInfo;
return retval;
}
P2 (PUBLIC pascal trap, OSErr, FSpSetFInfo,
FSSpecPtr, spec, FInfo *, fndr_info)
{
OSErr retval;
HParamBlockRec hpb;
warning_unimplemented ("poorly implemented: call of PBHGetFInfo wasteful");
hpb.fileParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.fileParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
hpb.fileParam.ioFDirIndex = CWC (0);
retval = PBHGetFInfo (&hpb, FALSE);
if (retval == noErr)
{
hpb.fileParam.ioDirID = spec->parID;
hpb.fileParam.ioFlFndrInfo = *fndr_info;
retval = PBHSetFInfo (&hpb, FALSE);
}
return retval;
}
typedef OSErrRET (*lock_procp) (HParmBlkPtr pb, BOOLEAN async);
PRIVATE OSErr
lock_helper (FSSpecPtr spec, lock_procp procp)
{
OSErr retval;
HParamBlockRec hpb;
hpb.fileParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.fileParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
retval = procp (&hpb, FALSE);
return retval;
}
P1 (PUBLIC pascal trap, OSErr, FSpSetFLock,
FSSpecPtr, spec)
{
return lock_helper (spec, PBHSetFLock);
}
P1 (PUBLIC pascal trap, OSErr, FSpRstFLock,
FSSpecPtr, spec)
{
return lock_helper (spec, PBHRstFLock);
}
P2 (PUBLIC pascal trap, OSErr, FSpRename,
FSSpecPtr, spec, Str255, new_name)
{
OSErr retval;
HParamBlockRec hpb;
hpb.fileParam.ioVRefNum = spec->vRefNum;
hpb.fileParam.ioDirID = spec->parID;
hpb.fileParam.ioNamePtr = (StringPtr) RM ((Ptr) spec->name);
hpb.ioParam.ioMisc = RM ((LONGINT) new_name);
retval = PBHRename (&hpb, FALSE);
return retval;
}
P2 (PUBLIC pascal trap, OSErr, FSpCatMove,
FSSpecPtr, src, FSSpecPtr, dst)
{
OSErr retval;
CMovePBRec cbr;
if (src->vRefNum != dst->vRefNum)
retval = paramErr;
else
{
cbr.ioVRefNum = src->vRefNum;
cbr.ioDirID = src->parID;
cbr.ioNamePtr = (StringPtr) RM ((Ptr) src->name);
cbr.ioNewName = (StringPtr) RM ((Ptr) dst->name);
cbr.ioNewDirID = dst->parID;
retval = PBCatMove (&cbr, FALSE);
}
return retval;
}
P4 (PUBLIC pascal trap, void, FSpCreateResFile,
FSSpecPtr, spec, OSType, creator, OSType, file_type,
ScriptCode, script)
{
HCreateResFile_helper (CW (spec->vRefNum), CL (spec->parID),
spec->name, creator, file_type, script);
}
P2 (PUBLIC pascal trap, INTEGER, FSpOpenResFile,
FSSpecPtr, spec, SignedByte, perms)
{
INTEGER retval;
retval = HOpenResFile (CW (spec->vRefNum), CL (spec->parID), spec->name,
perms);
return retval;
}
/* NOTE: the HCreate and HOpenRF are not traps, they're just high level
calls that are handy to use elsewhere, so they're included here. */
PUBLIC OSErr
HCreate (INTEGER vref, LONGINT dirid, Str255 name, OSType creator, OSType type)
{
HParamBlockRec hpb;
OSErr retval;
hpb.fileParam.ioNamePtr = RM (name);
hpb.fileParam.ioVRefNum = CW (vref);
hpb.fileParam.ioDirID = CL (dirid);
retval = PBHCreate (&hpb, FALSE);
if (retval == noErr)
{
hpb.fileParam.ioFDirIndex = CWC (0);
retval = PBHGetFInfo (&hpb, FALSE);
if (retval == noErr)
{
hpb.fileParam.ioFlFndrInfo.fdCreator = CL (creator);
hpb.fileParam.ioFlFndrInfo.fdType = CL (type);
hpb.fileParam.ioDirID = CL (dirid);
retval = PBHSetFInfo (&hpb, FALSE);
}
}
return retval;
}
PUBLIC OSErr
HOpenRF (INTEGER vref, LONGINT dirid, Str255 name, SignedByte perm,
INTEGER *refp)
{
HParamBlockRec hpb;
OSErr retval;
hpb.fileParam.ioNamePtr = RM (name);
hpb.fileParam.ioVRefNum = CW (vref);
hpb.ioParam.ioPermssn = CB (perm);
hpb.ioParam.ioMisc = CLC (0);
hpb.fileParam.ioDirID = CL (dirid);
retval = PBHOpenRF (&hpb, FALSE);
if (retval == noErr)
*refp = CW (hpb.ioParam.ioRefNum);
return retval;
}