28

NSHomeDirectory() is returning my sandbox root, not my home directory. [@"~" stringByExpandingTildeInPath] is doing the same thing.

This /Users/username/Library/Containers/appID/Data is what's being returned. How do I get /Users/username/?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Justin808
  • 20,859
  • 46
  • 160
  • 265

3 Answers3

38

If you want the path to the user's real home directory you can use:

char *realHome = getpwuid(getuid())->pw_dir;

Full example:

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <assert.h>

NSString *RealHomeDirectory() {
    struct passwd *pw = getpwuid(getuid());
    assert(pw);
    return [NSString stringWithUTF8String:pw->pw_dir];
}

This gives you the path to the user's home, but does not automatically give you access to that folder. As noted in comments, you can use this path for:

  • providing a sane default folder for the open/save dialogs
  • detecting whether you are in a sandbox, by comparing the result to NSHomeDirectory()
Andrey Tarantsov
  • 8,965
  • 7
  • 54
  • 58
CRD
  • 52,522
  • 5
  • 70
  • 86
  • 1
    The only thing its really good for is setting a sane default to the file open/save dialogs. Right now, if I set it to NSHomeDirectory() its not very user friendly. Most people don't even know what the Library folder is. – Justin808 Mar 04 '12 at 08:45
  • 1
    That's one good use, another is to test whether you're in the sandbox by comparing it to what `NSHomeDirectory()` returns, and I'm sure there are others... – CRD Mar 04 '12 at 08:52
  • 1
    And yet another is to gain access to a file via the `com.apple.security.temporary-exception.files.home-relative-path.*` temporary entitlements – Dov Apr 30 '14 at 18:07
  • I really needed that, thanks. The powerbox nsopenpanel in our app gets used to pick locations for a few different usages, we want to warm that up to a good starting point for the user. The wholescale change in meaning to all the app path commands is a travesty. – Tom Andersen Oct 15 '15 at 14:24
  • As NSUserName() should always return the right value. Wouldn't it work just fine? NSString *realHomeDir = [NSString stringWithFormat@"/Users/%@",NSUserName()]; – Tibidabo Apr 24 '17 at 07:18
  • @Tibidabo - Your suggestion will work approximately 99.99% of the time. However a users home directory need not be in `/Users` and that is why it is recommended a method is used which returns the users home directory as it will be always be correct, even for the rare 0.01% cases when it is somewhere else. (And the same applies for other standard directories for which Apple provides routines to determine their path - use the routines if they are available.) HTH – CRD Apr 24 '17 at 10:13
  • @CRD Thank you for the clarification. Actually I use this approach in one of my apps and one user complained that he couldn't use the app. It seems to be 100% I have to use your approach – Tibidabo Apr 24 '17 at 10:38
12

From apple documentation:

Accessing User Data

Mac OS X path-finding APIs, above the POSIX layer, return paths relative to the container instead of relative to the user’s home directory. If your app, before you sandbox it, accesses locations in the user’s actual home directory (~) and you are using Cocoa or Core Foundation APIs, then, after you enable sandboxing, your path-finding code automatically uses your app’s container instead.

For first launch of your sandboxed app, Mac OS X automatically migrates your app’s main preferences file. If your app uses additional support files, perform a one-time migration of those files to the container, as described in “Migrating an App to a Sandbox.”

If you are using a POSIX command such as getpwuid to obtain the path to the user’s actual home directory, consider instead using a Cocoa or Core Foundation symbol such as the NSHomeDirectory function. By using Cocoa or Core Foundation, you support the App Sandbox restriction against directly accessing the user’s home directory.

If your app requires access to the user’s home directory in order to function, let Apple know about your needs using the Apple bug reporting system.

Parag Bafna
  • 22,812
  • 8
  • 71
  • 144
7

Using Swift, you can access the users home directory path from a sandboxed app like this:

var userHomeDirectoryPath : String {
    let pw = getpwuid(getuid())
    let home = pw?.pointee.pw_dir
    let homePath = FileManager.default.string(withFileSystemRepresentation: home!, length: Int(strlen(home)))

    return homePath
}


I created this solution based on a snippet in this blog post: http://zpasternack.org/accessing-the-real-home-folder-from-a-sandboxed-app/

Robin Schmidt
  • 1,153
  • 8
  • 15