Системное программирование в UNIX средствами Free Pascal

       

Файл должен быть заранее открыт


uses linux;
type
  tmmapargs=record
    address : longint;
    size    : longint;
    prot    : longint;
    flags   : longint;
    fd      : longint;
    offset  : longint;
  end;
Function MMap(const m:tmmapargs):longint;
Файл должен быть заранее открыт при помощи системного вызова fdopen. Полученный дескриптор файла используется в качестве поля fd
в структуре tmmapargs.


Поле address позволяет программисту задать начало отображаемого файла в адресном пространстве процесса. Как и для вызова shmat, рассмотренного в разделе 8.3.4, в этом случае программе нужно знать расположение данных и кода процесса в памяти. Из соображений безопасности и переносимости лучше, конечно, позволить выбрать начальный адрес системе, и это можно сделать, присвоив параметру address значение 0. При этом возвращаемое вызовом mmap значение является адресом начала отображения. В случае ошибки вызов mmap вернет значение
-1.
Поле offset определяет смещение в файле, с которого начинается отображение данных. Обычно нужно отображать в память весь файл, поэтому поле offset часто равно 0, что соответствует началу файла. Если поле offset не равно нулю, то оно должно быть кратно размеру страницы памяти.
Число отображаемых в память байтов файла задается полем size. Если это поле не кратно размеру страницы памяти, то size байтов будут взяты из файла, а оставшаяся часть страницы будет заполнена нулями.
Поле prot определяет, можно ли выполнять чтение, запись или выполнение содержимого адресного пространства отображения. Поле prot может быть комбинацией следующих значений, определенных в файле linux:
PROT_READ          Разрешено выполнять чтение данных из памяти
PROT_WRITE        Разрешено выполнять запись данных в память
PROT_EXEC          Разрешено выполнение кода, содержащегося в памяти
PROT_NONE          Доступ к памяти запрещен
Значение поля prot не должно противоречить режиму, в котором открыт файл.
Поле flags влияет на доступность изменений отображенных в память данных файла для просмотра другими процессами. Наиболее полезны следующие значения этого параметра:

MAP_SHARED
Все изменения в области памяти будут видны в других процессах, также отображающих файл в память, изменения также записываются в файл на диске
MAP_PRIVATE
Изменения в области памяти не видны в других процессах и не записываются в файл

После завершения процесса отображение файла автоматически отменяется. Чтобы отменить отображение файла в память до завершения программы, можно использовать системный вызов munmap.


uses linux;
function MUnMap(address:Pointer; length:Longint):Boolean;
Если был задан флаг MAP_SHARED, то в файл вносятся все оставшиеся изменения, при флаге MAP_PRIVATE все изменения отбрасываются.
Следует иметь в виду, что эта функция только отменяет отображение файла в память, но не закрывает файл. Файл требуется закрыть при помощи системного вызова fdсlose.
Следующий пример повторяет программу copyfile, последний вариант которой был рассмотрен в разделе 11.4. Эта программа открывает входной и выходной файлы и копирует один из них в другой. Для простоты опущена часть процедур обработки ошибок.
uses linux;
var
  i, input, output, filesize:longint;
  source, target:pchar;
  args:tmmapargs;
const 
  endchar:char=#0;
type
  oearray=array [0..0] of char;
  poearray=^oearray;
begin
  (* Проверка числа входных параметров *)
  if paramcount <> 2 then
  begin
    writeln(stderr, 'Синтаксис: copyfile источник цель');
    halt (1);
  end;
  (* Открыть входной и выходной файлы *)
  input := fdopen (paramstr(1), Open_RDONLY);
  if input = -1 then
  begin
    writeln(stderr, 'Ошибка при открытии файла ', paramstr(1));
    halt (1);
  end;
  output := fdopen (paramstr(2), Open_RDWR or Open_CREAT or Open_TRUNC, octal(0666));
  if output = -1 then
  begin
    fdclose (input);
    writeln(stderr, 'Ошибка при открытии файла ', paramstr(2));
    halt (2);
  end;
  (* Создать второй файл с тем же размером, что и первый. *)
  filesize := fdseek (input, 0, SEEK_END);
  fdseek (output, filesize - 1, SEEK_SET);
  fdwrite (output, endchar, 1);
  (* Отобразить в память входной и выходной файлы. *)
  args.fd:=input;
  args.flags:=MAP_SHARED;
  args.prot:=PROT_READ;
  args.size:=filesize;
  args.address:=0;
  args.offset:=0;
  source:=pchar(mmap(args));
  if longint(source) = -1 then
  begin
    writeln(stderr, 'Ошибка отображения файла 1 в память');
    halt (1);
  end;
  args.fd:=output;
  args.flags:=MAP_SHARED;
  args.prot:=PROT_WRITE;
  args.size:=filesize;
  args.address:=0;
  args.offset:=0;
  target:=pchar(mmap(args));
  if longint(target) = -1 then
  begin
    writeln(stderr, 'Ошибка отображения файла 2 в память');
    halt (1);
  end;
  (* Копирование *)
  for i:=0 to filesize-1 do
    poearray(target)^[i] := poearray(source)^[i];
  (* Отменить отображение обоих файлов *)
  munmap (source, filesize);
  munmap (target, filesize);
  (* Закрыть оба файла *)
  fdclose (input);
  fdclose (output);
  halt (0);
end.
Конечно, файлы были бы автоматически закрыты при завершении программы. Вызовы munmap включены для полноты изложения.

Содержание раздела