Скачиваний:
65
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

13.4. Каталоги

Упражнение 13.28. Напишите аналог команды ls -l.

uses linux,strings,sysutils; (*для системных вызовов Linux и работы со строками PChar*)

function ctime(var time_t:longint):pchar;cdecl;external 'c';

function gettype(t:word):char;forward; (*тип объекта ф.с. в формате команды ls*)

(*тип объекта ф.с. в формате команды ls*)

function gettype(t:word):char;

begin

if S_ISDIR(t) then (*проверка на каталог*)

gettype:='d'

else

if S_ISREG(t) then (*проверка на обычный файл*)

gettype:='-'

else

if S_ISBLK(t) then (*проверка на блочное устройство*)

gettype:='b'

else

if S_ISCHR(t) then (*проверка на символьное устройство*)

gettype:='c'

else

if S_ISFIFO(t) then (*проверка на именованный программный канал*)

gettype:='p'

else

if S_ISLNK(t) then (*проверка на сиволическую ссылку*)

gettype:='l'

else

gettype:='?';

end;

function getrights(r:word):string;

var

u, (*права для владельца*)

g, (*права для группы*)

o, (*права для всех остальных*)

s, (*специальные права*)

i:integer;

res:string; (*права в символьной форме*)

const

o7777=(1 shl 12)-1; (*восьмеричная константа = все 12 бит прав заданы *)

o10 =8; (*010 *)

o100 =64; (*0100 *)

o1000=512; (*01000*)

symrights:array [0..7] of string=( (*базовые комбинации прав в символьной форме*)

'---', (*0 = 000*)

'--x', (*1 = 001*)

'-w-', (*2 = 010*)

'-wx', (*3 = 011*)

'r--', (*4 = 100*)

'r-x', (*5 = 101*)

'rw-', (*6 = 110*)

'rwx' (*7 = 111*)

);

spec='tss'; (*массив специальных прав доступа*)

begin

(*обрезаем старшие биты, не относящиеся к правам доступа (тип файла и т.п.)*)

r:=r and o7777;(*восьмеричная константа 10000-1==1*8^4-1==1*(2^3)^4-1==2^12-1 *)

(*выделяем числовые права для владельца, группы, остальных + специальные*)

o:=r mod o10;

s:=r div o1000;

u:=(r div o100) mod o10;

g:=(r mod o100) div o10;

res:=symrights[u]+symrights[g]+symrights[o];(*формируем символьыне права из базовых троек*)

for i:=1 to 3 do (*цикл проверки наличия чпециальных прав*)

if s and (1 shl (i-1)) <> 0 then (*если право установлено*)

if res[12-3*i]='x' then (*если есть обычное право на выполнение*)

res[12-3*i]:=spec[i] (*заносим маленькую букву*)

else

res[12-3*i]:=upcase(spec[i]); (*иначе - большую*)

getrights:=res; (*возвращаем результат - 9-символьное представление 12-битных прав*)

end;

var

d:^TDir; (*указатель на запись для работы с каталогом*)

elem:^Dirent; (*указатель на запись, хранящую один элекмент каталога*)

tekkat, (*строка для хранения имени каталога*)

fullpath (*полный путь к элементу каталога*)

:array [0..1000] of char;

st:stat; (*для хранения информации о файле или каталоге*)

begin

if paramcount=0 then (*если в командной строке не указан каталог*)

strcopy(tekkat,'.') (*то в качестве каталога используем текущий*)

else

tekkat:=paramstr(1); (*иначе используем каталог из командной строки*)

if not access(pchar(tekkat),F_OK or R_OK) then (*F_OK - проверка сущестования объекта ф.с.*)

begin

writeln('Каталог ', tekkat, ' не существует или недоступен для чтения'); (*диагностика*)

halt(1); (*возврат в предыдущую программу*)

end;

if not fstat(pchar(tekkat),st) then (*попытка получения информации о файле или каталоге*)

begin

writeln('Ошибка получения информации о каталоге ', tekkat); (*диагностика*)

halt(1); (*возврат в предыдущую программу*)

end;

if not S_ISDIR(st.mode) then (*проверка на каталог*)

begin

writeln(tekkat, ' - не каталог'); (*диагностика*)

halt(1); (*возврат в предыдущую программу*)

end;

d:=opendir(tekkat); (*попытка открытия каталога для чтения*)

if d=nil then (*если попытка не удалась*)

begin

writeln('Ошибка вызова opendir для каталога ', tekkat); (*диагностика*)

