11
votes

Comment puis-je utiliser Delphi pour tester si un répertoire est écrit?

Actuellement, j'utilise cette fonction, basée sur le code JCL, qui fonctionne bien:

function IsDirectoryWriteable(const AName: string): Boolean;
var
  FileName: PWideChar;
  H: THandle;
begin
  FileName := PWideChar(IncludeTrailingPathDelimiter(AName) + 'chk.tmp');

  H := CreateFile(FileName, GENERIC_READ or GENERIC_WRITE, 0, nil,
    CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);

  Result := H <> INVALID_HANDLE_VALUE;

  DeleteFile(FileName);
end;


12 commentaires

Le code ne fonctionne-t-il pas pour vous? Y a-t-il quelque chose à propos de cette approche que vous n'aimez pas? C'est en effet une voie très simple (la plus simple?) De tester pour l'accès à l'écriture de répertoire. Bien que je n'ai jamais beaucoup travaillé avec Windows Security, je suppose qu'une approche alternative consiste à utiliser la fonction getfileSecurity .


@Andreas Voir mon édition - si je pouvais remplacer cette fonction par un appel d'une fonction de bibliothèque existante (peut-être même avec un support multiplateform), cela serait certainement une amélioration.


Je ne peux pas vraiment voir quoi que ce soit, ce n'est pas dans la RTL - qui est l'appel JCL?


@ Demark Code est inspiré par Filecreatetemp dans l'unité JCLILEUSTILS, mais uniquement la partie Mswindows.


Je n'ai jamais été fan de fonctions comme celle-ci. Qu'est-ce que vous allez faire en fonction de la répertoire ou non du répertoire? Pourquoi n'essayez-vous pas de le faire, et s'il échoue, manipulez-la gracieusement.


@Luke non tous les utilisateurs ont des privilèges d'administration, mais l'application doit écrire dans ce répertoire - devinez maintenant que cette application fera si la fonction renvoie false :)


Que doivent faire les privilèges administratifs avec quoi que ce soit, @MJustin? Cette fonction ne compte pas du tout. Voulez-vous ça? Quelle différence cela ferait-il? Notez que, simplement parce que vous pouvez créer de nouveaux fichiers ne signifie pas que vous pouvez modifier (ou supprimer) fichiers existants. Ou, vous serez peut-être autorisé à modifier des fichiers, mais ne créez pas de nouveaux. Assurez-vous de tester les actions que vous voulez vraiment faire.


Mon point est qu'il n'y a pas vraiment besoin de fonctions génériques comme celle-ci. Au lieu de cela, essayez simplement d'essayer d'écrire tous les fichiers dont vous avez besoin, et si quelque chose échoue, faites ce que vous feriez si cette fonction est renvoyée fausse. Par exemple, si les fichiers que vous devez écrire sont bloqués par un autre processus? Cette fonction ne va pas attraper des choses comme ça.


@Luke: Lorsqu'un créateur échoue, il peut être utile de loger des informations supplémentaires sur l'environnement. Une partie de cela pourrait être de savoir si le dossier de destination a été trouvé et écrit. Une autre partie pourrait être (quelque chose que nous faisons régulièrement dans nos journaux) pour répertorier tous les processus ayant des poignées dans le fichier que nous ne pouvons pas accéder ... Cette fonction a donc son mérite de soi. En outre, nous l'utilisons souvent après l'échec de l'écriture de détection d'un dossier en lecture seule et tenter de la modifier à un écrinable afin que nous puissions réessayer l'écriture. Oui, nous pourrions aveuglément essayer de le rendre écritable, mais nos journaux sont maintenant beaucoup plus informatifs.


@Marjan Vous avez frappé la tache, par exemple, il est utile pour les chèques de la configuration d'environnement correcte dans une configuration multi-utilisateurs / TerminalServer / FileServer.


@Luke: Voici un scénario possible. Une application pouvant être utilisée comme "portable", c'est-à-dire d'un lecteur amovible. La première chose que je voudrais faire est de vérifier si je peux écrire des données et une configuration modifiées. Si, pour une raison quelconque, je suis à partir d'un CD-ROM, disons ou une pendrive protégée en écriture, je définirais un drapeau pour éviter toute tentative d'opérations d'écriture, car dans ce cas, ce n'est pas une erreur ou une cause de préoccupation . Sinon, l'utilisateur pourrait être soumis à beaucoup d'erreurs d'erreur «accès refusé» et être ennuyé à juste titre.


