web-dev-qa-db-ja.com

ディレクトリが書き込み可能かどうかを判断する

Pythonでスクリプトを実行しているユーザーがディレクトリに書き込み可能かどうかを判断する最良の方法は何でしょうか?これはおそらくosモジュールの使用を伴うため、 * nix環境。

91

クリストフが提案したのはよりPython的なソリューションですが、osモジュールにはアクセスをチェックするための os.access関数 があります:

os.access('/path/to/folder', os.W_OK)#W_OKは書き込み用、R_OKは読み取り用などです。

159
Max Shawabkeh

これを提案するのは奇妙に思えるかもしれませんが、一般的なPythonイディオムは

許可よりも許しを求める方が簡単です

そのイディオムに続いて、人は言うかもしれない:

問題のディレクトリへの書き込みを試みて、許可がない場合はエラーをキャッチします。

64
ChristopheD

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モジュールが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

もちろん、これらの場合、遅延は依然として存在します。

16
zak

誰かの例を探してこのスレッドに出くわしました。 Googleでの最初の結果、おめでとうございます!

このスレッドで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")

これは、書き込みのためにファイルハンドルを開こうとし、指定されたファイルに書き込むことができない場合はエラーで終了します:これは読みやすく、ファイルパスまたはディレクトリで事前チェ​​ックを行うよりもはるかに良い方法です、競合状態を回避するため。事前チェックを実行してから実際にファイルへの書き込みを試みるまでの間にファイルが書き込み不可になる場合。

10
Rohaq

ファイルのパーマのみに関心がある場合、os.access(path, os.W_OK)はあなたが求めることをするべきです。代わりに、ディレクトリに書き込むかcanかどうかを知りたい場合は、open()書き込み用のテストファイル(存在しないはずです)事前に)、IOErrorをキャッチして調べ、その後テストファイルをクリーンアップします。

より一般的には、 [〜#〜] toctou [〜#〜] 攻撃(スクリプトが昇格した特権で実行される場合のみ問題-suidまたはcgiなど)を避けるために、あなたは本当に信頼すべきではありませんこれらの事前テストは、特権を削除し、open()を実行し、IOErrorを期待します。

9
sverkerw

モードビットを確認します。

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)
     )
7
Joe Koberg

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"
4
khattam
 if os.access(path_to_folder, os.W_OK) is not True:
            print("Folder not writable")
 else :
            print("Folder writable")

アクセスに関する詳細情報は、それを見つけることができます here

3
Softmixt

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を最後に追加すると、すべてが期待どおりに機能しているように見えます。

1
796m9XfYTkmp

他のユーザーの許可を確認する必要がある場合(はい、これは質問と矛盾することを理解していますが、誰かのために役立つかもしれません)、あなたはすることができますpwdモジュール、およびディレクトリのモードビットを使用します。

免責事項-Windowsでは動作しません。POSIX権限モデルを使用しないためです(そしてpwdモジュールはそこで利用できません) )、例えば-* nixシステム専用のソリューション。

ディレクトリには、読み取り、書き込み、実行の3ビットすべてを設定する必要があることに注意してください。
OK、Rは絶対的な必須ではありませんが、ディレクトリ内のエントリを一覧表示することはできません(名前を知っている必要があります)。一方、実行は絶対に必要です-ユーザーがファイルのiノードを読み取れない場合。したがって、XファイルなしでWを作成したり、変更したりすることはできません。 このリンクの詳細な説明

最後に、モードはstatモジュールで利用可能です。それらは 説明は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
0
Todor Minakov