Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ОС операционные системы

.docx
Скачиваний:
39
Добавлен:
01.04.2014
Размер:
296.46 Кб
Скачать

Министерство образования Республики Беларусь

Учреждение образования «Белорусский государственный университет информатики и радиоэлектроники»

Контрольная работа по предмету «Операционные системы»

Вариант 4

Выполнил студент гр. 802301

Андрейчиков В.В.

Проверил

Минск 2010

Андрейчиков Василий Владимирович

N1 = 11, N2 =7, N3 = 12. (N1*N2*N3) mod 23 = 4

Вариант 4. Тоже что и п.8 но включая подкаталоги.

8. Написать программу поиска одинаковых по их содержимому файлов в двух каталогов, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2. В результате работы программы файлы, имеющиеся в Dir1, сравниваются с файлами в Dir2 по их содержимому. Процедуры сравнения должны запускаться с использованием функции fork() в отдельном процессе для каждой пары сравниваемых файлов. Каждый процесс выводит на экран свой pid, имя файла, число просмотренных байт и результаты сравнения. Число запущенных процессов в любой момент времени не должно превышать N (вводится пользователем). Проверить работу программы для каталога /usr/include/ и любого другого каталога в /home N=6.

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <dirent.h>

#include <errno.h>

#include <memory.h>

/*----------------------------------------------

Функция GETKOL рекурсивная. Возвращает количичестов

файлов по заданной директории и поддерикториях.

----------------------------------------------*/

int getkol(char* dirn) // Функция возращает количество рег. файлов в заданном каталоге включая подкаталоге

{

int dsize=0;//колич. файлов

DIR* dirs; //создаем указатель на поток директории

//if(*(dirn+(int)strlen(dirn)-1)==92) *(dirn+(int)strlen(dirn)-1)=0;

dirs = opendir(dirn); //открваем директорию с именем dirn

if (dirs) // если удается создать поток (открыть директорию)

{

struct dirent* dirstr; //создаем указатель на структуру для хранения

// элемента из потока директории

while(dirstr = readdir(dirs)) //пока удается получаем файл из потока

{

char* fnm=dirstr->d_name; //получаем из структуры имя файла

char* fullnm=(char*)alloca(strlen(dirn)+strlen(fnm)+1);//выделяем память по полное имя

//файла (путь + имя)

strcpy(fullnm,dirn);//операции для получения полного имени

strcat(fullnm,"/");

strcat(fullnm,fnm);

struct stat fst; //структура для хранения информации о файле

stat(fullnm,&fst); //получаем информацию о файле в структуру

if(S_ISREG(fst.st_mode)&&!S_ISLNK(fst.st_mode)) //Увеличиваем счетчик если файл

// регулярный и не является ссылкой (!второе условие не срабатывает (Ubuntu 10.04))

{

dsize++;

} else

if(S_ISDIR(fst.st_mode)&&strcmp(fnm,".")&&strcmp(fnm,"..")&&!S_ISLNK(fst.st_mode))//Если

//файл является каталогом и не является ссылкой(не сработало!).

// strcmp возвращает 0 если строки равны.

{

dsize=dsize+getkol(fullnm); //вызваем функцию рекурсивно

}

}

closedir(dirs); //закрываем каталог

}

else printf("Couldn't open derictory - %s\n",dirn);

return dsize;

}

/*----------------------------------------------

Функция GETLIST рекурсивна, на переданный указатель

записывает список имен файлов по заданому имени

каталога, а также заполняет соответственно массив

размеров каждого файла.

Входной параметр функциц "_i" служит для получения

числа фактически считанных файлов.

----------------------------------------------*/

void getlist(int* _i,char** _str,char* dirn,int* _fsize)

{

DIR* dirs;

dirs = opendir(dirn);

if (dirs)

{

struct dirent* dirstr;

while(dirstr = readdir(dirs))

{

char* fnm=dirstr->d_name; //получаем из структуры имя файла

char* fullnm=(char*)alloca(strlen(dirn)+strlen(fnm)+1);

strcpy(fullnm,dirn);

strcat(fullnm,"/");

strcat(fullnm,fnm);

struct stat fst;

stat(fullnm,&fst);

if(S_ISREG(fst.st_mode)&&!S_ISLNK(fst.st_mode))

{

strcpy(_str[*_i],fullnm);//копирование полного имени файла в массив

*(_fsize+*_i)=fst.st_size;//заполняем массив размера файла

(*_i)++;

}

if(S_ISDIR(fst.st_mode)&&strcmp(fnm,".")&&strcmp(fnm,"..")&&!S_ISLNK(fst.st_mode))

{

getlist(_i,_str,fullnm,_fsize); //если файл каталог функция вызывает саму себя

}

}

closedir(dirs);

}

else printf("Couldn't open derictory - %s\n",dirn);

}

