mkdir()如何成功但设置了错误的权限?

时间:2018-09-11 15:17:48

标签: linux multithreading thread-safety file-permissions

我的一段Linux代码(用C ++编写)有问题,该代码是这样的:

  1. 使用mkdir(“ xyz”,0755)创建一个成功的新目录(返回码为0)。
  2. 尝试在刚刚创建的目录中打开/创建一个新文件。
  3. 失败,因为新目录上的权限实际上是0600,而不是所请求的0755。

代码如下所示,并在进入此部分之前检查路径前缀“ / tmp / slim”是否存在:

int somefunc(const string& path)
{
  if ( mkdir( path.c_str(), 0755 ) == 0 ) {
    // (*) if (!access( path.c_str(), F_OK | R_OK | W_OK | X_OK ) == 0 )
    // (*)   chmod( path.c_str(), 0755);
    string pidinfo = to_string( getpid() ) + "\n";
    string pidinfofile = path + "/pid";
    int fd = open( pidinfofile.c_str(), O_RDWR | O_CREAT, S_IWUSR | S_IRUSR );
    if ( fd == -1 )
      return 0;
    ssize_t written = write( fd, text.c_str(), text.size() );
    // ... do more stuff
  }
}

此strace片段(没有丢失/删除的行)显示,即使mkdir()返回0,openat()也会失败。

13661 16:32:22.068465 mkdir("/tmp/slim/testsock", 0755) = 0
13661 16:32:22.068720 getpid()                = 13661
13661 16:32:22.068829 openat(AT_FDCWD, "/tmp/slim/testsock/pid", O_RDWR|O_CREAT, 0600) = -1 EACCES (Permission denied)

运行getfacl的结果如下:

[localhost]$ getfacl /tmp/slim/
getfacl: Removing leading '/' from absolute path names
# file: tmp/slim/
# owner: stk
# group: stk
user::rwx
group::r-x
other::r-x

mkdir()如何返回0,但创建一个权限与指定权限不同的目录?这不是umask的事情,我尝试在创建目录之前将umask设置为0,但没有任何效果。如果标有(*)的两条注释行已启用/未注释,则一切正常,但我不喜欢那种可以解决实际问题的症状处理方法。对于这种看似奇怪的行为,必须有一个合理的解释。

故事的一部分是这在具有多个线程的应用程序中有效。每个线程执行上面的代码(这是一个很小的线程安全功能),大多数线程成功执行,但是总是有1或2个(5-10个中的)失败,如所述。

1 个答案:

答案 0 :(得分:1)

好吧,事实证明(很可能是这样,对吧?),就像@RobertHarvey也暗示的那样,这是一个线程问题。但是,当我在评论中写道“某处存在一些隐藏的共享状态”时,我也很正确。嗯,进程umask是共享的,但可能不是完全隐藏的状态/变量。这是哪里出了问题:

  1. 一个或多个线程正在执行上面的代码,愉快地创建目录。
  2. 同时,另一个线程在摆弄umask以确保它正在创建的Unix套接字的正确权限,将umask临时设置为0177。
  3. 尽管umask摆弄太短了,但墨菲定律指出,有时有时恰好在umask为0177时创建目录,这也迫使目录获得权限掩码0600而不是0755。

L esson(重新)学习:当使用多个线程时,请注意隐藏的共享状态/变量。