7

I want to use the octal permissions (used for chmod) for NSFilePosixPermissions. Here is what I did now:

NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *attributes;

[attributes setValue:[NSString stringWithFormat:@"%d", 0777] 
             forKey:@"NSFilePosixPermissions"]; // chmod permissions 777
[manager setAttributes:attributes ofItemAtPath:@"/Users/lucky/Desktop/script" error:nil];

I get no error, but when I check the result with "ls -o" the permission are't -rwxrwxrwx.

What's wrong? Thanks for help.

Jan Rüegg
  • 9,587
  • 8
  • 63
  • 105
qwertz
  • 14,614
  • 10
  • 34
  • 46

3 Answers3

18

First, NSFilePosixPermissions is the name of a constant. Its value may also be the same, but that’s not guaranteed. The value of the NSFilePosixPermissions constant could change between framework releases, e. g. from @"NSFilePosixPermissions" to @"posixPermisions". This would break your code. The right way is to use the constant as NSFilePosixPermissions, not @"NSFilePosixPermissions".

Also, the NSFilePosixPermissions reference says about NSFilePosixPermisions:

The corresponding value is an NSNumber object. Use the shortValue method to retrieve the integer value for the permissions.

The proper way to set POSIX permissions is:

// chmod permissions 777

// Swift
attributes[NSFilePosixPermissions] = 0o777

// Objective-C
[attributes setValue:[NSNumber numberWithShort:0777] 
             forKey:NSFilePosixPermissions];
Ricardo Anjos
  • 1,417
  • 18
  • 22
gcbrueckmann
  • 2,413
  • 18
  • 10
  • Thanks! Only set the NSFilePermissions value don't work I did it so: `NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:[manager attributesOfItemAtPath:@"file..." error:nil]];`Next step I set the permissions and it worked! – qwertz Mar 11 '12 at 17:06
  • 2
    You can also use literal notation to pass an NSNumber (and NSDictionary): `@{NSFilePosixPermissions: @0777}` – Matthemattics Jan 24 '14 at 23:10
  • 1
    Note that the leading zero here is critical. That tells the C compiler that your constant is in Octal. Octal 0777 is 511 in decimal, not the same number! – Duncan C Dec 08 '15 at 18:30
  • You say a short. What if the octal I want is 0100640 instead of 0640? That's a perfectly valid octal for C's version of chmod(). However, a C short can only store a number up to 32767 if signed, and 65535 if unsigned. That's not enough to store 0100640. – Volomike Mar 14 '16 at 17:24
  • No, it’s not me who’s saying that. [Apple is.](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html#//apple_ref/doc/uid/20000305-SW2). Also, this attribute is about the file permissions. `0100000` isn’t a permission bit, however. It’s part of the mode. The permissions are a subset of the mode only. – gcbrueckmann Mar 15 '16 at 13:07
  • For anyone revisiting this with Swift, a leading 0 is not sufficient to indicate a number is octal, you must lead with `0o`. `NSFileManager.defaultManager.setAttributes([NSFilePosixPermissions: NSNumber(short: 0o777)], ofItemAtPath: "/tmp/foo")` – drootang Sep 09 '16 at 22:52
  • Added a Swift example. Note that you don’t need to explicitly wrap the value in an `NSNumber`. Swift-Objective-C bridging will do that automatically. – gcbrueckmann Sep 12 '16 at 13:25
  • Has now been updated to posixPermissions in swift 3 https://developer.apple.com/reference/foundation/fileattributekey/1418260-posixpermissions – Charlton Provatas Nov 19 '16 at 20:56
4

Solution in Swift 3

let fm = FileManager.default

var attributes = [FileAttributeKey : Any]()
attributes[.posixPermissions] = 0o777
do {
    try fm.setAttributes(attributes, ofItemAtPath: path.path)
}catch let error {
    print("Permissions error: ", error)
}
Charlton Provatas
  • 2,184
  • 25
  • 18
0

There is now a FilePermissions type that can make this easier.

You can add an extension:

extension FileManager {

  func setUnixPermissions(_ permissions: FilePermissions, atPath: String) throws {
    try FileManager.default.setAttributes(
      [.posixPermissions: permissions.rawValue],
      ofItemAtPath: atPath
    )
  }

}

Example usage:

  let fm = FileManager.default
  let path = "/path/to/something"

  // FilePermissions.
  try fm.setUnixPermissions([.ownerRead, .groupRead], atPath: path)

  // Octal permissions.
  try fm.setUnixPermissions(FilePermissions(rawValue: 0x777), atPath: path)

zekel
  • 9,227
  • 10
  • 65
  • 96