Использование FileGetSymLinkTarget в Delphi XE5 не возвращает сетевой адрес, на который он указывает
Я использую Delphi XE5 и XE6 и создаю несколько ссылок на каталоги программным путем, обрабатывая процесс, который запрашивает повышение прав и использует функцию Delphi:
FileCreateSymLink( sLinkPath, sTargetPath )
С этого момента мое использование sLinkPath автоматически направляется на путь sTarget файловой системой. Это все отлично работает. В других случаях мне также нужно опросить такую ссылку, чтобы увидеть (а), является ли она ссылкой и (б), куда она указывает. Для этого я вызываю функцию Delphi
function FileGetSymLinkTarget(const FileName: string; var TargetName: string): Boolean;
С успешно созданной ссылкой, которая указывает на другую папку на моем локальном жестком диске, это работает отлично. Однако, когда я создаю ссылку, которая указывает на сетевое местоположение, такое как
\\SERVER\Working\scratch\BJF\test
ссылка отлично работает на уровне файловой системы, но Delphi вызывает FileGetSymLinkTarget, возвращая false и нулевую целевую строку. При входе в SysUtils.pas обнаруживается вызов "InternalGetFileNameFromSymLink", который, в свою очередь, обнаруживает большое количество размахиваний руками, чтобы "попробовать" различные вызовы для получения разумной целевой информации. Я замечаю, что внутри этой процедуры единственной удачной попыткой является вызов
GetObjectInfoName(Handle)
который возвращается
\Device\Mup\SERVER\Working\scratch\BJF\test
(закрыть!), но затем уничтожается ExpandVolumeName, возможно из-за префикса, в пустую строку.
Итак, мой вопрос:
Это может быть ошибка в XE5 и XE6? Существуют ли другие способы чтения цели ссылки без использования SysUtils?
ПОСЛЕДНЕЕ ДОБАВЛЕНИЕ НА ОСНОВЕ ПРИНЯТОГО ОТВЕТА:
Я создал следующую процедуру на основе примера Sertac, который возвращает правильные пути символических ссылок для локальных дисков и сетевых путей. Хотя сейчас я вызываю эту процедуру вместо SysUtils.FileGetSymLinkTarget, может быть полезно сначала вызвать SysUtils.FileGetSymLinkTarget и использовать мою процедуру только в том случае, если возвращаемая цель пуста, возможно, для того, чтобы справиться с перенаправлениями, которые я не пробовал.
function MyFileGetSymLinkTarget( const APathToLink : string; var ATarget : string ) : boolean;
var
LinkHandle: THandle;
TargetName: array [0..OFS_MAXPATHNAME-1] of Char;
begin
ATarget := '';
LinkHandle := CreateFile( PChar(APathToLink), 0, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
Win32Check(LinkHandle <> INVALID_HANDLE_VALUE);
try
Result := GetFinalPathNameByHandle(LinkHandle, TargetName, OFS_MAXPATHNAME, FILE_NAME_NORMALIZED) > 0;
if Result then
begin
ATarget := TargetName;
if Pos( '\\?\UNC\', ATarget ) = 1 then
begin
Delete( ATarget, 1, 8 );
Insert( '\\', ATarget, 1 );
end
else
if Pos( '\\?\', ATarget ) = 1 then
Delete( ATarget, 1, 4 );
end;
finally
CloseHandle(LinkHandle);
end;
end;
1 ответ
Следующее работает в моей тестовой настройке, которая использует GetFinalPathNameByHandle
,
var
LinkHandle: THandle;
TargetName: array [0..512] of Char;
begin
LinkHandle := CreateFile('[path to sym link]', 0, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
Win32Check(LinkHandle <> INVALID_HANDLE_VALUE);
try
if GetFinalPathNameByHandle(LinkHandle, TargetName, 512,
FILE_NAME_NORMALIZED) > 0 then
ShowMessage(TargetName)
else
RaiseLastOSError;
finally
CloseHandle(LinkHandle);
end;
end;
Целевой путь отображается как \\?\UNC\Server\Share\Folder\SubFolder\
, Вы можете проверить крайнюю левую сторону против \\?\UNC
и заменить его на \
если хочешь.
Вы также можете заменить VOLUME_NAME_NONE
на месте FILE_NAME_NORMALIZED
иметь целевой путь как \Server\Share\Folder\SubFolder\
,
RTL использует ту же функцию в одной из своих попыток с VOLUME_NAME_NT
как тип результата, который возвращает путь как Device\Mup\..
, а затем пытается сопоставить начальную часть строки с одним из локальных логических томов (GetLogicalDriveStrings
). Когда нет совпадения, поскольку путь указывает на сетевой диск, он возвращает пустую строку, как вы заметили.
Обратите внимание на комментарий в источниках RTL относительно символических ссылок через границу машины:
Права доступа к символическим ссылкам непредсказуемы для сетевых дисков. Поэтому не рекомендуется создавать символические ссылки через сетевой диск. Чтобы включить удаленный доступ по символическим ссылкам в Windows Vista и Windows 7, используйте команду: "fsutil поведения set SymlinkEvaluation R2R:1 R2L:1"