ExtendScript Oddity with File/Folder on Mac OS X

Contributor ,
Feb 05, 2012 Feb 05, 2012

Copy link to clipboard

Copied

Here's a really odd one, happens on Mac OS X Lion 10.7.3 with InDesign CS5.5.

Enter the following little InDesign Script in ExtendScript Toolkit, and run it targeting InDesign CS5.5:

// Create a path of the form /Users/kris/Desktop or something similar, then resolve the path back to a File object

var fn = File(File("~").fsName + "/Desktop");

alert(fn.fsName + " exists: " + fn.exists);

If all is well, you get a dialog saying something like "/Users/kris/Desktop exists: true".

Nothing weird yet. Leave ExtendScript Toolkit running for a sec.

Now start up a Terminal window, and go to the /Volumes folder. Create a subfolder called Users (so  that the folder /Volumes/Users exists on your computer).

Re-run the script.

Weirdness: I get "/Volumes/Users/kris/Desktop exists: false". Euh?

Anyone seen that before? Don't forget to remove "/Volumes/Users" again!

It is probably related to another weirdness. Run this one-liner:

alert(File("///").fsName);

You'll get "/Volumes" - but you'd expect to get "/", no?

TOPICS
Scripting

Views

14.2K

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Weird stuff! It happens on Snow Leopard as well...

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Weird.

Is this just idle experimentation?  The Folder Class Folder.desktop (http://jongware.mit.edu/idcs5/pc_Folder.html) points directly to your desktop -- Windows compatible as well (I'm not sure your "~" notation is).

I don't know much about the low-level organization of Unix-style disk mountings, but isn't "/Volumes" more of a virtual construct by the OS than a physical one? Not at work today else I'd try (Dutch railroad made me wait for more than an hour last week 'cause of 1 inch of snow -- huh! "Extreme circumstances"! -- and now I have a severe headcold), but I think using plain "/" on a Windows set would bring you just to the root of the current drive, and I don't think there is a way to get a list of "mounted volumes" under Windows. The Mac solution, providing a higher-than-root-dir entry called Volumes solves this.

As for your "Users" question, well, you might be pushing against the boundaries of what's wise 😉 Folder names such as 'users' (lowercase) have special meanings in any OS, and trying to fiddle with Case Variations ("uSers", "deskTOP") may not only confuse ExtendScript -- which, remember, tries to mediate between Windows and Mac system folders -- but utlimately may bring down your Mac as well.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Hi Jongware!

Ignore the "~" stuff or the fact that I am using "/Users" to demonstrate it - it's my way to get the issue demonstrated in two lines.

I just tested some more: if I create any folder in the hard disk's root (e.g. /MyFolder) and put some file (e.g. test.txt) into it, there is no problem. Then, when I create the totally unrelated folder /Volumes/MyFolder, I suddenly get strange behavior, because for some odd reason, the ExtendScript path resolver prefers "/Volumes/MyFolder" instead of "/MyFolder" as a match to the expression "/MyFolder."

The thing is that "/whateveryouwant" gets resolved incorrectly on Mac OS X whenever there is a /Volumes/whateveryouwant folder. It gets resolved correctly if there is no /Volumes/whateveryouwant folder.

In other words, a constant string path gets interpreted differently dependent on the existence or non-existence of a seemingly unrelated folder. Internally, the algorithm that resolves a string path into a File or Folder object is using some incorrect logic, IMHO.

To try it out: create directory "/MyFolder", create a file "/MyFolder/text.txt" (keep in mind, we're not discussing whether that is wise or not - that's another discussion).

Now run

f = File("/MyFolder/test.txt");

alert(f.exists);

You get 'true'. Ok

Now create the directory "/Volumes/MyFolder" and re-run the same script

You get 'false'.