halt(1); (*возврат в предыдущую программу*)

end;

elem:=readdir(d); (*попытка чтения элемента каталога*)

while elem<>nil do

begin

(*формирование полного имени элемента каталога*)

strcopy(fullpath,tekkat); (*копируем имя текущего каталога в начало полного имени*)

if strcomp(tekkat,'/')<>0 then(*если текущий каталог - не корневой*)

begin

if fullpath[strlen(fullpath)-1]='/' then (*если в конце имени каталога слэш*)

fullpath[strlen(fullpath)-1]:=#0; (*заменяем его признаком конца строки*)

strcat(fullpath,'/'); (*добавляем после имени каталога слэш-разделитель*)

end;

strcat(fullpath,elem^.name); (*и имя элемента каталога*)

if not fstat(pchar(fullpath),st) then (*попытка получения информации о файле или каталоге*)

begin

writeln('Ошибка получения информации о ', fullpath); (*диагностика*)

continue; (*возврат в предыдущую программу*)

end;

{gmtime_r(st.mtime,mytm);}

writeln(gettype(st.mode),getrights(st.mode),st.nlink:5,

' ',st.size:10,' ',ctime(st.mtime), elem^.name); (*вывод имени элемента каталога*)

elem:=readdir(d); (*попытка чтения элемента каталога*)

end;

closedir(d); (*закрытие открытого opendir каталога*)

end.

Упражнение 13.29. Составьте аналог команды vdir.

uses linux,strings,sysutils;

function getname(uid:integer):string;

const w='/etc/passwd';

var ts,nam1,namb1:string;

tx:text;

begin

assign(tx,w);

reset(tx);

while not EOF (tx) do

begin

readln(tx,ts);

uid:=pos(':',ts);

nam1:=copy(ts,1,uid-1);

delete(ts,1,uid);

uid:=pos(':',ts);

delete(ts,1,uid);

namb1:=copy(ts,1,uid-1);

if namb1='500' then

write(nam1)

end;

close(tx);

getname:=nam1;

end;

function getgroup(gid:integer):string;

const q='/etc/group';

var ts,nam,namb:string;

t:text;

begin

assign(t,q);

reset(t);

while not EOF (t) do

begin

readln(t,ts);

gid:=pos(':',ts);

nam:=copy(ts,1,gid-1);

delete(ts,1,gid);

gid:=pos(':',ts);

delete(ts,1,gid);

namb:=copy(ts,1,gid-1);

if namb='500' then

write(nam);

end;

close(t);

getgroup:=nam;

end;

function gettype(mode:integer):char;

begin

if S_ISREG(mode) then

gettype:='-'

else

if S_ISDIR(mode) then

gettype:='d'

else

if S_ISCHR(mode) then

gettype:='c'

else

if S_ISBLK(mode) then

gettype:='b'

else

if S_ISFIFO(mode) then

gettype:='p'

else

gettype:='l';

end;

function getrights(mode:integer):string;

const

sympr:array [0..7] of string=(

'---', {0}

'--x', {1}

'-w-', {2}

'-wx', {3}

'r--', {4}

'r-x', {5}

'rw-', {6}

'rwx' {7}

);

specsympr:array [0..7] of string=(

'---', {0}

'--t', {1}

'-s-', {2}

'-st', {3}

's--', {4}

's-t', {5}

'ss-', {6}

'sst' {7}

);

var

s,u,g,o,i:integer;

res:string;

begin

mode:=mode and octal(7777);

u:=(mode div octal(100)) mod octal(10);

g:=(mode mod octal(100)) div octal(10);

o:=mode mod octal(10);

s:=mode div octal(1000);

res:=sympr[u]+sympr[g]+sympr[o];

for i:=1 to 3 do

if specsympr[s][i]<>'-' then

begin

if res[3*i]='-' then

res[3*i]:=upcase(specsympr[s][i])

else

res[3*i]:=specsympr[s][i];

end;

getrights:=res;

end;

var

d:PDIR;

el:pdirent;

st:stat;

res:integer;

dt:tdatetime;

polniypath,name:array [0..2000] of char;

begin

if paramcount = 0 then

name:='.'

else

name:=paramstr(1);

d:=opendir(name);

if d=nil then

begin

writeln('Ошибка открытия текущего каталога');

halt(0);

end;

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

{writeln(polniypath,' ',s.size);}

dt:=filedatetodatetime(st.mtime);

