web-dev-qa-db-fra.com

Déterminer si un répertoire est inscriptible

Quel serait le meilleur moyen en Python de déterminer si un répertoire est accessible en écriture pour l'utilisateur qui exécute le script? Etant donné que cela impliquera probablement l’utilisation du module os, je dois mentionner que je l’utilise sous un environnement * nix. 

85
illuminatedtiger

Bien que Christophe propose une solution plus pythonique, le module os a la fonction os.access pour vérifier l’accès:

os.access('/path/to/folder', os.W_OK) # W_OK est pour l'écriture, R_OK pour la lecture, etc.

144
Max Shawabkeh

Cela peut sembler étrange de suggérer cela, mais un idiome Python commun est 

Il est plus facile de demander pardon que pour la permission

Après cet idiome, on pourrait dire:

Essayez d'écrire dans le répertoire en question et interceptez l'erreur si vous n'en avez pas l'autorisation.

61
ChristopheD

Ma solution utilisant le module 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
15
zak

Je suis tombé sur ce fil à la recherche d'exemples pour quelqu'un. Premier résultat sur Google, bravo!

Les gens parlent de la façon de faire Pythonic dans ce fil, mais pas d’exemples de code simples? Voilà, pour tous ceux qui trébuchent:

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

Cela tente d'ouvrir un descripteur de fichier en écriture et ferme avec une erreur si le fichier spécifié ne peut pas être écrit: ceci est beaucoup plus facile à lire et constitue une bien meilleure façon de le faire plutôt que de faire une vérification préalable du chemin du fichier ou du répertoire. , car cela évite les conditions de course; les cas où le fichier devient non-lisible entre le moment où vous exécutez le contrôle préalable et le moment où vous essayez réellement d'écrire dans le fichier. 

10
Rohaq

Si vous vous souciez uniquement des permanentes de fichiers, os.access(path, os.W_OK) devrait faire ce que vous demandez. Si vous voulez plutôt savoir si pouvez écrire dans le répertoire, open(), un fichier de test à écrire (il ne devrait pas exister auparavant), récupérez et examinez toute variable IOError, puis nettoyez le fichier de test.

Plus généralement, pour éviter les attaques TOCTOU (uniquement si votre script s'exécute avec des privilèges élevés - suid ou cgi, etc.), vous ne devriez pas vraiment faire confiance à ces tests anticipés, mais abandonner les privs , faites la open() et attendez-vous à la IOError.

9
sverkerw

Vérifiez les bits de mode: 

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

Voici quelque chose que j'ai créé à partir de la réponse de 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")

plus d'informations sur l'accès peuvent être trouver ici

2
Softmixt

J'ai rencontré le même besoin en ajoutant un argument via argparse. La fonction intégrée type=FileType('w') ne fonctionnerait pas pour moi car je cherchais un répertoire. J'ai fini par écrire ma propre méthode pour résoudre mon problème. Voici le résultat avec snapset 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()

Cela se traduit par:

$ 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 ~

Je suis retourné et j'ai ajouté print opts.dir jusqu'à la fin, et tout semble fonctionner comme souhaité.

1
796m9XfYTkmp

Si vous devez vérifier l'autorisation de un autre utilisateur (oui, je comprends que cela contredit la question, mais peut s'avérer utile pour quelqu'un), vous pouvez le faire via le module pwd et les bits de mode du répertoire.

Disclaimer - ne fonctionne pas sous Windows, car il n'utilise pas le modèle d'autorisations POSIX (et le module pwd n'est pas disponible là-bas), par exemple. - solution uniquement pour les systèmes * nix.

Notez qu'un répertoire doit avoir tous les 3 bits définis - Lecture, Écriture et eXecute.
Ok, R n’est pas un impératif absolu, mais vous ne pouvez pas lister les entrées dans le répertoire (vous devez donc connaître leur nom). Par contre, exécuter est absolument nécessaire - sans quoi l'utilisateur ne peut pas lire les inodes du fichier; si bien que même avec W, sans X, les fichiers ne peuvent pas être créés ou modifiés. _ { Explication plus détaillée sur ce lien. _

Enfin, les modes sont disponibles dans le module stat, leurs les descriptions sont en inode (7) man .

Exemple de code pour vérifier:

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