[P&AM Lab] Cat ТЗ

Grigoriy A. Sitkarev sitkarev на komitex.ru
Вт Фев 15 23:43:11 MSK 2011


15.02.2011 21:18, LonelyRuyK пишет:
> Вроде бы ввёл поправки по основным пунктам.К сожалению пока не тестил на
> 64бит, изза того что с регистрацией на vmware проблемы.

Может быть стоит попробовать не vmware а какой-нибудь bochs или qemu?

Теперь по ходу текста программы замечания (самые важные).

1. Не понятно выходит у нас с BUFSIZE и count. Зачем-то делаем count = 
BUFSIZE-1 а потом при аллокации буфера для чтения обратно прибавляем к 
count+1.

2. Самый первый цикл while в main удивительно сложный в условии. Вообще, 
лучше использовать ф-ю getopt(3) для разбора опций. Раньше её не было 
просто в библиотеке, поэтому старые утилиты обходились без неё.

3. В switch лучше case оставить на том же уровне вложенности.

switch (*arg) {
case 'n': {
	nflg++;
	break;
}
...

4. Долго думал как же расшифровывается имя переменной fsti и так и не 
придумал. Наверное нужно выбрать какое-то вменяемое имя.

5. Закрывать файлы если мы делаем exit() в большинстве случаев не нужно. 
Потому что exit() их сам закроет и все ресурсы высвободит. Это лишнее.

6. Проверка на блочность сделана не совсем верно. Блочным будет и 
простой файл и файл блочного устройства. Т.е. надо:

if (S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) {
	...

Почему? Потому что блочное устройство у нас тоже будет эффективно 
читаться блоками.

7. Если я буду cat-ить файл например с флешки, а потом возьму и выдерну 
её, то программа будет работать неверно. Она может затереть чужие данные 
в куче (heap) потому что read(2) вернёт -1, а проверки там нет. Сейчас 
там так:

	res = read(fd, buff, count);
	buff[res] = '\0';

Мы не проверили, вернул ли read число > 0. Если была ошибка и read(2) 
вернул -1, то мы затрём что-то не наше в куче (heap). Для такой 
маленькой программы это пройдёт незаметно, но для той которая работает 
продолжительное время это однозначно приведёт к падению в SIGSEGV рано 
или поздно. Такие ошибки очень трудно искать.

Кроме того, программа может получить сигнал например. Мы сейчас не 
обрабатываем сигналы никак и поэтому любой сигнал приведёт к завершению 
процесса, но даже теоретически -- надо предусмотреть такой случай.

Здесь наверное нужно было сделать что-то вроде:

	for (;;) {
		res = read(fd, buff, count);

		if (res == -1 && errno == EINTR)
			continue;

		if (res == 0) {
			/* Handle end of file. */
			...
		} else if (res < 0) {
			/* Handle error. */
		}

		/* Now do something with input. */
		...
	}

Это практически идиома.

8. Не понятно, почему использован цикл for:

	i = 0;
	for(; i<res; i++){
		...
	}

вместо идиоматического:

	for (i = 0; i < res; i++) {
		...
	}


9. printfile() добавляет всегда лишний '\n' в файл. Этого быть не 
должно. И вообще, cat он предназначен для работы с любыми файлами, 
любыми. Не только текстовыми. Это нужно помнить.

10. Опция -v не обрабатывается, хотя утилита "кушает" её с командной 
строки. Это значит что программа не соответствует ТЗ.

Боря, ещё, обрати пожалуйста внимание на стиль. В некоторых местах всё 
прыгает, пробелы, скобки, а надо бы всё в удобный приятный вид привести, 
чтобы была глазу радость.

Пока вроде бы всё, мелочи потом.

--
Г.А.




Подробная информация о списке рассылки Lab