NT4: hardlinks

From
Aleksej Kozlov (2:5030/750.40)
To
All
Date
2002-11-12T00:07:08Z
Area
SU.WINDOWS.NT.PROG
Hello !


Интересные баги наблюдаются... Откопал в этой эхе проскакивавший когда-то сишный исходник для создания hardlink-ов под NT 4, перевёл его на паскаль. Вот что получилось:

{&Use32+}

uses
  Windows;

function CreateFileW(FileName: PWChar; DesiredAccess, ShareMode: Integer; SecurityAttributes: PSecurityAttributes; CreationDisposition, FlagsAndAttributes: DWord; TemplateFile: THandle): THandle;
cdecl;
external 'kernel32.dll' name 'CreateFileW';

function GetFullPathNameW(FileName: PWChar; BufferLength: DWord; Buffer: PWChar; var FilePart: PWChar): DWord;
cdecl;
external 'kernel32.dll' name 'GetFullPathNameW';

var
  szFilePath: array[0..MAX_PATH] of WChar;

function CreateHardLinkW(lpFileName: PWChar;
                         lpExistingFileName: PWChar;
                         lpSecurityAttributes: PSecurityAttributes): Boolean;
label
  Cleanup;
var
  hFile: THandle;
  dwError: DWord;
  cbWritten: DWord;
  StreamId: TWin32StreamId;
  pvContext: Pointer;
  cbHeader: DWord;
//szFilePath: array[0..MAX_PATH] of WChar;
  pszNamePart: PWChar;
  cchFilePath: DWord;
begin
//hFile := CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
//                     FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
//                     lpSecurityAttributes, OPEN_EXISTING, 0, 0);
  hFile := CreateFile('c:\temp\123', FILE_WRITE_ATTRIBUTES,
                      FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
                      lpSecurityAttributes, OPEN_EXISTING, 0, 0);
  if hFile = INVALID_HANDLE_VALUE then
    begin
      Result := False;
      Exit;
    end;

  dwError := 0;
  pvContext := nil;

  cchFilePath := GetFullPathNameW(lpFileName, MAX_PATH, @szFilePath, pszNamePart);
  if cchFilePath = 0 then
    begin
      dwError := GetLastError;
      goto Cleanup;
    end;

  with StreamId do
    begin
      dwStreamId := BACKUP_LINK;
      dwStreamAttributes := 0;
      dwStreamNameSize := 0;
      Size.HighPart := 0;
      Size.LowPart := (cchFilePath+1)*SizeOf(WChar);
    end;

  cbHeader := DWord(PChar(@StreamId.cStreamName)-PChar(@StreamId));

  if not BackupWrite(hFile, @StreamId, cbHeader, cbWritten, False, False, pvContext) then
    begin
      dwError := GetLastError;
      goto Cleanup;
    end;

  if not BackupWrite(hFile, @szFilePath, StreamId.Size.LowPart, cbWritten, False, False, pvContext) then
    dwError := GetLastError;

  BackupWrite(hFile, nil, 0, cbWritten, True, False, pvContext);

  Cleanup:

  CloseHandle(hFile);
  SetLastError(dwError);
  Result := (dwError = 0);
end;

function CreateHardLink(lpFileName: String;
                        lpExistingFileName: String;
                        lpSecurityAttributes: PSecurityAttributes): Boolean;
var
  lpFileNameBuf: array[0..MAX_PATH] of WChar;
  lpExistingFileNameBuf: array[0..MAX_PATH] of WChar;
begin
  FillChar(lpFileNameBuf, SizeOf(lpFileNameBuf), #0);
  FillChar(lpExistingFileNameBuf, SizeOf(lpExistingFileNameBuf), #0);
  MultiByteToWideChar(CP_OEMCP, 0, PChar(@lpFileName[1]), Length(lpFileName), LPWSTR(@lpFileNameBuf), SizeOf(lpFileNameBuf));
  MultiByteToWideChar(CP_OEMCP, 0, PChar(@lpExistingFileName[1]), Length(lpExistingFileName), LPWSTR(@lpExistingFileNameBuf), SizeOf(lpExistingFileNameBuf));
  Result := CreateHardLinkW(@lpFileNameBuf, @lpExistingFileNameBuf, lpSecurityAttributes);
end;

begin
  Writeln(CreateHardLink('c:\temp\456', 'c:\temp\123', nil));
  Writeln(GetLastError);
  Readln;
end.


В том виде, как это здесь приведено, всё работает. По сравнению с тем вариантом, "как должно быть" отличия в двух местах: szFilePath вынесено как глобальная переменная и CreateFileW заменено на CreateFile. В варианте с CreateFileW всё вроде бы отрабатывает как надо, никаких ошибок не выдаётся, но и hardlink тоже не создаётся. Если же помимо этого ещё и szFilePath оставить локальной переменной, то программа просто падает с exception-ом... Вот это мне вообще непонятно. К тому же, если пускать это всё в отладчике, то можно увидеть, что значение szFilePath поганится после первого запуска BackupWrite, который вообще про её существование и знать не должен...

Какие есть мысли относительно возможных причин?



With best wishes, Aleksej Kozlov

--- FleetStreet 1.27.1
 * Origin: Russian Team OS/2 (2:5030/750.40)