/*----------------------------------------------

Функция создает новый процесс в котором сравниваются

два фала. Входные параметры: имя первого, имя второго и размер

файла. В функцию буду передаватся только файлы одинакового размера.

----------------------------------------------*/

int xfork(char *fnm1,char *fnm2,int* _fs)

{

int ppid = fork(); //создается новый дочерний процесс

if(ppid==0) //если процесс ребенок

{

int t=0;

FILE* fd1 = fopen(fnm1,"r");

FILE* fd2 = fopen(fnm2,"r");

while(abs(fgetc(fd1))==fgetc(fd2)) t++;//сравниваем посимвольно

//выводим форматированную строку с результатом

printf("\n_____ PID: %d ____\n1> %s\n2> %s\n === Result: %d of %d bytes match ===\n",getpid(),fnm1,fnm2,t,*_fs);

fclose(fd1);

fclose(fd2);

}

return ppid;

}

/*----------------------------------------------

Главная функция. Входные параметры получаем из командной строки.

----------------------------------------------*/

main(int argc, char *argv[])

{

if(argc>4)//Если задано параметров больше чем требуетсяэ

{

puts("Put that info in argv: DIR1 DIR2 N");

exit(1);

}

char* fnm1=argv[1];//Получаем имена файлов.

char* fnm2=argv[2];

int N;

if(!sscanf(argv[3],"%d",&N))//Если вместо числа одновременно

{ //запущеных процессоввведена строка.

puts("Not whole number");

exit(1);

}

errno=0; //Обнуляем переменную ошибок описанную в заголовочом файле.

char** str1; // Список файлов в директориях, поддерикториях.

char** str2;

int* fsize1; // Массив размеров.

int* fsize2; // Массив размеров.

int ksize1=getkol(argv[1]); //Подсчитываем файлы в 2ух каталогах

int ksize2=getkol(argv[2]);

printf("Total files found: %d ",ksize1+ksize2);

/*----------------------------------------------

Далее идет процесс выделения памяти под необходимые данные

----------------------------------------------*/

str1=malloc(ksize1*(sizeof(char*)));

str2=malloc(ksize2*(sizeof(char*)));

fsize1=malloc(ksize1*(sizeof(int)));

fsize2=malloc(ksize2*(sizeof(int)));

int i=0; //переменная счетчик

while(i<ksize1)

{

*(str1+i)=malloc(512*sizeof(char));

i++;

}

i=0;

while(i<ksize2)

{

*(str2+i)=malloc(512*sizeof(char));

i++;

}

ksize1=0;

ksize2=0;//обнуляем размер

getlist(&ksize1,str1,argv[1],fsize1);//получаем список имен и размеров файлов

getlist(&ksize2,str2,argv[2],fsize2);

printf("Total files read: %d\n",ksize1+ksize2);

/*i=0;

while(i<ksize)//Выводим список файлов и размер каждого

{

printf("%s -- %d bytes\n",*(str+i),*(size+i));

i++;

}*/

i=0; //обнуляем счетчик

int fr=1; //результат работы фокр

int k,n=0; // переменные счетчики

while(i<ksize1) //в этом цикле берется итый размер файла из первого каталога

{

k=0;//катый размер во 2ом каталоге

while(k<ksize2) //катый размер 2ого каталога

{

if(fr > 0)//если процесс родетельский

{

if(*(fsize1+i)==*(fsize2+k))//если совпали размеры

{

if(n++>N) wait(); //Если запущено больше N процессов

//ждем первого завершивсегося.

fr=xfork(*(str1+i),*(str2+k),fsize1+i);

//Вызвали функцию сравнения в новом процессе.

}

k++;

} else break;//если процесс не родительский прерываем цикл

}

i++;

}

if(fr>0)//если процесс родетельский

{

while(wait()>0); //ожидание завершения всех доч. процессов.

char *err= strerror(errno);//проверяме переменную ошибок

printf("\nErrno result: %s \n",err);//Выводим отчет об ошибках.

}

//далее освобождаем динамическую память

i=0;

while(i<ksize1)

{

free(*(str1+i));

i++;

}

while(i<ksize2)

{

free(*(str2+i));

i++;

}

free(str1);

free(str2);

free(fsize1);

free(fsize2);

return 0;

}

Проверим работу программы для каталога /usr/include и /home/basil для 5 одновременно запущенных процессов сравнения. Для проверки скопируем несколько файлов из первого каталога и в некоторых изменим символы. Резльтат работы: