Учимся работать с "многопоточными файлами" в NT

Материал из DRKB

Учимся работать с "многопоточными файлами" в NT[править | править код]

1. Создание(изменение) и чтение "Опциональных потоков"[править | править код]

procedure TForm1.Button1Click(Sender: TObject);
begin
  // сохраняем то что в Memo в "многопоточный файл"
  Memo1.Lines.SaveToFile('k:\memo.txt');
  Memo2.Lines.SaveToFile('k:\memo.txt:memo2'); // опциональный поток
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  // читаем в обратном порядке из "многопоточного файла"
  Memo1.Lines.LoadFromFile('k:\memo.txt:memo2'); // опциональный поток
  Memo2.Lines.LoadFromFile('k:\memo.txt');
end;


Как видно из первого примера... что бы прочитать "Опциональный поток" нам необходимо знать его "имя"... . Если вам не известно енто "имя", а очень хочется... тогда код 2 пункта предназначен для вас


2. Определяем инфу о файле/директории - читаем инфу о потоках:[править | править код]

function InfoFileStreams(const FileName: string; Delete: Boolean; out RStreams: string): Boolean;
{ Входные данные:
- FileName: Имя файла/дирректории.
- Delete: Если Truе то... по мимо инфы еще и удаляем "Опциональные потоки" файла.
Выходные данные:
- True: Что-то смоглы определить :)
- RStreams - Определенная инфа}
const
  Error_Buffer_Overflow = $80000005;
type
  _IO_STATUS_BLOCK = packed record
    Status: DWord;
    Information: DWord;
  end;
  FILE_STREAM_INFORMATION = packed record
    NextEntry: DWord;
    NameLength: DWord;
    Size: Int64;
    AllocationSize: Int64;
    Name: WideChar;
  end;
  _FILE_INFORMATION_CLASS = (
    FileDirectoryInformation=1,FileFullDirectoryInformation,
    FileBothDirectoryInformation,FileBasicInformation,
    FileStandardInformation,FileInternalInformation,
    FileEaInformation,FileAccessInformation,FileNameInformation,
    FileRenameInformation,FileLinkInformation,FileNamesInformation,
    FileDispositionInformation,FilePositionInformation,FileFullEaInformation,
    FileModeInformation,FileAlignmentInformation,FileAllInformation,
    FileAllocationInformation,FileEndOfFileInformation,FileAlternateNameInformation,
    FileStreamInformation,FilePipeInformation,FilePipeLocalInformation,
    FilePipeRemoteInformation,FileMailslotQueryInformation,FileMailslotSetInformation,
    FileCompressionInformation,FileObjectIdInformation,FileCompletionInformation,
    FileMoveClusterInformation,FileQuotaInformation,FileReparsePointInformation,
    FileNetworkOpenInformation,FileAttributeTagInformation,FileTrackingInformation,
    FileMaximumInformation);
var
  NtQueryInformationFile: function (FileHandle: DWord; out IoStatusBlock: _IO_STATUS_BLOCK;
    FileInformation: Pointer; Length: DWord; FileInformationClass: _FILE_INFORMATION_CLASS): DWord; stdcall;
  fHandle: DWord;
  StreamIS: DWord;
  StreamInfo, tSI: ^FILE_STREAM_INFORMATION;
  IoSB: _IO_STATUS_BLOCK;
  t: DWord;
  sN, sT: string;
  NextEntry, sM: Boolean;
begin
  Result := False;
  NtQueryInformationFile := GetProcAddress(GetModuleHandle('ntdll.dll'), 'NtQueryInformationFile');
  if Assigned(NtQueryInformationFile) = False then exit;
  fHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
  if fHandle <> INVALID_HANDLE_VALUE then
  begin
    StreamIS := 0;
    GetMem(StreamInfo, StreamIS);
    repeat
      FreeMem(StreamInfo, StreamIS);
      StreamIS := StreamIS + 16384;
      GetMem(StreamInfo, StreamIS);
      t := NtQueryInformationFile(fHandle, IoSB, StreamInfo, StreamIS, FileStreamInformation);
    until (t <> Error_Buffer_Overflow);
    if (t = 0) and (IoSB.Information <> 0) then
    begin
      tSI := StreamInfo;
      sN := '';
      NextEntry := True;
      Result := True;
      sM := False;
      while NextEntry do
      begin
        if tSI^.NextEntry = 0 then NextEntry := False;
        sT := Copy(PWideChar(@tSI^.Name), 0, tSI^.NameLength div SizeOf(WideChar));
        if (sM = False) and (AnsiCompareText(sT, '::$DATA') = 0) then
        begin
          sM := True;
          sN := sN + 'Основной поток: ' + sT + '; Размер: ' + IntToStr(tSI^.Size) + ' байт' + Chr($D) + Chr($A);
        end
        else
        begin
          sN := sN + 'Опциональный поток: ' + sT + '; Размер: ' + IntToStr(tSI^.Size) + ' байт' + Chr($D) + Chr($A);
          if Delete then
            if DeleteFile(FileName+sT) then
              sN := sN + 'Удален!' + Chr($D) + Chr($A);
        end;
        tSI := Pointer(DWord(tSI) + tSI^.NextEntry);
      end;
      RStreams := sN;
    end;
    FreeMem(StreamInfo, StreamIS);
    CloseHandle(fHandle);
  end;
end;


Ну и до кучи... пример использывания InfoFileStreams:

const
  SE_BACKUP_NAME = 'SeBackupPrivilege';

function NTSetPrivilege(sPrivilege: string; fEnabled: LongBool): Boolean;
var
  hToken: THandle;
  TokenPriv, PrevTokenPriv: TOKEN_PRIVILEGES;
  PrivSet: PRIVILEGE_SET;
  f: LongBool;
  i: Cardinal;
begin
  Result := False;
  if Win32Platform <> VER_PLATFORM_WIN32_NT then exit;
  PrivSet.PrivilegeCount := 1;
  PrivSet.Control := 0;
  PrivSet.Privilege[0].Attributes := 0;
  if LookupPrivilegeValue(nil, PChar(sPrivilege), PrivSet.Privilege[0].Luid) then
  begin
    if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
    begin
      try
        if PrivilegeCheck(hToken, PrivSet, f) and (f <> fEnabled) then
        begin
          if LookupPrivilegeValue(nil, PChar(sPrivilege), TokenPriv.Privileges[0].Luid) then
          begin
            TokenPriv.PrivilegeCount := 1;
            if fEnabled then
              TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
            else
              TokenPriv.Privileges[0].Attributes := 0;
            i := 0;
            PrevTokenPriv := TokenPriv;
            AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv), PrevTokenPriv, i);
            Result := (GetLastError = ERROR_SUCCESS);
          end;
        end;
      except
      end;
      CloseHandle(hToken);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
 NTSetPrivilege(SE_BACKUP_NAME, True);
 if InfoFileStreams('k:\memo.txt', False, s) then Memo1.Lines.Text := s;
 // Удаляем опциональные потоки
 //if InfoFileStreams('k:\memo.txt', True, s) then Memo1.Lines.Text := s;
end;


Author: Girder
Source: Взято с Vingrad.ru http://forum.vingrad.ru
ID: 03121