2010-08-30 12 views
8

Actualmente uso de esta función, basado en el código JCL, que funciona bien:¿Cómo puedo usar Delphi para probar si un Directorio es grabable?

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; 

¿Hay algo que podría mejorar la bandera? ¿Se puede hacer la prueba sin crear realmente un archivo? ¿O esta funcionalidad ya está disponible en una de las bibliotecas RTL o Jedi?

+3

No ¿Funciona el código para usted? ¿Hay algo sobre este enfoque que no te gusta? De hecho, es una manera muy simple (¿la más simple?) De probar el acceso de escritura de directorio. Aunque nunca he trabajado demasiado con la seguridad de Windows, supongo que un enfoque alternativo es usar la función 'GetFileSecurity'. –

+0

@Andreas vea mi edición - si pudiera reemplazar esta función por una llamada de una función de biblioteca existente (tal vez incluso con soporte multiplataforma), esto definitivamente sería una mejora. – mjn

+0

No puedo ver nada allí que no esté en la RTL, ¿cuál es la llamada JCL? –

Respuesta

15

En realidad, escribir en el directorio es la forma más sencilla de determinar si el directorio es escribible. Hay demasiadas opciones de seguridad disponibles para verificar individualmente, e incluso entonces es posible que se pierda algo.

También debe cerrar el controlador abierto antes de llamar a DeleteFile(). Lo cual no es necesario hacer de todos modos ya que está usando el indicador FILE_FLAG_DELETE_ON_CLOSE.

Por cierto, hay un pequeño error en su código. Está creando un String temporal y lo está asignando a un PWideChar, pero el String queda fuera de alcance, liberando la memoria, antes de que realmente se use el PWideChar. Su variable FileName debería ser una Cadena en lugar de un PWideChar. Realice el lanzamiento de texto al llamar a CreateFile(), no antes.

Prueba esto:

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 (Personalmente usaría 'HFILE' en lugar de' THandle', pero por supuesto esto solo es cuestión de gusto.) –

+1

La cadena temporal no sale del alcance. El alcance temporal es el mismo que todo lo demás en la función. Solo se destruye cuando la función finaliza o cuando es necesario reutilizar temporalmente para contener otra cadena temporal. –

+2

Pero probablemente debe usar el nombre de archivo "aleatorio", porque la función devuelve FALSE, si el archivo chk.tmp ya existe en el directorio comprobado. – Peter

2

Andreas ...

El uso de las API de seguridad para obtener los derechos efectivos de un archivo/directorio es un lío PIA y no fiable. (Me deshice de todo mi código para hacerlo en favor de sólo la comprobación para ver si podía escribir un archivo en el directorio.)

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

(tengo otras referencias., Pero estoy un nuevo usuario y puede publicar solo un enlace. Simplemente siga las URL que figuran en el enlace anterior.)

0

Sin duda, todo lo que tiene que hacer es comprobar sus derechos de acceso al directorio. ¿Qué está mal con esto:

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

Aquí está mi versión utilizando GetTempFileName que intentará crear un archivo temporal única en el directorio de destino:

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; 
Cuestiones relacionadas