QString QFileInfo::readLink() const
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
    char s[PATH_MAX+1];
    if ( !isSymLink() )
	return QString();
    int len = readlink( QFile::encodeName(fn).data(), s, PATH_MAX );
    if ( len >= 0 ) {
	s[len] = '\0';
	return QFile::decodeName(s);
    }
#endif
#if !defined(QWS) && defined(Q_OS_MAC)
    {
        FSRef fref;
        if(FSPathMakeRef((const UInt8 *)QFile::encodeName(fn).data(), &fref, NULL) == noErr) {
            Boolean isAlias, isFolder;
            if(FSResolveAliasFile(&fref, TRUE, &isFolder, &isAlias) == noErr && isAlias) {
                AliasHandle alias;
                if(FSNewAlias(0, &fref, &alias) == noErr && alias) {
                    CFStringRef cfstr;
                    if(FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr) {
                        QString cfstring2qstring(CFStringRef str); //qglobal.cpp
                        return cfstring2qstring(cfstr);
                    }
                }
            }
        }
    }
#endif
    return QString();
}
Exemple #2
0
void
rbobj_to_alias_handle (VALUE obj, AliasHandle *alias)
{
    FSRef       ref;
    CFURLRef    URL;
    Boolean     ok;
    OSErr       error;

    Check_Type (obj, T_STRING);
    *alias = NULL;

    URL = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, 
                                                   (const UInt8 *)RSTRING (obj)->ptr, 
                                                   RSTRING (obj)->len,
                                                   0 /* XXX: normally passing 0 even if it's a directory should
                                                        not hurt, as we are just getting the FSRef. */); 
    if (URL == NULL)
        rb_raise (rb_eArgError, "Invalid path given");
    ok = CFURLGetFSRef (URL, &ref);
    CFRelease (URL);
    if (ok) {
        error = FSNewAlias (NULL, &ref, alias);
        if (error != noErr)
            rb_raise (rb_eArgError, "Cannot create alias handle for given filename '%s' : %s (%d)",
                      RSTRING (obj)->ptr, GetMacOSStatusErrorString (error), error); 
    }
    else {
        rb_raise (rb_eArgError, "Cannot obtain the filesystem reference for given filename '%s'",
                  RSTRING (obj)->ptr);
    }
}
Exemple #3
0
/********************************************************************************
	Add a parameter of type typeAlias to an AERecord (or AppleEvent) using the provided FSRef.

	pFSRef			input:	Pointer to the FSRef to use.
	pKeyword		input:	The key for the data to be added to the record.
	pAERecord		input:	Pointer to the record (or event) to add the data to.
	
	RESULT CODES
	____________
	noErr			   0	No error	
	paramErr		 -50	The value of target or alias parameter, or of
							both, is NIL, or the alias record is corrupt
	memFullErr		-108	Not enough room in heap zone	
*/
pascal	OSErr	MoreAEOAddAliasParameterFromFSRef(const FSRefPtr pFSRef,
												const DescType pKeyword,
												AERecord *pAERecord )
{
	OSErr			anErr = noErr;
	AliasHandle		tAliasHandle;

	anErr = FSNewAlias( NULL, pFSRef, &tAliasHandle);

	if ( noErr == anErr  &&  tAliasHandle == NULL )
	{
		anErr = paramErr;
	}
	
	if ( noErr == anErr )
	{
		char	handleState;
		
		handleState = HGetState((Handle) tAliasHandle );
		HLock((Handle) tAliasHandle );
		
		anErr = AEPutParamPtr( pAERecord, pKeyword, typeAlias,
							   *tAliasHandle, (*tAliasHandle)->aliasSize);
		
		HSetState( (Handle)tAliasHandle, handleState );
		DisposeHandle( (Handle)tAliasHandle );
	}
		
	return anErr;
}//end MoreAEOAddAliasParameterFromFSRef
Exemple #4
0
/********************************************************************************
	Create and return an AEDesc of type typeAlias using the provided FSRef.

	pFSRef			input:	Pointer to the FSRef to use.
	pAliasAEDesc	input:	Pointer to null AEDesc.
					output:	an AEDesc of type typeAlias.
	
	RESULT CODES
	____________
	noErr			   0	No error	
	paramErr		 -50	The value of target or alias parameter, or of
							both, is NIL, or the alias record is corrupt
	memFullErr		-108	Not enough room in heap zone	
*/
pascal	OSErr	MoreAEOCreateAliasDescFromFSRef( const FSRefPtr pFSRef,
												  AEDesc *pAliasAEDesc )
{
	OSErr			anErr = noErr;
	AliasHandle		tAliasHandle;
	
	anErr = FSNewAlias( NULL, pFSRef, &tAliasHandle);
	if ( noErr == anErr  &&  tAliasHandle == NULL )
	{
		anErr = paramErr;
	}

	if ( noErr == anErr )
	{
		anErr = MoreAEOCreateAliasDesc( tAliasHandle, pAliasAEDesc );
		DisposeHandle( (Handle)tAliasHandle );
	}
		
	return anErr;
}//end MoreAEOCreateAliasDescFromFSRef
CFDictionaryRef createDockDescriptionForURL(CFURLRef url) {
	if (!url) {
		NSLog(CFSTR("%@"), CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: Cannot copy Dock description for a NULL URL"));
		return NULL;
	}

	//return NULL for non-file: URLs.
	CFStringRef scheme = CFURLCopyScheme(url);
	Boolean isFileURL = (CFStringCompare(scheme, CFSTR("file"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
	CFRelease(scheme);
	if (!isFileURL)
		return NULL;

	CFDictionaryRef dict = NULL;
	CFStringRef path     = NULL;
	CFDataRef aliasData  = NULL;

	FSRef    fsref;
	if (CFURLGetFSRef(url, &fsref)) {
		AliasHandle alias = NULL;
		OSStatus    err   = FSNewAlias(/*fromFile*/ NULL, &fsref, &alias);
		if (err != noErr) {
			NSLog(CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: FSNewAlias for %@ returned %li"), url, (long)err);
		} else {
			HLock((Handle)alias);

			err = FSCopyAliasInfo(alias, /*targetName*/ NULL, /*volumeName*/ NULL, (CFStringRef *)&path, /*whichInfo*/ NULL, /*info*/ NULL);
			if (err != noErr) {
				NSLog(CFSTR("in copyDockDescriptionForURL in CFGrowlAdditions: FSCopyAliasInfo for %@ returned %li"), url, (long)err);
			}

			aliasData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)*alias, GetHandleSize((Handle)alias));

			HUnlock((Handle)alias);
			DisposeHandle((Handle)alias);
		}
	}

	if (!path) {
		path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
	}

	if (path || aliasData) {
		CFMutableDictionaryRef temp = CFDictionaryCreateMutable(kCFAllocatorDefault, /*capacity*/ 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

		if (path) {
			CFDictionarySetValue(temp, _CFURLStringKey, path);
			CFRelease(path);

			int pathStyle = kCFURLPOSIXPathStyle;
			CFNumberRef pathStyleNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pathStyle);
			CFDictionarySetValue(temp, _CFURLStringTypeKey, pathStyleNum);
			CFRelease(pathStyleNum);
		}

		if (aliasData) {
			CFDictionarySetValue(temp, _CFURLAliasDataKey, aliasData);
			CFRelease(aliasData);
		}

		dict = temp;
	}

	return dict;
}
QString QFSFileEngine::fileName(FileName file) const
{
    Q_D(const QFSFileEngine);
    if (file == BundleName) {
#if !defined(QWS) && defined(Q_OS_MAC)
        QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(d->filePath),
                                                              kCFURLPOSIXPathStyle, true);
        if(CFDictionaryRef dict = CFBundleCopyInfoDictionaryForURL(url)) {
            if(CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
                if(CFGetTypeID(name) == CFStringGetTypeID())
                    return QCFString::toQString((CFStringRef)name);
            }
        }
#endif
        return QString();
    } else if (file == BaseName) {
        int slash = d->filePath.lastIndexOf(QLatin1Char('/'));
        if (slash != -1)
            return d->filePath.mid(slash + 1);
    } else if (file == PathName) {
        int slash = d->filePath.lastIndexOf(QLatin1Char('/'));
        if (slash == -1)
            return QLatin1String(".");
        else if (!slash)
            return QLatin1String("/");
        return d->filePath.left(slash);
    } else if (file == AbsoluteName || file == AbsolutePathName) {
        QString ret;
        if (d->filePath.isEmpty() || !d->filePath.startsWith(QLatin1Char('/')))
            ret = QDir::currentPath();
        if (!d->filePath.isEmpty() && d->filePath != QLatin1String(".")) {
            if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
                ret += QLatin1Char('/');
            ret += d->filePath;
        }
        if (ret == QLatin1String("/"))
            return ret;
        bool isDir = ret.endsWith(QLatin1Char('/'));
        ret = QDir::cleanPath(ret);
        if (isDir)
            ret += QLatin1String("/");
        if (file == AbsolutePathName) {
            int slash = ret.lastIndexOf(QLatin1Char('/'));
            if (slash == -1)
                return QDir::currentPath();
            else if (!slash)
                return QLatin1String("/");
            return ret.left(slash);
        }
        return ret;
    } else if (file == CanonicalName || file == CanonicalPathName) {
        if (!(fileFlags(ExistsFlag) & ExistsFlag))
            return QString();

        QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName));
        if (!ret.isEmpty() && file == CanonicalPathName) {
            int slash = ret.lastIndexOf(QLatin1Char('/'));
            if (slash == -1)
                ret = QDir::currentPath();
            else if (slash == 0)
                ret = QLatin1String("/");
            ret = ret.left(slash);
        }
        return ret;
    } else if (file == LinkName) {
        if (d->isSymlink()) {
#if defined(__GLIBC__) && !defined(PATH_MAX)
#define PATH_CHUNK_SIZE 256
            char *s = 0;
            int len = -1;
            int size = PATH_CHUNK_SIZE;

            while (1) {
                s = (char *) ::realloc(s, size);
                if (s == 0) {
                    len = -1;
                    break;
                }
                len = ::readlink(d->nativeFilePath.constData(), s, size);
                if (len < 0) {
                    ::free(s);
                    break;
                }
                if (len < size) {
                    break;
                }
                size *= 2;
            }
#else
            char s[PATH_MAX+1];
            int len = readlink(d->nativeFilePath.constData(), s, PATH_MAX);
#endif
            if (len > 0) {
                QString ret;
                if (S_ISDIR(d->st.st_mode) && s[0] != '/') {
                    QDir parent(d->filePath);
                    parent.cdUp();
                    ret = parent.path();
                    if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
                        ret += QLatin1Char('/');
                }
                s[len] = '\0';
                ret += QFile::decodeName(QByteArray(s));
#if defined(__GLIBC__) && !defined(PATH_MAX)
		::free(s);
#endif

                if (!ret.startsWith(QLatin1Char('/'))) {
                    if (d->filePath.startsWith(QLatin1Char('/'))) {
                        ret.prepend(d->filePath.left(d->filePath.lastIndexOf(QLatin1Char('/')))
                                    + QLatin1Char('/'));
                    } else {
                        ret.prepend(QDir::currentPath() + QLatin1Char('/'));
                    }
                }
                ret = QDir::cleanPath(ret);
                if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
                    ret.chop(1);
                return ret;
            }
        }
#if !defined(QWS) && defined(Q_OS_MAC)
        {
            FSRef fref;
            if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(d->filePath)).data(), &fref, 0) == noErr) {
                Boolean isAlias, isFolder;
                if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) {
                    AliasHandle alias;
                    if (FSNewAlias(0, &fref, &alias) == noErr && alias) {
                        CFStringRef cfstr;
                        if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr)
                            return QCFString::toQString(cfstr);
                    }
                }
            }
        }