Ce sont deux choses différentes; Ce n'est pas parce qu'un répertoire n'est pas inscriptible (comme déterminé par le code donné dans la question) ne signifie pas qu'il réside sur un support en lecture seule. L'utilisation de code comme celle-ci est probablement suffisamment bonne pour une utilisation pratique, mais si votre programme est largement utilisé, vous passerez dans des cas de bord.


4 Réponses :


2
votes

andreas ...

Utilisation des API de sécurité Pour obtenir les droits effectifs d'un fichier / répertoire est un désordre PIA et tout simplement pas fiable. (J'ai largué tout mon code pour le faire en faveur de simplement vérifier pour voir si je pouvais écrire un fichier dans le dir.)

cf, http://www.reader.com/msg/16591730.aspx

(j'ai d'autres réfs., mais je suis un nouvel utilisateur et que je ne peux poster qu'un seul lien. Trouvez simplement les URL données dans le lien ci-dessus.)


0 commentaires

20
votes

Écrire en réalité dans le répertoire est le moyen le plus simple de déterminer si le répertoire est écritable. Il y a trop d'options de sécurité disponibles pour vérifier individuellement, et même vous risquez de manquer quelque chose.

Vous devez également fermer la poignée ouverte avant d'appeler deletefile () code>. Ce que vous n'avez pas besoin d'appeler de toute façon puisque vous utilisez le fichier file_flag_delete_on_flag_delete_on_flose code> drapeau. P>

BTW, il y a un petit bogue dans votre code. Vous créez une chaîne code> temporaire (code> et l'attribuant à un pwidechar code>, mais la chaîne code> est hors de portée, libérant la mémoire, avant le Pwidechar code> est en fait utilisé. Votre nom FileName code> La variable doit être une chaîne code> code> au lieu d'un pwidechar code>. Faites le type de type lors de l'appelant créefile () code>, pas avant. P>

Essayez ceci: p>

function IsDirectoryWriteable(const AName: string): Boolean; 
var 
  FileName: String; 
  H: THandle; 
begin 
  FileName := IncludeTrailingPathDelimiter(AName) + 'chk.tmp'; 
  H := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, 
    CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0); 
  Result := H <> INVALID_HANDLE_VALUE; 
  if Result then CloseHandle(H);
end;


8 commentaires

+1 (personnellement, j'utiliserais hfIle plutôt que Thandle , mais ce n'est bien sûr que une question de goût.)


La chaîne temporaire ne sort pas de la portée. La portée temporaire est la même que tout le reste de la fonction. Il n'est détruit que lorsque la fonction se ferme ou lorsque le temporaire doit être réutilisé pour contenir une autre chaîne temporaire.


Mais vous devez probablement utiliser un nom de fichier "aléatoire", car la fonction renvoie false, si fichier chk.tmp existe déjà dans le répertoire vérifié.


Il n'est pas nécessaire d'utiliser un nom de fichier "aléatoire". Si vous souhaitez réellement écrire dans un répertoire, vérifiez si le nom de fichier existe là-bas. Si tel est le cas, essayez d'ouvrir le fichier, sinon, créez-le avec le nom de fichier donné. Si vous souhaitez simplement vérifier que vous pouvez utiliser n'importe quel nom de fichier.


@stackmik create_new vérifie l'existence. Si le fichier existe déjà, créeefile () échoue avec error_file_existes .


@RemyleBeau Désolé, Remy, pour le retard. Ce que je voulais dire est, choisissez simplement n'importe quel nom de fichier et vérifiez son existence. Si cela existe, utilisez open_existing, sinon, créer_new.


@stackmik qui n'est pas nécessaire non plus. Vous pouvez utiliser open_always au lieu de cela, ce qui vérifie-t-on pour vous


@RemyleBeau vous avez raison, Remy. J'ai été dupe par la déclaration "... Le dernier code d'erreur est défini sur error_already_existes" et négligée "... La fonction réussit ..." Mais toujours, il n'a pas encore besoin de mettre des efforts pour trouver un nom de fichier unique si vous utilisez Open_always.



1
votes

Sûrement Tout ce que vous avez à faire est de vérifier vos droits d'accès au répertoire. Quel est le problème avec ceci: xxx


0 commentaires

5
votes

Voici ma version utilisant gettempfilename qui tentera de créer un fichier Temp unique unique dans le répertoire cible: xxx


1 commentaires

J'aime ça. Mais notez que la possibilité de créer un fichier et de pouvoir le supprimer par la suite, deux choses différentes. Il est possible, bien que rare, pour gettempfilename () pour réussir et deletefile () échouer