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


101

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

回答:


185

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

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


4
状況によっては、Pythonであっても「許しを求める方が簡単」というのは最善の方法ではありません。os.access()メソッドのように、たとえばエラーをキャッチする必要がある可能性が高い場合は、「許可を求める」ことをお勧めします。
mjv 2010

53
ディレクトリにファイルを書き込む場合は、書き込みビットだけをテストするだけでは不十分です。ディレクトリに書き込みたい場合は、実行ビットもテストする必要があります。os.access( '/ path / to / folder'、os.W_OK | os.X_OK)os.W_OKだけでは、ディレクトリを削除できます(そのディレクトリが空の場合のみ)
fthinker

4
もう1つの問題os.access()は、有効なものではなく、実際の UIDとGID を使用してチェックすることです。これにより、SUID / SGID環境で奇妙な問題が発生する可能性があります。(「しかし、スクリプトはsetuid rootを実行しますが、なぜファイルに書き込めないのですか?」)
Alexios

5
たぶん、プログラムは実際に書く必要がなくても知りたいだけなのかもしれません。プロパティに応じてGUIの外観や動作を変更したいだけかもしれません。その場合、私は単なるテストとしてファイルを書き込んで削除することをpythonicとは考えません。
バクサウ

1
Windowsネットワーク共有でテストされました。os.access(dirpath, os.W_OK | os.X_OK)書き込みアクセス権がない場合でもTrueを返します。
iamanigeeit 2018年

69

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

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

そのイディオムに従って、次のように言うかもしれません:

問題のディレクトリに書き込んでみて、権限がない場合はエラーをキャッチしてください。


5
+1 Pythonかどうかにかかわらず、これは本当にアクセスをテストする最も信頼できる方法です。
John Knoeller、2010年

5
これは、ディスクへの書き込み時に発生する可能性のある他のエラーにも対処します-たとえば、ディスク領域が残っていません。それが挑戦する力です..失敗する可能性のあるすべてのものを覚えておく必要はありません;-)
Jochen Ritzel

4
みんなありがとう。「許可よりも許しを求める方が簡単だ」というメリットは確かに理解できますが、速度は重要な要素なので、os.accessを使用することにしました。;)
照明付き

4
それは素晴らしいIDIOです... m-特に別のイディオムと組み合わせた場合except: pass-この方法で、常に楽観的になり、自分を高く評価できます。/皮肉オフ。なぜ、たとえばファイルシステムのすべてのディレクトリに何かを書き込んで、書き込み可能な場所のリストを作成したいのですか?
Tomasz Gandor

4
たぶん、プログラムは実際に書く必要がなくても知りたいだけなのかもしれません。プロパティに応じてGUIの外観や動作を変更したいだけかもしれません。その場合、私は単なるテストとしてファイルを書き込んで削除することをpythonicとは考えません。
バクサウ

19

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を使用すると実際に問題が発生することがわかりました。問題22107: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

もちろん、このような場合でも遅延は存在します。


1
tempfileを使用した方が残差が確実になくなるため、よりクリーンだと思います。
バッタ14

3
このメソッドはを使用して機能しませんtempfileOSError書き込み/削除の権限がある意味がない場合にのみ機能します。それ以外の場合return Falseは、エラーが返されないので、スクリプトは実行または終了しません。何も返されません。それはちょうどその行で立ち往生しています。ただし、許可が許可されている場合と拒否されている場合の両方で、ハッタムの回答などの一時的でないファイルを作成しても機能します。助けて?

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")

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


1
これは、OPが要求したディレクトリではなく、ファイルに適用されます。ディレクトリにファイルを作成し、そのディレクトリを書き込み不可にすることはできますが、ファイルがすでに存在している場合、ファイル自体は書き込み可能です。これは、システムアドミニストレーションで重要になる場合があります。たとえば、既存のログファイルを作成するが、一時スペースにログディレクトリを使用したくない場合などです。
Mike S

...そして実際に私は反対票を投じましたが、今はそれは間違いだと思います。Rohaqが述べたように、競合状態には問題があります。さまざまなプラットフォームでディレクトリをテストできる他の問題があり、ディレクトリは書き込み可能に見えますが、実際にはそうではありません。クロスプラットフォームのディレクトリ書き込み可能チェックの実行は、見た目よりも困難です。したがって、問題を認識している限り、これは優れた手法になる可能性があります。私はそれをあまりにもUNIX-yの視点から見ていましたが、それは私の間違いです。誰かがこの回答を編集して、-1を削除できるようにします。
Mike S

-1を削除したい場合に備えて、それを編集しました:)そして、はい、クロスプラットフォームのディレクトリチェックはより複雑になる可能性がありますが、一般的には、そのディレクトリ内のファイルを作成/書き込みしようとしています-その場合私が与えた例はまだ当てはまるはずです。ディレクトリパーミッション関連の問題が発生した場合でも、ファイルハンドルを開こうとすると、IOErrorがスローされます。
Rohaq 2017

反対票を削除しました。それについて申し訳ありません、そしてあなたの貢献に感謝します。
Mike S

心配いりません、答えを質問する人はいつでも歓迎します!
Rohaq 2017

9

ファイルのパーマのみを気にする場合は、os.access(path, os.W_OK)必要なことを行ってください。代わりに、ディレクトリに書き込むことができるかどうかを知りたい場合は、書き込みopen()用のテストファイル(事前に存在してはいけません)、をキャッチして調べIOError、後でテストファイルをクリーンアップします。

より一般的には、TOCTOU攻撃(スクリプトが昇格された特権(suidまたはcgiなど)で実行された場合にのみ問題)を回避するために、これらの事前テストを本当に信頼すべきではありませんが、特権を削除し、を実行し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
このソリューションはUnixのみです。
ビョルンLindqvist

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")

アクセスの詳細については、こちらをご覧ください。


2
これは基本的にMax Shawabkehの回答のコピーであり、小さなラッパーが付いています。クイックコピーペーストにしますが、マックスの元の投稿に追加することをお勧めします。
Jorrick Sleijster 2017

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


0

別のユーザーの権限を確認する必要がある場合(そうです、これは質問と矛盾しますが、誰かにとっては便利かもしれません)、pwdモジュールとディレクトリのモードビットを使用して確認できます。

免責事項 -POSIXアクセス許可モデルを使用していないため(そしてpwdモジュールがそこで利用できないため)、Windowsでは機能しません。例-* nixシステム専用のソリューション。

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

最後に、モードは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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.