#endif
        return QString();
    }
    return d->filePath;
}
//static
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
{
#if defined(__GLIBC__) && !defined(PATH_MAX)
#define PATH_CHUNK_SIZE 256
    char *s = 0;
    int len = -1;
    int size = PATH_CHUNK_SIZE;

    while (1) {
        s = (char *) ::realloc(s, size);
        Q_CHECK_PTR(s);
        len = ::readlink(link.nativeFilePath().constData(), s, size);
        if (len < 0) {
            ::free(s);
            break;
        }
        if (len < size) {
            break;
        }
        size *= 2;
    }
#else
    char s[PATH_MAX+1];
    int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX);
#endif
    if (len > 0) {
        QString ret;
        if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
            fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
        if (data.isDirectory() && s[0] != '/') {
            QDir parent(link.filePath());
            parent.cdUp();
            ret = parent.path();
            if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
                ret += QLatin1Char('/');
        }
        s[len] = '\0';
        ret += QFile::decodeName(QByteArray(s));
#if defined(__GLIBC__) && !defined(PATH_MAX)
        ::free(s);
#endif

        if (!ret.startsWith(QLatin1Char('/'))) {
            if (link.filePath().startsWith(QLatin1Char('/'))) {
                ret.prepend(link.filePath().left(link.filePath().lastIndexOf(QLatin1Char('/')))
                            + QLatin1Char('/'));
            } else {
                ret.prepend(QDir::currentPath() + QLatin1Char('/'));
            }
        }
        ret = QDir::cleanPath(ret);
        if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
            ret.chop(1);
        return QFileSystemEntry(ret);
    }