write(gettype(st.mode),getrights(st.mode),st.nlink:5,

getname(st.uid),' ',getgroup(st.gid),st.size:10,' ',datetimetostr(dt),' ' );

writeln(el^.name);

end;

el:=readdir(d);

end;

closedir(d);

end.

Упражнение 13.30. Напишите упрощенный аналог команды ls, распечатывающий содержимое текущего каталога (файла с именем ".") без сортировки имен по алфавиту. Предусмотрите чтение каталога, чье имя задается как аргумент программы. Имена "." и ".." не выдавать.

uses linux,strings,sysutils,crt;

{$linklib c}

type

plong=^longint;

function ctime(r:plong):pchar;cdecl;external;

function strchr(s:string;c:char):boolean;

var

i:integer;

begin

for i:=1 to length(s) do

if s[i]=c then

begin

strchr:=true;

exit;

end;

strchr:=false;

end;

function getall(w:string;uid:integer):string;

{const w='/etc/passwd';}

var ts,nam1,namb1:string;

tx:text;

d:integer;

begin

assign(tx,w);

reset(tx);

while not EOF (tx) do

begin

readln(tx,ts);

d:=pos(':',ts);

nam1:=copy(ts,1,d-1);

delete(ts,1,d+2);

d:=pos(':',ts);

{delete(ts,1,d);}

namb1:=copy(ts,1,d-1);

val(namb1,d);

{writeln('имя = ',nam1,', номер=',namb1);}

if d=uid then

break;

end;

close(tx);

getall:=nam1;

end;

function getname(uid:integer):string;

begin

getname:=getall('/etc/passwd',uid);

end;

function getgroup(gid:integer):string;

begin

getgroup:=getall('/etc/group',gid);

end;

function gettype(mode:integer):char;

begin

if S_ISREG(mode) then

gettype:='-'

else

if S_ISDIR(mode) then

gettype:='d'

else

if S_ISCHR(mode) then

gettype:='c'

else

if S_ISBLK(mode) then

gettype:='b'

else

if S_ISFIFO(mode) then

gettype:='p'

else

gettype:='l';

end;

function getrights(mode:integer):string;

const

sympr:array [0..7] of string=(

'---', {0}

'--x', {1}

'-w-', {2}

'-wx', {3}

'r--', {4}

'r-x', {5}

'rw-', {6}

'rwx' {7}

);

specsympr:array [0..7] of string=(

'---', {0}

'--t', {1}

'-s-', {2}

'-st', {3}

's--', {4}

's-t', {5}

'ss-', {6}

'sst' {7}

);

var

s,u,g,o,i:integer;

res:string;

begin

mode:=mode and octal(7777);

u:=(mode div octal(100)) mod octal(10);

g:=(mode mod octal(100)) div octal(10);

o:=mode mod octal(10);

s:=mode div octal(1000);

res:=sympr[u]+sympr[g]+sympr[o];

for i:=1 to 3 do

if specsympr[s][i]<>'-' then

begin

if res[3*i]='-' then

res[3*i]:=upcase(specsympr[s][i])

else

res[3*i]:=specsympr[s][i];

end;

getrights:=res;

end;

procedure obhod(name:pchar);

var

d:PDIR;

el:pdirent;

st:stat;

res:integer;

dt:tdatetime;

polniypath,datetime:array [0..2000] of char;

i,k:integer;

begin

d:=opendir(name);

if d=nil then

begin

writeln('Ошибка открытия каталога ',name);

exit;

end;

i:=0;

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

(*

strcopy(datetime,ctime(@st.mtime)+4);

datetime[12]:=#0;

write(gettype(st.mode),getrights(st.mode),st.nlink:5,' ',

getname(st.uid):10,' ',getgroup(st.gid):10,' ',st.size:10,' ',datetime,' ' );

*)

if(gettype(st.mode)='d') then

textcolor(9);

if(gettype(st.mode)='-') and strchr(getrights(st.mode),'x') then

textcolor(lightgreen);

if(gettype(st.mode)='p') then

textcolor(brown);

if(gettype(st.mode)='l') then

textcolor(lightblue);

if (gettype(st.mode)='c') or (gettype(st.mode)='b') then

textcolor(yellow);

write(el^.name);

for k:=strlen(el^.name) to 15 do

write(' ');

textcolor(7);

end;

el:=readdir(d);

inc(i);

if(i mod 5=0)then writeln;

end;

closedir(d);

if(i mod 5<>0)then writeln;

