executor/src/alias.c

772 lines
18 KiB
C

/* Copyright 1994, 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_alias[] =
"$Id: alias.c 88 2005-05-25 03:59:37Z ctm $";
#endif
#include "rsys/common.h"
#include <stdarg.h>
#include "FileMgr.h"
#include "AliasMgr.h"
#include "MemoryMgr.h"
#include "ToolboxUtil.h"
#include "rsys/file.h"
#include "rsys/hfs.h"
#include "rsys/string.h"
#if defined (CYGWIN32)
#include "win_temp.h"
#endif
#include "rsys/alias.h"
#define paramErr (-50)
/* NOTE: if we want to be more like the Mac, we should have a 'fld#',0
resource that will have in it: type, four bytes of 0, pascal string,
potential padding to even things up, type, four bytes of 0, ... */
PRIVATE const char *
find_sub_dir (OSType folderType)
{
typedef struct
{
OSType type;
const char *name;
}
sys_sub_dir_match_t;
static sys_sub_dir_match_t matches[] =
{
{ kPrintMonitorDocsFolderType, "PrintMonitor Documents", },
{ kStartupFolderType, "Startup Items", },
{ kAppleMenuFolderType, "Apple Menu Items", },
{ kExtensionFolderType, "Extensions", },
{ kPreferencesFolderType, "Preferences", },
{ kControlPanelFolderType, "Control Panels", },
{ kFontFolderType, "Fonts", },
};
int i;
const char *retval;
for (i = 0; i < (int) NELEM (matches) && matches[i].type != folderType; ++i)
;
if (i < (int) NELEM (matches))
retval = matches[i].name;
else
retval = 0;
return retval;
}
PRIVATE OSErr
get_sys_vref_and_dirid (INTEGER *sys_vrefp, LONGINT *sys_diridp)
{
OSErr err;
WDPBRec wdp;
wdp.ioVRefNum = BootDrive;
wdp.ioWDIndex = CWC (0);
wdp.ioNamePtr = CLC (0);
err = PBGetWDInfo (&wdp, FALSE);
if (err == noErr)
{
*sys_vrefp = CW (wdp.ioWDVRefNum);
*sys_diridp = CL (wdp.ioWDDirID);
}
return err;
}
PRIVATE OSErr
try_to_find (INTEGER vref, const char *str, INTEGER *vrefp, LONGINT *diridp)
{
OSErr err;
HVCB *vcbp;
warning_trace_info ("str = '%s'", str);
vcbp = ROMlib_vcbbybiggestunixname (str);
if (!vcbp)
err = nsvErr;
else
{
VCBExtra *vcbextrap;
struct stat sbuf;
vcbextrap = (VCBExtra *) vcbp;
warning_trace_info ("unixname = '%s'", vcbextrap->unixname);
if (Ustat (str, &sbuf) < 0)
{
warning_trace_info ("stat failed, errno = %d", errno);
err = ROMlib_maperrno ();
}
else
{
warning_trace_info ("ino = %ld, ufs.ino = %ld", (long) ST_INO (sbuf),
(long) vcbextrap->u.ufs.ino);
if (vref != CW (vcbp->vcbVRefNum))
err = fnfErr;
else
{
*vrefp = vref;
if (ST_INO(sbuf) == vcbextrap->u.ufs.ino)
*diridp = 2;
else
*diridp = ST_INO(sbuf);
err = noErr;
}
}
}
warning_trace_info ("err = %d", err);
return err;
}
PRIVATE OSErr
look_for_volume (const char *vol_name, INTEGER *vrefp, LONGINT *diridp)
{
OSErr retval;
ParamBlockRec pbr;
Str255 pvol_name;
str255_from_c_string (pvol_name, vol_name);
pbr.volumeParam.ioNamePtr = RM (&pvol_name[0]);
pbr.volumeParam.ioVolIndex = CLC (-1);
pbr.volumeParam.ioVRefNum = CWC (0);
retval = PBGetVInfo (&pbr, FALSE);
if (retval == noErr)
{
*vrefp = CW (pbr.volumeParam.ioVRefNum);
*diridp = 2;
}
return retval;
}
/*
* We call this when we haven't been able to find what we want, so we
* try to construct something ourselves.
*/
PRIVATE OSErr
last_chance_tmp_vref_and_dirid (INTEGER vref, INTEGER *tmp_vrefp,
LONGINT *tmp_diridp)
{
OSErr retval;
HParamBlockRec pb;
memset (&pb, 0, sizeof pb);
pb.volumeParam.ioVRefNum = CW (vref);
retval = PBHGetVInfo (&pb, FALSE);
if (retval == noErr)
{
static char *top_level_names[] =
{
"\3tmp",
"\4temp",
};
int i;
OSErr err;
*tmp_vrefp = vref;
for (i = 0, err = fnfErr;
err != noErr && i < NELEM (top_level_names);
++i)
{
CInfoPBRec hpb;
memset (&hpb, 0, sizeof hpb);
hpb.dirInfo.ioNamePtr = (StringPtr) RM (top_level_names[i]);
hpb.dirInfo.ioVRefNum = pb.volumeParam.ioVRefNum;
hpb.dirInfo.ioDrDirID = CLC (2);
err = PBGetCatInfo (&hpb, FALSE);
if (err == noErr && (hpb.hFileInfo.ioFlAttrib & ATTRIB_ISADIR))
*tmp_diridp = CL (hpb.dirInfo.ioDrDirID);
}
if (err != noErr)
*tmp_diridp = CLC (2);
}
return retval;
}
PRIVATE OSErr
get_tmp_vref_and_dirid (INTEGER vref, INTEGER *tmp_vrefp, LONGINT *tmp_diridp)
{
int i;
OSErr retval;
static const char *guesses[] =
{
#if !defined (MSDOS) && !defined (CYGWIN32)
"/tmp",
#else
#if defined (CYGWIN32)
NULL,
#endif
"c:/tmp",
"c:/temp",
"c:/"
#endif
};
{
static boolean_t been_here_p = FALSE;
if (!been_here_p)
{
int j;
#if defined (CYGWIN32)
guesses[0] = win_temp ();
#endif
for (j = 0; j < (int) NELEM (guesses); ++j)
{
char *p;
if (guesses[j])
{
p = alloca (strlen (guesses[j]) + 1);
strcpy (p, guesses[j]);
ROMlib_automount (p);
}
}
been_here_p = TRUE;
}
}
retval = look_for_volume ("tmp:", tmp_vrefp, tmp_diridp);
for (i = 0; retval != noErr && i < (int) NELEM (guesses); ++i)
retval = try_to_find (vref, guesses[i], tmp_vrefp, tmp_diridp);
if (retval != noErr)
retval = last_chance_tmp_vref_and_dirid (vref, tmp_vrefp, tmp_diridp);
return retval;
}
PRIVATE OSErr
test_directory (INTEGER vref, LONGINT dirid, const char *sub_dirp,
LONGINT *new_idp)
{
OSErr err;
CInfoPBRec cpb;
Str255 file_name;
str255_from_c_string (file_name, sub_dirp);
cpb.hFileInfo.ioNamePtr = (StringPtr) RM ((Ptr) file_name);
cpb.hFileInfo.ioVRefNum = CW (vref);
cpb.hFileInfo.ioFDirIndex = CWC (0);
cpb.hFileInfo.ioDirID = CL (dirid);
err = PBGetCatInfo (&cpb, FALSE);
if (err == noErr && !(cpb.hFileInfo.ioFlAttrib & ATTRIB_ISADIR))
err = dupFNErr;
if (err == noErr)
*new_idp = CL (cpb.dirInfo.ioDrDirID);
return err;
}
PRIVATE OSErr
create_directory (INTEGER sys_vref, LONGINT sys_dirid, const char *sub_dirp,
LONGINT *new_idp)
{
warning_unimplemented (NULL_STRING);
return paramErr;
}
P5 (PUBLIC pascal trap, OSErr, FindFolder,
int16, vRefNum, OSType, folderType,
Boolean, createFolder, int16 *, foundVRefNum, int32 *, foundDirID)
{
OSErr retval;
const char *sub_dir;
sub_dir = find_sub_dir (folderType);
if (sub_dir)
{
INTEGER sys_vref;
LONGINT sys_dirid, new_id;
retval = get_sys_vref_and_dirid (&sys_vref, &sys_dirid);
if (retval == noErr)
{
retval = test_directory (sys_vref, sys_dirid, sub_dir, &new_id);
if (retval == fnfErr && createFolder)
retval = create_directory (sys_vref, sys_dirid, sub_dir, &new_id);
if (retval == noErr)
{
*foundVRefNum = CW (sys_vref);
*foundDirID = CL (new_id);
}
}
}
else
switch (folderType)
{
case kSystemFolderType:
{
INTEGER sys_vref;
LONGINT sys_dirid;
retval = get_sys_vref_and_dirid (&sys_vref, &sys_dirid);
if (retval == noErr)
{
/* NOTE: IMVI 9-44 tells us to not create System Folder if it
doesn't already exist */
*foundVRefNum = CW (sys_vref);
*foundDirID = CL (sys_dirid);
}
}
break;
case kDesktopFolderType:
case kTrashFolderType:
case kWhereToEmptyTrashFolderType:
case kTemporaryFolderType:
/* These cases aren't properly handled, but they should allow some apps
to get further */
{
INTEGER tmp_vref;
LONGINT tmp_dirid;
retval = get_tmp_vref_and_dirid (vRefNum, &tmp_vref, &tmp_dirid);
warning_unimplemented ("poorly implemented");
if (retval == fnfErr && createFolder)
warning_unimplemented ("Didn't attempt to create folder");
if (retval == noErr)
{
*foundVRefNum = CW (tmp_vref);
*foundDirID = CL (tmp_dirid);
}
}
break;
default:
warning_unexpected ("unknown folderType");
retval = fnfErr;
break;
}
return retval;
}
P3 (PUBLIC pascal trap, OSErr, NewAlias,
FSSpecPtr, fromFile, FSSpecPtr, target,
AliasHandle *, alias)
{
OSErr retval;
*alias = 0;
warning_unimplemented ("poorly implemented");
retval = NewAliasMinimal (target, alias);
return retval;
}
P4 (PUBLIC pascal trap, OSErr, UpdateAlias,
FSSpecPtr, fromFile, FSSpecPtr, target,
AliasHandle, alias, Boolean *, wasChanged)
{
warning_unimplemented (NULL_STRING);
return paramErr;
}
enum
{
FULL_PATH_TAG = 0x0002,
TAIL_TAG = 0x0009,
};
/*
* ResolveAlias is just a stub so we can recover the fsspecs that are stored
* in the AppleEvent that is constructed as part of the process of launching
* another application. This stub doesn't look at fromFile, doesn't consider
* the fact that the alias may point to an alias. It won't work if a full-path
* alias is supplied either.
*/
P4 (PUBLIC pascal trap, OSErr, ResolveAlias,
FSSpecPtr, fromFile, AliasHandle, alias,
FSSpecPtr, target, Boolean *, wasAliased)
{
OSErr retval;
alias_head_t *headp;
Str255 volname;
FSSpec fs;
HParamBlockRec pb;
warning_unimplemented ("stub for Launch WON'T WORK WITH FULL PATH SPEC");
retval = noErr;
headp = (typeof (headp)) STARH (alias);
str255assign (volname, headp->volumeName);
fs.parID = headp->ioDirID; /* NOT VALID IF THIS IS A FULL PATH SPEC */
str255assign (fs.name, headp->fileName);
pb.volumeParam.ioNamePtr = (StringPtr) RM ((Ptr) volname);
pb.volumeParam.ioVolIndex = CLC (-1);
pb.volumeParam.ioVRefNum = 0;
retval = PBHGetVInfo (&pb, FALSE);
if (retval == noErr)
{
fs.vRefNum = pb.volumeParam.ioVRefNum;
*wasAliased = FALSE;
*target = fs;
}
return retval;
}
P4 (PUBLIC pascal trap, OSErr, ResolveAliasFile,
FSSpecPtr, theSpec, Boolean, resolveAliasChains,
Boolean *, targetIsFolder, Boolean *, wasAliased)
{
HParamBlockRec hpb;
OSErr retval;
memset (&hpb, 0, sizeof hpb);
hpb.fileParam.ioNamePtr = (StringPtr) RM ((Ptr) theSpec->name);
hpb.fileParam.ioDirID = theSpec->parID;
hpb.fileParam.ioVRefNum = theSpec->vRefNum;
retval = PBHGetFInfo (&hpb, FALSE);
if (retval == noErr)
{
*targetIsFolder = !!(hpb.fileParam.ioFlAttrib & ATTRIB_ISADIR);
*wasAliased = FALSE;
}
warning_unimplemented ("'%.*s' retval = %d, isFolder = %d", theSpec->name[0],
theSpec->name+1, retval, *targetIsFolder);
return retval;
}
P8 (PUBLIC pascal trap, OSErr, MatchAlias,
FSSpecPtr, fromFile, int32, rulesMask,
AliasHandle, alias, int16 *, aliasCount,
FSSpecArrayPtr, aliasList, Boolean *, needsUpdate,
AliasFilterProcPtr, aliasFilter,
Ptr, yourDataPtr)
{
warning_unimplemented (NULL_STRING);
return paramErr;
}
P3 (PUBLIC pascal trap, OSErr, GetAliasInfo,
AliasHandle, alias, AliasTypeInfo, index,
Str63, theString)
{
warning_unimplemented (NULL_STRING);
return paramErr;
}
PRIVATE int
EVENUP (n)
{
int retval;
retval = n;
if (retval & 1)
++retval;
return retval;
}
#if 0
PRIVATE OSErr
parse2 (AliasHandle ah, const void *addrs[], int count)
{
OSErr retval;
Size size;
size = GetHandleSize ((Handle) ah);
if (size < sizeof (alias_head_t) + sizeof (INTEGER))
retval = paramErr;
else if (count < 0)
retval = paramErr;
else
{
const alias_head_t *headp;
const INTEGER *partp, *ep;
headp = (alias_head_t *) STARH (ah);
partp = (INTEGER *) (&headp[1]);
ep = (INTEGER *) ((char *) headp + MIN (size, CW (headp->length)));
memset (addrs, 0, count * sizeof addrs[0]);
for (; partp < ep && *partp != CWC (-1);
partp = (INTEGER *) ((char *) partp + EVENUP (4 + CW (partp[1]))))
{
int part;
part = CW (*partp);
if (part < count)
addrs[part] = partp + 1;
}
retval = *partp == CWC (-1) ? noErr : paramErr;
}
return retval;
}
#endif
PRIVATE OSErr
decompose_full_path (INTEGER path_len, Ptr fullPath, Str27 volumeName,
Str31 fileName)
{
OSErr retval;
char *first_colon;
char *last_colon;
char *p, *ep;
int volume_len;
int file_len;
for (p = (char *) fullPath,
ep = p + path_len, first_colon = 0, last_colon = 0;
p != ep;
++p)
{
if (*p == ':')
{
if (!first_colon)
first_colon = p;
last_colon = p;
}
}
if (!first_colon)
retval = paramErr;
else
{
volume_len = first_colon - (char *) fullPath;
file_len = ep - last_colon - 1;
if (volume_len > 27 || file_len > 31)
retval = paramErr;
else
{
volumeName[0] = volume_len;
memcpy (volumeName+1, fullPath, volume_len);
fileName[0] = file_len;
memcpy (fileName+1, last_colon + 1, file_len);
retval = noErr;
}
}
return retval;
}
PRIVATE void
init_head (alias_head_t *headp, Str27 volumeName, Str31 fileName)
{
memset (headp, 0, sizeof *headp);
headp->usually_2 = CWC (2);
memcpy (headp->volumeName, volumeName, volumeName[0]+1);
memcpy (headp->fileName, fileName, fileName[0]+1);
headp->mystery_words[0] = CWC (-1);
headp->mystery_words[1] = CWC (-1);
headp->mystery_words[3] = CWC (17);
}
PRIVATE void
init_tail (alias_tail_t *tailp, Str32 zoneName, Str31 serverName,
Str27 volumeName)
{
Handle h;
memset (tailp, 0, sizeof *tailp);
memcpy (tailp->zone, zoneName, zoneName[0]+1);
memcpy (tailp->server, serverName, serverName[0]+1);
memcpy (tailp->volumeName, volumeName, volumeName[0]+1);
h = (Handle) GetString (-16096);
if (!h)
tailp->network_identity_owner_name[0] = 0;
else
{
int name_len;
name_len = MIN (GetHandleSize (h), 31);
memcpy (tailp->network_identity_owner_name, STARH (h), name_len);
}
tailp->weird_info[ 0] = CWC (0x00A8);
tailp->weird_info[ 1] = CWC (0x6166);
tailp->weird_info[ 2] = CWC (0x706D);
tailp->weird_info[ 5] = CWC (0x0003);
tailp->weird_info[ 6] = CWC (0x0018);
tailp->weird_info[ 7] = CWC (0x0039);
tailp->weird_info[ 8] = CWC (0x0059);
tailp->weird_info[ 9] = CWC (0x0075);
tailp->weird_info[10] = CWC (0x0095);
tailp->weird_info[11] = CWC (0x009E);
}
PRIVATE OSErr
assemble_pieces (AliasHandle *ahp, alias_head_t *headp, INTEGER n_pieces, ...)
{
Size n_bytes_needed;
va_list va;
int i;
Handle h;
OSErr retval;
n_bytes_needed = sizeof *headp;
va_start (va, n_pieces);
for (i = 0; i < n_pieces; ++i)
{
INTEGER tag;
INTEGER length;
void *p;
tag = va_arg (va, int);
length = va_arg (va, int);
p = va_arg (va, void *);
n_bytes_needed += sizeof (INTEGER) + sizeof (INTEGER) + EVENUP (length);
}
va_end (va);
n_bytes_needed += sizeof (INTEGER) + sizeof (INTEGER);
h = NewHandle (n_bytes_needed);
if (!h)
retval = MemError ();
else
{
char *op;
headp->length = n_bytes_needed;
op = (char *) STARH (h);
memcpy (op, headp, sizeof (*headp));
op += sizeof (*headp);
va_start (va, n_pieces);
for (i = 0; i < n_pieces; ++i)
{
INTEGER tag, tag_x;
INTEGER length, length_x;
void *p;
tag = va_arg (va, int);
tag_x = CW (tag);
length = va_arg (va, int);
length_x = CW (length);
p = va_arg (va, void *);
memcpy (op, &tag_x, sizeof tag_x);
op += sizeof tag_x;
memcpy (op, &length_x, sizeof length_x);
op += sizeof length_x;
memcpy (op, p, length);
op += length;
if (length & 1)
*op++ = 0;
}
va_end (va);
memset (op, -1, sizeof (INTEGER));
op += sizeof (INTEGER);
memset (op, 0, sizeof (INTEGER));
*ahp = (AliasHandle) RM (h);
retval = noErr;
}
return retval;
}
/*
FULL_PATH_TAG, path_len, fullPath,
TAIL_TAG , sizeof (tail)-2, &tail.weird_info)
*/
P5 (PUBLIC pascal trap, OSErr, NewAliasMinimalFromFullPath,
INTEGER, path_len, Ptr, fullPath, Str32, zoneName, Str31, serverName,
AliasHandle *, ahp)
{
OSErr retval;
warning_unimplemented ("not tested much");
if (zoneName[0] > 32 || serverName[0] > 31 || !ahp)
retval = paramErr;
else
{
Str27 volumeName;
Str63 fileName;
retval = decompose_full_path (path_len, fullPath, volumeName, fileName);
if (retval == noErr)
{
alias_head_t head;
alias_tail_t tail;
init_head (&head, volumeName, fileName);
if (volumeName[0] < 27)
head.volumeName[volumeName[0]+1] = ':';
head.zero_or_one = CWC (1);
head.zero_or_neg_one = CLC (-1);
head.ioDirID = CLC (-1);
head.ioFlCrDat = CLC (0);
init_tail (&tail, zoneName, serverName, volumeName);
retval = assemble_pieces (ahp, &head, 2,
FULL_PATH_TAG, path_len, (void *) fullPath,
TAIL_TAG , (int) sizeof (tail)-2,
(void *) &tail.weird_info);
}
}
if (retval != noErr)
*ahp = NULL;
return retval;
}
P2 (PUBLIC pascal trap, OSErr, NewAliasMinimal,
FSSpecPtr, fsp, AliasHandle *, ahp)
{
HParamBlockRec hpb;
OSErr retval;
Str27 volName;
warning_unimplemented ("not tested much");
memset (&hpb, 0, sizeof hpb);
hpb.ioParam.ioNamePtr = RM (&volName[0]);
hpb.ioParam.ioVRefNum = fsp->vRefNum;
retval = PBHGetVInfo (&hpb, FALSE);
if (retval == noErr)
{
alias_head_t head;
init_head (&head, volName, fsp->name);
head.ioVCrDate = hpb.volumeParam.ioVCrDate;
head.ioVSigWord = hpb.volumeParam.ioVSigWord;
memset (&hpb, 0, sizeof hpb);
hpb.ioParam.ioNamePtr = RM (&fsp->name[0]);
hpb.ioParam.ioVRefNum = fsp->vRefNum;
hpb.fileParam.ioDirID = fsp->parID;
retval = PBHGetFInfo (&hpb, FALSE);
if (retval == noErr)
{
alias_tail_t tail;
Handle h;
Str31 serverName;
head.ioDirID = hpb.fileParam.ioDirID;
head.ioFlCrDat = hpb.fileParam.ioFlCrDat;
head.type_info = hpb.fileParam.ioFlFndrInfo.fdType;
head.creator = hpb.fileParam.ioFlFndrInfo.fdCreator;
h = (Handle) GetString (-16413);
if (!h)
serverName[0] = 0;
else
{
int len;
len = MIN (GetHandleSize (h), 32);
memcpy (serverName, STARH (h), len);
}
init_tail (&tail, (StringPtr) "\1*", serverName, volName);
retval = assemble_pieces (ahp, &head, 1,
TAIL_TAG, (int) sizeof (tail)-2,
(void *) &tail.weird_info);
}
}
if (retval != noErr)
*ahp = NULL;
return retval;
}