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

       

Системный вызов fstat имеет два


uses linux;
Function FStat(Path:Pathstr;Var Info:tstat):Boolean;
Function FStat(Fd:longint;Var Info:tstat):Boolean;
Function FStat(var F:Text;Var Info:tstat):Boolean;
Function FStat(var F:File;Var Info:tstat):Boolean;
Function LStat(Path:Pathstr; Var Info:tstat):Boolean;
Системный вызов fstat имеет два аргумента: первый из них – path, как обычно, указывает на полное имя файла. Второй аргумент info является ссылкой на структуру tstat (stat). Эта структура после успешного вызова будет содержать связанную с файлом информацию. Вместо имени файла может также использоваться его дескриптор или файловая переменная.
.
.
.
var
  s:tstat;
  filedes:integer;


  retval:boolean;
filedes := fdopen('/tmp/dina', Open_RDWR);
(* Структура s может быть заполнена при помощи вызова ... *)
retval := fstat('/tmp/dina', s);
/* ... или */
retval := fstat(filedes, @s);
Определение структуры tstat находится в модуле linux и включает следующие элементы:
stat=record
  dev      :  word;
  pad1     :  word;
  ino      :  longint;
  mode     :  word;
  nlink    :  word;
  uid      :  word;
  gid      :  word;
  rdev     :  word;
  pad2     :  word;
  size     :  longint;
  blksze   :  Longint;
  blocks   :  Longint;
  atime    :  Longint;
  unused1  :  longint;
  mtime    :  Longint;
  unused2  :  longint;
  ctime    :  Longint;
  unused3  :  longint;
  unused4  :  longint;
  unused5  :  longint;
end;
Системный вызов lstat получает информацию о символьной ссылке. Например:
uses linux;
   
var f : text;   
    i : byte;
    info : stat;
   
begin
  { Make a file }
  assign (f,'test.fil');
  rewrite (f);
  for i:=1 to 10 do writeln (f,'Testline # ',i);
  close (f);
  { Do the call on made file. }
  if not fstat ('test.fil',info) then
     begin
     writeln('Fstat failed. Errno : ',linuxerror);
     halt (1);
     end;
  writeln;
  writeln ('Result of fstat on file ''test.fil''.');
  writeln ('Inode   : ',info.ino);


– uid, gid
Идентификаторы пользователя uid и группы gid файла. Первоначально устанавливаются вызовом fdcreat и изменяются системным вызовом chown
– rdev
Этот элемент имеет смысл только в случае использования файла для описания устройства. На него пока можно не обращать внимания.
– size
Текущий логический размер файла в байтах. Нужно понимать, что способ хранения файла определяется реальными параметрами устройства, и поэтому физический размер занимаемого пространства может быть больше, чем логический размер файла. Элемент size изменяется при каждом вызове fdwrite в конце файла.
– atime
Содержит время последнего чтения из файла (хотя первоначальные вызов fdcreat и fdopen устанавливают это значение).
– mtime
Указывает время последней модификации файла – изменяется при каждом вызове fdwrite для файла.
– ctime
Содержит время последнего изменения информации, возвращаемой в структуре stat. Это время изменяется системными вызовами link (меняется элемент nlink), chmod (меняется mode) и fdwrite (меняется mtime и, возможно, size).
– blksize
Содержит размер блока ввода/вывода, зависящий от настроек системы. Для некоторых систем этот параметр может различаться для разных файлов.
– blocks
Содержит число физических блоков, занимаемых определенным файлом.
Системный вызов utime позволяет установить время доступа и модификации файла. Структура utimbuf содержит два поля, actime и modtime, оба типа Longint. Они должны быть заполнены значениями времени в секундах с 1.1.1970 г. относительно последнего времени доступа и последнего времени модификации.


uses linux;
Function Utime(path:pathstr; utim:utimbuf):Boolean;
Например:
Uses linux;
Var utim : utimbuf;
    year,month,day,hour,minute,second : Word;
      
begin
  { Set access and modification time of executable source }
  GetTime (hour,minute,second);
  GetDate (year,month,day); 
  utim.actime:=LocalToEpoch(year,month,day,hour,minute,second);
  utim.modtime:=utim.actime;
  if not Utime('ex25.pp',utim) then
    writeln ('Call to UTime failed !')
  else
    begin
    Write ('Set access and modification times to : ');
    Write (Hour:2,':',minute:2,':',second,', ');
    Writeln (Day:2,'/',month:2,'/',year:4);
    end;