end;

var

name:array [0..2000] of char;

begin

if paramcount = 0 then

name:='.'

else

name:=paramstr(1);

obhod(name);

end.

Упражнение 13.31. Напишите программу удаления файлов и каталогов, заданных в командной строке. Программа должна удалять каталоги рекурсивно и отказываться удалять файлы устройств.

uses linux,strings,sysutils,crt;

{$linklib c}

type

plong=^longint;

function gettype(mode:integer):char;

begin

if S_ISREG(mode) then

gettype:='-'

else

if S_ISDIR(mode) then

gettype:='d'

else

if S_ISCHR(mode) then

gettype:='c'

else

if S_ISBLK(mode) then

gettype:='b'

else

if S_ISFIFO(mode) then

gettype:='p'

else

gettype:='l';

end;

function obhod(name:pchar):boolean;

var

flag:boolean;

d:PDIR;

el:pdirent;

st:stat;

res:integer;

polniypath:array [0..2000] of char;

begin

flag:=true;

d:=opendir(name);

if d=nil then

begin

writeln('Ошибка открытия каталога ',name);

exit;

end;

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

if not (gettype(st.mode) in ['b','c','d']) then

begin

writeln('Стираю файл ',polniypath);

//unlink(polniypath);

if not unlink(polniypath) then

begin

writeln('невозможно стереть файл ',polniypath);

flag:=false;(*ошибка удаления файла - нельзя будет стереть каталог*)

end;

end;

end;

el:=readdir(d);

end;

closedir(d);

d:=opendir(name);

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

if (gettype(st.mode)='d') and

(strcomp(el^.name,'.')<>0) and

(strcomp(el^.name,'..')<>0) then

begin

writeln('Переход в каталог ',polniypath);

if not obhod(polniypath) then

flag:=false;

end;

end;

el:=readdir(d);

end;

closedir(d);

if not flag then

writeln('Каталог ',name,

' не будет стерт, т.к. в нем не удалось стереть часть файлов или каталогов')

else

begin

{$i-}

rmdir(name);

if ioresult <> 0 then

begin

writeln('Ошибка удаления каталога ',name);

flag:=false;

end;

end;

writeln('Для каталога ',name, ' получен ',flag);

obhod:=flag;

end;

var

name:array [0..2000] of char;

begin

if paramcount<>0 then

begin

name:=paramstr(1);

obhod(name);

end

else

writeln('С особой осторожностью используйте: ',paramstr(0),' удаляемый каталог');

end.

Упражнение 13.32. Напишите функцию рекурсивного обхода дерева подкаталогов и печати имен всех файлов в нем с выдачей атрибутов в форме команды ls -l.

uses linux,strings,sysutils;

{$linklib c}

type

plong=^longint;

function ctime(r:plong):pchar;cdecl;external;

function getall(w:string;uid:integer):string;

{const w='/etc/passwd';}

var ts,nam1,namb1:string;

tx:text;

d:integer;

begin

assign(tx,w);

reset(tx);

while not EOF (tx) do

begin

readln(tx,ts);

d:=pos(':',ts);

nam1:=copy(ts,1,d-1);

delete(ts,1,d+2);

d:=pos(':',ts);

{delete(ts,1,d);}

namb1:=copy(ts,1,d-1);

val(namb1,d);

{writeln('имя = ',nam1,', номер=',namb1);}

if d=uid then

break;

end;

close(tx);

getall:=nam1;

end;

function getname(uid:integer):string;

begin

getname:=getall('/etc/passwd',uid);

end;

function getgroup(gid:integer):string;

begin

getgroup:=getall('/etc/group',gid);

end;

function gettype(mode:integer):char;

begin

if S_ISREG(mode) then

gettype:='-'

else

if S_ISDIR(mode) then

gettype:='d'

else

if S_ISCHR(mode) then

gettype:='c'

else

if S_ISBLK(mode) then

gettype:='b'

else

if S_ISFIFO(mode) then

gettype:='p'

else

gettype:='l';

end;

function getrights(mode:integer):string;

const

sympr:array [0..7] of string=(

'---', {0}

'--x', {1}

'-w-', {2}

'-wx', {3}

'r--', {4}

'r-x', {5}

'rw-', {6}

'rwx' {7}

);

specsympr:array [0..7] of string=(

'---', {0}

'--t', {1}

'-s-', {2}

'-st', {3}

's--', {4}

's-t', {5}

'ss-', {6}

'sst' {7}

);

