2010-08-30 3 views
8

Derzeit verwende ich diese Funktion, basierend auf Code JCL, der gut arbeitet:Wie kann ich mit Delphi testen, ob ein Verzeichnis beschreibbar ist?

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; 

Gibt es etwas, was ich mit den Flaggen verbessern könnte? Kann der Test durchgeführt werden, ohne tatsächlich eine Datei zu erstellen? Oder ist diese Funktionalität sogar bereits in einer der RTL- oder Jedi-Bibliotheken verfügbar?

+3

Ist für Sie nicht den Code arbeiten? Gibt es etwas an diesem Ansatz, den du nicht magst? Es ist in der Tat eine sehr einfache (die einfachste?) Art des Testens für Verzeichnis-Schreibzugriff. Obwohl ich nie viel mit Windows-Sicherheit gearbeitet habe, denke ich, dass ein alternativer Ansatz die 'GetFileSecurity'-Funktion ist. –

+0

@Andreas sehe meine Bearbeitung - wenn ich diese Funktion durch einen Aufruf einer vorhandenen Bibliotheksfunktion (vielleicht sogar mit Multiplattform-Unterstützung) ersetzen könnte, wäre dies definitiv eine Verbesserung. – mjn

+0

Ich kann wirklich nichts dort sehen, das nicht in der RTL ist - was ist der JCL-Aufruf? –

Antwort

15

Das Schreiben in das Verzeichnis ist der einfachste Weg, um festzustellen, ob das Verzeichnis beschreibbar ist. Es gibt zu viele Sicherheitsoptionen, die Sie einzeln überprüfen können, und selbst dann verpassen Sie möglicherweise etwas.

Sie müssen auch das geöffnete Handle vor dem Aufrufen von DeleteFile() schließen. Was Sie sowieso nicht tun müssen, da Sie das Flag FILE_FLAG_DELETE_ON_CLOSE verwenden.

BTW, es gibt einen kleinen Fehler in Ihrem Code. Sie erstellen einen temporären String und weisen ihn einem PWideChar zu, aber der String verlässt den Gültigkeitsbereich und gibt den Speicher frei, bevor der PWideChar tatsächlich verwendet wird. Ihre FileName-Variable sollte eine Zeichenfolge anstelle von PWideChar sein. Führen Sie die Typumwandlung beim Aufrufen von CreateFile() durch, nicht vorher.

Versuchen Sie folgendes:

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; 
+0

+1 (Ich persönlich würde 'HFILE' anstelle von' THandle' verwenden, aber das ist natürlich nur eine Frage des Geschmacks.) –

+1

Die temporäre Zeichenfolge wird nicht aus dem Gültigkeitsbereich entfernt. Der Bereich des Temporären ist derselbe wie alles andere in der Funktion. Es wird nur zerstört, wenn die Funktion beendet wird oder wenn das temporäre Objekt zum Speichern einer anderen temporären Zeichenfolge wiederverwendet werden muss. –

+2

Aber Sie müssen wahrscheinlich "zufällige" Dateinamen verwenden, da die Funktion FALSE zurückgibt, wenn die Datei chk.tmp bereits im überprüften Verzeichnis existiert. – Peter

2

Andreas ...

den Sicherheits-APIs Mit den effektiven Rechte für eine Datei erhalten/Verzeichnis ist ein Chaos PIA und einfach nicht zuverlässig. (I abgeladen alle meine Code zu tun, um für nur überprüfen, ob ich eine Datei im Verzeichnis schreiben konnte.)

Cf, http://www.ureader.com/msg/16591730.aspx

(Ich habe andere Refs., Aber ich bin ein neuer Benutzer und kann nur einen Link posten. Folgen Sie einfach den URLs im obigen Link.)

0

Sicherlich alles, was Sie tun müssen, um Ihre Zugriffsrechte auf das Verzeichnis überprüfen. Was ist mit dem ist falsch:

function IsDirectoryWriteable(aName : String); 
var 
    FileObject : TJwSecureFileObject; 
    DesiredAccess: ACCESS_MASK; 
begin 
    DesiredAccess := FILE_GENERIC_WRITE; 
    FileObject := TJwSecureFileObject.Create(aName); 
    try 
    result := FileObject.AccessCheck(DesiredAccess); 
    finally 
    FileObject.Free; 
    end; 
end; 
2

Hier ist meine Version GetTempFileName verwendet, die eine einzigartige temporäre Datei im Zielverzeichnis zu erstellen versucht:

function IsDirecoryWriteable(const AName: string): Boolean; 
var 
    TempFileName: array[0..MAX_PATH] of Char; 
begin 
    { attempt to create a temp file in the directory } 
    Result := GetTempFileName(PChar(AName), '$', 0, TempFileName) <> 0; 
    if Result then 
    { clean up } 
    Result := DeleteFile(TempFileName); 
end; 
Verwandte Themen