В настоящее время я использую эту функцию, основанную на коде JCL, который отлично работает:
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;
Можно что-нибудь улучшить с помощью флагов? Можно ли провести тест без создания файла? Или эта функция уже доступна в одной из библиотек RTL или Jedi?
На самом деле запись в каталог — самый простой способ определить, доступен ли каталог для записи. Доступно слишком много параметров безопасности, чтобы проверять их по отдельности, и даже в этом случае вы можете что-то упустить.
Вам также необходимо закрыть открытый дескриптор перед вызовом DeleteFile()
. Который вам в любом случае не нужно вызывать, поскольку вы используете флаг FILE_FLAG_DELETE_ON_CLOSE
.
Кстати, в вашем коде есть небольшая ошибка. Вы создаете временную String
и назначаете ее PWideChar
, но String
выходит за рамки, освобождая память перед PWideChar
. Ваша переменная FileName
должна быть String
вместо PWideChar
. Выполняйте приведение типов при вызове CreateFile()
, а не раньше.
Попробуйте так:
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;
Андреас...
Использование API-интерфейсов безопасности для получения эффективных прав для файла/каталога — это беспорядок PIA и просто ненадежный. (Для этого я выбросил весь свой код, чтобы просто проверить, могу ли я записать файл в каталог.)
Cf, http://www.ureader.com/msg/16591730. aspx
(у меня есть другие ссылки, но я новый пользователь и могу опубликовать только одну ссылку. Просто следуйте URL-адресам, указанным в ссылке выше.)