2010-01-21 5 views
75

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

Répondre

55

Il peut sembler étrange de suggérer, mais un langage Python commun est

Il est plus facile de demander pardon que 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.

+4

+1 Python ou non, ce qui est vraiment le moyen le plus fiable pour tester l'accès. –

+4

Cela prend également en charge d'autres erreurs qui peuvent se produire lors de l'écriture sur le disque - par exemple, il ne reste plus d'espace disque. C'est le pouvoir d'essayer .. vous n'avez pas besoin de se souvenir de tout ce qui peut aller mal ;-) –

+4

Merci les gars. Décidé d'aller avec os.access comme la vitesse est un facteur important dans ce que je fais ici, même si je peux certainement comprendre les mérites dans "il est plus facile de demander pardon que pour la permission." ;) – illuminatedtiger

6

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) 
    ) 
+2

Cette solution est uniquement Unix. –

127

Bien que Christophe a proposé une solution plus Pythonic, le module os n'ont the os.access function 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

+4

Selon la situation, le "plus facile de demander pardon" n'est pas le meilleur moyen, même en Python. Il est parfois conseillé de "demander la permission" comme avec la méthode os.access() mentionnée, par exemple quand la probabilité d'avoir une erreur est élevée. – mjv

+34

Il n'est pas suffisant de tester un répertoire uniquement pour le bit d'écriture si vous souhaitez écrire des fichiers dans le répertoire.Vous aurez également besoin de tester le bit d'exécution si vous voulez écrire dans le répertoire. os.access ('/ chemin/vers/dossier', os.W_OK | os.X_OK) Avec os.W_OK seul vous pouvez seulement supprimer le répertoire (et seulement si ce répertoire est vide) – fthinker

+3

Un autre gotcha de 'os.access() 'est-ce qu'il vérifie en utilisant le * real * UID et le GID, pas les * effective *. Cela pourrait causer de l'étrangeté dans les environnements SUID/SGID. ('Mais le script s'exécute setuid root, pourquoi ne peut-il pas écrire dans le fichier?') – Alexios

9

Si vous vous souciez uniquement des perms de fichier, os.access(path, os.W_OK) devrait faire ce que vous demandez. Si vous voulez savoir si vous pouvez pouvez écrire dans le répertoire, open() un fichier de test pour l'écriture (il ne devrait pas exister au préalable), attraper et examiner tout IOError, et nettoyer le fichier de test par la suite.

Plus généralement, pour éviter les attaques TOCTOU (seulement un problème si votre script s'exécute avec des privilèges élevés - suid ou cgi ou plus), vous ne devriez pas vraiment faire confiance à ces tests d'avance, mais laisser tomber les privs, le open(), et attendez le IOError.

4

Voici quelque chose que je créé sur la base de la réponse 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" 
9

Nous sommes tombés sur ce fil recherche d'exemples pour quelqu'un. Premier résultat sur Google, bravo!

Les gens parlent de la façon Pythonienne de le faire dans ce fil, mais pas de simples exemples de code? Ici, vous allez, pour quelqu'un d'autre qui trébuche dans:

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

Cette tente d'ouvrir un descripteur de fichier pour l'écriture, et se termine avec une erreur si le fichier spécifié ne peut pas être écrit à: Ceci est beaucoup plus facile à lire et est une meilleure façon de le faire plutôt que de faire des préchecks sur le chemin du fichier ou le répertoire, car cela évite les conditions de course; cas où le fichier devient non-inscriptible entre le moment où vous exécutez le pré-contrôle et quand vous essayez réellement d'écrire dans le fichier.

+1

Ceci s'applique à un fichier, pas à un répertoire qui est ce que l'OP a demandé. Vous pouvez avoir un fichier dans un répertoire et avoir le répertoire non inscriptible mais le fichier lui-même est, si le fichier existe déjà. Cela peut être important dans l'administration des systèmes où vous créez par exemple des fichiers journaux que vous voulez déjà exister mais que vous ne voulez pas que les personnes utilisent un répertoire de journaux pour l'espace temporaire. –

+0

... et en fait je l'ai rejeté, ce que je pense maintenant était une erreur. Comme Rohaq l'a mentionné, il y a des problèmes de conditions de course. Il existe d'autres problèmes sur diverses plates-formes où vous pouvez tester le répertoire, et il semble accessible en écriture, mais ce n'est pas le cas. L'exécution de contrôles inscriptibles dans le répertoire multiplate-forme est plus difficile qu'il n'y paraît. Donc, tant que vous êtes au courant des problèmes, cela peut être une bonne technique. Je regardais cela d'un point de vue UNIX-y, ce qui est mon erreur. Quelqu'un édite cette réponse pour que je puisse retirer mon -1. –

+0

Je l'ai édité, dans le cas où vous voulez supprimer le -1 :) Et oui, les vérifications de répertoires multiplateformes peuvent devenir plus compliquées, mais généralement vous cherchez à créer/écrire dans un fichier dans ce répertoire - Dans ce cas, l'exemple que j'ai donné devrait toujours s'appliquer. Si un problème lié à l'autorisation du répertoire survient, il doit toujours lancer une erreur IOError lors de la tentative d'ouverture du handle de fichier. – Rohaq

15

Ma solution à l'aide du 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 
+1

Je pense que celui qui utilise tempfile est le nettoyeur car il ne laisse pas de résidus. – grasshopper

+1

cette méthode ne fonctionne pas avec 'tempfile'. cela fonctionne seulement quand il n'y a pas de 'OSError' signifiant qu'il a l'autorisation d'écrire/supprimer. sinon, il ne renverra pas False car aucune erreur n'est renvoyée et le script ne continuera pas à s'exécuter ou à quitter. rien n'est retourné. c'est juste coincé à cette ligne. Cependant, la création d'un fichier non-temporaire comme la réponse de khattam fonctionne à la fois lorsque l'autorisation est autorisée ou refusée. Aidez-moi? –

2
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 peut être le trouver here

+0

Ceci est essentiellement une copie de la réponse de Max Shawabkeh avec un peu d'emballage autour d'elle. Il fait une pâte de copie rapide mais une meilleure idée serait de l'avoir ajouté à l'article original de Max. –

0

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

Responsabilité - ne fonctionne pas sous Windows, car il n'utilise pas le modèle d'autorisations POSIX (et le module pwd n'est pas là disponible), 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 must absolu, mais sans cela, vous ne pouvez pas lister les entrées dans le répertoire (vous devez donc connaître leurs noms). L'exécution d'un autre côté est absolument nécessaire - sans que l'utilisateur ne puisse lire les inodes du fichier; donc même avoir W, sans fichiers X ne peut pas être créé ou modifié. Enfin, les modes sont disponibles dans le module stat, leur descriptions are in inode(7) man.

Exemple de code comment 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 
Questions connexes