Использование 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"

Другие вопросы по тегам