디렉토리의 쓰기 가능 여부 확인


101

스크립트를 실행하는 사용자가 디렉토리를 쓸 수 있는지 여부를 결정하는 가장 좋은 방법은 파이썬에서 무엇입니까? 이것은 os 모듈을 사용하는 것과 관련이있을 것이므로 * nix 환경에서 실행하고 있다고 언급해야합니다.

답변:


185

Christophe가 제안한 것이 더 Python적인 솔루션이지만 os 모듈에는 액세스를 확인 하는 os.access 함수 가 있습니다.

os.access('/path/to/folder', os.W_OK) # W_OK는 쓰기, R_OK는 읽기 등입니다.


4
상황에 따라 "용서를 구하기가 더 쉬움"은 파이썬에서도 최선의 방법이 아닙니다. 언급 된 os.access () 메서드와 같이 "권한을 요청"하는 것이 좋습니다 (예 : 오류를 잡아야 할 확률이 높은 경우).
mjv

53
디렉토리에 파일을 쓰려는 경우 쓰기 비트에 대한 디렉토리 테스트만으로는 충분하지 않습니다. 디렉토리에 쓰려면 실행 비트도 테스트해야합니다. os.access ( '/ path / to / folder', os.W_OK | os.X_OK) os.W_OK만으로는 디렉토리를 삭제할 수 있습니다 (그리고 해당 디렉토리가 비어있는 경우에만)
fthinker

4
또 다른 문제 는 효과적인 UID가 아닌 실제 UID 및 GID를 os.access()사용하여 확인한다는 것입니다. 이로 인해 SUID / SGID 환경에서 이상이 발생할 수 있습니다. ( '하지만 스크립트는 setuid 루트를 실행하는데 왜 파일에 쓸 수 없습니까?')
Alexios

5
프로그램은 실제로 작성할 필요없이 알고 싶어 할 수도 있습니다. 속성에 따라 GUI의 모양 및 / 또는 동작을 변경하려고 할 수 있습니다. 이 경우 테스트로 파일을 작성하고 삭제하는 것이 비단뱀이라고 생각하지 않습니다.
Bachsau

1
Windows 네트워크 공유에서 테스트했습니다. os.access(dirpath, os.W_OK | os.X_OK)쓰기 권한이 없어도 True를 반환합니다.
iamanigeeit

69

이것을 제안하는 것이 이상하게 보일 수 있지만 일반적인 Python 관용구는 다음과 같습니다.

허락하는 것보다 용서를 구하는 것이 더 쉽다

그 관용구에 따라 다음과 같이 말할 수 있습니다.

문제의 디렉토리에 쓰기를 시도하고 그렇게 할 권한이 없으면 오류를 포착하십시오.


5
+1 Python이든 아니든, 이것은 액세스를 테스트하는 가장 신뢰할 수있는 방법입니다.
John Knoeller

5
또한 디스크에 쓸 때 발생할 수있는 다른 오류도 처리합니다. 예를 들어 디스크 공간이 남지 않습니다. 그것은 시도의 힘입니다 .. 당신은 잘못 될 수있는 모든 것을 기억할 필요가 없습니다 ;-)
Jochen Ritzel

4
감사합니다. 속도는 내가 여기서하는 일에서 중요한 요소이기 때문에 os.access를 사용하기로 결정했습니다. 비록 "허가보다는 용서를 구하는 것이 더 쉽다"는 장점을 확실히 이해할 수 있지만. ;)
Illuminatedtiger

4
그것은 훌륭한 IDIO ... m-특히 다른 관용구와 결합 될 때 except: pass-이렇게하면 항상 낙관적이고 자신을 높이 생각할 수 있습니다. / 풍자 해제. 이제 왜 내가 쓰기 가능한 위치 목록을 생성하기 위해 내 파일 시스템의 모든 디렉토리에 무언가를 쓰려고할까요?
Tomasz Gandor 2016

4
프로그램은 실제로 작성할 필요없이 알고 싶어 할 수도 있습니다. 속성에 따라 GUI의 모양 및 / 또는 동작을 변경하려고 할 수 있습니다. 이 경우 테스트로 파일을 작성하고 삭제하는 것이 비단뱀이라고 생각하지 않습니다.
Bachsau

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을 사용할 때 실제로 문제가 있음을 확인 했습니다. 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

물론 이러한 경우에도 지연은 여전히 ​​존재합니다.


1
나는 tempfile을 사용하는 것이 확실히 잔여 물을 남기지 않기 때문에 더 깨끗하다고 ​​생각합니다.
grasshopper

3
이 방법은 tempfile. OSError쓰기 / 삭제 권한이있는 의미 가없는 경우에만 작동합니다 . 그렇지 않으면 return False오류가 반환되지 않고 스크립트가 계속 실행되거나 종료 되지 않기 때문이 아닙니다. 아무것도 반환되지 않습니다. 그것은 그 선에 갇혀 있습니다. 그러나 khattam의 대답과 같은 비 임시 파일을 만드는 것은 권한이 허용되거나 거부 될 때 모두 작동합니다. 도움?

10

누군가에 대한 예제를 검색하는이 스레드를 우연히 발견했습니다. Google의 첫 번째 결과, 축하합니다!

사람들은이 스레드에서 파이썬적인 방법에 대해 이야기하지만 간단한 코드 예제는 없습니까? 여기에 걸려 넘어지는 다른 사람을 위해 :

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적인 관점에서 그것을 보았는데, 그것은 나의 실수입니다. 누군가이 대답을 편집하여 -1을 제거 할 수 있습니다.
Mike S

-1을 제거하려는 경우를 대비하여 편집했습니다. 예, 크로스 플랫폼 디렉토리 검사가 더 복잡해질 수 있지만 일반적으로 해당 디렉토리의 파일을 생성 / 쓰기하려고합니다.이 경우 내가 제시 한 예가 여전히 적용되어야합니다. 일부 디렉토리 권한 관련 문제가 발생하면 파일 핸들을 열려고 할 때 여전히 IOError가 발생합니다.
Rohaq

내 반대표를 제거했습니다. 죄송합니다. 기여해 주셔서 감사합니다.
Mike S

걱정하지 마세요. 질문하는 사람들은 항상 환영합니다!
Rohaq

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
이 솔루션은 Unix 전용입니다.
Björn Lindqvist 2013 년

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의 대답에 약간의 래퍼가 있습니다. 빠른 복사 붙여 넣기로 만들지 만 Max의 원래 게시물에 추가하는 것이 더 좋습니다.
Jorrick Sleijster

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 권한 모델을 사용하지 않기 때문에 Windows에서 작동하지 않습니다 (그리고 pwd모듈은 여기에서 사용할 수 없습니다). 예 : * nix 시스템 전용 솔루션.

디렉토리에는 읽기, 쓰기 및 eXecute의 3 비트가 모두 설정되어 있어야합니다.
좋아, R은 절대 필수는 아니지만 디렉토리에 항목을 나열 할 수 없으므로 해당 이름을 알아야합니다. 반면에 실행은 절대적으로 필요합니다. 사용자는 파일의 inode를 읽을 수 없습니다. 따라서 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.