#if !defined(QWS) && !defined(Q_WS_QPA) && defined(Q_OS_MAC)
    {
        FSRef fref;
        if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(link.filePath())).data(), &fref, 0) == noErr) {
            // TODO get the meta data info from the QFileSystemMetaData object
            Boolean isAlias, isFolder;
            if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) {
                AliasHandle alias;
                if (FSNewAlias(0, &fref, &alias) == noErr && alias) {
                    QCFString cfstr;
                    if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr)
                        return QFileSystemEntry(QCFString::toQString(cfstr));
                }
            }
        }
    }
#endif
    return QFileSystemEntry();
}
Exemple #8
0
//////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Given two path strings, srcPath and destPath, creates a MacOS Finder alias from file in srcPath
//  in the destPath, complete with custom icon and all.  Pretty neat.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
static void CreateAlias (char *srcPath, char *destPath)
{
  OSErr err;

  FSSpec sourceFSSpec;
  FSRef srcRef, destRef;
  OSType srcFileType = (OSType)NULL;
  OSType srcCreatorType = (OSType)NULL;
  FInfo srcFinderInfo, destFinderInfo;

  int fd;
  SInt16 rsrcRefNum;

  IconRef srcIconRef;
  IconFamilyHandle srcIconFamily;
  SInt16 theLabel;

  AliasHandle alias;
  short isSrcFolder;

  //find out if we're dealing with a folder alias
  isSrcFolder = UnixIsFolder(srcPath);
  if (isSrcFolder == -1)//error
  {
    fprintf(stderr, "UnixIsFolder(): Error doing a stat on %s\n", srcPath);
    exit(EX_IOERR);
  }

  ///////////////////// Get the FSRef's and FSSpec's for source and dest ///////////////////

  //get file ref to src
  err = FSPathMakeRef(srcPath, &srcRef, NULL);
  if (err != noErr)
  {
    fprintf(stderr, "FSPathMakeRef: Error %d getting file ref for source \"%s\"\n", err, srcPath);
    exit(EX_IOERR);
  }

  //retrieve source filespec from source file ref
  err = FSGetCatalogInfo (&srcRef, NULL, NULL, NULL, &sourceFSSpec, NULL);
  if (err != noErr)
  {
    fprintf(stderr, "FSGetCatalogInfo(): Error %d getting file spec from source FSRef\n", err);
    exit(EX_IOERR);
  }

  //get the finder info for the source if it's a folder
  if (!isSrcFolder)
  {
    err = FSGetFInfo (&srcRef, &srcFinderInfo);
    if (err != noErr)
    {
      fprintf(stderr, "FSpGetFInfo(): Error %d getting Finder info for source \"%s\"\n", err, srcPath);
      exit(EX_IOERR);
    }
    srcFileType = srcFinderInfo.fdType;
    srcCreatorType = srcFinderInfo.fdCreator;
  }

  //////////////// Get the source file's icon ///////////////////////

  if (!noCustomIconCopy)
  {
    err = GetIconRefFromFileInfo(
      &srcRef, 0, NULL, 0, NULL,
      kIconServicesNormalUsageFlag, &srcIconRef, &theLabel
    );

    if (err != noErr)
      fprintf(stderr, "GetIconRefFromFile(): Error getting source file's icon.\n");

    IconRefToIconFamily (srcIconRef, kSelectorAllAvailableData, &srcIconFamily);
  }

  ///////////////////// Create the relevant alias record ///////////////////

  if (makeRelativeAlias)
  {
    // The following code for making relative aliases was borrowed from Apple. See the following technote:
    //
    //  http://developer.apple.com/technotes/tn/tn1188.html
    //

    // create the new file
    err = myFSCreateResFile(destPath, 'TEMP', 'TEMP', &destRef);
    if (err != noErr)
    {
      fprintf(stderr, "FSpCreateResFile(): Error %d while creating file\n", err);
      exit(EX_CANTCREAT);
    }

    //create the alias record, relative to the new alias file
    err = FSNewAlias(&destRef, &srcRef, &alias);
    if (err != noErr)
    {
      fprintf(stderr, "NewAlias(): Error %d while creating relative alias\n", err);
      exit(EX_CANTCREAT);
    }

    // save the resource
    rsrcRefNum = FSOpenResFile(&destRef, fsRdWrPerm);
    if (rsrcRefNum == -1)
    {
      err = ResError();
      fprintf(stderr, "Error %d while opening resource fork for %s\n", err, (char *)&destPath);
      exit(EX_IOERR);
    }

    UseResFile(rsrcRefNum);
    Str255 rname;
    AddResource((Handle) alias, rAliasType, 0, NULL);

    if ((err = ResError()) != noErr)
    {
      fprintf(stderr, "Error %d while adding alias resource for %s", err, (char *)&destPath);
      exit(EX_IOERR);
    }
    if (!noCustomIconCopy)
    {
      //write the custom icon data
      AddResource( (Handle)srcIconFamily, kIconFamilyType, kCustomIconResource, "\p");
    }

    CloseResFile(rsrcRefNum);
  }
  else
  {
Exemple #9
0
/* alias
   -----
   Will create a Macintosh HFS  specific  alias at the path
   pointed to by dest.  The  alias  will  point to the file
   located at target. The target must exist.

   The return value is zero upon success.  If unsuccessful,
   a  non-zero value will be  returned and both  errno  and
   mac_errno should be consulted.
*/
int alias (const char *target, const char *dest)
{
   char *rtarget;
   char *destparentdir, *destname;
#ifdef HAVE_CORESERVICES
   char *targetsuffix;
   UniChar *udestname;
   FSRef *fstarget, *fsdest, *fsnewfile;
   FSCatalogInfo *fscdestinfo, *fsctargetinfo;
   FileInfo destinfo, targetinfo;
   AliasHandle aliasrec;
   u_int32_t infomap = 0;
   int resfrk;
   u_int8_t targetisdir = 0;
#endif
   u_int8_t destisdir = 0;
   size_t len = 0;

#ifndef HAVE_CORESERVICES
   /* this function is for creating macintosh aliases.
      if we don't have the CoreServices API it's impossible,
      so why fool ourselves, let's just return error now
      and save the cpu cycles for something else */

   errno = EIO; /* returning a generic I/O error */
   return errno;
#endif

   /* As of this writing,  this  function is not  complete.
      Things left to  complete are to  check the  target to
      see if it has a custom icon (if so,  copy the  custom
      to the alias file so that they appear the same. Also,
      copy custom icons of bundles to the alias.

      Another very  important thing left to  complete is to
      retire the process of making the alias  manually to a
      last resort if we cannot create the  alias by sending
      an apple event to the finder.
   */

   /* check for null parameters and return accordingly */
   if (!target || !dest) return 0;

#ifdef HAVE_CORESERVICES

   rtarget = (char *)malloc(PATH_MAX);
   if (!rtarget) return errno; /* ENOMEM */

   if (!resolve_alias(target, rtarget) || mac_errno)
      return errno;

   /* convert the target path into an FSRef */
  
   fstarget = (FSRef *)malloc(sizeof(FSRef));
   if (!fstarget) return errno; /* ENOMEM */
 
   mac_errno = FSPathMakeRef(rtarget, fstarget, &targetisdir);
   if (mac_errno) return 0;

   fsdest = (FSRef *)malloc(sizeof(FSRef));
   if (!fsdest) return errno; /* ENOMEM */

   /* convert the destination into an FSRef so that we can test if it exists
      and if it is a directory (in which we should save the new alias file
      inside the directory specified) */
   mac_errno = FSPathMakeRef(dest, fsdest, &destisdir);

#endif

   /* if the destination is not a directory, we'll disassemble the path we
      were given for the destination into a parent directory and a name */
   if (!destisdir) {

      /* obtain the name of the destination file */
      len = strlen(dest);
      destname = (char *)dest + len;
      while (destname > dest && *(destname - 1) != '/') destname--, len--;

      /* obtain the parent directory of the destination file */
      destparentdir = (char *)malloc(len);
      snprintf(destparentdir, len ? len + 1 : 3, "%s", len ? dest : "./");

   } else {

      /* the parent directory should be the destination we were passed */
      destparentdir = (char *)dest;

      /* and the name should be the real name of the target */
      destname = (char *)rtarget + strlen(rtarget);
      while (destname > rtarget && *(destname - 1) != '/') destname--;

   }

#ifdef HAVE_CORESERVICES

   /* attempt to convert the parent directory into an FSRef */
   mac_errno = FSPathMakeRef(destparentdir, fsdest, 0);
   if (mac_errno) return 0;

   /* infomap is an integer telling FSCreateResFile which settings from
      the FSCatalogInfo paramater you want to set */
   infomap |= kFSCatInfoFinderInfo;

   /* if the target is not a directory, get its file type/creator */
   if (!targetisdir) {

      fsctargetinfo = (FSCatalogInfo *)malloc(sizeof(FSCatalogInfo));
      if (!fsctargetinfo) return errno; /* ENOMEM */

      /* get the target files information */
      mac_errno = FSGetCatalogInfo(fstarget, infomap, fsctargetinfo, 0,0,0);
      if (mac_errno) return 0;

      /* I don't know why Apple did not declare the structure member
         'finderInfo' as an FileInfo type (it is an array of 16 single bytes).
         This makes it impossible to address elements of the finderInfo
         directly. So, we move it into an FileInfo data type we allocated */
      memmove(&targetinfo, fsctargetinfo->finderInfo, sizeof(FileInfo));

      /* this is not really necessary for the creation of the file, since
         a null type or creator will be transposed to '????', but should any
         functions try to display the type/creator, it is much friendlier to
         display '????' than an empty string (which hardcore mac people will
         understand better */
      if (!targetinfo.fileType) {
         targetinfo.fileType = '\?\?\?\?';
         targetinfo.fileCreator = '\?\?\?\?';
      }

   } else {

      /* folders natively return null as their file type and creator but to
         make an alias appear as a folder, we use the following settings */
      targetinfo.fileType = 'fldr';
      targetinfo.fileCreator = 'MACS';

      /* there is one exception, when the folder ends in .app it is an
         application package and should get the following settings */
      targetsuffix = suffix(rtarget);
      if (!strcmp(targetsuffix, "app")) {
         targetinfo.fileType = 'fapa';
         targetinfo.fileCreator = '\?\?\?\?';
         *--targetsuffix = '\0'; /* this will cut off the .app from the name */
      }

   }

   fscdestinfo = (FSCatalogInfo *)malloc(sizeof(FSCatalogInfo));
   if (!fscdestinfo) return errno; /* ENOMEM */

   /* set the file type, creator, and alias flag for the file */
   destinfo.fileType    = targetinfo.fileType;
   destinfo.fileCreator = targetinfo.fileCreator;
   destinfo.finderFlags = kIsAlias;
   memcpy(fscdestinfo->finderInfo, &destinfo, sizeof(FileInfo));

   fsnewfile = (FSRef *)malloc(sizeof(FSRef));
   if (!fsnewfile) return errno; /* ENOMEM */

   udestname = (UniChar *)malloc(PATH_MAX);
   len = utf8to16(destname, udestname, PATH_MAX);
   if (len < 0) return errno; /* caller: consult both errno and mac_errno */

   /* attempt to create the resource file (fails if it already exists) */
   FSCreateResFile(fsdest, len, udestname, infomap, fscdestinfo, fsnewfile, 0);

   free(udestname);

   /* test for error creating the file */
   mac_errno = ResError();
   if (mac_errno) return 0;

   /* attempt to open the resource fork of the file now */
   resfrk = FSOpenResFile(fsnewfile, fsRdWrPerm);

   /* test for errors */
   mac_errno = ResError();
   if (mac_errno) return 0;

   /* attempt to create an alias record to save in the resource file */
   mac_errno = FSNewAlias(0, fstarget, &aliasrec);
   if (mac_errno) return CloseResFile(resfrk), 0;

   /* add the alias record to the resource fork */
   AddResource((Handle)aliasrec, rAliasType, 0, 0);

   /* test for errors */
   mac_errno = ResError();
   if (mac_errno) return CloseResFile(resfrk), 0;

   /* write the resource fork data */
   WriteResource((Handle)aliasrec);

   /* test for errors */
   mac_errno = ResError();
   if (mac_errno) return CloseResFile(resfrk), 0;

   /* clean up */
   CloseResFile(resfrk);

#endif /* HAVE_CORESERVICES */

   /* return success */
   return 0;

}