【问题标题】:Using open() such that the file permission is guaranteed to be the same as that of files written out using the NSData file write methods使用 open() 以保证文件权限与使用 NSData 文件写入方法写出的文件的权限相同
【发布时间】:2011-12-14 19:55:59
【问题描述】:

我目前正在使用open()以如下方式写出一个文件:

NSString *path = @"/Users/enchilada/Desktop/file.txt";
int fd = open([path fileSystemRepresentation],
              O_EXCL | O_CREAT | O_WRONLY,
              S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);

我的问题是第三个参数。它是否“正确”,因为它可以保证在所有情况下都产生与 NSData 的常规 writeToFile: 方法完全相同的权限?

我想在使用纯 open() 而不是使用 Cocoa 的方法写出文件时获得适当的“默认”权限。

我发现上述权限 (rw-rw-rw-) 可以工作,因为 umask 实际上将它们降低 到 (rw-r--r--)。但我的问题是:这总是有保证的吗?我的第三个参数实际上应该是什么?

【问题讨论】:

  • 我认为当您没有特别需要不同权限时,通常您将0644(例如rw-r--r--)作为权限传递给open()。我只能猜测,但我认为这就是 NSData 所做的。
  • 是的,这不是一个坏猜测,但我想完全确定;)
  • 唯一能完全确定的方法是以某种方式获得对 Foundation 的源代码访问权限,而您将永远无法获得。但是,如果您想要一种更底层的方式来访问文件但仍然使用 Cocoa,您可以使用NSFileHandle,它提供了一个类方法,该方法将在路径上创建一个文件并打开它以进行写入。可以假设这使用与 NSData 方法相同的默认权限。
  • 我实际上正准备使用 NSFileHandle,但开始怀疑它是否与 open() 和 write() 调用一样快。我正在做的这些事情非常重复和密集……
  • @KevinBallard 否。当您没有特别需要不同权限时,通常会将 0666 作为权限传递给 open()。然后用户的 umask 修改它(用户通常将此设置为 0022,因此 0644 是新文件的常用权限)。见umask(2)

标签: objective-c c cocoa file permissions


【解决方案1】:

我们可以使用dtruss 查找。这是我的测试程序:

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
    @autoreleasepool {
        [[NSData dataWithBytes:"hello\n" length:6] writeToFile:@"/tmp/data.out" atomically:NO];
    }
    return 0;
}

这是我的运行日志:

$ sudo dtruss ~/Library/Dev*/Xcode/De*/datatest-*/B*/P*/D*/datatest 2>&1 | fgrep data.out
open("/tmp/data.out\0", 0x601, 0x1B6)        = 3 0

十六进制 0x1B6 是八进制 0666。

【讨论】:

  • 哦,太好了!您正在运行哪个操作系统?我正在运行 Snow Leopard,对于第二个和第三个参数,我得到的结果与您相同。很高兴知道 Lion 上的参数是否相同。
  • 另外,假设第二个参数为 0x601,我如何尽快确定它实际上是从哪些标志(O_WRONLY、O_CREAT 或你有什么)组合而来的? (我不太擅长处理不同基数的数字……)
  • 我使用的是 10.7.2,但很可能在所有版本的 OS X 和 iOS 上都相同。您可以使用 OS X 的计算器轻松地在十六进制和八进制之间进行转换。只需执行查看 > 程序员。 O_* 标志在/usr/include/sys/fcntl.h 中定义。 0x601 = O_WRONLY | O_CREAT | O_TRUNC.
【解决方案2】:

是的,0666 是正确的(至少对于 iOS 5 而言),但如果您不以原子方式编写,则第二个参数将是 O_CREAT | O_TRUNC | O_WRONLY(如果以原子方式编写,则在临时文件上为 O_CREAT | O_EXCL | O_RDWR。)

实际上你可以在调试器中运行你的程序,在open设置一个断点,然后检查第三个参数(p/o $r2 in gdb for ARM)以确保。

【讨论】:

  • 我尝试在打开时设置一个符号断点,但在调用 NSData 的 writeToFile 时并没有中断:原子:它只是照常写出文件,但根本没有中断。
  • @Enchilada: 也许名字没有打开(在某些 OS X 中,open 内部称为open$UNIX2003)。尝试rb ^open 打破所有以“open”开头的符号。使用disa 禁用所有断点,使用ena 启用所有断点。
  • 我确实在 Mac 上,你是对的。它现在在 open$UNIX2003 处中断。但是,如果我输入“p/o $r2”,它会打印出“$1 = 值不能转换为整数”。有什么想法吗?
猜你喜欢
  • 2012-02-29
  • 2011-01-20
  • 2015-12-31
  • 2011-08-21
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多