确定目录是否可写

问题描述 投票:90回答:10

Python中确定目录对于执行脚本的用户是否可写的最佳方法是什么?由于这可能涉及使用os模块,我应该提到我在* nix环境下运行它。

python file permissions directory operating-system
10个回答
156
投票

虽然Christophe建议的是一个更Pythonic的解决方案,os模块确实有the os.access function来检查访问:

os.access('/path/to/folder', os.W_OK)#W_OK用于写作,R_OK用于阅读等。


0
投票

如果你需要检查另一个用户的权限(是的,我意识到这与这个问题相矛盾,但对某人来说可能会派上用场),你可以通过pwd模块和目录的模式位来实现。

免责声明 - 在Windows上不起作用,因为它不使用POSIX权限模型(并且那里没有pwd模块),例如 - 仅适用于* nix系统的解决方案。

请注意,目录必须设置所有3位 - 读,写和执行。 好吧,R不是绝对必须的,但是如果不能列出目录中的条目(那么你必须知道它们的名字)。另一方面,执行是绝对必要的 - 用户无法读取文件的inode;所以即使有W,也没有X文件无法创建或修改。 More detailed explanation at this link.

最后,这些模式可以在stat模块中找到,它们的descriptions are in inode(7) man

示例代码如何检查:

import pwd
import stat
import os

def check_user_dir(user, directory):
    dir_stat = os.stat(directory)

    user_id, group_id = pwd.getpwnam(user).pw_uid, pwd.getpwnam(user).pw_gid
    directory_mode = dir_stat[stat.ST_MODE]

    # use directory_mode as mask 
    if user_id == dir_stat[stat.ST_UID] and stat.S_IRWXU & directory_mode == stat.S_IRWXU:     # owner and has RWX
        return True
    elif group_id == dir_stat[stat.ST_GID] and stat.S_IRWXG & directory_mode == stat.S_IRWXG:  # in group & it has RWX
        return True
    elif stat.S_IRWXO & directory_mode == stat.S_IRWXO:                                        # everyone has RWX
        return True

    # no permissions
    return False

64
投票

建议这可能看起来很奇怪,但一个常见的Python习语是

要求宽恕比获得许可更容易

在这个成语之后,有人会说:

尝试写入相关目录,如果您没有权限,请捕获错误。


16
投票

我使用tempfile模块的解决方案:

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True

更新:在Windows上再次测试代码后,我发现在那里使用tempfile确实存在问题,请参阅issue22107: tempfile module misinterprets access denied error on Windows。在不可写目录的情况下,代码挂起几秒钟,最后抛出一个IOError: [Errno 17] No usable temporary file name found。也许这就是user2171842观察的内容?不幸的是,现在问题还没有解决,所以为了解决这个问题,还需要捕获错误:

    except (OSError, IOError) as e:
        if e.errno == errno.EACCES or e.errno == errno.EEXIST:  # 13, 17

在这些情况下,延迟当然仍然存在。


10
投票

偶然发现这个线程正在寻找某人的例子。对谷歌的第一个结果,恭喜!

人们在这个帖子中谈论Pythonic的做法,但没有简单的代码示例?在这里,对于其他任何偶然发现的人:

import sys

filepath = 'C:\\path\\to\\your\\file.txt'

try:
    filehandle = open( filepath, 'w' )
except IOError:
    sys.exit( 'Unable to write to file ' + filepath )

filehandle.write("I am writing this text to the file\n")

这会尝试打开文件句柄进行写入,如果指定的文件无法写入,则会以错误退出:这更容易阅读,并且是一种更好的方法,而不是在文件路径或目录上进行预先检查,因为它避免了竞争条件;在运行预检和实际尝试写入文件之间文件变为不可写的情况。


9
投票

如果您只关心文件烫发,os.access(path, os.W_OK)应该按照您的要求进行操作。如果你想知道是否可以写入目录,open()是一个用于写入的测试文件(它不应该事先存在),捕获并检查任何IOError,然后清理测试文件。

更一般地说,为了避免TOCTOU攻击(如果你的脚本以提升的权限运行只是一个问题 - suid或cgi左右),你不应该真的相信这些提前测试,但是删除privs,做open(),以及期待IOError


7
投票

检查模式位:

def isWritable(name):
  uid = os.geteuid()
  gid = os.getegid()
  s = os.stat(dirname)
  mode = s[stat.ST_MODE]
  return (
     ((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
     ((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
     (mode & stat.S_IWOTH)
     )

4
投票

这是我根据ChristopheD的答案创建的:

import os

def isWritable(directory):
    try:
        tmp_prefix = "write_tester";
        count = 0
        filename = os.path.join(directory, tmp_prefix)
        while(os.path.exists(filename)):
            filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
            count = count + 1
        f = open(filename,"w")
        f.close()
        os.remove(filename)
        return True
    except Exception as e:
        #print "{}".format(e)
        return False

directory = "c:\\"
if (isWritable(directory)):
    print "directory is writable"
else:
    print "directory is not writable"

3
投票
 if os.access(path_to_folder, os.W_OK) is not True:
            print("Folder not writable")
 else :
            print("Folder writable")

有关访问的更多信息可以找到它here


1
投票

我在通过argparse添加参数时遇到了同样的需求。内置的type=FileType('w')不适合我,因为我正在寻找一个目录。我最终编写了自己的方法来解决我的问题。这是argparse片段的结果。

#! /usr/bin/env python
import os
import argparse

def writable_dir(dir):
    if os.access(dir, os.W_OK) and os.path.isdir(dir):
        return os.path.abspath(dir)
    else:
        raise argparse.ArgumentTypeError(dir + " is not writable or does not exist.")

parser = argparse.ArgumentParser()
parser.add_argument("-d","--dir", type=writable_dir(), default='/tmp/',
    help="Directory to use. Default: /tmp")
opts = parser.parse_args()

这导致以下结果:

$ python dir-test.py -h
usage: dir-test.py [-h] [-d DIR]

optional arguments:
  -h, --help         show this help message and exit
  -d DIR, --dir DIR  Directory to use. Default: /tmp

$ python dir-test.py -d /not/real
usage: dir-test.py [-h] [-d DIR]
dir-test.py: error: argument -d/--dir: /not/real is not writable or does not exist.

$ python dir-test.py -d ~

我回去并将print opts.dir添加到最后,所有内容似乎都按预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.