/* 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 #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; }