8

How we can check if a directory is readOnly or Not?

Adnan
  • 25,882
  • 18
  • 81
  • 110
user476601
  • 81
  • 2
  • 4
    @Oded: While the question was indeed terse, it *did* contain all the information required to answer it, since it's tagged Delphi... – Mihai Limbășan Oct 15 '10 at 09:45

5 Answers5

4

you can use the FileGetAttr function and check if the faReadOnly flag is set.

try this code

function DirIsReadOnly(Path:string):Boolean;
var
 attrs    : Integer;
begin
 attrs  := FileGetAttr(Path);
 Result := (attrs  and faReadOnly) > 0;
end;
RRUZ
  • 134,889
  • 20
  • 356
  • 483
  • Idea: the code could (as a 'special bonus') throw an exception if Path points to "something else than a directory" - or use Assert(DirectoryExists(Path))? – mjn Oct 15 '10 at 14:36
  • 1
    This code does not work for folders on Windows, only files. Windows file and folder attributes are based on legacy FAT which does not include a `Read-only` attribute for folders. These were never updated in the move to NTFS, but advanced `ACL` or `Access Control List` features of NTFS can be used to make a folder read-only. My answer below (adapted from `HeartWave`s) is more reliable. See this article for additional details: https://support.microsoft.com/en-gb/help/326549/you-cannot-view-or-change-the-read-only-or-the-system-attributes-of-fo – AlainD Sep 07 '17 at 09:15
2

Testing if the directory's attribute is R/O is only part of the answer. You can easily have a R/W directory that you still can't write to - because of Access Rights.

The best way to check if you can write to a directory or not is - to try it:

FUNCTION WritableDir(CONST Dir : STRING) : BOOLEAN;
  VAR
    FIL : FILE;
    N   : STRING;
    I   : Cardinal;

  BEGIN
    REPEAT
      N:=IncludeTrailingPathDelimiter(Dir);
      FOR I:=1 TO 250-LENGTH(N) DO N:=N+CHAR(RANDOM(26)+65)
    UNTIL NOT FileExists(N);
    Result:=TRUE;
    TRY
      AssignFile(FIL,N);
      REWRITE(FIL,1);
      Result:=FileExists(N); // Not sure if this is needed, but AlainD says so :-)
    EXCEPT
      Result:=FALSE
    END;
    IF Result THEN BEGIN
      CloseFile(FIL); 
      ERASE(FIL)
    END
  END;
HeartWare
  • 7,464
  • 2
  • 26
  • 30
  • 1
    looks like COBOL or FORTRAN to me at first look :) – mjn Oct 15 '10 at 14:25
  • What you did is close to the worst way. Unnecessary filesystem, hd burden. Next, what if you have some sort of fs change subscribers attached? The best way is just to write whatever you planned on writing there. If the directory is protected, you'll get an error. That's it. – himself Oct 19 '10 at 12:34
  • Agreed. But if for some reason you NEED to know BEFOREHAND if the directory is writable, the only way is - as you yourself are implying - to just do it. The above function just does this and returns the result. – HeartWare Oct 19 '10 at 13:20
  • @HeartWare: Cool, have deleted my earlier comment. The extra check is required because `Active Control List` (ACL) can deny write permissions to the current user. When I tested the code, the file was NOT written...but no exception is thrown. Belt-and-braces :o) – AlainD Sep 08 '17 at 13:18
1

The version HeartWare has given is nice but contains two bugs. This modified versions works more reliably and has comments to explain what is going on:

function IsPathWriteable(const cszPath: String) : Boolean;
var
    fileTest: file;
    szFile: String;
    nChar: Cardinal;
begin
    // Generate a random filename that does NOT exist in the directory
    Result := True;
    repeat
        szFile := IncludeTrailingPathDelimiter(cszPath);
        for nChar:=1 to (250 - Length(szFile)) do
            szFile := (szFile + char(Random(26) + 65));
    until (not FileExists(szFile));

    // Attempt to write the file to the directory. This will fail on something like a CD drive or
    // if the user does not have permission, but otherwise should work.
    try
        AssignFile(fileTest, szFile);
        Rewrite(fileTest, 1);

        // Note: Actually check for the existence of the file. Windows may appear to have created
        // the file, but this fails (without an exception) if advanced security attibutes for the
        // folder have denied "Create Files / Write Data" access to the logged in user.
        if (not FileExists(szFile)) then
            Result := False;
    except
        Result := False;
    end;

    // If the file was written to the path, delete it
    if (Result) then
        begin
        CloseFile(fileTest);
        Erase(fileTest);
        end;
end;
HeartWare
  • 7,464
  • 2
  • 26
  • 30
AlainD
  • 5,413
  • 6
  • 45
  • 99
  • 2
    This is way too complex. see: https://stackoverflow.com/a/46094359/937125 – kobik Sep 07 '17 at 10:49
  • I didn't know about that other question when I answered this one. However, disagree this is `way too complex`. It does the same thing: Try and write a file. If it succeeds, then the directory is not read-only. – AlainD Sep 07 '17 at 15:55
0

In Windows API way, it is:

fa := GetFileAttributes(PChar(FileName))
if (fa and FILE_ATTRIBUTE_DIRECTORY <> 0) and (fa and FILE_ATTRIBUTE_READONLY <> 0) then
  ShowMessage('Directory is read-only');
Vantomex
  • 2,247
  • 5
  • 20
  • 22
  • This answer is correct for files but not for folders. Windows (all versions) does not set FILE_ATTRIBUTE_READONLY for folders. See this question which gives more details: https://superuser.com/questions/1247843/why-can-i-write-files-into-a-folder-that-is-read-only/1247851?noredirect=1#comment1831434_1247851 – AlainD Sep 06 '17 at 11:26
0

One possible way is to try list the files in that directory and check for the status. This way we can check whether it is readable. this answer is applicable to 2009 or lower. Remember we have to check whether the folder exists and then whether the folder is readable. you can find the implementation here http://simplebasics.net/delphi-how-to-check-if-you-have-read-permission-on-a-directory/

Libish Jacob
  • 308
  • 4
  • 8