end.
Следующий пример – процедура filedata выводит данные, связанные с файлом, определяемым переменной pathname. Пример сообщает размер файла, идентификатор пользователя, группу файла, а также права доступа к файлу.
Чтобы преобразовать права доступа к файлу в удобочитаемую форму, похожую на результат, выводимый командой ls, был использован массив octarray чисел типа integer, содержащий значения для основных прав доступа, и массив символов perms, содержащий символьные эквиваленты прав доступа.
(* Процедура filedata выводит данные о файле *)
uses linux;
(*
 * Массив octarray используется для определения
 * установки битов прав доступа.
 *)
const
  octarray:array[0..8] of integer= (
              0400, 0200, 0100,
              0040, 0020, 0010,
              0004, 0002, 0001);
(*
 * Мнемонические коды для прав доступа к файлу,
 * длиной 10 символов, включая нулевой символ в конце строки.
 *)
const
  perms:pchar = 'rwxrwxrwx';
function filedata(pathname:string):integer;
var
  statbuf:tstat;
  descrip:array [0..9] of char;
  j:integer;
begin
  if not fstat (pathname, statbuf) then
  begin
    writeln('Ошибка вызова stat для ', pathname);
    filedata:=-1;
    exit;
  end;
  (* Преобразовать права доступа в удобочитаемую форму *)
  for j:=0 to 8 do
  begin


      (*
       * Проверить, установлены ли права доступа
       * при помощи побитового И
       *)
      if (statbuf.mode and octal(octarray[j]))<>0 then
        descrip[j] := perms[j]
      else
        descrip[j] := '-';
  end;
  descrip[9] := #0;          (* задать строку *)
  (* Вывести информацию о файле *)
  writeln(#10'Файл ', pathname, ':');
  writeln('Размер ',statbuf.size,' байт');
  writeln('User-id ',statbuf.uid,', Group-id ',statbuf.gid,#10);
  writeln('Права доступа: ', descrip);
  filedata:=0;
end;
Более полезным инструментом является следующая программа lookout. Она раз в минуту проверяет, изменился ли какой-либо из файлов из заданного списка, опрашивая время модификации каждого из файлов (mtime). Это утилита, которая предназначена для запуска в качестве фонового процесса.[3]
(* Программа lookout сообщает об изменении файла *)
uses linux, stdio;
const
  MFILE=10;
var
  sb:tstat;
  j:integer;
  last_time:array [1..MFILE] of longint;
procedure sleep(t:longint);cdecl;external 'c';
procedure cmp(name:string;last:longint);
begin
  (*
   * Проверять время изменения файла,
   * если можно считать данные о файле.
   *)
  if not fstat(name,sb) or (sb.mtime <> last) then
  begin
    writeln('lookout: файл ',name,' изменился');
    halt(0);
   end;
end;
begin
  if (paramcount < 1) then
  begin
    writeln('Применение: lookout имя_файла ...');
    halt(1);
  end;
  if (paramcount > MFILE) then
  begin
    writeln('lookout: слишком много имен файлов');
    halt (1);
  end;
  (* Инициализация *)
  for j:=1 to paramcount do
  begin
    if not fstat(paramstr(j), sb) then
    begin
      writeln ('lookout: ошибка вызова stat для ', paramstr(j));
      halt(1);
    end;
    last_time[j]:=sb.mtime;
  end;
  (* Повторять до тех пор, пока файл не изменится *)
  while true do
  begin
    for j:=1 to paramcount do
      cmp(paramstr(j), last_time[j]);
      (*
       * Остановиться на 60 секунд.
       * Функция 'sleep' стандартная
       * библиотечная процедура UNIX.
       *)
    sleep (60);
  end;
end.
Упражнение 3.9. Напишите программу, которая проверяет и записывает изменения размера файла в течение часа. В конце работы она должна строить простую гистограмму, демонстрирующую изменения размера во времени.
Упражнение 3.10. Напишите программу slowwatch, которая периодически проверяет время изменения заданного файла (она не должна завершаться ошибкой, если файл изначально не существует). При изменении файла программа slowwatch должна копировать его на свой стандартный вывод. Как можно убедиться (или предположить), что обновление файла закончено до того, как он будет скопирован?

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