var

s,u,g,o,i:integer;

res:string;

begin

mode:=mode and octal(7777);

u:=(mode div octal(100)) mod octal(10);

g:=(mode mod octal(100)) div octal(10);

o:=mode mod octal(10);

s:=mode div octal(1000);

res:=sympr[u]+sympr[g]+sympr[o];

for i:=1 to 3 do

if specsympr[s][i]<>'-' then

begin

if res[3*i]='-' then

res[3*i]:=upcase(specsympr[s][i])

else

res[3*i]:=specsympr[s][i];

end;

getrights:=res;

end;

procedure obhod(name:pchar);

var

d:PDIR;

el:pdirent;

st:stat;

res:integer;

dt:tdatetime;

polniypath,datetime:array [0..2000] of char;

begin

d:=opendir(name);

if d=nil then

begin

writeln('Ошибка открытия каталога ',name);

exit;

end;

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

strcopy(datetime,ctime(@st.mtime)+4);

datetime[12]:=#0;

write(gettype(st.mode),getrights(st.mode),st.nlink:5,' ',

getname(st.uid):10,' ',getgroup(st.gid):10,' ',st.size:10,' ',datetime,' ' );

writeln(el^.name);

end;

el:=readdir(d);

end;

closedir(d);

d:=opendir(name);

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

if S_ISDIR(st.mode) then

begin

if (strcomp(el^.name,'.')<>0) and (strcomp(el^.name,'..')<>0) then

begin

writeln;

writeln(polniypath,':');

obhod(polniypath);

end;

end;

end;

el:=readdir(d);

end;

closedir(d);

end;

var

name:array [0..2000] of char;

begin

if paramcount = 0 then

name:='.'

else

name:=paramstr(1);

obhod(name);

end.

Упражнение 13.33. Напишите программу удаления каталога, которая удаляет все файлы в нем и, рекурсивно, все его подкаталоги.

uses linux,strings,sysutils,crt;

{$linklib c}

type

plong=^longint;

function gettype(mode:integer):char;

begin

if S_ISREG(mode) then

gettype:='-'

else

if S_ISDIR(mode) then

gettype:='d'

else

if S_ISCHR(mode) then

gettype:='c'

else

if S_ISBLK(mode) then

gettype:='b'

else

if S_ISFIFO(mode) then

gettype:='p'

else

gettype:='l';

end;

function obhod(name:pchar):boolean;

var

flag:boolean;

d:PDIR;

el:pdirent;

st:stat;

res:integer;

polniypath:array [0..2000] of char;

begin

flag:=true;

d:=opendir(name);

if d=nil then

begin

writeln('Ошибка открытия каталога ',name);

exit;

end;

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

if not (gettype(st.mode) = 'd') then

begin

writeln('Стираю файл ',polniypath);

//unlink(polniypath);

if not unlink(polniypath) then

begin

writeln('невозможно стереть файл ',polniypath);

flag:=false;(*ошибка удаления файла - нельзя будет стереть каталог*)

end;

end;

end;

el:=readdir(d);

end;

closedir(d);

d:=opendir(name);

el:=readdir(d);

while el<>nil do

begin

polniypath:=name;

if strcomp(name,'/')=0 then

strcat(polniypath,el^.name)

else

begin

if name[strlen(name)-1]<>'/' then

strcat(polniypath,'/');

strcat(polniypath,el^.name);

end;

if not fstat(pchar(polniypath),st) then

writeln('Ошибка вызова stat для ',polniypath)

else

begin

if (gettype(st.mode)='d') and

(strcomp(el^.name,'.')<>0) and

(strcomp(el^.name,'..')<>0) then

begin

writeln('Переход в каталог ',polniypath);

if not obhod(polniypath) then

flag:=false;

end;

end;

el:=readdir(d);

end;

closedir(d);

if not flag then

writeln('Каталог ',name,

' не будет стерт, т.к. в нем не удалось стереть часть файлов или каталогов')

else

begin

{$i-}

rmdir(name);

if ioresult <> 0 then

begin

writeln('Ошибка удаления каталога ',name);

flag:=false;

end;

end;

writeln('Для каталога ',name, ' получен ',flag);

obhod:=flag;

end;

var

name:array [0..2000] of char;

begin

if paramcount<>0 then

begin

name:=paramstr(1);

obhod(name);

end

else

writeln('С особой осторожностью используйте: ',paramstr(0),' удаляемый каталог');

end.

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal