0

My code sometimes gets paths that point to the secondary volume of a volume group.

For instance, on a Catalina or Big Sur startup volume, where there's a System and a Data role member, I may have a path such as:

/System/Volumes/Data/usr/local/bin

The regular ("normalized") path would be:

/usr/local/bin

How do I turn the first path into the second, using available macOS framework functions (Obj-C or Swift)?

Note that I don't want to simply hard-code a string replacement for this, because, at least on Big Sur, the same also happens with other mounted volumes that are in a group. For instance, I may have another bootable system with 10.15, whose volume is named "Catalina", and the two volumes then would appear as:

System: /Volumes/Catalina Data: /Volumes/Catalina - Data

Now, if I get a path like /Volumes/Catalina - Data/Users/Shared, I want to normalize that into /Volumes/Catalina/Users/Shared.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149

2 Answers2

1

NSStrings resolvingsymlinksinpath method should do the trick!

Given let path:String = "/System/Volumes/Data/Users/":

(lldb) po path
"/System/Volumes/Data/Users/"

(lldb) po (path as NSString).resolvingSymlinksInPath
"/Users"
patrick
  • 380
  • 2
  • 14
  • Right. Actually, I was also wrong saying that NSURLCanonicalPathKey and URLByStandardizingPath would not work (I'll fix that). They do work, just not for the one path of "/System/Volumes/Data" (which I expected to become "/"). – Thomas Tempelmann Nov 06 '20 at 19:38
1

Beside Patrick's answer, here are a few alternatives that should work as well:

// macOS 10.12 and later:
NSString *normalizedPath;
[url getResourceValue:&normalizedPath forKey:NSURLCanonicalPathKey error:nil];

// pre-10.12:
NSURL *normalizedURL = url.fileReferenceURL.filePathURL;

Also, the fcntl call F_GETPATH_NOFIRMLINK should work for this.

What does not work, though, is [NSURL URLByStandardizingPath]

Just be aware that the root of the firmlinked volume, e.g. /System/Volumes/Data, won't lead to / as one might have hoped. This one path requires special handling, i.e. one needs to detect that it's a volume (NSURLIsVolumeKey) and if so, determine its "master" member. See https://stackoverflow.com/a/63886185/43615 for a way to accomplish that part.

For determining the normalized path in a shell (Terminal), see https://superuser.com/a/1490999/41872

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149