Now, before you say "Don't create any folders in /Volumes, then!" - the problem is that our users do this all the time! E.g. they have a USB drive called 'Users'. They insert it - KABOOM! Suddenly our scripts lose access to /Users/... because inserting that USB drive created the mount point /Volumes/Users. So, no - it's not idle experimentation. It's blood, sweat and tears 😞

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Yeah. This seems to me a pretty major bug in ExtendScript (it's not limited to InDesign).

I'd log this bugger, and bug someone at Adobe to get this fixed. I wish I knew who to bug about that...

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

There's a whole section about this in the Guide. Seems vaguely relevant...

Volume and drive names

A volume or drive name can be the first part of an absolute path in URI

notation. The values are interpreted

according to the platform.

Mac OS volumes

When Mac OS X starts, the startup volume is the root directory of the

file system. All other volumes,

including remote volumes, are part of the /Volumes directory. The File

and Folder objects use these

rules to interpret the first element of a path name:

➤ If the name is the name of the startup volume, discard it.

➤ If the name is a volume name, prepend /Volumes.

➤ Otherwise, leave the path as is.

Ariel

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Interesting. Faulty logic if you ask me...

This seems to be a workable workaround assuming there's a good way of discovering the root volume name: (any suggestions on that front?)

var rootName = "Gabe";

var fn = File(File("~").fsName + "/Desktop");

alert(fn.fsName + " exists: " + fn.exists);

fn = File(fn.fsName.replace(/^\/Volumes/,"/" + rootName));

alert(fn.fsName + " exists: " + fn.exists);

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

...assuming there's a good way of discovering the root volume name: (any suggestions on that front?)

var rootName = app.doScript("tell application \"Finder\" to return name of startup disk", ScriptLanguage.APPLESCRIPT_LANGUAGE);

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Thanks Jeff.

Yes. That'll work nicely for InDesign. Of course only InDesign has doScript(). I suppose system() will work for the apps that support that.

I wonder if there's an environment variable which stores the startup disk name...

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

var f = File("///").parent;

alert(f.displayName);

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Very nice!

So I guess the "solution" is something like this:

var fn = normalizeFilePath(File(File("~").fsName + "/Desktop"));

function normalizeFilePath(file){

          if(File.fs != "Macintosh"){return file}

          return File(file.fsName.replace(/^\/Volumes/,"/" + File("///").parent.displayName));

}

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Mar 03, 2015 Mar 03, 2015

Copy link to clipboard

Copied

Thanks for pointing out at File and Folder handle paths differently so you can get the username from File.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Building on Harb's solution: a wrapper for 'new File'. Haven't tested it extensively yet, and I am not sure it's covering all the bases, so take it for what it's worth:

function newFile(filePath)

{

          do

          {

                    try

                    {

                              var retVal = new File(filePath);

                              if (File.fs != "Macintosh")

                              {

                                        break;

                              }

 

                              if (retVal.fsName == filePath)

                              {

                                        break;

                              }

 

                              var rootVolumeName = File("/").parent.displayName;

                              retVal = new File(retVal.fsName.replace(/^\/Volumes\//,"/" + rootVolumeName + "/"));

                    }

                    catch (error)

                    {

                              retVal = null;

                    }

          }

          while (false);

 

          return retVal;

}



Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Funny. Nearly identical, eh!

I tried to make sure that any 'legal' accesses to /Volumes are also covered (whether ill-advised or not).

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

RorohikoKris wrote:

I tried to make sure that any 'legal' accesses to /Volumes are also covered (whether ill-advised or not).

Yeah. I noticed that. Nice touch.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

Looks pretty good to me. The only way I can see breaking this, is if there's more bugs that'll change the file path that we don't know about...

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

I'm still a bit groggy due to aformentioned PT shenanigans (now they're discussing reduced services the entire week, can you believe it!) but is this related to last month's thread on the Illustrator forum?

"Error on opening file after upgrade to Lion" -- http://forums.adobe.com/thread/938672?tstart=0

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 06, 2012 Feb 06, 2012

Copy link to clipboard

Copied

[Jongware] wrote:

...but is this related to last month's thread on the Illustrator forum?

Nope. This is not Lion specific, and it has nothing to do with a file prefix. Nothing to do with openDialog() either...

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Feb 09, 2012 Feb 09, 2012

Copy link to clipboard

Copied

It seems the Folder.create() function is immune to this hack.

I can successfully reference a folder object on my desktop using the hack function:

          var folder = Folder(newFile("~/Desktop/Test"));

But if you still have a Users folder in your Volumes, calling:

          folder.create();

Will return true but won't create the folder on the desktop.

Where was it created? In the /Volumes/Users directory!

=> /Volumes/Users/[USERNAME]/Desktop/Test

Joris

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 09, 2012 Feb 09, 2012

Copy link to clipboard

Copied

Hi Joris,

Ugh! I just tried using changePath() to try to move the folder to the correct location afterwards, but it does not seem to work as I'd hoped...

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 09, 2012 Feb 09, 2012

Copy link to clipboard

Copied

I guess using AppleScript to create the folder would be a workaround, but all this stuff is pretty bad...

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Feb 09, 2012 Feb 09, 2012

Copy link to clipboard

Copied

Try this wrapper for new Folder(...):

function newFolder(filePath)

{

    var retVal;

    do

    {

        try

        {

            if (File.fs != "Macintosh")

            {

                break;

            }

            if (filePath.match(/^\/Volumes\//i) != null)

            {

                break;

            }

            if (filePath.charAt(0) == "~")

            {

                filePath = File("~").fsName + filePath.substr(1);

            }

            else if (filePath.charAt(0) != "/")

            {

                break;

            }

            var rootVolumeName = File("/").parent.displayName;

            retVal = new Folder("/Volumes/" + rootVolumeName + "/" + filePath);

        }

        catch (error)

        {

        }

    }

    while (false);

    if (retVal == null)

    {

        retVal = new Folder(filePath);

    }

    return retVal;

}

If /Volumes/Users exists on my system so it interferes with the ExtendScript file handling, then:

var folder = new Folder("~/Desktop/Test");

folder.create();

fails, but

var folder = newFolder("~/Desktop/Test");

folder.create();

succeeds

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Feb 14, 2012 Feb 14, 2012

Copy link to clipboard

Copied

That works!

I modified both functions a little bit to work for the following test cases:

  • NewFolder("~/Desktop/TestFolder");
  • NewFolder("/Users/[USERNAME]/Desktop/TestFolder");
  • NewFolder("/Volumes/[ROOTVOLUME]/Users/[USERNAME]/Desktop/TestFolder");
  • NewFolder("/[ROOTVOLUME]/Users/[USERNAME]/Desktop/TestFolder");

  • NewFile("~/Desktop/TestFile.txt");
  • NewFile("/Users/[USERNAME]/Desktop/TestFile.txt");
  • NewFile("/Volumes/[ROOTVOLUME]/Users/[USERNAME]/Desktop/TestFile.txt");
  • NewFile("/[ROOTVOLUME]/Users/[USERNAME]/Desktop/TestFile.txt");

They also work with legal accesses, (if you actually wanted to create something at /Volumes/Users)

  i.e:

  • NewFolder("/Volumes/Users/TestFolder");
  • NewFile("/Volumes/Users/TestFile.txt");

You can also use them correctly in combination with File/Folder objects:

  i.e:

  var folder = NewFolder("~/Desktop/TestFolder");

  var sameFolder = NewFolder(folder);

  var folder = NewFolder("~/Desktop/TestFolder");

  var file = NewFile(folder + "/TestFile.txt");

Functions:

function NewFile(in_path)

{

 

  var file;

 

  try

  {

    do

    {

     

      if (in_path instanceof File)

        var path = in_path.absoluteURI;

      else if (in_path instanceof Folder)

        var path = in_path.absoluteURI;

      else

        var path = in_path;

     

      file = new File(path)

     

      if (File.fs != "Macintosh")

        break;

     

      var filePath = file.fsName;

      if (filePath == path) // File path wasn't changed by Extendscript

        break;

     

      if (filePath.match(/^\/Volumes\//i) == null) // File path isn't a Volumes path

        break;

     

      var rootVolumeName = File("/").parent.displayName;

      filePath = filePath.replace(/^\/Volumes\//,"/" + rootVolumeName + "/")

     

      file = new File(filePath);

     

    }

    while (false);

  }

  catch (err)

  {

    file = null;

  }

 

  return file;

 

}

// ******************************

function NewFolder(in_path)

{

 

  var folder;

 

  try

  {

    do

    {

     

     

      if (in_path instanceof File)

        var path = in_path.absoluteURI;

      else if (in_path instanceof Folder)

        var path = in_path.absoluteURI;

      else

        var path = in_path;

     

      folder = new Folder(path)

     

      if (File.fs != "Macintosh")

        break;

     

      var folderPath = folder.fsName;

      if (folderPath == path) // Folder path wasn't changed by Extendscript

        break;

     

      if (path.charAt(0) == "~")

        path = File("~").fsName + path.substr(1);

     

      if (path.charAt(0) != "/") // Not an absolute path

        break;

     

      var rootVolumeName = File("/").parent.displayName;

      folder = new Folder("/Volumes/" + rootVolumeName + path);

     

    }

    while (false);

  }

  catch (err)

  {

    folder = null;

  }

 

  return folder;

 

}

Joris

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 15, 2012 Feb 15, 2012

Copy link to clipboard

Copied

Great stuff!

Harbs

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 12, 2020 Jun 12, 2020

Copy link to clipboard

Copied

8 years later and I encounter the same problem. Thank you Kris and Joris!

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines