views:

313

answers:

2

Currently I use this function, based on JCL code, which works fine:

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;

Is there anything I could improve with the flags? Can the test be done without actually creating a file? Or is this functionality even already available in one of the RTL or Jedi libraries?

+3  A: 

Andreas...

Using the security APIs to get the effective rights for a file/directory is a PIA mess and just not reliable. (I dumped all of my code for doing so in favor of just checking to see if I could write a file in the dir.)

C.f., http://www.ureader.com/msg/16591730.aspx

(I have other refs., but I'm a new user and can post only one link. Just follow along with the URLS given in the link above.)

Erik Knowles
+ 1 great link - so it is KISS again :)
mjustin
+4  A: 

Actually writing to the directory is the simpliest way to determine if the directory is writable. There are too many security options available to check individually, and even then you might miss something.

You also need to close the opened handle before calling DeleteFile(). Which you do not need to do anyway since you are using the FILE_FLAG_DELETE_ON_CLOSE flag.

BTW, there is a small bug in your code. You are creating a temporary String and assigning it to a PWideChar, but the String goes out of scope, freeing the memory, before the PWideChar is actually used. Your FileName variable should be a String instead of a PWideChar. Do the type-cast when calling CreateFile(), not before.

Try this:

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; 
Remy Lebeau - TeamB
+1 (Personally I would use `HFILE` rather than `THandle`, but of course this is only a matter of taste.)
Andreas Rejbrand
The temporary string does not go out of scope. The temporary's scope is the same as everything else in the function. It's only destroyed when the function exits, or when the temporary needs to be re-used to hold another temporary string.
Rob Kennedy