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)